[
  {
    "path": ".gitignore",
    "content": "/db/*.sqlite3\n/db/pgdump_full.sql\n/log/*.log\n/tmp/**/*\n/config/additional_environment.rb\n/config/database.yml\n/config/email.yml\n/config/initializers/session_store.rb\n/coverage\n/db/*.db\n/db/*.sqlite3\n!/db/schema.rb\n/files/*\n/log/*.log*\n/log/mongrel_debug\n/public/dispatch.*\n/public/plugin_assets\n/tmp/*\n/tmp/cache/*\n/tmp/sessions/*\n/tmp/sockets/*\n/tmp/test/*\n/vendor/rails\n/config/database.yml\n/nbproject\nredmine.tmproj\nserverlog\n.DS_Store\n*.swp\n*.swo\n.redcar/\n.bundle\n/bin\n"
  },
  {
    "path": ".gitmodules",
    "content": ""
  },
  {
    "path": ".rspec",
    "content": "--colour\n--format profile\n--loadby mtime\n--reverse\n"
  },
  {
    "path": ".rvmrc",
    "content": "#!/usr/bin/env bash\n\n# This is an RVM Project .rvmrc file, used to automatically load the ruby\n# development environment upon cd'ing into the directory\n\n# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,\n# Only full ruby name is supported here, for short names use:\n#     echo \"rvm use 1.8.7\" > .rvmrc\nenvironment_id=\"ruby-1.8.7-p370@bettermeans\"\n\n# Uncomment the following lines if you want to verify rvm version per project\n# rvmrc_rvm_version=\"1.14.1 (stable)\" # 1.10.1 seams as a safe start\n# eval \"$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print \"[[ \"$1*65536+$2*256+$3\" -ge \"$4*65536+$5*256+$6\" ]]\"}' )\" || {\n#   echo \"This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading.\"\n#   return 1\n# }\n\n# First we attempt to load the desired environment directly from the environment\n# file. This is very fast and efficient compared to running through the entire\n# CLI and selector. If you want feedback on which environment was used then\n# insert the word 'use' after --create as this triggers verbose mode.\nif [[ -d \"${rvm_path:-$HOME/.rvm}/environments\"\n  && -s \"${rvm_path:-$HOME/.rvm}/environments/$environment_id\" ]]\nthen\n  \\. \"${rvm_path:-$HOME/.rvm}/environments/$environment_id\"\n  [[ -s \"${rvm_path:-$HOME/.rvm}/hooks/after_use\" ]] &&\n    \\. \"${rvm_path:-$HOME/.rvm}/hooks/after_use\" || true\n  if [[ $- == *i* ]] # check for interactive shells\n  then echo \"Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)\" # show the user the ruby and gemset they are using in green\n  else echo \"Using: $GEM_HOME\" # don't use colors in non-interactive shells\n  fi\nelse\n  # If the environment file has not yet been created, use the RVM CLI to select.\n  rvm --create use  \"$environment_id\" || {\n    echo \"Failed to create RVM environment '${environment_id}'.\"\n    return 1\n  }\nfi\n\n# If you use bundler, this might be useful to you:\n# if [[ -s Gemfile ]] && {\n#   ! builtin command -v bundle >/dev/null ||\n#   builtin command -v bundle | GREP_OPTIONS= \\grep $rvm_path/bin/bundle >/dev/null\n# }\n# then\n#   printf \"%b\" \"The rubygem 'bundler' is not installed. Installing it now.\\n\"\n#   gem install bundler\n# fi\n# if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null\n# then\n#   bundle install | GREP_OPTIONS= \\grep -vE '^Using|Your bundle is complete'\n# fi\n"
  },
  {
    "path": "Gemfile",
    "content": "source :rubygems\n\ngem 'rake', '0.8.7'\n\ngem 'rails', '2.3.14'\n\ngem 'ruby-debug', '0.10.4'\ngem 'rubytree', '0.7.0'\ngem 'rpx_now', '0.6.24'\ngem 'recurly', '0.3.3'\ngem 'fleximage', '1.0.4'\ngem 'reportable', '1.1.2'\ngem 'comma', :git => 'https://github.com/crafterm/comma.git', :ref => 'rails2'\ngem 'fastercsv', '1.5.4'\ngem 'SystemTimer', '1.2.2', :require => 'system_timer', :platforms => :ruby_18\ngem 'rack-timeout', '0.0.1'\ngem 'will_paginate', '2.3.15'\ngem 'grosser-ssl_requirement', :require => 'ssl_requirement'\n\ngroup :test do\n  gem 'shoulda'\n  gem 'webrat', '0.7.3'\n  gem 'rspec', '1.3.2'\n  gem 'rspec-rails', '1.3.4'\n  gem 'pickle', \"0.3.4\"\n  gem 'factory_girl', \"1.3.3\"\n  gem 'object_daddy', \"0.4.3\"\n  #gem 'capybara-webkit'\n  gem 'fakeweb'\nend\n\ngroup :development do\n  gem 'sqlite3-ruby', :require => 'sqlite3'\n  gem 'pg'\n  gem 'mysql2', '< 0.3'\n  gem 'guard-rspec'\n  gem 'spork', '0.8.5'\n  gem 'guard-spork'\n  #gem 'reek'\n  gem 'ruby2ruby', '1.2.2'\n  gem 'heckle'\nend\n\ngroup :development, :test do\n  gem 'capybara'\n  gem 'steak'\nend\n"
  },
  {
    "path": "Guardfile",
    "content": "# A sample Guardfile\n# More info at https://github.com/guard/guard#readme\nguard 'spork', :rspec_env => { 'RAILS_ENV' => 'test' } do\n  watch('config/application.rb')\n  watch('config/environment.rb')\n  watch('config/environments/test.rb')\n  watch(%r{^config/initializers/.+\\.rb$})\n  watch('Gemfile')\n  watch('Gemfile.lock')\n  watch('spec/spec_helper.rb') { :rspec }\n  watch('spec/factories.rb')\n  watch('db/seeds.rb')\n  watch(%r{features/support/}) { :cucumber }\n  watch(%r{^app/models/.+\\.rb$})\n  watch(%r{^app/controllers/.+\\.rb$})\nend\n\nguard 'rspec', :version => 1, :cli => '--drb --color' do\n  watch(%r{^spec/.+_spec\\.rb$})\n  watch(%r{^lib/(.+)\\.rb$})     { |m| \"spec/lib/#{m[1]}_spec.rb\" }\n  watch('spec/spec_helper.rb')  { \"spec\" }\n\n  # Rails example\n  watch(%r{^app/(.+)\\.rb$})                           { |m| \"spec/#{m[1]}_spec.rb\" }\n  watch(%r{^app/(.*)(\\.erb|\\.haml)$})                 { |m| \"spec/#{m[1]}#{m[2]}_spec.rb\" }\n  watch(%r{^app/controllers/(.+)_(controller)\\.rb$})  { |m| [\"spec/routing/#{m[1]}_routing_spec.rb\", \"spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb\", \"spec/acceptance/#{m[1]}_spec.rb\"] }\n  watch(%r{^spec/support/(.+)\\.rb$})                  { \"spec\" }\n  watch('config/routes.rb')                           { \"spec/routing\" }\n  watch('app/controllers/application_controller.rb')  { \"spec/controllers\" }\n  \n  # Capybara request specs\n  watch(%r{^app/views/(.+)/.*\\.(erb|haml)$})          { |m| \"spec/requests/#{m[1]}_spec.rb\" }\n  \n  # Turnip features and steps\n  watch(%r{^spec/acceptance/(.+)\\.feature$})\n  watch(%r{^spec/acceptance/steps/(.+)_steps\\.rb$})   { |m| Dir[File.join(\"**/#{m[1]}.feature\")][0] || 'spec/acceptance' }\nend\n"
  },
  {
    "path": "README.md",
    "content": "BetterMeans\n-----------\n\nBetterMeans is giving birth to a new kind of company. An Open Enterprise.\n\nMore details can be found at http://bettermeans.com and here http://bettermeans.org\n\n\nGetting started\n---------------\n\n* `git clone git@github.com:Bettermeans/bettermeans.git`\n\n* bundle install\n\n* Rename `database.yml.example` to `database.yml`\n\n* Run rake `db:create:all` and `rake db:schema:load`\n\nThat's it. Now you're ready to change the world. Here's to making a dent in things together!\n\n\nDev notes\n---------\n\nPlatform workstream: http://bettermeans.com/projects/2/dashboard\n\nIRC: #bettermeans irc.feenode.net\n\nmailinglist: bettermeans@librelist.org (or build in workstream forum)\n\n\nTesting\n-------\n\ncapybara-webkit depends on a WebKit implementation from Qt as explained in https://github.com/thoughtbot/capybara-webkit/wiki/Installing-QT\n\n\nTranslating\n-----------\n\nYou can find language specific translation groups at: https://www.transifex.net/projects/p/bettermeans\n\n\nKnown issues\n------------\n\nAttachments doesn't work in dev environment\n\nLogging in via the janrain plugin (e.g. google, twitter...etc) won't work in dev environment (if you need to work with this, drop me a message, there's an involved workaround)\n\n\nLicense and legalese\n--------------------\n\nOur codebase is based largely on an early fork of Redmine.\n\nRedmine is open source and released under the terms of the GNU General Public License v2 (GPL).\nAll redmine code is Copyright (C) 2006-2011  Jean-Philippe Lang\nAll non-redmine code is Copyright (C) Shereef Bishay, and is dual-licensed: you may use either the GNU General Public License v2 (GPL), or the MIT License (see http://www.opensource.org/licenses/mit-license.php).\n\nThanks for joining us! May our work be used for the greater good of everyone.\n"
  },
  {
    "path": "Rakefile",
    "content": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/switchtower.rake, and they will automatically be available to Rake.\n\nrequire(File.join(File.dirname(__FILE__), 'config', 'boot'))\n\nrequire 'rake'\nrequire 'rake/testtask'\nrequire 'rake/rdoctask'\nrequire 'tasks/rails'\n"
  },
  {
    "path": "app/controllers/account_controller.rb",
    "content": "# TODO: rename this to something like SessionsController after integration specs are done\nclass AccountController < ApplicationController\n\n  # RPX does not pass Rails form tokens...\n  skip_before_filter :verify_authenticity_token, :only => [ :rpx_token, :register ]\n\n  # prevents login action from being filtered by check_if_login_required application scope filter\n  skip_before_filter :check_if_login_required, :except => [ :cancel ]\n  ssl_required :all\n\n  # Login request and validation\n  def login\n    set_invitation_token\n    if request.get?\n      logout_user\n      session[:invitation_token] = @invitation_token\n      render :layout => 'static'\n    elsif open_id_authenticate?\n      open_id_authenticate(params[:openid_url])\n    else\n      password_authentication(@invitation_token)\n    end\n  end\n\n  def rpx_token\n    find_user_by_identifier || find_user_by_mail || create_new_user\n    message = reactivate_user\n    successful_authentication(@user, @invitation_token, message)\n  end\n\n  # Log out current user and redirect to welcome page\n  def logout\n    cookies.delete :autologin\n    current_user.delete_autologin_tokens\n    logout_user\n    redirect_to home_url\n  end\n\n  # Enable user to choose a new password\n  def lost_password\n    redirect_to(home_url) && return unless Setting.lost_password?\n    validate_token || create_token\n  end\n\n  # User self-registration\n  def register\n    redirect_to(home_url) && return unless check_registration\n\n    pick_plan\n    if request.get?\n      logout_and_invite\n    else\n      initialize_user_with_plan\n      return if register_user_with_auth_source || register_user\n    end\n    render :layout => 'static'\n  end\n\n  # Token based account activation\n  def activate\n    redirect_to(home_url) && return unless can_activate? && user = registered_user\n    user.activate\n\n    if user.save\n      @token.destroy\n      flash.now[:success] = l(:notice_account_activated)\n      successful_authentication(user)\n    else\n      render :action => 'login', :layout => 'static'\n    end\n  end\n\n  def cancel\n    current_user.cancel_account!\n    render_message(l(:notice_account_canceled))\n  end\n\n  private\n\n  def password_authentication(invitation_token=nil)\n    user = User.try_to_login(params[:username], params[:password])\n\n    if user.nil?\n      invalid_credentials\n    elsif user.new_record?\n      onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id })\n    elsif user.active?\n      successful_authentication(user,invitation_token)\n    else\n      inactive_user\n    end\n  end\n\n  def open_id_authenticate(openid_url)\n    authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration|\n      if result.successful?\n        user = User.find_or_initialize_by_identity_url(identity_url)\n        if user.new_record?\n          # Self-registration off\n          redirect_to(home_url) && return unless Setting.self_registration?\n\n          # Create on the fly\n          user.login = registration['nickname'] unless registration['nickname'].nil?\n          user.mail = registration['email'] unless registration['email'].nil?\n          user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil?\n          user.random_password\n          user.status = User::STATUS_REGISTERED\n\n          case Setting.self_registration\n          when '1'\n            register_by_email_activation(user) do\n              onthefly_creation_failed(user)\n            end\n          when '3'\n            register_automatically(user) do\n              onthefly_creation_failed(user)\n            end\n          else\n            register_manually_by_administrator(user) do\n              onthefly_creation_failed(user)\n            end\n          end\n        else\n          # Existing record\n          if user.active?\n            successful_authentication(user)\n          else\n            account_pending\n          end\n        end\n      end\n    end\n  end\n\n  def successful_authentication(user, invitation_token = nil, msg=nil)\n    # Valid user\n    self.logged_user = user\n    Track.log(Track::LOGIN,session[:client_ip])\n\n    if invitation_token\n      invitation = Invitation.find_by_token(invitation_token)\n      invitation.accept(user) if invitation\n    end\n\n    # generate a key and set cookie if autologin\n    if params[:autologin] && Setting.autologin?\n      token = Token.create(:user => user, :action => 'autologin')\n      cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now }\n    end\n\n    if msg\n      render_message(msg)\n    else\n      redirect_back_or_default :controller => 'welcome', :action => 'index'\n    end\n  end\n\n  # Onthefly creation failed, display the registration form to fill/fix attributes\n  def onthefly_creation_failed(user, auth_source_options = { })\n    @user = user\n    session[:auth_source_registration] = auth_source_options unless auth_source_options.empty?\n    render :action => 'register'\n  end\n\n  def invalid_credentials\n    # BUGBUG: \"invalid_credentials\", spelling\n    flash.now[:error] = l(:notice_account_invalid_creditentials)\n    render :layout => 'static'\n  end\n\n  def inactive_user\n    flash.now[:error] = l(:notice_account_inactive_user)\n    render_error(l(:notice_account_inactive_user))\n  end\n\n  # Register a user for email activation.\n  #\n  # Pass a block for behavior when a user fails to save\n  def register_by_email_activation(user, invitation_token = nil)\n\n    # BUGBUG: this should just be `invitation_token.blank?`\n    # when it's nil this throws an error\n    unless invitation_token.empty? || invitation_token.nil?\n      invitation = Invitation.find_by_token invitation_token\n      invitation.new_mail = user.mail\n      invitation.save\n    end\n\n    if invitation && invitation.mail == user.mail\n      return register_automatically(user)\n    end\n\n    token = Token.new(:user => user, :action => \"register\")\n    if user.save and token.save\n      Mailer.send_later(:deliver_register,token)\n      flash.now[:success] = l(:notice_account_register_done)\n      render :action => 'login', :layout => 'static'\n      return true\n    else\n      yield if block_given?\n      return false\n    end\n  end\n\n  # Automatically register a user\n  #\n  # Pass a block for behavior when a user fails to save\n  def register_automatically(user, &block)\n    # Automatic activation\n    user.status = User::STATUS_ACTIVE\n    user.last_login_on = Time.now\n    if user.save\n      self.logged_user = user\n      Track.log(Track::LOGIN,session[:client_ip])\n      redirect_with_flash :success, l(:notice_account_activated), :controller => 'welcome', :action => 'index'\n      return true\n    else\n      yield if block_given?\n      return false\n    end\n  end\n\n  # Manual activation by the administrator\n  #\n  # Pass a block for behavior when a user fails to save\n  def register_manually_by_administrator(user, &block)\n    if user.save\n      # Sends an email to the administrators\n      Mailer.send_later(:deliver_account_activation_request,user)\n      account_pending\n    else\n      yield if block_given?\n    end\n  end\n\n  def account_pending\n    flash.now[:notice] = l(:notice_account_pending)\n    render :action => 'login', :layout => 'static'\n  end\n\n  def random_email\n    \"#{(0...8).map{65.+(rand(25)).chr}.join}_noemail@bettermeans.com\"\n  end\n\n  def data\n    @data ||= RPXNow.user_data(params[:token])\n    raise \"hackers?\" unless @data\n    @data\n  end\n\n  def invitation\n    return @invitation if defined? @invitation\n    if session[:invitation_token]\n      @invitation = Invitation.find_by_token(session[:invitation_token])\n      @invitation_token = session[:invitation_token]\n    end\n    @invitation\n  end\n\n  def invitation_mail\n    invitation.mail if invitation\n  end\n\n  def update_invitation\n    invitation.update_attributes(:new_mail => @user.mail) if invitation\n  end\n\n  def find_user_by_identifier\n    if @user = User.find_by_identifier(data[:identifier])\n      update_invitation\n      true\n    end\n  end\n\n  def find_user_by_mail\n    if data[:email] && @user = User.find_by_mail(data[:email])\n      @user.update_attributes(:identifier => data[:identifier])\n      true\n    end\n  end\n\n  def create_new_user\n    @user = User.new(:firstname => name,\n                      :mail => mail,\n                      :identifier => data[:identifier])\n\n    @user.login = available_login\n    update_invitation\n    save_user_or_raise\n  end\n\n  def reactivate_user\n    unless @user.active?\n      @user.reactivate\n      return l(:notice_account_reactivated)\n    end\n  end\n\n  def save_user_or_raise\n    unless @user.save\n      session[:debug_user] = @user.inspect\n      session[:debug_data] = data.inspect\n      raise \"Couldn't create new account\"\n    end\n  end\n\n  def name\n    data[:name] || data[:username]\n  end\n\n  def mail\n    # twitter accounts don't give email so we generate a random one\n    # TODO: get a real email from the user, or don't require one\n    data[:email] || invitation_mail || random_email\n  end\n\n  def available_login\n    # BUGBUG: if data[:email] is nil this won't fail based on validations\n    # should probably use mail from up above\n    User.find_available_login([data[:username], name]) || data[:email]\n  end\n\n  def logout_user\n    self.logged_user = nil\n  end\n\n  def set_invitation_token\n    session[:invitation_token] = params[:invitation_token] || session[:invitation_token]\n    @invitation_token = session[:invitation_token]\n  end\n\n  def open_id_authenticate?\n    Setting.openid? && using_open_id?\n  end\n\n  def update_password\n    # BUGBUG: password confirmation isn't validated when nil\n    @user.password = params[:new_password]\n    @user.password_confirmation = params[:new_password_confirmation]\n\n    if @user.save\n      @token.destroy\n      flash.now[:success] = l(:notice_account_password_updated)\n      render :action => 'login', :layout => 'static'\n      true\n    end\n  end\n\n  def valid_user\n    user = User.find_by_mail(params[:mail])\n\n    if user.nil?\n      flash.now[:error] = l(:notice_account_unknown_email)\n      nil\n    elsif user.auth_source_id\n      flash.now[:error] = l(:notice_can_t_change_password)\n      nil\n    else\n      user\n    end\n  end\n\n  def valid_token\n    if token && !token.expired?\n      token\n    else\n      redirect_to(home_url)\n      nil\n    end\n  end\n\n  def token\n    find_token('recovery')\n  end\n\n  # TODO: should be able to somehow combine #token and #find_token\n  def find_token(action)\n    @token ||= if params[:token]\n      Token.find_by_action_and_value(action, params[:token])\n    end\n  end\n\n  def send_mail(token)\n    Mailer.send_later(:deliver_lost_password, token)\n    flash.now[:success] = l(:notice_account_lost_email_sent)\n    render :action => 'login', :layout => 'static'\n  end\n\n  def validate_token\n    if params[:token] && @token = valid_token\n      @user = @token.user\n      return true if request.post? && update_password\n      render :template => \"account/password_recovery\"\n      true\n    end\n  end\n\n  def create_token\n    if request.post? && user = valid_user\n      token = Token.new(:user => user, :action => \"recovery\")\n      token.save && send_mail(token)\n    end\n  end\n\n  def pick_plan\n    if params[:plan]\n      @plan_id = Plan.find_by_code(params[:plan]).id\n    elsif params[:plan_id]\n      @plan_id = params[:plan_id]\n    else\n      @plan_id = Plan.find_by_code(Plan::FREE_CODE).id\n    end\n  end\n\n  def register_user\n    @user.login = params[:user][:login]\n    @user.password = params[:password]\n    @user.password_confirmation = params[:password_confirmation]\n\n    case Setting.self_registration\n    when '1'\n      register_by_email_activation(@user,params[:invitation_token])\n    when '3'\n      register_automatically(@user)\n      false\n    else\n      register_manually_by_administrator(@user)\n      false\n    end\n  end\n\n  def invite_to_login\n    session[:invitation_token] = params[:invitation_token]\n    invitation = Invitation.find_by_token(params[:invitation_token])\n    @user.mail = invitation.mail if invitation\n    flash.now[:notice] = \"Sign up below to activate your invitation.\" <<\n                         \"<br><br><a href='/login?invitation_token=\" <<\n                         \"#{params[:invitation_token]}'>\" <<\n                         \"Login here if you already have an account.</a>\"\n  end\n\n  def initialize_user_with_plan\n    @user = User.new(params[:user])\n    @user.plan_id = @plan_id\n\n    # TODO: it shouldn't be possible for @user.plan_id to be nil here\n    @user.trial_expires_on = 30.days.from_now if @user.plan_id && !@user.plan.free?\n    # TODO: admin is attr_protected in the model, so it shouldn't be necessary here\n    @user.admin = false\n    @user.status = User::STATUS_REGISTERED\n  end\n\n  def register_user_with_auth_source\n    return false unless session[:auth_source_registration]\n    @user.status = User::STATUS_ACTIVE\n    @user.login = session[:auth_source_registration][:login]\n    @user.auth_source_id = session[:auth_source_registration][:auth_source_id]\n\n    if @user.save\n      # TODO: this isn't necessary, as the session gets cleared in logged_user=\n      session[:auth_source_registration] = nil\n      self.logged_user = @user\n      Track.log(Track::LOGIN,session[:client_ip])\n      redirect_with_flash :notice, l(:notice_account_activated), :controller => 'my', :action => 'account'\n      true\n    end\n  end\n\n  def logout_and_invite\n    # TODO: this isn't necessary, as the session gets cleared in logged_user=\n    session[:auth_source_registration] = nil\n    logout_user\n    @user = User.new(:language => Setting.default_language)\n    invite_to_login if params[:invitation_token]\n  end\n\n  def check_registration\n    Setting.self_registration? || session[:auth_source_registration]\n  end\n\n  def can_activate?\n    Setting.self_registration? && params[:token] && valid_register_token?\n  end\n\n  def valid_register_token?\n    find_token('register')\n    @token && !@token.expired?\n  end\n\n  def registered_user\n    # TODO: this is brittle, depending on @token being set earlier\n    user = @token.user\n    user if user.registered?\n  end\nend\n"
  },
  {
    "path": "app/controllers/activity_stream_preferences_controller.rb",
    "content": "#--\n# Copyright (c) 2008 Matson Systems, Inc.\n# Released under the BSD license found in the file\n# LICENSE included with this ActivityStreams plug-in.\n#++\n# Template to generate the controllers\nclass ActivityStreamPreferencesController < ApplicationController\n  include ActivityStreamPreferencesModule\n  before_filter :require_login, :except => :feed\nend\n"
  },
  {
    "path": "app/controllers/activity_stream_preferences_module.rb",
    "content": "#--\n# Copyright (c) 2008 Matson Systems, Inc.\n# Released under the BSD license found in the file\n# LICENSE included with this ActivityStreams plug-in.\n#++\n# activity_stream_preferences_module.rb provides ActivityStreamPreferencesModule\n\nrequire 'digest/sha1'\n\n# ActivityStreamPreferencesModule is included in your generated ActivityStreamPereference Controller and provides functionality for User to configure preferences as to where their activities are displayed\nmodule ActivityStreamPreferencesModule\n\n  def index\n\n    get_user_id\n\n    @activity_stream_preferences = ActivityStreamPreference.find(:all,\n      :conditions => { ACTIVITY_STREAM_USER_MODEL_ID => @user_id })\n\n    build_activities_hash\n\n    klass = Object::const_get(ACTIVITY_STREAM_USER_MODEL)\n    @user = klass.find(@user_id)\n    if @user.activity_stream_token.blank?\n      @user.update_attribute(:activity_stream_token,\n        Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join ))\n      if @user.id == self.current_user.id\n        self.current_user.reload\n      end\n    end\n\n    respond_to do |format|\n      format.html # index.html.erb\n      format.xml  { render :xml => @activity_stream_preferences }\n    end\n  end\n\n  def create\n\n    get_user_id\n\n    @activity_stream_preferences = ActivityStreamPreference.find(:all,\n      :conditions => { ACTIVITY_STREAM_USER_MODEL_ID => @user_id })\n\n    build_activities_hash\n\n    locations = params[:locations] || []\n\n    all_locations = []\n\n    ACTIVITY_STREAM_LOCATIONS.each do |location|\n      ACTIVITY_STREAM_ACTIVITIES.each_key do |activity|\n        all_locations <<  \"#{activity.to_s}.#{location[0]}\"\n      end\n    end\n\n    (all_locations - locations).each do |location|\n      activity = @activities[location]\n      if activity\n        @activities.delete(location)\n        next\n      end\n      activity = ActivityStreamPreference.new\n      (activity_name,location_id) = location.split('.')\n      activity.activity = activity_name\n      activity.location = location_id\n      activity.send(\"#{ACTIVITY_STREAM_USER_MODEL_ID}=\", @user_id)\n      activity.save!\n    end\n\n    @activities.each_value { |a| a.destroy }\n\n    respond_to do |format|\n      flash.now[:success] = 'Activity Stream Preferences were successfully updated.'\n      format.html do\n        if current_user.admin? && params[ACTIVITY_STREAM_USER_MODEL_ID.to_sym] != current_user.id.to_s\n          redirect_to(activity_stream_preferences_path(ACTIVITY_STREAM_USER_MODEL_ID => @user_id))\n        else\n          redirect_to(activity_stream_preferences_path)\n        end\n      end\n      format.xml  { head :ok }\n    end\n  end\n\n  protected\n\n  def get_user_id\n    if User.current.admin? && params[ACTIVITY_STREAM_USER_MODEL_ID.to_sym]\n      @user_id = params[ACTIVITY_STREAM_USER_MODEL_ID.to_sym]\n    else\n      @user_id = User.current.id\n    end\n  end\n\n  def build_activities_hash\n    @activities = {}\n    @activity_stream_preferences.each do |a|\n      key = \"#{a.activity}.#{a.location}\"\n      @activities[key] = a\n    end\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/activity_streams_controller.rb",
    "content": "#--\n# Copyright (c) 2008 Matson Systems, Inc.\n# Released under the BSD license found in the file\n# LICENSE included with this ActivityStreams plug-in.\n#++\n# Template to generate the controllers\nclass ActivityStreamsController < ApplicationController\n\n  include ActivityStreamsModule\n  before_filter :authorize, :except => [ :index, :feed]\n  ssl_required :all\n\n  def index\n    respond_to do |wants|\n      wants.js do\n        render :update do |page|\n          if params[:refresh]\n            page.replace \"activity_stream_list\", :partial => \"activity_streams/activity_stream_list\", :locals => {\n                                                :user_id => params[:user_id],\n                                                :project_id => params[:project_id],\n                                                :with_subprojects => params[:with_subprojects],\n                                                :limit => params[:limit],\n                                                :max_created_at => nil,\n                                                :show_refresh => true}\n            page.call \"arm_fancybox\" #attaches fancybox triggers to new issues\n            page.call \"break_long_words\"\n          else\n            page.replace \"activity_stream_bottom\", :partial => \"activity_streams/activity_stream_list\", :locals => {\n                                                :user_id => params[:user_id],\n                                                :project_id => params[:project_id],\n                                                :with_subprojects => params[:with_subprojects],\n                                                :limit => params[:limit],\n                                                :max_created_at => params[:max_created_at],\n                                                :show_refresh => false}\n            page.call \"arm_fancybox\" #attaches fancybox triggers to new issues\n            page.call \"break_long_words\"\n          end\n        end\n      end\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/activity_streams_module.rb",
    "content": "#--\n# Copyright (c) 2008 Matson Systems, Inc.\n# Released under the BSD license found in the file\n# LICENSE included with this ActivityStreams plug-in.\n#++\n# activity_streams_module.rb provides ActivityStreamsModule\n#\n# ActivityStreamsModule is included in your generated ActivityStreams Controller and provides base functionality for the Activity Streams Plug-in\nmodule ActivityStreamsModule\n\n  def index\n    @activity_streams = ActivityStream.find(:all, :limit => 200, :order => \"updated_at DESC\")\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @activity_streams }\n    end\n  end\n\n  def show\n    @activity_stream = ActivityStream.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @activity_stream }\n    end\n  end\n\n  def new\n    @activity_stream = ActivityStream.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @activity_stream }\n    end\n  end\n\n  def edit\n    @activity_stream = ActivityStream.find(params[:id])\n  end\n\n  def create\n    @activity_stream = ActivityStream.new(params[:activity_stream])\n\n    respond_to do |format|\n      if @activity_stream.save\n        flash.now[:success] = 'ActivityStream was successfully created.'\n        format.html { redirect_to(@activity_stream) }\n        format.xml  { render :xml => @activity_stream, :status => :created, :location => @activity_stream }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @activity_stream.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @activity_stream = ActivityStream.find(params[:id])\n\n    respond_to do |format|\n      if @activity_stream.update_attributes(params[:activity_stream])\n        flash.now[:success] = 'ActivityStream was successfully updated.'\n        format.html { redirect_to(@activity_stream) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @activity_stream.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @activity_stream = ActivityStream.find(params[:id])\n\n    respond_to do |format|\n      if (current_user.admin? || (current_user.id == @activity_stream.actor_id && @activity_stream.actor_type == ACTIVITY_STREAM_USER_MODEL)) && @activity_stream.soft_destroy\n        flash.now[:success] = 'Activity Removed.'\n        format.html { redirect_to \"#{request.protocol}#{request.host_with_port}#{params[:ref]}\" }\n        format.xml  { head :ok }\n      else\n        flash.now[:error] = 'Unexpected Error removing ActivityStream.'\n        format.html {redirect_to \"#{request.protocol}#{request.host_with_port}#{params[:ref]}\"}\n        format.xml  { head :error }\n      end\n    end\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/admin_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass AdminController < ApplicationController\n  layout 'admin'\n\n  before_filter :require_admin, :except => :user_stats\n  ssl_required :all\n\n  helper :sort\n  include SortHelper\n\n  def index\n    @no_configuration_data = Redmine::DefaultData::Loader::no_data?\n  end\n\n  def projects\n    @status = params[:status] ? params[:status].to_i : 1\n    c = ARCondition.new(@status == 0 ? \"status <> 0\" : [\"status = ?\", @status])\n\n    unless params[:name].blank?\n      name = \"%#{params[:name].strip.downcase}%\"\n      c << [\"LOWER(identifier) LIKE ? OR LOWER(name) LIKE ?\", name, name]\n    end\n\n    @projects = Project.find :all, :order => 'lft',\n                                   :conditions => c.conditions\n\n    render :action => \"projects\", :layout => false if request.xhr?\n  end\n\n  def plugins\n    @plugins = Redmine::Plugin.all\n  end\n\n  # Loads the default configuration\n  # (roles, trackers, statuses, workflow, enumerations)\n  def default_configuration\n    if request.post?\n      begin\n        Redmine::DefaultData::Loader::load(params[:lang])\n        flash.now[:success] = l(:notice_default_data_loaded)\n      rescue Exception => e\n        flash.now[:error] = l(:error_can_t_load_default_data, e.message)\n      end\n    end\n    redirect_to :action => 'index'\n  end\n\n  def test_email\n    raise_delivery_errors = ActionMailer::Base.raise_delivery_errors\n    # Force ActionMailer to raise delivery errors so we can catch it\n    ActionMailer::Base.raise_delivery_errors = true\n    begin\n      @test = Mailer.deliver_test(User.current)\n      flash.now[:success] = l(:notice_email_sent, User.current.mail)\n    rescue Exception => e\n      flash.now[:error] = l(:notice_email_error, e.message)\n    end\n    ActionMailer::Base.raise_delivery_errors = raise_delivery_errors\n    redirect_to :controller => 'settings', :action => 'edit', :tab => 'notifications'\n  end\n\n  def user_data_dump\n    @users = User.find(:all, :conditions => {:status => 1})\n    render :csv => @users\n  end\n\n  def info\n    @db_adapter_name = ActiveRecord::Base.connection.adapter_name\n    @checklist = [\n      [:text_default_administrator_account_changed, User.find(:first, :conditions => [\"login=? and hashed_password=?\", 'admin', User.hash_password('admin')]).nil?],\n      [:text_file_repository_writable, File.writable?(Attachment.storage_path)],\n      [:text_plugin_assets_writable, File.writable?(Engines.public_directory)],\n      [:text_rmagick_available, Object.const_defined?(:Magick)]\n    ]\n  end\nend\n"
  },
  {
    "path": "app/controllers/application_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nrequire 'uri'\nrequire 'cgi'\nrequire 'ruby-debug'\n\nclass ApplicationController < ActionController::Base\n  include Redmine::I18n\n  include LogActivityStreams\n\n  before_filter :set_user_ip\n\n  include SslRequirement\n  # don't require ssl in development\n  skip_before_filter :ensure_proper_protocol if Rails.env.development?\n\n  layout 'gooey'\n\n  # Remove broken cookie after upgrade from 0.8.x (#4292)\n  # See https://rails.lighthouseapp.com/projects/8994/tickets/3360\n  # TODO: remove it when Rails is fixed\n  before_filter :delete_broken_cookies\n  def delete_broken_cookies\n    if cookies['_redmine_session'] && cookies['_redmine_session'] !~ /--/\n      cookies.delete '_redmine_session'\n      redirect_to home_path\n      return false\n    end\n  end\n\n  before_filter :user_setup, :check_if_login_required, :set_localization\n  filter_parameter_logging :password\n  protect_from_forgery\n\n  rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token\n\n  include Redmine::Search::Controller\n  include Redmine::MenuManager::MenuController\n  helper Redmine::MenuManager::MenuHelper\n\n  def set_user_ip\n    session[:client_ip] = request.headers['X-Real-Ip'] unless session[:client_ip]\n  end\n\n  def user_setup\n    # Check the settings cache for each request\n    Setting.check_cache\n    # Find the current user\n    User.current = find_current_user\n  end\n\n  def redirect_with_flash(flash_type,msg,*params)\n    flash[flash_type] = msg\n    redirect_to(*params)\n  end\n\n  def current_user\n    User.current\n  end\n\n  # Returns the current user or nil if no user is logged in\n  # and starts a session if needed\n  def find_current_user\n    if session[:user_id]\n      # existing session\n      user = (User.active.find(session[:user_id]) rescue nil)\n      user\n    elsif cookies[:autologin] && Setting.autologin?\n      # auto-login feature starts a new session\n      user = User.try_to_autologin(cookies[:autologin])\n      session[:user_id] = user.id if user\n      Track.log(Track::LOGIN,session[:client_ip]) if user\n      user\n    elsif Setting.rest_api_enabled? && ['xml', 'json'].include?(params[:format]) && accept_key_auth_actions.include?(params[:action])\n      if params[:key].present?\n        # Use API key\n        User.find_by_api_key(params[:key])\n      else\n        # HTTP Basic, either username/password or API key/random\n        authenticate_with_http_basic do |username, password|\n          #TODO: track login here: Track.log(Track::LOGIN,session[:client_ip])\n          User.try_to_login(username, password) || User.find_by_api_key(username)\n        end\n      end\n    end\n  end\n\n  # Sets the logged in user\n  def logged_user=(user)\n    #resetting session, but keeping client_ip\n    ip = session[:client_ip] if session[:client_ip]\n    reset_session\n    session[:client_ip] = ip\n    if user && user.is_a?(User)\n      User.current = user\n      session[:user_id] = user.id\n    else\n      User.current = User.anonymous\n    end\n  end\n\n  # check if login is globally required to access the application\n  def check_if_login_required\n    # no check needed if user is already logged in\n    return true if User.current.logged?\n    require_login if Setting.login_required?\n  end\n\n  def set_localization\n    lang = nil\n    if User.current.logged?\n      lang = find_language(User.current.language)\n    end\n    lang ||= Setting.default_language\n    set_language_if_valid(lang)\n  end\n\n  def data_admin_logged_in?\n    return true if User.current == User.find_by_login(\"shereef\") || User.current == User.find_by_login(\"adelegb\") || User.current == User.find_by_login(\"crabari\")\n    return false\n  end\n\n  def require_login\n    if !User.current.logged?\n      # Extract only the basic url parameters on non-GET requests\n      if request.get?\n        url = url_for(params)\n      else\n        url = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id], :project_id => params[:project_id])\n      end\n      respond_to do |format|\n        format.html { redirect_to :controller => \"account\", :action => \"login\", :back_url => url }\n        format.xml { head :unauthorized }\n        format.json { head :unauthorized }\n      end\n      return false\n    end\n    true\n  end\n\n  def require_admin\n    return unless require_login\n    if !User.current.admin?\n      render_403\n      return false\n    end\n    true\n  end\n\n  def deny_access\n    User.current.logged? ? render_403 : require_login\n  end\n\n  # Authorize the user for the requested action\n  def authorize(ctrl = params[:controller], action = params[:action], global = false)\n    return true if params[:format] == \"png\"\n    allowed = User.current.allowed_to?({:controller => ctrl, :action => action}, @project, :global => global)\n    allowed ? true : deny_access\n  end\n\n  # Authorize the user for the requested action outside a project\n  def authorize_global(ctrl = params[:controller], action = params[:action], global = true)\n    authorize(ctrl, action, global)\n  end\n\n  # make sure that the user is a member of the project (or admin) if project is private\n  # used as a before_filter for actions that do not require any particular permission on the project\n  def check_project_privacy\n    if @project && @project.active?\n      if @project.is_public? || User.current.allowed_to_see_project?(@project) || User.current.admin?\n        true\n      else\n        User.current.logged? ? render_403 : require_login\n      end\n    else\n      @project = nil\n      render_404\n      false\n    end\n  end\n\n  def redirect_back_or_default(default)\n    back_url = CGI.unescape(params[:back_url].to_s)\n    if !back_url.blank? && !back_url.include?(\"/home/\") && !back_url.include?(\"/front/\")\n      begin\n        uri = URI.parse(back_url)\n\n        # do not redirect user to another host or to the login or register page\n        if (uri.relative? || (uri.host == request.host)) && !uri.path.match(%r{/(login|account/register)})\n          redirect_to(back_url)\n          return\n        end\n      rescue URI::InvalidURIError\n        # redirect to default\n      end\n    end\n    redirect_to default\n  end\n\n  def render_403\n    @project = nil\n    render :template => \"common/403\", :layout => (request.xhr? ? false : 'gooey'), :status => 403\n    return false\n  end\n\n  def render_404\n    render :template => \"common/404\", :layout => !request.xhr?, :status => 404\n    return false\n  end\n\n  def render_error(msg)\n    flash.now[:error] = msg\n    render :text => '', :layout => !request.xhr?, :status => 500\n  end\n\n  def render_message(msg)\n    flash.now[:notice] = msg\n    render :text => '', :layout => !request.xhr?\n  end\n\n  def invalid_authenticity_token\n    redirect_back_or_default(home_path)\n  end\n\n  def render_feed(items, options={})\n    @items = items || []\n    @items.sort! {|x,y| y.event_datetime <=> x.event_datetime }\n    @items = @items.slice(0, Setting.feeds_limit.to_i)\n    @title = options[:title] || Setting.app_title\n    render :template => \"common/feed.atom.rxml\", :layout => false, :content_type => 'application/atom+xml'\n  end\n\n  def self.accept_key_auth(*actions)\n    actions = actions.flatten.map(&:to_s)\n    write_inheritable_attribute('accept_key_auth_actions', actions)\n  end\n\n  def accept_key_auth_actions\n    self.class.read_inheritable_attribute('accept_key_auth_actions') || []\n  end\n\n  def attach_files_for_new_issue(issue,attachment_ids)\n    if attachment_ids\n      Attachment.update_all(\"container_id = #{issue.id}\" , \"id in (#{attachment_ids}) and container_id = 0\" )\n    end\n  end\n\n  # TODO: move to model\n  def attach_files(obj, attachments)\n    attached = []\n    unsaved = []\n    if attachments && attachments.is_a?(Hash)\n      attachments.each_value do |attachment|\n        file = attachment['file']\n        next unless file && file.size > 0\n        a = Attachment.create(:container => obj,\n                              :file => file,\n                              :description => attachment['description'].to_s.strip,\n                              :author => User.current)\n        a.new_record? ? (unsaved << a) : (attached << a)\n      end\n      if unsaved.any?\n        flash.now[:error] = l(:warning_attachments_not_saved, unsaved.size)\n      end\n    end\n    attached\n  end\n\n  def attach_temp_files(obj, attachments)\n    attached = []\n    unsaved = []\n    logger.info { \"attaching temp #{attachments.inspect}\" }\n    if attachments && attachments.is_a?(Hash)\n      attachments.each_value do |attachment|\n        logger.info { \"atatchment #{attachment}\" }\n        file = Tempfile.open(attachment)\n        next unless file && file.size > 0\n        a = Attachment.create(:container => obj,\n                              :file => file,\n                              :description => '',\n                              :author => User.current)\n        a.new_record? ? (unsaved << a) : (attached << a)\n      end\n      if unsaved.any?\n        flash.now[:error] = l(:warning_attachments_not_saved, unsaved.size)\n      end\n    end\n    attached\n  end\n\n  #replaces newline characters with more binary-compatible ones\n  def cleanup_newline(text)\n    return text unless text and !text.empty?\n    text.gsub(/\\r?\\n/, \"\\r\\n\")\n  end\n\n  # Same as Rails' simple_format helper without using paragraphs\n  def simple_format_without_paragraph(text)\n    text.to_s.\n      gsub(/\\r\\n?/, \"\\n\").                    # \\r\\n and \\r -> \\n\n      gsub(/\\n\\n+/, \"<br /><br />\").          # 2+ newline  -> 2 br\n      gsub(/([^\\n]\\n)(?=[^\\n])/, '\\1<br />')  # 1 newline   -> br\n  end\n\n  # Returns the number of objects that should be displayed\n  # on the paginated list\n  def per_page_option\n    per_page = nil\n    if params[:per_page] && Setting.per_page_options_array.include?(params[:per_page].to_s.to_i)\n      per_page = params[:per_page].to_s.to_i\n      session[:per_page] = per_page\n    elsif session[:per_page]\n      per_page = session[:per_page]\n    else\n      per_page = Setting.per_page_options_array.first || 25\n    end\n    per_page\n  end\n\n  # qvalues http header parser\n  # code taken from webrick\n  def parse_qvalues(value)\n    tmp = []\n    if value\n      parts = value.split(/,\\s*/)\n      parts.each {|part|\n        if m = %r{^([^\\s,]+?)(?:;\\s*q=(\\d+(?:\\.\\d+)?))?$}.match(part)\n          val = m[1]\n          q = (m[2] or 1).to_f\n          tmp.push([val, q])\n        end\n      }\n      tmp = tmp.sort_by{|val, q| -q}\n      tmp.collect!{|val, q| val}\n    end\n    return tmp\n  rescue\n    nil\n  end\n\n  # Returns a string that can be used as filename value in Content-Disposition header\n  def filename_for_content_disposition(name)\n    request.env['HTTP_USER_AGENT'] =~ %r{MSIE} ? ERB::Util.url_encode(name) : name\n  end\n\n  #breakpoint\n  def bp\n    debugger if ENV['RAILS_ENV'] == 'development'\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/attachments_controller.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nclass AttachmentsController < ApplicationController\n  before_filter :find_project, :except => :create\n  before_filter :read_authorize, :except => [:destroy, :create]\n  before_filter :delete_authorize, :only => :destroy\n  ssl_required :all\n\n  verify :method => :post, :only => :destroy\n\n  unloadable # Send unloadable so it will not be unloaded in development\n\n  before_filter :redirect_to_s3, :except => [:destroy, :create]\n\n\n  def create\n    logger.info { \"params #{params.inspect}\" }\n    if params[:file]\n      file = params[:file]\n      logger.info { \"file #{file.inspect}\" }\n      a = Attachment.create(:container_id => params[:container_id],\n                            :container_type => params[:container_type],\n                            :file => file,\n                            :author => User.current)\n      logger.info { \"created attachment #{a.inspect}\" }\n    end\n    logger.info {\"done with create\" }\n\n    render :json => a.to_json\n  end\n\n  def redirect_to_s3\n    if @attachment.container.is_a?(Project)\n      @attachment.increment_download\n    end\n    redirect_to(\"#{RedmineS3::Connection.uri}/#{@attachment.disk_filename}\")\n  end\n\n\n  def show\n    if @attachment.is_diff?\n      @diff = File.new(@attachment.diskfile, \"rb\").read\n      render :action => 'diff'\n    elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte\n      @content = File.new(@attachment.diskfile, \"rb\").read\n      render :action => 'file'\n    else\n      download\n    end\n  end\n\n  def download\n    if @attachment.container.is_a?(Project)\n      @attachment.increment_download\n    end\n\n    # images are sent inline\n    send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename),\n                                    :type => @attachment.content_type,\n                                    :disposition => (@attachment.image? ? 'inline' : 'attachment')\n  end\n\n  def destroy\n    # Make sure association callbacks are called\n    @attachment.container.attachments.delete(@attachment)\n    redirect_to :back\n  rescue ::ActionController::RedirectBackError\n    redirect_to :controller => 'projects', :action => 'show', :id => @project\n  end\n\n  private\n\n  def find_project\n    @attachment = Attachment.find(params[:id])\n    # Show 404 if the filename in the url is wrong\n    raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename\n    @project = @attachment.project\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  # Checks that the file exists and is readable\n  def file_readable\n    @attachment.readable? ? true : render_404\n  end\n\n  def read_authorize\n    @attachment.visible? ? true : deny_access\n  end\n\n  def delete_authorize\n    @attachment.deletable? ? true : deny_access\n  end\nend\n"
  },
  {
    "path": "app/controllers/auth_sources_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass AuthSourcesController < ApplicationController\n  layout 'admin'\n\n  before_filter :require_admin\n  ssl_required :all\n\n  def index\n    list\n    render :action => 'list' unless request.xhr?\n  end\n\n  # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)\n  verify :method => :post, :only => [ :destroy, :create, :update ],\n         :redirect_to => { :action => :list }\n\n  def list\n    @auth_source_pages, @auth_sources = paginate :auth_sources, :per_page => 10\n    render :action => \"list\", :layout => false if request.xhr?\n  end\n\n  def new\n    @auth_source = AuthSourceLdap.new\n  end\n\n  def create\n    @auth_source = AuthSourceLdap.new(params[:auth_source])\n    if @auth_source.save\n      flash.now[:success] = l(:notice_successful_create)\n      redirect_to :action => 'list'\n    else\n      render :action => 'new'\n    end\n  end\n\n  def edit\n    @auth_source = AuthSource.find(params[:id])\n  end\n\n  def update\n    @auth_source = AuthSource.find(params[:id])\n    if @auth_source.update_attributes(params[:auth_source])\n      flash.now[:success] = l(:notice_successful_update)\n      redirect_to :action => 'list'\n    else\n      render :action => 'edit'\n    end\n  end\n\n  def test_connection\n    @auth_method = AuthSource.find(params[:id])\n    begin\n      @auth_method.test_connection\n      flash.now[:success] = l(:notice_successful_connection)\n    rescue => text\n      flash.now[:error] = \"Unable to connect (#{text})\"\n    end\n    redirect_to :action => 'list'\n  end\n\n  def destroy\n    @auth_source = AuthSource.find(params[:id])\n    unless @auth_source.users.find(:first)\n      @auth_source.destroy\n      flash.now[:success] = l(:notice_successful_delete)\n    end\n    redirect_to :action => 'list'\n  end\nend\n"
  },
  {
    "path": "app/controllers/boards_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass BoardsController < ApplicationController\n  default_search_scope :messages\n  before_filter :find_project, :authorize\n  ssl_required :all\n\n  helper :messages\n  include MessagesHelper\n  helper :sort\n  include SortHelper\n  helper :watchers\n  include WatchersHelper\n\n  def index\n    @boards = @project.boards\n    # show the board if there is only one\n    if @boards.size == 1\n      @board = @boards.first\n      show\n    end\n  end\n\n  def show\n    respond_to do |format|\n      format.html {\n        sort_init 'updated_at', 'desc'\n        sort_update 'created_at' => \"#{Message.table_name}.created_at\",\n                    'replies' => \"#{Message.table_name}.replies_count\",\n                    'updated_at' => \"#{Message.table_name}.updated_at\"\n\n        @topic_count = @board.topics.count\n        @topic_pages = Paginator.new self, @topic_count, per_page_option, params['page']\n        @topics =  @board.topics.find :all, :order => [\"#{Message.table_name}.sticky DESC\", sort_clause].compact.join(', '),\n                                      :include => [:author, {:last_reply => :author}],\n                                      :limit  =>  @topic_pages.items_per_page,\n                                      :offset =>  @topic_pages.current.offset\n        @message = Message.new\n        render :action => 'show', :layout => !request.xhr?\n      }\n    end\n  end\n\n  verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :index }\n\n  def new\n    @board = Board.new(params[:board])\n    @board.project = @project\n    if request.post? && @board.save\n      flash.now[:success] = l(:notice_successful_create)\n      redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'boards'\n    end\n  end\n\n  def edit\n    if request.post? && @board.update_attributes(params[:board])\n      redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'boards'\n    end\n  end\n\n  def destroy\n    @board.destroy\n    redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'boards'\n  end\n\n  private\n\n  def find_project\n    @project = Project.find(params[:project_id])\n    render_message l(:text_project_locked) if @project.locked?\n    @board = @project.boards.find(params[:id]) if params[:id]\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\nend\n"
  },
  {
    "path": "app/controllers/comments_controller.rb",
    "content": "class CommentsController < ApplicationController\n  unloadable\n  before_filter :find_issue, :only => [:index, :create ]\n  before_filter :find_project, :authorize\n  ssl_required :all\n\n  log_activity_streams :current_user, :name, :updated, :@issue, :subject, :create, :issues, {\n            :object_description_method => :description,\n            :indirect_object => :@journal,\n            :indirect_object_description_method => :notes,\n            :indirect_object_phrase => '' }\n\n  def index\n    @journals = @issue.journals.find(:all,\n                                          :include => [:user, :details],\n                                          :order => \"#{Journal.table_name}.created_at DESC\",\n                                          :conditions => \"notes!=''\")\n  end\n\n  def create\n    @journal = @issue.init_journal(User.current, params[:comment])\n    @journal.save!\n    @journal.reload\n    @issue.reload\n    render :json => @issue.to_dashboard\n  end\n\n  private\n\n  def find_issue\n    @issue = Issue.find(params[:issue_id])\n  end\n\n  def find_project\n    @project = @issue.project\n  end\nend\n"
  },
  {
    "path": "app/controllers/credit_distributions_controller.rb",
    "content": "class CreditDistributionsController < ApplicationController\n  before_filter :require_admin\n  ssl_required :all\n\n\n  def index\n    @credit_distributions = CreditDistribution.all\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @credit_distributions }\n    end\n  end\n\n  def show\n    @credit_distribution = CreditDistribution.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @credit_distribution }\n    end\n  end\n\n  def new\n    @credit_distribution = CreditDistribution.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @credit_distribution }\n    end\n  end\n\n  def edit\n    @credit_distribution = CreditDistribution.find(params[:id])\n  end\n\n  def create\n    @credit_distribution = CreditDistribution.new(params[:credit_distribution])\n\n    respond_to do |format|\n      if @credit_distribution.save\n        flash.now[:success] = 'CreditDistribution was successfully created.'\n        format.html { redirect_to(@credit_distribution) }\n        format.xml  { render :xml => @credit_distribution, :status => :created, :location => @credit_distribution }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @credit_distribution.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @credit_distribution = CreditDistribution.find(params[:id])\n\n    respond_to do |format|\n      if @credit_distribution.update_attributes(params[:credit_distribution])\n        flash.now[:success] = 'CreditDistribution was successfully updated.'\n        format.html { redirect_to(@credit_distribution) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @credit_distribution.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @credit_distribution = CreditDistribution.find(params[:id])\n    @credit_distribution.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(credit_distributions_url) }\n      format.xml  { head :ok }\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/credit_transfers_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nclass CreditTransfersController < ApplicationController\n  ssl_required :all\n  before_filter :authorize_global, :except => :eligible_recipients\n\n  def index\n    @credit_transfers = CreditTransfer.find(:all, :conditions => \"sender_id = #{User.current.id} or recipient_id = #{User.current.id}\", :include => [:sender, :recipient, :project],:order => \"created_at DESC\")\n    project_id_array = Credit.find(:all,:conditions => {:settled_on => nil, :owner_id => User.current.id}).group_by(&:project_id).collect{|p| p[0]}\n    if project_id_array.empty?\n    else\n      @project_list = Project.find(:all, :conditions => \"id IN (#{project_id_array.join(\",\")})\").sort! {|x,y| x.name <=> y.name }\n      if params[:selected_project_id]\n        @selected_project_id = Integer(params[:selected_project_id])\n        @project = Project.find(@selected_project_id)\n        @total_credits = Credit.round(Credit.sum(:amount, :conditions => {:settled_on => nil, :owner_id => User.current.id, :project_id => @project.id}))\n        @user_list = @project.root.all_members\n        #remove current user from list\n        @user_list.delete_if { |a| a.user_id == User.current.id}\n\n      end\n    end\n  end\n\n  def create\n    recipient = User.find(params[:credit_transfer][:recipient_id])\n    project = Project.find(params[:credit_transfer][:project_id])\n\n    total_transferred = Credit.transfer User.current, recipient, project, Float(params[:amount]), params[:note]\n\n    respond_to do |format|\n      flash.now[:success] = \"Successfully transferred #{total_transferred} credits to #{recipient.name}\"\n      format.html { redirect_to :action => \"index\" }\n      flash.keep\n    end\n  rescue Exception => e\n    flash.now[:error] = l(:text_failed_to_transfer) + e.message\n    redirect_to :action => \"index\"\n    flash.keep\n  end\n\n\n  def eligible_recipients\n    @project = Project.find(params[:project_id])\n    @total_credits = Credit.round(Credit.sum(:amount, :conditions => {:settled_on => nil, :owner_id => User.current.id, :project_id => @project.id}))\n    @user_list = \"\"\n    @user_list = @project.root.all_members\n\n    #remove current user from list\n    @user_list.delete_if { |a| a.user_id == User.current.id}\n\n    render :partial => \"eligible_recipients\"\n  end\n\n\nend\n"
  },
  {
    "path": "app/controllers/credits_controller.rb",
    "content": "class CreditsController < ApplicationController\n\n  before_filter :require_admin, :except => [:disable, :enable]\n  before_filter :find_credit, :only => [:disable, :enable]\n  before_filter :self_authorize, :only => [:disable, :enable]\n  ssl_required :all\n\n\n  def index\n    @project = Project.find(params[:project_id]) unless params[:project_id].nil?\n\n    @credits = @project.credits\n    @active_credits = @credits.find_all{|credit| credit.enabled == true }.group_by{|credit| credit.owner_id}\n\n\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @credits }\n    end\n  end\n\n  def show\n    @credit = Credit.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @credit }\n    end\n  end\n\n  def new\n    @credit = Credit.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @credit }\n    end\n  end\n\n  def edit\n    @credit = Credit.find(params[:id])\n  end\n\n  def create\n    @credit = Credit.new(params[:credit])\n\n    respond_to do |format|\n      if @credit.save\n        flash.now[:success] = 'Credit was successfully created.'\n        format.html { redirect_to :controller => :projects, :id => @credit.project_id, :action => \"credits\" }\n        format.xml  { render :xml => @credit, :status => :created, :location => @credit }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @credit.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @credit = Credit.find(params[:id])\n\n    respond_to do |format|\n      if @credit.update_attributes(params[:credit])\n        flash.now[:success] = 'Credit was successfully updated.'\n        format.html { redirect_to :controller => :projects, :id => @credit.project_id, :action => \"credits\" }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @credit.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def disable\n    respond_to do |format|\n      if @credit.disable\n        format.html { redirect_to :controller => :projects, :id => @credit.project_id, :action => \"credits\" }\n        format.js do\n          update_credit_partials\n        end\n      else\n        format.html { redirect_to :controller => :projects, :id => @credit.project_id, :action => \"credits\" }\n        format.js do\n          render :update do |page|\n            page.call '$.jGrowl', 'Something went wrong. Couldn\\'t update record.'\n          end\n        end\n      end\n    end\n  end\n\n  def enable\n    respond_to do |format|\n      if @credit.enable\n        format.html { redirect_to :controller => :projects, :id => @credit.project_id, :action => \"credits\" }\n        format.js do\n          update_credit_partials\n        end\n      else\n        format.html { redirect_to :controller => :projects, :id => @credit.project_id, :action => \"credits\" }\n        format.js do\n          render :update do |page|\n            page.call '$.jGrowl', 'Something went wrong. Couldn\\'t update record.'\n          end\n        end\n      end\n    end\n  end\n\n  def update_credit_partials\n    @project = Project.find(params[:project_id])\n    @credits = @project.fetch_credits(params[:with_subprojects])\n    @active_credits = @credits.find_all{|credit| credit.enabled == true && credit.settled_on.nil? == true }.group_by{|credit| credit.owner_id}\n\n    render :update do |page|\n      page.replace_html \"my_credits_partial\", :partial => 'credits/my_credits'\n      page.replace_html \"credit_queue_partial\", :partial => 'credits/credit_queue'\n      page.replace_html \"credit_history_partial\", :partial => 'credits/credit_history'\n      page.replace_html \"active_credits_partial\", :partial => 'credits/credit_breakdown', :locals => {:group_credits => @active_credits, :title => l(:label_active_credits)}\n      page.visual_effect :highlight, \"q_#{@credit.id}\", :duration => 2\n      page.visual_effect :highlight, \"h_#{@credit.id}\", :duration => 2\n      page.visual_effect :highlight, \"m_#{@credit.id}\", :duration => 3\n    end\n  end\n\n  def destroy\n    @credit = Credit.find(params[:id])\n    @credit.destroy\n\n    respond_to do |format|\n      format.html { redirect_to :controller => :projects, :id => @credit.project_id, :action => \"credits\" }\n      format.xml  { head :ok }\n    end\n  end\n\n  private\n\n  def find_credit\n    @credit = Credit.find(params[:id])\n    rescue ActiveRecord::RecordNotFound\n      render_404\n  end\n\n  def self_authorize\n    if User.current.id != @credit.owner_id\n      render_403\n      return false\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/documents_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass DocumentsController < ApplicationController\n  default_search_scope :documents\n  before_filter :find_project, :only => [:index, :new]\n  before_filter :find_document, :except => [:index, :new]\n  before_filter :authorize\n  ssl_required :all\n\n  helper :attachments\n\n  log_activity_streams :current_user, :name, :added, :@document, :title, :new, :documents, {:object_description_method => :description}\n  log_activity_streams :current_user, :name, :updated, :@document, :title, :edit, :documents, {:object_description_method => :description}\n  log_activity_streams :current_user, :name, :deleted, :@document, :title, :destroy, :documents, {:object_description_method => :description}\n\n\n  def index\n    @sort_by = %w(catego»ry date title author).include?(params[:sort_by]) ? params[:sort_by] : 'title'\n    documents = @project.documents.find :all, :include => [:attachments]\n    case @sort_by\n    when 'date'\n      @grouped = documents.group_by {|d| d.updated_at.to_date }\n    when 'title'\n      @grouped = documents.group_by {|d| d.title.first.upcase}\n    when 'author'\n      @grouped = documents.select{|d| d.attachments.any?}.group_by {|d| d.attachments.last.author}\n    else\n      @grouped = documents.group_by {|d| d.updated_at.to_date }\n    end\n    @document = @project.documents.build\n    render :layout => false if request.xhr?\n  end\n\n  def show\n    @attachments = @document.attachments.find(:all, :order => \"created_at DESC\")\n  end\n\n  def new\n    @document = @project.documents.build(params[:document])\n    if request.post? and @document.save\n      attach_files(@document, params[:attachments])\n      flash.now[:success] = l(:notice_successful_create)\n      redirect_to :action => 'index', :project_id => @project\n    end\n  end\n\n  def edit\n    if request.post? and @document.update_attributes(params[:document])\n      flash.now[:success] = l(:notice_successful_update)\n      redirect_to :action => 'show', :id => @document\n    end\n  end\n\n  def destroy\n    @document.destroy\n    redirect_to :controller => 'documents', :action => 'index', :project_id => @project\n  end\n\n  def add_attachment\n    attachments = attach_files(@document, params[:attachments])\n    Mailer.deliver_attachments_added(attachments) if !attachments.empty? && Setting.notified_events.include?('document_added')\n    redirect_to :action => 'show', :id => @document\n  end\n\n  private\n\n  def find_project\n    @project = Project.find(params[:project_id])\n    render_message l(:text_project_locked) if @project.locked?\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def find_document\n    @document = Document.find(params[:id])\n    @project = @document.project\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\nend\n"
  },
  {
    "path": "app/controllers/email_updates_controller.rb",
    "content": "class EmailUpdatesController < ApplicationController\n  before_filter :require_login\n  ssl_required :all\n\n  def new\n    @email_update = EmailUpdate.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @invitation }\n    end\n  end\n\n  def create\n    @email_update = EmailUpdate.new(params[:email_update])\n    @email_update.user = User.current\n\n    respond_to do |format|\n      if @email_update.save\n        @email_update.send_activation\n        format.html { redirect_with_flash :success, \"Please check #{@email_update.mail} for the activation email\", {:controller => :my, :action => \"account\"}  }\n      else\n        flash.now[:error] = \"Couldn't create email update\"\n        format.html { render :action => \"new\" }\n      end\n    end\n  end\n\n  def activate\n    @email_update = EmailUpdate.find_by_token(params[:token])\n\n    if @email_update.nil?\n      redirect_with_flash :error, l(:error_bad_email_update), :controller => :my, :action => :account\n      return\n    end\n\n    @email_update.accept\n\n\n    redirect_with_flash :success, l(:text_email_updated), :controller => :my, :action => :account\n    return\n\n  rescue ActiveRecord::RecordNotFound\n    redirect_with_flash :error, l(:error_bad_email_update), :controller => :my, :action => :account\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/enterprises_controller.rb",
    "content": "class EnterprisesController < ApplicationController\n  ssl_required :all\n\n  def index\n    @enterprises = Enterprise.all\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @enterprises }\n    end\n  end\n\n  def show\n    @enterprise = Enterprise.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @enterprise }\n    end\n  end\n\n  def new\n    @enterprise = Enterprise.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @enterprise }\n    end\n  end\n\n  def edit\n    @enterprise = Enterprise.find(params[:id])\n  end\n\n  def create\n    @enterprise = Enterprise.new(params[:enterprise])\n\n    respond_to do |format|\n      if @enterprise.save\n        flash.now[:success] = 'Enterprise was successfully created.'\n        format.html { redirect_to(@enterprise) }\n        format.xml  { render :xml => @enterprise, :status => :created, :location => @enterprise }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @enterprise.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @enterprise = Enterprise.find(params[:id])\n\n    respond_to do |format|\n      if @enterprise.update_attributes(params[:enterprise])\n        flash.now[:success] = 'Enterprise was successfully updated.'\n        format.html { redirect_to(@enterprise) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @enterprise.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @enterprise = Enterprise.find(params[:id])\n    @enterprise.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(enterprises_url) }\n      format.xml  { head :ok }\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/enumerations_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass EnumerationsController < ApplicationController\n  layout 'admin'\n\n  before_filter :require_admin\n  ssl_required :all\n\n  def index\n    list\n    render :action => 'list'\n  end\n\n  # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)\n  verify :method => :post, :only => [ :destroy, :create, :update ],\n         :redirect_to => { :action => :list }\n\n  def list\n  end\n\n  def new\n    begin\n      @enumeration = params[:type].constantize.new\n    rescue NameError\n      @enumeration = Enumeration.new\n    end\n  end\n\n  def create\n    @enumeration = Enumeration.new(params[:enumeration])\n    @enumeration.type = params[:enumeration][:type]\n    if @enumeration.save\n      flash.now[:success] = l(:notice_successful_create)\n      redirect_to :action => 'list', :type => @enumeration.type\n    else\n      render :action => 'new'\n    end\n  end\n\n  def edit\n    @enumeration = Enumeration.find(params[:id])\n  end\n\n  def update\n    @enumeration = Enumeration.find(params[:id])\n    @enumeration.type = params[:enumeration][:type] if params[:enumeration][:type]\n    if @enumeration.update_attributes(params[:enumeration])\n      flash.now[:success] = l(:notice_successful_update)\n      redirect_to :action => 'list', :type => @enumeration.type\n    else\n      render :action => 'edit'\n    end\n  end\n\n  def destroy\n    @enumeration = Enumeration.find(params[:id])\n    if !@enumeration.in_use?\n      # No associated objects\n      @enumeration.destroy\n      redirect_to :action => 'index'\n    elsif params[:reassign_to_id]\n      if reassign_to = Enumeration.find_by_type_and_id(@enumeration.type, params[:reassign_to_id])\n        @enumeration.destroy(reassign_to)\n        redirect_to :action => 'index'\n      end\n    end\n    @enumerations = Enumeration.find(:all, :conditions => ['type = (?)', @enumeration.type]) - [@enumeration]\n  end\nend\n"
  },
  {
    "path": "app/controllers/help_controller.rb",
    "content": "class HelpController < ApplicationController\n  def show\n    @help_key = params[:key]\n  end\nend\n"
  },
  {
    "path": "app/controllers/help_sections_controller.rb",
    "content": "class HelpSectionsController < ApplicationController\n  before_filter :authorize, :except => :dont_show\n  ssl_required :all\n\n  def show\n\n    respond_to do |format|\n      if @help_section.show\n        format.html\n        format.xml  { render :xml => @help_section }\n      else\n        format.html { render :nothing => true}\n      end\n    end\n  end\n\n  def dont_show\n    @help_section = HelpSection.find(params[:id])\n    @help_section.show = false\n    @help_section.save\n    respond_to do |wants|\n      wants.js { render :update do |page|\n                    page.replace \"help_section\", \"\"\n                  end\n          }\n    end\n  end\n\n  def new\n    @help_section = HelpSection.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @help_section }\n    end\n  end\n\n  def edit\n    @help_section = HelpSection.find(params[:id])\n  end\n\n  def create\n    @help_section = HelpSection.new(params[:help_section])\n\n    respond_to do |format|\n      if @help_section.save\n        flash.now[:success] = 'HelpSection was successfully created.'\n        format.html { redirect_to(@help_section) }\n        format.xml  { render :xml => @help_section, :status => :created, :location => @help_section }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @help_section.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @help_section = HelpSection.find(params[:id])\n\n    respond_to do |format|\n      if @help_section.update_attributes(params[:help_section])\n        flash.now[:success] = 'HelpSection was successfully updated.'\n        format.html { redirect_to(@help_section) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @help_section.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @help_section = HelpSection.find(params[:id])\n    @help_section.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(help_sections_url) }\n      format.xml  { head :ok }\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/home_controller.rb",
    "content": "class HomeController < ApplicationController\n  ssl_required :index\n  layout 'static'\n  def index\n    if User.current.logged?\n      redirect_to :controller => 'welcome', :action => 'index'\n    else\n      redirect_to \"/front/index.html\"\n    end\n  end\n\n  def show\n    render :action => params[:page]\n  end\n\n  def robots\n    @projects = Project.all_public.active\n    render :layout => false, :content_type => 'text/plain'\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/hourly_types_controller.rb",
    "content": "class HourlyTypesController < ApplicationController\n  before_filter :find_project\n  ssl_required :all\n\n  def new\n    @hourly_type = HourlyType.new(params[:hourly_type])\n    @hourly_type.project = @project\n    if request.post? && @hourly_type.save\n      flash.now[:success] = l(:notice_successful_create)\n      redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'hourly_types'\n    end\n  end\n\n  def edit\n    if request.post? && @hourly_type.update_attributes(params[:hourly_type])\n      redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'hourly_types'\n    end\n  end\n\n  def destroy\n    @hourly_type.destroy\n    redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'hourly_types'\n  end\n\n  private\n\n  def find_project\n    @project = Project.find(params[:project_id])\n    @hourly_type = @project.hourly_types.find(params[:id]) if params[:id]\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\nend\n"
  },
  {
    "path": "app/controllers/invitations_controller.rb",
    "content": "class InvitationsController < ApplicationController\n  before_filter :find_project, :except => :accept\n  before_filter :authorize, :except => :accept\n  ssl_required :all\n\n  def index\n    @all_invites, @invitations = paginate :invitations,\n                                   :per_page => 30,\n                                   :conditions => {:user_id => User.current.id, :project_id => @project.id},\n                                   :order => \"created_at DESC\"\n\n    respond_to do |format|\n      format.html { render :layout => false if request.xhr? }\n      format.xml  { render :xml => @invitations.to_xml }\n      format.json { render :json => @invitation.to_json }\n    end\n  end\n\n  def show\n    @invitation = Invitation.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @invitation }\n    end\n  end\n\n  def new\n    unless @project.root?\n      render_error(\"Project is not root. No invitations needed here.\")\n      return\n    end\n\n    @note = l(:text_invitation_note_default, {:user => User.current.name, :project => @project.name})\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @invitation }\n    end\n  end\n\n  def edit\n    @invitation = Invitation.find(params[:id])\n  end\n\n  def create\n\n    #can't invite someone to anything other than contributor if you're not admin\n    if params[:invitation][:role_id] != Role.contributor.id.to_s && !User.current.admin_of?(@project)\n      render_403\n      return\n    end\n\n    success = false\n    @emails = params[:emails]\n    @email_array = @emails.gsub(/\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b/i) {|s| s}.collect\n    @email_array.uniq!\n\n    @email_array.each do |email|\n        @email_array.delete email unless valid_email?(email)\n    end\n\n    @email_array.each do |email|\n      @invitation = Invitation.new(params[:invitation])\n      @invitation.mail = TMail::Address.parse(email).to_s\n      @invitation.project_id = @project.id\n      @invitation.user_id = User.current.id\n      if @invitation.save\n        @invitation.deliver(simple_format_without_paragraph(params[:note]))\n        success = true\n      end\n    end\n\n    respond_to do |format|\n      if success\n        @emails = nil\n        @note = params[:note]\n        @roles = Role.find(:all, :conditions => {:level => 1}, :order => \"position DESC\")\n\n        flash.now[:success] = \"#{@email_array.length} invitation(s)  successfully sent to<br>\" + @email_array.join(\", \")\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @invitation, :status => :created, :location => @invitation }\n      else\n        flash.now[:error] = \"Failed to send invitations. Make sure emails are properly formatted, and are each on a seperate line\"\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @invitation.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def accept\n    @invitation = Invitation.find(params[:id])\n\n    if @invitation.token != params[:token] || @invitation.status != Invitation::PENDING\n      redirect_with_flash :error, l(:error_old_invite), :controller => :projects, :action => :show, :id => @invitation.project_id\n      return\n    end\n\n    if @invitation.new_mail && !@invitation.new_mail.empty?\n      @user = User.find_by_mail(@invitation.new_mail)\n    else\n      @user = User.find_by_mail(@invitation.mail)\n    end\n\n    respond_to do |wants|\n      wants.html {\n        if @user && !@user.anonymous?\n          self.logged_user = @user\n          Track.log(Track::LOGIN,request.env['REMOTE_ADDR'])\n          @invitation.accept\n          msg = \"Invitation accepted. You are now a #{@invitation.role.name} of #{@invitation.project.name}.\"\n          redirect_with_flash :success, msg, :controller => :projects, :action => :show, :id => @invitation.project_id\n          return\n        else\n          session[:invitation] = @invitation.token\n          redirect_to :controller => :account, :action => :register, :invitation_token => @invitation.token\n        end\n        }\n    end\n  end\n\n  def resend\n    @invitation = Invitation.find(params[:id])\n\n    respond_to do |format|\n      if @invitation.resend(params[:note])\n        logger.info { \"1\" }\n\n        format.js do\n          logger.info { \"format\" }\n\n          render :update do |page|\n            logger.info { \"ID BABY #{@invitation.id}\" }\n            page.visual_effect :highlight, \"row-#{@invitation.id}\", :duration => 3\n            page.replace \"resend-#{@invitation.id}\", \"Resent!\"\n            page.call '$.jGrowl', l(:notice_successful_update)\n          end\n        end\n      else\n        format.js do\n          render :update do |page|\n            page.parent.call '$.jGrowl', l(:error_general)\n          end\n        end\n      end\n    end\n  end\n\n  def destroy\n    @invitation = Invitation.find(params[:id])\n    @invitation.destroy\n\n    respond_to do |format|\n      format.js do\n        render :update do |page|\n          page.visual_effect :highlight, \"row-#{@invitation.id}\", :duration => 3\n          page.remove \"row-#{@invitation.id}\"\n          page.call '$.jGrowl', l(:notice_successful_delete)\n        end\n      end\n    end\n  end\n\n  private\n\n  def find_project\n    @project = Project.find(params[:project_id])\n    render_message l(:text_project_locked) if @project.locked?\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def valid_email?(email)\n    TMail::Address.parse(email)\n    return true\n  rescue\n    return false\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/issue_invitations_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass IssueInvitationsController < ApplicationController\n  def new\n    @quote = Quote.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @quote }\n    end\n  end\n\n  def create\n    @quote = Quote.new(params[:quote])\n    @quote.user_id = User.current.id\n\n    respond_to do |format|\n      flash.now[:success] = 'Invitation was successfully created and sent'\n      format.html { redirect_to(@quote) }\n      format.xml  { render :xml => @quote, :status => :created, :location => @quote }\n    end\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/issue_relations_controller.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\n\nclass IssueRelationsController < ApplicationController\n  before_filter :find_project, :authorize\n  ssl_required :all\n\n  def new\n    @relation = IssueRelation.new(params[:relation])\n    @relation.issue_from = @issue\n    if params[:relation] && !params[:relation][:issue_to_id].blank?\n      @relation.issue_to = Issue.visible.find_by_id(params[:relation][:issue_to_id])\n    end\n    @relation.save if request.post?\n    respond_to do |format|\n      format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }\n      format.js do\n        render :update do |page|\n          page.replace_html \"relations\", :partial => 'issues/relations'\n          if @relation.errors.empty?\n            page << \"$('relation_delay').value = ''\"\n            page << \"$('relation_issue_to_id').value = ''\"\n          end\n        end\n      end\n    end\n  end\n\n  def destroy\n    relation = IssueRelation.find(params[:id])\n    if request.post? && @issue.relations.include?(relation)\n      relation.destroy\n      @issue.reload\n    end\n    respond_to do |format|\n      format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }\n      format.js { render(:update) {|page| page.replace_html \"relations\", :partial => 'issues/relations'} }\n    end\n  end\n\n  private\n\n  def find_project\n    @issue = Issue.find(params[:issue_id])\n    @project = @issue.project\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/issue_statuses_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass IssueStatusesController < ApplicationController\n  layout 'admin'\n\n  before_filter :require_admin\n  ssl_required :all\n\n  verify :method => :post, :only => [ :destroy, :create, :update, :move ],\n         :redirect_to => { :action => :list }\n\n  def index\n    list\n    render :action => 'list' unless request.xhr?\n  end\n\n  def list\n    @issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => \"position\"\n    render :action => \"list\", :layout => false if request.xhr?\n  end\n\n  def new\n    @issue_status = IssueStatus.new\n  end\n\n  def create\n    @issue_status = IssueStatus.new(params[:issue_status])\n    if @issue_status.save\n      flash.now[:success] = l(:notice_successful_create)\n      redirect_to :action => 'list'\n    else\n      render :action => 'new'\n    end\n  end\n\n  def edit\n    @issue_status = IssueStatus.find(params[:id])\n  end\n\n  def update\n    @issue_status = IssueStatus.find(params[:id])\n    if @issue_status.update_attributes(params[:issue_status])\n      flash.now[:success] = l(:notice_successful_update)\n      redirect_to :action => 'list'\n    else\n      render :action => 'edit'\n    end\n  end\n\n  def destroy\n    IssueStatus.find(params[:id]).destroy\n    redirect_to :action => 'list'\n  rescue\n    flash.now[:error] = \"Unable to delete issue status\"\n    redirect_to :action => 'list'\n  end\nend\n"
  },
  {
    "path": "app/controllers/issue_votes_controller.rb",
    "content": "class IssueVotesController < ApplicationController\n  ssl_required :all\n\n  def index\n    @issue_votes = IssueVote.all\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @issue_votes }\n    end\n  end\n\n  def show\n    @issue_vote = IssueVote.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @issue_vote }\n    end\n  end\n\n  def new\n    @issue_vote = IssueVote.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @issue_vote }\n    end\n  end\n\n  def edit\n    @issue_vote = IssueVote.find(params[:id])\n  end\n\n  def create\n    @issue_vote = IssueVote.new(params[:issue_vote])\n\n    respond_to do |format|\n      if @issue_vote.save\n        flash.now[:success] = 'IssueVote was successfully created.'\n        format.html { redirect_to(@issue_vote) }\n        format.xml  { render :xml => @issue_vote, :status => :created, :location => @issue_vote }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @issue_vote.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @issue_vote = IssueVote.find(params[:id])\n\n    respond_to do |format|\n      if @issue_vote.update_attributes(params[:issue_vote])\n        flash.now[:success] = 'IssueVote was successfully updated.'\n        format.html { redirect_to(@issue_vote) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @issue_vote.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @issue_vote = IssueVote.find(params[:id])\n    @issue_vote.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(issue_votes_url) }\n      format.xml  { head :ok }\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/issues_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass IssuesController < ApplicationController\n  menu_item :new_issue, :only => :new\n  default_search_scope :issues\n  ssl_required :all\n\n  # BUGBUG: :disagree and :reject don't seem to be used anymore\n  before_filter :find_issue, :only => [:show, :edit, :reply, :start, :finish, :release, :cancel, :restart, :prioritize, :agree, :disagree, :accept, :reject, :estimate, :join, :leave, :add_team_member, :remove_team_member, :move, :update_tags]\n  before_filter :find_issues, :only => [:bulk_edit, :move, :destroy]\n  before_filter :find_project, :only => [:new, :update_form, :preview]\n  before_filter :authorize, :except => [:index, :changes, :gantt, :calendar, :preview, :context_menu, :datadump, :temp]\n  before_filter :find_optional_project, :only => [:index, :changes, :gantt, :calendar]\n  accept_key_auth :index, :show, :changes\n\n  rescue_from Query::StatementInvalid, :with => :query_statement_invalid\n\n  helper :journals\n  helper :projects\n  include ProjectsHelper\n  helper :issue_relations\n  include IssueRelationsHelper\n  helper :watchers\n  include WatchersHelper\n  helper :attachments\n  include AttachmentsHelper\n  helper :queries\n  helper :sort\n  include SortHelper\n  include IssuesHelper\n  include Redmine::Export::PDF\n\n  verify :method => :post,\n         :only => :destroy,\n         :render => { :nothing => true, :status => :method_not_allowed}\n\n  log_activity_streams :current_user, :name, :added, :@issue, :subject, :new, :issues, {:object_description_method => :description}\n  log_activity_streams :current_user, :name, :finished, :@issue, :subject, :finish, :issues, {\n    :object_description_method => :description,\n    :indirect_object => :@journal,\n    :indirect_object_description_method => :notes,\n    :indirect_object_phrase => '' }\n\n  log_activity_streams :current_user, :name, :started, :@issue, :subject, :start, :issues, {:object_description_method => :description}\n  log_activity_streams :current_user, :name, :gave_up_on, :@issue, :subject, :release, :issues, {:object_description_method => :description}\n  log_activity_streams :current_user, :name, :canceled, :@issue, :subject, :cancel, :issues, {\n    :object_description_method => :description,\n    :indirect_object => :@journal,\n    :indirect_object_description_method => :notes,\n    :indirect_object_phrase => '' }\n  log_activity_streams :current_user, :name, :joined, :@issue, :subject, :join, :issues, {:object_description_method => :description}\n  log_activity_streams :current_user, :name, :left, :@issue, :subject, :leave, :issues, {:object_description_method => :description}\n  log_activity_streams :current_user, :name, :updated, :@issue, :subject, :edit, :issues,{\n    :object_description_method => :description,\n    :indirect_object => :@journal,\n    :indirect_object_description_method => :notes,\n    :indirect_object_phrase => 'GENERATEDETAILS' } #special value generates details for each property change\n\n  log_activity_streams :current_user, :name, :restarted, :@issue, :subject, :restart, :issues, {}\n\n  def index\n    retrieve_query\n    sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria)\n    sort_update({'id' => \"#{Issue.table_name}.id\"}.merge(@query.available_columns.inject({}) {|h, c| h[c.name.to_s] = c.sortable; h}))\n\n    if @query.valid?\n      limit = per_page_option\n      respond_to do |format|\n        format.html { }\n        format.csv  { limit = Setting.issues_export_limit.to_i }\n        format.pdf  { limit = Setting.issues_export_limit.to_i }\n      end\n\n      @issue_count = @query.issue_count\n      @issue_pages = Paginator.new self, @issue_count, limit, params['page']\n      @issues = @query.issues(:include => [:assigned_to, :tracker],\n                              :order => sort_clause,\n                              :offset => @issue_pages.current.offset,\n                              :limit => limit)\n      @issue_count_by_group = @query.issue_count_by_group\n\n      respond_to do |format|\n        format.html { render :template => 'issues/index.html.erb', :layout => !request.xhr? }\n        format.csv  { send_data(issues_to_csv(@issues, @project), :type => 'text/csv; header=present', :filename => 'export.csv') }\n        format.pdf  { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }\n      end\n    else\n      # Send html if the query is not valid\n      render(:template => 'issues/index.html.erb', :layout => !request.xhr?)\n    end\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def show\n    @journals = @issue.journals.find(:all, :include => [:user, :details], :order => \"#{Journal.table_name}.created_at ASC\")\n    @journals.each_with_index {|j,i| j.indice = i+1}\n    @journals.reverse! if User.current.wants_comments_in_reverse_order?\n    @edit_allowed = true\n    @edit_allowed = @issue.editable? && User.current.allowed_to?(:edit_issues, @project)\n\n    respond_to do |format|\n      format.html { render :template => 'issues/show.html.erb', :layout => 'issue_blank' }\n      format.pdf  { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => \"#{@project.identifier}-#{@issue.id}.pdf\") }\n    end\n  end\n\n  # Add a new issue\n  # The new issue will be created from an existing one if copy_from parameter is given\n  def new\n    @issue = Issue.new\n    @issue.copy_from(params[:copy_from]) if params[:copy_from]\n    @issue.project = @project\n    @issue.tracker ||= Tracker.find(params[:tracker_id] || :first || params[:issue][:tracker_id])\n    if @issue.tracker.nil?\n      render_error l(:error_no_tracker_in_project)\n      return\n    end\n    if params[:issue].is_a?(Hash)\n      @issue.attributes = params[:issue]\n      @issue.watcher_user_ids = params[:issue]['watcher_user_ids'] if User.current.allowed_to?(:add_issue_watchers, @project)\n    end\n    @issue.author = User.current\n\n\n    default_status = IssueStatus.default\n    unless default_status\n      render_error l(:error_no_default_issue_status)\n      return\n    end\n    @issue.status = default_status\n    @allowed_statuses = ([default_status] + default_status.find_new_statuses_allowed_to(User.current.roles_for_project(@project), @issue.tracker)).uniq\n\n    if request.get?\n      @issue.start_date ||= Date.today\n    else\n      if params[:issue].nil? || params[:issue][:status_id].nil?\n        requested_status = default_status\n      else\n        requested_status = IssueStatus.find_by_id(params[:issue][:status_id])\n      end\n\n      @issue.status = requested_status\n      @issue.tag_list = @issue.tags_copy if @issue.tags_copy\n\n      if @issue.save\n        Mention.parse(@issue, User.current.id)\n        attach_files_for_new_issue(@issue, params[:attachments])\n\n        #adding self-agree vote\n        @iv = IssueVote.create :issue_id => @issue.id, :user_id => User.current.id, :points => 1, :vote_type => IssueVote::AGREE_VOTE_TYPE\n        @issue.update_agree_total @iv.isbinding\n\n        #dealing with the estimate\n        if params[:estimate] && params[:estimate] != \"\"  #-2 means that nothing was chosen\n          @iv = IssueVote.create :issue_id => @issue.id, :user_id => User.current.id, :points => params[:estimate].to_i, :vote_type => IssueVote::ESTIMATE_VOTE_TYPE\n          @issue.update_estimate_total @iv.isbinding\n        end\n\n        #dealing with prioritizing\n        if params[:prioritize] == \"true\"\n          @iv = IssueVote.create :issue_id => @issue.id, :user_id => User.current.id, :points => 1, :vote_type => IssueVote::PRI_VOTE_TYPE\n          @issue.update_pri_total @iv.isbinding\n        end\n\n        @issue.save if !@issue.update_status\n\n        @issue.reload\n\n        respond_to do |format|\n          format.js {render :json => @issue.to_dashboard}\n          format.html {redirect_to(params[:continue] ? { :action => 'new', :tracker_id => @issue.tracker } :\n                                        { :action => 'show', :id => @issue })}\n        end\n        return\n      else\n        respond_to do |format|\n          format.js {render :text => nil}\n          format.html { render :action => \"new\" }\n        end\n        return\n      end\n    end\n\n    render :layout => !request.xhr?\n  end\n\n  # Attributes that can be updated on workflow transition (without :edit permission)\n  # TODO: make it configurable (at least per role)\n  UPDATABLE_ATTRS_ON_TRANSITION = %w(status_id assigned_to_id done_ratio) unless const_defined?(:UPDATABLE_ATTRS_ON_TRANSITION)\n\n  def edit\n    @allowed_statuses = @issue.new_statuses_allowed_to(User.current)\n    @edit_allowed = @issue.editable? && User.current.allowed_to?(:edit_issues, @project)\n\n    @notes = params[:notes]\n    @journal = @issue.init_journal(User.current, @notes)\n    # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed\n    if (@edit_allowed || !@allowed_statuses.empty?) && params[:issue]\n      attrs = params[:issue].dup\n      attrs.delete_if {|k,v| !UPDATABLE_ATTRS_ON_TRANSITION.include?(k) } unless @edit_allowed\n      attrs.delete(:status_id) unless @allowed_statuses.detect {|s| s.id.to_s == attrs[:status_id].to_s}\n      @issue.attributes = attrs\n    end\n\n    if request.post?\n      attachments = attach_files(@issue, params[:attachments])\n      attachments.each {|a| @journal.details << JournalDetail.new(:property => 'attachment', :prop_key => a.id, :value => a.filename)}\n\n      if @issue.save\n        Mention.parse(@issue, User.current.id)\n\n        @issue.reload\n        respond_to do |format|\n          format.js {render :json => @issue.to_dashboard}\n          format.html {redirect_to(params[:back_to] || {:action => 'show', :id => @issue})}\n        end\n      end\n    end\n  rescue ActiveRecord::StaleObjectError\n    # Optimistic locking exception\n    flash.now[:error] = l(:notice_locking_conflict)\n    # Remove the previously added attachments if issue was not updated\n    attachments.each(&:destroy)\n  end\n\n  def start\n    @in_progress = Issue.count(:conditions => {:assigned_to_id => User.current.id, :status_id => IssueStatus.assigned.id, :project_id => @issue.project_id})\n    if @in_progress >= Setting::MAXIMUM_CONCURRENT_REQUESTS\n      render_error \"Maximum issues owned by this user already\"\n      return false;\n    else\n      IssueVote.create :user_id => User.current.id, :issue_id => params[:id], :vote_type => IssueVote::JOIN_VOTE_TYPE, :points => 1 #Joins as first person on the team\n      IssueVote.delete_all :issue_id => params[:id], :vote_type => IssueVote::ACCEPT_VOTE_TYPE\n      params[:issue] = {:status_id => IssueStatus.assigned.id, :assigned_to_id => User.current.id}\n      change_status\n    end\n  end\n\n  def finish\n    params[:issue] = {:status_id => IssueStatus.done.id}\n    @iv = IssueVote.create :user_id => User.current.id, :issue_id => @issue.id, :vote_type => IssueVote::ACCEPT_VOTE_TYPE, :points => 1 #adding accept vote for user who finished the issue\n    @issue.update_accept_total  @iv.isbinding\n    @issue.clone_recurring if @issue.tracker.recurring?\n    @issue.set_points_from_hourly if @issue.is_hourly? #an hourly item is done, we set the\n    change_status\n  end\n\n  def release\n    if(@issue.is_hourly?)\n      params[:issue] = {:status_id => IssueStatus.newstatus.id, :assigned_to_id => ''}\n    else\n      #Deleting current user from issue\n      IssueVote.delete_all([\"user_id = ? AND issue_id = ? AND vote_type = ?\", User.current.id, params[:id], IssueVote::JOIN_VOTE_TYPE])\n\n      #Check to see if anybody else is on the issue, if they are assign the issue to them\n      next_team_member = @issue.team_members.first\n      if next_team_member.nil?\n        new_status_id = IssueStatus.open.id\n        params[:issue] = {:status_id => IssueStatus.open.id, :assigned_to_id => ''}\n      else\n        params[:issue] = {:assigned_to_id => next_team_member.id}\n      end\n    end\n\n    change_status\n  end\n\n  def cancel\n    params[:issue] = {:status_id => IssueStatus.canceled.id}\n    change_status\n  end\n\n  def restart\n    params[:issue] = {:status_id => IssueStatus.newstatus.id}\n    change_status\n  end\n\n  def change_status\n      @notes = params[:notes]\n      @journal = @issue.init_journal(User.current, @notes)\n\n        attrs = params[:issue].dup\n        @issue.attributes = attrs\n\n      if @issue.save\n        respond_to do |format|\n          @issue.reload\n          format.js {render :json => @issue.to_dashboard}\n          format.html {redirect_to(params[:back_to] || {:action => 'show', :id => @issue})}\n        end\n      end\n    rescue ActiveRecord::StaleObjectError\n      # Optimistic locking exception\n      flash.now[:error] = l(:notice_locking_conflict)\n  end\n\n  def prioritize\n    @iv = IssueVote.create :user_id => User.current.id, :issue_id => params[:id], :vote_type => IssueVote::PRI_VOTE_TYPE, :points => params[:points]\n    @issue.update_pri_total @iv.isbinding\n    @issue.save\n    @issue.reload\n    respond_to do |format|\n      format.js {render :json => @issue.to_dashboard}\n      format.html {redirect_to(params[:back_to] || {:action => 'show', :id => @issue})}\n    end\n  end\n\n  def update_tags\n    @issue.send_later(:update_tags,params[:tags])\n\n    respond_to do |format|\n      format.js {render :nothing => true}\n      format.html {redirect_to(params[:back_to] || {:action => 'show', :id => @issue})}\n    end\n  end\n\n\n  def estimate\n    if(@issue.is_hourly?)\n      render_error 'Can not estimate hourly items'\n      return false;\n    end\n\n    @journal = @issue.init_journal(User.current, params[\"notes\"])\n\n    @iv = IssueVote.create :user_id => User.current.id, :issue_id => params[:id], :vote_type => IssueVote::ESTIMATE_VOTE_TYPE, :points => params[:points]\n    logger.info { \"before update #{@issue.inspect}\" }\n    @issue.update_estimate_total @iv.isbinding\n    logger.info { \"after update #{@issue.inspect}\" }\n    logger.info { \"start saving\" }\n    @issue.save if !@issue.update_status\n    logger.info { \"done saving #{@issue.inspect}\" }\n    @issue.reload\n\n    respond_to do |format|\n      format.js {render :json => @issue.to_dashboard}\n      format.html {redirect_to(params[:back_to] || {:action => 'show', :id => @issue})}\n    end\n  end\n\n\n  def agree\n    @iv = IssueVote.create :user_id => User.current.id, :issue_id => params[:id], :vote_type => IssueVote::AGREE_VOTE_TYPE, :points => params[:points]\n    journal = @issue.init_journal(User.current, params[:notes]) if params[:notes]\n    @issue.update_agree_total @iv.isbinding\n    @issue.save if !@issue.update_status\n    @issue.reload\n\n    if params[:notes]\n      action = :updated\n      logger.info { \"action is #{params[:points]}\" }\n      case params[:points]\n      when \"-1\"\n        action = \"voted against\"\n      when \"-9999\"\n        action = :blocked\n      end\n\n      LogActivityStreams.write_single_activity_stream(User.current,:name,@issue,:subject,action,:issues, 0, journal,{\n          :indirect_object_description_method => :notes,\n          :indirect_object_phrase => 'GENERATEDETAILS' })\n    end\n\n    respond_to do |format|\n      format.js {render :json => @issue.to_dashboard}\n      format.html {redirect_to(params[:back_to] || {:action => 'show', :id => @issue})}\n    end\n  end\n\n\n  def accept\n    @iv = IssueVote.create :user_id => User.current.id, :issue_id => params[:id], :vote_type => IssueVote::ACCEPT_VOTE_TYPE, :points => params[:points]\n    journal = @issue.init_journal(User.current, params[:notes]) if params[:notes]\n    @issue.update_accept_total  @iv.isbinding\n    @issue.save if !@issue.update_status\n    @issue.reload\n\n    if params[:notes]\n      action = :updated\n      logger.info { \"action is #{params[:points]}\" }\n      case params[:points]\n      when \"-1\"\n        action = :rejected\n      when \"-9999\"\n        action = \"blocked acceptance of\"\n      end\n\n      LogActivityStreams.write_single_activity_stream(User.current,:name,@issue,:subject,action,:issues, 0, journal,{\n          :indirect_object_description_method => :notes,\n          :indirect_object_phrase => 'GENERATEDETAILS' })\n    end\n\n\n    respond_to do |format|\n      format.js {render :json => @issue.to_dashboard}\n      format.html {redirect_to(params[:back_to] || {:action => 'show', :id => @issue})}\n    end\n  end\n\n  def join\n    IssueVote.create :user_id => User.current.id, :issue_id => params[:id], :vote_type => IssueVote::JOIN_VOTE_TYPE, :points => 1\n    @issue.save\n    @issue.reload\n\n    Notification.create :recipient_id => @issue.assigned_to_id,\n                        :variation => 'issue_joined',\n                        :params => {:issue_id => @issue.id},\n                        :sender_id => User.current.id,\n                        :source_id => @issue.id,\n                        :source_type => \"Issue\"\n\n\n    respond_to do |format|\n      format.js {render :json => @issue.to_dashboard}\n      format.html {redirect_to(params[:back_to] || {:action => 'show', :id => @issue})}\n    end\n  end\n\n  def add_team_member\n    IssueVote.create :user_id => params[:issue_vote][:user_id], :issue_id => params[:id], :vote_type => IssueVote::JOIN_VOTE_TYPE, :points => 1\n    @issue.save\n    @issue.reload\n\n    Notification.create :recipient_id => params[:issue_vote][:user_id],\n                        :variation => 'issue_team_member_added',\n                        :params => {:issue_id => @issue.id, :joiner_id => params[:issue_vote][:user_id]},\n                        :sender_id => User.current.id,\n                        :source_id => @issue.id,\n                        :source_type => \"Issue\"\n\n\n    respond_to do |format|\n      format.js do\n        render :update do |page|\n          page.replace \"joined_by_partial\", :partial => 'issues/joined_by'\n          page.visual_effect :highlight, \"joined_by_partial\"\n        end\n      end\n    end\n  end\n\n  def remove_team_member\n    IssueVote.delete_all :user_id => params[:user_id], :issue_id => params[:id], :vote_type => IssueVote::JOIN_VOTE_TYPE\n\n    Notification.create :recipient_id => params[:user_id],\n                        :variation => 'issue_team_member_removed',\n                        :params => {:issue_id => @issue.id, :joiner_id => params[:user_id]},\n                        :sender_id => User.current.id,\n                        :source_id => @issue.id,\n                        :source_type => \"Issue\"\n\n    respond_to do |format|\n      format.js do\n        render :update do |page|\n          page.replace \"joined_by_partial\", :partial => 'issues/joined_by'\n          page.visual_effect :highlight, \"joined_by_partial\"\n        end\n      end\n    end\n  end\n\n\n  def leave\n    IssueVote.delete_all([\"user_id = ? AND issue_id = ? AND vote_type = ?\", User.current.id, params[:id], IssueVote::JOIN_VOTE_TYPE])\n    @issue.save\n    @issue.reload\n\n    admin = User.sysadmin\n    Notification.create :recipient_id => @issue.assigned_to_id,\n                        :variation => 'issue_left',\n                        :params => {:issue => @issue, :joiner => User.current},\n                        :sender_id => User.current.id,\n                        :source_id => @issue.id,\n                        :source_type => \"Issue\"\n\n\n    respond_to do |format|\n      format.js {render :json => @issue.to_dashboard}\n      format.html {redirect_to(params[:back_to] || {:action => 'show', :id => @issue})}\n    end\n  end\n\n  def reply\n    journal = Journal.find(params[:journal_id]) if params[:journal_id]\n    if journal\n      user = journal.user\n      text = journal.notes\n    else\n      user = @issue.author\n      text = @issue.description\n    end\n    content = \"#{ll(Setting.default_language, :text_user_wrote, user)}\\\\n> \"\n    content << text.to_s.strip.gsub(%r{<pre>((.|\\s)*?)</pre>}m, '[...]').gsub('\"', '\\\"').gsub(/(\\r?\\n|\\r\\n?)/, \"\\\\n> \") + \"\\\\n\\\\n\"\n    render(:update) { |page|\n      page.<< \"$('notes').value = \\\"#{content}\\\";\"\n      page.show 'update'\n      page << \"$('#notes').focus();\"\n      page << \"$('body').scrollTo('#update');\"\n    }\n  end\n\n  # Bulk edit a set of issues\n  def bulk_edit\n    if request.post?\n      tracker = params[:tracker_id].blank? ? nil : @project.trackers.find_by_id(params[:tracker_id])\n      status = params[:status_id].blank? ? nil : IssueStatus.find_by_id(params[:status_id])\n      assigned_to = (params[:assigned_to_id].blank? || params[:assigned_to_id] == 'none') ? nil : User.find_by_id(params[:assigned_to_id])\n\n      unsaved_issue_ids = []\n      @issues.each do |issue|\n        journal = issue.init_journal(User.current, params[:notes])\n        issue.tracker = tracker if tracker\n        issue.assigned_to = assigned_to if assigned_to || params[:assigned_to_id] == 'none'\n        issue.start_date = params[:start_date] unless params[:start_date].blank?\n        issue.due_date = params[:due_date] unless params[:due_date].blank?\n        issue.done_ratio = params[:done_ratio] unless params[:done_ratio].blank?\n        # Don't save any change to the issue if the user is not authorized to apply the requested status\n        unless (status.nil? || (issue.new_statuses_allowed_to(User.current).include?(status) && issue.status = status)) && issue.save\n          # Keep unsaved issue ids to display them in flash error\n          unsaved_issue_ids << issue.id\n        end\n      end\n      if unsaved_issue_ids.empty?\n        flash.now[:success] = l(:notice_successful_update) unless @issues.empty?\n      else\n        flash.now[:error] = l(:notice_failed_to_save_issues, :count => unsaved_issue_ids.size,\n                                                         :total => @issues.size,\n                                                         :ids => '#' + unsaved_issue_ids.join(', #'))\n      end\n      redirect_to(params[:back_to] || {:controller => 'issues', :action => 'index', :project_id => @project})\n      return\n    end\n    @available_statuses = Workflow.available_statuses(@project)\n  end\n\n  def move\n    @copy = params[:copy_options] && params[:copy_options][:copy]\n    @allowed_projects = []\n    # find projects to which the user is allowed to move the issue\n    if User.current.admin?\n      # admin is allowed to move issues to any active (visible) project\n      @allowed_projects = Project.find(:all, :conditions => Project.visible_by(User.current))\n    else\n      @issue.project.root.self_and_descendants.each {|p| @allowed_projects << p if p.visible_to(User.current)}\n    end\n\n    @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id]\n    @target_project ||= @project\n    @trackers = @target_project.trackers\n    @available_statuses = Workflow.available_statuses(@project)\n    if request.post?\n      new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id])\n      unsaved_issue_ids = []\n      moved_issues = []\n      @issues.each do |issue|\n        changed_attributes = {}\n        [:assigned_to_id, :status_id, :start_date, :due_date].each do |valid_attribute|\n          unless params[valid_attribute].blank?\n            changed_attributes[valid_attribute] = (params[valid_attribute] == 'none' ? nil : params[valid_attribute])\n          end\n        end\n        issue.init_journal(User.current)\n        if r = issue.move_to(@target_project, new_tracker, {:copy => @copy, :attributes => changed_attributes})\n          LogActivityStreams.write_single_activity_stream(User.current,:name,issue,:subject,:moved,:move, 0, @target_project, {\n                    :indirect_object_name_method => :name,\n                    :indirect_object_description_method => :name,\n                    :indirect_object_phrase => 'to ' })\n          moved_issues << r\n        else\n          unsaved_issue_ids << issue.id\n        end\n      end\n      @project.project.send_later :refresh_issue_count\n      if unsaved_issue_ids.empty?\n      else\n        flash.now[:error] = l(:notice_failed_to_save_issues, :count => unsaved_issue_ids.size,\n                                                         :total => @issues.size,\n                                                         :ids => '#' + unsaved_issue_ids.join(', #'))\n      end\n      if params[:follow]\n        if @issues.size == 1 && moved_issues.size == 1\n          redirect_to :controller => 'projects', :action => 'dashboard', :id => (@target_project || @project), :show_issue_id => moved_issues.first\n        else\n          redirect_to :controller => 'projects', :action => 'dashboard', :id => (@target_project || @project)\n        end\n      else\n        redirect_to :controller => 'projects', :action => 'dashboard', :id => @project\n      end\n      return\n    end\n    render :layout => false if request.xhr?\n  end\n\n  def destroy\n    @issues.each(&:destroy)\n    redirect_to :action => 'index', :project_id => @project\n  end\n\n  def gantt\n    @gantt = Redmine::Helpers::Gantt.new(params)\n    retrieve_query\n    if @query.valid?\n      events = []\n      # Issues that have start and due dates\n      events += @query.issues(:include => [:tracker, :assigned_to],\n                              :order => \"start_date, due_date\",\n                              :conditions => [\"(((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?) or (start_date<? and due_date>?)) and start_date is not null and due_date is not null)\", @gantt.date_from, @gantt.date_to, @gantt.date_from, @gantt.date_to, @gantt.date_from, @gantt.date_to]\n                              )\n      # Issues that don't have a due date but that are assigned to a version with a date\n      events += @query.issues(:include => [:tracker, :assigned_to],\n                              :order => \"start_date, effective_date\",\n                              :conditions => [\"(((start_date>=? and start_date<=?) or (effective_date>=? and effective_date<=?) or (start_date<? and effective_date>?)) and start_date is not null and due_date is null and effective_date is not null)\", @gantt.date_from, @gantt.date_to, @gantt.date_from, @gantt.date_to, @gantt.date_from, @gantt.date_to]\n                              )\n\n      @gantt.events = events\n    end\n\n    basename = (@project ? \"#{@project.identifier}-\" : '') + 'gantt'\n\n    respond_to do |format|\n      format.html { render :template => \"issues/gantt.html.erb\", :layout => !request.xhr? }\n      format.png  { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => \"#{basename}.png\") } if @gantt.respond_to?('to_image')\n      format.pdf  { send_data(gantt_to_pdf(@gantt, @project), :type => 'application/pdf', :filename => \"#{basename}.pdf\") }\n    end\n  end\n\n  def calendar\n    if params[:year] and params[:year].to_i > 1900\n      @year = params[:year].to_i\n      if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13\n        @month = params[:month].to_i\n      end\n    end\n    @year ||= Date.today.year\n    @month ||= Date.today.month\n\n    @calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month)\n    retrieve_query\n    if @query.valid?\n      events = []\n      events += @query.issues(:include => [:tracker, :assigned_to],\n                              :conditions => [\"((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?))\", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt]\n                              )\n\n      @calendar.events = events\n    end\n\n    render :layout => false if request.xhr?\n  end\n\n  def context_menu\n    @issues = Issue.find_all_by_id(params[:ids], :include => :project)\n    if (@issues.size == 1)\n      @issue = @issues.first\n      @allowed_statuses = @issue.new_statuses_allowed_to(User.current)\n    end\n    projects = @issues.collect(&:project).compact.uniq\n    @project = projects.first if projects.size == 1\n\n    @can = {:edit => (@project && User.current.allowed_to?(:edit_issues, @project)),\n            :update => (@project && (User.current.allowed_to?(:edit_issues, @project) || (User.current.allowed_to?(:change_status, @project) && @allowed_statuses && !@allowed_statuses.empty?))),\n            :move => (@project && User.current.allowed_to?(:move_issues, @project)),\n            :copy => (@issue && @project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)),\n            :delete => (@project && User.current.allowed_to?(:delete_issues, @project))\n            }\n    if @project\n      @assignables = @project.assignable_users\n      @assignables << @issue.assigned_to if @issue && @issue.assigned_to && !@assignables.include?(@issue.assigned_to)\n      @trackers = @project.trackers\n    end\n\n    @statuses = IssueStatus.find(:all, :order => 'position')\n    @back = params[:back_url] || request.env['HTTP_REFERER']\n\n    render :layout => false\n  end\n\n  def update_form\n    if params[:id].blank?\n      @issue = Issue.new\n      @issue.project = @project\n    else\n      @issue = @project.issues.visible.find(params[:id])\n    end\n    @issue.attributes = params[:issue]\n    @allowed_statuses = ([@issue.status] + @issue.status.find_new_statuses_allowed_to(User.current.roles_for_project(@project), @issue.tracker)).uniq\n\n    render :partial => 'attributes'\n  end\n\n  def preview\n    @issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank?\n    @attachements = @issue.attachments if @issue\n    @text = params[:notes] || (params[:issue] ? params[:issue][:description] : nil)\n    render :partial => 'common/preview'\n  end\n\n  def datadump\n    @issues = Issue.find(:all, :conditions => \"project_id IN (#{User.current.owned_projects.collect {|p| p.id}.join(\",\")})\")\n    render :csv => @issues\n  end\n\n  private\n\n  def find_issue\n    @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author])\n    @project = @issue.project\n    render_message l(:text_project_locked) if @project.locked?\n    render_404 if @issue.is_gift? && @issue.assigned_to_id == User.current.id\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  # Filter for bulk operations\n  def find_issues\n    @issues = Issue.find_all_by_id(params[:id] || params[:ids])\n    raise ActiveRecord::RecordNotFound if @issues.empty?\n    projects = @issues.collect(&:project).compact.uniq\n    if projects.size == 1\n      @project = projects.first\n    else\n      # TODO: let users bulk edit/move/destroy issues from different projects\n      render_error 'Can not bulk edit/move/destroy issues from different projects'\n      return false\n    end\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def find_project\n    @project = Project.find(params[:project_id])\n    render_message l(:text_project_locked) if @project.locked?\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def find_optional_project\n    @project = Project.find(params[:project_id]) unless params[:project_id].blank?\n    allowed = User.current.allowed_to?({:controller => params[:controller], :action => params[:action]}, @project, :global => true)\n    allowed ? true : deny_access\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  # Retrieve query from session or build a new query\n  def retrieve_query\n    if !params[:query_id].blank?\n      cond = \"project_id IS NULL\"\n      cond << \" OR project_id = #{@project.id}\" if @project\n      @query = Query.find(params[:query_id], :conditions => cond)\n      @query.project = @project\n      session[:query] = {:id => @query.id, :project_id => @query.project_id}\n      sort_clear\n    else\n      if params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)\n        # Give it a name, required to be valid\n        @query = Query.new(:name => \"_\")\n        @query.project = @project\n        if params[:fields] and params[:fields].is_a? Array\n          params[:fields].each do |field|\n            @query.add_filter(field, params[:operators][field], params[:values][field])\n          end\n        else\n          @query.available_filters.keys.each do |field|\n            @query.add_short_filter(field, params[field]) if params[field]\n          end\n        end\n        @query.group_by = params[:group_by]\n        @query.column_names = params[:query] && params[:query][:column_names]\n        session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}\n      else\n        @query = Query.find_by_id(session[:query][:id]) if session[:query][:id]\n        @query ||= Query.new(:name => \"_\", :project => @project, :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])\n        @query.project = @project\n      end\n    end\n  end\n\n  # Rescues an invalid query statement. Just in case...\n  def query_statement_invalid(exception)\n    logger.error \"Query::StatementInvalid: #{exception.message}\" if logger\n    session.delete(:query)\n    sort_clear\n    render_error \"An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator.\"\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/journals_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nclass JournalsController < ApplicationController\n  before_filter :find_journal\n  ssl_required :all\n\n  def edit\n    if request.post?\n      @journal.update_attributes(:notes => params[:notes]) if params[:notes]\n      if @journal.details.empty? && @journal.notes.blank?\n        @journal.destroy\n      else\n        update_activity_stream(params[:notes]) if params[:notes]\n      end\n\n      respond_to do |format|\n        format.html { redirect_to :controller => 'issues', :action => 'show', :id => @journal.journalized_id }\n        format.js { render :action => 'update' }\n      end\n    end\n  end\n\n  def edit_from_dashboard\n    if @journal.update_attributes(params[:journal])\n      update_activity_stream(params[:journal][:notes])\n    end\n    respond_to do |format|\n      format.js {render :json => @journal.issue.to_dashboard}\n    end\n  end\n\n  private\n\n  def update_activity_stream(notes)\n    ActivityStream.update_all([\"indirect_object_description = ?\", notes], {:indirect_object_id => @journal.id,\n                                                                            :indirect_object_type => \"Journal\",\n                                                                            :object_type => \"Issue\",\n                                                                            :actor_id => User.current.id},\n                                                                          :order => 'created_at DESC', :limit => 1)\n  end\n\n  def find_journal\n    @journal = Journal.find(params[:id])\n    (render_403; return false) unless @journal.editable_by?(User.current)\n    @project = @journal.journalized.project\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/mail_handler_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nclass MailHandlerController < ActionController::Base\n  before_filter :check_credential\n\n  verify :method => :post,\n         :only => :index,\n         :render => { :nothing => true, :status => 405 }\n\n\n  # Submits an incoming email to MailHandler\n  def index\n    options = params.dup\n    email = options.delete(:email)\n    if MailHandler.receive(email, options)\n      render :nothing => true, :status => :created\n    else\n      render :nothing => true, :status => :unprocessable_entity\n    end\n  end\n\n  # Submits an incoming email from sendgrid to MailHandler\n  def sendgrid\n    @email = TMail::Mail.new\n    @email.subject = params[:subject]\n    @email.body = params[:text].to_s.gsub(/\"/,'\\\"')\n    @email.to = params[:to]\n    @email.from = params[:from]\n    @email.subject = params[:subject]\n\n    logger.info { \"email coming up\" }\n    logger.info(@email.inspect)\n    #   attachments - Number of attachments included in email\n    # *\n    #   attachment1, attachment2, …, attachmentN - File upload names. The numbers are sequence numbers starting from 1 and ending on the number specified by the attachments parameter. If attachments is 0, there will be no attachment files. If attachments is 3, parameters attachment1, attachment2, and attachment3 will have file uploads.\n\n\n    if MailHandler.receive_from_api(@email)\n      render :nothing => true, :status => :created\n    else\n      render :nothing => true, :status => :unprocessable_entity\n    end\n  end\n\n  private\n\n  def check_credential\n    User.current = nil\n\n    unless Setting.mail_handler_api_enabled? && params[:key].to_s == Setting.mail_handler_api_key\n      render :text => 'Access denied. Incoming emails WS is disabled or key is invalid.', :status => 403\n    end\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/mails_controller.rb",
    "content": "class MailsController < ApplicationController\n\n  before_filter :set_user\n\n  def index\n    if params[:mailbox] == \"sent\"\n      @mails = @user.sent_messages\n    else\n      @mails = @user.received_messages\n    end\n  end\n\n  def show\n    @mail = Mail.read_and_get(params[:id], User.current)\n  end\n\n  def new\n    @mail = Mail.new\n\n    if params[:reply_to]\n      @reply_to = @user.received_messages.find(params[:reply_to])\n      unless @reply_to.nil?\n        @mail.to = @reply_to.sender.login\n        @mail.subject = \"Re: #{@reply_to.subject}\"\n        @mail.body = \"\\n\\n*Original message*\\n\\n #{@reply_to.body}\"\n      end\n    end\n  end\n\n  def create\n    @mail = Mail.new(params[:mail])\n    @mail.sender = @user\n    @mail.recipient = User.find_by_login(params[:mail][:to])\n\n    if @mail.save\n      flash.now[:success] = \"Message sent\"\n      redirect_to user_mails_path(@user)\n    else\n      render :action => :new\n    end\n  end\n\n  def delete_selected\n    if request.post?\n      if params[:delete]\n        params[:delete].each { |id|\n          @mail = Mail.find(:first, :conditions => [\"mails.id = ? AND (sender_id = ? OR recipient_id = ?)\", id, @user, @user])\n          @mail.mark_deleted(@user) unless @mail.nil?\n        }\n        flash.now[:success] = \"Messages deleted\"\n      end\n      redirect_to user_mail_path(@user, @mails)\n    end\n  end\n\n  private\n\n  def set_user\n    @user = User.current\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/members_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass MembersController < ApplicationController\n  before_filter :find_member, :except => [:new, :autocomplete_for_member]\n  before_filter :find_project, :only => [:new, :autocomplete_for_member]\n  before_filter :authorize\n  ssl_required :all\n\n  def new\n    members = []\n    if params[:member] && request.post?\n      attrs = params[:member].dup\n      if (user_ids = attrs.delete(:user_ids))\n        user_ids.each do |user_id|\n          members << Member.new(attrs.merge(:user_id => user_id))\n        end\n      else\n        members << Member.new(attrs)\n      end\n      result = @project.all_members << members\n    end\n    respond_to do |format|\n      format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }\n      format.js {\n        render(:update) {|page|\n          page.replace_html \"tab-content-members\", :partial => 'projects/settings/members'\n          members.each {|member| page.visual_effect(:highlight, \"member-#{member.id}\") }\n        }\n      }\n    end\n  end\n\n  def edit\n    if request.post? and @member.update_attributes(params[:member])\n      respond_to do |format|\n        format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }\n        format.js {\n          render(:update) {|page|\n            page.replace_html \"tab-content-members\", :partial => 'projects/settings/members'\n            page.visual_effect(:highlight, \"member-#{@member.id}\")\n          }\n        }\n      end\n    end\n  end\n\n  def destroy\n    if request.post? && @member.deletable?\n      @member.destroy\n    end\n    respond_to do |format|\n      format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }\n      format.js { render(:update) {|page| page.replace_html \"tab-content-members\", :partial => 'projects/settings/members'} }\n    end\n  end\n\n  def autocomplete_for_member\n    @users = User.active.like(params[:q]).find(:all, :limit => 100) - @project.users\n    render :layout => false\n  end\n\n  private\n\n  def find_project\n    @project = Project.find(params[:id])\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def find_member\n    @member = Member.find(params[:id])\n    @project = @member.project\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/messages_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass MessagesController < ApplicationController\n  menu_item :boards\n  default_search_scope :messages\n  before_filter :find_board, :only => [:new, :preview]\n  before_filter :find_message, :except => [:new, :preview, :motion_reply]\n  before_filter :authorize, :except => [:preview, :edit, :destroy]\n  ssl_required :all\n\n\n  verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show }\n  verify :xhr => true, :only => :quote\n\n  helper :watchers\n  helper :attachments\n  include AttachmentsHelper\n\n  log_activity_streams :current_user, :name, :created, :@message, :subject, :new, :messages, {:object_description_method => :content}\n  log_activity_streams :current_user, :name, :edited, :@message, :subject, :edit, :messages, {:object_description_method => :content}\n  log_activity_streams :current_user, :name, :replied_to, :@topic, :subject, :reply, :messages, {\n            :object_description_method => :content,\n            :indirect_object => :@reply,\n            :indirect_object_description_method => :content,\n            :indirect_object_phrase => '' }\n\n  # Show a topic and its replies\n  def show\n    @replies = @topic.children.find(:all, :include => [:author, :attachments, {:board => :project}])\n    @replies.reverse! if User.current.wants_comments_in_reverse_order?\n    @reply = Message.new(:subject => \"RE: #{@message.subject}\")\n    render :action => \"show\", :layout => false if request.xhr?\n  end\n\n  # Create a new topic\n  def new\n    @message = Message.new(params[:message])\n    @message.author = User.current\n    @message.board = @board\n    if params[:message] && User.current.allowed_to?(:edit_messages, @project)\n      @message.locked = params[:message]['locked']\n      @message.sticky = params[:message]['sticky']\n    end\n    if request.post? && @message.save\n      attach_files(@message, params[:attachments])\n      redirect_to :action => 'show', :id => @message\n    end\n  end\n\n  # Reply to a topic\n  def reply\n    @reply = Message.new(params[:reply])\n    @reply.subject = @message.subject if @reply.subject == \"\"\n    @reply.author = User.current\n    @reply.board = @board\n    @topic.children << @reply\n    if !@reply.new_record?\n      attach_files(@reply, params[:attachments])\n    end\n    respond_to do |wants|\n      wants.html { redirect_to :action => 'show', :id => @topic  }\n      wants.js { render :nothing => :true}\n    end\n  end\n\n  # Edit a message\n  def edit\n    (render_403; return false) unless @message.editable_by?(User.current)\n    if params[:message]\n      @message.locked = params[:message]['locked']\n      @message.sticky = params[:message]['sticky']\n    end\n    if request.post? && @message.update_attributes(params[:message])\n      attach_files(@message, params[:attachments])\n      flash.now[:success] = l(:notice_successful_update)\n      @message.reload\n      redirect_to :action => 'show', :board_id => @message.board, :id => @message.root\n    end\n  end\n\n  # Delete a messages\n  def destroy\n    (render_403; return false) unless @message.destroyable_by?(User.current)\n    @message.destroy\n    redirect_to @message.parent.nil? ?\n      { :controller => 'boards', :action => 'show', :project_id => @project, :id => @board } :\n      { :action => 'show', :id => @message.parent }\n  end\n\n  def quote\n    user = @message.author\n    text = @message.content\n    subject = @message.subject.gsub('\"', '\\\"')\n    subject = \"RE: #{subject}\" unless subject.starts_with?('RE:')\n    content = \"#{ll(Setting.default_language, :text_user_wrote, user)}\\\\n> \"\n    content << text.to_s.strip.gsub(%r{<pre>((.|\\s)*?)</pre>}m, '[...]').gsub('\"', '\\\"').gsub(/(\\r?\\n|\\r\\n?)/, \"\\\\n> \") + \"\\\\n\\\\n\"\n    render(:update) { |page|\n      page << \"$('reply_subject').value = \\\"#{subject}\\\";\"\n      page.<< \"$('message_content').value = \\\"#{content}\\\";\"\n      page.show 'reply'\n      page << \"$('#message_content').focus();\"\n      page << \"$('body').scrollTo('#reply');\"\n    }\n  end\n\n  def preview\n    message = @board.messages.find_by_id(params[:id])\n    @attachements = message.attachments if message\n    @text = (params[:message] || params[:reply])[:content]\n    render :partial => 'common/preview'\n  end\n\n  private\n\n  def find_message\n    if params[:board_id] == 'guess'\n      logger.info { \"guessing board\" }\n      guess_board\n    else\n      find_board\n      @message = @board.messages.find(params[:id], :include => :parent)\n    end\n    @topic = @message.root unless @message.nil?\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  #This function is used to redirect links coming from the activity stream\n  #To save queries on the database, we don't try to load the board id in the link to a message\n  def guess_board\n    @message = Message.find(params[:id], :include => :parent)\n    @board = @message.board\n    @project = @board.project\n    logger.info { \"guessed board #{@board.inspect}\" }\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def find_board\n    @board = Board.find(params[:board_id], :include => :project)\n    @project = @board.project\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/motion_votes_controller.rb",
    "content": "class MotionVotesController < ApplicationController\n  ssl_required :all\n\n  def index\n    @motion_votes = MotionVote.all\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @motion_votes }\n    end\n  end\n\n  def show\n    @motion_vote = MotionVote.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @motion_vote }\n    end\n  end\n\n  def new\n    @motion_vote = MotionVote.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @motion_vote }\n    end\n  end\n\n  def edit\n    @motion_vote = MotionVote.find(params[:id])\n  end\n\n  def create\n    @motion_vote = MotionVote.new(params[:motion_vote])\n    @motion_vote.motion_id = params[:motion_id]\n    @motion_vote.user_id = User.current.id\n\n    if @motion_vote.motion.motion_type == Motion::TYPE_SHARE\n      sum = @motion_vote.user.shares.for_project(@motion_vote.motion.project_id).sum(:amount).to_i\n      @motion_vote.points = params[:points].to_i * sum\n    else\n      @motion_vote.points = params[:points]\n    end\n\n    respond_to do |format|\n      if @motion_vote.save\n        format.js  { render :action => \"cast_vote\", :motion => @motion_vote.motion}\n      else\n        format.js { render :action => \"error\"}\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @motion_vote.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @motion_vote = MotionVote.find(params[:id])\n\n    respond_to do |format|\n      if @motion_vote.update_attributes(params[:motion_vote])\n        flash.now[:success] = 'MotionVote was successfully updated.'\n        format.html { redirect_to(@motion_vote) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @motion_vote.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @motion_vote = MotionVote.find(params[:id])\n    @motion_vote.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(motion_votes_url) }\n      format.xml  { head :ok }\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/motions_controller.rb",
    "content": "class MotionsController < ApplicationController\n\n  before_filter :find_project, :only => [:new,:index,:create,:show, :edit, :eligible_users]\n  before_filter :find_motion, :only => [:show, :edit, :destroy, :update, :reply]\n  before_filter :check_visibility_permission, :only => [:show]\n  before_filter :require_admin, :only => [:edit, :update, :destroy]\n  before_filter :authorize, :except => [:check_visibility_permission]\n  ssl_required :all\n\n\n  def index\n    @motions = @project.motions\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @motions }\n    end\n  end\n\n  def show\n    if @motion.concerned_user_id == User.current.id\n      render_403\n      return false\n    end\n\n    @motion.create_forum_topic if @motion.topic.nil?\n\n    @topic = @motion.topic\n    @board = @topic.board\n    @replies = @topic.children.find(:all, :include => [:author, :attachments, {:board => :project}])\n    @replies.reverse! if User.current.wants_comments_in_reverse_order?\n    @reply = Message.new(:subject => \"RE: #{@topic.subject}\")\n\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @motion }\n    end\n  end\n\n  def new\n    @motion = Motion.new(params[:motion])\n\n    @concerned_user_list = Motion.eligible_users(@motion.variation, @project.id)\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @motion }\n    end\n  end\n\n  def eligible_users\n    @concerned_user_list = \"\"\n    @variation = params[:variation].to_i\n    case @variation\n      when Motion::VARIATION_NEW_MEMBER\n        @concerned_user_list = @project.contributor_list\n      when Motion::VARIATION_NEW_CORE\n        @concerned_user_list = @project.member_list\n      when Motion::VARIATION_FIRE_MEMBER\n        @concerned_user_list = @project.member_list\n      when Motion::VARIATION_FIRE_CORE\n        @concerned_user_list = @project.core_member_list\n    end\n\n    @concerned_user_list = [] if @concerned_user_list == \"\"\n    #remove current user from list\n    @concerned_user_list.delete_if {|a| a.user_id == User.current.id}\n\n    render :layout => false\n  end\n\n  def edit\n  end\n\n  def create\n    @motion = Motion.new(params[:motion])\n    @motion.project_id = @project.id\n    @motion.author_id = User.current.id\n    @motion.params = params[:param]\n\n    respond_to do |format|\n      if @motion.concerned_user == User.current\n        format.html { redirect_with_flash :error, 'Cannot create a motion concerning yourself', :action => 'index' }\n        format.xml  { render :xml => @motion.errors, :status => :unprocessable_entity }\n      elsif !@motion.concerned_user && @motion.concerns_someone?\n        format.html { redirect_with_flash :error, 'Who does this motion apply to? You need to select the user that this motion is concerned with.', :action => 'index' }\n        format.xml  { render :xml => @motion.errors, :status => :unprocessable_entity }\n      elsif @motion.save\n        format.html { redirect_with_flash :success, 'Motion was successfully created', :action => \"show\", :id => @motion }\n        format.xml  { render :xml => @motion, :status => :created, :location => @motion }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @motion.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    respond_to do |format|\n      if @motion.update_attributes(params[:motion])\n        flash.now[:success] = 'Motion was successfully updated.'\n        format.html { redirect_to(@motion) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @motion.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @motion.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(motions_url) }\n      format.xml  { head :ok }\n    end\n  end\n\n  # Reply to a motion discussion\n  def reply\n    @topic = @motion.topic\n    @reply = Message.new(params[:reply])\n    @reply.author = User.current\n    @reply.board = @topic.board\n    @topic.children << @reply\n    if !@reply.new_record?\n      attach_files(@reply, params[:attachments])\n    end\n    redirect_to :action => 'show', :id => @motion, :project_id => @motion.project_id\n  rescue\n    404\n  end\n\n  private\n\n  def find_project\n    @project = Project.find(params[:project_id]).root\n    render_message l(:text_project_locked) if @project.locked?\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def find_motion\n    @motion = Motion.find(params[:id])\n    @project = @motion.project\n    render_message l(:text_project_locked) if @project.locked?\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def check_visibility_permission\n    if !User.current.allowed_to_see_motion?(@motion)\n       render_403\n       return false\n    end\n    return true\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/my_controller.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass MyController < ApplicationController\n  before_filter :require_login\n  ssl_required :all\n\n\n  helper :issues\n\n  BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues,\n             'issuesreportedbyme' => :label_reported_issues,\n             'issueswatched' => :label_watched_issues,\n             'news' => :label_news_latest,\n             'calendar' => :label_calendar,\n             'documents' => :label_document_plural\n           }.merge(Redmine::Views::MyPage::Block.additional_blocks).freeze\n\n  DEFAULT_LAYOUT = {  'left' => ['issuesassignedtome'],\n                      'right' => ['issuesreportedbyme']\n                   }.freeze\n\n  verify :xhr => true,\n         :only => [:add_block, :remove_block, :order_blocks]\n\n  def index\n    page\n    render :action => 'page'\n  end\n\n  # Show user's page\n  def page\n    @user = User.current\n    @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT\n  end\n\n  def projects\n    project_ids = User.current.projects.collect{|p| p.id}.join(\",\")\n    @all_projects = project_ids.any? ? Project.find(:all, :conditions => \"(parent_id in (#{project_ids}) OR id in (#{project_ids})) AND (status=#{Project::STATUS_ACTIVE})\") : []\n    @my_projects = User.current.owned_projects\n    @belong_to_projects = User.current.belongs_to_projects\n    @active_projects = User.current.active_memberships.collect(&:project)\n  end\n\n  def issues\n    @assigned_issues = Issue.visible.open.find(:all,\n                                    :conditions => {:assigned_to_id => User.current.id},\n                                    :include => [:project, :tracker ],\n                                    :order => \"#{Issue.table_name}.subject ASC\")\n\n    @watched_issues = Issue.visible.find(:all,\n                                     :include => [:project, :tracker, :watchers],\n                                     :conditions => [\"#{Watcher.table_name}.user_id = ?\", User.current.id],\n                                     :order => \"#{Issue.table_name}.subject ASC\")\n\n     @joined_issues = Issue.visible.find(:all,\n                                      :include => [:project, :tracker, :issue_votes],\n                                      :conditions => [\"#{IssueVote.table_name}.user_id = ? AND #{IssueVote.table_name}.vote_type = ? AND #{Issue.table_name}.assigned_to_id != ? AND #{Issue.table_name}.status_id = ?\", User.current.id, IssueVote::JOIN_VOTE_TYPE, User.current.id, IssueStatus.assigned.id],\n                                      :order => \"#{Issue.table_name}.subject ASC\")\n\n    @added_issues = Issue.visible.open.find(:all,\n                                    :conditions => {:author_id => User.current.id},\n                                    :include => [:project, :tracker ],\n                                    :order => \"#{Issue.table_name}.created_at DESC\")\n\n    @recent_issues = User.current.recent_items(30)\n\n  end\n\n  # Edit user's account\n  def account\n    @user = User.current\n    @pref = @user.pref\n    if request.post?\n      cc = params[:user][:b_cc_last_four]\n\n      if cc && cc.length > 14\n        cc.gsub!(/[^0-9]/,'')\n        params[:user][:b_cc_last_four] = (\"XXXX-\") + params[:user][:b_cc_last_four][cc.length-4,cc.length-1] if cc.length > 14\n      end\n      @user.attributes = params[:user]\n      @user.login = params[:user][:login]\n      logger.info { \"@user.attributes #{@user.attributes.inspect}\" }\n      @user.mail_notification = (params[:notification_option] == 'all')\n\n      logger.info { \"params[:pref] #{params[:pref].inspect}\" }\n      @user.pref.attributes = params[:pref]\n      logger.info { \"@user.pref.attributes #{@user.pref.inspect}\" }\n      logger.info { \"params[:active_only_jumps] #{params[:active_only_jumps]}  and boolean #{params[:active_only_jumps] == '1'}\" }\n\n      @user.pref[:no_self_notified] = (params[:no_self_notified] == '1')\n      @user.pref[:daily_digest] = (params[:daily_digest] == '1')\n      @user.pref[:no_emails] = (params[:no_emails] == '1')\n      @user.pref[:hide_mail] = (params[:pref][:hide_mail] == '1')\n      @user.pref[:active_only_jumps] = (params[:pref][:active_only_jumps] == '1')\n\n      logger.info { \"user pref #{@user.pref.inspect}\" }\n      if @user.save\n        @user.pref.save\n        @user.reload\n        @user.save_billing cc, params[:ccverify], request.remote_ip\n        @user.notified_project_ids = (params[:notification_option] == 'selected' ? params[:notified_project_ids] : [])\n        set_language_if_valid @user.language\n        redirect_with_flash :notice, l(:notice_account_updated), :action => 'account'\n        return\n      end\n    end\n    @notification_options = [[l(:label_user_mail_option_all), 'all'],\n                             [l(:label_user_mail_option_none), 'none']]\n    @notification_option = @user.mail_notification? ? 'all' : (@user.notified_projects_ids.empty? ? 'none' : 'selected')\n  end\n\n  def upgrade\n    @user = User.current\n    @plans = Plan.all\n    @selected_plan = @user.plan\n\n    if request.post?\n      cc = params[:user][:b_cc_last_four]\n      cc.gsub!(/[^0-9]/,'')\n      logger.info { \"length #{cc.length} #{cc}\" }\n      if cc.length > 14\n        params[:user][:b_cc_last_four] = (\"XXXX-\") + params[:user][:b_cc_last_four][cc.length-4,cc.length-1]\n      else\n        params[:user].delete :b_cc_last_four\n      end\n\n      logger.info { \"inspect #{params.inspect}\" }\n\n      @new_plan = Plan.find(params[:user][:plan_id])\n      @user.attributes = params[:user]\n      @user.plan_id = @user.plan.id #not upgrading yet\n\n      account = User.update_recurly_billing @user.id, cc, params[:ccverify], request.remote_ip\n\n      @user.save\n\n      if defined? account.billing_info && defined? account.billing_info.errors\n        if account.billing_info.errors.length > 0\n          flash.now[:error] = account.billing_info.errors[:base].collect {|v| \"#{v}\"}.join('<br>')\n          return\n        end\n      end\n\n      if @new_plan.code == Plan::FREE_CODE && @new_plan.code != @selected_plan.code\n        begin\n          sub = Recurly::Subscription.find(@user.id.to_s)\n          sub.cancel(@user.id.to_s)\n        rescue Exception => e\n          flash.now[:error] = e.message\n          return\n        else\n          @user.trial_expires_on = nil\n          @user.trial_expired_at = nil\n          @user.plan_id = @new_plan.id\n          @user.save\n          @user.update_usage_over\n          @user.update_trial_expiration\n          @user.lock_workstreams\n          flash.now[:success] = \"Your plan was successfully canceled\"\n          @user.reload\n          return\n        end\n      elsif @new_plan.code != @selected_plan.code\n        begin\n          sub = Recurly::Subscription.find(@user.id.to_s)\n          begin\n          sub.change('now', :plan_code => @new_plan.code, :quantity => 1)\n          rescue Exception => e\n            flash.now[:error] = e.message\n            @user.reload\n            return\n          end\n        rescue ActiveResource::ResourceNotFound\n          begin\n          trial_expiration = @user.trial_expires_on || -1.days.from_now\n          logger.info { \"trial #{trial_expiration}\" }\n          sub = Recurly::Subscription.create(\n            :account_code => account.account_code,\n            :plan_code => @new_plan.code,\n            :quantity => 1,\n            :account => account\n          )\n          rescue Exception => e\n              flash.now[:error] = e.message\n              @user.reload\n              return\n          end\n        else\n          @user.trial_expires_on = nil\n          @user.trial_expired_at = nil\n        end\n\n        if sub.errors && sub.errors.any?\n          flash.now[:error] = sub.errors.collect {|k, v| \"#{v}\"}.join('<br>')\n          @user.reload\n          return\n        else\n          @user.plan_id = @new_plan.id\n          @user.save\n          @user.update_usage_over\n          @user.update_trial_expiration\n          @user.unlock_workstreams\n          flash.now[:success] = \"Plan successfully changed to #{@new_plan.name}\"\n        end\n      else\n        flash.now[:success] = l(:notice_account_updated) + \" No changes were made to your plan\"\n      end\n      @user.reload\n\n      return\n    end\n  end\n\n  # Manage user's password\n  def password\n    @user = User.current\n    if @user.auth_source_id\n      flash.now[:error] = l(:notice_can_t_change_password)\n      redirect_to :action => 'account'\n      return\n    end\n    if request.post?\n      if @user.check_password?(params[:password])\n        @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]\n        if @user.save\n          flash.now[:success] = l(:notice_account_password_updated)\n          redirect_to :action => 'account'\n        end\n      else\n        flash.now[:error] = l(:notice_account_wrong_password)\n      end\n    end\n  end\n\n  # Create a new feeds key\n  def reset_rss_key\n    if request.post?\n      if User.current.rss_token\n        User.current.rss_token.destroy\n        User.current.reload\n      end\n      User.current.rss_key\n      flash.now[:success] = l(:notice_feeds_access_key_reseted)\n    end\n    redirect_to :action => 'account'\n  end\n\n  # Create a new API key\n  def reset_api_key\n    if request.post?\n      if User.current.api_token\n        User.current.api_token.destroy\n        User.current.reload\n      end\n      User.current.api_key\n      flash.now[:success] = l(:notice_api_access_key_reseted)\n    end\n    redirect_to :action => 'account'\n  end\n\n  # User's page layout configuration\n  def page_layout\n    @user = User.current\n    @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT.dup\n    @block_options = []\n    BLOCKS.each {|k, v| @block_options << [l(\"my.blocks.#{v}\", :default => [v, v.to_s.humanize]), k.dasherize]}\n  end\n\n  # Add a block to user's page\n  # The block is added on top of the page\n  # params[:block] : id of the block to add\n  def add_block\n    block = params[:block].to_s.underscore\n    (render :nothing => true; return) unless block && (BLOCKS.keys.include? block)\n    @user = User.current\n    layout = @user.pref[:my_page_layout] || {}\n    # remove if already present in a group\n    %w(top left right).each {|f| (layout[f] ||= []).delete block }\n    # add it on top\n    layout['top'].unshift block\n    @user.pref[:my_page_layout] = layout\n    @user.pref.save\n    render :partial => \"block\", :locals => {:user => @user, :block_name => block}\n  end\n\n  # Remove a block to user's page\n  # params[:block] : id of the block to remove\n  def remove_block\n    block = params[:block].to_s.underscore\n    @user = User.current\n    # remove block in all groups\n    layout = @user.pref[:my_page_layout] || {}\n    %w(top left right).each {|f| (layout[f] ||= []).delete block }\n    @user.pref[:my_page_layout] = layout\n    @user.pref.save\n    render :nothing => true\n  end\n\n  # Change blocks order on user's page\n  # params[:group] : group to order (top, left or right)\n  # params[:list-(top|left|right)] : array of block ids of the group\n  def order_blocks\n    group = params[:group]\n    @user = User.current\n    if group.is_a?(String)\n      group_items = (params[\"list-#{group}\"] || []).collect(&:underscore)\n      if group_items and group_items.is_a? Array\n        layout = @user.pref[:my_page_layout] || {}\n        # remove group blocks if they are presents in other groups\n        %w(top left right).each {|f|\n          layout[f] = (layout[f] || []) - group_items\n        }\n        layout[group] = group_items\n        @user.pref[:my_page_layout] = layout\n        @user.pref.save\n      end\n    end\n    render :nothing => true\n  end\nend\n"
  },
  {
    "path": "app/controllers/news_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass NewsController < ApplicationController\n  default_search_scope :news\n  before_filter :find_news, :except => [:new, :index, :preview]\n  before_filter :find_project, :only => [:new, :preview]\n  before_filter :authorize, :except => [:index, :preview]\n  before_filter :find_optional_project, :only => :index\n  accept_key_auth :index\n  ssl_required :all\n\n\n  log_activity_streams :current_user, :name, :announced, :@news, :title, :new, :news, {:object_description_method => :summary}\n  log_activity_streams :current_user, :name, :edited, :@news, :title, :edit, :news, {:object_description_method => :summary}\n  log_activity_streams :current_user, :name, :commented_on, :@news, :title, :add_comment, :news, {\n              :object_description_method => :summary,\n              :indirect_object => :@comment,\n              :indirect_object_description_method => :comments,\n              :indirect_object_phrase => '' }\n\n  def index\n    @news_pages, @newss = paginate :news,\n                                   :per_page => 10,\n                                   :conditions => Project.allowed_to_condition(User.current, :view_news, :project => @project),\n                                   :include => [:author, :project],\n                                   :order => \"#{News.table_name}.created_at DESC\"\n    respond_to do |format|\n      format.html { render :layout => false if request.xhr? }\n      format.xml { render :xml => @newss.to_xml }\n      format.json { render :json => @newss.to_json }\n    end\n  end\n\n  def show\n    @comments = @news.comments\n    @comments.reverse! if User.current.wants_comments_in_reverse_order?\n  end\n\n  def new\n    @news = News.new(:project => @project, :author => User.current)\n    if request.post?\n      @news.attributes = params[:news]\n      if @news.save\n        flash.now[:success] = l(:notice_successful_create)\n        redirect_to :controller => 'news', :action => 'index', :project_id => @project\n      end\n    end\n  end\n\n  def edit\n    if request.post? and @news.update_attributes(params[:news])\n      flash.now[:success] = l(:notice_successful_update)\n      redirect_to :action => 'show', :id => @news\n    end\n  end\n\n  def add_comment\n    @comment = Comment.new(params[:comment])\n    @comment.author = User.current\n    if @news.comments << @comment\n      flash.now[:success] = l(:label_comment_added)\n      redirect_to :action => 'show', :id => @news\n    else\n      show\n      render :action => 'show'\n    end\n  end\n\n  def destroy_comment\n    @news.comments.find(params[:comment_id]).destroy\n    redirect_to :action => 'show', :id => @news\n  end\n\n  def destroy\n    @news.destroy\n    redirect_to :action => 'index', :project_id => @project\n  end\n\n  def preview\n    @text = (params[:news] ? params[:news][:description] : nil)\n    render :partial => 'common/preview'\n  end\n\n  private\n\n  def find_news\n    @news = News.find(params[:id])\n    @project = @news.project\n    render_message l(:text_project_locked) if @project.locked?\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def find_project\n    @project = Project.find(params[:project_id])\n    render_message l(:text_project_locked) if @project.locked?\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def find_optional_project\n    return true unless params[:project_id]\n    @project = Project.find(params[:project_id])\n    render_message l(:text_project_locked) if @project.locked?\n    authorize\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/notifications_controller.rb",
    "content": "class NotificationsController < ApplicationController\n  ssl_required :all\n  def index\n    @notifications = Notification.unresponded\n    @mentions = @notifications.select {|n| n.mention?}\n    @notifications = @notifications.select {|n| !n.mention?}\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @notifications }\n    end\n  end\n\n  def show\n    @notification = Notification.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @notification }\n    end\n  end\n\n  def new\n    @notification = Notification.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @notification }\n    end\n  end\n\n  def edit\n    @notification = Notification.find(params[:id])\n  end\n\n  def create\n    @notification = Notification.new(params[:notification])\n\n    respond_to do |format|\n      if @notification.save\n        flash.now[:success] = 'Notification was successfully created.'\n        format.html { redirect_to(@notification) }\n        format.xml  { render :xml => @notification, :status => :created, :location => @notification }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @notification.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @notification = Notification.find(params[:id])\n\n    respond_to do |format|\n      if @notification.update_attributes(params[:notification])\n        format.html { redirect_to(@notification) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @notification.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def hide\n    @notification = Notification.find(params[:notification_id])\n\n    respond_to do |format|\n      if @notification.mark_as_responded\n        format.js {render :action => \"hide\"}\n        format.xml  { head :ok }\n      else\n        flash.now[:success] = 'Error ignoring notification'\n        format.js {render :action => \"error\"}\n        format.xml  { render :xml => @notification.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @notification = Notification.find(params[:id])\n    @notification.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(notifications_url) }\n      format.xml  { head :ok }\n    end\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/projects_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass ProjectsController < ApplicationController\n\n  menu_item :overview\n  menu_item :activity, :only => :activity\n  menu_item :dashboard, :only => :dashboard\n  menu_item :files, :only => [:list_files, :add_file]\n  menu_item :settings, :only => :settings\n  menu_item :team, :only => :team\n  menu_item :credits, :only => :credits\n\n  ssl_required :all\n\n  before_filter :find_project, :except => [ :index, :list, :copy, :activity, :update_scale, :add, :index_active, :index_latest ]\n  before_filter :find_optional_project, :only => [:activity, :add]\n\n  #BUGBUG: why aren't these actions being authorized!!! archive can be removed, unarchive doesn't seem to work when removed from here\n  before_filter :authorize, :except => [ :index, :index_latest, :index_active, :list, :add, :copy, :archive, :unarchive, :destroy, :activity, :dashboard, :dashdata, :new_dashdata, :mypris, :update_scale, :community_members, :community_members_array, :issue_search, :hourly_types, :join]\n\n  before_filter :authorize_global, :only => :add\n  before_filter :require_admin, :only => [ :copy ]\n  accept_key_auth :activity\n\n  after_filter :only => [:add, :edit, :archive, :unarchive, :destroy] do |controller|\n    if controller.request.post?\n      controller.send :expire_action, :controller => 'welcome', :action => 'robots.txt'\n    end\n  end\n\n  helper :sort\n  include SortHelper\n  helper :issues\n  helper IssuesHelper\n  helper :queries\n  include QueriesHelper\n  include ProjectsHelper\n\n  log_activity_streams :current_user, :name, :edited, :@project, :name, :edit, :workstreams, {:object_description_method => :description}\n\n  def index\n    @latest_enterprises = Project.latest_public\n    @active_enterprises = Project.most_active_public\n  end\n\n  def index_latest\n    limit = 10\n    @latest_enterprises = Project.latest_public(limit, params[:offset].to_i)\n\n    respond_to do |wants|\n      wants.js do\n        render :update do |page|\n          page.replace \"project_index_bottom_latest\", :partial => \"project_list\", :locals => {\n                                              :projects => @latest_enterprises,\n                                              :offset => Integer(params[:offset]) + limit,\n                                              :index_type => 'latest'}\n          page.call \"display_sparks\"\n        end\n      end\n    end\n  end\n\n  def index_active\n    limit = 10\n    @active_enterprises = Project.most_active_public(limit, params[:offset].to_i)\n\n    respond_to do |wants|\n      wants.js do\n        render :update do |page|\n          page.replace \"project_index_bottom_active\", :partial => \"project_list\", :locals => {\n                                              :projects => @active_enterprises,\n                                              :offset => Integer(params[:offset]) + limit,\n                                              :index_type => 'active'}\n          page.call \"display_sparks\"\n        end\n      end\n    end\n  end\n\n  def map\n  end\n\n  # Add a new project\n  #TODO too much logic here, needs to move to model somehow\n  def add\n    @project = Project.new(params[:project])\n    @parent = Project.find(params[:parent_id]) unless params[:parent_id] == \"\" || params[:parent_id].nil?\n\n    if request.get?\n      @project.enabled_module_names = Setting.default_projects_modules\n      @project.dpp = 100\n\n      if @parent\n        @project.is_public = @parent.is_public\n        @project.volunteer = @parent.volunteer\n      end\n    else\n      @project.enabled_module_names = params[:enabled_modules]\n      @project.is_public = params[:project][:is_public] || false\n      @project.volunteer = params[:project][:volunteer] || false\n      @project.homepage = url_for(:controller => 'projects', :action => 'wiki', :id => @project)\n\n\n      if validate_parent_id && @project.save\n        LogActivityStreams.write_single_activity_stream(User.current, :name, @project, :name, :created, :workstreams, 0, nil,{:object_description_method => :description})\n\n\n        if @parent.nil?\n          # Add current user as a admin and core team member\n          r = Role.core_member\n          r2 = Role.administrator\n          m = Member.new(:user => User.current, :roles => [r,r2])\n          @project.all_members << m\n          @project.update_attribute(:owner_id, User.current.id)\n\n        else\n          @project.set_parent!(@parent.id)\n          @project.set_owner\n          @project.refresh_active_members\n          User.current.add_to_project(@project, Role.active)\n        end\n\n\n        flash.now[:success] = l(:notice_successful_create)\n        redirect_to :controller => 'projects', :action => 'dashboard', :id => @project.id\n      else\n        redirect_with_flash :error, \"Couldn't create project\", :controller => \"my\", :action => \"projects\"\n      end\n    end\n  end\n\n  def copy\n    @trackers = Tracker.all\n    @root_projects = Project.find(:all,\n                                  :conditions => \"parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}\",\n                                  :order => 'name')\n    @source_project = Project.find(params[:id])\n    if request.get?\n      @project = Project.copy_from(@source_project)\n      if @project\n        @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?\n      else\n        redirect_to :controller => 'admin', :action => 'projects'\n      end\n    else\n      @project = Project.new(params[:project])\n      @project.enabled_module_names = params[:enabled_modules]\n      if validate_parent_id && @project.copy(@source_project, :only => params[:only])\n        @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')\n        flash.now[:success] = l(:notice_successful_create)\n        redirect_to :controller => 'admin', :action => 'projects'\n      end\n    end\n  rescue ActiveRecord::RecordNotFound\n    redirect_to :controller => 'admin', :action => 'projects'\n  end\n\n  def reset_invitation_token\n    @project.invitation_token = Token.generate_token_value\n    @project.save\n\n    respond_to do |wants|\n      wants.js do\n        render :update do |page|\n          page.replace \"generic-invitation\", :partial => 'invitations/generic_invitation', :locals => {:project => @project}\n          page.visual_effect :highlight, \"generic-link\", :duration => 6\n          page.visual_effect :highlight, \"generic-invitation\", :duration => 2\n          page.call '$.jGrowl', l(:notice_successful_update)\n        end\n      end\n    end\n  end\n\n  def join\n    #check token\n    if params[:token] != @project.invitation_token\n      render_error(l(:error_old_invite))\n      return\n    else\n      #add as contributor\n      if @project.root?\n        unless User.current.community_member_of? @project\n          User.current.add_to_project @project, Role.contributor\n          msg = \"Invitation accepted. You are now a contributor of #{@project.name}\"\n          redirect_with_flash :success, msg, :controller => :projects, :action => :show, :id => @project.id\n        else\n          msg = \"You're already on the #{@project.name} team. Invitation ignored\"\n          redirect_with_flash :error, msg, :controller => :projects, :action => :show, :id => @project.id\n        end\n      end\n    end\n  end\n\n  # Show @project\n  def overview\n    if params[:jump]\n      # try to redirect to the requested menu item\n      redirect_to_project_menu_item(@project, params[:jump]) && return\n    end\n\n    @subprojects = @project.descendants.active\n    @news = @project.news.find(:all, :conditions => \" (created_at > '#{Time.now.advance :days => (Setting::DAYS_FOR_LATEST_NEWS * -1)}')\", :limit => 5, :include => [ :author, :project ], :order => \"#{News.table_name}.created_at DESC\")\n    @trackers = @project.rolled_up_trackers\n\n    cond = @project.project_condition(Setting.display_subprojects_issues?)\n\n    @open_issues_by_tracker = Issue.visible.count(:group => :tracker,\n                                            :include => [:project, :status, :tracker],\n                                            :conditions => [\"(#{cond}) AND #{IssueStatus.table_name}.is_closed=?\", false])\n    @total_issues_by_tracker = Issue.visible.count(:group => :tracker,\n                                            :include => [:project, :status, :tracker],\n                                            :conditions => cond)\n\n    @key = User.current.rss_key\n\n    @motions = @project.motions.viewable_by(User.current.position_for(@project)).allactive\n  end\n\n\n  def hourly_types\n    render :json => @project.hourly_types.inject({}) { |hash, hourly_type|\n      hash[hourly_type.id] = hourly_type.name\n      hash\n    }.to_json\n  end\n\n  def community_members\n    render :json => @project.root.all_members.inject({}) { |hash, member|\n      hash[member.user_id] = member.name\n      hash\n    }.to_json\n  end\n\n  def community_members_array\n    array = []\n    @project.root.member_users.each {|m| array.push({:label => \"#{m.user.name} (@#{m.user.login})\", :value => m.user.login, :mail_hash => m.user.mail_hash })}\n    @project.member_users.each {|m| array.push({:label => \"#{m.user.name} (@#{m.user.login})\", :value => m.user.login, :mail_hash => m.user.mail_hash }) }\n    render :json => array.sort{|x,y| x[:label] <=> y[:label]}.uniq.to_json\n  end\n\n  def issue_search\n    term = params[:searchTerm]\n    render :json => Issue.find(:all, :conditions => \"project_id = #{@project.id} AND (subject ilike '%#{term}%' OR CAST(id as varchar) ilike '%#{term}%')\").to_json(:only => [:id, :subject, :description])\n  end\n\n  def all_tags\n    render :json => @project.all_tags(params[:term]).to_json\n  end\n\n\n  def dashboard\n    @credit_base = @project.dpp\n    @show_issue_id = params[:show_issue_id] #Optional parameter to start the dashboard off showing an issue\n    @show_retro_id = params[:show_retro_id] #Optional parameter to start the dashboard off showing a retrospective\n  end\n\n  #TODO: optimize this query, it's WAY too heavy, and we need fewer columns, and it's executing hundreds of queries!\n  def dashdata\n\n    if params[:include_subworkstreams]\n      project_ids = [@project.sub_project_array_visible_to(User.current).join(\",\")]\n    else\n      project_ids = [@project.id]\n    end\n\n    if params[:status_ids]\n      conditions = \"project_id in (#{project_ids}) AND (retro_id < 0 OR retro_id is null) AND status_id in (#{params[:status_ids]})\"\n    else\n      conditions = \"project_id in (#{project_ids}) AND (retro_id < 0 OR retro_id is null)\"\n    end\n\n    render :json => Issue.find(:all, :conditions => conditions)  \\\n                         .to_json(:include => { :journals =>    { :only => [:id, :notes, :created_at, :user_id], :include => {:user => { :only => [:firstname, :lastname, :login] }}},\n                                                :issue_votes => { :include => {:user => { :only => [:firstname, :lastname, :login] }}},\n                                                :status =>      { :only => :name },\n                                                :attachments => { :only => [:id, :filename]},\n                                                :todos =>       { :only => [:id, :subject, :completed_on, :owner_login] },\n                                                :tracker =>     { :only => [:name,:id] },\n                                                :author =>      { :only => [:firstname, :lastname, :login, :mail_hash] },\n                                                :assigned_to => { :only => [:firstname, :lastname, :login] }\n                                                },\n                                                :except => :tags)\n  end\n\n  # Checks to see if any items have changed in this project (in the last params[:seconds]).\n  # If it has, returns only items that have changed\n  def new_dashdata\n    if @project.last_item_updated_on.nil?\n      @project.last_item_updated_on = DateTime.now\n      @project.save\n    end\n\n    if params[:include_subworkstreams]\n      if @project.last_item_sub_updated_on.nil?\n        @project.last_item_sub_updated_on = DateTime.now\n        @project.save\n      end\n\n      project_ids = [@project.sub_project_array_visible_to(User.current).join(\",\")]\n      total_count = (@project.issue_count + @project.issue_count_sub).to_s\n      last_update = @project.last_item_sub_updated_on\n    else\n      project_ids = [@project.id]\n      total_count = @project.issue_count.to_s\n      last_update = @project.last_item_updated_on\n    end\n\n    seconds_ago = params[:seconds].to_f.round\n\n    if (last_update.advance(:seconds => seconds_ago) > DateTime.now)\n      conditions = \"project_id in (#{project_ids}) AND \" +\n        \"updated_at >= '#{@project.last_item_updated_on.advance(:seconds => -1 * seconds_ago)}'\"\n\n      render :json => Issue.find(:all, :conditions => conditions).to_json(\n        :include => {\n          :journals => {\n            :only => [:id, :notes, :created_at, :user_id],\n            :include => {\n              :user => { :only => [:firstname, :lastname, :login] }\n            }\n          },\n          :issue_votes => { :include => {:user => { :only => [:firstname, :lastname, :login] }}},\n          :status =>      { :only => :name },\n          :attachments => { :only => [:id, :filename]},\n          :todos =>       { :only => [:id, :subject, :completed_on, :owner_login] },\n          :tracker =>     { :only => [:name,:id] },\n          :author =>      { :only => [:firstname, :lastname, :login, :mail_hash] },\n          :assigned_to => { :only => [:firstname, :lastname, :login] }\n        },\n        :except => :tags\n      )\n    elsif params[:issuecount] != total_count\n      render :json =>  Issue.find(:all,\n        :conditions => \"project_id in (#{project_ids}) AND (retro_id < 0 OR retro_id is null)\"\n      ).collect {|i| i.id}\n    else\n      render :text => 'no'\n    end\n  end\n\n  def update_scale\n    render :update do |page|\n      page.replace 'point_scale', :partial => 'point_scale', :locals => {:dpp => params[:dpp] }\n      page[\"point_scale\"].visual_effect :highlight\n    end\n  end\n\n  #TODO: remove this function, we're no longer using it??\n  #Returns my priorities for issues belonging to this project\n  def mypris\n    render :json => Issue.find(:all, :conditions => \"project_id = #{@project.id} AND id IN (SELECT DISTINCT issue_id FROM #{Pri.table_name} where user_id = #{User.current.id})\", :select => \"id\").to_json\n  end\n\n  def settings\n    @member ||= @project.all_members.new\n    @trackers = Tracker.all\n    @wiki ||= @project.wiki\n    @allow_logo_selection = true\n  end\n\n  # Edit @project\n  def edit\n    if request.post?\n      old_attributes = @project.attributes\n      @project.attributes = params[:project]\n      @project.is_public = params[:project][:is_public] || false\n      @project.volunteer = params[:project][:volunteer] || false\n\n\n      if (old_attributes[\"is_public\"] != (params[:project][\"is_public\"] == \"1\"))\n        description = (params[:project][\"is_public\"] == \"1\") ? \"publicised\" : \"privatized\"\n          LogActivityStreams.write_single_activity_stream(User.current, :name, @project, :name, description, :workstreams, 0, nil,{})\n      end\n\n      if validate_parent_id && @project.save\n        @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')\n        @project.refresh_active_members\n        flash.now[:success] = l(:notice_successful_update)\n        redirect_to :action => 'settings', :id => @project\n      else\n        settings\n        render :action => 'settings'\n      end\n    end\n  end\n\n  def modules\n    @project.enabled_module_names = params[:enabled_modules]\n    @project.attributes = params[:project]\n    @project.save\n    redirect_with_flash :notice, l(:notice_successful_update), :action => 'settings', :id => @project, :tab => 'modules'\n  end\n\n  def archive\n    if @project.active? && request.post? && @project.archive\n      project_id_override = @project.parent ? @project.parent.id : @project.id #archived projects don't show up in activity stream, so we log the activity to its parent if it exists\n      LogActivityStreams.write_single_activity_stream(User.current, :name, @project, :name, l(:label_archived), :workstreams, 0, nil,{:project_id => project_id_override})\n      redirect_with_flash :notice, l(:notice_successful_update), :controller => \"my\", :action => 'projects'\n    else\n      render_error(l(:error_general))\n    end\n  end\n\n  def unarchive\n    if !@project.active? && request.post? && @project.unarchive\n      LogActivityStreams.write_single_activity_stream(User.current, :name, @project, :name, l(:label_unarchived), :workstreams, 0, nil,{})\n\n      respond_to do |wants|\n\n        wants.js do\n          @my_projects = User.current.owned_projects\n\n          render :update do |page|\n            page.replace params[:table_id], :partial => 'my/my_projects', :locals => {:my_projects => @my_projects, :table_id => params[:table_id]}\n            page.call '$.jGrowl', l(:notice_successful_update)\n            page.call 'display_sparks'\n          end\n        end\n      end\n    else\n      respond_to do |wants|\n        wants.js do\n          render :update do |page|\n            page.call '$.jGrowl', l(:error_general)\n          end\n        end\n      end\n    end\n  end\n\n  # Delete @project\n  def destroy\n    @project_to_destroy = @project\n    if request.post?\n      project_id_override = @project.parent ? @project.parent.id : @project.id #deleted projects don't show up in activity stream, so we log the activity to its parent if it exists\n      LogActivityStreams.write_single_activity_stream(User.current, :name, @project, :name, l(:label_deleted), :workstreams, 0, nil,{:project_id => project_id_override})\n      if @project_to_destroy.destroy\n        redirect_with_flash :notice, l(:notice_successful_delete), :controller => \"welcome\", :action => 'index'\n      else\n        render_error(l(:error_general))\n      end\n    end\n    # hide project in layout\n    @project = nil\n  end\n\n  #move project\n  def move\n    redirect_to(:action => 'settings') and return if @project.root?\n\n    #TODO @project.allowed_parents should be used but it isn't working correctly currently\n    @allowed_projects = []\n    disallowed_projects = @project.self_and_descendants\n    @project.root.self_and_descendants.each {|p| @allowed_projects << p if p.visible_to(User.current) && !disallowed_projects.include?(p) }\n\n    if request.post?\n      if (parent = Project.find params[:parent_id]) && @allowed_projects.include?(parent)\n        @project.move_to_child_of(parent)\n        flash[:success] = l(:notice_successful_update)\n        LogActivityStreams.write_single_activity_stream(User.current, :name, @project, :name, l(:label_moved), :workstreams, 0, nil,{:project_id => @project.id})\n        redirect_to @project\n      else\n        render_403 and return\n      end\n    end\n  end\n\n  def add_file\n    if request.post?\n      container = @project\n      attachments = attach_files(container, params[:attachments])\n      if !attachments.empty? && Setting.notified_events.include?('file_added')\n        Mailer.deliver_attachments_added(attachments)\n      end\n      redirect_to :controller => 'projects', :action => 'list_files', :id => @project\n      return\n    end\n  end\n\n  def list_files\n    sort_init 'filename', 'asc'\n    sort_update 'filename' => \"#{Attachment.table_name}.filename\",\n                'created_at' => \"#{Attachment.table_name}.created_at\",\n                'size' => \"#{Attachment.table_name}.filesize\",\n                'downloads' => \"#{Attachment.table_name}.downloads\"\n\n    @containers = [ Project.find(@project.id, :include => :attachments, :order => sort_clause)]\n    render :layout => !request.xhr?\n  end\n\n  def team\n      @days = Setting.activity_days_default.to_i\n      @hide_view_team_link = true #hides the link to this page from the active box\n  end\n\n  def credits\n    @credits = @project.fetch_credits(params[:with_subprojects])\n\n    @credits_pages, @creditss = @project.fetch_credits(params[:with_subprojects])\n\n\n    @active_credits = @credits.find_all{|credit| credit.enabled == true && credit.settled_on.nil? == true }.group_by{|credit| credit.owner_id}\n    @oustanding_credits = @credits.find_all{|credit| credit.settled_on.nil? == true }.group_by{|credit| credit.owner_id}\n    @total_credits = @credits.group_by{|credit| credit.owner_id}\n  end\n\n  #params that can be passed: length, with_subprojects, and author\n  def activity\n\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  private\n\n  def find_project\n    if (params[:show_issue_id])\n      @project = Issue.find(params[:show_issue_id]).project\n    else\n      @project = Project.find(params[:id])\n    end\n    render_message l(:text_project_locked) if @project.locked?\n\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def find_optional_project\n    return true unless params[:id]\n    @project = Project.find(params[:id])\n    authorize\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def retrieve_selected_tracker_ids(selectable_trackers, default_trackers=nil)\n    if ids = params[:tracker_ids]\n      @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s }\n    else\n      @selected_tracker_ids = (default_trackers || selectable_trackers).collect {|t| t.id.to_s }\n    end\n  end\n\n  # Validates parent_id param according to user's permissions\n  # TODO: move it to Project model in a validation that depends on User.current\n  def validate_parent_id\n    return true if User.current.admin?\n    parent_id = params[:project] && params[:project][:parent_id]\n    if parent_id || @project.new_record?\n      parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i)\n      unless @project.allowed_parents.include?(parent)\n        @project.errors.add :parent_id, :invalid\n        return false\n      end\n    end\n    true\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/queries_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass QueriesController < ApplicationController\n  menu_item :issues\n  before_filter :find_query, :except => :new\n  before_filter :find_optional_project, :only => :new\n\n  def new\n    @query = Query.new(params[:query])\n    @query.project = params[:query_is_for_all] ? nil : @project\n    @query.user = User.current\n    @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?\n    @query.column_names = nil if params[:default_columns]\n\n    params[:fields].each do |field|\n      @query.add_filter(field, params[:operators][field], params[:values][field])\n    end if params[:fields]\n    @query.group_by ||= params[:group_by]\n\n    if request.post? && params[:confirm] && @query.save\n      flash.now[:success] = l(:notice_successful_create)\n      redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query\n      return\n    end\n    render :layout => false if request.xhr?\n  end\n\n  def edit\n    if request.post?\n      @query.filters = {}\n      params[:fields].each do |field|\n        @query.add_filter(field, params[:operators][field], params[:values][field])\n      end if params[:fields]\n      @query.attributes = params[:query]\n      @query.project = nil if params[:query_is_for_all]\n      @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?\n      @query.column_names = nil if params[:default_columns]\n\n      if @query.save\n        flash.now[:success] = l(:notice_successful_update)\n        redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query\n      end\n    end\n  end\n\n  def destroy\n    @query.destroy if request.post?\n    redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1\n  end\n\n  private\n\n  def find_query\n    @query = Query.find(params[:id])\n    @project = @query.project\n    render_403 unless @query.editable_by?(User.current)\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def find_optional_project\n    @project = Project.find(params[:project_id]) if params[:project_id]\n    User.current.allowed_to?(:save_queries, @project, :global => true)\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/quotes_controller.rb",
    "content": "class QuotesController < ApplicationController\n  ssl_required :all\n\n  def index\n    @quotes = Quote.all\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @quotes }\n    end\n  end\n\n  def show\n    @quote = Quote.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @quote }\n    end\n  end\n\n  def new\n    @quote = Quote.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @quote }\n    end\n  end\n\n  def edit\n    @quote = Quote.find(params[:id])\n  end\n\n  def create\n    @quote = Quote.new(params[:quote])\n    @quote.user_id = User.current.id\n\n    respond_to do |format|\n      if @quote.save\n        flash.now[:success] = 'Quote was successfully created.'\n        format.html { redirect_to(@quote) }\n        format.xml  { render :xml => @quote, :status => :created, :location => @quote }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @quote.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @quote = Quote.find(params[:id])\n\n    respond_to do |format|\n      if @quote.update_attributes(params[:quote])\n        flash.now[:success] = 'Quote was successfully updated.'\n        format.html { redirect_to(@quote) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @quote.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @quote = Quote.find(params[:id])\n    @quote.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(quotes_url) }\n      format.xml  { head :ok }\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/recurly_notifications_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass RecurlyNotificationsController < ApplicationController\n  def listen\n    logger.info { \"params #{params.inspect}\" }\n    if params[:updated_subscription_notification]\n      update_subscription(params[:updated_subscription_notification],true)\n    end\n\n    if params[:new_subscription_notification]\n      update_subscription(params[:new_subscription_notification],true)\n    end\n\n    if params[:expired_subscription_notification]\n      update_subscription(params[:expired_subscription_notification],false)\n    end\n\n    render :nothing => true\n  end\n\n  private\n\n  def update_subscription(params,active_subscription)\n    account = params[\"account\"]\n    subscription = params[\"subscription\"]\n    begin\n      user = User.find(account[\"account_code\"])\n\n      if active_subscription\n        user.plan_id = Plan.find_by_code(subscription[\"plan\"][\"plan_code\"]).id\n        user.active_subscription = true\n      else\n        user.plan_id = Plan.find(Plan::FREE_CODE).id\n        user.active_subscription = false\n      end\n      user.save\n      logger.info { \"saved for user #{user.name} new plan #{user.plan_id}\" }\n    rescue Exception => e\n      logger.info { e.inspect }\n    end\n\n  end\nend\n"
  },
  {
    "path": "app/controllers/reports_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass ReportsController < ApplicationController\n  menu_item :issues\n  before_filter :find_project, :authorize\n\n  def issue_report\n    @statuses = IssueStatus.find(:all, :order => 'position')\n\n    case params[:detail]\n    when \"tracker\"\n      @field = \"tracker_id\"\n      @rows = @project.trackers\n      @data = issues_by_tracker\n      @report_title = l(:field_tracker)\n      render :template => \"reports/issue_report_details\"\n    when \"assigned_to\"\n      @field = \"assigned_to_id\"\n      @rows = @project.all_members.collect { |m| m.user }\n      @data = issues_by_assigned_to\n      @report_title = l(:field_assigned_to)\n      render :template => \"reports/issue_report_details\"\n    when \"author\"\n      @field = \"author_id\"\n      @rows = @project.all_members.collect { |m| m.user }\n      @data = issues_by_author\n      @report_title = l(:field_author)\n      render :template => \"reports/issue_report_details\"\n    when \"subproject\"\n      @field = \"project_id\"\n      @rows = @project.descendants.active\n      @data = issues_by_subproject\n      @report_title = l(:field_subproject)\n      render :template => \"reports/issue_report_details\"\n    else\n      @trackers = @project.trackers\n      @categories = @project.issue_categories\n      @assignees = @project.all_members.collect { |m| m.user }\n      @authors = @project.all_members.collect { |m| m.user }\n      @subprojects = @project.descendants.active\n      issues_by_tracker\n      issues_by_assigned_to\n      issues_by_author\n      issues_by_subproject\n\n      render :template => \"reports/issue_report\"\n    end\n  end\n\n  private\n\n  # Find project of id params[:id]\n  def find_project\n    @project = Project.find(params[:id])\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def issues_by_tracker\n    @issues_by_tracker ||=\n        ActiveRecord::Base.connection.select_all(\"select    s.id as status_id,\n                                                  s.is_closed as closed,\n                                                  t.id as tracker_id,\n                                                  count(i.id) as total\n                                                from\n                                                  #{Issue.table_name} i, #{IssueStatus.table_name} s, #{Tracker.table_name} t\n                                                where\n                                                  i.status_id=s.id\n                                                  and i.tracker_id=t.id\n                                                  and i.project_id=#{@project.id}\n                                                group by s.id, s.is_closed, t.id\")\n  end\n\n  def issues_by_assigned_to\n    @issues_by_assigned_to ||=\n      ActiveRecord::Base.connection.select_all(\"select    s.id as status_id,\n                                                  s.is_closed as closed,\n                                                  a.id as assigned_to_id,\n                                                  count(i.id) as total\n                                                from\n                                                  #{Issue.table_name} i, #{IssueStatus.table_name} s, #{User.table_name} a\n                                                where\n                                                  i.status_id=s.id\n                                                  and i.assigned_to_id=a.id\n                                                  and i.project_id=#{@project.id}\n                                                group by s.id, s.is_closed, a.id\")\n  end\n\n  def issues_by_author\n    @issues_by_author ||=\n      ActiveRecord::Base.connection.select_all(\"select    s.id as status_id,\n                                                  s.is_closed as closed,\n                                                  a.id as author_id,\n                                                  count(i.id) as total\n                                                from\n                                                  #{Issue.table_name} i, #{IssueStatus.table_name} s, #{User.table_name} a\n                                                where\n                                                  i.status_id=s.id\n                                                  and i.author_id=a.id\n                                                  and i.project_id=#{@project.id}\n                                                group by s.id, s.is_closed, a.id\")\n  end\n\n  def issues_by_subproject\n    @issues_by_subproject ||=\n      ActiveRecord::Base.connection.select_all(\"select    s.id as status_id,\n                                                  s.is_closed as closed,\n                                                  i.project_id as project_id,\n                                                  count(i.id) as total\n                                                from\n                                                  #{Issue.table_name} i, #{IssueStatus.table_name} s\n                                                where\n                                                  i.status_id=s.id\n                                                  and i.project_id IN (#{@project.descendants.active.collect{|p| p.id}.join(',')})\n                                                group by s.id, s.is_closed, i.project_id\") if @project.descendants.active.any?\n    @issues_by_subproject ||= []\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/reputations_controller.rb",
    "content": "class ReputationsController < ApplicationController\n  ssl_required :all\n\n  def index\n    @reputations = Reputation.all\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @reputations }\n    end\n  end\n\n  def show\n    @reputation = Reputation.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @reputation }\n    end\n  end\n\n  def new\n    @reputation = Reputation.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @reputation }\n    end\n  end\n\n  def edit\n    @reputation = Reputation.find(params[:id])\n  end\n\n  def create\n    @reputation = Reputation.new(params[:reputation])\n\n    respond_to do |format|\n      if @reputation.save\n        flash.now[:success] = 'Reputation was successfully created.'\n        format.html { redirect_to(@reputation) }\n        format.xml  { render :xml => @reputation, :status => :created, :location => @reputation }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @reputation.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @reputation = Reputation.find(params[:id])\n\n    respond_to do |format|\n      if @reputation.update_attributes(params[:reputation])\n        flash.now[:success] = 'Reputation was successfully updated.'\n        format.html { redirect_to(@reputation) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @reputation.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @reputation = Reputation.find(params[:id])\n    @reputation.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(reputations_url) }\n      format.xml  { head :ok }\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/retro_ratings_controller.rb",
    "content": "class RetroRatingsController < ApplicationController\n  ssl_required :all\n\n  def index\n    @retro_ratings = RetroRating.all\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @retro_ratings }\n    end\n  end\n\n  def show\n    @retro_rating = RetroRating.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @retro_rating }\n    end\n  end\n\n  def new\n    @retro_rating = RetroRating.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @retro_rating }\n    end\n  end\n\n  def edit\n    @retro_rating = RetroRating.find(params[:id])\n  end\n\n  def create\n    @retro_ratings = params[:retro_ratings].values.collect { |retro_rating| RetroRating.new(retro_rating) }\n\n    #Archive notification for this retrospective\n    @retro_id = params[:retro_ratings].values[0][\"retro_id\"]\n    @rater_id = params[:retro_ratings].values[0][\"rater_id\"]\n    Notification.update_all \"state = #{Notification::STATE_ARCHIVED}\" , [\"variation = 'retro_started' AND source_id = ? AND recipient_id = ?\", @retro_id, @rater_id]\n\n\n    #TODO: security: make sure to only create ratings if current user is same as rater_id (and user is actually on those teams!)\n    respond_to do |format|\n      if @retro_ratings.all?(&:valid?)\n        RetroRating.delete_all(:rater_id => @retro_ratings[0].rater_id , :retro_id => @retro_ratings[0].retro_id)\n        @retro_ratings.each(&:save!)\n        format.html { redirect_to(@retro_rating) }\n        format.xml  { render :xml => @retro_rating, :status => :created, :location => @retro_rating }\n        format.js  { render :json => @retro_ratings.to_json}\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @retro_rating.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @retro_rating = RetroRating.find(params[:id])\n\n    respond_to do |format|\n      if @retro_rating.update_attributes(params[:retro_rating])\n        flash.now[:success] = 'RetroRating was successfully updated.'\n        format.html { redirect_to(@retro_rating) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @retro_rating.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @retro_rating = RetroRating.find(params[:id])\n    @retro_rating.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(retro_ratings_url) }\n      format.xml  { head :ok }\n    end\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/retros_controller.rb",
    "content": "class RetrosController < ApplicationController\n  before_filter :find_retro, :only => [:show]\n  before_filter :find_project, :only => [:index, :index_json, :dashdata, :new, :edit, :create, :update, :destroy, :show_multiple]\n  before_filter :authorize\n  ssl_required :all\n\n  def index\n    @retros = Retro.all\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @retros }\n    end\n  end\n\n  def index_json\n    render :json => Retro.find(:all, :conditions => {:project_id => @project.id}).to_json\n  end\n\n  def dashdata\n    render :json => Issue.find(:all, :conditions => {:retro_id => params[:id]}).to_json(:include => {:journals => {:include => :user}, :issue_votes => {:include => :user}, :status => {:only => :name}, :todos => {:only => [:id, :subject, :completed_on]}, :tracker => {:only => [:name,:id]}, :author => {:only => [:firstname, :lastname, :login]}, :assigned_to => {:only => [:firstname, :lastname, :login]}})\n  end\n\n  def show\n\n    @retro = Retro.find(params[:id])\n    @team_hash = {}\n    @final_hash = {}\n    @user_retro_hash = {}\n\n    new_user_retro = {\"issues\" => [],\n                    \"total_points\" => 0,\n                    \"percentage_points\" => 0,\n                    \"given_percentage\" => 0,\n                    \"self_bias\" => nil,\n                    \"scale_bias\" => nil,\n                    \"journals\" => [],\n                    \"total_journals\" => 0,\n                    \"votes\" => [],\n                    \"total_votes\" => 0,\n                    \"total_ideas\" => 0\n                    }\n\n    #Calculating oustanding points for entire retrospective\n    @total_points = 0\n    @total_ideas = @retro.issues.length\n\n    @max_range = 0\n    @pie_data_points = []\n    @pie_labels_points = []\n    @max_points = 0\n\n    #Calculating team size for issues (to distribute total points amongst team)\n    issue_team_sizes = Hash.new\n    @retro.issues.each {|issue| issue_team_sizes[issue.id] = 1}\n\n    @retro.issues.each do |issue|\n      issue.issue_votes.each do |issue_vote|\n          next if issue_vote.vote_type != IssueVote::JOIN_VOTE_TYPE\n          #Incrementing team size for the issue\n          issue_team_sizes[issue_vote.issue_id] += 1 if issue_vote.user_id != issue.assigned_to_id\n      end\n    end\n\n    #Adding users that have issues assigned to them and calculating total points for each user\n    issue_group = @retro.issues.group_by{|issue| issue.assigned_to_id}\n    issue_group.each_value {|issues| @total_points += issues.collect(&:points).sum }\n    issue_group.keys.sort.each do |assigned_to_id|\n      next if (@user_retro_hash.has_key? assigned_to_id)  || assigned_to_id == User.sysadmin.id\n      @user_retro_hash.store assigned_to_id, new_user_retro.dup\n      @user_retro_hash[assigned_to_id].store \"issues\", issue_group[assigned_to_id]\n      @user_retro_hash[assigned_to_id].store \"total_points\", 0\n    end\n\n    #Adding users that have joined the issues and calculating total points for each user\n    @retro.issues.each do |issue|\n      points = issue.points.to_f / (issue_team_sizes[issue.id])\n      next if issue.assigned_to_id == User.sysadmin.id\n      @user_retro_hash[issue.assigned_to_id][\"total_points\"]+=points\n      @max_points = @user_retro_hash[issue.assigned_to_id][\"total_points\"] if @user_retro_hash[issue.assigned_to_id][\"total_points\"] > @max_points\n\n      issue.issue_votes.each do |issue_vote|\n        next if issue_vote.vote_type != IssueVote::JOIN_VOTE_TYPE || issue_vote.user_id == User.sysadmin.id\n        if @user_retro_hash.has_key? issue_vote.user_id\n          @user_retro_hash[issue_vote.user_id][\"total_points\"]+=points if issue_vote.user_id != issue.assigned_to_id\n        else\n          @user_retro_hash.store issue_vote.user_id, new_user_retro.dup\n          @user_retro_hash[issue_vote.user_id].store \"issues\", []\n          @user_retro_hash[issue_vote.user_id].store \"total_points\", points\n        end\n        @max_points = @user_retro_hash[issue_vote.user_id][\"total_points\"] if @user_retro_hash[issue_vote.user_id][\"total_points\"] > @max_points\n\n      end\n    end\n\n    @user_retro_hash.delete(nil)\n\n    @user_retro_hash.keys.each do |key|\n      @user_retro_hash[key].store \"percentage_points\", @total_points == 0 ? 100  : (@user_retro_hash[key][\"total_points\"].to_f / @total_points * 100).round_to(0).to_i\n      @pie_data_points << @user_retro_hash[key][\"percentage_points\"]\n      @pie_labels_points << User.find(key).firstname + \" #{@user_retro_hash[key][\"percentage_points\"].to_s}%\"\n    end\n\n\n    @max_ideas = 0\n\n    #Adding users that have authored issues and calculating total ideas generated per user\n    author_group = @retro.issues.group_by{|issue| issue.author_id}\n    author_group.keys.sort.each do |author_id|\n      next if author_id == User.sysadmin.id\n      if !(@user_retro_hash.has_key? author_id)\n        @user_retro_hash.store author_id, new_user_retro.dup\n        @user_retro_hash[author_id].store \"issues\", []\n        @user_retro_hash[author_id].store \"total_points\", 0\n        @user_retro_hash[author_id].store \"percentage_points\", 0\n      end\n      @user_retro_hash[author_id].store \"total_ideas\", author_group[author_id].length\n      @max_ideas = @user_retro_hash[author_id][\"total_ideas\"] if @user_retro_hash[author_id][\"total_ideas\"] > @max_ideas\n    end\n\n    @max_range = @max_ideas if @max_ideas > @max_range\n\n    #Adding users that have authored journals\n    @retro.journals.each do |journal|\n      next if (@user_retro_hash.has_key? journal.user_id) || journal.user_id == User.sysadmin.id\n      @user_retro_hash.store journal.user_id, new_user_retro.dup\n      @user_retro_hash[journal.user_id].store \"issues\", []\n      @user_retro_hash[journal.user_id].store \"total_points\", 0\n      @user_retro_hash[journal.user_id].store \"percentage_points\", 0\n    end\n\n    @confidence_percentage = 100\n    @retro.retro_ratings.each do |retro_rating|\n      next if retro_rating.ratee_id == User.sysadmin.id || retro_rating.rater_id == User.sysadmin.id\n      @user_retro_hash.store retro_rating.ratee_id, new_user_retro.dup unless @user_retro_hash.has_key? retro_rating.ratee_id\n      @user_retro_hash[retro_rating.ratee_id].store \"given_percentage\", retro_rating.score.round if retro_rating.rater_id == User.current.id\n      @confidence_percentage = retro_rating.confidence if retro_rating.rater_id == User.current.id\n      @team_hash[retro_rating.ratee_id] = retro_rating.score.round if retro_rating.rater_id == RetroRating::TEAM_AVERAGE\n      @final_hash[retro_rating.ratee_id] = retro_rating.score.round_to(0) if retro_rating.rater_id == RetroRating::FINAL_AVERAGE\n      @user_retro_hash[retro_rating.ratee_id].store \"self_bias\", retro_rating.score.round if retro_rating.rater_id == RetroRating::SELF_BIAS\n      @user_retro_hash[retro_rating.ratee_id].store \"scale_bias\", retro_rating.score.round if retro_rating.rater_id == RetroRating::SCALE_BIAS\n    end\n\n    #Total journals\n    @total_journals = @retro.journals.length\n    @pie_data_journals = []\n    @pie_labels_journals = []\n    @max_journals = 0\n    journals_group = @retro.journals.group_by{|journal| journal.user_id}\n    journals_group.keys.sort.each do |user_id|\n      next if user_id == User.sysadmin.id\n      @user_retro_hash.store user_id, new_user_retro.dup unless @user_retro_hash.has_key? user_id\n      @user_retro_hash[user_id].store \"journals\", journals_group[user_id]\n      @user_retro_hash[user_id].store \"total_journals\", journals_group[user_id].length\n      @user_retro_hash[user_id].store \"percentage_journals\", (@user_retro_hash[user_id][\"total_journals\"].to_f / @total_journals * 100).round_to(0).to_i\n      @max_journals = @user_retro_hash[user_id][\"total_journals\"] if @user_retro_hash[user_id][\"total_journals\"] > @max_journals\n      @pie_data_journals << @user_retro_hash[user_id][\"percentage_journals\"]\n      @pie_labels_journals << User.find(user_id).firstname + \" #{@user_retro_hash[user_id][\"percentage_journals\"].to_s}%\"\n    end\n\n    @max_range = @max_journals if @max_journals > @max_range\n\n    #Total voting activity\n    @total_votes = @retro.issue_votes.length\n    @pie_data_votes = []\n    @pie_labels_votes = []\n    @max_votes = 0\n    votes_group = @retro.issue_votes.group_by{|issue_vote| issue_vote.user_id}\n    votes_group.keys.sort.each do |user_id|\n      next if user_id == User.sysadmin.id\n      @user_retro_hash.store user_id, new_user_retro.dup unless @user_retro_hash.has_key? user_id\n      @user_retro_hash[user_id].store \"votes\", votes_group[user_id]\n      @user_retro_hash[user_id].store \"total_votes\", votes_group[user_id].length\n      @user_retro_hash[user_id].store \"percentage_votes\", (@user_retro_hash[user_id][\"total_votes\"].to_f / @total_votes * 100).round_to(0).to_i\n      @max_votes = @user_retro_hash[user_id][\"total_votes\"] if @user_retro_hash[user_id][\"total_votes\"] > @max_votes\n      @pie_data_votes << @user_retro_hash[user_id][\"percentage_votes\"]\n      @pie_labels_votes << User.find(user_id).firstname + \" #{@user_retro_hash[user_id][\"percentage_votes\"].to_s}%\"\n    end\n\n    #Total ideas\n    @total_ideas = @retro.issues.length\n    @pie_data_ideas = []\n    @pie_labels_ideas = []\n\n    author_group.keys.sort.each do |author_id|\n      next if author_id == User.sysadmin.id\n      percentage = (@user_retro_hash[author_id][\"total_ideas\"].to_f / @total_ideas * 100).round_to(0).to_i\n      @pie_data_ideas << percentage\n      @pie_labels_ideas << User.find(author_id).firstname + \" #{percentage.to_s}%\"\n    end\n\n    @max_range = @max_votes if @max_votes > @max_range\n\n    #Build Chart\n    @point_totals = []\n    @vote_totals = []\n    @journal_totals = []\n    @idea_totals = []\n    @axis_labels = []\n    x_axis = ''\n\n\n    @user_retro_hash.keys.sort.each do |user_id|\n      @point_totals << @user_retro_hash[user_id][\"total_points\"]\n      @vote_totals << @user_retro_hash[user_id][\"total_votes\"]\n      @journal_totals << @user_retro_hash[user_id][\"total_journals\"]\n      @idea_totals << @user_retro_hash[user_id][\"total_ideas\"]\n      x_axis = x_axis + User.find(user_id).firstname + '|'\n    end\n    @axis_labels << x_axis\n\n    #Average time taken to complete a point?\n\n    respond_to do |format|\n      format.html { render :layout => 'blank'}# show.html.erb\n      format.xml  { render :xml => @retro }\n    end\n  end\n\n  def new\n    @retro = Retro.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @retro }\n    end\n  end\n\n  def edit\n    @retro = Retro.find(params[:id])\n  end\n\n  def create\n    @retro = Retro.new(params[:retro])\n\n    respond_to do |format|\n      if @retro.save\n        flash.now[:success] = 'Retro was successfully created.'\n        format.html { redirect_to(@retro) }\n        format.xml  { render :xml => @retro, :status => :created, :location => @retro }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @retro.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @retro = Retro.find(params[:id])\n\n    respond_to do |format|\n      if @retro.update_attributes(params[:retro])\n        flash.now[:success] = 'Retro was successfully updated.'\n        format.html { redirect_to(@retro) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @retro.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @retro = Retro.find(params[:id])\n    @retro.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(retros_url) }\n      format.xml  { head :ok }\n    end\n  end\n\n  private\n\n  def find_retro\n    @retro = Retro.find(params[:id])\n    @project = @retro.project\n    render_message l(:text_project_locked) if @project.locked?\n  end\n\n\n  def find_project\n    @project = Project.find(params[:project_id])\n    render_message l(:text_project_locked) if @project.locked?\n  end\nend\n"
  },
  {
    "path": "app/controllers/roles_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass RolesController < ApplicationController\n  layout 'admin'\n\n  before_filter :require_admin\n  ssl_required :all\n\n  verify :method => :post, :only => [ :destroy, :move ],\n         :redirect_to => { :action => :list }\n\n  def index\n    list\n    render :action => 'list' unless request.xhr?\n  end\n\n  def list\n    @role_pages, @roles = paginate :roles, :per_page => 25, :order => 'builtin, position'\n    render :action => \"list\", :layout => false if request.xhr?\n  end\n\n  def new\n    # Prefills the form with 'Non member' role permissions\n    @role = Role.new(params[:role] || {:permissions => Role.non_member.permissions})\n    if request.post? && @role.save\n      # workflow copy\n      if !params[:copy_workflow_from].blank? && (copy_from = Role.find_by_id(params[:copy_workflow_from]))\n        @role.workflows.copy(copy_from)\n      end\n      flash.now[:success] = l(:notice_successful_create)\n      redirect_to :action => 'index'\n    end\n    @permissions = @role.setable_permissions\n    @roles = Role.find :all, :order => 'builtin, position'\n  end\n\n  def edit\n    @role = Role.find(params[:id])\n    if request.post? and @role.update_attributes(params[:role])\n      flash.now[:success] = l(:notice_successful_update)\n      redirect_to :action => 'index'\n    end\n    @permissions = @role.setable_permissions\n  end\n\n  def destroy\n    @role = Role.find(params[:id])\n    @role.destroy\n    redirect_to :action => 'index'\n  rescue\n    flash.now[:error] = 'This role is in use and can not be deleted.'\n    redirect_to :action => 'index'\n  end\n\n  def report\n    @roles = Role.find(:all, :order => 'builtin, position')\n    @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? }\n    if request.post?\n      @roles.each do |role|\n        role.permissions = params[:permissions][role.id.to_s]\n        role.save\n      end\n      flash.now[:success] = l(:notice_successful_update)\n      redirect_to :action => 'index'\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/search_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass SearchController < ApplicationController\n  before_filter :find_optional_project\n  ssl_required :all\n\n  helper :messages\n  include MessagesHelper\n\n  def index\n    @question = params[:q] || \"\"\n    @question.strip!\n    @all_words = params[:all_words] || (params[:submit] ? false : true)\n    @titles_only = !params[:titles_only].nil?\n\n    projects_to_search =\n      case params[:scope]\n      when 'all'\n        nil\n      when 'my_projects'\n        User.current.memberships.collect(&:project)\n      when 'subprojects'\n        @project ? (@project.self_and_descendants.active) : nil\n      else\n        @project\n      end\n\n    offset = nil\n    begin; offset = params[:offset].to_time if params[:offset]; rescue; end\n\n    # quick jump to an issue\n    if @question.match(/^#?(\\d+)$/) && Issue.visible.find_by_id($1)\n      redirect_to :controller => \"issues\", :action => \"show\", :id => $1\n      return\n    end\n\n    @object_types = %w(issues news documents wiki_pages messages projects)\n    if projects_to_search.is_a? Project\n      # don't search projects\n      @object_types.delete('projects')\n      # only show what the user is allowed to view\n      @object_types = @object_types.select {|o| User.current.allowed_to?(\"view_#{o}\".to_sym, projects_to_search)}\n    end\n\n    @scope = @object_types.select {|t| params[t]}\n    @scope = @object_types if @scope.empty?\n\n    # extract tokens from the question\n    # eg. hello \"bye bye\" => [\"hello\", \"bye bye\"]\n    @tokens = @question.scan(%r{((\\s|^)\"[\\s\\w]+\"(\\s|$)|\\S+)}).collect {|m| m.first.gsub(%r{(^\\s*\"\\s*|\\s*\"\\s*$)}, '')}\n    # tokens must be at least 3 character long\n    @tokens = @tokens.uniq.select {|w| w.length > 2 }\n\n    if !@tokens.empty?\n      # no more than 5 tokens to search for\n      @tokens.slice! 5..-1 if @tokens.size > 5\n      # strings used in sql like statement\n      like_tokens = @tokens.collect {|w| \"%#{w.downcase}%\"}\n\n      @results = []\n      @results_by_type = Hash.new {|h,k| h[k] = 0}\n\n      limit = 10\n      @scope.each do |s|\n        r, c = s.singularize.camelcase.constantize.search(like_tokens, projects_to_search,\n          :all_words => @all_words,\n          :titles_only => @titles_only,\n          :limit => (limit+1),\n          :offset => offset,\n          :before => params[:previous].nil?)\n        @results += r\n        @results_by_type[s] += c\n      end\n      @results = @results.sort {|a,b| b.event_datetime <=> a.event_datetime}\n      if params[:previous].nil?\n        @pagination_previous_date = @results[0].event_datetime if offset && @results[0]\n        if @results.size > limit\n          @pagination_next_date = @results[limit-1].event_datetime\n          @results = @results[0, limit]\n        end\n      else\n        @pagination_next_date = @results[-1].event_datetime if offset && @results[-1]\n        if @results.size > limit\n          @pagination_previous_date = @results[-(limit)].event_datetime\n          @results = @results[-(limit), limit]\n        end\n      end\n    else\n      @question = \"\"\n    end\n    render :layout => false if request.xhr?\n  end\n\n  private\n\n  def find_optional_project\n    return true unless params[:id]\n    @project = Project.find(params[:id])\n    check_project_privacy\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/settings_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n# This program is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation; either version 2\n# of the License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n\nclass SettingsController < ApplicationController\n  layout 'admin'\n\n  before_filter :require_admin\n\n  def index\n    edit\n    render :action => 'edit'\n  end\n\n  def edit\n    @notifiables = %w(issue_added issue_updated news_added document_added file_added message_posted wiki_content_added wiki_content_updated)\n    if request.post? && params[:settings] && params[:settings].is_a?(Hash)\n      settings = (params[:settings] || {}).dup.symbolize_keys\n      settings.each do |name, value|\n        # remove blank values in array settings\n        value.delete_if {|v| v.blank? } if value.is_a?(Array)\n        Setting[name] = value\n      end\n      flash.now[:success] = l(:notice_successful_update)\n      redirect_to :action => 'edit', :tab => params[:tab]\n      return\n    end\n    @options = {}\n    @options[:user_format] = User::USER_FORMATS.keys.collect {|f| [User.current.name(f), f.to_s] }\n    @deliveries = ActionMailer::Base.perform_deliveries\n\n    @guessed_host_and_path = request.host_with_port.dup\n    @guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\\/}, '')) unless Redmine::Utils.relative_url_root.blank?\n  end\n\n  def plugin\n    @plugin = Redmine::Plugin.find(params[:id])\n    if request.post?\n      Setting[\"plugin_#{@plugin.id}\"] = params[:settings]\n      flash.now[:success] = l(:notice_successful_update)\n      redirect_to :action => 'plugin', :id => @plugin.id\n    end\n    @partial = @plugin.settings[:partial]\n    @settings = Setting[\"plugin_#{@plugin.id}\"]\n  rescue Redmine::PluginNotFound\n    render_404\n  end\nend\n"
  },
  {
    "path": "app/controllers/shares_controller.rb",
    "content": "class SharesController < ApplicationController\n  ssl_required :all\n\n  def index\n    @shares = Share.all\n    @project = Project.find(params[:project_id]) unless params[:project_id].nil?\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @shares }\n    end\n  end\n\n  def show\n    @share = Share.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @share }\n    end\n  end\n\n  def new\n    @share = Share.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @share }\n    end\n  end\n\n  def edit\n    @share = Share.find(params[:id])\n  end\n\n  def create\n    @share = Share.new(params[:share])\n\n    respond_to do |format|\n      if @share.save\n        flash.now[:success] = 'Share was successfully created.'\n        format.html { redirect_to(@share) }\n        format.xml  { render :xml => @share, :status => :created, :location => @share }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @share.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @share = Share.find(params[:id])\n\n    respond_to do |format|\n      if @share.update_attributes(params[:share])\n        flash.now[:success] = 'Share was successfully updated.'\n        format.html { redirect_to(@share) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @share.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @share = Share.find(params[:id])\n    @share.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(shares_url) }\n      format.xml  { head :ok }\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/todos_controller.rb",
    "content": "class TodosController < ApplicationController\n\n  before_filter :find_issue, :only => [:index, :create, :update, :destroy ]\n  before_filter :find_project, :authorize\n  ssl_required :all\n\n  def index\n    @todos = Todo.all\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @todos }\n    end\n  end\n\n  def show\n    @todo = Todo.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @todo }\n    end\n  end\n\n  def new\n    @todo = Todo.new\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @todo }\n    end\n  end\n\n  def edit\n    @todo = Todo.find(params[:id])\n  end\n\n  def create\n    @todo = Todo.new(params[:todo])\n    @todo.issue_id = @issue.id\n\n    respond_to do |format|\n      if @todo.save\n        @issue.reload\n        format.js {render :json => @issue.to_dashboard}\n        format.html { redirect_to(@todo) }\n        format.xml  { render :xml => @todo, :status => :created, :location => @todo }\n      else\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @todo.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def update\n    @todo = Todo.find(params[:id])\n\n    respond_to do |format|\n      if @todo.update_attributes(params[:todo])\n        @issue.reload\n        format.js {render :json => @issue.to_dashboard}\n        format.html { redirect_to(@todo) }\n        format.xml  { head :ok }\n      else\n        format.html { render :action => \"edit\" }\n        format.xml  { render :xml => @todo.errors, :status => :unprocessable_entity }\n      end\n    end\n  end\n\n  def destroy\n    @todo = Todo.find(params[:id])\n    @todo.destroy\n\n    respond_to do |format|\n      format.js {render :json => @issue.to_dashboard}\n      format.html { redirect_to(todos_url) }\n      format.xml  { head :ok }\n    end\n  end\n\n  private\n\n  def find_issue\n    @issue = Issue.find(params[:issue_id])\n  end\n\n  def find_project\n    @project = @issue.project\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/trackers_controller.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass TrackersController < ApplicationController\n  layout 'admin'\n\n  before_filter :require_admin\n  ssl_required :all\n\n  def index\n    list\n    render :action => 'list' unless request.xhr?\n  end\n\n  verify :method => :post, :only => :destroy, :redirect_to => { :action => :list }\n\n  def list\n    @tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position'\n    render :action => \"list\", :layout => false if request.xhr?\n  end\n\n  def new\n    @tracker = Tracker.new(params[:tracker])\n    if request.post? and @tracker.save\n      # workflow copy\n      if !params[:copy_workflow_from].blank? && (copy_from = Tracker.find_by_id(params[:copy_workflow_from]))\n        @tracker.workflows.copy(copy_from)\n      end\n      flash.now[:success] = l(:notice_successful_create)\n      redirect_to :action => 'list'\n      return\n    end\n    @trackers = Tracker.find :all, :order => 'position'\n    @projects = Project.find(:all)\n  end\n\n  def edit\n    @tracker = Tracker.find(params[:id])\n    if request.post? and @tracker.update_attributes(params[:tracker])\n      flash.now[:success] = l(:notice_successful_update)\n      redirect_to :action => 'list'\n      return\n    end\n    @projects = Project.find(:all)\n  end\n\n  def destroy\n    @tracker = Tracker.find(params[:id])\n    unless @tracker.issues.empty?\n      flash.now[:error] = \"This tracker contains issues and can\\'t be deleted.\"\n    else\n      @tracker.destroy\n    end\n    redirect_to :action => 'list'\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/users_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass UsersController < ApplicationController\n\n  before_filter :require_admin, :except => [:show, :rpx_token]\n  ssl_required :all\n\n  helper :sort\n  include SortHelper\n\n  def index\n    sort_init 'login', 'asc'\n    sort_update %w(login firstname lastname mail admin created_at last_login_on)\n\n    @status = params[:status] ? params[:status].to_i : 1\n    c = ARCondition.new(@status == 0 ? \"status <> 0\" : [\"status = ?\", @status])\n\n    unless params[:name].blank?\n      name = \"%#{params[:name].strip.downcase}%\"\n      c << [\"LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ? OR LOWER(mail) LIKE ?\", name, name, name, name]\n    end\n\n    @user_count = User.count(:conditions => c.conditions)\n    @user_pages = Paginator.new self, @user_count,\n                per_page_option,\n                params['page']\n    @users =  User.find :all,:order => sort_clause,\n                        :conditions => c.conditions,\n            :limit  =>  @user_pages.items_per_page,\n            :offset =>  @user_pages.current.offset\n\n    render :layout => !request.xhr?\n  end\n\n  def show\n    @user = User.find(params[:id])\n\n    # show only public projects and private projects that the logged in user is also a member of\n    @memberships = @user.memberships.select do |membership|\n      membership.project.visible_to(User.current)\n    end\n\n    # show only public projects and private projects that the logged in user is also a member of\n    @reputations = @user.reputations.select do |reputation|\n      reputation.project_id == 0 || reputation.project.visible_to(User.current)\n    end\n\n    flash.now[:notice] = l(:notice_this_is_your_profie) if @user == User.current\n\n    render :layout => 'gooey'\n\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  def add\n    if request.get?\n      @user = User.new(:language => Setting.default_language)\n    else\n      @user = User.new(params[:user])\n      @user.admin = params[:user][:admin] || false\n      @user.login = params[:user][:login]\n      @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless @user.auth_source_id\n      if @user.save\n        Mailer.deliver_account_information(@user, params[:password]) if params[:send_information]\n        flash.now[:success] = l(:notice_successful_create)\n        redirect_to(params[:continue] ? {:controller => 'users', :action => 'add'} :\n                                        {:controller => 'users', :action => 'edit', :id => @user})\n        return\n      end\n    end\n    @auth_sources = AuthSource.find(:all)\n  end\n\n  def edit\n    @user = User.find(params[:id])\n    if request.post?\n      @user.admin = params[:user][:admin] if params[:user][:admin]\n      @user.login = params[:user][:login] if params[:user][:login]\n      @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless params[:password].nil? or params[:password].empty? or @user.auth_source_id\n      @user.group_ids = params[:user][:group_ids] if params[:user][:group_ids]\n      @user.attributes = params[:user]\n      # Was the account actived ? (do it before User#save clears the change)\n      was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])\n      if @user.save\n        if was_activated\n          Mailer.deliver_account_activated(@user)\n        elsif @user.active? && params[:send_information] && !params[:password].blank? && @user.auth_source_id.nil?\n          Mailer.deliver_account_information(@user, params[:password])\n        end\n        flash.now[:success] = l(:notice_successful_update)\n        redirect_to :back\n      end\n    end\n    @auth_sources = AuthSource.find(:all)\n    @membership ||= Member.new\n  rescue ::ActionController::RedirectBackError\n    redirect_to :controller => 'users', :action => 'edit', :id => @user\n  end\n\n  def edit_membership\n    @user = User.find(params[:id])\n    @membership = params[:membership_id] ? Member.find(params[:membership_id]) : Member.new(:user => @user)\n    @membership.attributes = params[:membership]\n    @membership.save if request.post?\n    respond_to do |format|\n       format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }\n       format.js {\n         render(:update) {|page|\n           page.replace_html \"tab-content-memberships\", :partial => 'users/memberships'\n           page.visual_effect(:highlight, \"member-#{@membership.id}\")\n         }\n       }\n     end\n  end\n\n  def destroy_membership\n    @user = User.find(params[:id])\n    @membership = Member.find(params[:membership_id])\n    if request.post? && @membership.deletable?\n      @membership.destroy\n    end\n    respond_to do |format|\n      format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }\n      format.js { render(:update) {|page| page.replace_html \"tab-content-memberships\", :partial => 'users/memberships'} }\n    end\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/votes_controller.rb",
    "content": "# An example controller for \"votes\" that are nested resources under users. See examples/routes.rb\n\nclass VotesController < ApplicationController\n\n  # First, figure out our nested scope. User or issue?\n  before_filter :find_votes_for_my_scope, :only => [:index]\n  ssl_required :all\n\n  #TODO: figure out the equivalent of login_required in redmine and fix this line\n  before_filter :must_own_vote,  :only => [:edit, :destroy, :update]\n  before_filter :not_allowed,    :only => [:edit, :update, :new]\n\n  def index\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @votes }\n    end\n  end\n\n  def show\n    @issue = Vote.find(params[:id])\n\n    respond_to do |format|\n      format.html\n      format.xml  { render :xml => @vote }\n    end\n  end\n\n  def new\n  end\n\n  def edit\n  end\n\n  def create\n\n    # TODO: Is there a way to cast the model from :voteable_type automatically?\n    # Depending on the type of voteable, we dig it up from a different model\n    # See Railscast #154 for find_commentable method\n    case params[:voteable_type]\n    when \"issue\"\n      @voteable = Issue.find(params[:issue_id])\n    when \"journal\"\n      @voteable = Journal.find(params[:journal_id])\n    when \"message\"\n      @voteable = Message.find(params[:message_id])\n    when \"reply\"\n      @voteable = Message.find(params[:reply_id])\n    end\n\n    respond_to do |format|\n      if User.current.vote(@voteable, params[:vote])\n        format.js  { render :action => \"create\", :vote => @vote, :voteable_type => params[:voteable_type] }\n        format.html { redirect_to([@voteable.author, @voteable]) }\n        format.xml  { render :xml => @voteable, :status => :created, :location => @voteable }\n      else\n        format.js  { render :action => \"error\" }\n        format.html { render :action => \"new\" }\n        format.xml  { render :xml => @vote.errors, :status => :unprocessable_entity }\n      end\n    end\n\n  end\n\n  def update\n  end\n\n  def destroy\n    @vote = Vote.find(params[:id])\n    @vote.destroy\n\n    respond_to do |format|\n      format.html { redirect_to(user_votes_url) }\n      format.xml  { head :ok }\n    end\n  end\n\n  private\n\n  def find_votes_for_my_scope\n    if params[:issue_id]\n      @votes = Vote.for_voteable(issue.find(params[:issue_id])).descending\n    elsif params[:user_id]\n      @votes = Vote.for_voter(User.find(params[:user_id])).descending\n    else\n      @votes = []\n    end\n  end\n\n  def must_own_vote\n    @vote ||= Vote.find(params[:id])\n    @vote.user == current_user || ownership_violation\n  end\n\n  def ownership_violation\n    respond_to do |format|\n      flash.now[:error] = 'You cannot edit or delete votes that you do not own!'\n      format.html do\n        redirect_to user_path(User.current)\n      end\n    end\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/watchers_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass WatchersController < ApplicationController\n  before_filter :find_project\n  before_filter :require_login, :check_project_privacy, :only => [:watch, :unwatch]\n  before_filter :authorize, :only => [:new, :destroy]\n  ssl_required :all\n\n  verify :method => :post,\n         :only => [ :watch, :unwatch ],\n         :render => { :nothing => true, :status => :method_not_allowed }\n\n  def watch\n    if @watched.respond_to?(:visible?) && !@watched.visible?(User.current)\n      render_403\n    else\n      set_watcher(User.current, true)\n    end\n  end\n\n  def unwatch\n    set_watcher(User.current, false)\n  end\n\n  def new\n    @watcher = Watcher.new(params[:watcher])\n    @watcher.watchable = @watched\n    @watcher.save if request.post?\n    respond_to do |format|\n      format.html { redirect_to :back }\n      format.js do\n        render :update do |page|\n          page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched}\n        end\n      end\n    end\n  rescue ::ActionController::RedirectBackError\n    render :text => 'Watcher added.', :layout => true\n  end\n\n  def destroy\n    @watched.set_watcher(User.find(params[:user_id]), false) if request.post?\n    respond_to do |format|\n      format.html { redirect_to :back }\n      format.js do\n        render :update do |page|\n          page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched}\n        end\n      end\n    end\n  end\n\n  private\n\n  def find_project\n    klass = Object.const_get(params[:object_type].camelcase)\n    return false unless klass.respond_to?('watched_by')\n    @watched = klass.find(params[:object_id])\n    @project = @watched.project\n  rescue\n    render_404\n  end\n\n  def set_watcher(user, watching)\n    @watched.set_watcher(user, watching)\n    if params[:replace].present?\n      if params[:replace].is_a? Array\n        replace_ids = params[:replace]\n      else\n        replace_ids = [params[:replace]]\n      end\n    else\n      replace_ids = 'watcher'\n    end\n    respond_to do |format|\n      format.html { redirect_to :back }\n      format.js do\n        render(:update) do |page|\n          replace_ids.each do |replace_id|\n            page.replace_html replace_id, watcher_link(@watched, user, :replace => replace_ids)\n          end\n        end\n      end\n    end\n  rescue ::ActionController::RedirectBackError\n    render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/welcome_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass WelcomeController < ApplicationController\n  caches_action :robots\n  ssl_required :all\n\n  before_filter :require_login, :except => :robots\n\n  def index\n    @my_projects = User.current.recent_projects(10)\n\n    unless @my_projects.nil?\n      @news = News.find(:all,\n                               :limit => 30,\n                               :order => \"#{News.table_name}.created_at DESC\",\n                               :conditions => \"#{News.table_name}.project_id in (#{User.current.projects.collect{|m| m.id}.join(',')}) AND (created_at > '#{Time.now.advance :days => (Setting::DAYS_FOR_LATEST_NEWS * -1)}')\",\n                               :include => [:project, :author]) unless User.current.projects.empty?\n\n      @assigned_issues = Issue.visible.open.find(:all,\n                                      :conditions => [\"#{IssueVote.table_name}.user_id = ? AND #{IssueVote.table_name}.vote_type = ? AND #{Issue.table_name}.status_id = ?\", User.current.id, IssueVote::JOIN_VOTE_TYPE, IssueStatus.assigned.id],\n                                      :include => [:project, :tracker, :issue_votes ],\n                                      :order => \"#{Project.table_name}.name ASC\")\n    end\n  end\n\n  def robots\n    @projects = Project.all_public.active\n    render :layout => false, :content_type => 'text/plain'\n  end\nend\n"
  },
  {
    "path": "app/controllers/wiki_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nrequire 'diff'\n\nclass WikiController < ApplicationController\n  default_search_scope :wiki_pages\n  before_filter :find_wiki, :authorize\n  before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy]\n  ssl_required :all\n\n\n  verify :method => :post, :only => [:destroy, :protect], :redirect_to => { :action => :index }\n\n  helper :attachments\n  include AttachmentsHelper\n  helper :watchers\n\n  log_activity_streams :current_user, :name, :attached, :@page, :title, :add_attachment, :wikis, {}\n\n  # display a page (in editing mode if it doesn't exist)\n  def index\n    page_title = params[:page]\n    @page = @wiki.find_or_new_page(page_title)\n    if @page.new_record?\n      if User.current.allowed_to?(:edit_wiki_pages, @project)\n        edit\n        render :action => 'edit'\n      else\n        render_404\n      end\n      return\n    end\n    if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)\n      # Redirects user to the current version if he's not allowed to view previous versions\n      redirect_to :version => nil\n      return\n    end\n    @content = @page.content_for_version(params[:version])\n    if params[:format] == 'html'\n      export = render_to_string :action => 'export', :layout => false\n      send_data(export, :type => 'text/html', :filename => \"#{@page.title}.html\")\n      return\n    elsif params[:format] == 'txt'\n      send_data(@content.text, :type => 'text/plain', :filename => \"#{@page.title}.txt\")\n      return\n    end\n  @editable = editable?\n    render :action => 'show'\n  end\n\n  # edit an existing page or a new one\n  def edit\n    @page = @wiki.find_or_new_page(params[:page])\n    return render_403 unless editable?\n    @page.content = WikiContent.new(:page => @page) if @page.new_record?\n\n    @content = @page.content_for_version(params[:version])\n    @content.text = initial_page_content(@page) if @content.text.blank?\n    # don't keep previous comment\n    @content.comments = nil\n    if request.get?\n      # To prevent StaleObjectError exception when reverting to a previous version\n      @content.version = @page.content.version\n    else\n      if !@page.new_record? && @content.text == params[:content][:text]\n        # don't save if text wasn't changed\n        redirect_to :action => 'index', :id => @project, :page => @page.title\n        return\n      end\n      @content.text = params[:content][:text]\n      @content.comments = params[:content][:comments]\n      @content.attributes = params[:content]\n      @content.author = User.current\n      # if page is new @page.save will also save content, but not if page isn't a new record\n      if @page.new_record?\n        @page.save\n        LogActivityStreams.write_single_activity_stream(User.current, :name, @page, :title, :created, :wikis, 0, nil,{})\n        redirect_to :action => 'index', :id => @project, :page => @page.title\n      else\n        @content.save\n        LogActivityStreams.write_single_activity_stream(User.current, :name, @page, :title, :edited, :wikis, 0, nil,{})\n        redirect_to :action => 'index', :id => @project, :page => @page.title\n      end\n    end\n  rescue ActiveRecord::StaleObjectError\n    # Optimistic locking exception\n    flash.now[:error] = l(:notice_locking_conflict)\n  end\n\n  # rename a page\n  def rename\n    return render_403 unless editable?\n    @page.redirect_existing_links = true\n    # used to display the *original* title if some AR validation errors occur\n    @original_title = @page.pretty_title\n    if request.post? && @page.update_attributes(params[:wiki_page])\n      flash.now[:success] = l(:notice_successful_update)\n      redirect_to :action => 'index', :id => @project, :page => @page.title\n    end\n  end\n\n  def protect\n    @page.update_attribute :protected, params[:protected]\n    redirect_to :action => 'index', :id => @project, :page => @page.title\n  end\n\n  # show page history\n  def history\n    @version_count = @page.content.versions.count\n    @version_pages = Paginator.new self, @version_count, per_page_option, params['p']\n    # don't load text\n    @versions = @page.content.versions.find :all,\n                                            :select => \"id, author_id, comments, updated_at, version\",\n                                            :order => 'version DESC',\n                                            :limit  =>  @version_pages.items_per_page + 1,\n                                            :offset =>  @version_pages.current.offset\n\n    render :layout => false if request.xhr?\n  end\n\n  def diff\n    @diff = @page.diff(params[:version], params[:version_from])\n    render_404 unless @diff\n  end\n\n  def annotate\n    @annotate = @page.annotate(params[:version])\n    render_404 unless @annotate\n  end\n\n  # Removes a wiki page and its history\n  # Children can be either set as root pages, removed or reassigned to another parent page\n  def destroy\n    return render_403 unless editable?\n\n    @descendants_count = @page.descendants.size\n    if @descendants_count > 0\n      case params[:todo]\n      when 'nullify'\n        # Nothing to do\n      when 'destroy'\n        # Removes all its descendants\n        @page.descendants.each(&:destroy)\n      when 'reassign'\n        # Reassign children to another parent page\n        reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)\n        return unless reassign_to\n        @page.children.each do |child|\n          child.update_attribute(:parent, reassign_to)\n        end\n      else\n        @reassignable_to = @wiki.pages - @page.self_and_descendants\n        return\n      end\n    end\n    @page.destroy\n    redirect_to :action => 'special', :id => @project, :page => 'Page_index'\n  end\n\n  # display special pages\n  def special\n    page_title = params[:page].downcase\n    case page_title\n    # show pages index, sorted by title\n    when 'page_index', 'date_index'\n      # eager load information about last updates, without loading text\n      @pages = @wiki.pages.find :all, :select => \"#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_at\",\n                                      :joins => \"LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id\",\n                                      :order => 'title'\n      @pages_by_date = @pages.group_by {|p| p.updated_at.to_date}\n      @pages_by_parent_id = @pages.group_by(&:parent_id)\n    # export wiki to a single html file\n    when 'export'\n      @pages = @wiki.pages.find :all, :order => 'title'\n      export = render_to_string :action => 'export_multiple', :layout => false\n      send_data(export, :type => 'text/html', :filename => \"wiki.html\")\n      return\n    else\n      # requested special page doesn't exist, redirect to default page\n      redirect_to :action => 'index', :id => @project, :page => nil\n      return\n    end\n    render :action => \"special_#{page_title}\"\n  end\n\n  def preview\n    page = @wiki.find_page(params[:page])\n    # page is nil when previewing a new page\n    return render_403 unless page.nil? || editable?(page)\n    if page\n      @attachements = page.attachments\n      @previewed = page.content\n    end\n    @text = params[:content][:text]\n    render :partial => 'common/preview'\n  end\n\n  def add_attachment\n    return render_403 unless editable?\n    attach_files(@page, params[:attachments])\n    redirect_to :action => 'index', :page => @page.title\n  end\n\n  private\n\n  def find_wiki\n    @project = Project.find(params[:id])\n    render_message l(:text_project_locked) if @project.locked?\n\n    @wiki = @project.wiki\n    render_404 unless @wiki\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\n  # Finds the requested page and returns a 404 error if it doesn't exist\n  def find_existing_page\n    @page = @wiki.find_page(params[:page])\n    render_404 if @page.nil?\n  end\n\n  # Returns true if the current user is allowed to edit the page, otherwise false\n  def editable?(page = @page)\n    page.editable_by?(User.current)\n  end\n\n  # Returns the default content of a new wiki page\n  def initial_page_content(page)\n    helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)\n    extend helper unless self.instance_of?(helper)\n    helper.instance_method(:initial_page_content).bind(self).call(page)\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/wikis_controller.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass WikisController < ApplicationController\n  menu_item :settings\n  before_filter :find_project, :authorize\n  ssl_required :all\n\n  # Create or update a project's wiki\n  def edit\n    @wiki = @project.wiki || Wiki.new(:project => @project)\n    @wiki.attributes = params[:wiki]\n    @wiki.save if request.post?\n    render(:update) {|page| page.replace_html \"tab-content-wiki\", :partial => 'projects/settings/wiki'}\n  end\n\n  # Delete a project's wiki\n  def destroy\n    if request.post? && params[:confirm] && @project.wiki\n      @project.wiki.destroy\n      redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'wiki'\n    end\n  end\n\n  private\n\n  def find_project\n    @project = Project.find(params[:id])\n    render_message l(:text_project_locked) if @project.locked?\n  rescue ActiveRecord::RecordNotFound\n    render_404\n  end\n\nend\n"
  },
  {
    "path": "app/controllers/workflows_controller.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nclass WorkflowsController < ApplicationController\n  layout 'admin'\n\n  before_filter :require_admin\n  ssl_required :all\n\n  def index\n    @workflow_counts = Workflow.count_by_tracker_and_role\n  end\n\n  def edit\n    @role = Role.find_by_id(params[:role_id])\n    @tracker = Tracker.find_by_id(params[:tracker_id])\n\n    if request.post?\n      Workflow.destroy_all( [\"role_id=? and tracker_id=?\", @role.id, @tracker.id])\n      (params[:issue_status] || []).each { |old, news|\n        news.each { |new|\n          @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new)\n        }\n      }\n      if @role.save\n        flash.now[:success] = l(:notice_successful_update)\n        redirect_to :action => 'edit', :role_id => @role, :tracker_id => @tracker\n      end\n    end\n    @roles = Role.find(:all, :order => 'builtin, position')\n    @trackers = Tracker.find(:all, :order => 'position')\n\n    @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true)\n    if @tracker && @used_statuses_only && @tracker.issue_statuses.any?\n      @statuses = @tracker.issue_statuses\n    end\n    @statuses ||= IssueStatus.find(:all, :order => 'position')\n  end\n\n  def copy\n    @trackers = Tracker.find(:all, :order => 'position')\n    @roles = Role.find(:all, :order => 'builtin, position')\n\n    if params[:source_tracker_id].blank? || params[:source_tracker_id] == 'any'\n      @source_tracker = nil\n    else\n      @source_tracker = Tracker.find_by_id(params[:source_tracker_id].to_i)\n    end\n    if params[:source_role_id].blank? || params[:source_role_id] == 'any'\n      @source_role = nil\n    else\n      @source_role = Role.find_by_id(params[:source_role_id].to_i)\n    end\n\n    @target_trackers = params[:target_tracker_ids].blank? ? nil : Tracker.find_all_by_id(params[:target_tracker_ids])\n    @target_roles = params[:target_role_ids].blank? ? nil : Role.find_all_by_id(params[:target_role_ids])\n\n    if request.post?\n      if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?)\n        flash.now[:error] = l(:error_workflow_copy_source)\n      elsif @target_trackers.nil? || @target_roles.nil?\n        flash.now[:error] = l(:error_workflow_copy_target)\n      else\n        Workflow.copy(@source_tracker, @source_role, @target_trackers, @target_roles)\n        flash.now[:success] = l(:notice_successful_update)\n        redirect_to :action => 'copy', :source_tracker_id => @source_tracker, :source_role_id => @source_role\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/admin_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule AdminHelper\n  def project_status_options_for_select(selected)\n    options_for_select([[l(:label_all), ''],\n                        [l(:status_active), 1]], selected)\n  end\n\n  def css_project_classes(project)\n    s = 'project'\n    s << ' root' if project.root?\n    s << ' child' if project.child?\n    s << (project.leaf? ? ' leaf' : ' parent')\n    s\n  end\nend\n"
  },
  {
    "path": "app/helpers/application_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nrequire 'coderay'\nrequire 'coderay/helpers/file_type'\nrequire 'forwardable'\nrequire 'cgi'\n\nmodule ApplicationHelper\n  include Redmine::WikiFormatting::Macros::Definitions\n  include Redmine::I18n\n  include GravatarHelper::PublicMethods\n\n  extend Forwardable\n  def_delegators :wiki_helper\n\n  def help_section(name, popup=false)\n    if popup\n      return if User.current.anonymous?\n\n      help_section = HelpSection.first(:conditions => {:user_id => User.current.id, :name => name})\n\n      if help_section.nil?\n        help_section = HelpSection.create(\n        :user_id => User.current.id,\n        :name => name,\n        :show => true\n        )\n      end\n      render :partial => 'help_sections/show_popup', :locals => {:help_section => help_section} if help_section.show\n    else\n      render :partial => 'help_sections/show', :locals => {:name => name}\n    end\n  end\n\n  # Return true if user is authorized for controller/action, otherwise false\n  def authorize_for(controller, action)\n    logger.info { \"authorize for #{controller} #{action} #{@project.name}\" }\n    User.current.allowed_to?({:controller => controller, :action => action}, @project)\n  end\n\n  # Display a link if user is authorized\n  def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)\n    link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])\n  end\n\n  # Display a link if user is not logged in\n  def link_to_if_anon(name, options = {}, html_options = nil, *parameters_for_method_reference)\n    link_to(name, options, html_options, *parameters_for_method_reference) if User.current == User.anonymous\n  end\n\n  # Display a link to remote if user is authorized\n  def link_to_remote_if_authorized(name, options = {}, html_options = nil)\n    url = options[:url] || {}\n    link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action])\n  end\n\n  # Displays a link to user's account page if active\n  def link_to_user(user, options={})\n    if user.is_a?(User)\n      name = h(user.name(options[:format]))\n      if user.active?\n        link_to name, :controller => 'users', :action => 'show', :id => user\n      else\n        name\n      end\n    else\n      h(user.to_s)\n    end\n  end\n\n  def link_to_user_or_you(user, options={})\n    if user == User.current\n      \"You\"\n    else\n      link_to_user(user,options)\n    end\n  end\n\n  # Displays a link to project\n  def link_to_project(project, options={})\n    if project.is_a?(Project)\n      name = h(project.name)\n      link_to name, :controller => 'projects', :action => 'show', :id => project\n    else\n      h(project.to_s)\n    end\n  end\n\n\n  def link_to_user_from_id(user_id, options={})\n    link_to_user(User.find(user_id))\n  end\n\n  # Displays a link to +issue+ with its subject.\n  # Examples:\n  #\n  #   link_to_issue(issue)                        # => Defect #6: This is the subject\n  #   link_to_issue(issue, :truncate => 6)        # => Defect #6: This i...\n  #   link_to_issue(issue, :subject => false)     # => Defect #6\n  #   link_to_issue(issue, :project => true)      # => Foo - Defect #6\n  #\n  def link_to_issue(issue, options={})\n    title = nil\n    subject = nil\n    css_class = nil\n    if options[:subject] == false\n      title = truncate(issue.subject, :length => 60)\n    else\n      subject = issue.subject\n      if options[:truncate]\n        subject = truncate(subject, :length => options[:truncate])\n      end\n    end\n    if options[:css_class]\n      css_class = options[:css_class]\n    else\n      css_class = issue.css_classes\n    end\n    css_class = css_class + \" fancyframe\" #loads fancybox\n    s = link_to \"#{issue.tracker} ##{issue.id}\", {:controller => \"issues\", :action => \"show\", :id => issue},\n                                                 :class => css_class,\n                                                 :title => title\n    s << \": #{h subject}\" if subject\n    s = \"#{h issue.project} - \" + s if options[:project]\n    s\n  end\n\n  def link_to_issue_from_id(issue_id, options={})\n    link_to_issue(Issue.find(issue_id), options)\n  rescue ActiveRecord::RecordNotFound\n    css_class = \"fancyframe\" #loads fancybox\n    s = link_to \"Issue ##{issue_id}\", {:controller => \"issues\", :action => \"show\", :id => issue_id},\n                                                 :class => css_class\n  end\n\n  # Generates a link to an attachment.\n  # Options:\n  # * :text - Link text (default to attachment filename)\n  # * :download - Force download (default: false)\n  def link_to_attachment(attachment, options={})\n    text = options.delete(:text) || attachment.filename\n    action = options.delete(:download) ? 'download' : 'show'\n\n    link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options)\n  end\n\n  def current_user\n    User.current\n  end\n\n  def logged_in?\n    User.current.logged?\n  end\n\n  def toggle_link(name, id, options={})\n    onclick = \"$('##{id}').toggle(); \"\n    onclick << \"$('##{options[:second_toggle]}').toggle(); \" if options[:second_toggle]\n    onclick << (options[:focus] ? \"$('##{options[:focus]}').focus(); \" : \"this.blur(); \")\n    onclick << \"return false;\"\n    link_to(name, \"#\", options.merge({:onclick => onclick}))\n  end\n\n  def image_to_function(name, function, html_options = {})\n    html_options.symbolize_keys!\n    tag(:input, html_options.merge({\n        :type => \"image\", :src => image_path(name),\n        :onclick => (html_options[:onclick] ? \"#{html_options[:onclick]}; \" : \"\") + \"#{function};\"\n        }))\n  end\n\n  def prompt_to_remote(name, text, param, url, html_options = {})\n    html_options[:onclick] = \"promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;\"\n    link_to name, {}, html_options\n  end\n\n  #id is the id of the element sending the request\n  #name is the text on the link\n  #title of the command prompt\n  #message bellow title in prompt\n  #params to be passed with url\n  #url to submit to after input is collected\n  #required input or just optional\n  #html_options for this link\n  def prompt_input_to_remote(id, name, title, message, param, url, required, html_options = {})\n    html_options[:onclick] = \"comment_prompt_to_remote('#{id}', '#{title}', '#{message}', '#{param}', '#{url_for(url)}', #{required}); return false;\"\n    link_to name, {}, html_options\n  end\n\n  def format_activity_title(text)\n    h(truncate_single_line(text, :length => 100))\n  end\n\n  def format_activity_day(date)\n    date == Date.today ? l(:label_today).titleize : format_date(date)\n  end\n\n  def format_activity_description(text)\n    make_expandable(textilizable(text),300)\n  end\n\n  def make_expandable(newhtml,length=400)\n    return if newhtml.nil?\n    return newhtml if newhtml.gsub(/<\\/?[^>]*>/,  \"\").length < length\n    id = rand(100000)\n    h = \"\"\n    h << \"<div class='hidden' id=#{id.to_s}>\"\n    h << newhtml\n    h << \"</div>\"\n    h << \"<div id=truncated_#{id.to_s}>\"\n    h << newhtml.truncate_html(length)\n    h = h[0..-5]\n    h << \"<a href='' onclick='$(\\\"#truncated_#{id.to_s}\\\").remove();$(\\\"##{id.to_s}\\\").show();return false;'><strong>... see more</strong></a>\"\n    h << \"<p>\"\n    h << \"</div>\"\n  end\n\n\n\n  def due_date_distance_in_words(date)\n    if date\n      l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))\n    end\n  end\n\n  def render_page_hierarchy(pages, node=nil)\n    content = ''\n    if pages[node]\n      content << \"<ul class=\\\"pages-hierarchy\\\">\\n\"\n      pages[node].each do |page|\n        content << \"<li>\"\n        content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'index', :id => page.project, :page => page.title},\n                           :title => (page.respond_to?(:updated_at) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_at)) : nil))\n        content << \"\\n\" + render_page_hierarchy(pages, page.id) if pages[page.id]\n        content << \"</li>\\n\"\n      end\n      content << \"</ul>\\n\"\n    end\n    content\n  end\n\n  # Renders flash messages\n  def render_flash_messages\n    s = ''\n    flash.each do |k,v|\n      s << content_tag('div', v, :class => \"flash #{k}\")\n    end\n    s\n  end\n\n  def render_global_messages\n    s = ''\n    if User.current.logged? && User.current.trial_expired_at && User.current.trial_expired_at < (-1 * Setting::GLOBAL_OVERUSE_THRESHOLD).days.from_now\n      s << content_tag('div', link_to(l(:text_trial_expired), {:controller => 'my', :action => 'upgrade'}), :class => \"flash error\")\n    elsif User.current.logged? && User.current.usage_over_at && User.current.usage_over_at < (-1 * Setting::GLOBAL_OVERUSE_THRESHOLD).days.from_now\n      s << content_tag('div', link_to(l(:text_usage_over), {:controller => 'my', :action => 'upgrade'}), :class => \"flash error\")\n    end\n    s\n  end\n\n  # Renders tabs and their content\n  def render_tabs(tabs)\n    if tabs.any?\n      render :partial => 'common/tabs', :locals => {:tabs => tabs}\n    else\n      content_tag 'p', l(:label_no_data), :class => \"nodata\"\n    end\n  end\n\n  # Renders the project quick-jump box\n  def render_project_jump_box\n    # Retrieve them now to avoid a COUNT query\n    if User.current.pref[:active_only_jumps]\n      projects = User.current.projects.all\n    else\n      project_ids = User.current.projects.collect{|p| p.id}.join(\",\")\n      projects = project_ids.any? ? Project.find(:all, :conditions => \"(parent_id in (#{project_ids}) OR id in (#{project_ids})) AND (status=#{Project::STATUS_ACTIVE})\") : []\n    end\n\n\n      s = '<select id=\"jumpbox\" onchange=\"if (this.value != \\'\\') { window.location = this.value; }\">' +\n            \"<option value='/projects' selected=\\\"yes\\\">#{l(:label_jump_to_a_project)}</option>\" +\n            '<option value=\"\" disabled=\"disabled\">---</option>'\n      if projects.any?\n        s_options = \"\"\n        s_options << project_tree_options_for_select(projects, :selected => @project) do |p|\n          { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }\n        end\n        s << s_options\n        s << '<option value=\"\" disabled=\"disabled\">---</option>'\n      end\n      s << \"<option value='#{url_for({:controller => :projects, :action => :index})}'>#{l(:label_browse_workstreams)}</option>\"\n      s << \"<option value='#{url_for({:controller => :projects, :action => :new})}'>#{l(:label_project_new)}</option>\"\n      s << '</select>'\n      s << '<span id=\"widthcalc\" style=\"display:none;\"></span>'\n  end\n\n  def sub_workstream_project_box(project)\n      return '' if project.nil?\n      @project_descendants = project.descendants.active\n      return '' if @project_descendants.length == 0\n\n\n      s = '<select id=\"project_jumpbox\" onchange=\"if (this.value != \\'\\') { window.location = this.value; }\">' +\n            \"<option value='/projects' selected=\\\"yes\\\">#{pluralize(@project_descendants.length,l(:label_subproject)).downcase}</option>\" +\n            '<option value=\"\" disabled=\"disabled\">---</option>'\n      if @project_descendants.any?\n        s_options = \"\"\n        s_options << project_tree_options_for_select(@project_descendants) do |p|\n          { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }\n        end\n        s << s_options\n      end\n      if User.current.allowed_to?(:add_subprojects, project)\n        s << '<option value=\"\" disabled=\"disabled\">---</option>'\n        s << \"<option value='#{url_for({:controller => :projects, :action => :new, :parent_id => project.id})}'>#{l(:label_subproject_new)}</option>\"\n      end\n\n      s << '</select>'\n  end\n\n\n  def project_tree_options_for_select(projects, options = {})\n    s = ''\n    project_tree_sorted(projects) do |project, level|\n      name_prefix = (level > 0 ? ('&nbsp;' * 2 * level + '&#187; ') : '')\n      tag_options = {:value => project.id, :selected => ((project == options[:selected] && false) ? 'selected' : nil)}\n      tag_options.merge!(yield(project)) if block_given?\n      s << content_tag('option', name_prefix + h(project), tag_options)\n    end\n    s\n  end\n\n  # Yields the given block for each project with its level in the tree\n  def project_tree(projects, &block)\n    ancestors = []\n    projects.sort_by(&:lft).each do |project|\n      while (ancestors.any? && !project.is_descendant_of?(ancestors.last))\n        ancestors.pop\n      end\n      yield project, ancestors.size\n      ancestors << project\n    end\n  end\n\n  def project_tree_sorted(projects, &block)\n    ancestors = []\n    sorted = [] #nested array for alphabetical sorting\n    last_array = sorted\n    projects.sort_by(&:lft).each do |project|\n\n      while (ancestors.any? && !project.is_descendant_of?(ancestors.last))\n        ancestors.pop\n      end\n\n      if ancestors.size == 0\n        sorted << [[project.name, ancestors.size,project]]\n      else\n        sorted_string = \"sorted\" + \".last\" * ancestors.size\n        eval(sorted_string) << [[project.name, ancestors.size,project]]\n      end\n\n      # yield project, ancestors.size\n      ancestors << project\n    end\n\n    sorted = sort2d(sorted)\n    traverse_sorted(sorted, &block)\n    sorted\n  end\n\n  def sort2d(ar)\n    ar.sort! {|a,b| a[0][0][0] <=> b[0][0][0]}\n\n    if ar[0][0].class.to_s != \"String\"\n      ar.each {|sub| sub = sort2d(sub)}\n    end\n  end\n\n  def traverse_sorted(ar, &block)\n    unless ar[0].class.to_s != \"String\"\n      yield ar[2], ar[1]\n    else\n      ar.each {|sub| sub = traverse_sorted(sub, &block)}\n    end\n  end\n\n  def show_detail(detail, no_html=false)\n    case detail.property\n    when 'attr'\n      label = l((\"field_\" + detail.prop_key.to_s.gsub(/\\_id$/, \"\")).to_sym)\n      case detail.prop_key\n      when 'due_date', 'start_date'\n        value = format_date(detail.value.to_date) if detail.value\n        old_value = format_date(detail.old_value.to_date) if detail.old_value\n      when 'project_id'\n        p = Project.find_by_id(detail.value) and value = p.name if detail.value\n        p = Project.find_by_id(detail.old_value) and old_value = p.name if detail.old_value\n      when 'status_id'\n        s = IssueStatus.find_by_id(detail.value) and value = s.name if detail.value\n        s = IssueStatus.find_by_id(detail.old_value) and old_value = s.name if detail.old_value\n      when 'tracker_id'\n        t = Tracker.find_by_id(detail.value) and value = t.name if detail.value\n        t = Tracker.find_by_id(detail.old_value) and old_value = t.name if detail.old_value\n      when 'assigned_to_id'\n        u = User.find_by_id(detail.value) and value = u.name if detail.value\n        u = User.find_by_id(detail.old_value) and old_value = u.name if detail.old_value\n      when 'estimated_hours'\n        value = \"%0.02f\" % detail.value.to_f unless detail.value.blank?\n        old_value = \"%0.02f\" % detail.old_value.to_f unless detail.old_value.blank?\n      end\n    when 'attachment'\n      label = l(:label_attachment)\n    end\n\n    label ||= detail.prop_key\n    value ||= detail.value\n    old_value ||= detail.old_value\n\n    unless no_html\n      label = content_tag('strong', label)\n      old_value = content_tag(\"i\", h(old_value)) if detail.old_value\n      old_value = content_tag(\"strike\", old_value) if detail.old_value and (!detail.value or detail.value.empty?)\n      if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key)\n        # Link to the attachment if it has not been removed\n        value = link_to_attachment(a)\n      else\n        value = content_tag(\"i\", h(value)) if value\n      end\n    end\n\n    if !detail.value.blank?\n      case detail.property\n      when 'attr', 'cf'\n        if !detail.old_value.blank?\n          l(:text_journal_changed, :label => label, :old => old_value, :new => value)\n        else\n          l(:text_journal_set_to, :label => label, :value => value)\n        end\n      when 'attachment'\n        l(:text_journal_added, :label => label, :value => value)\n      end\n    else\n      l(:text_journal_deleted, :label => label, :old => old_value)\n    end\n  end\n\n  def format_time_ago(updated_at)\n    \"#{distance_of_time_in_words(Time.now,local_time(updated_at))} ago\"\n  end\n\n\n  def project_nested_ul(projects, &block)\n    s = ''\n    if projects.any?\n      ancestors = []\n      projects.sort_by(&:lft).each do |project|\n        if (ancestors.empty? || project.is_descendant_of?(ancestors.last))\n          s << \"<ul>\\n\"\n        else\n          ancestors.pop\n          s << \"</li>\"\n          while (ancestors.any? && !project.is_descendant_of?(ancestors.last))\n            ancestors.pop\n            s << \"</ul></li>\\n\"\n          end\n        end\n        s << \"<li>\"\n        s << yield(project).to_s\n        ancestors << project\n      end\n      s << (\"</li></ul>\\n\" * ancestors.size)\n    end\n    s\n  end\n\n  def users_check_box_tags(name, users)\n    s = ''\n    users.sort.each do |user|\n      s << \"<label>#{ check_box_tag name, user.id, false } #{h user}</label>\\n\"\n    end\n    s\n  end\n\n  # Truncates and returns the string as a single line\n  def truncate_single_line(string, *args)\n    truncate(string.to_s, *args).gsub(%r{[\\r\\n]+}m, ' ')\n  end\n\n  def html_hours(text)\n    text.gsub(%r{(\\d+)\\.(\\d+)}, '<span class=\"hours hours-int\">\\1</span><span class=\"hours hours-dec\">.\\2</span>')\n  end\n\n  def authoring(created, author, options={})\n    l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created))\n  end\n\n\n  def time_tag(time)\n    text = distance_of_time_in_words(Time.now, time)\n    if @project\n      link_to(text, {:controller => 'projects', :action => 'activity', :id => @project, :from => time.to_date}, :title => format_time(time))\n    else\n      content_tag('acronym', text, :title => format_time(time))\n    end\n  end\n\n  def since_tag(time)\n    text = distance_of_time_in_words(Time.now, time).gsub(/about/,\"\")\n    content_tag('acronym', text, :title => format_time(time))\n  end\n\n  def syntax_highlight(name, content)\n    type = CodeRay::FileType[name]\n    type ? CodeRay.scan(content, type).html : h(content)\n  end\n\n  def to_path_param(path)\n    path.to_s.split(%r{[/\\\\]}).select {|p| !p.blank?}\n  end\n\n  def pagination_links_full(paginator, count=nil, options={})\n    page_param = options.delete(:page_param) || :page\n    url_param = params.dup\n    # don't reuse query params if filters are present\n    url_param.merge!(:fields => nil, :values => nil, :operators => nil) if url_param.delete(:set_filter)\n\n    html = ''\n    if paginator.current.previous\n      html << link_to_remote_content_update('&#171; ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '\n    end\n\n    html << (pagination_links_each(paginator, options) do |n|\n      link_to_remote_content_update(n.to_s, url_param.merge(page_param => n))\n    end || '')\n\n    if paginator.current.next\n      html << ' ' + link_to_remote_content_update((l(:label_next) + ' &#187;'), url_param.merge(page_param => paginator.current.next))\n    end\n\n    unless count.nil?\n      html << [\n        \" (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})\",\n        per_page_links(paginator.items_per_page)\n      ].compact.join(' | ')\n    end\n\n    html\n  end\n\n  def per_page_links(selected=nil)\n    url_param = params.dup\n    url_param.clear if url_param.has_key?(:set_filter)\n\n    links = Setting.per_page_options_array.collect do |n|\n      n == selected ? n : link_to_remote(n, {:update => \"content\",\n                                             :url => params.dup.merge(:per_page => n),\n                                             :method => :get},\n                                            {:href => url_for(url_param.merge(:per_page => n))})\n    end\n    links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil\n  end\n\n  def reorder_links(name, url)\n    link_to(image_tag('2uparrow.png',   :alt => l(:label_sort_highest)), url.merge({\"#{name}[move_to]\" => 'highest'}), :method => :post, :title => l(:label_sort_highest)) +\n    link_to(image_tag('1uparrow.png',   :alt => l(:label_sort_higher)),  url.merge({\"#{name}[move_to]\" => 'higher'}),  :method => :post, :title => l(:label_sort_higher)) +\n    link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)),   url.merge({\"#{name}[move_to]\" => 'lower'}),   :method => :post, :title => l(:label_sort_lower)) +\n    link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)),  url.merge({\"#{name}[move_to]\" => 'lowest'}),  :method => :post, :title => l(:label_sort_lowest))\n  end\n\n  def breadcrumb(*args)\n    elements = args.flatten\n    elements.any? ? content_tag('p', args.join(' &#187; ') + ' &#187; ', :class => 'breadcrumb') : nil\n  end\n\n  def other_formats_links(&block)\n    concat('<p class=\"other-formats\">' + l(:label_export_to))\n    yield Redmine::Views::OtherFormatsBuilder.new(self)\n    concat('</p>')\n  end\n\n  def page_header_title\n    if @project.nil?\n      link_to(@page_header_name.nil? ? User.current.name : \"Bettermeans\", {:controller => 'welcome', :action => 'index'}) + (@page_header_name.nil? ? '' :  ' &#187; ' + @page_header_name)\n    elsif @project.new_record? #TODO: would be nice to have the project's parent name here if it's a new record\n      b = []\n      b << link_to(l(:label_project_plural), {:controller => 'projects', :action => 'index'}, :class => 'root')\n      unless @parent.nil?\n        ancestors = (@parent.root? ? [] : @parent.ancestors.visible)\n        if ancestors.any?\n          root = ancestors.shift\n          b << link_to(h(root), {:controller => 'projects', :action => 'show', :id => root, :jump => current_menu_item }, :class => 'root')\n          if ancestors.size > 2\n            b << '&#8230;'\n            ancestors = ancestors[-2, 2]\n          end\n          b += ancestors.collect {|p| link_to(h(p), {:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item}, :class => 'ancestor') }\n        end\n        b << link_to(h(@parent), {:controller => 'projects', :action => 'show', :id => @parent, :jump => current_menu_item}, :class => 'ancestor')\n        b << \"New sub workstream\"\n        b = b.join(' &#187; ')\n        b\n      else\n        b << l(:label_project_new)\n        b = b.join(' &#187; ')\n        b\n      end\n    else\n      b = []\n      b << link_to(l(:label_project_plural), {:controller => 'projects', :action => 'index'}, :class => 'root')\n\n      ancestors = (@project.root? ? [] : @project.ancestors.visible)\n      if ancestors.any?\n        root = ancestors.shift\n        b << link_to(h(root), {:controller => 'projects', :action => 'show', :id => root, :jump => current_menu_item}, :class => 'root')\n        if ancestors.size > 2\n          b << '&#8230;'\n          ancestors = ancestors[-2, 2]\n        end\n        b += ancestors.collect {|p| link_to(h(p), {:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item}, :class => 'ancestor') }\n      end\n      b.push link_to(h(@project), {:controller => 'projects', :action => 'show', :id => @project, :jump => current_menu_item}, :class => 'ancestor')\n      b = b.join(' &#187; ')\n\n    end\n  end\n\n  def page_header_name\n    begin\n    if @project.nil? || @project.new_record?\n      @page_header_name.nil? ? l(:label_my_home) : @page_header_name\n    elsif @project.new_record?\n      l(:label_project_new)\n    else\n      html = h(@project.name)\n      html << privacy(@project)\n      html << volunteering(@project)\n      html\n    end\n    rescue\n      \"Home\"\n    end\n  end\n\n  def html_title(*args)\n    if args.empty?\n      title = []\n      title << @project.name if @project\n      title += @html_title if @html_title\n      title << Setting.app_title\n      title.select {|t| !t.blank? }.join(' - ')\n    else\n      @html_title ||= []\n      @html_title += args\n    end\n  end\n\n  def accesskey(s)\n    Redmine::AccessKeys.key_for s\n  end\n\n\n  # Formats text according to system settings.\n  # 2 ways to call this method:\n  # * with a String: textilizable(text, options)\n  # * with an object and one of its attribute: textilizable(issue, :description, options)\n  def textilizable(*args)\n    options = args.last.is_a?(Hash) ? args.pop : {}\n    case args.size\n    when 1\n      obj = options[:object]\n      text = args.shift\n    when 2\n      obj = args.shift\n      text = obj.send(args.shift).to_s\n    else\n      raise ArgumentError, 'invalid arguments to textilizable'\n    end\n    return '' if text.blank?\n\n    only_path = options.delete(:only_path) == false ? false : true\n\n    # when using an image link, try to use an attachment, if possible\n    attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)\n\n    if attachments\n      attachments = attachments.sort_by(&:created_at).reverse\n      text = text.gsub(/!((\\<|\\=|\\>)?(\\([^\\)]+\\))?(\\[[^\\]]+\\])?(\\{[^\\}]+\\})?)(\\S+\\.(bmp|gif|jpg|jpeg|png))!/i) do |m|\n        style = $1\n        filename = $6.downcase\n        # search for the picture in attachments\n        if found = attachments.detect { |att| att.filename.downcase == filename }\n          image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found\n          desc = found.description.to_s.gsub(/^([^\\(\\)]*).*$/, \"\\\\1\")\n          alt = desc.blank? ? nil : \"(#{desc})\"\n          \"!#{style}#{image_url}#{alt}!\"\n        else\n          m\n        end\n      end\n    end\n\n    text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text) { |macro, args| exec_macro(macro, obj, args) }\n\n    # different methods for formatting wiki links\n    case options[:wiki_links]\n    when :local\n      # used for local links to html files\n      format_wiki_link = Proc.new {|project, title, anchor| \"#{title}.html\" }\n    when :anchor\n      # used for single-file wiki export\n      format_wiki_link = Proc.new {|project, title, anchor| \"##{title}\" }\n    else\n      format_wiki_link = Proc.new {|project, title, anchor| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title, :anchor => anchor) }\n    end\n\n    project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)\n\n    # Wiki links\n    #\n    # Examples:\n    #   [[mypage]]\n    #   [[mypage|mytext]]\n    # wiki links can refer other project wikis, using project name or identifier:\n    #   [[project:]] -> wiki starting page\n    #   [[project:|mytext]]\n    #   [[project:mypage]]\n    #   [[project:mypage|mytext]]\n    text = text.gsub(/(!)?(\\[\\[([^\\]\\n\\|]+)(\\|([^\\]\\n\\|]+))?\\]\\])/) do |m|\n      link_project = project\n      esc, all, page, title = $1, $2, $3, $5\n      if esc.nil?\n        if page =~ /^([^\\:]+)\\:(.*)$/\n          link_project = Project.find_by_name($1) || Project.find_by_identifier($1)\n          page = $2\n          title ||= $1 if page.blank?\n        end\n\n        if link_project && link_project.wiki\n          # extract anchor\n          anchor = nil\n          if page =~ /^(.+?)\\#(.+)$/\n            page, anchor = $1, $2\n          end\n          # check if page exists\n          wiki_page = link_project.wiki.find_page(page)\n          link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page), anchor),\n                                   :class => ('wiki-page' + (wiki_page ? '' : ' new')))\n        else\n          # project or wiki doesn't exist\n          all\n        end\n      else\n        all\n      end\n    end\n\n    # Redmine links\n    #\n    # Examples:\n    #   Issues:\n    #     #52 -> Link to issue #52\n    #   Documents:\n    #     document#17 -> Link to document with id 17\n    #     document:Greetings -> Link to the document with title \"Greetings\"\n    #     document:\"Some document\" -> Link to the document with title \"Some document\"\n    #   Versions:\n    #     version#3 -> Link to version with id 3\n    #     version:1.0.0 -> Link to version named \"1.0.0\"\n    #     version:\"1.0 beta 2\" -> Link to version named \"1.0 beta 2\"\n    #   Attachments:\n    #     attachment:file.zip -> Link to the attachment of the current object named file.zip\n    #   Source files:\n    #     source:some/file -> Link to the file located at /some/file in the project's repository\n    #     source:some/file@52 -> Link to the file's revision 52\n    #     source:some/file#L120 -> Link to line 120 of the file\n    #     source:some/file@52#L120 -> Link to line 120 of the file's revision 52\n    #     export:some/file -> Force the download of the file\n    #  Forum messages:\n    #     message#1218 -> Link to message with id 1218\n    #  User mentions:\n    #    @userlogin -> Link to user with login:userlogin\n    # text = text.gsub(%r{([\\s\\(,\\-\\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\\d+)|(:)([^\"\\s<>][^\\s<>]*?|\"[^\"]+?\"))(?=(?=[[:punct:]]\\W)|,|\\s|<|$)}) do |m|\n    text = text.gsub(%r{([\\s\\(,\\-\\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\\d+)|(@)([a-zA-Z0-9._@]+)|(:)([^\"\\s<>][^\\s<>]*?|\"[^\"]+?\"))(?=(?=[[:punct:]]\\W)|,|\\s|<|$)}) do |m|\n      leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8\n\n      link = nil\n      if esc.nil?\n        if sep == '#'\n          oid = oid.to_i\n          case prefix\n          when nil\n            if issue = Issue.visible.find_by_id(oid, :include => :status)\n              link = link_to(\"##{oid}\", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid},\n                                        :class => issue.css_classes,\n                                        :title => \"#{truncate(issue.subject, :length => 100)} (#{issue.status.name})\")\n            end\n          when 'document'\n            if document = Document.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))\n              link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},\n                                                :class => 'document'\n            end\n          when 'message'\n            if message = Message.find_by_id(oid, :include => [:parent, {:board => :project}], :conditions => Project.visible_by(User.current))\n              link = link_to h(truncate(message.subject, :length => 60)), {:only_path => only_path,\n                                                                :controller => 'messages',\n                                                                :action => 'show',\n                                                                :board_id => message.board,\n                                                                :id => message.root,\n                                                                :anchor => (message.parent ? \"message-#{message.id}\" : nil)},\n                                                 :class => 'message'\n            end\n          end\n        elsif sep == '@'\n          link = link_to(\"@#{oid}\", {:only_path => only_path, :controller => 'users', :action => 'show', :id => 0, :login => oid})\n        elsif sep == ':'\n          # removes the double quotes if any\n          name = oid.gsub(%r{^\"(.*)\"$}, \"\\\\1\")\n          case prefix\n          when 'document'\n            if project && document = project.documents.find_by_title(name)\n              link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},\n                                                :class => 'document'\n            end\n          when 'attachment'\n            if attachments && attachment = attachments.detect {|a| a.filename == name }\n              link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},\n                                                     :class => 'attachment'\n            end\n          end\n        end\n      end\n      leading + (link || \"#{prefix}#{sep}#{oid}\")\n    end\n\n    text\n  end\n\n  # Same as Rails' simple_format helper without using paragraphs\n  def simple_format_without_paragraph(text)\n    text.to_s.\n      gsub(/\\r\\n?/, \"\\n\").                    # \\r\\n and \\r -> \\n\n      gsub(/\\n\\n+/, \"<br /><br />\").          # 2+ newline  -> 2 br\n      gsub(/([^\\n]\\n)(?=[^\\n])/, '\\1<br />')  # 1 newline   -> br\n  end\n\n  def lang_options_for_select(blank=true)\n    (blank ? [[\"(auto)\", \"\"]] : []) +\n      valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }\n  end\n\n  def month_hash\n    [\n      [\"01 - January\",1],\n      [\"02 - February\",2],\n      [\"03 - March\",3],\n      [\"04 - April\",4],\n      [\"05 - May\",5],\n      [\"06 - June\",6],\n      [\"07 - July\",7],\n      [\"08 - August\",8],\n      [\"09 - September\",9],\n      [\"10 - October\",10],\n      [\"11 - November\",11],\n      [\"12 - December\",12]\n    ]\n  end\n\n  def privacy(project)\n    project.is_public ? \"\" : help_bubble(:help_this_workstream_is_private, {:image =>\"icon_privacy.png\"})\n  end\n\n  def volunteering(project)\n    project.volunteer ? help_bubble(:help_volunteer, {:image => \"icon_volunteer.png\"}) : \"\"\n  end\n\n  def year_hash\n    [0,1,2,3,4,5,6,7,8,9,10].collect{|n| [(Date.today.year + n).to_s, Date.today.year + n]}\n  end\n\n  def unit_for(project)\n    if project.volunteer?\n      return '♥'\n    else\n      return '●'\n    end\n  end\n\n\n\n  def country_hash\n    {\n      \"Afghanistan\" => \"AF\",\n      \"Albania\" => \"AL\",\n      \"Algeria\" => \"DZ\",\n      \"American Samoa\" => \"AS\",\n      \"Andorra\" => \"AD\",\n      \"Angola\" => \"AO\",\n      \"Anguilla\" => \"AI\",\n      \"Antigua and Barbuda\" => \"AG\",\n      \"Argentina\" => \"AR\",\n      \"Armenia\" => \"AM\",\n      \"Aruba\" => \"AW\",\n      \"Australia\" => \"AU\",\n      \"Austria\" => \"AT\",\n      \"Aland Islands\" => \"AX\",\n      \"Azerbaijan\" => \"AZ\",\n      \"Bahamas\" => \"BS\",\n      \"Bahrain\" => \"BH\",\n      \"Bangladesh\" => \"BD\",\n      \"Barbados\" => \"BB\",\n      \"Belarus\" => \"BY\",\n      \"Belgium\" => \"BE\",\n      \"Belize\" => \"BZ\",\n      \"Benin\" => \"BJ\",\n      \"Bermuda\" => \"BM\",\n      \"Bhutan\" => \"BT\",\n      \"Bolivia\" => \"BO\",\n      \"Bosnia and Herzegovina\" => \"BA\",\n      \"Botswana\" => \"BW\",\n      \"Bouvet Island\" => \"BV\",\n      \"Brazil\" => \"BR\",\n      \"Brunei Darussalam\" => \"BN\",\n      \"British Indian Ocean Territory\" => \"IO\",\n      \"Bulgaria\" => \"BG\",\n      \"Burkina Faso\" => \"BF\",\n      \"Burundi\" => \"BI\",\n      \"Cambodia\" => \"KH\",\n      \"Cameroon\" => \"CM\",\n      \"Canada\" => \"CA\",\n      \"Cape Verde\" => \"CV\",\n      \"Cayman Islands\" => \"KY\",\n      \"Central African Republic\" => \"CF\",\n      \"Chad\" => \"TD\",\n      \"Chile\" => \"CL\",\n      \"China\" => \"CN\",\n      \"Christmas Island\" => \"CX\",\n      \"Cocos (Keeling) Islands\" => \"CC\",\n      \"Colombia\" => \"CO\",\n      \"Comoros\" => \"KM\",\n      \"Congo\" => \"CG\",\n      \"Congo, the Democratic Republic of the\" => \"CD\",\n      \"Cook Islands\" => \"CK\",\n      \"Costa Rica\" => \"CR\",\n      \"Cote D'Ivoire\" => \"CI\",\n      \"Croatia\" => \"HR\",\n      \"Cuba\" => \"CU\",\n      \"Cyprus\" => \"CY\",\n      \"Czech Republic\" => \"CZ\",\n      \"Denmark\" => \"DK\",\n      \"Djibouti\" => \"DJ\",\n      \"Dominica\" => \"DM\",\n      \"Dominican Republic\" => \"DO\",\n      \"Ecuador\" => \"EC\",\n      \"Egypt\" => \"EG\",\n      \"El Salvador\" => \"SV\",\n      \"Equatorial Guinea\" => \"GQ\",\n      \"Eritrea\" => \"ER\",\n      \"Estonia\" => \"EE\",\n      \"Ethiopia\" => \"ET\",\n      \"Falkland Islands (Malvinas)\" => \"FK\",\n      \"Faroe Islands\" => \"FO\",\n      \"Fiji\" => \"FJ\",\n      \"Finland\" => \"FI\",\n      \"France\" => \"FR\",\n      \"French Guiana\" => \"GF\",\n      \"French Polynesia\" => \"PF\",\n      \"French Southern Territories\" => \"TF\",\n      \"Gabon\" => \"GA\",\n      \"Gambia\" => \"GM\",\n      \"Georgia\" => \"GE\",\n      \"Germany\" => \"DE\",\n      \"Ghana\" => \"GH\",\n      \"Gibraltar\" => \"GI\",\n      \"Greece\" => \"GR\",\n      \"Greenland\" => \"GL\",\n      \"Grenada\" => \"GD\",\n      \"Guadeloupe\" => \"GP\",\n      \"Guam\" => \"GU\",\n      \"Guatemala\" => \"GT\",\n      \"Guinea\" => \"GN\",\n      \"Guinea-Bissau\" => \"GW\",\n      \"Guyana\" => \"GY\",\n      \"Guernsey\" => \"GG\",\n      \"Haiti\" => \"HT\",\n      \"Holy See (Vatican City State)\" => \"VA\",\n      \"Honduras\" => \"HN\",\n      \"Hong Kong\" => \"HK\",\n      \"Heard Island And Mcdonald Islands\" => \"HM\",\n      \"Hungary\" => \"HU\",\n      \"Iceland\" => \"IS\",\n      \"India\" => \"IN\",\n      \"Indonesia\" => \"ID\",\n      \"Iran, Islamic Republic of\" => \"IR\",\n      \"Iraq\" => \"IQ\",\n      \"Ireland\" => \"IE\",\n      \"Isle Of Man\" => \"IM\",\n      \"Israel\" => \"IL\",\n      \"Italy\" => \"IT\",\n      \"Jamaica\" => \"JM\",\n      \"Japan\" => \"JP\",\n      \"Jersey\" => \"JE\",\n      \"Jordan\" => \"JO\",\n      \"Kazakhstan\" => \"KZ\",\n      \"Kenya\" => \"KE\",\n      \"Kiribati\" => \"KI\",\n      \"Korea, Democratic People's Republic of\" => \"KP\",\n      \"Korea, Republic of\" => \"KR\",\n      \"Kuwait\" => \"KW\",\n      \"Kyrgyzstan\" => \"KG\",\n      \"Lao People's Democratic Republic\" => \"LA\",\n      \"Latvia\" => \"LV\",\n      \"Lebanon\" => \"LB\",\n      \"Lesotho\" => \"LS\",\n      \"Liberia\" => \"LR\",\n      \"Libyan Arab Jamahiriya\" => \"LY\",\n      \"Liechtenstein\" => \"LI\",\n      \"Lithuania\" => \"LT\",\n      \"Luxembourg\" => \"LU\",\n      \"Macao\" => \"MO\",\n      \"Macedonia, the Former Yugoslav Republic of\" => \"MK\",\n      \"Madagascar\" => \"MG\",\n      \"Malawi\" => \"MW\",\n      \"Malaysia\" => \"MY\",\n      \"Maldives\" => \"MV\",\n      \"Mali\" => \"ML\",\n      \"Malta\" => \"MT\",\n      \"Marshall Islands\" => \"MH\",\n      \"Martinique\" => \"MQ\",\n      \"Mauritania\" => \"MR\",\n      \"Mauritius\" => \"MU\",\n      \"Mayotte\" => \"YT\",\n      \"Mexico\" => \"MX\",\n      \"Micronesia, Federated States of\" => \"FM\",\n      \"Moldova, Republic of\" => \"MD\",\n      \"Monaco\" => \"MC\",\n      \"Mongolia\" => \"MN\",\n      \"Montenegro\" => \"ME\",\n      \"Montserrat\" => \"MS\",\n      \"Morocco\" => \"MA\",\n      \"Mozambique\" => \"MZ\",\n      \"Myanmar\" => \"MM\",\n      \"Namibia\" => \"NA\",\n      \"Nauru\" => \"NR\",\n      \"Nepal\" => \"NP\",\n      \"Netherlands\" => \"NL\",\n      \"Netherlands Antilles\" => \"AN\",\n      \"New Caledonia\" => \"NC\",\n      \"New Zealand\" => \"NZ\",\n      \"Nicaragua\" => \"NI\",\n      \"Niger\" => \"NE\",\n      \"Nigeria\" => \"NG\",\n      \"Niue\" => \"NU\",\n      \"Norfolk Island\" => \"NF\",\n      \"Northern Mariana Islands\" => \"MP\",\n      \"Norway\" => \"NO\",\n      \"Oman\" => \"OM\",\n      \"Pakistan\" => \"PK\",\n      \"Palau\" => \"PW\",\n      \"Palestinian Territory, Occupied\" => \"PS\",\n      \"Panama\" => \"PA\",\n      \"Papua New Guinea\" => \"PG\",\n      \"Paraguay\" => \"PY\",\n      \"Peru\" => \"PE\",\n      \"Philippines\" => \"PH\",\n      \"Pitcairn\" => \"PN\",\n      \"Poland\" => \"PL\",\n      \"Portugal\" => \"PT\",\n      \"Puerto Rico\" => \"PR\",\n      \"Qatar\" => \"QA\",\n      \"Reunion\" => \"RE\",\n      \"Romania\" => \"RO\",\n      \"Russian Federation\" => \"RU\",\n      \"Rwanda\" => \"RW\",\n      \"Saint Barthélemy\" => \"BL\",\n      \"Saint Helena\" => \"SH\",\n      \"Saint Kitts and Nevis\" => \"KN\",\n      \"Saint Lucia\" => \"LC\",\n      \"Saint Martin (French part)\" => \"MF\",\n      \"Saint Pierre and Miquelon\" => \"PM\",\n      \"Saint Vincent and the Grenadines\" => \"VC\",\n      \"Samoa\" => \"WS\",\n      \"San Marino\" => \"SM\",\n      \"Sao Tome and Principe\" => \"ST\",\n      \"Saudi Arabia\" => \"SA\",\n      \"Senegal\" => \"SN\",\n      \"Serbia\" => \"RS\",\n      \"Seychelles\" => \"SC\",\n      \"Sierra Leone\" => \"SL\",\n      \"Singapore\" => \"SG\",\n      \"Slovakia\" => \"SK\",\n      \"Slovenia\" => \"SI\",\n      \"Solomon Islands\" => \"SB\",\n      \"Somalia\" => \"SO\",\n      \"South Africa\" => \"ZA\",\n      \"South Georgia and the South Sandwich Islands\" => \"GS\",\n      \"Spain\" => \"ES\",\n      \"Sri Lanka\" => \"LK\",\n      \"Sudan\" => \"SD\",\n      \"Suriname\" => \"SR\",\n      \"Svalbard and Jan Mayen\" => \"SJ\",\n      \"Swaziland\" => \"SZ\",\n      \"Sweden\" => \"SE\",\n      \"Switzerland\" => \"CH\",\n      \"Syrian Arab Republic\" => \"SY\",\n      \"Taiwan, Province of China\" => \"TW\",\n      \"Tajikistan\" => \"TJ\",\n      \"Tanzania, United Republic of\" => \"TZ\",\n      \"Thailand\" => \"TH\",\n      \"Timor Leste\" => \"TL\",\n      \"Togo\" => \"TG\",\n      \"Tokelau\" => \"TK\",\n      \"Tonga\" => \"TO\",\n      \"Trinidad and Tobago\" => \"TT\",\n      \"Tunisia\" => \"TN\",\n      \"Turkey\" => \"TR\",\n      \"Turkmenistan\" => \"TM\",\n      \"Turks and Caicos Islands\" => \"TC\",\n      \"Tuvalu\" => \"TV\",\n      \"Uganda\" => \"UG\",\n      \"Ukraine\" => \"UA\",\n      \"United Arab Emirates\" => \"AE\",\n      \"United Kingdom\" => \"GB\",\n      \"United States\" => \"US\",\n      \"United States Minor Outlying Islands\" => \"UM\",\n      \"Uruguay\" => \"UY\",\n      \"Uzbekistan\" => \"UZ\",\n      \"Vanuatu\" => \"VU\",\n      \"Venezuela\" => \"VE\",\n      \"Viet Nam\" => \"VN\",\n      \"Virgin Islands, British\" => \"VG\",\n      \"Virgin Islands, U.S.\" => \"VI\",\n      \"Wallis and Futuna\" => \"WF\",\n      \"Western Sahara\" => \"EH\",\n      \"Yemen\" => \"YE\",\n      \"Zambia\" => \"ZM\",\n      \"Zimbabwe\" => \"ZW\"\n    }\n  end\n\n  def label_tag_for(name, option_tags = nil, options = {})\n    label_text = l((\"field_\"+field.to_s.gsub(/\\_id$/, \"\")).to_sym) + (options.delete(:required) ? @template.content_tag(\"span\", \" *\", :class => \"required\"): \"\")\n    content_tag(\"label\", label_text)\n  end\n\n  def labelled_tabular_form_for(name, object, options, &proc)\n    options[:html] ||= {}\n    options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)\n    form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)\n  end\n\n  def back_url_hidden_field_tag\n    back_url = params[:back_url] || request.env['HTTP_REFERER']\n    back_url = CGI.unescape(back_url.to_s)\n    hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank?\n  end\n\n  def check_all_links(form_name)\n    link_to_function(l(:button_check_all), \"checkAll('#{form_name}', true)\") +\n    \" | \" +\n    link_to_function(l(:button_uncheck_all), \"checkAll('#{form_name}', false)\")\n  end\n\n  def progress_bar(pcts, options={})\n    pcts = [pcts, pcts] unless pcts.is_a?(Array)\n    pcts = pcts.collect(&:round)\n    pcts[1] = pcts[1] - pcts[0]\n    pcts << (100 - pcts[1] - pcts[0])\n    width = options[:width] || '100px;'\n    legend = options[:legend] || ''\n    content_tag('table',\n      content_tag('tr',\n        (pcts[0] > 0 ? content_tag('td', '', :style => \"width: #{pcts[0]}%;\", :class => 'closed') : '') +\n        (pcts[1] > 0 ? content_tag('td', '', :style => \"width: #{pcts[1]}%;\", :class => 'done') : '') +\n        (pcts[2] > 0 ? content_tag('td', '', :style => \"width: #{pcts[2]}%;\", :class => 'todo') : '')\n      ), :class => 'progress', :style => \"width: #{width};\") +\n      content_tag('p', legend, :class => 'pourcent')\n  end\n\n  def context_menu_link(name, url, options={})\n    options[:class] ||= ''\n    if options.delete(:selected)\n      options[:class] << ' icon-checked disabled'\n      options[:disabled] = true\n    end\n    if options.delete(:disabled)\n      options.delete(:method)\n      options.delete(:confirm)\n      options.delete(:onclick)\n      options[:class] << ' disabled'\n      url = '#'\n    end\n    link_to name, url, options\n  end\n\n  def help_link(name, options={})\n    options[:show_name] ||= false #When true, we show the text of the help key next to the link\n    link_to(options[:show_name] ? l('help_' + name.to_s) : '', {:controller => 'help', :action => 'show', :key => name}, {:id =>'help_button_' + name.to_s, :class => 'lbOn icon icon-help'})\n  end\n\n  def help_bubble(name, options={})\n\n    imagename = options[:image] || \"question_mark.gif\"\n    image = image_tag(imagename, :class=> \"help_question_mark\", :id=>\"help_image_#{name}\")\n    html = link_to(image, {:href => '#'}, {:onclick => \"$('#help_image_#{name}').bubbletip('#tip_#{name}', {deltaDirection: 'right', bindShow: 'click'}); return false;\"})\n    html << content_tag(:span, l(name, options), :class => 'tip hidden', :id=>\"tip_#{name}\")\n\n    # <img id=\"help_image_panel_' + name + '\" src=\"/images/question_mark.gif\" class=\"help_question_mark\">\n    # <div id=\"help_panel_canceled\" style=\"display:none;\">\n    #   <div class=\"tip\" style=\"width:300px\">\n    #     <strong>Canceled Ideas</strong><br>\n    #       If a request hasn't been prioritized by anyone and has been sitting in the queue for more than a month, anyone team member can cancel it.<br><br>\n    #       Once a request has been canceled, anyone can re-open it, effectively pushing it back as a new item for reconsideration.\n    #   </div>\n    # </div>\n  end\n\n  def calendar_for(field_id)\n    include_calendar_headers_tags\n    image_tag(\"calendar.png\", {:id => \"#{field_id}_trigger\",:class => \"calendar-trigger\"}) +\n    javascript_tag(\"Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });\")\n  end\n\n  def include_calendar_headers_tags\n    unless @calendar_headers_tags_included\n      @calendar_headers_tags_included = true\n      content_for :header_tags do\n        start_of_week = case Setting.start_of_week.to_i\n        when 1\n          'Calendar._FD = 1;' # Monday\n        when 7\n          'Calendar._FD = 0;' # Sunday\n        else\n          '' # use language\n        end\n\n        javascript_include_tag('calendar/calendar') +\n        javascript_include_tag(\"calendar/lang/calendar-#{current_language.to_s.downcase}.js\") +\n        javascript_tag(start_of_week) +\n        javascript_include_tag('calendar/calendar-setup') +\n        stylesheet_link_tag('calendar')\n      end\n    end\n  end\n\n  def content_for(name, content = nil, &block)\n    @has_content ||= {}\n    @has_content[name] = true\n    super(name, content, &block)\n  end\n\n  def has_content?(name)\n    (@has_content && @has_content[name]) || false\n  end\n\n  # Returns the avatar image tag for the given +user+ if avatars are enabled\n  # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')\n  def avatar(user, options = { })\n    options.merge!({:ssl => Setting.protocol == 'https', :default => Setting.gravatar_default})\n    email = nil\n    if user.respond_to?(:mail)\n      email = user.mail\n    elsif user.to_s =~ %r{<(.+?)>}\n      email = $1\n    end\n    return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil\n  end\n\n  def render_journal_details(journal)\n    return unless journal\n    html = \"\"\n    if journal && journal.details && journal.details.count > 0\n      html = \"<ul>\"\n      for detail in journal.details\n        html << \"<li>#{show_detail(detail)}</li>\"\n      end\n      html << \"</ul>\"\n    end\n\n    content = \"\"\n    content << textilizable(journal, :notes)\n    content = make_expandable content, 250\n    css_classes = \"wiki\"\n    css_classes << \" gravatar-margin\" if Setting.gravatar_enabled?\n\n    html << content\n\n  end\n\n  def link_to_activity(as)\n    link_to name_for_activity_stream(as), url_for_activity_stream(as), {:class => class_for_activity_stream(as)}\n  end\n\n  def name_for_activity_stream(as)\n    (as.tracker_name) ? \"a #{as.tracker_name.downcase}\" : \"a \" + l(\"label_#{as.object_type.downcase}\")\n  end\n\n  def class_for_activity_stream(as)\n     (as.object_type.match(/^Issue/)) ? \"fancyframe\" : \"noframe\"\n  end\n\n  def url_for_activity_stream(as)\n    case as.object_type.downcase\n    when 'message'\n      return {:controller => 'messages', :action => 'show', :board_id => 'guess', :id => as.object_id}\n    when 'wikipage'\n      return {:controller => 'wiki', :action => 'index', :id => as.project_id, :page => as.object_name}\n    when 'memberrole'\n      return {:controller => 'projects', :action => 'team', :id => as.project_id}\n    when 'motion'\n      return {:controller => 'motions', :action => 'show', :project_id => as.project_id, :id => as.object_id}\n    else\n      return {:controller => as.object_type.downcase.pluralize, :action => 'show', :id => as.object_id}\n    end\n  end\n\n  def title_for_activity_stream(as)\n    case as.object_type.downcase\n    when 'memberrole'\n      begin\n        \"#{as.indirect_object_phrase || as.object.user.name} is now #{as.object_name}\"\n      rescue\n         \"New member role\"\n      end\n    else\n      format_activity_title(as.object_name)\n    end\n  end\n\n  def action_times(count)\n    count = count.to_i\n    return nil if count < 2\n    return \" twice\" if count == 2\n    return \" #{count.to_s} times\" if count > 2\n  end\n\n\n\n  def avatar_from_id(user_id, options = { })\n    avatar(User.find(user_id), options)\n  end\n\n  def button(text, cssclass)\n    return \"<div class='action_button_no_float action_button_#{cssclass}' onclick=\\\"$('.action_button_no_float').hide();\\\" ><span>#{text}</span></div>\"\n  end\n\n  def tally_table(motion)\n    content = \"<table id='motion_votes_totals' class='gt-table'>\"\n    content << \"<thead><tr>\"\n    content << \"<th>&nbsp;</th><th>#{l :label_binding}</th><th>#{l :label_non_binding}</th>\"\n    content << \"</tr></thead>\"\n    content << \"<tr>\"\n    content << \"<th>#{l(:label_agree)}</th><td>#{motion.agree}</td><td>#{motion.agree_nonbind}</td>\"\n    content << \"</tr>\"\n    content << \"<tr>\"\n    content << \"<th>#{l(:label_disagree)}</th><td>#{motion.disagree}</td><td>#{motion.disagree_nonbind}</td>\"\n    content << \"</tr>\"\n    content << \"<tr>\"\n    content << \"<th>#{l(:label_total)}</th><td>#{motion.agree_total}</td><td>#{motion.agree_total_nonbind}</td>\"\n    content << \"</tr>\"\n    content << \"</table>\"\n  end\n\n  def tame_bias(number)\n    if number.nil?\n      return \"\"\n    else\n      number = number.round\n      number > 0 ? \"Self:&nbsp&nbsp; +#{number}\" : number == 0 ? \"Self:&nbsp&nbsp; No Bias\" : \"Self:&nbsp&nbsp; #{number}\"\n    end\n  end\n\n  def tame_scale(number)\n    if number.nil?\n      \"\"\n    else\n      number = number.round\n      number == 0 ? \"Other: No Bias\" : \"Other: &plusmn;#{number}\"\n    end\n  end\n\n  #depending on credit's status, provides link to activate/deactivate a credit. Project id is the current project being viewed\n  def credit_activation_link(credit, project_id, include_sub_workstreams)\n    return '' if !credit.settled_on.nil?\n\n    return link_to_remote(l(:button_deactivate),\n                            { :url => {:controller => 'credits', :action => 'disable', :id => credit.id, :project_id => project_id, :with_subprojects => include_sub_workstreams} },\n                            :class => 'icon icon-deactivate') if credit.enabled\n\n    return link_to_remote(l(:button_activate),\n                            { :url => {:controller => 'credits', :action => 'enable', :id => credit.id, :project_id => project_id, :with_subprojects => include_sub_workstreams} },\n                            :class => 'icon icon-activate') if !credit.enabled\n  end\n\n  def login_protocol\n    if ENV['RAILS_ENV'] == \"development\"\n      'http'\n    else\n      'https'\n    end\n  end\n\n  private\n\n  def wiki_helper\n    helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)\n    extend helper\n    return self\n  end\n\n  def link_to_remote_content_update(text, url_params)\n    link_to_remote(text,\n      {:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'},\n      {:href => url_for(:params => url_params)}\n    )\n  end\n\nend\n"
  },
  {
    "path": "app/helpers/attachments_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule AttachmentsHelper\n  # Displays view/delete links to the attachments of the given object\n  # Options:\n  #   :author -- author names are not displayed if set to false\n  def link_to_attachments(container, options = {})\n    options.assert_valid_keys(:author)\n\n    if container.attachments.any?\n      options = {:deletable => container.attachments_deletable?, :author => true}.merge(options)\n      render :partial => 'attachments/links', :locals => {:attachments => container.attachments, :options => options}\n    end\n  end\n\n  def link_to_attachments_table(container, options = {})\n    options.assert_valid_keys(:author)\n\n    if container.attachments.any?\n      options = {:deletable => container.attachments_deletable?, :author => true}.merge(options)\n      render :partial => 'attachments/table', :locals => {:attachments => container.attachments, :options => options}\n    end\n  end\n\n  def to_utf8(str)\n    str\n  end\nend\n"
  },
  {
    "path": "app/helpers/groups_helper.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule GroupsHelper\n  # Options for the new membership projects combo-box\n  def options_for_membership_project_select(user, projects)\n    options = content_tag('option', \"--- #{l(:actionview_instancetag_blank_option)} ---\")\n    options << project_tree_options_for_select(projects) do |p|\n      {:disabled => (user.projects.include?(p))}\n    end\n    options\n  end\n\n  def group_settings_tabs\n    tabs = [{:name => 'general', :partial => 'groups/general', :label => :label_general},\n            {:name => 'users', :partial => 'groups/users', :label => :label_user_plural},\n            {:name => 'memberships', :partial => 'groups/memberships', :label => :label_project_plural}\n            ]\n  end\nend\n"
  },
  {
    "path": "app/helpers/issue_relations_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule IssueRelationsHelper\n  def collection_for_relation_type_select\n    values = IssueRelation::TYPES\n    values.keys.sort{|x,y| values[x][:order] <=> values[y][:order]}.collect{|k| [l(values[k][:name]), k]}\n  end\nend\n"
  },
  {
    "path": "app/helpers/issues_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule IssuesHelper\n  include ApplicationHelper\n\n  def render_issue_tooltip(issue)\n    @cached_label_start_date ||= l(:field_start_date)\n    @cached_label_due_date ||= l(:field_due_date)\n    @cached_label_assigned_to ||= l(:field_assigned_to)\n\n    link_to_issue(issue) + \"<br /><br />\" +\n      \"<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />\" +\n      \"<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />\" +\n      \"<strong>#{@cached_label_assigned_to}</strong>: #{issue.assigned_to}<br />\"\n  end\n\n  def sidebar_queries\n    unless @sidebar_queries\n      # User can see public queries and his own queries\n      visible = ARCondition.new([\"is_public = ? OR user_id = ?\", true, (User.current.logged? ? User.current.id : 0)])\n      # Project specific queries and global queries\n      visible << (@project.nil? ? [\"project_id IS NULL\"] : [\"project_id IS NULL OR project_id = ?\", @project.id])\n      @sidebar_queries = Query.find(:all,\n                                    :select => 'id, name',\n                                    :order => \"name ASC\",\n                                    :conditions => visible.conditions)\n    end\n    @sidebar_queries\n  end\n\n  def tags(issue, editable)\n    if editable\n      text_field :issue, :tag_list, :class => 'gt-form-text issue-tags', :value => issue.tag_list.join(\",\")\n    else\n      html = ''\n      issue.tag_list.each {|t| html = html + content_tag('span', t, :class => \"tag\")}\n      content_tag('div', html, :class => \"tagsoutput\")\n    end\n  end\n\n\n  def issues_to_csv(issues, project = nil)\n    ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')\n    decimal_separator = l(:general_csv_decimal_separator)\n    export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|\n      # csv header fields\n      headers = [ \"#\",\n                  l(:field_status),\n                  l(:field_project),\n                  l(:field_tracker),\n                  l(:field_subject),\n                  l(:field_assigned_to),\n                  l(:field_author),\n                  l(:field_start_date),\n                  l(:field_due_date),\n                  l(:field_estimated_hours),\n                  l(:field_created_at),\n                  l(:field_updated_at)\n                  ]\n      # Description in the last column\n      headers << l(:field_description)\n      csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }\n      # csv lines\n      issues.each do |issue|\n        fields = [issue.id,\n                  issue.status.name,\n                  issue.project.name,\n                  issue.tracker.name,\n                  issue.subject,\n                  issue.assigned_to,\n                  issue.author.name,\n                  format_date(issue.start_date),\n                  format_date(issue.due_date),\n                  issue.estimated_hours.to_s.gsub('.', decimal_separator),\n                  format_time(issue.created_at),\n                  format_time(issue.updated_at)\n                  ]\n        fields << issue.description\n        csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }\n      end\n    end\n    export\n  end\n\n  def collection_for_project_members_select\n    values = @issue.project.root.all_members.collect {|p| [p.name, p.user.id]}\n    existing_team = @issue.team_votes.collect {|p| [User.find(p.user_id).name, p.user_id]}\n    values - existing_team\n  end\n\nend\n"
  },
  {
    "path": "app/helpers/journals_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nmodule JournalsHelper\n  def render_notes(journal, editable, options={})\n    content = ''\n    editable ||= false;\n    links = []\n    if !journal.notes.blank?\n      links << link_to_in_place_notes_editor(l(:button_edit), \"journal-#{journal.id}-notes\",\n                                                 { :controller => 'journals', :action => 'edit', :id => journal },\n                                                    :title => l(:button_edit),\n                                                    :class => 'icon icon-edit') if editable\n    end\n\n    content << content_tag('div', links.join(' '), :class => 'contextual') unless links.empty?\n    content << textilizable(journal, :notes)\n    css_classes = \"wiki\"\n    css_classes << \" editable\" if editable\n    css_classes << \" gravatar-margin\" if Setting.gravatar_enabled?\n    content_tag('div', content, :id => \"journal-#{journal.id}-notes\", :class => css_classes)\n  end\n\n  def render_votes(journal, options={})\n    votingcontent = ''\n    #We show total votes regardless\n    votingcontent << \" \" + String(journal.votes_for - journal.votes_against) + \" points\"\n\n    # Voting on journal items\n    unless journal.user_id == User.current.id ||\n      !User.current.logged? ||\n      User.current.voted_on?(journal)\n      votingcontent << link_to_remote(image_tag('/images/aupgray.gif', :size => \"15x14\", :border => 0),\n        {\n        :url => user_journal_votes_path(User.current, journal, :vote => :true, :format => :js, :voteable_type => \"journal\"),\n        :method => :post\n        })\n      votingcontent << link_to_remote(image_tag('/images/adowngray.gif', :size => \"15x14\", :border => 0),\n        {\n        :url => user_journal_votes_path(User.current, journal, :vote => :false, :format => :js, :voteable_type => \"journal\"),\n        :method => :post\n        })\n    end\n\n    content_tag('span', votingcontent, :id => \"votes_\" + String(journal.id), :class => 'journalvote')\n\n  end\n\n\n  def link_to_in_place_notes_editor(text, field_id, url, options={})\n    onclick = \"$.ajax({type: 'GET', url: '#{url_for(url)}'});return false;\"\n    link_to text, '#', options.merge(:onclick => onclick)\n  end\nend\n"
  },
  {
    "path": "app/helpers/messages_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule MessagesHelper\n\n  def link_to_message(message)\n    return '' unless message\n    link_to h(truncate(message.subject, :length => 60)), :controller => 'messages',\n                                           :action => 'show',\n                                           :board_id => message.board_id,\n                                           :id => message.root,\n                                           :anchor => (message.parent_id ? \"message-#{message.id}\" : nil)\n  end\nend\n"
  },
  {
    "path": "app/helpers/motions_helper.rb",
    "content": "module MotionsHelper\n  def render_title_date\n    end_date = @motion.ends_on\n    if (!@motion.active?)\n      logger.info { DateTime.now }\n      logger.info { \"message\" }\n      return \"Voting ended #{distance_of_time_in_words(Time.now,end_date)} ago\"\n    else\n      return \"Voting ends in #{distance_of_time_in_words(Time.now,end_date)}\"\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/my_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule MyHelper\n  def describe(amount)\n    amount == -1 ? 'unlimited' : amount\n  end\n\n  def my_issues_tabs\n    tabs = [\n            {:name => 'recent',\n             :partial => 'issues/list_very_simple',\n             :label => :label_recent_issues,\n             :label_ending => \" (#{@recent_issues.length})\",\n             :locals => {:issues => @recent_issues}\n            },\n            {:name => 'assigned',\n             :partial => 'issues/list_very_simple',\n             :label => :label_assigned_to_me_issues,\n             :label_ending => \" (#{@assigned_issues.length})\",\n             :locals => {:issues => @assigned_issues}\n            },\n            {:name => 'joined',\n             :partial => 'issues/list_very_simple',\n             :label => :label_joined_issues,\n             :label_ending => \" (#{@joined_issues.length})\",\n             :locals => {:issues => @joined_issues}\n            },\n            {:name => 'added',\n             :partial => 'issues/list_very_simple',\n             :label => :label_added_issues,\n             :label_ending => \" (#{@added_issues.length})\",\n             :locals => {:issues => @added_issues}\n            },\n            {:name => 'watched',\n             :partial => 'issues/list_very_simple',\n             :label => :label_watched_issues,\n             :label_ending => \" (#{@watched_issues.length})\",\n             :locals => {:issues => @watched_issues}\n            }\n          ]\n  end\n\n\n  def my_projects_tabs\n    tabs = [\n            {:name => 'all',\n             :partial => 'my/project_list',\n             :label => :label_projects_all,\n             :locals => {\n                          :my_projects => @all_projects,\n                          :table_head => l(:label_projects_all),\n                          :table_id => \"all_my_projects_table\",\n                          :table_bottom_link => link_to(l(:label_project_new), {:controller => :projects, :action => :add}, :class => \"gt-btn-blue-large\"),\n                          :no_data_help => l(:help_no_workstreams),\n                          :no_data_link => link_to(l(:label_project_new), {:controller => 'projects', :action => 'add'}) + \"<br>or<br>\" + link_to(l(:label_browse_workstreams), {:controller => :projects, :action => :index})\n                        }\n            },\n            {:name => 'active',\n             :partial => 'my/project_list',\n             :label => :label_projects_active_in,\n             :locals => {\n                          :my_projects => @active_projects,\n                          :table_head => l(:label_projects_active_in),\n                          :table_id => \"active_projects_table\",\n                          :table_bottom_link => link_to(l(:label_browse_workstreams), {:controller => :projects, :action => :index}, :class => \"gt-btn-blue-large\"),\n                          :no_data_help => l(:help_no_workstreams_active),\n                          :no_data_link => link_to(l(:label_browse_workstreams), {:controller => :projects, :action => :index})\n                        }\n            },\n            {:name => 'started',\n             :partial => 'my/project_list',\n             :label => :label_projects_i_started,\n             :locals => {\n                          :my_projects => @my_projects,\n                          :table_head => l(:label_projects_i_started),\n                          :table_id => \"my_projects_table\",\n                          :table_bottom_link => link_to(l(:label_project_new), {:controller => :projects, :action => :add}, :class => \"gt-btn-blue-large\"),\n                          :no_data_help => l(:help_no_my_workstreams),\n                          :no_data_link => link_to(l(:label_project_new), {:controller => 'projects', :action => 'add'})\n                        }\n            },\n          ]\n  end\n\n\n  def upgrade_options(user)\n    if user.plan.code == Plan::FREE_CODE\n      link_to \"Upgrade\", {:controller => :my, :action => :upgrade}, :class => \"gt-btn-blue-large\"\n    else\n      link_to \"Upgrade / Downgrade\", {:controller => :my, :action => :upgrade}, :class => \"gt-btn-blue-large\"\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/news_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule NewsHelper\nend\n"
  },
  {
    "path": "app/helpers/projects_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule ProjectsHelper\n  def project_settings_tabs\n    tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural},\n            {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural},\n            {:name => 'members', :action => :manage_members, :partial => 'projects/settings/members', :label => :label_member_plural},\n            {:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural}\n            ]\n    tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)}\n  end\n\n  def project_image(project)\n  begin\n    content_tag('div', (image_tag formatted_project_path(@project, :png)), :class => \"gt-sidebar-logo\") if project && project.has_image?\n  rescue\n  end\n  end\n\n  def nomination_links(member,project)\n    return if member.user_id == User.current.id\n    return unless User.current.binding_voter_of?(project)\n    content = '<p class=\"gt-table-action-list\">'\n\n    #Link to nominate to core if user is a member\n    content << link_to(l(:label_nominate_to_core_team), project_motions_path(project, \"motion[variation]\" => Motion::VARIATION_NEW_CORE, \"motion[concerned_user_id]\" => member.user_id),\n                                           :class => 'icon icon-cr-offer',\n                                           :confirm => \"Are you sure you want to start a motion to nominate #{member.name} to the Core Team?\",\n                                           :method => :post) << '&nbsp;&nbsp;&nbsp;&nbsp;' if member.roles.first.id  == Role.member.id\n\n\n    #Link to drop from core if user is a core member\n    content << link_to(l(:label_drop_from_core_team), project_motions_path(project, \"motion[variation]\" => Motion::VARIATION_FIRE_CORE, \"motion[concerned_user_id]\" => member.user_id),\n                                          :method => :post,\n                                          :confirm => \"Are you sure you want to start a motion to remove #{member.name} from the Core Team and make her a Member?\",\n                                           :class => 'icon icon-cr-decline') << '  ' if member.roles.first.id  == Role.core_member.id\n\n\n    #Link to nominate to member if user is contributor, and current user is a binding member\n    content << link_to(l(:label_nominate_to_member), project_motions_path(project, \"motion[variation]\" => Motion::VARIATION_NEW_MEMBER, \"motion[concerned_user_id]\" => member.user_id),\n                                          :method => :post,\n                                          :confirm => \"Are you sure you want to start a motion to nominate #{member.name} as a Member?\",\n                                           :class => 'icon icon-cr-offer') << '  ' if member.roles.first.id  == Role.contributor.id\n\n    #Link to drop from member if user is member, and current user is binding member\n    content << link_to(l(:label_drop_from_member), project_motions_path(project, \"motion[variation]\" => Motion::VARIATION_FIRE_MEMBER, \"motion[concerned_user_id]\" => member.user_id),\n                                          :confirm => \"Are you sure you want to start a motion to remove the membership of #{member.name}\",\n                                          :method => :post,\n                                           :class => 'icon icon-cr-decline') << '  ' if member.roles.first.id  == Role.member.id\n\n    content << \"</p\"\n  end\n\n  def parent_project_select_tag(project)\n    selected = project.parent\n    # retrieve the requested parent project\n    parent_id = (params[:project] && params[:project][:parent_id]) || params[:parent_id]\n    if parent_id\n      selected = (parent_id.blank? ? nil : Project.find(parent_id))\n    end\n\n    options = ''\n    options << \"<option value=''></option>\" if project.allowed_parents.include?(nil)\n    options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected)\n    content_tag('select', options, :name => 'project[parent_id]')\n  end\n\n  # Renders a tree of projects as a nested set of unordered lists\n  # The given collection may be a subset of the whole project tree\n  # (eg. some intermediate nodes are private and can not be seen)\n  def render_project_hierarchy(projects)\n    s = ''\n    if projects.any?\n      ancestors = []\n      projects.each do |project|\n        if (ancestors.empty? || project.is_descendant_of?(ancestors.last))\n          s << \"<ul class='projects #{ ancestors.empty? ? 'root' : nil}'>\\n\"\n        else\n          ancestors.pop\n          s << \"</li>\"\n          while (ancestors.any? && !project.is_descendant_of?(ancestors.last))\n            ancestors.pop\n            s << \"</ul></li>\\n\"\n          end\n        end\n        classes = (ancestors.empty? ? 'root' : 'child')\n        s << \"<li class='#{classes}'><div class='#{classes}'>\" +\n               link_to(h(project), {:controller => 'projects', :action => 'show', :id => project}, :class => \"project #{User.current.member_of?(project) ? 'my-project' : nil}\")\n        s << \"<div class='wiki description'>#{textilizable(project.short_description, :project => project)}</div>\" unless project.description.blank?\n        s << \"</div>\\n\"\n        ancestors << project\n      end\n      s << (\"</li></ul>\\n\" * ancestors.size)\n    end\n    s\n  end\n\n  # Renders the \"add item\" quick jump box.\n  def render_new_item_jump_box\n      s = '<select id=\"new_item_jumpbox\" onchange=\"if (this.value != \\'\\') { window.location = this.value; }\">' +\n            \"<option value='/projects/#{@project.id}' selected=\\\"yes\\\">#{l(:label_new_item_in)}</option>\" +\n            \"<option value='#{url_for(:controller => 'issues', :action => 'new', :project_id => @project)}'>#{@project}</option>\" +\n            '<option value=\"\" disabled=\"disabled\">---</option>'\n      if @subprojects.any?\n        s_options = \"\"\n        s_options << project_tree_options_for_select(@subprojects, :selected => @project) do |p|\n          { :value => url_for(:controller => 'issues', :action => 'new', :project_id => p) }\n        end\n        s << s_options\n        s << '<option value=\"\" disabled=\"disabled\">---</option>'\n      end\n      s << '</select>'\n      s << '<span id=\"widthcalc\" style=\"display:none;\"></span>'\n  end\n\nend\n"
  },
  {
    "path": "app/helpers/queries_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule QueriesHelper\n\n  def operators_for_select(filter_type)\n    Query.operators_by_filter_type[filter_type].collect {|o| [l(Query.operators[o]), o]}\n  end\n\n  def column_header(column)\n    column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,\n                                                        :default_order => column.default_order) :\n                      content_tag('th', column.caption)\n  end\n\n  def column_content(column, issue)\n    value = column.value(issue)\n\n    case value.class.name\n    when 'String'\n      if column.name == :subject\n        link_to(h(value), {:controller => 'issues', :action => 'show', :id => issue}, :class => \"fancyframe\")\n      else\n        h(value)\n      end\n    when 'Time'\n      format_time(value)\n    when 'Date'\n      format_date(value)\n    when 'Fixnum', 'Float'\n      value.to_s\n    when 'User'\n      link_to_user value\n    when 'Project'\n      link_to(h(value), :controller => 'projects', :action => 'show', :id => value)\n    when 'TrueClass'\n      l(:general_text_Yes)\n    when 'FalseClass'\n      l(:general_text_No)\n    else\n      h(value)\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/reports_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule ReportsHelper\n\n  def aggregate(data, criteria)\n    a = 0\n    data.each { |row|\n      match = 1\n      criteria.each { |k, v|\n        match = 0 unless (row[k].to_s == v.to_s) || (k == 'closed' && row[k] == (v == 0 ? \"f\" : \"t\"))\n      } unless criteria.nil?\n      a = a + row[\"total\"].to_i if match == 1\n    } unless data.nil?\n    a\n  end\n\n  def aggregate_link(data, criteria, *args)\n    a = aggregate data, criteria\n    a > 0 ? link_to(a, *args) : '-'\n  end\nend\n"
  },
  {
    "path": "app/helpers/retros_helper.rb",
    "content": "module RetrosHelper\n  def render_title_date\n    end_date = @retro.created_at.advance(:days => Setting::DEFAULT_RETROSPECTIVE_LENGTH)\n    if (@retro.ended?)\n      return \"ended #{distance_of_time_in_words(Time.now,end_date)} ago\"\n    else\n      return \"ends in #{distance_of_time_in_words(Time.now,end_date)}\"\n    end\n  end\n\n  def team_from_issue(issue)\n    issue.team_votes.collect{|iv| link_to_user_from_id iv.user_id }.join(\", \")\n  end\n\n  def accuracy_display(self_bias,magnitude)\n    return \"<br>Didn't vote\" if self_bias.nil? && magnitude.nil?\n    content = \"\"\n    content << \"<br>#{tame_bias(self_bias)}<br>#{tame_scale(magnitude)}\"\n  end\nend\n"
  },
  {
    "path": "app/helpers/search_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule SearchHelper\n  def highlight_tokens(text, tokens)\n    return text unless text && tokens && !tokens.empty?\n    re_tokens = tokens.collect {|t| Regexp.escape(t)}\n    regexp = Regexp.new \"(#{re_tokens.join('|')})\", Regexp::IGNORECASE\n    result = ''\n    text.split(regexp).each_with_index do |words, i|\n      if result.length > 1200\n        # maximum length of the preview reached\n        result << '...'\n        break\n      end\n      words = words.mb_chars\n      if i.even?\n        result << h(words.length > 100 ? \"#{words.slice(0..44)} ... #{words.slice(-45..-1)}\" : words)\n      else\n        t = (tokens.index(words.downcase) || 0) % 4\n        result << content_tag('span', h(words), :class => \"highlight token-#{t}\")\n      end\n    end\n    result\n  end\n\n  def type_label(t)\n    l(\"label_#{t.singularize}_plural\")\n  end\n\n  def project_select_tag\n    options = [[l(:label_project_all), 'all']]\n    options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty?\n    options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty?\n    options << [@project.name, ''] unless @project.nil?\n    select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1\n  end\n\n  def render_results_by_type(results_by_type)\n    return unless results_by_type\n    links = []\n    # Sorts types by results count\n    results_by_type.keys.sort {|a, b| results_by_type[b] <=> results_by_type[a]}.each do |t|\n      c = results_by_type[t]\n      next if c == 0\n      text = \"#{type_label(t)} (#{c})\"\n      links << link_to(text, :q => params[:q], :titles_only => params[:title_only], :all_words => params[:all_words], :scope => params[:scope], t => 1)\n    end\n    ('<ul>' + links.map {|link| content_tag('li', link)}.join(' ') + '</ul>') unless links.empty?\n  end\nend\n"
  },
  {
    "path": "app/helpers/settings_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule SettingsHelper\n  def administration_settings_tabs\n    tabs = [{:name => 'general', :partial => 'settings/general', :label => :label_general},\n            {:name => 'display', :partial => 'settings/display', :label => :label_display},\n            {:name => 'authentication', :partial => 'settings/authentication', :label => :label_authentication},\n            {:name => 'projects', :partial => 'settings/projects', :label => :label_project_plural},\n            {:name => 'issues', :partial => 'settings/issues', :label => :label_issue_tracking},\n            {:name => 'notifications', :partial => 'settings/notifications', :label => :field_mail_notification},\n            {:name => 'mail_handler', :partial => 'settings/mail_handler', :label => :label_incoming_emails}\n            ]\n  end\n\n  def setting_select(setting, choices, options={})\n    if blank_text = options.delete(:blank)\n      choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices\n    end\n    setting_label(setting, options) +\n      select_tag(\"settings[#{setting}]\", options_for_select(choices, Setting.send(setting).to_s), options)\n  end\n\n  def setting_multiselect(setting, choices, options={})\n    setting_values = Setting.send(setting)\n    setting_values = [] unless setting_values.is_a?(Array)\n\n    setting_label(setting, options) +\n      hidden_field_tag(\"settings[#{setting}][]\", '') +\n      choices.collect do |choice|\n        text, value = (choice.is_a?(Array) ? choice : [choice, choice])\n        content_tag('label',\n          check_box_tag(\"settings[#{setting}][]\", value, Setting.send(setting).include?(value)) + text.to_s,\n          :class => 'block'\n        )\n      end.join\n  end\n\n  def setting_text_field(setting, options={})\n    setting_label(setting, options) +\n      text_field_tag(\"settings[#{setting}]\", Setting.send(setting), options)\n  end\n\n  def setting_text_area(setting, options={})\n    setting_label(setting, options) +\n      text_area_tag(\"settings[#{setting}]\", Setting.send(setting), options)\n  end\n\n  def setting_check_box(setting, options={})\n    setting_label(setting, options) +\n      hidden_field_tag(\"settings[#{setting}]\", 0) +\n      check_box_tag(\"settings[#{setting}]\", 1, Setting.send(\"#{setting}?\"), options)\n  end\n\n  def setting_label(setting, options={})\n    label = options.delete(:label)\n    label != false ? content_tag(\"label\", l(label || \"setting_#{setting}\")) : ''\n  end\nend\n"
  },
  {
    "path": "app/helpers/sort_helper.rb",
    "content": "# Helpers to sort tables using clickable column headers.\n#\n# Author:  Stuart Rackham <srackham@methods.co.nz>, March 2005.\n#          Shereef Bishay, 2009\n# License: This source code is released under the MIT license.\n#\n# - Consecutive clicks toggle the column's sort order.\n# - Sort state is maintained by a session hash entry.\n# - CSS classes identify sort column and state.\n# - Typically used in conjunction with the Pagination module.\n#\n# Example code snippets:\n#\n# Controller:\n#\n#   helper :sort\n#   include SortHelper\n#\n#   def list\n#     sort_init 'last_name'\n#     sort_update %w(first_name last_name)\n#     @items = Contact.find_all nil, sort_clause\n#   end\n#\n# Controller (using Pagination module):\n#\n#   helper :sort\n#   include SortHelper\n#\n#   def list\n#     sort_init 'last_name'\n#     sort_update %w(first_name last_name)\n#     @contact_pages, @items = paginate :contacts,\n#       :order_by => sort_clause,\n#       :per_page => 10\n#   end\n#\n# View (table header in list.rhtml):\n#\n#   <thead>\n#     <tr>\n#       <%= sort_header_tag('id', :title => 'Sort by contact ID') %>\n#       <%= sort_header_tag('last_name', :caption => 'Name') %>\n#       <%= sort_header_tag('phone') %>\n#       <%= sort_header_tag('address', :width => 200) %>\n#     </tr>\n#   </thead>\n#\n# - Introduces instance variables: @sort_default, @sort_criteria\n# - Introduces param :sort\n#\n\nmodule SortHelper\n  class SortCriteria\n\n    def initialize\n      @criteria = []\n    end\n\n    def available_criteria=(criteria)\n      unless criteria.is_a?(Hash)\n        criteria = criteria.inject({}) {|h,k| h[k] = k; h}\n      end\n      @available_criteria = criteria\n    end\n\n    def from_param(param)\n      @criteria = param.to_s.split(',').collect {|s| s.split(':')[0..1]}\n      normalize!\n    end\n\n    def criteria=(arg)\n      @criteria = arg\n      normalize!\n    end\n\n    def to_param\n      @criteria.collect {|k,o| k + (o ? '' : ':desc')}.join(',')\n    end\n\n    def to_sql\n      sql = @criteria.collect do |k,o|\n        if s = @available_criteria[k]\n          (o ? s.to_a : s.to_a.collect {|c| \"#{c} DESC\"}).join(', ')\n        end\n      end.compact.join(', ')\n      sql.blank? ? nil : sql\n    end\n\n    def add!(key, asc)\n      @criteria.delete_if {|k,o| k == key}\n      @criteria = [[key, asc]] + @criteria\n      normalize!\n    end\n\n    def add(*args)\n      r = self.class.new.from_param(to_param)\n      r.add!(*args)\n      r\n    end\n\n    def first_key\n      @criteria.first && @criteria.first.first\n    end\n\n    def first_asc?\n      @criteria.first && @criteria.first.last\n    end\n\n    def empty?\n      @criteria.empty?\n    end\n\n    private\n\n    def normalize!\n      @criteria ||= []\n      @criteria = @criteria.collect {|s| s = s.to_a; [s.first, (s.last == false || s.last == 'desc') ? false : true]}\n      @criteria = @criteria.select {|k,o| @available_criteria.has_key?(k)} if @available_criteria\n      @criteria.slice!(3)\n      self\n    end\n\n  end\n\n  def sort_name\n    controller_name + '_' + action_name + '_sort'\n  end\n\n  # Initializes the default sort.\n  # Examples:\n  #\n  #   sort_init 'name'\n  #   sort_init 'id', 'desc'\n  #   sort_init ['name', ['id', 'desc']]\n  #   sort_init [['name', 'desc'], ['id', 'desc']]\n  #\n  def sort_init(*args)\n    case args.size\n    when 1\n      @sort_default = args.first.is_a?(Array) ? args.first : [[args.first]]\n    when 2\n      @sort_default = [[args.first, args.last]]\n    else\n      raise ArgumentError\n    end\n  end\n\n  # Updates the sort state. Call this in the controller prior to calling\n  # sort_clause.\n  # - criteria can be either an array or a hash of allowed keys\n  #\n  def sort_update(criteria)\n    @sort_criteria = SortCriteria.new\n    @sort_criteria.available_criteria = criteria\n    @sort_criteria.from_param(params[:sort] || session[sort_name])\n    @sort_criteria.criteria = @sort_default if @sort_criteria.empty?\n    session[sort_name] = @sort_criteria.to_param\n  end\n\n  # Clears the sort criteria session data\n  #\n  def sort_clear\n    session[sort_name] = nil\n  end\n\n  # Returns an SQL sort clause corresponding to the current sort state.\n  # Use this to sort the controller's table items collection.\n  #\n  def sort_clause\n    @sort_criteria.to_sql\n  end\n\n  # Returns a link which sorts by the named column.\n  #\n  # - column is the name of an attribute in the sorted record collection.\n  # - the optional caption explicitly specifies the displayed link text.\n  # - 2 CSS classes reflect the state of the link: sort and asc or desc\n  #\n  def sort_link(column, caption, default_order)\n    css, order = nil, default_order\n\n    if column.to_s == @sort_criteria.first_key\n      if @sort_criteria.first_asc?\n        css = 'sort asc'\n        order = 'desc'\n      else\n        css = 'sort desc'\n        order = 'asc'\n      end\n    end\n    caption = column.to_s.humanize unless caption\n\n    sort_options = { :sort => @sort_criteria.add(column.to_s, order).to_param }\n    # don't reuse params if filters are present\n    url_options = params.has_key?(:set_filter) ? sort_options : params.merge(sort_options)\n\n     # Add project_id to url_options\n    url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id)\n\n    link_to_remote(caption,\n                  {:update => \"content\", :url => url_options, :method => :get},\n                  {:href => url_for(url_options),\n                   :class => css})\n  end\n\n  # Returns a table header <th> tag with a sort link for the named column\n  # attribute.\n  #\n  # Options:\n  #   :caption     The displayed link name (defaults to titleized column name).\n  #   :title       The tag's 'title' attribute (defaults to 'Sort by :caption').\n  #\n  # Other options hash entries generate additional table header tag attributes.\n  #\n  # Example:\n  #\n  #   <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %>\n  #\n  def sort_header_tag(column, options = {})\n    caption = options.delete(:caption) || column.to_s.humanize\n    default_order = options.delete(:default_order) || 'asc'\n    options[:title] = l(:label_sort_by, \"\\\"#{caption}\\\"\") unless options[:title]\n    content_tag('th', sort_link(column, caption, default_order), options)\n  end\n\nend\n"
  },
  {
    "path": "app/helpers/users_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule UsersHelper\n  def users_status_options_for_select(selected)\n    user_count_by_status = User.count(:group => 'status').to_hash\n    options_for_select([[l(:label_all), ''],\n                        [\"#{l(:status_active)} (#{user_count_by_status[1].to_i})\", 1],\n                        [\"#{l(:status_registered)} (#{user_count_by_status[2].to_i})\", 2],\n                        [\"#{l(:status_locked)} (#{user_count_by_status[3].to_i})\", 3]], selected)\n  end\n\n  # Options for the new membership projects combo-box\n  def options_for_membership_project_select(user, projects)\n    options = content_tag('option', \"--- #{l(:actionview_instancetag_blank_option)} ---\")\n    options << project_tree_options_for_select(projects) do |p|\n      {:disabled => (user.projects.include?(p))}\n    end\n    options\n  end\n\n  def change_status_link(user)\n    url = {:controller => 'users', :action => 'edit', :id => user, :page => params[:page], :status => params[:status], :tab => nil}\n\n    if user.locked?\n      link_to l(:button_unlock), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :post, :class => 'icon icon-unlock'\n    elsif user.registered?\n      link_to l(:button_activate), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :post, :class => 'icon icon-unlock'\n    elsif user != User.current\n      link_to l(:button_lock), url.merge(:user => {:status => User::STATUS_LOCKED}), :method => :post, :class => 'icon icon-lock'\n    end\n  end\n\n  def user_settings_tabs\n    tabs = [{:name => 'general', :partial => 'users/general', :label => :label_general},\n            {:name => 'memberships', :partial => 'users/memberships', :label => :label_project_plural}\n            ]\n    tabs\n  end\n\n\n  def reputation_value(reputation_type, reputation_value)\n    case reputation_type\n    when Reputation::VARIATION_SELF_BIAS\n      tame_bias(reputation_value)\n    when Reputation::VARIATION_SCALE_BIAS\n      tame_scale(reputation_value)\n    end\n  end\n\n  def reputation_project(reputation)\n    if reputation.project_id != 0\n      link_to(h(reputation.project.name_with_ancestors), :controller => 'projects', :action => 'show', :id => reputation.project)\n    else\n      \"Platform Wide\"\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/watchers_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule WatchersHelper\n\n  # Valid options\n  # * :id - the element id\n  # * :replace - a string or array of element ids that will be\n  #   replaced\n  def watcher_tag(object, user, options={:replace => 'watcher'})\n    id = options[:id]\n    id ||= options[:replace] if options[:replace].is_a? String\n    content_tag(\"span\", watcher_link(object, user, options), :id => id)\n  end\n\n  # Valid options\n  # * :replace - a string or array of element ids that will be\n  #   replaced\n  def watcher_link(object, user, options={:replace => 'watcher'})\n    return '' unless user && user.logged? && object.respond_to?('watched_by?')\n    watched = object.watched_by?(user)\n    url = {:controller => 'watchers',\n           :action => (watched ? 'unwatch' : 'watch'),\n           :object_type => object.class.to_s.underscore,\n           :object_id => object.id,\n           :replace => options[:replace]}\n    link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)),\n                   {:url => url},\n                   :href => url_for(url),\n                   :class => (watched ? 'icon icon-fav action-state-button' : 'icon icon-fav-off action-state-button'))\n\n  end\n\n  # Returns a comma separated list of users watching the given object\n  def watchers_list(object)\n    remove_allowed = User.current.allowed_to?(\"delete_#{object.class.name.underscore}_watchers\".to_sym, object.project)\n    object.watcher_users.collect do |user|\n      s = content_tag('span', link_to_user(user), :class => 'user')\n      if remove_allowed\n        url = {:controller => 'watchers',\n               :action => 'destroy',\n               :object_type => object.class.to_s.underscore,\n               :object_id => object.id,\n               :user_id => user}\n        s += ' ' + link_to_remote(image_tag('delete.png'),\n                                  {:url => url},\n                                  :href => url_for(url),\n                                  :style => \"vertical-align: middle\")\n      end\n      s\n    end.join(\",\\n\")\n  end\nend\n"
  },
  {
    "path": "app/helpers/wiki_helper.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule WikiHelper\n\n  def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0)\n    s = ''\n    pages.select {|p| p.parent == parent}.each do |page|\n      attrs = \"value='#{page.id}'\"\n      attrs << \" selected='selected'\" if selected == page\n      indent = (level > 0) ? ('&nbsp;' * level * 2 + '&#187; ') : nil\n\n      s << \"<option value='#{page.id}'>#{indent}#{h page.pretty_title}</option>\\n\" +\n             wiki_page_options_for_select(pages, selected, page, level + 1)\n    end\n    s\n  end\n\n  def html_diff(wdiff)\n    words = wdiff.words.collect{|word| h(word)}\n    words_add = 0\n    words_del = 0\n    dels = 0\n    del_off = 0\n    wdiff.diff.diffs.each do |diff|\n      add_at = nil\n      add_to = nil\n      del_at = nil\n      deleted = \"\"\n      diff.each do |change|\n        pos = change[1]\n        if change[0] == \"+\"\n          add_at = pos + dels unless add_at\n          add_to = pos + dels\n          words_add += 1\n        else\n          del_at = pos unless del_at\n          deleted << ' ' + h(change[2])\n          words_del   += 1\n        end\n      end\n      if add_at\n        words[add_at] = '<span class=\"diff_in\">' + words[add_at]\n        words[add_to] = words[add_to] + '</span>'\n      end\n      if del_at\n        words.insert del_at - del_off + dels + words_add, '<span class=\"diff_out\">' + deleted + '</span>'\n        dels += 1\n        del_off += words_del\n        words_del = 0\n      end\n    end\n    simple_format_without_paragraph(words.join(' '))\n  end\nend\n"
  },
  {
    "path": "app/models/activity_stream.rb",
    "content": "# Copyright (c) 2008 Matson Systems, Inc.\n# Released under the BSD license found in the file\n# LICENSE included with this ActivityStreams plug-in.\n\n# activity_stream.rb provides the model ActivityStream\n\nclass ActivityStream < ActiveRecord::Base\n\n  # status levels, for generating activites that don't display\n  VISIBLE   = 0     # Noraml visible activity\n  DEBUG     = 1     # Test activity used for debugginng\n  INTERNAL  = 2     # Internal system activity\n  DELETED   = 3     # A deleted activity (soft delete)\n\n  belongs_to :actor, :polymorphic => true\n  belongs_to :object, :polymorphic => true\n  belongs_to :indirect_object, :polymorphic => true\n  belongs_to :project\n\n  named_scope :recent, {:conditions => \"activity_streams.created_at > '#{(Time.now.advance :days => Setting::DAYS_FOR_ACTIVE_MEMBERSHIP * -1).to_s}'\"}\n\n  def before_save\n    self.is_public = self.project.is_public if self.project\n    self.is_public = false if self.hidden_from_user_id > 0\n  end\n\n  # Finds the recent activities for a given actor, and honors\n  # the users activity_stream_preferences.  Please see the README\n  # for an example usage.\n  def self.recent_actors(actor, location, limit=12)\n\n    unless actor.class.name == ACTIVITY_STREAM_USER_MODEL\n      find(:all, :conditions =>\n        {:actor_id => actor.id,\n        :actor_type => actor.class.name,\n        :status => 0}, :order => \"created_at DESC\", :limit => limit,\n        :include => [:actor, :object, :indirect_object])\n\n    else\n      # FIXME: We really want :include => [:actor, :object], however, when\n      # the \"p.id\" => nil condition prevents polymorphic :include from working\n      find(:all,\n        :joins => self.preference_join(location),\n        :conditions => [\n          'actor_id = ? and actor_type = ? and status = ? and p.id IS NULL',\n          actor.id, actor.class.name, 0 ],\n        :order => \"created_at DESC\",\n        :limit => limit)\n    end\n  end\n\n  # Finds the recent activities for a given actor, and honors\n  # the users activity_stream_preferences.  Please see the README\n  # for a sample usage.\n  def self.recent_objects(object, location, limit=12)\n    # FIXME: We really want :include => [:actor, :object], however, when\n    # the \"p.id\" => nil condition prevents polymorphic :include from working\n    find(:all,\n      :joins => self.preference_join(location),\n      :conditions => [\n          \"object_id = ? and object_type = ? and status = ? and p.id IS NULL\",\n          object.id, object.class.name, 0 ],\n      :order => \"created_at DESC\",\n      :limit => limit)\n  end\n\n  def self.preference_join(location) # :nodoc:\n    # location is not tainted as it is a symbol from\n    # the code\n    \"LEFT OUTER JOIN activity_stream_preferences p \\\n      ON #{ACTIVITY_STREAM_USER_MODEL_ID} = actor_id  \\\n      AND actor_type = '#{ACTIVITY_STREAM_USER_MODEL}'  \\\n      AND activity_streams.activity = p.activity \\\n      AND location = '#{location.to_s}'\"\n  end\n\n  def self.fetch(user_id, project_id, with_subprojects, limit, max_created_at = nil)\n    max_created_at = DateTime.now if max_created_at.nil? || max_created_at == \"\"\n    length = limit  || Setting::ACTIVITY_STREAM_LENGTH\n\n    if limit\n      length = limit\n    end\n\n    with_subprojects ||= true\n    project_id.nil? ? project = nil : project = Project.find(project_id)\n\n    user = User.find(user_id) if user_id\n    return [] if user && with_subprojects == \"custom\" && user.projects.empty?#Customized activity stream for user, but user doesn't belong to any projects\n\n\n    conditions = {}\n    conditions[:actor_id] = user_id unless user_id.nil? || with_subprojects == \"custom\"\n    conditions[:project_id] = user.projects.collect{|m| m.id} if !user.nil? && with_subprojects == \"custom\" && !user.projects.empty? #Customized activity stream for user\n    conditions[:project_id] = project.id if project && !with_subprojects\n    conditions[:project_id] = project.sub_project_array_visible_to(User.current) if project && with_subprojects\n\n    project_specified = conditions[:project_id] #temp variable for later use\n\n    conditions = conditions.to_array_conditions\n\n    logger.info { \"conditions #{conditions.inspect}\" }\n    conditions[0] += \" AND \" unless conditions[0].empty?\n    conditions[0] += \" created_at >= ? AND created_at <= ?\"\n    conditions.push DateTime.now - 20.year\n    conditions.push max_created_at\n\n    conditions[0] += \" AND hidden_from_user_id <> ?\"\n    conditions.push User.current.id\n\n    unless project_specified\n      conditions[0] += \" AND ((is_public = true) OR (project_id in (?)))\"\n      conditions.push User.current.projects.collect{|m| m.id}\n    end\n\n    unless User.current.logged?\n      conditions[0] += \" AND (is_public = true)\"\n    end\n\n    activities_by_item = ActivityStream.all(:conditions => conditions, :limit => length, :order => \"created_at desc\").group_by {|a| a.object_type.to_s + a.object_id.to_s}\n    activities_by_item.each_pair do |key,value|\n      activities_by_item[key] = value.sort_by{|i| - i[:created_at].to_i}\n    end\n\n    activities_by_item.sort_by{|g| - g[1][0][:created_at].to_i}\n  end\n\n  # Soft Delete in as some activites are necessary for site stats\n  def soft_destroy\n    self.update_attribute(:status, DELETED)\n  end\n\nend\n\n\n\n"
  },
  {
    "path": "app/models/activity_stream_preference.rb",
    "content": "# Copyright (c) 2008 Matson Systems, Inc.\n# Released under the BSD license found in the file\n# LICENSE included with this ActivityStreams plug-in.\n\n# activity_stream_preference.rb provides the model ActivityStreamPreference\n#\n# ActivityStreamPreference is the model used to keep track of preferences for the Activity Stream Plug-in\n\nclass ActivityStreamPreference < ActiveRecord::Base\nend\n"
  },
  {
    "path": "app/models/activity_stream_total.rb",
    "content": "# Copyright (c) 2008 Matson Systems, Inc.\n# Released under the BSD license found in the file\n# LICENSE included with this ActivityStreams plug-in.\n\n# activity_stream_total.rb provides the model ActivityStreamTotal\n#\n# ActivityStreamTotal is the model used to keep total counts on related activities\n#\n\nclass ActivityStreamTotal < ActiveRecord::Base\n  belongs_to :object, :polymorphic => true\nend\n"
  },
  {
    "path": "app/models/attachment.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nrequire \"digest/md5\"\n\nclass Attachment < ActiveRecord::Base\n  belongs_to :container, :polymorphic => true\n  belongs_to :author, :class_name => \"User\", :foreign_key => \"author_id\"\n\n  validates_presence_of :filename, :author\n  validates_length_of :filename, :maximum => 255\n  validates_length_of :disk_filename, :maximum => 255\n\n  after_validation :put_to_s3\n  before_destroy   :delete_from_s3\n\n\n  acts_as_event :title => :filename,\n                :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}}\n\n  cattr_accessor :storage_path\n  unloadable # Send unloadable so it will not be unloaded in development\n  attr_accessor :s3_access_key_id, :s3_secret_acces_key, :s3_bucket, :s3_bucket\n\n  @@storage_path = \"#{RAILS_ROOT}/files\"\n\n  def validate\n    if self.filesize > Setting.attachment_max_size.to_i.kilobytes\n      errors.add(:base, :too_long, :count => Setting.attachment_max_size.to_i.kilobytes)\n    end\n  end\n\n  def put_to_s3\n    if @temp_file && (@temp_file.size > 0)\n      logger.debug(\"Uploading to #{RedmineS3::Connection.uri}/#{disk_filename}\")\n      RedmineS3::Connection.put(disk_filename, @temp_file.read)\n      RedmineS3::Connection.publicly_readable!(disk_filename)\n      md5 = Digest::MD5.new\n      self.digest = md5.hexdigest\n    end\n    @temp_file = nil # so that the model's original after_save block skips writing to the fs\n  end\n\n  def delete_from_s3\n    if ENV['RACK_ENV'] == 'production'\n      logger.debug(\"Deleting #{RedmineS3::Connection.uri}/#{disk_filename}\")\n      RedmineS3::Connection.delete(disk_filename)\n    end\n  end\n\n\n  def file=(incoming_file)\n    unless incoming_file.nil?\n      @temp_file = incoming_file\n      if @temp_file.size > 0\n        self.filename = sanitize_filename(@temp_file.original_filename)\n        self.disk_filename = Attachment.disk_filename(filename)\n        self.content_type = @temp_file.content_type.to_s.chomp\n        self.filesize = @temp_file.size\n      end\n    end\n  end\n\n  def file\n    nil\n  end\n\n  # Copies the temporary file to its final location\n  # and computes its MD5 hash\n  def before_save\n    logger.debug(\"entering before save\")\n    if @temp_file && (@temp_file.size > 0)\n      logger.debug(\"saving '#{self.diskfile}'\")\n      md5 = Digest::MD5.new\n      File.open(diskfile, \"wb\") do |f|\n        buffer = \"\"\n        while (buffer = @temp_file.read(8192))\n          f.write(buffer)\n          md5.update(buffer)\n        end\n      end\n      self.digest = md5.hexdigest\n    end\n    # Don't save the content type if it's longer than the authorized length\n    if self.content_type && self.content_type.length > 255\n      self.content_type = nil\n    end\n  end\n\n  # Deletes file on the disk\n  def after_destroy\n    File.delete(diskfile) if !filename.blank? && File.exist?(diskfile)\n  end\n\n  # Returns file's location on disk\n  def diskfile\n    \"#{@@storage_path}/#{self.disk_filename}\"\n  end\n\n  def increment_download\n    increment!(:downloads)\n  end\n\n  def project\n    container.project\n  end\n\n  def visible?(user=User.current)\n    container.attachments_visible?(user)\n  end\n\n  def deletable?(user=User.current)\n    container.attachments_deletable?(user)\n  end\n\n  def image?\n    self.filename =~ /\\.(jpe?g|gif|png)$/i\n  end\n\n  def is_text?\n    Redmine::MimeType.is_type?('text', filename)\n  end\n\n  def is_diff?\n    self.filename =~ /\\.(patch|diff)$/i\n  end\n\n  # Returns true if the file is readable\n  def readable?\n    File.readable?(diskfile)\n  end\n\n  private\n\n  def sanitize_filename(value)\n    # get only the filename, not the whole path\n    just_filename = value.gsub(/^.*(\\\\|\\/)/, '')\n    # NOTE: File.basename doesn't work right with Windows paths on Unix\n    # INCORRECT: just_filename = File.basename(value.gsub('\\\\\\\\', '/'))\n\n    # Finally, replace all non alphanumeric, hyphens or periods with underscore\n    @filename = just_filename.gsub(/[^\\w\\.\\-]/,'_')\n  end\n\n  # Returns an ASCII or hashed filename\n  def self.disk_filename(filename)\n    df = DateTime.now.strftime(\"%y%m%d%H%M%S\") + \"_\"\n    if filename =~ %r{^[a-zA-Z0-9_\\.\\-]*$}\n      df << filename\n    else\n      df << Digest::MD5.hexdigest(filename)\n      # keep the extension if any\n      df << $1 if filename =~ %r{(\\.[a-zA-Z0-9]+)$}\n    end\n    df\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/auth_source.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass AuthSource < ActiveRecord::Base\n  has_many :users\n\n  validates_presence_of :name\n  validates_uniqueness_of :name\n  validates_length_of :name, :maximum => 60\n\n  def authenticate(login, password)\n  end\n\n  def test_connection\n  end\n\n  def auth_method_name\n    \"Abstract\"\n  end\n\n  # Try to authenticate a user not yet registered against available sources\n  def self.authenticate(login, password)\n    AuthSource.find(:all, :conditions => [\"onthefly_register=?\", true]).each do |source|\n      begin\n        logger.debug \"Authenticating '#{login}' against '#{source.name}'\" if logger && logger.debug?\n        attrs = source.authenticate(login, password)\n      rescue => e\n        logger.error \"Error during authentication: #{e.message}\"\n        attrs = nil\n      end\n      return attrs if attrs\n    end\n    return nil\n  end\nend\n\n"
  },
  {
    "path": "app/models/auth_source_ldap.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nrequire 'net/ldap'\nrequire 'iconv'\n\nclass AuthSourceLdap < AuthSource\n  validates_presence_of :host, :port, :attr_login\n  validates_length_of :name, :host, :account_password, :maximum => 60, :allow_nil => true\n  validates_length_of :account, :base_dn, :maximum => 255, :allow_nil => true\n  validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true\n  validates_numericality_of :port, :only_integer => true\n\n  before_validation :strip_ldap_attributes\n\n  def after_initialize\n    self.port = 389 if self.port == 0\n  end\n\n  def authenticate(login, password)\n    return nil if login.blank? || password.blank?\n    attrs = []\n    # get user's DN\n    ldap_con = initialize_ldap_con(self.account, self.account_password)\n    login_filter = Net::LDAP::Filter.eq( self.attr_login, login )\n    object_filter = Net::LDAP::Filter.eq( \"objectClass\", \"*\" )\n    dn = String.new\n    ldap_con.search( :base => self.base_dn,\n                     :filter => object_filter & login_filter,\n                     # only ask for the DN if on-the-fly registration is disabled\n                     :attributes=> (onthefly_register? ? ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail] : ['dn'])) do |entry|\n      dn = entry.dn\n      attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),\n               :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),\n               :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),\n               :auth_source_id => self.id ] if onthefly_register?\n    end\n    return nil if dn.empty?\n    logger.debug \"DN found for #{login}: #{dn}\" if logger && logger.debug?\n    # authenticate user\n    ldap_con = initialize_ldap_con(dn, password)\n    return nil unless ldap_con.bind\n    # return user's attributes\n    logger.debug \"Authentication successful for '#{login}'\" if logger && logger.debug?\n    attrs\n  rescue  Net::LDAP::LdapError => text\n    raise \"LdapError: \" + text\n  end\n\n  # test the connection to the LDAP\n  def test_connection\n    ldap_con = initialize_ldap_con(self.account, self.account_password)\n    ldap_con.open { }\n  rescue  Net::LDAP::LdapError => text\n    raise \"LdapError: \" + text\n  end\n\n  def auth_method_name\n    \"LDAP\"\n  end\n\n  private\n\n  def strip_ldap_attributes\n    [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr|\n      write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil?\n    end\n  end\n\n  def initialize_ldap_con(ldap_user, ldap_password)\n    options = { :host => self.host,\n                :port => self.port,\n                :encryption => (self.tls ? :simple_tls : nil)\n              }\n    options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank?\n    Net::LDAP.new options\n  end\n\n  def self.get_attr(entry, attr_name)\n    if !attr_name.blank?\n      entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]\n    end\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/board.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Board < ActiveRecord::Base\n  belongs_to :project\n  has_many :topics, :class_name => 'Message', :conditions => \"#{Message.table_name}.parent_id IS NULL\", :order => \"#{Message.table_name}.created_at DESC\"\n  has_many :messages, :dependent => :delete_all, :order => \"#{Message.table_name}.created_at DESC\"\n  belongs_to :last_message, :class_name => 'Message', :foreign_key => :last_message_id\n  acts_as_list :scope => :project_id\n  acts_as_watchable\n\n\n  validates_presence_of :name, :description\n  validates_length_of :name, :maximum => 30\n  validates_length_of :description, :maximum => 255\n\n  def visible?(user=User.current)\n    !user.nil? && user.allowed_to?(:view_messages, project)\n  end\n\n  def to_s\n    name\n  end\n\n  def reset_counters!\n    self.class.reset_counters!(id)\n  end\n\n  # Updates topics_count, messages_count and last_message_id attributes for +board_id+\n  def self.reset_counters!(board_id)\n    board_id = board_id.to_i\n    update_all(\"topics_count = (SELECT COUNT(*) FROM #{Message.table_name} WHERE board_id=#{board_id} AND parent_id IS NULL),\" +\n               \" messages_count = (SELECT COUNT(*) FROM #{Message.table_name} WHERE board_id=#{board_id}),\" +\n               \" last_message_id = (SELECT MAX(id) FROM #{Message.table_name} WHERE board_id=#{board_id})\",\n               [\"id = ?\", board_id])\n  end\nend\n\n"
  },
  {
    "path": "app/models/comment.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Comment < ActiveRecord::Base\n  belongs_to :commented, :polymorphic => true, :counter_cache => true\n  belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'\n\n  validates_presence_of :commented, :author, :comments\n\n  after_save :send_mentions\n\n  def send_mentions\n    Mention.parse(self, self.author_id)\n  end\n\n  def title\n    case self.commented_type\n    when \"News\"\n      self.commented.title\n    end\n  end\n\n  def mention(mentioner_id, mentioned_id, mention_text)\n    Notification.create :recipient_id => mentioned_id,\n                        :variation => 'mention',\n                        :params => {:mention_text => self.comments,\n                                    :url => {:controller => self.commented_type.to_s.pluralize.downcase, :action => \"show\", :id => self.commented_id},\n                                    :title => self.title},\n                        :sender_id => mentioner_id,\n                        :source_id => self.id,\n                        :source_type => \"Comment(#{self.commented_type})\"\n  end\nend\n\n"
  },
  {
    "path": "app/models/credit.rb",
    "content": "class Credit < ActiveRecord::Base\n\n  default_value_for :issued_on do\n    Time.now\n  end\n\n  #Constants\n  ROUNDING_LEVEL = 2 #How many digits to round down to when paying off\n\n  belongs_to :owner, :class_name => 'User', :foreign_key => 'owner_id'\n  belongs_to :project\n\n  after_create :issue_shares\n\n  def issue_day\n    self.issued_on.strftime('%D')\n  end\n\n  def disable\n    self.enabled = false\n    return self.save\n  end\n\n  def enable\n    self.enabled = true\n    return self.save\n  end\n\n  #For every credit that is issue, a corresponding share is issued\n  def issue_shares\n    Share.create! :amount => amount, :owner => owner, :project => project, :issued_on => issued_on unless previously_issued #We don't create shares if we're creating credit for a past issue date (i.e. in case of an incomplete payoff)\n  end\n\n  def previously_issued\n    (issued_on - created_at) > 2 #if created date is different than issued on date (by more than a few milliseconds) then this was a previously issued credit, that's being recreated as portion of shares already given out\n  end\n\n  def settled?\n    return !self.settled.nil?\n  end\n\n  def pay_out(pay_amount)\n    pay_amount = Credit.round(pay_amount)\n    return false if pay_amount > amount #TODO raise an error here?\n    original_amount = self.amount\n\n    #Saving current record\n    self.amount = pay_amount\n    self.settled_on = Time.now\n    self.save\n\n    #We cashed out some credits, so we set some shares to expire\n    Share.set_expiration(owner,project,pay_amount,Time.now + (Time.now - issued_on))\n\n    #Wasn't fully paid out, we need to create a new entry with the remaining unissued credit\n    if original_amount > pay_amount\n      Credit.create! :amount => Credit.round(original_amount-pay_amount), :owner => owner, :project => project, :issued_on => issued_on\n    end\n  end\n\n  def self.round(x)\n      (x * 10**ROUNDING_LEVEL).floor.to_f / 10**ROUNDING_LEVEL #rounds down\n  end\n\n  #Pays out a certain amount of credit for a certain project (e.g. payout $6000 for the website project)\n  #Owners on top of the stack are paid out first, and shares are updated accordingly\n  def self.settle(project,amount)\n    remaining_amount = amount\n\n    Credit.find(:all,:conditions => {:project_id => project, :enabled => true, :settled_on => nil}, :order => 'issued_on ASC').group_by(&:issue_day).each do |day,credits|\n      #Looping once for each day\n      day_amount = credits.inject(0) {|sum, credit| sum = sum + credit.amount}\n      if remaining_amount >= day_amount\n        credits.each {|credit| credit.pay_out(credit.amount)} #payoff full amount of each credit\n      else\n        credits.each {|credit| credit.pay_out(credit.amount * remaining_amount / day_amount)} #payoff full amount of each credit\n        break; #Stop looping through days\n      end\n      remaining_amount = remaining_amount - day_amount\n      break if remaining_amount <= 0\n    end\n\n    remaining_amount <= 0 ? 0 : remaining_amount\n  end\n\n  #transfers a certain amount of credit for a certain user for a certain project to another user (e.g. shereef gives $6000 from the website project to adele)\n  #newest credits are transfered first\n  #returns total paid\n  def self.transfer(sender,recipient,project,amount, note)\n    remaining_amount = amount\n\n    Credit.find(:all,:conditions => {:project_id => project.id, :settled_on => nil, :owner_id => sender.id}, :order => 'issued_on DESC').each do |credit|\n      #Looping once for each day\n      if remaining_amount >= credit.amount\n        credit.owner_id = recipient.id\n        credit.save\n        remaining_amount = remaining_amount - credit.amount\n      else\n        credit.amount = Credit.round(credit.amount - remaining_amount)\n        credit.save\n        Credit.create! :amount => Credit.round(remaining_amount), :owner => recipient, :project => project\n        remaining_amount = 0\n        break; #Stop looping through days\n      end\n\n      break if remaining_amount <= 0\n    end\n    total_paid = Credit.round(amount - remaining_amount)\n\n    CreditTransfer.create! :sender => sender, :recipient => recipient, :project => project, :amount => total_paid, :note => note if total_paid > 0\n\n    return total_paid\n  end\n\n\nend\n\n\n\n\n\n"
  },
  {
    "path": "app/models/credit_distribution.rb",
    "content": "class CreditDistribution < ActiveRecord::Base\n  after_create :add_credits\n  belongs_to :project\n  belongs_to :retro\n  belongs_to :user\n\n  GIFT = -1 #value in retro_id when distribution is a result of a gift, not a retrospective\n  EXPENSE = -2 #value in retro_id when distribution is a result of an expense, not a retrospective\n  HOURLY = -3 # value in retro_id when distribution is a result of an hourly, not a retrospective\n\n  def add_credits\n    Credit.create :owner_id => self.user_id, :project_id => self.project_id, :amount => self.amount\n\n    #Add as contributor\n    self.user.add_as_contributor_if_new(self.project.root)\n\n\n    admin = User.sysadmin\n    Notification.create :recipient_id => self.user_id,\n                        :variation => 'credits_distributed',\n                        :params => {:project_name => project.name, :credit_distribution => self.attributes, :enterprise_id => self.project.root.id},\n                        :sender_id => admin.id,\n                        :source_id => self.id,\n                        :source_type => \"Credit\"\n  end\nend\n"
  },
  {
    "path": "app/models/credit_transfer.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass CreditTransfer < ActiveRecord::Base\n  belongs_to :sender, :class_name => \"User\", :foreign_key => \"sender_id\"\n  belongs_to :recipient, :class_name => \"User\", :foreign_key => \"recipient_id\"\n  belongs_to :project\n\n  after_create :send_notification\n\n  def send_notification\n    Notification.create :recipient_id => self.recipient_id,\n                        :variation => 'credits_transferred',\n                        :params => {:amount => self.amount, :note => self.note, :project => self.project, :sender_name => sender.name},\n                        :sender_id => self.sender_id,\n                        :source_id => self.id,\n                        :source_type => \"CreditTransfer\"\n\n  end\nend\n"
  },
  {
    "path": "app/models/daily_digest.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass DailyDigest < ActiveRecord::Base\n  belongs_to :issue\n  belongs_to :journal\n\n  def self.deliver\n    digests_by_mail = DailyDigest.all.group_by{|digest| digest.mail}\n    digests_by_mail.each_pair do |mail,journals|\n      Mailer.send_later(:deliver_daily_digest,mail,journals)\n      DailyDigest.delete_all :mail => mail\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/document.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Document < ActiveRecord::Base\n  belongs_to :project\n  acts_as_attachable :delete_permission => :manage_documents\n\n  acts_as_searchable :columns => ['title', \"#{table_name}.description\"], :include => :project\n\n  acts_as_event :title => Proc.new {|o| \"#{l(:label_document)}: #{o.title}\"},\n                :author => Proc.new {|o| (a = o.attachments.find(:first, :order => \"#{Attachment.table_name}.created_at ASC\")) ? a.author : nil },\n                :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}\n\n  validates_presence_of :project, :title\n  validates_length_of :title, :maximum => 60\n\n  def size\n    sum = 0.0\n    attachments.each do |a|\n      sum += a.filesize\n    end\n\n    sum = sum / 1000000000\n    sum.round(3)\n  end\n\n  def visible?(user=User.current)\n    !user.nil? && user.allowed_to?(:view_documents, project)\n  end\n\n  def updated_at\n    unless @updated_at\n      a = attachments.find(:first, :order => 'created_at DESC')\n      @updated_at = (a && a.created_at) || created_at\n    end\n    @updated_at\n  end\n\n  # Returns the mail adresses of users that should be notified\n  def recipients\n    notified = project.notified_users\n    notified.reject! {|user| !visible?(user) || user.pref[:no_emails]}\n    notified.collect(&:mail)\n  end\nend\n\n\n"
  },
  {
    "path": "app/models/document_observer.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass DocumentObserver < ActiveRecord::Observer\n  def after_create(document)\n    Mailer.send_later(:deliver_document_added,document) if Setting.notified_events.include?('document_added')\n  end\nend\n"
  },
  {
    "path": "app/models/email_update.rb",
    "content": "class EmailUpdate < ActiveRecord::Base\n  belongs_to :user\n\n  def before_create\n    self.token = Token.generate_token_value\n  end\n\n  def send_activation\n    Mailer.send_later(:deliver_email_update_activation,self)\n  end\n\n  def accept\n    self.update_attribute(:activated, true)\n    self.user.update_attribute(:mail, self.mail)\n  end\n\nend\n"
  },
  {
    "path": "app/models/enabled_module.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass EnabledModule < ActiveRecord::Base\n  belongs_to :project\n\n  validates_presence_of :name\n\n  after_create :module_enabled\n\n  private\n\n  # after_create callback used to do things when a module is enabled\n  def module_enabled\n    case name\n    when 'wiki'\n      # Create a wiki with a default start page\n      if project && project.wiki.nil?\n        Wiki.create(:project => project, :start_page => 'Wiki')\n      end\n    end\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/enterprise.rb",
    "content": "class Enterprise < ActiveRecord::Base\n    has_one :root_project, :class_name => 'Project', :conditions => \"parent_id is null\"\n    has_many :projects\n    has_many :issues, :through => :projects\n    has_many :members, :through => :projects\n    has_many :users, :through => :members\n    has_many :news, :through => :projects\n\n    validates_presence_of :name\n    validates_uniqueness_of :name\n    validates_length_of :name, :maximum => 50\n    validates_length_of :homepage, :maximum => 255\n\nend\n\n"
  },
  {
    "path": "app/models/enumeration.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Enumeration < ActiveRecord::Base\n  default_scope :order => \"#{Enumeration.table_name}.position ASC\"\n\n  belongs_to :project\n\n  acts_as_list :scope => 'type = \\'#{type}\\''\n  acts_as_tree :order => 'position ASC'\n\n  before_destroy :check_integrity\n\n  validates_presence_of :name\n  validates_uniqueness_of :name, :scope => [:type, :project_id]\n  validates_length_of :name, :maximum => 30\n\n  named_scope :values, lambda {|type| { :conditions => { :type => type }, :order => 'position' } } do\n    def default\n      find(:first, :conditions => { :is_default => true })\n    end\n  end\n  # End backwards compatiblity named_scopes\n\n  named_scope :shared, :conditions => { :project_id => nil }\n  named_scope :active, :conditions => { :active => true }\n\n  def self.default\n    # Creates a fake default scope so Enumeration.default will check\n    # it's type.  STI subclasses will automatically add their own\n    # types to the finder.\n    if self.descends_from_active_record?\n      find(:first, :conditions => { :is_default => true, :type => 'Enumeration' })\n    else\n      # STI classes are\n      find(:first, :conditions => { :is_default => true })\n    end\n  end\n\n  # Overloaded on concrete classes\n  def option_name\n    nil\n  end\n\n  # Backwards compatiblity.  Can be removed post-0.9\n  def opt\n    ActiveSupport::Deprecation.warn(\"Enumeration#opt is deprecated, use the STI classes now. (#{Redmine::Info.issue(3007)})\")\n    return OptName\n  end\n\n  def before_save\n    if is_default? && is_default_changed?\n      Enumeration.update_all(\"is_default = #{connection.quoted_false}\", {:type => type})\n    end\n  end\n\n  # Overloaded on concrete classes\n  def objects_count\n    0\n  end\n\n  def in_use?\n    self.objects_count != 0\n  end\n\n  # Is this enumeration overiding a system level enumeration?\n  def is_override?\n    !self.parent.nil?\n  end\n\n  alias :destroy_without_reassign :destroy\n\n  # Destroy the enumeration\n  # If a enumeration is specified, objects are reassigned\n  def destroy(reassign_to = nil)\n    if reassign_to && reassign_to.is_a?(Enumeration)\n      self.transfer_relations(reassign_to)\n    end\n    destroy_without_reassign\n  end\n\n  def <=>(enumeration)\n    position <=> enumeration.position\n  end\n\n  def to_s; name end\n\n  # Returns the Subclasses of Enumeration.  Each Subclass needs to be\n  # required in development mode.\n  #\n  # Note: subclasses is protected in ActiveRecord\n  def self.get_subclasses\n    @@subclasses[Enumeration]\n  end\n\n  # Does the +new+ Hash override the previous Enumeration?\n  def self.overridding_change?(new, previous)\n    if (same_active_state?(new['active'], previous.active))\n      return false\n    else\n      return true\n    end\n  end\n\n\n  # Are the new and previous fields equal?\n  def self.same_active_state?(new, previous)\n    new = (new == \"1\" ? true : false)\n    return new == previous\n  end\n\n  private\n\n  def check_integrity\n    raise \"Can't delete enumeration\" if self.in_use?\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/help_section.rb",
    "content": "class HelpSection < ActiveRecord::Base\n  belongs_to :user\nend\n"
  },
  {
    "path": "app/models/hourly_type.rb",
    "content": "class HourlyType < ActiveRecord::Base\n  belongs_to :project\n  has_many :issues\n\n  validates_presence_of :name, :project, :hourly_rate_per_person, :hourly_cap\n  validates_length_of :name,        :maximum => 255\n  validates_numericality_of :hourly_rate_per_person, :hourly_cap\n\n  def validate\n    errors.add(:hourly_rate_per_person, \"should be at least 1\") if hourly_rate_per_person.nil? || hourly_rate_per_person < 1\n    errors.add(:hourly_cap, \"should be at least 1\") if hourly_cap.nil? || hourly_cap < 1\n  end\n\n  def name_with_rates\n    \"#{name} -- rate per person: #{hourly_rate_per_person}, cap: #{hourly_cap}\"\n  end\nend\n\n\n"
  },
  {
    "path": "app/models/invitation.rb",
    "content": "class Invitation < ActiveRecord::Base\n  belongs_to :project\n  belongs_to :user\n  belongs_to :role\n\n  PENDING = 0\n  ACCEPTED = 1\n\n  def before_create\n    # TODO: check for dupes?\n    self.token = Token.generate_token_value\n    # TODO: should be `self.role ||= Role.contributor`\n    self.role_id = Role.contributor.id unless self.role_id\n  end\n\n  def deliver(note=\"\")\n    return unless self.status == PENDING\n\n    Mailer.send(:deliver_invitation_add,self,note)\n\n    # add notification here\n    # TODO: don't send email, once notifications are auto-sending emails\n    recipient = User.find_by_mail(self.mail)\n\n    Notification.create :recipient_id => recipient.id,\n                              :variation => 'invitation',\n                              :params => {:role_name => self.role.name, :project_name => self.project.name, :project_id => self.project_id, :token => self.token, :note => note},\n                              :sender_id => self.user_id,\n                              :source_id => self.id,\n                              :source_type => \"Invitation\" if recipient\n\n  end\n\n  def resend(note=\"\")\n    return unless self.status == PENDING\n    Mailer.send_later(:deliver_invitation_remind,self,note)\n    return true\n  end\n\n  def status_name\n    case self.status\n      when PENDING\n        return \"Pending\"\n      when ACCEPTED\n        return \"Accepted\"\n      else\n        return \"Unkown\"\n    end\n  end\n\n  def accept(user=nil)\n    return unless self.status == PENDING\n\n    if user && !user.anonymous?\n      @user = user\n    elsif self.new_mail && !self.new_mail.empty?\n      @user = User.find_by_mail(self.new_mail)\n    else\n      @user = User.find_by_mail(self.mail)\n    end\n    return unless @user && !@user.anonymous?\n\n    if self.project.root?\n      @user.add_to_project self.project, self.role\n    else\n      @user.add_to_project self.project, Role.active\n      @user.add_to_project self.project.root, self.role\n    end\n\n    @user.add_to_project self.project, Role.clearance unless self.project.is_public?\n\n    self.new_mail = @user.mail if @user.mail\n    self.status = ACCEPTED\n    self.save!\n\n    Notification.delete_all(:variation => 'invitation', :source_id => self.id)\n  end\n\nend\n\n\n\n"
  },
  {
    "path": "app/models/issue.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Issue < ActiveRecord::Base\n\n  belongs_to :project\n  belongs_to :tracker\n  belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'\n  belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'\n  belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'\n  belongs_to :retro\n  belongs_to :hourly_type\n\n  has_many :journals, :as => :journalized, :dependent => :destroy, :order => \"#{Journal.table_name}.created_at ASC\"\n\n  has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all\n  has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all\n\n  has_many :issue_votes, :dependent => :delete_all\n  has_many :todos, :dependent => :delete_all\n\n  acts_as_attachable :after_remove => :attachment_removed\n  acts_as_watchable\n  acts_as_searchable :columns => ['subject', \"#{table_name}.description\", \"#{Journal.table_name}.notes\"],\n                     :include => [:project, :journals],\n                     # sort by id so that limited eager loading doesn't break with postgresql\n                     :order_column => \"#{table_name}.id\"\n\n  acts_as_taggable\n\n  acts_as_event :title => Proc.new {|o| \"#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}\"},\n                :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}},\n                :type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') }\n\n  # ===============\n  # = CSV support =\n  # ===============\n  comma do  # implicitly named :default\n     id\n     tracker :name\n     project :name\n     subject\n     description\n     status :name\n     assigned_to :name\n     author :name\n     points\n     pri\n     accept\n     reject\n     agree\n     disagree\n     accept_nonbind\n     reject_nonbind\n     agree_nonbind\n     disagree_nonbind\n     agree_total_nonbind\n     points_nonbind\n     pri_nonbind\n     hourly_type :name\n     num_hours\n     created_at\n     updated_at\n  end\n\n  DONE_RATIO_OPTIONS = %w(issue_field issue_status)\n\n  validates_presence_of :subject, :project, :tracker, :author, :status\n  validates_length_of :subject, :maximum => 255\n\n  named_scope :visible, lambda {|*args| { :include => :project,\n                                          :conditions => Project.allowed_to_condition(args.first || User.current, :view_issues) } }\n\n  named_scope :open, :conditions => [\"#{IssueStatus.table_name}.is_closed = ?\", false], :include => :status\n\n  named_scope :open_status, :conditions => {:status_id => 1}, :include => :status #BUGBUG: hard coded because IssueStatus.open.id breaks rake for some reason!!!\n\n  after_save :after_save\n\n  # Returns true if usr or current user is allowed to view the issue\n  def visible?(usr=nil)\n    (usr || User.current).allowed_to?(:view_issues, self.project)\n  end\n\n  # Returns true if there are enough agreements in relation to the estimated points of the request\n  def ready_for_open?\n    return false if points.nil? || agree_total < 1\n    return true if agree - disagree > points_from_credits / 2\n    return true if agree_total > 0\n    return false\n  end\n\n  # Returns true if there are enough disagreements in relation to the estimated points of the request\n  def ready_for_canceled?\n    return false if agree_total > 0\n    return true if agree_total < 0 && (updated_at < DateTime.now - Setting::LAZY_MAJORITY_LENGTH)\n    return false\n  end\n\n  def ready_for_accepted?\n    return true if self.status == IssueStatus.accepted\n    return false if points.nil? || accept_total < 1\n    return true if accept_total > 0 && (self.updated_at < DateTime.now - Setting::LAZY_MAJORITY_LENGTH)\n    return false\n  end\n\n  def ready_for_rejected?\n    return true if self.status == IssueStatus.rejected\n    return false if points.nil? || accept_total > -1\n    return true if accept_total < 0 && (updated_at < DateTime.now - Setting::LAZY_MAJORITY_LENGTH) #rejected\n    return false\n  end\n\n  def is_gift?\n    tracker.gift?\n  end\n\n  def is_expense?\n    tracker.expense?\n  end\n\n  def is_hourly?\n    tracker.hourly?\n  end\n\n  def is_feature\n    tracker.feature?\n  end\n\n  def is_bug\n    tracker.bug?\n  end\n\n  def is_chore\n    tracker.chore?\n  end\n\n  def updated_status\n    return IssueStatus.canceled if self.status == IssueStatus.canceled\n    return IssueStatus.accepted if ready_for_accepted?\n    return IssueStatus.rejected if ready_for_rejected?\n    return IssueStatus.done if self.status == IssueStatus.done || (ready_for_open? && is_gift?)\n    return IssueStatus.inprogress if self.status == IssueStatus.inprogress\n    return IssueStatus.open if ready_for_open?\n    return IssueStatus.canceled if ready_for_canceled?\n    return IssueStatus.newstatus #default\n  end\n\n  def after_initialize\n    if new_record?\n      # set default values for new records only\n      self.status ||= IssueStatus.default\n    end\n  end\n\n  # Returns true if one or more people joined this issue\n  def has_team?\n    team_votes.length>1\n  end\n\n  def has_todos?\n    todos.length>0\n  end\n\n  def team_votes\n    issue_votes.select {|i| i.vote_type == IssueVote::JOIN_VOTE_TYPE}\n  end\n\n  def team_members\n    IssueVote.find(:all, :conditions => [\"issue_id=? AND vote_type=?\",\n                                                   self.id, IssueVote::JOIN_VOTE_TYPE], :order => \"updated_at ASC\").map(&:user)\n  end\n\n  def copy_from(arg)\n    issue = arg.is_a?(Issue) ? arg : Issue.find(arg)\n    self.attributes = issue.attributes.dup.except(\"id\", \"created_at\", \"updated_at\")\n    self.status = issue.status\n    self\n  end\n\n  #returns true if issue can be started (in the correct priority tier)\n  def startable?\n    return false unless self.status_id == IssueStatus.open.id\n    self.pri > project.issues.open_status.maximum(\"pri\") - Setting::NUMBER_OF_STARTABLE_PRIORITY_TIERS || points_from_credits == 0\n  end\n\n\n  #Creates a new issue and sets its status to open\n  #Copies all issue votes except team ones and accept/reject ones\n  def clone_recurring\n    @new_issue = Issue.new\n    @new_issue.attributes = self.attributes.dup.except(\"id\", \"created_at\", \"updated_at\")\n    @new_issue.status = IssueStatus.open\n    @new_issue.save\n    self.issue_votes.each do |iv|\n      next if iv.vote_type == IssueVote::JOIN_VOTE_TYPE || iv.vote_type == IssueVote::ACCEPT_VOTE_TYPE\n      @new_iv = IssueVote.new\n      @new_iv.attributes = iv.attributes.dup.except(\"id\", \"issue_id\")\n      @new_iv.issue_id = @new_issue.id\n      @new_iv.save\n    end\n  end\n\n  # Moves/copies an issue to a new project and tracker\n  # Returns the moved/copied issue on success, false on failure\n  def move_to(new_project, new_tracker = nil, options = {})\n    options ||= {}\n    issue = options[:copy] ? self.clone : self\n    transaction do\n      if new_project && issue.project_id != new_project.id\n        # delete issue relations\n        unless Setting.cross_project_issue_relations?\n          issue.relations_from.clear\n          issue.relations_to.clear\n        end\n        issue.project = new_project\n      end\n      if new_tracker\n        issue.tracker = new_tracker\n      end\n      if options[:copy]\n        issue.status = if options[:attributes] && options[:attributes][:status_id]\n                         IssueStatus.find_by_id(options[:attributes][:status_id])\n                       else\n                         self.status\n                       end\n      end\n      # Allow bulk setting of attributes on the issue\n      if options[:attributes]\n        issue.attributes = options[:attributes]\n      end\n      if !issue.save\n        Issue.connection.rollback_db_transaction\n        return false\n      end\n    end\n    return issue\n  end\n\n  def tracker_id=(tid)\n    self.tracker = nil\n    write_attribute(:tracker_id, tid)\n    result = write_attribute(:tracker_id, tid)\n    result\n  end\n\n  def mention(mentioner_id, mentioned_id, mention_text)\n    Notification.create :recipient_id => mentioned_id,\n                        :variation => 'mention',\n                        :params => {:mention_text => self.description,\n                                    :url => {:controller => \"issues\", :action => \"show\", :id => self.id},\n                                    :title => self.subject},\n                        :sender_id => mentioner_id,\n                        :source_id => self.id,\n                        :source_type => \"Issue\"\n  end\n\n  def update_tags(tags)\n    self.update_attribute(:tag_list, tags)\n    self.update_attribute(:tags_copy, self.tags.map {|t|t.name}.join(\",\"))\n    update_last_item_stamp\n  end\n\n  # Overrides attributes= so that tracker_id gets assigned first\n  def attributes_with_tracker_first=(new_attributes, *args)\n    return if new_attributes.nil?\n    new_tracker_id = new_attributes['tracker_id'] || new_attributes[:tracker_id]\n    if new_tracker_id\n      self.tracker_id = new_tracker_id\n    end\n    self.attributes_without_tracker_first = new_attributes, *args\n  end\n  alias_method_chain :attributes=, :tracker_first\n\n  def estimated_hours=(h)\n    write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)\n  end\n\n\n  def validate\n  end\n\n  def init_journal(user, notes = \"\")\n    @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes)\n    @issue_before_change = self.clone\n    @issue_before_change.status = self.status\n\n    # Make sure updated_at is updated when adding a note.\n    updated_at_will_change!\n    @current_journal\n\n  end\n\n  # Return true if the issue is closed, otherwise false\n  def closed?\n    self.status.is_closed?\n  end\n\n  # Return true if the issue is being reopened\n  def reopened?\n    if !new_record? && status_id_changed?\n      status_was = IssueStatus.find_by_id(status_id_was)\n      status_new = IssueStatus.find_by_id(status_id)\n      if status_was && status_new && status_was.is_closed? && !status_new.is_closed?\n        return true\n      end\n    end\n    false\n  end\n\n  def editable?\n    return !(status == IssueStatus.assigned   ||\n             status == IssueStatus.done       ||\n             status == IssueStatus.canceled   ||\n             status == IssueStatus.archived)\n\n\n  end\n\n  # Returns true if the issue is overdue\n  def overdue?\n    !due_date.nil? && (due_date < DateTime.now) && !status.is_closed?\n  end\n\n  # Users the issue can be assigned to\n  def assignable_users\n    project.assignable_users\n  end\n\n  # Returns true if this issue is blocked by another issue that is still open\n  def blocked?\n    !relations_to.detect {|ir| ir.relation_type == 'blocks' && !ir.issue_from.closed?}.nil?\n  end\n\n  # Returns an array of status that user is able to apply\n  def new_statuses_allowed_to(user)\n    logger.info { \"New statuses allowed\" }\n    statuses = status.find_new_statuses_allowed_to(user.roles_for_project(project), tracker)\n    statuses << status unless statuses.empty?\n    statuses = statuses.uniq.sort\n    blocked? ? statuses.reject {|s| s.is_closed?} : statuses\n  end\n\n  # Returns the mail adresses of users that should be notified\n  def recipients\n    notified = project.notified_users\n    # Author and assignee are always notified unless they have been locked\n    notified << author if author && author.active?\n    notified << assigned_to if assigned_to && assigned_to.active? unless self.tracker.gift?\n    notified += team_members\n    notified += journals.collect {|j| j.user}\n    notified.uniq!\n    # Remove users that can not view the issue\n    notified.reject! {|user| !visible?(user) || user.pref[:no_emails]}\n\n    notified.delete User.sysadmin\n    notified.collect(&:mail)\n  end\n\n  def relations\n    (relations_from + relations_to).sort\n  end\n\n  def all_dependent_issues\n    dependencies = []\n    relations_from.each do |relation|\n      dependencies << relation.issue_to\n      dependencies += relation.issue_to.all_dependent_issues\n    end\n    dependencies\n  end\n\n  # Returns an array of issues that duplicate this one\n  def duplicates\n    relations_to.select {|r| r.relation_type == IssueRelation::TYPE_DUPLICATES}.collect {|r| r.issue_from}\n  end\n\n  # Returns the due date or the target due date if any\n  # Used on gantt chart\n  def due_before\n    due_date\n  end\n\n  # Returns the time scheduled for this issue.\n  #\n  # Example:\n  #   Start Date: 2/26/09, End Date: 3/04/09\n  #   duration => 6\n  def duration\n    (start_date && due_date) ? due_date - start_date : 0\n  end\n\n  def soonest_start\n    @soonest_start ||= relations_to.collect{|relation| relation.successor_soonest_start}.compact.min\n  end\n\n  def to_s\n    \"#{tracker} ##{id}: #{subject}\"\n  end\n\n  # Returns a string of css classes that apply to the issue\n  def css_classes\n    s = \"issue status-#{status.position}\"\n    s << ' closed' if closed?\n    s << ' overdue' if overdue?\n    s << ' created-by-me' if User.current.logged? && author_id == User.current.id\n    s << ' assigned-to-me' if User.current.logged? && assigned_to_id == User.current.id\n    s\n  end\n\n\n  #returns true if this user is allowed to take (and/or offer) ownership for this particular issue\n  def push_allowed?(user)\n    return false if user.nil?\n    return true if self.assigned_to == user #Any user who owns an issue can offer for people to take it, or can accept offers\n\n    #True if user has push commitment, AND expected date has passed or doesn't exist AND it's assigned to nobody or assigned to same user\n    user.allowed_to?(:push_commitment, self.project) && (self.expected_date.nil? || self.expected_date < Time.new.to_date) && (self.assigned_to.nil? || self.assigned_to == user)\n  end\n\n  def update_estimate_total(binding)\n    if binding\n      self.points =   IssueVote.average(:points, :conditions => \" issue_id = #{self.id} AND  vote_type = #{IssueVote::ESTIMATE_VOTE_TYPE} AND isbinding= true AND points != -1\")\n    else\n      self.points_nonbind =   IssueVote.average(:points, :conditions => \" issue_id = #{self.id} AND  vote_type = #{IssueVote::ESTIMATE_VOTE_TYPE} AND isbinding= false AND points != -1\")\n    end\n  end\n\n  def update_pri_total(binding)\n    if binding\n      self.pri = IssueVote.sum(:points, :conditions => {:issue_id => self.id, :vote_type => IssueVote::PRI_VOTE_TYPE, :isbinding=> true})\n    else\n      self.pri_nonbind = IssueVote.sum(:points, :conditions => {:issue_id => self.id, :vote_type => IssueVote::PRI_VOTE_TYPE, :isbinding=> false})\n    end\n  end\n\n  def update_agree_total(binding)\n    if binding\n      self.agree =   IssueVote.count(:conditions => {:issue_id => self.id, :vote_type => IssueVote::AGREE_VOTE_TYPE, :points => 1, :isbinding=> true})\n      self.disagree =   IssueVote.sum(:points, :conditions => \"issue_id = '#{self.id}' AND vote_type = '#{IssueVote::AGREE_VOTE_TYPE}' AND points < 0 AND isbinding='true'\") * -1\n      self.agree_total = self.agree - self.disagree\n    else\n      self.agree_nonbind =   IssueVote.count(:conditions => {:issue_id => self.id, :vote_type => IssueVote::AGREE_VOTE_TYPE, :points => 1, :isbinding=> false})\n      self.disagree_nonbind =   IssueVote.sum(:points, :conditions => \"issue_id = '#{self.id}' AND vote_type = '#{IssueVote::AGREE_VOTE_TYPE}' AND points < 0 AND isbinding='false'\") * -1\n      self.agree_total_nonbind = self.agree_nonbind - self.disagree_nonbind\n    end\n  end\n\n  def update_accept_total(binding)\n    if binding\n      self.accept =   IssueVote.count(:conditions => {:issue_id => self.id, :vote_type => IssueVote::ACCEPT_VOTE_TYPE, :points => 1, :isbinding=> true})\n      self.reject =   IssueVote.sum(:points, :conditions => \"issue_id = '#{self.id}' AND vote_type = '#{IssueVote::ACCEPT_VOTE_TYPE}' AND points < 0 AND isbinding='true'\") * -1\n      self.accept_total = self.accept - self.reject\n    else\n      self.accept_nonbind =   IssueVote.count(:conditions => {:issue_id => self.id, :vote_type => IssueVote::ACCEPT_VOTE_TYPE, :points => 1, :isbinding=> false})\n      self.reject_nonbind =   IssueVote.sum(:points, :conditions => \"issue_id = '#{self.id}' AND vote_type = '#{IssueVote::ACCEPT_VOTE_TYPE}' AND points < 0 AND isbinding='false'\") * -1\n      self.accept_total_nonbind = self.accept_nonbind - self.reject_nonbind\n    end\n  end\n\n  #refreshes issue status, returns true if status changed\n  def update_status\n    original = self.status\n    @updated = self.updated_status\n\n    if (original.id != @updated.id)\n      admin = User.find(:first,:conditions => {:login => \"admin\"})\n      journal = self.init_journal(admin)\n      self.status = @updated\n      self.retro_id = nil\n\n      LogActivityStreams.write_single_activity_stream(User.sysadmin,:name,self,:subject,:changed,\"update_to_#{@updated.name}\", 0, @updated,{\n                :indirect_object_name_method => :name,\n                :indirect_object_phrase => \"From <strong>#{original.name}</strong> to <strong>#{@updated.name}</strong> \" })\n\n\n      if self.status == IssueStatus.accepted\n        self.assigned_to.add_as_contributor_if_new(self.project) unless self.assigned_to.nil?\n        if self.is_gift?\n          self.retro_id = Retro::NOT_NEEDED_ID\n          self.give_credits\n        elsif self.is_expense?\n          self.retro_id = Retro::NOT_NEEDED_ID\n          self.give_credits\n        elsif self.is_hourly?\n          self.retro_id = Retro::GIVEN_BUT_NOT_PART_OF_RETRO\n          self.give_credits\n        else #if a non-gift/expense/hourly is accepted, set retro id to not started to prep for next retrospective\n          if self.project.credits_enabled?\n            self.retro_id = Retro::NOT_STARTED_ID\n            self.project.start_retro_if_ready\n          else\n            self.retro_id = Retro::NOT_ENABLED_ID #credits not enabled, we don't care\n          end\n        end\n      end\n\n      self.save\n      return true\n    else\n      return false\n    end\n  end\n\n  # sets number of points for an hourly item\n  def set_points_from_hourly\n    return unless self.is_hourly?\n\n    if (hourly_type.hourly_rate_per_person * self.team_members.length) > hourly_type.hourly_cap\n      self.points = hourly_type.hourly_cap * self.num_hours\n    else\n      self.points = self.num_hours * self.team_members.length * hourly_type.hourly_rate_per_person\n    end\n  end\n\n  # issues credits for this one issue to the people it's assigned to\n  def give_credits\n    if self.is_gift?\n      CreditDistribution.create(:user_id => self.assigned_to_id,\n                                :project_id => self.project_id,\n                                :retro_id => CreditDistribution::GIFT,\n                                :amount => self.points) unless self.points == 0 || self.points.nil?\n    elsif self.is_expense?\n      CreditDistribution.create(:user_id => self.assigned_to_id,\n                                :project_id => self.project_id,\n                                :retro_id => CreditDistribution::EXPENSE,\n                                :amount => self.points) unless self.points == 0 || self.points.nil?\n    elsif self.is_hourly?\n      credits_per_person_per_hour = 0\n\n      if (hourly_type.hourly_rate_per_person * self.team_members.length) > hourly_type.hourly_cap\n        credits_per_person_per_hour = hourly_type.hourly_cap / self.team_members.length\n      else\n        credits_per_person_per_hour = hourly_type.hourly_rate_per_person\n      end\n\n      credits_per_person = credits_per_person_per_hour * self.num_hours\n\n      self.team_members.each do |member|\n        CreditDistribution.create(:user_id => member.id,\n                                  :project_id => self.project_id,\n                                  :retro_id => CreditDistribution::HOURLY,\n                                  :amount => credits_per_person) unless credits_per_person == 0 || self.points.nil?\n      end\n    end\n  end\n\n  #returns json object for consumption from dashboard\n  def to_dashboard\n    self.to_json(:include => {:journals => { :only => [:id, :notes, :created_at, :user_id], :include => {:user => { :only => [:firstname, :lastname, :login] }}},\n                              :issue_votes => { :include => {:user => { :only => [:firstname, :lastname, :login] }}},\n                              :status => {:only => :name},\n                              :attachments => { :only => [:id, :filename]},\n                              :todos => {:only => [:id, :subject, :completed_on, :owner_login]},\n                              :tracker => {:only => [:name,:id]},\n                              :author => {:only => [:firstname, :lastname, :login, :mail_hash]},\n                              :assigned_to => { :only => [:firstname, :lastname, :login] }\n                              },\n                              :except => :tags)\n  end\n\n  #returns dollar amount based on points for this issue\n  def dollar_amount\n    return self.points\n  end\n\n  #returns number of \"points\" based on scale. used to calculate votes needed in lazy majority\n  def points_from_credits\n    normalized = (points/self.project.dpp).round\n    return Setting::CREDITS_TO_POINTS[Setting::CREDITS_TO_POINTS.length - 1] if normalized > Setting::CREDITS_TO_POINTS.length #returns max if credits are more than max\n    return Setting::CREDITS_TO_POINTS[normalized];\n  end\n\n  def size\n    sum = 0.0\n    attachments.each do |a|\n      sum += a.filesize\n    end\n\n    sum = sum / 1000000000\n    sum.round(3)\n  end\n\n  def after_create\n    self.project.send_later :refresh_issue_count\n  end\n\n  def update_last_item_stamp\n    self.project.send_later(\"update_last_item\")\n  end\n\n  private\n\n  # Callback on attachment deletion\n  def attachment_removed(obj)\n    journal = init_journal(User.current)\n    journal.details << JournalDetail.new(:property => 'attachment',\n                                         :prop_key => obj.id,\n                                         :old_value => obj.filename)\n    journal.save\n  end\n\n  def after_save\n    # Reload is needed in order to get the right status\n    reload\n\n    # Update start/due dates of following issues\n    relations_from.each(&:set_issue_to_dates)\n\n    # Close duplicates if the issue was closed\n    if @issue_before_change && !@issue_before_change.closed? && self.closed?\n      duplicates.each do |duplicate|\n        # Reload is need in case the duplicate was updated by a previous duplicate\n        duplicate.reload\n        # Don't re-close it if it's already closed\n        next if duplicate.closed?\n        # Same user and notes\n        duplicate.init_journal(@current_journal.user, @current_journal.notes)\n        duplicate.update_attribute :status, IssueStatus.archived\n      end\n    end\n\n    update_last_item_stamp #TODO: should be before save!\n    create_journal\n  end\n\n  # Saves the changes in a Journal\n  # Called after_save\n  def create_journal\n    if @current_journal\n\n      logger.info { \"creating journal...\" }\n      # attributes changes\n      (Issue.column_names - %w(id lock_version created_at updated_at pri accept reject accept_total agree disagree agree_total retro_id accept_nonbind reject_nonbind accept_total_nonbind agree_nonbind disagree_nonbind agree_total_nonbind points_nonbind pri_nonbind tags)).each {|c|\n        @current_journal.details << JournalDetail.new(:property => 'attr',\n                                                      :prop_key => c,\n                                                      :old_value => @issue_before_change.send(c),\n                                                      :value => send(c)) unless send(c)==@issue_before_change.send(c)\n      }\n      @current_journal.save\n    end\n  end\n\nend\n"
  },
  {
    "path": "app/models/issue_observer.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass IssueObserver < ActiveRecord::Observer\n  def after_create(issue)\n    Mailer.send_later(:deliver_issue_add,issue) if Setting.notified_events.include?('issue_added')\n  end\nend\n"
  },
  {
    "path": "app/models/issue_relation.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass IssueRelation < ActiveRecord::Base\n  belongs_to :issue_from, :class_name => 'Issue', :foreign_key => 'issue_from_id'\n  belongs_to :issue_to, :class_name => 'Issue', :foreign_key => 'issue_to_id'\n\n  TYPE_RELATES      = \"relates\"\n  TYPE_DUPLICATES   = \"duplicates\"\n  TYPE_BLOCKS       = \"blocks\"\n  TYPE_PRECEDES     = \"precedes\"\n  TYPE_FOLLOWS      = \"follows\"\n\n  TYPES = { TYPE_RELATES =>     { :name => :label_relates_to, :sym_name => :label_relates_to, :order => 1 },\n            TYPE_DUPLICATES =>  { :name => :label_duplicates, :sym_name => :label_duplicated_by, :order => 2 },\n            TYPE_BLOCKS =>      { :name => :label_blocks, :sym_name => :label_blocked_by, :order => 3 },\n            TYPE_PRECEDES =>    { :name => :label_precedes, :sym_name => :label_follows, :order => 4 },\n            TYPE_FOLLOWS =>     { :name => :label_follows, :sym_name => :label_precedes, :order => 5 }\n          }.freeze\n\n  validates_presence_of :issue_from, :issue_to, :relation_type\n  validates_inclusion_of :relation_type, :in => TYPES.keys\n  validates_numericality_of :delay, :allow_nil => true\n  validates_uniqueness_of :issue_to_id, :scope => :issue_from_id\n\n  attr_protected :issue_from_id, :issue_to_id\n\n  def validate\n    if issue_from && issue_to\n      errors.add :issue_to_id, :invalid if issue_from_id == issue_to_id\n      errors.add :issue_to_id, :not_same_project unless issue_from.project_id == issue_to.project_id || Setting.cross_project_issue_relations?\n      errors.add_to_base :circular_dependency if issue_to.all_dependent_issues.include? issue_from\n    end\n  end\n\n  def other_issue(issue)\n    (self.issue_from_id == issue.id) ? issue_to : issue_from\n  end\n\n  def label_for(issue)\n    TYPES[relation_type] ? TYPES[relation_type][(self.issue_from_id == issue.id) ? :name : :sym_name] : :unknow\n  end\n\n  def before_save\n    reverse_if_needed\n\n    if TYPE_PRECEDES == relation_type\n      self.delay ||= 0\n    else\n      self.delay = nil\n    end\n    set_issue_to_dates\n  end\n\n  def set_issue_to_dates\n    soonest_start = self.successor_soonest_start\n    if soonest_start && (!issue_to.start_date || issue_to.start_date < soonest_start)\n      issue_to.start_date, issue_to.due_date = successor_soonest_start, successor_soonest_start + issue_to.duration\n      issue_to.save\n    end\n  end\n\n  def successor_soonest_start\n    return nil unless (TYPE_PRECEDES == self.relation_type) && (issue_from.start_date || issue_from.due_date)\n    (issue_from.due_date || issue_from.start_date) + 1 + delay\n  end\n\n  def <=>(relation)\n    TYPES[self.relation_type][:order] <=> TYPES[relation.relation_type][:order]\n  end\n\n  private\n\n  def reverse_if_needed\n    if (TYPE_FOLLOWS == relation_type)\n      issue_tmp = issue_to\n      self.issue_to = issue_from\n      self.issue_from = issue_tmp\n      self.relation_type = TYPE_PRECEDES\n    end\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/issue_status.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass IssueStatus < ActiveRecord::Base\n  before_destroy :check_integrity\n  has_many :workflows, :foreign_key => \"old_status_id\", :dependent => :delete_all\n  acts_as_list\n\n  validates_presence_of :name\n  validates_uniqueness_of :name\n  validates_length_of :name, :maximum => 30\n  validates_format_of :name, :with => /^[\\w\\s\\'\\-]*$/i\n\n  def after_save\n    IssueStatus.update_all(\"is_default=#{connection.quoted_false}\", ['id <> ?', id]) if self.is_default?\n  end\n\n  # Returns the default status for new issues\n  def self.default\n    find(:first, :conditions =>[\"is_default=?\", true])\n  end\n\n  def self.assigned\n    @@assigned_status ||= find(:first, :conditions =>[\"name=?\", l(:default_issue_status_assigned)])\n  end\n\n  def self.done\n    @@done_status ||= find(:first, :conditions =>[\"name=?\", l(:default_issue_status_done)])\n  end\n\n  def self.inprogress\n    @@inprogress_status ||= find(:first, :conditions =>[\"name=?\", l(:default_issue_status_inprogress)])\n  end\n\n  def self.newstatus\n    @@newstatus_status ||= find(:first, :conditions =>[\"name=?\", l(:default_issue_status_new)])\n  end\n\n  def self.open\n    @@open_status ||= find(:first, :conditions =>[\"name=?\", l(:default_issue_status_open)])\n  end\n\n  def self.canceled\n    @@canceled_status ||= find(:first, :conditions =>[\"name=?\", l(:default_issue_status_canceled)])\n  end\n\n  def self.estimate\n    @@estimate_status ||= find(:first, :conditions =>[\"name=?\", l(:default_issue_status_estimate)])\n  end\n\n  def self.accepted\n    find(:first, :conditions =>[\"name=?\", l(:default_issue_status_accepted)])\n  end\n\n  def self.rejected\n    find(:first, :conditions =>[\"name=?\", l(:default_issue_status_rejected)])\n  end\n\n  def self.archived\n    @@archived_status ||= find(:first, :conditions =>[\"name=?\", l(:default_issue_status_archived)])\n  end\n\n\n\n  # Returns an array of all statuses the given role can switch to\n  # Uses association cache when called more than one time\n  def new_statuses_allowed_to(roles, tracker)\n    if roles && tracker\n      role_ids = roles.collect(&:id)\n      new_statuses = workflows.select {|w| role_ids.include?(w.role_id) && w.tracker_id == tracker.id}.collect{|w| w.new_status}.compact.sort\n    else\n      []\n    end\n  end\n\n  # Same thing as above but uses a database query\n  # More efficient than the previous method if called just once\n  def find_new_statuses_allowed_to(roles, tracker)\n    if roles && tracker\n      workflows.find(:all,\n                     :include => :new_status,\n                     :conditions => { :role_id => roles.collect(&:id),\n                                      :tracker_id => tracker.id}).collect{ |w| w.new_status }.compact.sort\n    else\n      []\n    end\n  end\n\n  def new_status_allowed_to?(status, roles, tracker)\n    if status && roles && tracker\n      !workflows.find(:first, :conditions => {:new_status_id => status.id, :role_id => roles.collect(&:id), :tracker_id => tracker.id}).nil?\n    else\n      false\n    end\n  end\n\n  def <=>(status)\n    position <=> status.position\n  end\n\n  def to_s; name end\n\n  private\n\n  def check_integrity\n    raise \"Can't delete status\" if Issue.find(:first, :conditions => [\"status_id=?\", self.id])\n  end\n\nend\n\n\n"
  },
  {
    "path": "app/models/issue_vote.rb",
    "content": "class IssueVote < ActiveRecord::Base\n  belongs_to :user\n  belongs_to :issue\n  before_create :remove_similar\n  before_save :set_binding\n\n  AGREE_VOTE_TYPE = 1\n  ACCEPT_VOTE_TYPE = 2\n  PRI_VOTE_TYPE = 3\n  ESTIMATE_VOTE_TYPE = 4\n  JOIN_VOTE_TYPE = 5 # Not exactly a vote, but used to join the team that's working on an issue\n\n  def project\n    issue.project\n  end\n\n  def update_issue_totals\n    case vote_type\n      when AGREE_VOTE_TYPE\n        issue.update_agree_total self.isbinding\n      when ACCEPT_VOTE_TYPE\n        issue.update_accept_total self.isbinding\n      when PRI_VOTE_TYPE\n        issue.update_pri_total self.isbinding\n      when ESTIMATE_VOTE_TYPE\n        issue.update_estimate_total self.isbinding\n      end\n  end\n\n  def remove_similar\n    deleted = IssueVote.delete_all(:issue_id => issue_id, :user_id => user_id, :vote_type => vote_type)\n\n    #log activity for estimate change\n    if deleted > 0 && vote_type == ESTIMATE_VOTE_TYPE\n      self.issue.save\n      LogActivityStreams.write_single_activity_stream(self.user,:name,self.issue,:subject,\"changed their estimate for\",:issues, 0, nil,{})\n    end\n  end\n\n  def set_binding\n    result = User.find(self.user_id).binding_voter_of?(self.issue.project)\n    self.isbinding = result\n    return true\n  end\n\nend\n\n\n\n\n"
  },
  {
    "path": "app/models/journal.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Journal < ActiveRecord::Base\n\n  belongs_to :journalized, :polymorphic => true\n  # added as a quick fix to allow eager loading of the polymorphic association\n  # since always associated to an issue, for now\n  belongs_to :issue, :foreign_key => :journalized_id\n\n  belongs_to :user\n  has_many :details, :class_name => \"JournalDetail\", :dependent => :delete_all\n  attr_accessor :indice\n\n  after_save :update_issue_timestamp, :send_mentions, :parse_relations\n\n  def update_issue_timestamp\n    issue.updated_at = DateTime.now\n    issue.save\n  end\n\n  def send_mentions\n    Mention.parse(self, self.user_id)\n  end\n\n  def mention(mentioner_id, mentioned_id, mention_text)\n    Notification.create :recipient_id => mentioned_id,\n                        :variation => 'mention',\n                        :params => {:mention_text => self.notes,\n                                    :url => {:controller => self.journalized_type.to_s.pluralize.downcase, :action => \"show\", :id => self.journalized_id},\n                                    :title => self.issue.subject},\n                        :sender_id => mentioner_id,\n                        :source_id => self.id,\n                        :source_type => \"Journal(#{self.journalized_type})\"\n  end\n\n  def parse_relations\n    self.send_later(:parse_relations_delayed)\n  end\n\n  def issue_id\n    self.journalized_id\n  end\n\n  #parses issue ids in body of journal, and adds related issues\n  def parse_relations_delayed\n    text = self.notes\n    return if text.nil?\n\n    text = text.gsub(%r{([\\s\\(,\\-\\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\\d+)|(@)([a-zA-Z0-9._@]+)|(:)([^\"\\s<>][^\\s<>]*?|\"[^\"]+?\"))(?=(?=[[:punct:]]\\W)|,|\\s|<|$)}) do |m|\n      leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8\n      link = nil\n      if esc.nil?\n        if sep == '#'\n          @relation = IssueRelation.new\n          @relation.issue_from_id = self.journalized_id\n          @relation.issue_to_id = oid\n          @relation.relation_type = IssueRelation::TYPE_RELATES\n          @relation.save\n        end\n      end\n    end\n  end\n\n  def save(*args)\n    # Do not save an empty journal\n    (details.empty? && notes.blank?) ? false : super\n  end\n\n  # Returns the new status if the journal contains a status change, otherwise nil\n  def new_status\n    c = details.detect {|detail| detail.prop_key == 'status_id'}\n    (c && c.value) ? IssueStatus.find_by_id(c.value.to_i) : nil\n  end\n\n  def new_value_for(prop)\n    c = details.detect {|detail| detail.prop_key == prop}\n    c ? c.value : nil\n  end\n\n  def editable_by?(usr)\n    usr && usr.logged? && (usr.allowed_to?(:edit_issue_notes, project) || (self.user == usr && usr.allowed_to?(:edit_own_issue_notes, project)))\n  end\n\n  def project\n    journalized.respond_to?(:project) ? journalized.project : nil\n  end\n\n  def attachments\n    journalized.respond_to?(:attachments) ? journalized.attachments : nil\n  end\nend\n\n"
  },
  {
    "path": "app/models/journal_detail.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass JournalDetail < ActiveRecord::Base\n  belongs_to :journal\n\n  def before_save\n    self.value = value[0..254] if value && value.is_a?(String)\n    self.old_value = old_value[0..254] if old_value && old_value.is_a?(String)\n  end\nend\n\n"
  },
  {
    "path": "app/models/journal_observer.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass JournalObserver < ActiveRecord::Observer\n  def after_create(journal)\n    if journal.user == User.sysadmin #send system events to a daily digest\n      all_recipients = journal.issue.recipients + (journal.issue.watcher_recipients - journal.issue.recipients)\n      all_recipients.each do |rec|\n        DailyDigest.create :mail => rec, :journal_id => journal.id, :issue_id => journal.issue.id\n      end\n    else\n      Mailer.send_later(:deliver_issue_edit,journal) if Setting.notified_events.include?('issue_updated')\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/mail.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Mail < ActiveRecord::Base\n\n  is_private_message\n\n  # The :to accessor is used by the scaffolding,\n  # uncomment it if using it or you can remove it if not\n  attr_accessor :to\n\nend\n"
  },
  {
    "path": "app/models/mail_handler.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass MailHandler < ActiveRecord::Base\n  include ActionView::Helpers\n\n  class UnauthorizedAction < StandardError; end\n  class MissingInformation < StandardError; end\n\n  attr_reader :email, :user\n\n  # BUGBUG: this initialize won't work consistently\n  # when extending from ActiveRecord initialize doesn't always get called\n  # http://blog.dalethatcher.com/2008/03/rails-dont-override-initialize-on.html\n  # better to make this an after_initialize\n  def initialize(email, user,options = {})\n    logger.info { \"initializing mail handler\" } if logger\n    @@handler_options = options.dup\n\n    @@handler_options[:issue] ||= {}\n\n    @@handler_options[:allow_override] = @@handler_options[:allow_override].split(',').collect(&:strip) if @@handler_options[:allow_override].is_a?(String)\n    @@handler_options[:allow_override] ||= []\n    # Project needs to be overridable if not specified\n    @@handler_options[:allow_override] << 'project' unless @@handler_options[:issue].has_key?(:project)\n    # Status overridable by default\n    @@handler_options[:allow_override] << 'status' unless @@handler_options[:issue].has_key?(:status)\n\n    @@handler_options[:no_permission_check] = (@@handler_options[:no_permission_check].to_s == '1' ? true : false)\n    @user = user\n    @email = email\n    dispatch\n  end\n\n  def self.receive(email, options={})\n    @@handler_options = options.dup\n\n    @@handler_options[:issue] ||= {}\n\n    @@handler_options[:allow_override] = @@handler_options[:allow_override].split(',').collect(&:strip) if @@handler_options[:allow_override].is_a?(String)\n    @@handler_options[:allow_override] ||= []\n    # Project needs to be overridable if not specified\n    @@handler_options[:allow_override] << 'project' unless @@handler_options[:issue].has_key?(:project)\n    # Status overridable by default\n    @@handler_options[:allow_override] << 'status' unless @@handler_options[:issue].has_key?(:status)\n\n    @@handler_options[:no_permission_check] = (@@handler_options[:no_permission_check].to_s == '1' ? true : false)\n    super email\n  end\n\n  # Processes incoming emails\n  # Returns the created object (eg. an issue, a message) or false\n  def receive(email)\n    @email = email\n    sender_email = email.from.to_a.first.to_s.strip\n    # Ignore emails received from the application emission address to avoid hell cycles\n    if sender_email.downcase == Setting.mail_from.to_s.strip.downcase\n      return false\n    end\n    @user = User.find_by_mail(sender_email)\n    if @user && !@user.active?\n      return false\n    end\n    if @user.nil?\n      # Email was submitted by an unknown user\n      case @@handler_options[:unknown_user]\n      when 'accept'\n        @user = User.anonymous\n      when 'create'\n        @user = MailHandler.create_user_from_email(email)\n        if @user\n          Mailer.deliver_account_information(@user, @user.password)\n        else\n          logger.error \"MailHandler: could not create account for [#{sender_email}]\" if logger && logger.error\n          return false\n        end\n      else\n        # Default behaviour, emails from unknown users are ignored\n        return false\n      end\n    end\n    User.current = @user\n    dispatch\n  end\n\n  # Processes incoming emails\n  # Returns the created object (eg. an issue, a message) or false\n  def self.receive_from_api(email,options ={})\n    logger.info { \"recieving from api\" } if logger\n    @@handler_options = options.dup\n\n    @email = email\n\n    logger.info { \"1\" } if logger\n\n    sender_email = email.from.to_a.first.to_s.strip\n    # Ignore emails received from the application emission address to avoid hell cycles\n    if sender_email.downcase == Setting.mail_from.to_s.strip.downcase\n      return false\n    end\n\n    logger.info { \"2\" } if logger\n\n    @user = User.find_by_mail(sender_email)\n    if @user && !@user.active?\n      return false\n    end\n\n    logger.info { \"3\" } if logger\n\n    if @user.nil?\n      # Email was submitted by an unknown user\n      case @@handler_options[:unknown_user]\n      when 'accept'\n        @user = User.anonymous\n      when 'create'\n        @user = MailHandler.create_user_from_email(email)\n        if @user\n          Mailer.deliver_account_information(@user, @user.password)\n        else\n          return false\n        end\n      else\n        # Default behaviour, emails from unknown users are ignored\n        return false\n      end\n    end\n    logger.info { \"4\" } if logger\n\n    mailhandler = MailHandler.new(email, @user)\n  end\n\n  private\n\n  MESSAGE_ID_RE = %r{^<redmine\\.([a-z0-9_]+)\\-(\\d+)\\.\\d+@}\n  ISSUE_REPLY_SUBJECT_RE = %r{\\[[^\\]]*#(\\d+)\\]}\n  MESSAGE_REPLY_SUBJECT_RE = %r{\\[[^\\]]*msg(\\d+)\\]}\n\n  def dispatch\n    logger.info { \"attempting to dispatch\" } if logger\n    headers = [email.in_reply_to, email.references].flatten.compact\n    if headers.detect {|h| h.to_s =~ MESSAGE_ID_RE}\n      klass, object_id = $1, $2.to_i\n      method_name = \"receive_#{klass}_reply\"\n      if self.class.private_instance_methods.collect(&:to_s).include?(method_name)\n        send method_name, object_id\n      else\n        # ignoring it\n      end\n    elsif m = email.subject.match(ISSUE_REPLY_SUBJECT_RE)\n      receive_issue_reply(m[1].to_i)\n    elsif m = email.subject.match(MESSAGE_REPLY_SUBJECT_RE)\n      receive_message_reply(m[1].to_i)\n    else\n      receive_issue\n    end\n  rescue ActiveRecord::RecordInvalid => e\n    # TODO: send a email to the user\n    logger.error e.message if logger\n    false\n  rescue MissingInformation => e\n    logger.error \"MailHandler: missing information from #{user}: #{e.message}\" if logger\n    false\n  rescue UnauthorizedAction => e\n    logger.error \"MailHandler: unauthorized attempt from #{user}\" if logger\n    false\n  end\n\n  # Creates a new issue\n  def receive_issue\n    project = target_project\n    tracker = (get_keyword(:tracker) && project.trackers.find_by_name(get_keyword(:tracker))) || project.trackers.find(:first)\n    status =  (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))\n\n    # check permission\n    unless @@handler_options[:no_permission_check]\n      raise UnauthorizedAction unless user.allowed_to?(:add_issues, project)\n    end\n\n    issue = Issue.new(:author => user, :project => project, :tracker => tracker)\n    # check workflow\n    if status && issue.new_statuses_allowed_to(user).include?(status)\n      issue.status = status\n    end\n    issue.subject = email.subject.chomp\n    issue.subject = issue.subject.toutf8 if issue.subject.respond_to?(:toutf8)\n    if issue.subject.blank?\n      issue.subject = '(no subject)'\n    end\n    issue.description = cleaned_up_text_body\n    # add To and Cc as watchers before saving so the watchers can reply to Redmine\n    add_watchers(issue)\n    issue.save!\n    add_attachments(issue)\n    issue\n  end\n\n  def target_project\n    # TODO: other ways to specify project:\n    # * parse the email To field\n    # * specific project (eg. Setting.mail_handler_target_project)\n    target = Project.find_by_identifier(get_keyword(:project))\n    raise MissingInformation.new('Unable to determine target project') if target.nil?\n    target\n  end\n\n  # Adds a note to an existing issue\n  def receive_issue_reply(issue_id)\n    status =  (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))\n\n    issue = Issue.find_by_id(issue_id)\n    return unless issue\n    # check permission\n    unless @@handler_options[:no_permission_check]\n      raise UnauthorizedAction unless user.allowed_to?(:add_issue_notes, issue.project) || user.allowed_to?(:edit_issues, issue.project)\n      raise UnauthorizedAction unless status.nil? || user.allowed_to?(:edit_issues, issue.project)\n    end\n\n    # add the note\n    journal = issue.init_journal(user, cleaned_up_text_body)\n    add_attachments(issue)\n    # check workflow\n    if status && issue.new_statuses_allowed_to(user).include?(status)\n      issue.status = status\n    end\n    issue.save!\n\n    LogActivityStreams.write_single_activity_stream(user,:name,issue,:subject,:updated,:issues, 0, journal,{\n        :indirect_object_description_method => :notes,\n        :indirect_object_phrase => 'GENERATEDETAILS' })\n\n    journal\n  end\n\n  # Reply will be added to the issue\n  def receive_journal_reply(journal_id)\n    journal = Journal.find_by_id(journal_id)\n    if journal && journal.journalized_type == 'Issue'\n      receive_issue_reply(journal.journalized_id)\n    end\n  end\n\n  # Receives a reply to a forum message\n  def receive_message_reply(message_id)\n    message = Message.find_by_id(message_id)\n    if message\n      message = message.root\n\n      unless @@handler_options[:no_permission_check]\n        raise UnauthorizedAction unless user.allowed_to?(:add_messages, message.project)\n      end\n\n      if !message.locked?\n        reply = Message.new(:subject => email.subject.gsub(%r{^.*msg\\d+\\]}, '').strip,\n                            :content => cleaned_up_text_body)\n        reply.author = user\n        reply.board = message.board\n        message.children << reply\n        add_attachments(reply)\n        reply\n      else\n      end\n    end\n  end\n\n  def add_attachments(obj)\n    if email.has_attachments?\n      email.attachments.each do |attachment|\n        Attachment.create(:container => obj,\n                          :file => attachment,\n                          :author => user,\n                          :content_type => attachment.content_type)\n      end\n    end\n  end\n\n  # Adds To and Cc as watchers of the given object if the sender has the\n  # appropriate permission\n  def add_watchers(obj)\n    if user.allowed_to?(\"add_#{obj.class.name.underscore}_watchers\".to_sym, obj.project)\n      addresses = [email.to, email.cc].flatten.compact.uniq.collect {|a| a.strip.downcase}\n      unless addresses.empty?\n        watchers = User.active.find(:all, :conditions => ['LOWER(mail) IN (?)', addresses])\n        watchers.each {|w| obj.add_watcher(w)}\n      end\n    end\n  end\n\n  def get_keyword(attr, options={})\n    @keywords ||= {}\n    if @keywords.has_key?(attr)\n      @keywords[attr]\n    else\n      @keywords[attr] = begin\n        if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && plain_text_body.gsub!(/^#{attr}[ \\t]*:[ \\t]*(.+)\\s*$/i, '')\n          $1.strip\n        elsif !@@handler_options[:issue][attr].blank?\n          @@handler_options[:issue][attr]\n        end\n      end\n    end\n  end\n\n  # Returns the text/plain part of the email\n  # If not found (eg. HTML-only email), returns the body with tags removed\n  def plain_text_body\n    return @plain_text_body unless @plain_text_body.nil?\n    parts = @email.parts.collect {|c| (c.respond_to?(:parts) && !c.parts.empty?) ? c.parts : c}.flatten\n    if parts.empty?\n      parts << @email\n    end\n    plain_text_part = parts.detect {|p| p.content_type == 'text/plain'}\n    if plain_text_part.nil?\n      # no text/plain part found, assuming html-only email\n      # strip html tags and remove doctype directive\n      @plain_text_body = @email.body.to_s\n      @plain_text_body.gsub! /On.{30,100}wrote:(.+)/sm, ''  #removing all lines including and after a \"On xxxxxx (email)\"\n      @plain_text_body = strip_tags(sanitize(@plain_text_body))\n      @plain_text_body.gsub! %r{^<!DOCTYPE .*$}, ''\n    else\n      @plain_text_body = plain_text_part.body.to_s\n    end\n    @plain_text_body.strip!\n    @plain_text_body\n  end\n\n  def cleaned_up_text_body\n    cleanup_body(plain_text_body)\n  end\n\n  def self.full_sanitizer\n    @full_sanitizer ||= HTML::FullSanitizer.new\n  end\n\n  # Creates a user account for the +email+ sender\n  def self.create_user_from_email(email)\n    addr = email.from_addrs.to_a.first\n    if addr && !addr.spec.blank?\n      user = User.new\n      user.mail = addr.spec\n\n      names = addr.name.blank? ? addr.spec.gsub(/@.*$/, '').split('.') : addr.name.split\n      user.firstname = names.shift\n      user.lastname = names.join(' ')\n      user.lastname = '-' if user.lastname.blank?\n\n      user.login = user.mail\n      user.password = ActiveSupport::SecureRandom.hex(5)\n      user.language = Setting.default_language\n      user.save ? user : nil\n    end\n  end\n\n  # Removes the email body of text after the truncation configurations.\n  def cleanup_body(body)\n    delimiters = Setting.mail_handler_body_delimiters.to_s.split(/[\\r\\n]+/).reject(&:blank?).map {|s| Regexp.escape(s)}\n    unless delimiters.empty?\n      regex = Regexp.new(\"^(#{ delimiters.join('|') })\\s*[\\r\\n].*\", Regexp::MULTILINE)\n      body = body.gsub(regex, '')\n    end\n\n    index = body.index(/^.*#{Setting.mail_from_raw}.*$/)\n    body = body[0..index - 2] if index\n    body.strip\n  end\n\nend\n"
  },
  {
    "path": "app/models/mailer.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Mailer < ActionMailer::Base\n  layout 'mailer'\n  helper :application\n  helper :issues\n\n  include ActionController::UrlWriter\n  include Redmine::I18n\n\n  def self.default_url_options\n    h = Setting.host_name\n    h = h.to_s.gsub(%r{\\/.*$}, '') unless Redmine::Utils.relative_url_root.blank?\n    { :host => h, :protocol => Setting.protocol }\n  end\n\n  # Builds a tmail object used to email recipients of the added issue.\n  #\n  # Example:\n  #   issue_add(issue) => tmail object\n  #   Mailer.deliver_issue_add(issue) => sends an email to issue recipients\n  def issue_add(issue)\n    redmine_headers 'Project' => issue.project.identifier,\n                    'Issue-Id' => issue.id,\n                    'Issue-Author' => issue.author.login\n    redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to\n    message_id issue\n    recipient_list = issue.recipients\n    recipient_list.delete issue.author.mail if issue.author.pref[:no_self_notified]\n    recipients recipient_list\n    cc(issue.watcher_recipients - @recipients)\n    subject \"[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}\"\n    body :issue => issue,\n         :issue_url => url_for(:controller => 'projects', :action => 'dashboard', :show_issue_id => issue.id)\n    render_multipart('issue_add', body)\n  end\n\n  # Builds a tmail object used to email recipients of the edited issue.\n  #\n  # Example:\n  #   issue_edit(journal) => tmail object\n  #   Mailer.deliver_issue_edit(journal) => sends an email to issue recipients\n  def issue_edit(journal)\n    issue = journal.journalized.reload\n    redmine_headers 'Project' => issue.project.identifier,\n                    'Issue-Id' => issue.id,\n                    'Issue-Author' => issue.author.login\n    redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to\n    message_id journal\n    references issue\n    @author = journal.user\n    recipient_list = issue.recipients\n    recipient_list.delete @author.mail if @author.pref[:no_self_notified]\n    recipients recipient_list\n    # Watchers in cc\n    cc(issue.watcher_recipients - @recipients)\n    s = \"[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] \"\n    s << \"(#{issue.status.name}) \" if journal.new_value_for('status_id')\n    s << issue.subject\n    subject s\n    body :issue => issue,\n         :journal => journal,\n         :issue_url => url_for(:controller => 'projects', :action => 'dashboard', :show_issue_id => issue.id)\n\n    render_multipart('issue_edit', body)\n  end\n\n  def daily_digest(recipient,journals)\n    @journals = journals\n    @author = User.sysadmin\n    recipients recipient\n    s = \"Daily Digest - \"\n    s << Time.now.strftime(\"%m/%d/%Y\")\n    subject s\n    body :journals => journals\n\n    render_multipart('daily_digest', body)\n\n  end\n\n  def invitation_add(invitation,note)\n    from invitation.user.mail\n    subject \"Invitation to join #{invitation.project.name}\"\n    recipients invitation.mail\n    body :user => invitation.user,\n         :project => invitation.project,\n         :note => note,\n         :invitation_url => url_for(:controller => :invitations, :action => \"accept\", :id => invitation.id, :token => invitation.token),\n         :footer => Setting.emails_footer_nospam,\n         :ignore_bcc_setting => true\n    render_multipart('invitation_add', body)\n    @ignore_bcc_setting = true\n  end\n\n  def invitation_remind(invitation,note)\n    from invitation.user.mail\n    subject \"Reminder: Invitation to join #{invitation.project.name}\"\n    recipients invitation.mail\n    body :user => invitation.user,\n         :project => invitation.project,\n         :note => note,\n         :invitation_url => url_for(:controller => :invitations, :action => \"accept\", :id => invitation.id, :token => invitation.token),\n         :footer => Setting.emails_footer_nospam,\n         :ignore_bcc_setting => true\n    render_multipart('invitation_remind', body)\n    @ignore_bcc_setting = true\n  end\n\n  def reminder(user, issues, days)\n    set_language_if_valid user.language\n    recipients user.mail\n    subject l(:mail_subject_reminder, issues.size)\n    body :issues => issues,\n         :days => days,\n         :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'due_date', :sort_order => 'asc')\n    render_multipart('reminder', body)\n  end\n\n  # Builds a tmail object used to email users belonging to the added document's project.\n  #\n  # Example:\n  #   document_added(document) => tmail object\n  #   Mailer.deliver_document_added(document) => sends an email to the document's project recipients\n  def document_added(document)\n    redmine_headers 'Project' => document.project.identifier\n    recipients document.recipients\n    subject \"[#{document.project.name}] #{l(:label_document_new)}: #{document.title}\"\n    body :document => document,\n         :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)\n    render_multipart('document_added', body)\n  end\n\n  # Builds a tmail object used to email recipients of a project when an attachements are added.\n  #\n  # Example:\n  #   attachments_added(attachments) => tmail object\n  #   Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients\n  def attachments_added(attachments)\n    container = attachments.first.container\n    added_to = ''\n    added_to_url = ''\n    case container.class.name\n    when 'Project'\n      added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container)\n      added_to = \"#{l(:label_project)}: #{container}\"\n      recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project) && !user.pref[:no_emails]}\n    when 'Document'\n      added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)\n      added_to = \"#{l(:label_document)}: #{container.title}\"\n      recipients container.recipients\n    end\n    redmine_headers 'Project' => container.project.identifier\n    subject \"[#{container.project.name}] #{l(:label_attachment_new)}\"\n    body :attachments => attachments,\n         :added_to => added_to,\n         :added_to_url => added_to_url\n    render_multipart('attachments_added', body)\n  end\n\n  # Builds a tmail object used to email recipients of a news' project when a news item is added.\n  #\n  # Example:\n  #   news_added(news) => tmail object\n  #   Mailer.deliver_news_added(news) => sends an email to the news' project recipients\n  def news_added(news)\n    redmine_headers 'Project' => news.project.identifier\n    message_id news\n    recipients news.recipients\n    subject \"[#{news.project.name}] #{l(:label_news)}: #{news.title}\"\n    body :news => news,\n         :news_url => url_for(:controller => 'news', :action => 'show', :id => news)\n    render_multipart('news_added', body)\n  end\n\n  # Builds a tmail object used to email the recipients of the specified message that was posted.\n  #\n  # Example:\n  #   message_posted(message) => tmail object\n  #   Mailer.deliver_message_posted(message) => sends an email to the recipients\n  def message_posted(message)\n    redmine_headers 'Project' => message.project.identifier,\n                    'Topic-Id' => (message.parent_id || message.id)\n    message_id message\n    references message.parent unless message.parent.nil?\n\n    recipient_list = message.recipients\n    recipient_list.delete message.author.mail if message.author.pref[:no_self_notified]\n    recipients recipient_list\n\n\n    all_recipients = (message.root.watcher_recipients + message.board.watcher_recipients).uniq - @recipients\n\n    all_recipients.delete(message.author.mail) if message.author.pref[:no_self_notified] || message.author.pref[:no_emails]\n    cc(all_recipients)\n\n    subject \"[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}\"\n    body :message => message,\n         :message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root)\n    render_multipart('message_posted', body)\n  end\n\n  # Builds a tmail object used to email the recipients of a project of the specified wiki content was added.\n  #\n  # Example:\n  #   wiki_content_added(wiki_content) => tmail object\n  #   Mailer.deliver_wiki_content_added(wiki_content) => sends an email to the project's recipients\n  def wiki_content_added(wiki_content)\n    redmine_headers 'Project' => wiki_content.project.identifier,\n                    'Wiki-Page-Id' => wiki_content.page.id\n    message_id wiki_content\n\n    recipient_list = wiki_content.recipients\n    recipient_list.delete wiki_content.author.mail if wiki_content.author.pref[:no_self_notified]\n    recipients recipient_list\n\n    cc(wiki_content.page.wiki.watcher_recipients - recipients)\n    subject \"[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :page => wiki_content.page.pretty_title)}\"\n    body :wiki_content => wiki_content,\n         :wiki_content_url => url_for(:controller => 'wiki', :action => 'index', :id => wiki_content.project, :page => wiki_content.page.title)\n    render_multipart('wiki_content_added', body)\n  end\n\n  # Builds a tmail object used to email the recipients of a project of the specified wiki content was updated.\n  #\n  # Example:\n  #   wiki_content_updated(wiki_content) => tmail object\n  #   Mailer.deliver_wiki_content_updated(wiki_content) => sends an email to the project's recipients\n  def wiki_content_updated(wiki_content)\n    redmine_headers 'Project' => wiki_content.project.identifier,\n                    'Wiki-Page-Id' => wiki_content.page.id\n    message_id wiki_content\n    recipients wiki_content.recipients\n    cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients)\n    subject \"[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :page => wiki_content.page.pretty_title)}\"\n    body :wiki_content => wiki_content,\n         :wiki_content_url => url_for(:controller => 'wiki', :action => 'index', :id => wiki_content.project, :page => wiki_content.page.title),\n         :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff', :id => wiki_content.project, :page => wiki_content.page.title, :version => wiki_content.version)\n    render_multipart('wiki_content_updated', body)\n  end\n\n  # Builds a tmail object used to email the specified user their account information.\n  #\n  # Example:\n  #   account_information(user, password) => tmail object\n  #   Mailer.deliver_account_information(user, password) => sends account information to the user\n  def account_information(user, password)\n    set_language_if_valid user.language\n    recipients user.mail\n    subject l(:mail_subject_register, Setting.app_title)\n    body :user => user,\n         :password => password,\n         :login_url => url_for(:controller => 'account', :action => 'login')\n    render_multipart('account_information', body)\n  end\n\n  # Builds a tmail object used to email all active administrators of an account activation request.\n  #\n  # Example:\n  #   account_activation_request(user) => tmail object\n  #   Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators\n  def account_activation_request(user)\n    # Send the email to all active administrators\n    recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact\n    subject l(:mail_subject_account_activation_request, Setting.app_title)\n    body :user => user,\n         :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_at', :sort_order => 'desc')\n    render_multipart('account_activation_request', body)\n  end\n\n  # Builds a tmail object used to email the specified user that their account was activated by an administrator.\n  #\n  # Example:\n  #   account_activated(user) => tmail object\n  #   Mailer.deliver_account_activated(user) => sends an email to the registered user\n  def account_activated(user)\n    set_language_if_valid user.language\n    recipients user.mail\n    subject l(:mail_subject_register, Setting.app_title)\n    body :user => user,\n         :login_url => url_for(:controller => 'account', :action => 'login')\n    render_multipart('account_activated', body)\n  end\n\n  def lost_password(token)\n    set_language_if_valid(token.user.language)\n    recipients token.user.mail\n    subject l(:mail_subject_lost_password, Setting.app_title)\n    body :token => token,\n         :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)\n    render_multipart('lost_password', body)\n  end\n\n  def register(token)\n    recipients token.user.mail\n    subject l(:mail_subject_register, Setting.app_title)\n    body :token => token,\n         :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)\n    render_multipart('register', body)\n  end\n\n  # Builds a tmail object used to email recipients of the added issue.\n  #\n  # Example:\n  #   issue_add(issue) => tmail object\n  #   Mailer.deliver_issue_add(issue) => sends an email to issue recipients\n  def personal_welcome(user,project)\n    from \"shereef@bettermeans.com\"\n    cc \"support@bettermeans.com\"\n    recipients user.mail\n    subject \"bettermeans and \" + project.name\n    body :name => user.firstname,\n        :footer => \"Don't ask yourself what the world needs; ask yourself what makes you come alive and then go do that. Because what the world needs is people who are alive.\"\n    render_multipart('personal_welcome', body)\n  end\n\n\n  def test(user)\n    set_language_if_valid(user.language)\n    recipients user.mail\n    subject 'Bettermeans test'\n    body :url => url_for(:controller => 'welcome')\n    render_multipart('test', body)\n  end\n\n  # Overrides default deliver! method to prevent from sending an email\n  # with no recipient, cc or bcc\n  def deliver!(mail = @mail)\n    return false if (recipients.nil? || recipients.empty?) &&\n                    (cc.nil? || cc.empty?) &&\n                    (bcc.nil? || bcc.empty?)\n\n    # Set Message-Id and References\n    if @message_id_object\n      mail.message_id = self.class.message_id_for(@message_id_object)\n    end\n    if @references_objects\n      mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}\n    end\n    super(mail)\n  end\n\n  def email_update_activation(email_update)\n    recipients email_update.mail\n    subject l(:mail_subject_email_update_activation, Setting.app_title)\n    body :activation_url => url_for(:controller => 'email_updates', :action => 'activate', :token => email_update.token)\n    render_multipart('email_update_activation', body)\n  end\n\n\n\n  # Sends reminders to issue assignees\n  # Available options:\n  # * :days     => how many days in the future to remind about (defaults to 7)\n  # * :tracker  => id of tracker for filtering issues (defaults to all trackers)\n  # * :project  => id or identifier of project to process (defaults to all projects)\n  def self.reminders(options={})\n    days = options[:days] || 7\n    project = options[:project] ? Project.find(options[:project]) : nil\n    tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil\n\n    s = ARCondition.new [\"#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?\", false, days.day.from_now.to_date]\n    s << \"#{Issue.table_name}.assigned_to_id IS NOT NULL\"\n    s << \"#{Project.table_name}.status = #{Project::STATUS_ACTIVE}\"\n    s << \"#{Issue.table_name}.project_id = #{project.id}\" if project\n    s << \"#{Issue.table_name}.tracker_id = #{tracker.id}\" if tracker\n\n    issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],\n                                          :conditions => s.conditions\n                                    ).group_by(&:assigned_to)\n    issues_by_assignee.each do |assignee, issues|\n      deliver_reminder(assignee, issues, days) unless assignee.nil?\n    end\n  end\n\n  private\n\n  def initialize_defaults(method_name)\n    super\n    set_language_if_valid Setting.default_language\n    from Setting.mail_from\n\n    # Common headers\n    headers 'X-Mailer' => 'BetterMeans',\n            'X-BetterMeans-Host' => Setting.host_name,\n            'X-BetterMeans-Site' => Setting.app_title,\n            'Precedence' => 'bulk',\n            'Auto-Submitted' => 'auto-generated'\n  end\n\n  # Appends a Redmine header field (name is prepended with 'X-Redmine-')\n  def redmine_headers(h)\n    h.each { |k,v| headers[\"X-BetterMeans-#{k}\"] = v }\n  end\n\n  # Overrides the create_mail method\n  def create_mail\n    # Removes the current user from the recipients and cc\n    # if he doesn't want to receive notifications about what he does\n    @author ||= User.current\n    if @author.pref[:no_self_notified] || @author.pref[:no_emails]\n      recipients.delete(@author.mail) if recipients\n      cc.delete(@author.mail) if cc\n      bcc.delete(@author.mail) if bcc\n    end unless @author == User.anonymous #no need to check for prefs if current user is anonymous\n    # Blind carbon copy recipients\n    if Setting.bcc_recipients?\n      bcc([recipients, cc].flatten.compact.uniq)\n      recipients []\n      cc []\n    end unless @ignore_bcc_setting\n    super\n  end\n\n  # Rails 2.3 has problems rendering implicit multipart messages with\n  # layouts so this method will wrap an multipart messages with\n  # explicit parts.\n  #\n  # https://rails.lighthouseapp.com/projects/8994/tickets/2338-actionmailer-mailer-views-and-content-type\n  # https://rails.lighthouseapp.com/projects/8994/tickets/1799-actionmailer-doesnt-set-template_format-when-rendering-layouts\n\n  def render_multipart(method_name, body)\n    if Setting.plain_text_mail?\n      content_type \"text/plain\"\n      body render(:file => \"#{method_name}.text.plain.html.erb\", :body => body, :layout => 'mailer.text.plain.erb')\n    else\n      content_type \"multipart/alternative\"\n      part :content_type => \"text/plain\", :body => render(:file => \"#{method_name}.text.plain.html.erb\", :body => body, :layout => 'mailer.text.plain.erb')\n      part :content_type => \"text/html\", :body => render_message(\"#{method_name}.text.html.html.erb\", body)\n    end\n  end\n\n  # Makes partial rendering work with Rails 1.2 (retro-compatibility)\n  def self.controller_path\n    ''\n  end unless respond_to?('controller_path')\n\n  # Returns a predictable Message-Id for the given object\n  def self.message_id_for(object)\n    # id + timestamp should reduce the odds of a collision\n    # as far as we don't send multiple emails for the same object\n    timestamp = object.send(object.respond_to?(:created_at) ? :created_at : :updated_at)\n    hash = \"redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{timestamp.strftime(\"%Y%m%d%H%M%S\")}\"\n    host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')\n    host = \"#{::Socket.gethostname}.redmine\" if host.empty?\n    \"<#{hash}@#{host}>\"\n  end\n\n  def message_id(object)\n    @message_id_object = object\n  end\n\n  def references(object)\n    @references_objects ||= []\n    @references_objects << object\n  end\n\nend\n\n# Patch TMail so that message_id is not overwritten\nmodule TMail\n\n  class Mail\n\n    def add_message_id( fqdn = nil )\n      self.message_id ||= ::TMail::new_message_id(fqdn)\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "app/models/member.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Member < ActiveRecord::Base\n\n  belongs_to :user\n  has_many :member_roles, :dependent => :destroy\n  has_many :roles, :through => :member_roles\n  belongs_to :project\n\n  validates_presence_of :user, :project\n  validates_uniqueness_of :user_id, :scope => :project_id\n\n  after_destroy :unwatch_from_permission_change\n\n  def name\n    self.user.name if self.user\n  end\n\n  def name_and_id\n    \"#{self.user.id.to_s}:#{self.user.name}\"\n  end\n\n  alias :base_role_ids= :role_ids=\n  def role_ids=(arg)\n    arg = [arg] unless arg.respond_to? :collect\n    ids = (arg || []).collect(&:to_i) - [0]\n    # Keep inherited roles\n    ids += member_roles.select {|mr| !mr.inherited_from.nil?}.collect(&:role_id)\n    new_role_ids = ids - role_ids\n    # Add new roles\n    new_role_ids.each {|id| member_roles << MemberRole.new(:role_id => id) }\n    # Remove roles (Rails' #role_ids= will not trigger MemberRole#on_destroy)\n    member_roles_to_destroy = member_roles.select {|mr| !ids.include?(mr.role_id)}\n    if member_roles_to_destroy.any?\n      member_roles_to_destroy.each(&:destroy)\n      unwatch_from_permission_change\n    end\n  end\n\n  def <=>(member)\n    a, b = roles.sort.first, member.roles.sort.first\n    a == b ? (user <=> member.user) : (a <=> b)\n  end\n\n  def deletable?\n    member_roles.detect {|mr| mr.inherited_from}.nil?\n  end\n\n  protected\n\n  def validate\n    errors.add_to_base \"Role can't be blank\" if member_roles.empty? && roles.empty?\n  end\n\n  private\n\n  # Unwatch things that the user is no longer allowed to view inside project\n  def unwatch_from_permission_change\n    if user\n      Watcher.prune(:user => user, :project => project)\n    end\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/member_role.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass MemberRole < ActiveRecord::Base\n\n  belongs_to :member\n  belongs_to :role\n\n  after_create :send_notification, :log_activity , :refresh_memberships\n\n  after_destroy :remove_member_if_empty, :refresh_memberships\n\n  validates_presence_of :role\n\n  acts_as_event :title => :event_title,\n                :description => :long_description,\n                :author =>  :user,\n                :type => 'member-role',\n                :url => Proc.new {|o| {:controller => 'projects', :action => 'team', :id => o.member.project_id}}\n\n\n  def project\n    member.respond_to?(:project) ? member.project : nil\n  end\n\n  #used for activity stream\n  def name\n    role.name\n  end\n\n  def project_id\n    project.id\n  end\n\n  def user_id\n    member.user.id\n  end\n\n  def user\n    member.user\n  end\n\n  def long_description\n    \"#{user.name} is now: #{role.name}\"\n  end\n\n  def event_title\n    \"Team change\"\n  end\n\n  private\n\n  def remove_member_if_empty\n    return unless member\n    if member.roles.empty?\n      member.destroy\n    end# unless role_id == Role::BUILTIN_CORE_MEMBER #We don't destory the member if the role being removed is the core_member role since we're going to add a contributor role\n  end\n\n  def send_notification\n    Notification.create :recipient_id => self.member.user_id,\n                              :variation => 'new_role',\n                              :params => {:role_name => self.role.name, :project_name => self.member.project.root.name, :enterprise_id => self.member.project.root.id},\n                              :sender_id => User.sysadmin.id,\n                              :source_type => \"MemberRole\",\n                              :source_id => self.id if self.role.level == Role::LEVEL_ENTERPRISE\n  end\n\n  def log_activity\n    return if role.active? || role.clearance? #don't log active memberships\n    LogActivityStreams.write_single_activity_stream(User.sysadmin,:name,self,:name,:created,:memberships, 0, self.member.user,{:indirect_object_phrase => self.member.user.name})\n  end\n\n  #refreshes memberships for all private workstreams\n  def refresh_memberships\n    return unless member\n    return unless role.level == Role::LEVEL_ENTERPRISE\n    MemberRole.send_later(:refresh_memberships_delayed,self)\n  end\n\n  #refreshes memberships for all private workstreams\n  def self.refresh_memberships_delayed(member_role)\n    return unless member_role.member\n    return unless member_role.role.level == Role::LEVEL_ENTERPRISE\n    member_role.member.project.root.descendants.each(&:refresh_active_members) if member_role.member.project\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/message.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Message < ActiveRecord::Base\n  belongs_to :board\n  belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'\n  acts_as_tree :counter_cache => :replies_count, :order => \"#{Message.table_name}.created_at ASC\"\n  acts_as_attachable\n  belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id'\n\n  acts_as_searchable :columns => ['subject', 'content'],\n                     :include => {:board => :project},\n                     :project_key => 'project_id',\n                     :date_column => \"#{table_name}.created_at\"\n\n  acts_as_event :title => Proc.new {|o| \"#{o.board.name}: #{o.subject}\"},\n                :description => :content,\n                :type => Proc.new {|o| o.parent_id.nil? ? 'message' : 'reply'},\n                :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} :\n                                                                                                                                       {:id => o.parent_id, :anchor => \"message-#{o.id}\"})}\n  acts_as_watchable\n\n  attr_protected :locked, :sticky\n  validates_presence_of :board, :subject, :content\n  validates_length_of :subject, :maximum => 255\n\n  after_create :add_author_as_watcher\n  after_save :send_mentions\n\n  def project_id\n    board.project.id\n  end\n\n  def visible?(user=User.current)\n    !user.nil? && user.allowed_to?(:view_messages, project)\n  end\n\n  def validate_on_create\n    # Can not reply to a locked topic\n    errors.add_to_base 'Topic is locked' if root.locked? && self != root\n  end\n\n  def after_create\n    if parent\n      parent.reload.update_attribute(:last_reply_id, self.id)\n    end\n    board.reset_counters!\n  end\n\n  def send_mentions\n    Mention.parse(self, self.author_id)\n  end\n\n  def mention(mentioner_id, mentioned_id, mention_text)\n    Notification.create :recipient_id => mentioned_id,\n                        :variation => 'mention',\n                        :params => {:mention_text => self.content,\n                                    :url => {:controller => \"messages\", :action => \"show\", :board_id => self.board_id, :id => self.id},\n                                    :title => self.subject},\n                        :sender_id => mentioner_id,\n                        :source_id => self.id,\n                        :source_type => \"Message\"\n  end\n\n\n  def after_update\n    if board_id_changed?\n      Message.update_all(\"board_id = #{board_id}\", [\"id = ? OR parent_id = ?\", root.id, root.id])\n      Board.reset_counters!(board_id_was)\n      Board.reset_counters!(board_id)\n    end\n  end\n\n  def after_destroy\n    board.reset_counters!\n  end\n\n  def sticky=(arg)\n    write_attribute :sticky, (arg == true || arg.to_s == '1' ? 1 : 0)\n  end\n\n  def sticky?\n    sticky == 1\n  end\n\n  def project\n    board.project\n  end\n\n  def editable_by?(usr)\n    usr && usr.logged? && (usr.allowed_to?(:edit_messages, project) || (self.author == usr && usr.allowed_to?(:edit_own_messages, project)))\n  end\n\n  def destroyable_by?(usr)\n    usr && usr.logged? && (usr.allowed_to?(:delete_messages, project) || (self.author == usr && usr.allowed_to?(:delete_own_messages, project)))\n  end\n\n  # Returns the mail adresses of users that should be notified\n  def recipients\n    notified = project.notified_users\n    notified << author if author && author.active? && !author.pref[:no_emails]\n    notified.reject! {|user| !visible?(user) || user.pref[:no_emails]}\n    notified.collect(&:mail)\n  end\n\n  private\n\n  def add_author_as_watcher\n    Watcher.create(:watchable => self.root, :user => author)\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/message_observer.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass MessageObserver < ActiveRecord::Observer\n  def after_create(message)\n    Mailer.send_later(:deliver_message_posted,message) if Setting.notified_events.include?('message_posted')\n  end\nend\n"
  },
  {
    "path": "app/models/motion.rb",
    "content": "class Motion < ActiveRecord::Base\n  include ActionController::UrlWriter\n  STATE_ACTIVE = 0\n  STATE_PASSED = 1\n  STATE_DEFEATED = 2\n  STATE_CANCELED = 3\n\n  TYPE_CONSENSUS = 1 #Any disagree defeats the motion\n  TYPE_MAJORITY = 2 #Any block defeats the motion\n  TYPE_SHARE = 3 #Majority vote, 1 share = 1 vote\n\n  VISIBLE_BOARD = 1 #Only board can see this motion\n  VISIBLE_CORE = 2 #Only core & board\n  VISIBLE_MEMBER = 3 #All members, core and board\n  VISIBLE_CONTRIBUTER = 4 #Everyone who is a part of the enterprise\n  VISIBLE_USER = 10 #Everyone on the platform\n\n  BINDING_BOARD = 1 #Only board votes are binding\n  BINDING_CORE = 2 #Only core & board votes are binding\n  BINDING_MEMBER = 3 #All members, core and board votes are binding\n  BINDING_CONTRIBUTER = 4 #Everyone who is a part of the enterprise has a binding vote\n  BINDING_USER = 5 #Everyone on the platform has a binding vote\n\n  VARIATION_GENERAL = 0 #Miscellaneous issues\n  VARIATION_EXTRAORDINARY = 1 #e.g. sell a company!\n  VARIATION_NEW_MEMBER = 2\n  VARIATION_NEW_CORE = 3\n  VARIATION_FIRE_MEMBER = 4\n  VARIATION_FIRE_CORE = 5\n  VARIATION_BOARD_PUBLIC = 6\n  VARIATION_BOARD_PRIVATE = 7\n  VARIATION_HOURLY_TYPE = 8\n\n  serialize :params\n\n  belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'\n  belongs_to :concerned_user, :class_name => 'User', :foreign_key => 'concerned_user_id'\n  belongs_to :project\n  has_many :motion_votes\n  belongs_to :topic, :class_name => 'Message', :foreign_key => 'topic_id'\n\n  named_scope :allactive, :conditions => [\"state = #{STATE_ACTIVE}\", Time.new.to_date]\n  named_scope :viewable_by, lambda { |*level|\n    {:conditions => \"visibility_level >= #{level}\", :order => \"updated_at DESC\"}\n  }\n\n  before_create :set_values\n  after_create :send_announce,:create_forum_topic\n  after_save :close\n\n  def active?\n    self.state == STATE_ACTIVE\n  end\n\n  def ended?\n\n    return true if Time.now > self.ends_on\n\n    case self.motion_type\n    when TYPE_CONSENSUS #if we don't have a disagreement, and have more than half binding agreement, we're a go\n      if self.disagree == 0 && self.agree_total > self.project.role_and_above_count(self.binding_level).to_f / 2\n        return true;\n      end\n    when TYPE_MAJORITY #if have majority binding agreement, and no blocking, we're a go\n      if self.disagree < 500 && self.agree_total > self.project.role_and_above_count(self.binding_level).to_f / 2\n          return true;\n      end\n    end\n\n    return false\n\n  end\n\n  # true if variation requires a concerned user to be specified\n  def concerns_someone?\n    return (self.variation == VARIATION_NEW_MEMBER || self.variation == VARIATION_NEW_CORE || self.variation == VARIATION_FIRE_MEMBER || self.variation == VARIATION_FIRE_CORE)\n  end\n\n  #Checks if motion has reached end date, calculates vote and takes action\n  def close\n    return if !active?\n    return if !ended?\n    return if self.motion_votes.nil?\n\n    case self.motion_type\n    when TYPE_CONSENSUS\n      if self.disagree > 0\n        self.state = STATE_DEFEATED\n      else\n        self.state = STATE_PASSED\n      end\n    when TYPE_MAJORITY\n      if self.disagree > 500 || self.agree_total < 1\n          self.state = STATE_DEFEATED\n        else\n          self.state = STATE_PASSED\n        end\n    when TYPE_SHARE\n      if (self.agree + (self.disagree * -1)) * Setting::SHARE_MAJORIY_MOTION_RATIO < self.agree\n          self.state = STATE_DEFEATED\n        else\n          self.state = STATE_PASSED\n        end\n    end\n\n    self.ends_on = DateTime.now\n\n    self.save\n    announce_passed if self.state == STATE_PASSED\n    execute_action if self.state == STATE_PASSED\n\n  end\n\n  def set_values\n    self.title = Setting::MOTIONS[self.variation][\"Title\"]\n    self.title = self.generate_title\n    self.binding_level = Setting::MOTIONS[self.variation][\"Binding\"]\n    self.visibility_level = Setting::MOTIONS[self.variation][\"Visible\"]\n    self.motion_type = Setting::MOTIONS[self.variation][\"Type\"]\n    self.ends_on = Time.new.advance :days => Setting::MOTIONS[self.variation][\"Days\"].to_f\n    self.state = STATE_ACTIVE\n    self.author = User.sysadmin if self.author.nil?\n    self.description = self.generate_description\n  end\n\n  def generate_title\n     case self.variation\n       when VARIATION_GENERAL\n         self.title\n       when VARIATION_EXTRAORDINARY\n         self.title\n       when VARIATION_NEW_MEMBER\n         l(:title_member_nomination, :user => self.concerned_user.name)\n       when VARIATION_NEW_CORE\n         l(:title_core_member_nomination, :user => self.concerned_user.name)\n       when VARIATION_FIRE_MEMBER\n         l(:title_member_removal, :user => self.concerned_user.name)\n       when VARIATION_FIRE_CORE\n         l(:title_core_member_removal, :user => self.concerned_user.name)\n       when VARIATION_BOARD_PUBLIC\n         self.title\n       when VARIATION_BOARD_PRIVATE\n         self.title\n       when VARIATION_HOURLY_TYPE\n         self.title\n     end\n  end\n\n\n  def generate_description\n    content = \"\"\n     case self.variation\n       when VARIATION_GENERAL\n         self.description == \"\" ? self.title : self.description\n       when VARIATION_EXTRAORDINARY\n         self.description == \"\" ? self.title : self.description\n       when VARIATION_NEW_MEMBER\n         content << l(:text_member_nomination, :user => self.concerned_user.name, :enterprise => self.project.name)\n       when VARIATION_NEW_CORE\n         content << l(:text_core_member_nomination, :user => self.concerned_user.name, :enterprise => self.project.name)\n       when VARIATION_FIRE_MEMBER\n         content << l(:text_member_removal, :user => self.concerned_user.name, :enterprise => self.project.name)\n       when VARIATION_FIRE_CORE\n         content << l(:text_core_member_removal, :user => self.concerned_user.name, :enterprise => self.project.name)\n       when VARIATION_BOARD_PUBLIC\n         self.description == \"\" ? self.title : self.description\n       when VARIATION_BOARD_PRIVATE\n         self.description == \"\" ? self.title : self.description\n       when VARIATION_HOURLY_TYPE\n         self.description == \"\" ? self.title : self.description\n     end\n  end\n\n  def self.eligible_users(variation,project_id)\n\n    project = Project.find(project_id)\n    @concerned_user_list = \"\"\n    case variation\n      when VARIATION_NEW_MEMBER\n        @concerned_user_list = project.contributor_list\n      when VARIATION_NEW_CORE\n        @concerned_user_list = project.member_list\n      when VARIATION_FIRE_MEMBER\n        @concerned_user_list = project.member_list\n      when VARIATION_FIRE_CORE\n        @concerned_user_list = project.core_member_list\n    end\n    @concerned_user_list\n  end\n\n  def create_forum_topic\n\n    main_board = Board.first(:conditions => {:project_id => self.project, :name => Setting.forum_name})\n\n    motion_topic = Message.create! :board_id => main_board.id,\n                 :subject => self.title,\n                 :content => self.description,\n                 :author_id => self.author_id\n\n    self.update_attribute(:topic_id,motion_topic.id)\n\n  end\n\n  def visibility_level_description\n    Role.first(:conditions => {:position => self.visibility_level}).name\n  end\n\n  def binding_level_description\n    Role.first(:conditions => {:position => self.binding_level}).name\n  end\n\n  def execute_action\n    return if self.state != STATE_PASSED\n    case self.variation\n      when VARIATION_GENERAL\n      when VARIATION_EXTRAORDINARY\n      when VARIATION_NEW_MEMBER\n        return if !self.concerned_user.contributor_of?(self.project)\n        self.concerned_user.add_as_member(self.project)\n      when VARIATION_NEW_CORE\n        return if !self.concerned_user.member_of?(self.project)\n        self.concerned_user.add_as_core(self.project)\n      when VARIATION_FIRE_MEMBER\n        return if !self.concerned_user.member_of?(self.project)\n        self.concerned_user.add_as_contributor(self.project)\n      when VARIATION_FIRE_CORE\n        return if !self.concerned_user.core_member_of?(self.project)\n        self.concerned_user.add_as_member(self.project)\n      when VARIATION_BOARD_PUBLIC\n      when VARIATION_BOARD_PRIVATE\n      when VARIATION_HOURLY_TYPE\n    end\n  end\n\n  def send_announce\n    self.send_later :announce\n  end\n\n  def announce\n    admin = User.sysadmin\n\n    self.project.all_members.each do |member|\n      user = member.user\n      Notification.create :recipient_id => user.id,\n                          :variation => 'motion_started',\n                          :params => {:motion_title => self.title, :motion_description => self.description, :enterprise_id => self.project.root.id},\n                          :sender_id => self.author_id,\n                          :source_id => self.id,\n                          :source_type => \"Motion\",\n                          :expiration => self.ends_on if user.allowed_to_see_motion?(self) unless self.concerned_user_id == user.id\n    end\n  end\n\n  def announce_passed\n    admin = User.sysadmin\n\n    LogActivityStreams.write_single_activity_stream(User.sysadmin,:name,self,:title,:passed_a,:motions, 0, nil,{})\n\n    News.create :project_id => self.project.id,\n                :title => \"Passed! #{self.title}\",\n                :summary => \"#{self.title} has passed\",\n                :description => \"#{self.description}\",\n                :author_id => admin\n  end\n\nend\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "app/models/motion_vote.rb",
    "content": "class MotionVote < ActiveRecord::Base\n  belongs_to :user\n  belongs_to :motion\n  before_create :remove_similar_votes\n  before_save :set_binding\n  after_save :update_agree_total, :remove_notifications\n\n  named_scope :belong_to_user, lambda {|user_id| {:conditions => {:user_id => user_id}} } do\n    def default\n      find(:first, :conditions => { :is_default => true })\n    end\n  end\n\n\n  named_scope :history, :order => 'updated_at DESC', :include => :user\n\n  def project\n    self.motion.project\n  end\n\n  def remove_similar_votes\n    MotionVote.delete_all(:motion_id => motion_id, :user_id => user_id)\n  end\n\n  def set_binding\n    self.isbinding = self.user.binding_voter_of_motion?(self.motion)\n    return true\n  end\n\n  def action_description\n    if self.motion.motion_type == Motion::TYPE_SHARE\n      if (self.points < 0)\n        l(\"label_motion_vote_action_share_disagree\",:points => self.points * -1 )\n      elsif (self.points == 0)\n        l(\"label_motion_vote_action_share_neutral\",:points => self.points)\n      else\n        l(\"label_motion_vote_action_share_agree\",:points => self.points)\n      end\n    else\n      l(\"label_motion_vote_action#{self.points + 10000}\")\n    end\n  end\n\n  def update_agree_total\n    @motion = self.motion\n    if self.isbinding\n      @motion.agree =   MotionVote.sum(:points, :conditions => \"motion_id = '#{@motion.id}' AND points > 0 AND isbinding='true'\")\n      @motion.disagree =   MotionVote.sum(:points, :conditions => \"motion_id = '#{@motion.id}' AND points < 0 AND isbinding='true'\") * -1\n      @motion.agree_total = @motion.agree - @motion.disagree\n    else\n      @motion.agree_nonbind =   MotionVote.sum(:points, :conditions => \"motion_id = '#{@motion.id}' AND points > 0 AND isbinding='false'\")\n      @motion.disagree_nonbind =   MotionVote.sum(:points, :conditions => \"motion_id = '#{@motion.id}' AND points < 0 AND isbinding='false'\") * -1\n      @motion.agree_total_nonbind = @motion.agree_nonbind - @motion.disagree_nonbind\n    end\n    @motion.save\n  end\n\n  def remove_notifications\n    Notification.update_all \"state = #{Notification::STATE_ARCHIVED}\" , [\"variation = 'motion_started' AND source_id = ? AND recipient_id = ?\", self.motion_id, self.user_id]\n  end\n\n\nend\n\n"
  },
  {
    "path": "app/models/news.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nclass News < ActiveRecord::Base\n  belongs_to :project\n  belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'\n  has_many :comments, :as => :commented, :dependent => :delete_all, :order => \"created_at\"\n\n  validates_presence_of :title, :description\n  validates_length_of :title, :maximum => 60\n  validates_length_of :summary, :maximum => 255\n\n  after_save :send_mentions\n\n  acts_as_searchable :columns => ['title', 'summary', \"#{table_name}.description\"], :include => :project\n\n  acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}}\n\n  def visible?(user=User.current)\n    !user.nil? && user.allowed_to?(:view_news, project)\n  end\n\n  # Returns the mail adresses of users that should be notified\n  def recipients\n    notified = project.notified_users\n    notified.reject! {|user| !visible?(user) || user.pref[:no_emails]}\n    notified.collect(&:mail)\n  end\n\n  # returns latest news for projects visible by user\n  def self.latest(user = User.current, count = 5)\n    find(:all, :limit => count, :conditions => Project.allowed_to_condition(user, :view_news) + \" (created_at > '#{Time.now.advance :days => (Setting::DAYS_FOR_LATEST_NEWS * -1)}')\", :include => [ :author, :project ], :order => \"#{News.table_name}.created_at DESC\")\n  end\n\n  def send_mentions\n    Mention.parse(self, self.author_id)\n  end\n\n  def mention(mentioner_id, mentioned_id, mention_text)\n    Notification.create :recipient_id => mentioned_id,\n                        :variation => 'mention',\n                        :params => {:mention_text => self.description,\n                                    :url => {:controller => \"news\", :action => \"show\", :id => self.id},\n                                    :title => self.title},\n                        :sender_id => mentioner_id,\n                        :source_id => self.id,\n                        :source_type => \"News\"\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/news_observer.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass NewsObserver < ActiveRecord::Observer\n  def after_create(news)\n    Mailer.send_later(:deliver_news_added,news) if Setting.notified_events.include?('news_added')\n  end\nend\n"
  },
  {
    "path": "app/models/notification.rb",
    "content": "class Notification < ActiveRecord::Base\n  serialize :params\n\n  belongs_to :recipient, :class_name => 'User', :foreign_key => 'recipient_id'\n  belongs_to :sender, :class_name => 'User', :foreign_key => 'sender_id'\n\n  # Returns all active, non responded, non-expired notifications\n  named_scope :allactive, :conditions => [\"state = 0 AND (expiration is null or expiration >=?)\", Time.new.to_date]\n\n  before_create :remove_mention_duplicates\n\n  STATE_DEACTIVATED = -1\n  STATE_ACTIVE = 0\n  STATE_RESPONDED = 1\n  STATE_ARCHIVED = 2\n  STATE_RECINDED = 3\n\n  def mark_as_responded\n    self.state = STATE_RESPONDED\n    self.params = nil\n    self.save\n  end\n\n  #returns true if notification is of a mention type\n  def mention?\n    self.variation == \"mention\"\n  end\n\n  # Returns true or false based on if this user has any notifications that haven't been responded to\n  def self.unresponded?\n    self.unresponded_count > 0 ? true : false\n  end\n\n  # Returns the number of unresponded notifications for this user\n  def self.unresponded_count\n    self.count(:conditions => [\"recipient_id=? AND (expiration is null or expiration >=?) AND state = 0\", User.current, Time.new.to_date])\n  end\n\n  def self.unresponded\n    self.find(:all, :conditions => [\"recipient_id=? AND (expiration is null or expiration >=?) AND state = 0\", User.current, Time.new.to_date])\n  end\n\n  def remove_mention_duplicates\n    return unless mention?\n    Notification.update_all([\"state = ?\", STATE_ARCHIVED], {:variation => 'mention', :recipient_id => self.recipient_id, :source_id => self.source_id, :source_type => self.source_type})\n  end\n\n  # Deactivates all unanswered notifications for a particular variation and source id\n  def self.recind(variation, source_id, sender_id)\n    @notifications = self.find(:all, :conditions => [\"source_id =? AND variation =? AND state =0 AND params like'%:sender_id => ?%'\", source_id, variation, sender_id])\n    @notifications.each do |@n|\n      @n.state = STATE_RECINDED\n      @n.save\n    end\n  end\n\n  # Deactivates all unanswered notifications for a particular variation and source id\n  def self.deactivate_all(variation, source_id)\n    update_all(variation,source_id,0,STATE_DEACTIVATED)\n  end\n\n  def self.activate_all(variation, source_id)\n    update_all(variation,source_id,-1,STATE_ACTIVE)\n  end\nend\n\n\n"
  },
  {
    "path": "app/models/open_id_authentication_association.rb",
    "content": "class OpenIdAuthenticationAssociation < ActiveRecord::Base\nend\n"
  },
  {
    "path": "app/models/open_id_authentication_nonces.rb",
    "content": "class OpenIdAuthenticationNonces < ActiveRecord::Base\nend\n"
  },
  {
    "path": "app/models/personal_welcome.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass PersonalWelcome < ActiveRecord::Base\n  belongs_to :user\n\n  def self.deliver\n    projects = Project.find(:all, :conditions => \"created_at > '#{Time.now.advance :days => -7}' AND parent_id is null AND owner_id not in (select user_id from personal_welcomes)\").group_by{|p| p.owner_id}\n\n    projects.each_pair do |owner_id,project_list|\n      project_list.sort! {|x,y| x.created_at <=> y.created_at }\n      Mailer.send_later(:deliver_personal_welcome,User.find(owner_id),Project.find(project_list[0].id))\n      PersonalWelcome.create :user_id => owner_id\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/plan.rb",
    "content": "class Plan < ActiveRecord::Base\n  FREE_CODE = 0\n\n  def free?\n    return self.code == FREE_CODE\n  end\n\n  def self.free\n    find_by_code(FREE_CODE)\n  end\nend\n"
  },
  {
    "path": "app/models/plugin_schema_info.rb",
    "content": "class PluginSchemaInfo < ActiveRecord::Base\n  set_table_name 'plugin_schema_info'\nend\n"
  },
  {
    "path": "app/models/project.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Project < ActiveRecord::Base\n\n  # Project statuses\n  STATUS_ACTIVE     = 1\n  STATUS_LOCKED     = 2 #private workstream, and user is overdue\n  STATUS_ARCHIVED   = 9\n\n\n\n\n  belongs_to :enterprise\n  belongs_to :owner, :class_name => 'User', :foreign_key => 'owner_id'\n\n  # Specific overidden Activities\n  has_many :all_members,:class_name => 'Member',\n                        :include => [:user, :roles], :conditions => \"#{User.table_name}.status=#{User::STATUS_ACTIVE}\",\n                        :order => \"firstname ASC\"\n\n  has_many :administrators, :class_name => 'Member',\n                          :include => [:user,:roles],\n                          :conditions => \"#{Role.table_name}.builtin=#{Role::BUILTIN_ADMINISTRATOR}\",\n                           :order => \"firstname ASC\"\n\n  has_many :core_members, :class_name => 'Member',\n                          :include => [:user,:roles],\n                          :conditions => \"#{Role.table_name}.builtin=#{Role::BUILTIN_CORE_MEMBER}\",\n                           :order => \"firstname ASC\"\n\n\n  has_many :members, :class_name => 'Member',\n                           :include => [:user,:roles],\n                           :conditions => \"#{Role.table_name}.builtin=#{Role::BUILTIN_MEMBER}\",\n                            :order => \"firstname ASC\",\n                            :dependent => :destroy\n\n  has_many :board_members, :class_name => 'Member',\n                            :include => [:user,:roles],\n                            :conditions => \"#{Role.table_name}.builtin=#{Role::BUILTIN_BOARD}\",\n                             :order => \"firstname ASC\"\n\n  has_many :contributors, :class_name => 'Member',\n                          :include => [:user,:roles],\n                          :conditions => \"#{Role.table_name}.builtin=#{Role::BUILTIN_CONTRIBUTOR}\",\n                           :order => \"firstname ASC\"\n\n\n   has_many :binding_members, :class_name => 'Member',\n                           :include => [:user,:roles],\n                           :conditions => \"#{Role.table_name}.builtin=#{Role::BUILTIN_MEMBER} OR #{Role.table_name}.builtin=#{Role::BUILTIN_CORE_MEMBER} OR #{Role.table_name}.builtin=#{Role::BUILTIN_BOARD} OR #{Role.table_name}.builtin=#{Role::BUILTIN_ADMINISTRATOR}\",\n                            :order => \"firstname ASC\"\n\n  has_many :enterprise_members, :class_name => 'Member',\n                          :include => [:user,:roles],\n                          :conditions => \"#{Role.table_name}.builtin=#{Role::BUILTIN_CONTRIBUTOR} OR #{Role.table_name}.builtin=#{Role::BUILTIN_MEMBER} OR #{Role.table_name}.builtin=#{Role::BUILTIN_CORE_MEMBER} OR #{Role.table_name}.builtin=#{Role::BUILTIN_BOARD} OR #{Role.table_name}.builtin=#{Role::BUILTIN_ADMINISTRATOR}\",\n                           :order => \"firstname ASC\"\n\n\n  has_many :member_users, :class_name => 'Member',\n                               :include => :user,\n                               :conditions => \"#{User.table_name}.status=#{User::STATUS_ACTIVE}\",\n                               :order => \"firstname ASC\"\n\n  has_many :users, :through => :all_members\n\n  has_many :credit_distributions, :dependent => :delete_all\n  has_many :enabled_modules, :dependent => :delete_all\n  has_and_belongs_to_many :trackers, :order => \"#{Tracker.table_name}.position\"\n  has_many :issues, :dependent => :destroy, :order => \"#{Issue.table_name}.created_at DESC\", :include => [:status, :tracker]\n  has_many :issue_votes, :through => :issues\n  has_many :issue_changes, :through => :issues, :source => :journals\n  has_many :queries, :dependent => :delete_all\n  has_many :documents, :dependent => :destroy\n  has_many :news, :dependent => :delete_all, :include => :author\n  has_many :boards, :dependent => :destroy, :order => \"position ASC\"\n  has_many :messages, :through => :boards\n  has_one :wiki, :dependent => :destroy\n  has_many :shares, :dependent => :delete_all\n  has_many :credits, :dependent => :delete_all, :order => 'created_at ASC'\n  has_many :retros, :dependent => :delete_all\n  has_many :reputations, :dependent => :delete_all\n  has_many :motions, :dependent => :delete_all\n  has_many :hourly_types, :dependent => :delete_all\n  has_many :activity_streams, :dependent => :delete_all #TODO: include sub workstreams here!\n  has_many :invitations, :dependent => :delete_all\n\n  acts_as_nested_set :order => 'name', :dependent => :destroy\n  acts_as_attachable :view_permission => :view_files,\n                     :delete_permission => :manage_files\n\n  acts_as_searchable :columns => ['name', 'description'], :project_key => 'id', :permission => nil\n  acts_as_event :title => Proc.new {|o| \"#{l(:label_project)}: #{o.name}\"},\n                :url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o.id}},\n                :author => nil\n\n  acts_as_fleximage do\n    begin\n      require_image false\n      if RAILS_ENV == 'production'\n        s3_bucket 'bettermeans_workstream_logos'\n      else\n        image_directory '/public/help'\n      end\n      preprocess_image do |image|\n        image.resize '200x600'\n      end\n    rescue\n    end\n  end\n\n  attr_protected :status, :enabled_module_names\n\n  validates_presence_of :name, :identifier\n  validates_uniqueness_of :identifier\n  validates_associated :wiki\n  validates_length_of :name, :maximum => 50\n  validates_length_of :homepage, :maximum => 255\n  validates_length_of :identifier, :in => 1..20\n  # reserved words\n  validates_exclusion_of :identifier, :in => %w( new )\n\n  before_destroy :delete_all_members\n\n  named_scope :has_module, lambda { |mod| { :conditions => [\"#{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name=?)\", mod.to_s] } }\n  named_scope :active, { :conditions => \"#{Project.table_name}.status = #{STATUS_ACTIVE}\"}\n  named_scope :all_public, { :conditions => { :is_public => true } }\n  named_scope :visible, lambda { { :conditions => Project.visible_by(User.current) } }\n  named_scope :all_roots, {:conditions => \"parent_id is null\"}\n  named_scope :all_children, {:conditions => \"parent_id is not null\"}\n  named_scope :does_not_belong_to, lambda {|id|\n    {:conditions => [\"owner_id <> :s\", {:s => id}],\n     :order => 'name'\n    }\n  }\n\n  reportable :daily_new_projects, :aggregation => :count, :limit => 14\n  reportable :weekly_new_projects, :aggregation => :count, :grouping => :week, :limit => 20\n\n\n  def project_id\n    self.id\n  end\n\n  def all_tags(term = '')\n    ActsAsTaggableOn::Tag.find_by_sql([\"select name from tags inner join taggings on taggings.tag_id = tags.id where taggings.project_id = ? and name like '%#{term}%'\",self.id]).map{|t| t.name}.uniq.sort\n  end\n\n  def graph_data\n    valid_kids = children.select{|c| c.active?}\n    if valid_kids.size > 0\n      mychildren = valid_kids.collect{ |node|  node.graph_data }\n    else\n      mychildren = []\n    end\n    diameter = issues.length**0.5/3.142*6\n    { :id => self.identifier, :name => name, :children => mychildren, :data => {:$dim => diameter,:$angularWidth => diameter, :$color => '#fdd13d' } }\n  end\n\n  #returns array of project ids that are children of this project. includes id of current project\n  def sub_project_array\n    array = [self.id]\n    self.children.each do |child|\n      array += child.sub_project_array\n    end\n    array\n  end\n\n  #returns array of project ids that are children of this project. includes id of current project that are visible to user\n  def sub_project_array_visible_to(user)\n    if self.visible_to(user)\n      array = [self.id]\n    else\n      array = []\n    end\n\n    self.children.each do |child|\n      array += child.sub_project_array_visible_to(user)\n    end\n    array\n  end\n\n\n  def graph_data2\n    valid_kids = children.select{|c| c.active?}\n    if valid_kids.size > 0\n      mychildren = valid_kids.collect{ |node|  node.graph_data2 }\n    else\n      mychildren = []\n    end\n    diameter = issues.length**0.5/3.142*3\n    { :levelDistance => issues.length,:id => self.identifier, :name => name, :children => mychildren, :data => {:$dim => diameter,:$angularWidth => diameter, :$color => '#fdd13d' } }\n  end\n\n  def identifier=(identifier)\n    super unless identifier_frozen?\n  end\n\n  def identifier_frozen?\n    errors[:identifier].nil? && !(new_record? || identifier.blank?)\n  end\n\n  def self.latest_public(count=10, offset=0)\n    filter = \"#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND \" +\n      \"#{Project.table_name}.is_public = #{connection.quoted_true}\"\n\n    all_roots.find(\n      :all,\n      :limit => count,\n      :conditions => filter,\n      :order => \"created_at DESC\",\n      :offset => offset\n    )\n  end\n\n  def self.most_active_public(count=10, offset=0)\n    filter = \"#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND \" +\n      \"#{Project.table_name}.is_public = #{connection.quoted_true}\"\n\n    all_roots.find(\n      :all,\n      :limit => count,\n      :conditions => filter,\n      :order => \"activity_total DESC\",\n      :offset => offset\n    )\n  end\n\n  # returns most active projects\n  # non public projects will be returned only if user is a member of those\n  def self.most_active(user=nil, count=10, root=false, offset=0)\n    if root\n      all_roots.find(:all, :limit => count, :conditions => visible_by(user), :order => \"activity_total DESC\", :offset => offset)\n    else\n      all_children.find(:all, :limit => count, :conditions => visible_by(user), :order => \"activity_total DESC\", :offset => offset)\n    end\n  end\n\n\n  #Returns true if project is visible by user\n  def visible_to(user)\n    return true if user.admin?\n    return false unless active?\n    return true if is_public\n    return true if user.allowed_to_see_project?(self)\n    return false\n  end\n\n  # Returns a SQL :conditions string used to find all active projects for the specified user.\n  #\n  # Examples:\n  #     Projects.visible_by(admin)        => \"projects.status = 1\"\n  #     Projects.visible_by(normal_user)  => \"projects.status = 1 AND projects.is_public = 1\"\n  def self.visible_by(user=nil)\n    user ||= User.anonymous\n    if user && user.admin?\n      return \"#{Project.table_name}.status=#{Project::STATUS_ACTIVE}\"\n    elsif user && user.memberships.any?\n      return \"#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND (#{Project.table_name}.is_public = #{connection.quoted_true} or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')}))\"\n    else\n      return \"#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = #{connection.quoted_true}\"\n    end\n  end\n\n  def fetch_credits(with_subprojects)\n    with_subprojects ||= 'true'\n    if with_subprojects == 'true'\n      conditions = {}\n      conditions[:project_id] = self.sub_project_array\n      Credit.all(:conditions => conditions, :order => 'created_at ASC')\n    else\n      self.credits\n    end\n  end\n\n\n  def self.allowed_to_condition(user, permission, options={})\n    statements = []\n    base_statement = \"#{Project.table_name}.status=#{Project::STATUS_ACTIVE}\"\n    if perm = Redmine::AccessControl.permission(permission)\n      unless perm.project_module.nil?\n        # If the permission belongs to a project module, make sure the module is enabled\n        base_statement << \" AND #{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name='#{perm.project_module}')\"\n      end\n    end\n    if options[:project]\n      project_statement = \"#{Project.table_name}.id = #{options[:project].id}\"\n      project_statement << \" OR (#{Project.table_name}.lft > #{options[:project].lft} AND #{Project.table_name}.rgt < #{options[:project].rgt})\" if options[:with_subprojects]\n      base_statement = \"(#{project_statement}) AND (#{base_statement})\"\n    end\n    if user.admin?\n      # no restriction\n    else\n      statements << \"1=0\"\n      if user.logged?\n        if Role.non_member.allowed_to?(permission) && !options[:member]\n          statements << \"#{Project.table_name}.is_public = #{connection.quoted_true}\"\n        end\n        allowed_project_ids = user.memberships.select {|m| m.roles.detect {|role| role.allowed_to?(permission)}}.collect {|m| m.project_id}\n        statements << \"#{Project.table_name}.id IN (#{allowed_project_ids.join(',')})\" if allowed_project_ids.any?\n      else\n        if Role.anonymous.allowed_to?(permission) && !options[:member]\n          # anonymous user allowed on public project\n          statements << \"#{Project.table_name}.is_public = #{connection.quoted_true}\"\n        end\n      end\n    end\n    statements.empty? ? base_statement : \"((#{base_statement}) AND (#{statements.join(' OR ')}))\"\n  end\n\n  # Returns the Systemwide and project specific activities\n  def activities(include_inactive=false)\n    if include_inactive\n      return all_activities\n    else\n      return active_activities\n    end\n  end\n\n  # Returns a :conditions SQL string that can be used to find the issues associated with this project.\n  #\n  # Examples:\n  #   project.project_condition(true)  => \"(projects.id = 1 OR (projects.lft > 1 AND projects.rgt < 10))\"\n  #   project.project_condition(false) => \"projects.id = 1\"\n  def project_condition(with_subprojects)\n    cond = \"#{Project.table_name}.id = #{id}\"\n    cond = \"(#{cond} OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt}))\" if with_subprojects\n    cond\n  end\n\n  def self.find(*args)\n    if args.first && args.first.is_a?(String) && !args.first.match(/^\\d*$/)\n      project = find_by_identifier(*args)\n      raise ActiveRecord::RecordNotFound, \"Couldn't find Project with identifier=#{args.first}\" if project.nil?\n      project\n    else\n      super\n    end\n  end\n\n  def active?\n    self.status == STATUS_ACTIVE\n  end\n\n  def archived?\n    self.status == STATUS_ARCHIVED\n  end\n\n  def locked?\n    self.status == STATUS_LOCKED\n  end\n\n  def lock\n    self.update_attribute(:status, STATUS_LOCKED) if active? && !locked?\n  end\n\n  def unlock\n    self.update_attribute(:status, STATUS_ACTIVE) if locked?\n  end\n\n  def enterprise?\n    self.parent_id.nil?\n  end\n\n  # Archives the project and its descendants\n  def archive\n    Project.transaction do\n      archive!\n    end\n    true\n  end\n\n  # Unarchives the project\n  # All its ancestors must be active\n  def unarchive\n    return false if ancestors.detect {|a| !a.active?}\n    update_attribute :status, STATUS_ACTIVE\n  end\n\n  # Returns an array of projects the project can be moved to\n  # by the current user\n  def allowed_parents\n    return @allowed_parents if @allowed_parents\n    @allowed_parents = Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_subprojects))\n    @allowed_parents = @allowed_parents - self_and_descendants\n    if User.current.allowed_to?(:add_project, nil, :global => true)\n      @allowed_parents << nil\n    end\n    unless parent.nil? || @allowed_parents.empty? || @allowed_parents.include?(parent)\n      @allowed_parents << parent\n    end\n    @allowed_parents\n  end\n\n  # Sets the parent of the project with authorization check\n  def set_allowed_parent!(p)\n    unless p.nil? || p.is_a?(Project)\n      if p.to_s.blank?\n        p = nil\n      else\n        p = Project.find_by_id(p)\n        return false unless p\n      end\n    end\n    if p.nil?\n      if !new_record? && allowed_parents.empty?\n        return false\n      end\n    elsif !allowed_parents.include?(p)\n      return false\n    end\n    set_parent!(p)\n  end\n\n  # Sets the parent of the project\n  # Argument can be either a Project, a String, a Fixnum or nil\n  # WARNING: This doesn't move the children for the project, if moving a project use: move_to_child_of\n  def set_parent!(p)\n    unless p.nil? || p.is_a?(Project)\n      if p.to_s.blank?\n        p = nil\n      else\n        p = Project.find_by_id(p)\n        return false unless p\n      end\n    end\n    if p == parent && !p.nil?\n      # Nothing to do\n      true\n    elsif p.nil? || (p.active? && move_possible?(p))\n      # Insert the project so that target's children or root projects stay alphabetically sorted\n      sibs = (p.nil? ? self.class.roots : p.children)\n      to_be_inserted_before = sibs.detect {|c| c.name.to_s.downcase > name.to_s.downcase }\n      if to_be_inserted_before\n        move_to_left_of(to_be_inserted_before)\n      elsif p.nil?\n        if sibs.empty?\n          # move_to_root adds the project in first (ie. left) position\n          move_to_root\n        else\n          move_to_right_of(sibs.last) unless self == sibs.last\n        end\n      else\n        # move_to_child_of adds the project in last (ie.right) position\n        move_to_child_of(p)\n      end\n      true\n    else\n      # Can not move to the given target\n      false\n    end\n  end\n\n  # Returns an array of the trackers used by the project and its active sub projects\n  def rolled_up_trackers\n    @rolled_up_trackers ||=\n      Tracker.find(:all, :include => :projects,\n                         :select => \"DISTINCT #{Tracker.table_name}.*\",\n                         :conditions => [\"#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status = #{STATUS_ACTIVE}\", lft, rgt],\n                         :order => \"#{Tracker.table_name}.position\")\n  end\n\n  # Returns a hash of project users grouped by role\n  def users_by_role\n    all_members.find(:all, :include => [:user, :roles]).inject({}) do |h, m|\n      m.roles.each do |r|\n        h[r] ||= []\n        h[r] << m.user\n      end\n      h\n    end\n  end\n\n  # Returns a hash of active project users\n  def active_members\n    all_members.find(:all, :conditions => \"roles.builtin = #{Role::BUILTIN_ACTIVE}\",:include => [:user, :roles], :order => \"firstname ASC\")\n  end\n\n  # Returns a hash of project users with clearance\n  def clearance_members\n    all_members.find(:all, :conditions => \"roles.builtin = #{Role::BUILTIN_CLEARANCE}\",:include => [:user, :roles], :order => \"firstname ASC\")\n  end\n\n  # Returns a hash of contributers\n  def contributor_list\n    self.contributors\n  end\n\n  # Returns a hash of active project users grouped by role\n  def member_list\n    self.members\n  end\n\n  # Returns a hash of active project users grouped by role\n  def core_member_list\n    self.core_members\n  end\n\n  # Number of members who are active and have a binding vote\n  def active_binding_members_count\n    active_members = self.active_members.collect{|member| member.user_id}\n    active_binding_members_count = (self.root.core_member_list.collect{|member| member.user_id} & active_members).length\n    active_binding_members_count += (self.root.member_list.collect{|member| member.user_id} & active_members).length\n  end\n\n  def binding_members_count\n    self.root.core_member_list.count + self.root.member_list.count  + self.root.member_list.count\n  end\n\n  # returns count of all users for this role and higher roles\n  def role_and_above_count(position)\n    all_members.count(:all, :conditions => \"roles.position <= #{position}\", :group => \"user_id\").length\n  end\n\n\n  # Retrieves a list of all active users for the past (x days) and refreshes their roles\n  # Also refreshes members with clearance\n  def refresh_active_members\n    return unless self.active?\n\n    u = {}\n\n    #Adding from activity stream\n    self.activity_streams.recent.each do |as|\n      u[as.actor_id] ||= as.actor_id\n    end\n\n    #Adding voters (do we really need this?)\n    issues.each do |issue|\n      next if (issue.updated_at.advance :days => Setting::DAYS_FOR_ACTIVE_MEMBERSHIP) > Time.now\n      issue.issue_votes.each do |iv|\n        u[iv.user_id] ||= iv.user_id if (iv.updated_at.advance :days => Setting::DAYS_FOR_ACTIVE_MEMBERSHIP) > Time.now\n      end\n    end\n\n    u.delete nil\n    u.delete User.sysadmin.id\n\n    #removing active members that aren't in new list\n    self.active_members.each do |m|\n      if u[m.user_id].nil?\n        new_m = Member.find(m.id)  #for some amazing reason, I have to reload the member to get all its roles! Otherwise, I only get the active roles\n        a = new_m.role_ids\n        a.delete Role.active.id\n        new_m.role_ids = a\n      end\n    end\n\n    #adding active members that are in new list that aren't already active\n    existing_active_members = self.active_members.collect(&:user_id)\n    u.keys.each do |user_id|\n      begin\n        user = User.find(user_id)\n        user.add_to_project(self, Role.active) unless existing_active_members.include? user_id\n      rescue #user not found (when deleting users)\n      end\n    end\n\n    unless self.is_public?\n      #giving clearance to all active members\n      self.active_members.each do |m|\n        User.find(m.user_id).add_to_project(self, Role.clearance)\n      end\n\n      #giving all root binding members clearance\n      self.root.binding_members.each do |m|\n        User.find(m.user_id).add_to_project(self, Role.clearance)\n      end\n    end\n  end\n\n\n\n  # Deletes all project's members\n  def delete_all_members\n    me, mr = Member.table_name, MemberRole.table_name\n    connection.delete(\"DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.project_id = #{id})\")\n    Member.delete_all(['project_id = ?', id])\n  end\n\n  # Users issues can be assigned to\n  def assignable_users\n    all_members.select {|m| m.roles.detect {|role| role.assignable?}}.collect {|m| m.user}.sort\n  end\n\n  # Returns the mail adresses of users that should be always notified on project events\n  def recipients\n    all_members.select {|m| m.mail_notification? || m.user.mail_notification?}.collect {|m| m.user.mail}\n  end\n\n  # Returns the users that should be notified on project events\n  def notified_users\n    all_members.select {|m| m.mail_notification? || m.user.mail_notification?}.collect {|m| m.user}\n  end\n\n  def project\n    self\n  end\n\n  def <=>(project)\n    name.downcase <=> project.name.downcase\n  end\n\n  def to_s\n    name\n  end\n\n  def name_with_ancestors\n    b = []\n\n    ancestors = (project.root? ? [] : project.ancestors.visible)\n    if ancestors.any?\n      root = ancestors.shift\n      b << root.name\n      if ancestors.size > 2\n        b << '...'\n        ancestors = ancestors[-2, 2]\n      end\n      b += ancestors.collect {|p| p.name }\n    end\n    b << project.name\n    b.join( ' » ')\n  end\n\n  # Returns a short description of the projects (first lines)\n  def short_description(length = 255)\n    description.gsub(/^(.{#{length}}[^\\n\\r]*).*$/m, '\\1...').strip if description\n  end\n\n  # Return true if this project is allowed to do the specified action.\n  # action can be:\n  # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')\n  # * a permission Symbol (eg. :edit_project)\n  def allows_to?(action)\n    if action.is_a? Hash\n      allowed_actions.include? \"#{action[:controller]}/#{action[:action]}\"\n    else\n      allowed_permissions.include? action\n    end\n  end\n\n  def module_enabled?(module_name)\n    module_name = module_name.to_s\n    enabled_modules.detect {|m| m.name == module_name}\n  end\n\n  def credits_enabled?\n    !module_enabled?(:credits).nil?\n  end\n\n  def enabled_module_names=(module_names)\n    if module_names && module_names.is_a?(Array)\n      module_names = module_names.collect(&:to_s)\n      # remove disabled modules\n      enabled_modules.each {|mod| mod.destroy unless module_names.include?(mod.name)}\n      # add new modules\n      module_names.reject {|name| module_enabled?(name)}.each {|name| enabled_modules << EnabledModule.new(:name => name)}\n    else\n      enabled_modules.clear\n    end\n  end\n\n  # Returns an auto-generated project identifier based on the last identifier used\n  def self.next_identifier\n    p = Project.find(:first, :order => 'created_at DESC')\n    return 'A' if p.nil?\n\n    next_id = p.identifier.to_s.succ\n\n    while Project.exists?(:identifier => next_id)\n      next_id = next_id.succ\n    end\n\n    next_id\n\n  end\n\n  # Copies and saves the Project instance based on the +project+.\n  # Duplicates the source project's:\n  # * Wiki\n  # * Categories\n  # * Issues\n  # * Members\n  # * Queries\n  #\n  # Accepts an +options+ argument to specify what to copy\n  #\n  # Examples:\n  #   project.copy(1)                                    # => copies everything\n  #   project.copy(1, :only => 'members')                # => copies members only\n  #   project.copy(1, :only => ['members', 'versions'])  # => copies members and versions\n  def copy(project, options={})\n    project = project.is_a?(Project) ? project : Project.find(project)\n\n    to_be_copied = %w(wiki issue_categories issues members queries boards)\n    to_be_copied = to_be_copied & options[:only].to_a unless options[:only].nil?\n\n    Project.transaction do\n      if save\n        reload\n        to_be_copied.each do |name|\n          send \"copy_#{name}\", project\n        end\n        save\n      end\n    end\n  end\n\n\n  # Copies +project+ and returns the new instance.  This will not save\n  # the copy\n  def self.copy_from(project)\n    begin\n      project = project.is_a?(Project) ? project : Project.find(project)\n      if project\n        # clear unique attributes\n        attributes = project.attributes.dup.except('id', 'name', 'identifier', 'status', 'parent_id', 'lft', 'rgt')\n        copy = Project.new(attributes)\n        copy.enabled_modules = project.enabled_modules\n        copy.trackers = project.trackers\n        return copy\n      else\n        return nil\n      end\n    rescue ActiveRecord::RecordNotFound\n      return nil\n    end\n  end\n\n  def team_points_for(user, options={})\n    user.team_points_for(project)\n  end\n\n  #highest priority for open items in this project\n  def highest_pri\n    self.issues.maximum(:pri, :conditions => {:status_id => IssueStatus.open.id }) || -9999\n  end\n\n  def before_validation_on_create\n    self.enterprise_id = self.parent.enterprise_id unless self.parent.nil?\n    self.identifier = Project.next_identifier\n    self.invitation_token = Token.generate_token_value\n\n    if self.credits_enabled?\n      self.trackers = Tracker.all\n    else\n      self.trackers = Tracker.no_credits\n    end\n    return true\n  end\n\n\n\n  #Setup default forum for workstream\n  def after_create\n    logger.info { \"entering after create\" }\n    #Send notification of request or invitation to recipient\n     Board.create! :project_id => id,\n                  :name => Setting.forum_name,\n                  :description => Setting.forum_description + name\n\n    self.refresh_activity_line\n    self.save!\n    return true\n  end\n\n  def set_owner\n\n    if !self.root?\n      self.update_attribute(:owner_id,self.root.owner_id)\n    elsif owner_id.nil?\n      self.owner_id = User.current.id if self.parent_id.nil?\n      admins = self.administrators.sort {|x,y| x.created_at <=> y.created_at}\n      if admins.length > 0\n        self.owner_id = admins[0].user_id\n        self.save\n      else\n        core = self.core_members.sort {|x,y| x.created_at <=> y.created_at}\n        self.owner_id = core[0].user_id if core.length > 0\n        self.save\n      end\n    end\n  end\n\n\n  #Returns true if threshold of points that haven't been included in a retrospective have been created\n  def ready_for_retro?\n    return false if !credits_enabled?\n\n    total_unretroed = Issue.sum(:points, :conditions => {:status_id => IssueStatus.accepted.id,:retro_id => Retro::NOT_STARTED_ID, :project_id => id})\n    return true if total_unretroed >= Setting::RETRO_CREDIT_THRESHOLD\n\n    #Getting most recent issue that's not part of retrospective\n    first_issue = Issue.first(:conditions => {:project_id => self.id, :status_id => IssueStatus.accepted, :retro_id => Retro::NOT_STARTED_ID}, :order => \"updated_at asc\")\n    return false if first_issue == nil\n    return true if (first_issue.updated_at.advance :days => Setting::RETRO_DAY_THRESHOLD) < Time.now\n\n    return false\n\n  end\n\n  #Starts a new retrospective for this project\n  def start_new_retro\n    return false if !credits_enabled?\n\n    from_date = issues.first(:conditions => {:retro_id => Retro::NOT_STARTED_ID}, :order => \"updated_at ASC\").updated_at\n    total_points = issues.sum(:points, :conditions => {:retro_id => Retro::NOT_STARTED_ID})\n    @retro = Retro.create :project_id => id, :status_id => Retro::STATUS_INPROGRESS,  :to_date => DateTime.now, :from_date => from_date, :total_points => total_points\n    Issue.update_all(\"retro_id = #{@retro.id}\" , \"project_id = #{id} AND retro_id = #{Retro::NOT_STARTED_ID}\")\n    @retro.announce_start\n  end\n\n  #Starts a new retrospective if it's ready\n  def start_retro_if_ready\n    start_new_retro if ready_for_retro?\n  end\n\n  def refresh_activity_line\n    date_array = Hash.new(0)\n    for i in (1..Setting::ACTIVITY_LINE_LENGTH)\n      date_array[(Date.today - i).to_s] = 0\n    end\n\n    #All issue votes\n    iv_array = issue_votes.count(:group => 'DATE(issue_votes.created_at)', :conditions => \"issue_votes.created_at > '#{(Date.today - Setting::ACTIVITY_LINE_LENGTH).to_s}'\")\n    my_line = date_array.merge iv_array\n\n    #all issues\n    iv_array = issues.count(:group => 'DATE(issues.updated_at)', :conditions => \"issues.updated_at > '#{(Date.today - Setting::ACTIVITY_LINE_LENGTH).to_s}'\")\n    my_line + iv_array\n\n    #all board messages\n    iv_array = messages.count(:group => 'DATE(messages.updated_at)', :conditions => \"messages.updated_at > '#{(Date.today - Setting::ACTIVITY_LINE_LENGTH).to_s}'\")\n    my_line + iv_array\n\n    #all journals\n    iv_array = issue_changes.count(:group => 'DATE(journals.updated_at)', :conditions => \"journals.updated_at > '#{(Date.today - Setting::ACTIVITY_LINE_LENGTH).to_s}'\")\n    my_line + iv_array\n\n    self.children.each do |sub_project|\n      my_line + sub_project.refresh_activity_line\n    end\n\n    self.activity_line = (my_line.sort.collect {|v| v[1]}).inspect.delete(\"[\").delete(\"]\")\n    weight = 1\n    activity_total = 0\n    my_line.sort.each do |v|\n      logger.info { \"activity total #{activity_total} weight #{weight}  value #{v[1]}\" }\n      activity_total = activity_total +  (weight**1.7 * v[1])\n      weight = weight + 1\n    end\n    self.activity_total = activity_total\n    self.save\n    my_line\n  end\n\n  def activity_line_max\n    self.activity_line.split(',').max{|a,b| a.to_f <=> b.to_f}\n  end\n\n  def activity_line_show(length)\n    activity_line.split(\",\").slice(self.activity_line.split(\",\").length - length,length).join(\",\")\n  end\n\n  def volunteer?\n    return self.volunteer == true\n  end\n\n  def calculate_storage\n    sum = 0\n    documents.each do |d|\n      sum += d.size\n    end\n\n    issues.each do |d|\n      sum += d.size\n    end\n\n    self.storage = sum\n    self.save\n  end\n\n  def allowed_actions\n    @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten\n  end\n\n  def refresh_issue_count\n    self.update_attribute(:issue_count,Issue.count(:conditions => [\"project_id = ?  AND (retro_id < 0 OR retro_id is null)\", self.id]) )\n    self.parent.refresh_issue_count_sub unless self.root?\n  end\n\n  def refresh_issue_count_sub\n    count_sub = self.children.inject(0){|sum,p| sum + p.issue_count + p.issue_count_sub}\n    self.update_attribute(:issue_count_sub, count_sub)\n    self.parent.refresh_issue_count_sub unless self.root?\n  end\n\n  def update_last_item\n    self.update_attribute(:last_item_updated_on, DateTime.now)\n    self.parent.update_last_item_sub unless self.root?\n  end\n\n  def update_last_item_sub\n    self.update_attribute(:last_item_sub_updated_on, DateTime.now)\n    self.parent.update_last_item_sub unless self.root?\n  end\n\n  private\n\n  # Copies wiki from +project+\n  def copy_wiki(project)\n    # Check that the source project has a wiki first\n    unless project.wiki.nil?\n      self.wiki ||= Wiki.new\n      wiki.attributes = project.wiki.attributes.dup.except(\"id\", \"project_id\")\n      project.wiki.pages.each do |page|\n        new_wiki_content = WikiContent.new(page.content.attributes.dup.except(\"id\", \"page_id\", \"updated_at\"))\n        new_wiki_page = WikiPage.new(page.attributes.dup.except(\"id\", \"wiki_id\", \"created_at\", \"parent_id\"))\n        new_wiki_page.content = new_wiki_content\n        wiki.pages << new_wiki_page\n      end\n    end\n  end\n\n  # Copies issues from +project+\n  def copy_issues(project)\n    # Stores the source issue id as a key and the copied issues as the\n    # value.  Used to map the two togeather for issue relations.\n    issues_map = {}\n\n    project.issues.each do |issue|\n      new_issue = Issue.new\n      new_issue.copy_from(issue)\n      self.issues << new_issue\n      issues_map[issue.id] = new_issue\n    end\n\n    # Relations after in case issues related each other\n    project.issues.each do |issue|\n      new_issue = issues_map[issue.id]\n\n      # Relations\n      issue.relations_from.each do |source_relation|\n        new_issue_relation = IssueRelation.new\n        new_issue_relation.attributes = source_relation.attributes.dup.except(\"id\", \"issue_from_id\", \"issue_to_id\")\n        new_issue_relation.issue_to = issues_map[source_relation.issue_to_id]\n        if new_issue_relation.issue_to.nil? && Setting.cross_project_issue_relations?\n          new_issue_relation.issue_to = source_relation.issue_to\n        end\n        new_issue.relations_from << new_issue_relation\n      end\n\n      issue.relations_to.each do |source_relation|\n        new_issue_relation = IssueRelation.new\n        new_issue_relation.attributes = source_relation.attributes.dup.except(\"id\", \"issue_from_id\", \"issue_to_id\")\n        new_issue_relation.issue_from = issues_map[source_relation.issue_from_id]\n        if new_issue_relation.issue_from.nil? && Setting.cross_project_issue_relations?\n          new_issue_relation.issue_from = source_relation.issue_from\n        end\n        new_issue.relations_to << new_issue_relation\n      end\n    end\n  end\n\n  # Copies members from +project+\n  def copy_members(project)\n    project.all_members.each do |member|\n      new_member = Member.new\n      new_member.attributes = member.attributes.dup.except(\"id\", \"project_id\", \"created_at\")\n      new_member.role_ids = member.role_ids.dup\n      new_member.project = self\n      self.all_members << new_member\n    end\n  end\n\n  # Copies queries from +project+\n  def copy_queries(project)\n    project.queries.each do |query|\n      new_query = Query.new\n      new_query.attributes = query.attributes.dup.except(\"id\", \"project_id\", \"sort_criteria\")\n      new_query.sort_criteria = query.sort_criteria if query.sort_criteria\n      new_query.project = self\n      self.queries << new_query\n    end\n  end\n\n  # Copies boards from +project+\n  def copy_boards(project)\n    project.boards.each do |board|\n      new_board = Board.new\n      new_board.attributes = board.attributes.dup.except(\"id\", \"project_id\", \"topics_count\", \"messages_count\", \"last_message_id\")\n      new_board.project = self\n      self.boards << new_board\n    end\n  end\n\n  def allowed_permissions\n    @allowed_permissions ||= begin\n      module_names = enabled_modules.collect {|m| m.name}\n      Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name}\n    end\n  end\n\n  # Archives subprojects recursively\n  def archive!\n    children.each do |subproject|\n      subproject.send :archive!\n    end\n    update_attribute :status, STATUS_ARCHIVED\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/query.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nclass QueryColumn\n  attr_accessor :name, :sortable, :groupable, :default_order\n  include Redmine::I18n\n\n  def initialize(name, options={})\n    self.name = name\n    self.sortable = options[:sortable]\n    self.groupable = options[:groupable] || false\n    if groupable == true\n      self.groupable = name.to_s\n    end\n    self.default_order = options[:default_order]\n  end\n\n  def caption\n    l(\"field_#{name}\")\n  end\n\n  # Returns true if the column is sortable, otherwise false\n  def sortable?\n    !sortable.nil?\n  end\n\n  def value(issue)\n    issue.send name\n  end\nend\n\nclass Query < ActiveRecord::Base\n  class StatementInvalid < ::ActiveRecord::StatementInvalid\n  end\n\n  belongs_to :project\n  belongs_to :user\n  serialize :filters\n  serialize :column_names\n  serialize :sort_criteria, Array\n\n  attr_protected :project_id, :user_id\n\n  validates_presence_of :name, :on => :save\n  validates_length_of :name, :maximum => 255\n\n  @@operators = { \"=\"   => :label_equals,\n                  \"!\"   => :label_not_equals,\n                  \"o\"   => :label_open_issues,\n                  \"c\"   => :label_closed_issues,\n                  \"!*\"  => :label_none,\n                  \"*\"   => :label_all,\n                  \">=\"  => :label_greater_or_equal,\n                  \"<=\"  => :label_less_or_equal,\n                  \"<t+\" => :label_in_less_than,\n                  \">t+\" => :label_in_more_than,\n                  \"t+\"  => :label_in,\n                  \"t\"   => :label_today,\n                  \"w\"   => :label_this_week,\n                  \">t-\" => :label_less_than_ago,\n                  \"<t-\" => :label_more_than_ago,\n                  \"t-\"  => :label_ago,\n                  \"~\"   => :label_contains,\n                  \"!~\"  => :label_not_contains }\n\n  cattr_reader :operators\n\n  @@operators_by_filter_type = { :list => [ \"=\", \"!\" ],\n                                 :list_status => [ \"o\", \"=\", \"!\", \"c\", \"*\" ],\n                                 :list_optional => [ \"=\", \"!\", \"!*\", \"*\" ],\n                                 :list_subprojects => [ \"*\", \"!*\", \"=\" ],\n                                 :date => [ \"<t+\", \">t+\", \"t+\", \"t\", \"w\", \">t-\", \"<t-\", \"t-\" ],\n                                 :date_past => [ \">t-\", \"<t-\", \"t-\", \"t\", \"w\" ],\n                                 :string => [ \"=\", \"~\", \"!\", \"!~\" ],\n                                 :text => [  \"~\", \"!~\" ],\n                                 :integer => [ \"=\", \">=\", \"<=\", \"!*\", \"*\" ] }\n\n  cattr_reader :operators_by_filter_type\n\n  @@available_columns = [\n    QueryColumn.new(:project, :sortable => \"#{Project.table_name}.name\", :groupable => true),\n    QueryColumn.new(:tracker, :sortable => \"#{Tracker.table_name}.position\", :groupable => true),\n    QueryColumn.new(:status, :sortable => \"#{IssueStatus.table_name}.position\", :groupable => true),\n    QueryColumn.new(:pri, :sortable => \"#{Issue.table_name}.pri\", :default_order => 'desc', :groupable => true),\n    QueryColumn.new(:subject, :sortable => \"#{Issue.table_name}.subject\"),\n    QueryColumn.new(:author),\n    QueryColumn.new(:assigned_to, :sortable => [\"#{User.table_name}.lastname\", \"#{User.table_name}.firstname\", \"#{User.table_name}.id\"], :groupable => true),\n    QueryColumn.new(:updated_at, :sortable => \"#{Issue.table_name}.updated_at\", :default_order => 'desc'),\n    QueryColumn.new(:start_date, :sortable => \"#{Issue.table_name}.start_date\"),\n    QueryColumn.new(:due_date, :sortable => \"#{Issue.table_name}.due_date\"),\n    QueryColumn.new(:estimated_hours, :sortable => \"#{Issue.table_name}.estimated_hours\"),\n    QueryColumn.new(:created_at, :sortable => \"#{Issue.table_name}.created_at\", :default_order => 'desc'),\n  ]\n  cattr_reader :available_columns\n\n  # BUGBUG: this initialize won't work consistently:\n  # http://blog.dalethatcher.com/2008/03/rails-dont-override-initialize-on.html\n  # better to make this an after_initialize\n  def initialize(attributes = nil)\n    super attributes\n    self.filters ||= { 'status_id' => {:operator => \"o\", :values => [\"\"]} }\n  end\n\n  def after_initialize\n    # Store the fact that project is nil (used in #editable_by?)\n    @is_for_all = project.nil?\n  end\n\n  def validate\n    filters.each_key do |field|\n      errors.add label_for(field), :blank unless\n          # filter requires one or more values\n          (values_for(field) and !values_for(field).first.blank?) or\n          # filter doesn't require any value\n          [\"o\", \"c\", \"!*\", \"*\", \"t\", \"w\"].include? operator_for(field)\n    end if filters\n  end\n\n  def editable_by?(user)\n    return false unless user\n    # Admin can edit them all and regular users can edit their private queries\n    return true if user.admin? || (!is_public && self.user_id == user.id)\n    # Members can not edit public queries that are for all project (only admin is allowed to)\n    is_public && !@is_for_all && user.allowed_to?(:manage_public_queries, project)\n  end\n\n  def available_filters\n    return @available_filters if @available_filters\n\n    trackers = project.nil? ? Tracker.find(:all, :order => 'position') : project.rolled_up_trackers\n\n    @available_filters = { \"status_id\" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } },\n                           \"tracker_id\" => { :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] } },\n                           \"subject\" => { :type => :text, :order => 8 },\n                           \"created_at\" => { :type => :date_past, :order => 9 },\n                           \"updated_at\" => { :type => :date_past, :order => 10 },\n                           \"start_date\" => { :type => :date, :order => 11 },\n                           \"due_date\" => { :type => :date, :order => 12 },\n                           \"estimated_hours\" => { :type => :integer, :order => 13 }\n                         }\n\n    user_values = []\n    user_values << [\"<< #{l(:label_me)} >>\", \"me\"] if User.current.logged?\n    if project\n      user_values += project.users.sort.collect{|s| [s.name, s.id.to_s] }\n    else\n      # members of the user's projects\n      # OPTIMIZE: Is selecting from users per project (N+1)\n      user_values += User.current.projects.collect(&:users).flatten.uniq.sort.collect{|s| [s.name, s.id.to_s] }\n    end\n    @available_filters[\"assigned_to_id\"] = { :type => :list_optional, :order => 4, :values => user_values } unless user_values.empty?\n    @available_filters[\"author_id\"] = { :type => :list, :order => 5, :values => user_values } unless user_values.empty?\n\n    if User.current.logged?\n      @available_filters[\"watcher_id\"] = { :type => :list, :order => 15, :values => [[\"<< #{l(:label_me)} >>\", \"me\"]] }\n    end\n\n    if project\n      unless @project.descendants.active.empty?\n        @available_filters[\"subproject_id\"] = { :type => :list_subprojects, :order => 13, :values => @project.descendants.visible.collect{|s| [s.name, s.id.to_s] } }\n      end\n    else\n      # global filters for cross project issue list\n    end\n    @available_filters\n  end\n\n  def add_filter(field, operator, values)\n    # values must be an array\n    return unless values and values.is_a? Array\n    # check if field is defined as an available filter\n    if available_filters.has_key? field\n      filter_options = available_filters[field]\n      filters[field] = {:operator => operator, :values => values }\n    end\n  end\n\n  def add_short_filter(field, expression)\n    return unless expression\n    parms = expression.scan(/^(o|c|\\!|\\*)?(.*)$/).first\n    add_filter field, (parms[0] || \"=\"), [parms[1] || \"\"]\n  end\n\n  def has_filter?(field)\n    filters and filters[field]\n  end\n\n  def operator_for(field)\n    has_filter?(field) ? filters[field][:operator] : nil\n  end\n\n  def values_for(field)\n    has_filter?(field) ? filters[field][:values] : nil\n  end\n\n  def label_for(field)\n    label = available_filters[field][:name] if available_filters.has_key?(field)\n    label ||= field.gsub(/\\_id$/, \"\")\n  end\n\n  def available_columns\n    return @available_columns if @available_columns\n    @available_columns = Query.available_columns\n  end\n\n  # Returns an array of columns that can be used to group the results\n  def groupable_columns\n    available_columns.select {|c| c.groupable}\n  end\n\n  def columns\n    if has_default_columns?\n      available_columns.select do |c|\n        # Adds the project column by default for cross-project lists\n        Setting.issue_list_default_columns.include?(c.name.to_s) || (c.name == :project && project.nil?)\n      end\n    else\n      # preserve the column_names order\n      column_names.collect {|name| available_columns.find {|col| col.name == name}}.compact\n    end\n  end\n\n  def column_names=(names)\n    if names\n      names = names.select {|n| n.is_a?(Symbol) || !n.blank? }\n      names = names.collect {|n| n.is_a?(Symbol) ? n : n.to_sym }\n      # Set column_names to nil if default columns\n      if names.map(&:to_s) == Setting.issue_list_default_columns\n        names = nil\n      end\n    end\n    write_attribute(:column_names, names)\n  end\n\n  def has_column?(column)\n    column_names && column_names.include?(column.name)\n  end\n\n  def has_default_columns?\n    column_names.nil? || column_names.empty?\n  end\n\n  def sort_criteria=(arg)\n    c = []\n    if arg.is_a?(Hash)\n      arg = arg.keys.sort.collect {|k| arg[k]}\n    end\n    c = arg.select {|k,o| !k.to_s.blank?}.slice(0,3).collect {|k,o| [k.to_s, o == 'desc' ? o : 'asc']}\n    write_attribute(:sort_criteria, c)\n  end\n\n  def sort_criteria\n    read_attribute(:sort_criteria) || []\n  end\n\n  def sort_criteria_key(arg)\n    sort_criteria && sort_criteria[arg] && sort_criteria[arg].first\n  end\n\n  def sort_criteria_order(arg)\n    sort_criteria && sort_criteria[arg] && sort_criteria[arg].last\n  end\n\n  # Returns the SQL sort order that should be prepended for grouping\n  def group_by_sort_order\n    if grouped? && (column = group_by_column)\n      column.sortable.is_a?(Array) ?\n        column.sortable.collect {|s| \"#{s} #{column.default_order}\"}.join(',') :\n        \"#{column.sortable} #{column.default_order}\"\n    end\n  end\n\n  # Returns true if the query is a grouped query\n  def grouped?\n    !group_by.blank?\n  end\n\n  def group_by_column\n    groupable_columns.detect {|c| c.name.to_s == group_by}\n  end\n\n  def group_by_statement\n    group_by_column.groupable\n  end\n\n  def project_statement\n    project_clauses = []\n    if project && !@project.descendants.active.empty?\n      ids = [project.id]\n      if has_filter?(\"subproject_id\")\n        case operator_for(\"subproject_id\")\n        when '='\n          # include the selected subprojects\n          ids += values_for(\"subproject_id\").each(&:to_i)\n        when '!*'\n          # main project only\n        else\n          # all subprojects\n          ids += project.descendants.collect(&:id)\n        end\n      elsif Setting.display_subprojects_issues?\n        ids += project.descendants.collect(&:id)\n      end\n      project_clauses << \"#{Project.table_name}.id IN (%s)\" % ids.join(',')\n    elsif project\n      project_clauses << \"#{Project.table_name}.id = %d\" % project.id\n    end\n    project_clauses <<  Project.allowed_to_condition(User.current, :view_issues)\n    project_clauses.join(' AND ')\n  end\n\n  def statement\n    # filters clauses\n    filters_clauses = []\n    filters.each_key do |field|\n      next if field == \"subproject_id\"\n      v = values_for(field).clone\n      next unless v and !v.empty?\n      operator = operator_for(field)\n\n      # \"me\" value subsitution\n      if %w(assigned_to_id author_id watcher_id).include?(field)\n        v.push(User.current.logged? ? User.current.id.to_s : \"0\") if v.delete(\"me\")\n      end\n\n      sql = ''\n      if field == 'watcher_id'\n        db_table = Watcher.table_name\n        db_field = 'user_id'\n        sql << \"#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND \"\n        sql << sql_for_field(field, '=', v, db_table, db_field) + ')'\n      else\n        # regular field\n        db_table = Issue.table_name\n        db_field = field\n        sql << '(' + sql_for_field(field, operator, v, db_table, db_field) + ')'\n      end\n      filters_clauses << sql\n\n    end if filters and valid?\n\n    (filters_clauses << project_statement).join(' AND ')\n  end\n\n  # Returns the issue count\n  def issue_count\n    Issue.count(:include => [:status, :project], :conditions => statement)\n  rescue ::ActiveRecord::StatementInvalid => e\n    raise StatementInvalid.new(e.message)\n  end\n\n  # Returns the issue count by group or nil if query is not grouped\n  def issue_count_by_group\n    r = nil\n    if grouped?\n      begin\n        # Rails will raise an (unexpected) RecordNotFound if there's only a nil group value\n        r = Issue.count(:group => group_by_statement, :include => [:status, :project], :conditions => statement)\n      rescue ActiveRecord::RecordNotFound\n        r = {nil => issue_count}\n      end\n      c = group_by_column\n    end\n    r\n  rescue ::ActiveRecord::StatementInvalid => e\n    raise StatementInvalid.new(e.message)\n  end\n\n  # Returns the issues\n  # Valid options are :order, :offset, :limit, :include, :conditions\n  def issues(options={})\n    order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',')\n    order_option = nil if order_option.blank?\n\n    Issue.find :all, :include => ([:status, :project] + (options[:include] || [])).uniq,\n                     :conditions => Query.merge_conditions(statement, options[:conditions]),\n                     :order => order_option,\n                     :limit  => options[:limit],\n                     :offset => options[:offset]\n  rescue ::ActiveRecord::StatementInvalid => e\n    raise StatementInvalid.new(e.message)\n  end\n\n  # Returns the journals\n  # Valid options are :order, :offset, :limit\n  def journals(options={})\n    Journal.find :all, :include => [:details, :user, {:issue => [:project, :author, :tracker, :status]}],\n                       :conditions => statement,\n                       :order => options[:order],\n                       :limit => options[:limit],\n                       :offset => options[:offset]\n  rescue ::ActiveRecord::StatementInvalid => e\n    raise StatementInvalid.new(e.message)\n  end\n\n  private\n\n  # Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+\n  def sql_for_field(field, operator, value, db_table, db_field)\n    sql = ''\n    case operator\n    when \"=\"\n      sql = \"#{db_table}.#{db_field} IN (\" + value.collect{|val| \"'#{connection.quote_string(val)}'\"}.join(\",\") + \")\"\n    when \"!\"\n      sql = \"(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (\" + value.collect{|val| \"'#{connection.quote_string(val)}'\"}.join(\",\") + \"))\"\n    when \"!*\"\n      sql = \"#{db_table}.#{db_field} IS NULL\"\n    when \"*\"\n      sql = \"#{db_table}.#{db_field} IS NOT NULL\"\n    when \">=\"\n      sql = \"#{db_table}.#{db_field} >= #{value.first.to_i}\"\n    when \"<=\"\n      sql = \"#{db_table}.#{db_field} <= #{value.first.to_i}\"\n    when \"o\"\n      sql = \"#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}\" if field == \"status_id\"\n    when \"c\"\n      sql = \"#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}\" if field == \"status_id\"\n    when \">t-\"\n      sql = date_range_clause(db_table, db_field, - value.first.to_i, 0)\n    when \"<t-\"\n      sql = date_range_clause(db_table, db_field, nil, - value.first.to_i)\n    when \"t-\"\n      sql = date_range_clause(db_table, db_field, - value.first.to_i, - value.first.to_i)\n    when \">t+\"\n      sql = date_range_clause(db_table, db_field, value.first.to_i, nil)\n    when \"<t+\"\n      sql = date_range_clause(db_table, db_field, 0, value.first.to_i)\n    when \"t+\"\n      sql = date_range_clause(db_table, db_field, value.first.to_i, value.first.to_i)\n    when \"t\"\n      sql = date_range_clause(db_table, db_field, 0, 0)\n    when \"w\"\n      from = l(:general_first_day_of_week) == '7' ?\n      # week starts on sunday\n      ((Date.today.cwday == 7) ? Time.now.at_beginning_of_day : Time.now.at_beginning_of_week - 1.day) :\n        # week starts on monday (Rails default)\n        Time.now.at_beginning_of_week\n      sql = \"#{db_table}.#{db_field} BETWEEN '%s' AND '%s'\" % [connection.quoted_date(from), connection.quoted_date(from + 7.days)]\n    when \"~\"\n      sql = \"LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'\"\n    when \"!~\"\n      sql = \"LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'\"\n    end\n\n    return sql\n  end\n\n  # Returns a SQL clause for a date or datetime field.\n  def date_range_clause(table, field, from, to)\n    s = []\n    if from\n      s << (\"#{table}.#{field} > '%s'\" % [connection.quoted_date((Date.yesterday + from).to_time.end_of_day)])\n    end\n    if to\n      s << (\"#{table}.#{field} <= '%s'\" % [connection.quoted_date((Date.today + to).to_time.end_of_day)])\n    end\n    s.join(' AND ')\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/quote.rb",
    "content": "class Quote < ActiveRecord::Base\n  belongs_to :user\n\n  def self.random\n    Quote.find :first, :offset => rand(Quote.count)\n  end\nend\n"
  },
  {
    "path": "app/models/reputation.rb",
    "content": "class Reputation < ActiveRecord::Base\n  belongs_to :user\n  belongs_to :project\n\n  VARIATION_SELF_BIAS = 1\n  VARIATION_SCALE_BIAS = 2\n\n  def self.calculate_all\n    calculate(VARIATION_SELF_BIAS)\n    calculate(VARIATION_SCALE_BIAS)\n  end\n\n  def self.calculate(variation)\n    User.active.each do |user|\n      case variation\n      when VARIATION_SELF_BIAS\n        calculate_moving_average(variation,user.id)\n      when VARIATION_SCALE_BIAS\n        calculate_moving_average(variation,user.id)\n      end\n    end\n  end\n\n  #calculates a running weighted average of the reputation index\n  #more recent averages are weighed more heavily.\n  def self.calculate_moving_average(variation,user_id)\n    User.find(user_id).projects.all_roots.each do |project|\n      average = bias_moving_average(variation,user_id,project.id)\n      create_or_update(variation,user_id,average,project.id) unless average.nil?\n    end\n\n    #Platform-wide average\n    project_id = 0\n    average = bias_moving_average(variation,user_id,project_id)\n    create_or_update(variation,user_id,average,project_id) unless average.nil?\n\n  end\n\n  def self.create_or_update(variation,user_id,average,project_id)\n    reputation = Reputation.first(:conditions => {:reputation_type => variation, :user_id => user_id, :project_id => project_id})\n    if !reputation.nil?\n      reputation.value = average\n      reputation.save\n    else\n      Reputation.create :reputation_type => variation,\n                        :user_id => user_id,\n                        :project_id => project_id,\n                        :value => average\n    end\n  end\n\n\n  #Calculates a moving average for an assessment bias (in retrospectives that have their root project: project_id)\n  #When project_id is 0, moving average is calculated across all projects\n  def self.bias_moving_average(variation,user_id,project_id)\n    rr_variation = nil\n    case variation\n    when VARIATION_SELF_BIAS\n      rr_variation = RetroRating::SELF_BIAS\n    when VARIATION_SCALE_BIAS\n      rr_variation = RetroRating::SCALE_BIAS\n    end\n\n    score_total = 0\n    weight_total = 0\n    counter = Setting::LENGTH_OF_MOVING_AVERAGE\n\n    RetroRating.all(:conditions => {:ratee_id => user_id, :rater_id => rr_variation}, :include => :retro, :order => \"updated_at DESC\").each do |rr|\n      next if rr.retro.project.root.id != project_id && project_id != 0\n      weight = rr.retro.total_points * (counter.to_f/Setting::LENGTH_OF_MOVING_AVERAGE)\n      weight_total += weight\n      score_total += rr.score * weight\n      counter += -1 if counter > 1\n    end\n\n    weight_total == 0 ? nil : score_total / weight_total\n\n  end\n\nend\n"
  },
  {
    "path": "app/models/retro.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Retro < ActiveRecord::Base\n\n  include ActionController::UrlWriter\n  include ActionView::Helpers\n\n  STATUS_INPROGRESS = 1\n  STATUS_COMPLETE = 2 #is closed, but credits haven't been distributed yet\n  STATUS_DISTRIBUTED = 3 #credits have been distributed\n  STATUS_DISPUTED = 9\n  NOT_STARTED_ID = -1 #is for issues that haven't been started yet\n  NOT_NEEDED_ID = -2 #is for issues that don't need a retrospective b/c only one person worked on them (e.g gifts)\n  NOT_ENABLED_ID = -5 #is for issues that don't need a retrospective b/c credits are disabled for their workstream\n\n  #\n  # The following two statuses are for issues that aren't part of a\n  # retrospective but whose credits are given when credits are\n  # distributed in the next retrospective\n  #\n  NOT_GIVEN_AND_NOT_PART_OF_RETRO = -3\n  GIVEN_BUT_NOT_PART_OF_RETRO = -4\n\n\n\n\n  belongs_to :project\n  has_many :issues\n  has_many :journals, :through => :issues\n  has_many :issue_votes, :through => :issues\n  has_many :retro_ratings\n  has_many :credit_disributions\n\n\n\n  #Sets the from_date according to earliest updated issue in retrospective\n  def set_from_date\n    from_date = issues.first(:order => \"updated_at ASC\").updated_at\n    self.save\n  end\n\n  def ended?\n    return status_id == STATUS_COMPLETE || status_id == STATUS_DISTRIBUTED\n  end\n\n  #For closed retrospectives\n  def distribute_credits\n    return unless status_id == STATUS_COMPLETE\n    return if retro_ratings.length == 0\n    total_dollars = 0 #Total dollar amount for retrospsective\n    issues.each do |issue|\n      total_dollars+= issue.dollar_amount\n    end\n\n    retro_ratings.find_all{|retro_rating| retro_rating.rater_id == -2}.each do |rr|\n      amount = rr.score * total_dollars / 100\n      CreditDistribution.create :user_id => rr.ratee_id, :project_id => project_id, :retro_id => rr.retro_id, :amount => amount unless amount == 0\n    end\n\n    #\n    # Distribute the hourly credits\n    # They weren't a part of this retrospective but are distributed w/\n    # the other credits in this retrospective.\n    #\n    hourly_issues = project.issues.find(:all, :conditions => [\"retro_id=? AND hourly_type_id IS NOT NULL\", Retro::NOT_GIVEN_AND_NOT_PART_OF_RETRO])\n\n    hourly_issues.each do |hourly|\n      hourly.give_credits\n    end\n\n    project.issues.update_all(\"retro_id=#{Retro::GIVEN_BUT_NOT_PART_OF_RETRO}\",\n                              \"retro_id=#{Retro::NOT_GIVEN_AND_NOT_PART_OF_RETRO} AND hourly_type_id IS NOT NULL\")\n\n    self.status_id = STATUS_DISTRIBUTED\n    self.save\n  end\n\n  def close\n    return unless status_id == STATUS_INPROGRESS\n    calculate_ratings\n    announce_close\n    self.status_id = STATUS_COMPLETE\n    self.save\n    self.distribute_credits\n  end\n\n  def calculate_ratings\n    @user_hash = Hash.new\n    @user_final = Hash.new #final distribution\n    @user_self = Hash.new #self assessment\n    @user_total_bias = Hash.new #total bias\n    @confidence_hash = Hash.new\n    @confidence_array = [] #stores confidence that each rater voted with\n\n    RetroRating.delete_all :rater_id => RetroRating::TEAM_AVERAGE , :retro_id => self.id\n    RetroRating.delete_all :rater_id => RetroRating::FINAL_AVERAGE , :retro_id => self.id\n    RetroRating.delete_all :rater_id => RetroRating::SELF_BIAS , :retro_id => self.id\n    RetroRating.delete_all :rater_id => RetroRating::SCALE_BIAS , :retro_id => self.id\n\n    return if retro_ratings.length == 0\n\n    total_raters = retro_ratings.group_by{|retro_rating| retro_rating.rater_id}.length\n\n    retro_ratings.group_by{|retro_rating| retro_rating.ratee_id}.keys.each do |user_id|\n      next if user_id < 0;\n      @user_hash[user_id] = []\n      @confidence_hash[user_id] = 0\n      @confidence_array[user_id] = 0\n    end\n\n    team_confidence_total = 0\n    retro_ratings.each do |rr|\n      next if rr.rater_id < 0;\n      @user_hash[rr.ratee_id].push(rr.score * rr.confidence) unless ((rr.ratee_id == rr.rater_id) && (total_raters > 1))\n      @confidence_hash[rr.ratee_id] += rr.confidence unless ((rr.ratee_id == rr.rater_id) && (total_raters > 1))\n\n      if (rr.ratee_id == rr.rater_id)\n        @user_self[rr.ratee_id] = rr.score\n        @confidence_array[rr.rater_id] = rr.confidence\n        @user_total_bias[rr.rater_id] = 0 #initializing for later\n      end\n    end\n\n    #team averages\n    team_average_total = 0\n    @user_hash.keys.each do |user_id|\n      score = @user_hash[user_id].length == 0 ? 0 : @user_hash[user_id].sum.to_f / @confidence_hash[user_id]\n      RetroRating.create :rater_id => RetroRating::TEAM_AVERAGE, :ratee_id => user_id, :score => score, :retro_id => self.id, :confidence => @confidence_array[user_id]\n      team_average_total = team_average_total + score\n    end\n\n    #final distribution and self bias\n    @user_hash.keys.each do |user_id|\n      score = @user_hash[user_id].length == 0 ? 0 : @user_hash[user_id].sum.to_f / @confidence_hash[user_id]\n      score = score * 100 / team_average_total\n      self_bias = (@user_self[user_id] - score) * @confidence_array[user_id] / 100 unless @user_self[user_id].nil? || @user_self[user_id].nan?\n\n      @user_final[user_id] = score\n      RetroRating.create :rater_id => RetroRating::FINAL_AVERAGE, :ratee_id => user_id, :score => score, :retro_id => self.id, :confidence => @confidence_array[user_id]\n      RetroRating.create :rater_id => RetroRating::SELF_BIAS, :ratee_id => user_id, :score => self_bias, :retro_id => self.id, :confidence => @confidence_array[user_id] unless self_bias.nil? || self_bias.nan?\n    end\n\n    #total bias points\n    retro_ratings.each do |rr|\n      next if rr.rater_id < 0;\n      @user_total_bias[rr.rater_id] += (rr.score -  @user_final[rr.ratee_id]).abs\n    end\n\n    @user_total_bias.keys.each do |user_id|\n      RetroRating.create :rater_id => RetroRating::SCALE_BIAS, :ratee_id => user_id, :score => @user_total_bias[user_id] * @confidence_array[user_id] / 100, :retro_id => self.id, :confidence => @confidence_array[user_id] unless @user_total_bias[user_id].nan?\n    end\n  end\n\n  #Sends notification to everyone in the retrospective that it's starting\n  def announce_start\n    @users = {}\n\n    issues.each do |issue|\n      @users.store issue.author_id, 1 unless @users.has_key? issue.author_id\n      @users.store issue.assigned_to_id, 1 unless @users.has_key? issue.assigned_to_id\n      issue.journals.each do |journal|\n        @users.store journal.user_id, 1 unless @users.has_key? journal.user_id\n      end\n      issue.issue_votes.each do |iv|\n        @users.store iv.user_id, 1 unless @users.has_key? iv.user_id\n      end\n    end\n\n    admin = User.find(:first,:conditions => {:login => \"admin\"})\n    @users.keys.each do |user_id|\n      Notification.create :recipient_id => user_id,\n                          :variation => 'retro_started',\n                          :params => {:project => project},\n                          :sender_id => admin.id,\n                          :source_type => \"Retro\",\n                          :source_id => self.id\n    end\n  end\n\n  #Sends notification to everyone in the retrospective that it's ended\n  def announce_close\n    @users = Hash.new\n    issue_votes.each do |issue_vote|\n      @users[issue_vote.user_id] = 1 if issue_vote.vote_type == IssueVote::JOIN_VOTE_TYPE\n    end\n\n    admin = User.find(:first,:conditions => {:login => \"admin\"})\n\n    @users.keys.each do |user_id|\n      Notification.create :recipient_id => user_id,\n                          :variation => 'retro_ended',\n                          :params => {:project => project},\n                          :sender_id => admin.id,\n                          :source_type => \"Retro\",\n                          :source_id => self.id\n    end\n  end\n\n  #True when all team members in a retrospective have participated\n  def all_in?\n    rater_group = retro_ratings.group_by {|retro_rating| retro_rating.rater_id}\n    ratee_group = retro_ratings.group_by {|retro_rating| retro_rating.ratee_id}\n    return (ratee_group.length <= rater_group.length) && (rater_group.length != 0)\n  end\nend\n\n\n\n"
  },
  {
    "path": "app/models/retro_rating.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass RetroRating < ActiveRecord::Base\n\n  TEAM_AVERAGE = -1 #retro ratings with a rater id of -1 represent the team average for the ratee\n  FINAL_AVERAGE = -2 #final distribution for the ratee\n  SELF_BIAS = -3 #difference between self assesment and final average as a percentage of final\n  SCALE_BIAS = -4 #sum of differences in percentage points between user's assessment of self and others, and final average\n\n\n  belongs_to :retro\n  belongs_to :rater, :class_name => 'User', :foreign_key => 'rater_id'\n  belongs_to :ratee, :class_name => 'User', :foreign_key => 'ratee_id'\n\n  named_scope :for_project, lambda { |project_id|\n    {\n      :joins      => \"JOIN retros ON retro_id = retros.id\",\n      :conditions => \"retros.project_id = #{project_id}\"\n    }\n  }\n\nend\n\n"
  },
  {
    "path": "app/models/role.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Role < ActiveRecord::Base\n\n  # Scopes\n  LEVEL_PLATFORM = 0\n  LEVEL_ENTERPRISE = 1\n  LEVEL_PROJECT = 2\n\n  # Built-in roles\n  BUILTIN_NON_MEMBER = 1 #scope platform\n  BUILTIN_ANONYMOUS  = 2 #scope platform\n  BUILTIN_ADMINISTRATOR = 3 #scope enterprise\n  BUILTIN_CORE_MEMBER = 4 #scope enterprise\n  BUILTIN_CONTRIBUTOR = 5 #scope enterprise\n  BUILTIN_ACTIVE = 7 #scope project\n  BUILTIN_MEMBER = 8 #scope enterprise\n  BUILTIN_BOARD = 9 #scope enterprise\n  BUILTIN_CLEARANCE = 10 #scope project\n\n  named_scope :givable, { :conditions => \"builtin = 0\", :order => 'position' }\n  named_scope :builtin, lambda { |*args|\n    compare = 'not' if args.first == true\n    { :conditions => \"#{compare} builtin = 0\" }\n  }\n\n  before_destroy :check_deletable\n  has_many :workflows, :dependent => :delete_all do\n    def copy(source_role)\n      Workflow.copy(nil, source_role, nil, proxy_owner)\n    end\n  end\n\n  has_many :member_roles, :dependent => :destroy\n  has_many :members, :through => :member_roles\n  acts_as_list\n\n  serialize :permissions, Array\n\n  validates_presence_of :name\n  validates_uniqueness_of :name\n  validates_length_of :name, :maximum => 30\n  validates_format_of :name, :with => /^[\\w\\s\\'\\-]*$/i\n\n  def permissions\n    read_attribute(:permissions) || []\n  end\n\n  def permissions=(perms)\n    perms = perms.collect {|p| p.to_sym unless p.blank? }.compact.uniq if perms\n    write_attribute(:permissions, perms)\n  end\n\n  def add_permission!(*perms)\n    self.permissions = [] unless permissions.is_a?(Array)\n\n    permissions_will_change!\n    perms.each do |p|\n      p = p.to_sym\n      permissions << p unless permissions.include?(p)\n    end\n    save!\n  end\n\n  def remove_permission!(*perms)\n    return unless permissions.is_a?(Array)\n    permissions_will_change!\n    perms.each { |p| permissions.delete(p.to_sym) }\n    save!\n  end\n\n  # Returns true if the role has the given permission\n  def has_permission?(perm)\n    !permissions.nil? && permissions.include?(perm.to_sym)\n  end\n\n  def <=>(role)\n    role ? position <=> role.position : -1\n  end\n\n  def to_s\n    name\n  end\n\n  # Return true if the role is a builtin role\n  def builtin?\n    self.builtin != 0\n  end\n\n  # Return true if the role belongs to the community in any way\n  def community_member?\n    builtin == BUILTIN_CONTRIBUTOR || builtin == BUILTIN_CORE_MEMBER || builtin == BUILTIN_MEMBER || builtin == BUILTIN_ADMINISTRATOR || builtin == BUILTIN_ACTIVE  || builtin == BUILTIN_BOARD || builtin == BUILTIN_CLEARANCE\n  end\n\n  # Return true if the role belongs to the enterprise (i.e. contributor, member, coreateam, admin, or board)\n  def enterprise_member?\n    level == LEVEL_ENTERPRISE\n  end\n\n  # Return true if the role belongs to the platform (i.e. anonymous, or non member)\n  def platform_member?\n    level == LEVEL_PLATFORM\n  end\n\n  # Return true if the role is a binding member role\n  def binding_member?\n    builtin == BUILTIN_CORE_MEMBER || builtin == BUILTIN_MEMBER || builtin == BUILTIN_ADMINISTRATOR\n  end\n\n  # Return true if the role is admin\n  def admin?\n    builtin == BUILTIN_ADMINISTRATOR\n  end\n\n  # Return true if the role is a project core team member\n  def core_member?\n    builtin == BUILTIN_CORE_MEMBER\n  end\n\n  # Return true if the role is a project contributor\n  def contributor?\n    builtin == BUILTIN_CONTRIBUTOR\n  end\n\n  # Return true if the role is a project contributor\n  def member?\n    builtin == BUILTIN_MEMBER\n  end\n\n  # Return true if the role is active\n  def active?\n    builtin == BUILTIN_ACTIVE\n  end\n\n  # Return true if the role is a clearance\n  def clearance?\n    builtin == BUILTIN_CLEARANCE\n  end\n\n\n  # Return true if role is allowed to do the specified action\n  # action can be:\n  # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')\n  # * a permission Symbol (eg. :edit_project)\n  def allowed_to?(action)\n    if action.is_a? Hash\n      allowed_actions.include? \"#{action[:controller]}/#{action[:action]}\"\n    else\n      allowed_permissions.include? action\n    end\n  end\n\n  # Return all the permissions that can be given to the role\n  def setable_permissions\n    setable_permissions = Redmine::AccessControl.permissions - Redmine::AccessControl.public_permissions\n    setable_permissions -= Redmine::AccessControl.members_only_permissions if self.builtin == BUILTIN_NON_MEMBER\n    setable_permissions -= Redmine::AccessControl.loggedin_only_permissions if self.builtin == BUILTIN_ANONYMOUS\n    setable_permissions\n  end\n\n  # Find all the roles that can be given to a project member\n  def self.find_all_givable(level)\n    find(:all, :conditions => {:level => level}, :order => 'position')\n  end\n\n  # Return the builtin 'non member' role\n  def self.non_member\n    find(:first, :conditions => {:builtin => BUILTIN_NON_MEMBER}) || raise('Missing non-member builtin role.')\n  end\n\n  # Return the builtin 'anonymous' role\n  def self.anonymous\n    find(:first, :conditions => {:builtin => BUILTIN_ANONYMOUS}) || raise('Missing anonymous builtin role.')\n  end\n\n\n  # Return the builtin 'administrator' role\n  def self.administrator\n    find(:first, :conditions => {:builtin => BUILTIN_ADMINISTRATOR}) || raise('Missing Administrator builtin role.')\n  end\n\n  # Return the builtin 'board' role\n  def self.board\n    find(:first, :conditions => {:builtin => BUILTIN_BOARD}) || raise('Missing Board builtin role.')\n  end\n\n\n  # Return the builtin 'contributor' role\n  def self.contributor\n    find(:first, :conditions => {:builtin => BUILTIN_CONTRIBUTOR}) || raise('Missing contributor builtin role.')\n  end\n\n\n  # Return the builtin 'core member' role\n  def self.core_member\n    find(:first, :conditions => {:builtin => BUILTIN_CORE_MEMBER}) || raise('Missing core member builtin role.')\n  end\n\n  # Return the builtin 'member' role\n  def self.member\n    find(:first, :conditions => {:builtin => BUILTIN_MEMBER}) || raise('Missing member builtin role.')\n  end\n\n  # Return the builtin 'founder' role\n  def self.founder\n    find(:first, :conditions => {:builtin => BUILTIN_FOUNDER}) || raise('Missing founder builtin role.')\n  end\n\n  # Return the builtin 'clearance' role\n  def self.clearance\n    find(:first, :conditions => {:builtin => BUILTIN_CLEARANCE}) || raise('Missing clearance builtin role.')\n  end\n\n  # Return the builtin 'active' role\n  def self.active\n    find(:first, :conditions => {:builtin => BUILTIN_ACTIVE}) || raise('Missing active builtin role.')\n  end\n\n\n  private\n\n  def allowed_permissions\n    @allowed_permissions ||= permissions + Redmine::AccessControl.public_permissions.collect {|p| p.name}\n  end\n\n  def allowed_actions\n    @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten\n  end\n\n  def check_deletable\n    raise \"Can't delete role\" if members.any?\n    raise \"Can't delete builtin role\" if builtin?\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/setting.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Setting < ActiveRecord::Base\n\n  APP_TITLE = \"Bettermeans.com\"\n\n  TEXT_FORMATTING = \"textile\"\n\n  MAXIMUM_CONCURRENT_REQUESTS = 10 #Maximum issues same pereson can own at the same time per workstream\n\n  PAY_SCALES = {'Scale 1' => 100, 'Scale 2' => 50, 'Scale 3' => 20}\n  PAY_SCALES_DEFAULT = 100\n\n  DEFAULT_RETROSPECTIVE_LENGTH = 3 #Length in days for which a retrospective is open\n  RETRO_CREDIT_THRESHOLD = 3000 # credit threshold for  retrospective to start.\n  RETRO_DAY_THRESHOLD = 21 # day threshold for  retrospective to start (days since last retrospective ended)\n  DAY_FOR_CREDIT_DISTRIBUTION = \"Saturday\"\n\n  NUMBER_OF_STARTABLE_PRIORITY_TIERS = 3 #number of highest tiers that are startable\n\n  DAYS_FOR_ACTIVE_MEMBERSHIP = 14 #If a member does any activity on a project in the last X days, they're considered active\n\n  DAYS_FOR_LATEST_NEWS = 45 #Number of days before a news item expires\n\n  DAYS_FOR_RECENT_PROJECTS = 60 #Number of days workstreams appear if they were part of recent activity\n\n  ACTIVITY_LINE_LENGTH = 90 #number of days for activity sparklines\n\n  ACTIVITY_STREAM_LENGTH = 40 #number of actions to show before paginating\n\n  WORKSTREAM_LOCK_THRESHOLD = 30 #number of days overdue before workstreams are locked\n\n  GLOBAL_OVERUSE_THRESHOLD = 7 #number of days before which a global flash message is issued saying that user is over limits\n\n\n  #Factor by which dollars per point is multiplies e.g. a 5 point issue is worth $(POINT_FACTOR[5] * dpp)\n  POINT_FACTOR = [0.2,1,2,4,6,9,12]\n\n  #Reverse lookup. Converts credits to points\n  CREDITS_TO_POINTS = [0,1,2,3,3,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,9,10,10,10,10,10,11,11,11,11,11,11,12,12,12,12,12,12,13,13,13,13,13,13,13,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,20];\n\n  #Percentage of share that need to agree on a share-majority motion before it passes\n  SHARE_MAJORIY_MOTION_RATIO = 0.666666666\n\n  MOTIONS = {\n    Motion::VARIATION_GENERAL => {\n      \"Title\" => \"General Motion\",\n      \"Binding\" => Motion::BINDING_MEMBER,\n      \"Visible\" => Motion::VISIBLE_USER,\n      \"Type\" => Motion::TYPE_MAJORITY,\n      \"Days\" => 3\n    },\n    Motion::VARIATION_EXTRAORDINARY => {\n      \"Title\" => \"Extraordinary Motion\",\n      \"Binding\" => Motion::BINDING_USER,\n      \"Visible\" => Motion::VISIBLE_USER,\n      \"Type\" => Motion::TYPE_SHARE,\n      \"Days\" => 10\n    },\n    Motion::VARIATION_NEW_MEMBER => {\n      \"Title\" => \"Motion to elect a new Member\",\n      \"Binding\" => Motion::BINDING_CORE,\n      \"Visible\" => Motion::VISIBLE_CONTRIBUTER,\n      \"Type\" => Motion::TYPE_CONSENSUS,\n      \"Days\" => 5\n    },\n    Motion::VARIATION_FIRE_MEMBER => {\n      \"Title\" => \"Motion to remove an existing Member\",\n      \"Binding\" => Motion::BINDING_CORE,\n      \"Visible\" => Motion::VISIBLE_CONTRIBUTER,\n      \"Type\" => Motion::TYPE_CONSENSUS,\n      \"Days\" => 5\n    },\n    Motion::VARIATION_NEW_CORE => {\n      \"Title\" => \"Motion to elect a new Core Team Member\",\n      \"Binding\" => Motion::BINDING_MEMBER,\n      \"Visible\" => Motion::VISIBLE_CONTRIBUTER,\n      \"Type\" => Motion::TYPE_CONSENSUS,\n      \"Days\" => 5\n    },\n    Motion::VARIATION_FIRE_CORE => {\n      \"Title\" => \"Motion to remove an existing Core Team Member\",\n      \"Binding\" => Motion::BINDING_MEMBER,\n      \"Visible\" => Motion::VISIBLE_CONTRIBUTER,\n      \"Type\" => Motion::TYPE_CONSENSUS,\n      \"Days\" => 5\n    },\n    Motion::VARIATION_BOARD_PRIVATE => {\n      \"Title\" => \"Closed Board Motion\",\n      \"Binding\" => Motion::BINDING_BOARD,\n      \"Visible\" => Motion::VISIBLE_BOARD,\n      \"Type\" => Motion::TYPE_CONSENSUS,\n      \"Days\" => 5\n    }\n}\n\n\n  LAZY_MAJORITY_LENGTH = 3 #number of days before a lazy majority vote is counted\n\n  LAZY_MAJORITY_NO_ACTIVITY_LENGTH = 1 #number of days an item needs to have no activity on before a lazy majority move is attempted on it\n\n  #Reputation calculation constants\n\n  #lenght of window for moving averages for reputation index average calculation.\n  #example: if this number is 20, the average before last will be weighed at 19/20, the one before that at 18/20, all scores past the 20th most recent scores will be weighed at 1/20 of their value in the totaly average\n  LENGTH_OF_MOVING_AVERAGE = 20\n\n  DATE_FORMATS = [\n  '%Y-%m-%d',\n  '%d/%m/%Y',\n  '%d.%m.%Y',\n  '%d-%m-%Y',\n  '%m/%d/%Y',\n  '%d %b %Y',\n  '%d %B %Y',\n  '%b %d, %Y',\n  '%B %d, %Y'\n    ]\n\n  TIME_FORMATS = [\n    '%H:%M',\n    '%I:%M %p'\n    ]\n\n  ENCODINGS = %w(US-ASCII\n                  windows-1250\n                  windows-1251\n                  windows-1252\n                  windows-1253\n                  windows-1254\n                  windows-1255\n                  windows-1256\n                  windows-1257\n                  windows-1258\n                  windows-31j\n                  ISO-2022-JP\n                  ISO-2022-KR\n                  ISO-8859-1\n                  ISO-8859-2\n                  ISO-8859-3\n                  ISO-8859-4\n                  ISO-8859-5\n                  ISO-8859-6\n                  ISO-8859-7\n                  ISO-8859-8\n                  ISO-8859-9\n                  ISO-8859-13\n                  ISO-8859-15\n                  KOI8-R\n                  UTF-8\n                  UTF-16\n                  UTF-16BE\n                  UTF-16LE\n                  EUC-JP\n                  Shift_JIS\n                  GB18030\n                  GBK\n                  ISCII91\n                  EUC-KR\n                  Big5\n                  Big5-HKSCS\n                  TIS-620)\n\n  cattr_accessor :available_settings\n  @@available_settings = YAML::load(File.open(\"#{RAILS_ROOT}/config/settings.yml\"))\n  Redmine::Plugin.all.each do |plugin|\n    next unless plugin.settings\n    @@available_settings[\"plugin_#{plugin.id}\"] = {'default' => plugin.settings[:default], 'serialized' => true}\n  end\n\n  validates_uniqueness_of :name\n  validates_inclusion_of :name, :in => @@available_settings.keys\n  validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting| @@available_settings[setting.name]['format'] == 'int' }\n\n  # Hash used to cache setting values\n  @cached_settings = {}\n  @cached_cleared_on = Time.now\n\n  before_save :serialize_value\n\n  def value\n    @value ||= read_attribute(:value)\n    # Unserialize serialized settings\n    @value = YAML::load(@value) if @@available_settings[name]['serialized'] && @value.is_a?(String)\n    @value = @value.to_sym if @@available_settings[name]['format'] == 'symbol' && !@value.blank?\n    @value\n  end\n\n  def value=(value)\n    @value = value\n  end\n\n  def serialize_value\n    @value = @value.to_yaml if @value && @@available_settings[name]['serialized']\n    write_attribute(:value, @value.to_s)\n  end\n\n  # Returns the value of the setting named name\n  def self.[](name)\n    v = @cached_settings[name]\n    v ? v : (@cached_settings[name] = find_or_default(name).value)\n  end\n\n  def self.[]=(name, v)\n    setting = find_or_default(name)\n    setting.value = (v ? v : \"\")\n    @cached_settings[name] = nil\n    setting.save\n    setting.value\n  end\n\n  # Defines getter and setter for each setting\n  # Then setting values can be read using: Setting.some_setting_name\n  # or set using Setting.some_setting_name = \"some value\"\n  @@available_settings.each do |name, params|\n    src = <<-END_SRC\n    def self.#{name}\n      self[:#{name}]\n    end\n\n    def self.#{name}?\n      self[:#{name}].to_i > 0\n    end\n\n    def self.#{name}=(value)\n      self[:#{name}] = value\n    end\n    END_SRC\n    class_eval src, __FILE__, __LINE__\n  end\n\n  # Helper that returns an array based on per_page_options setting\n  def self.per_page_options_array\n    per_page_options.split(%r{[\\s,]}).collect(&:to_i).select {|n| n > 0}.sort\n  end\n\n  def self.openid?\n    Object.const_defined?(:OpenID) && self[:openid].to_i > 0\n  end\n\n  # Checks if settings have changed since the values were read\n  # and clears the cache hash if it's the case\n  # Called once per request\n  def self.check_cache\n    settings_updated_at = Setting.maximum(:updated_at)\n    if settings_updated_at && @cached_cleared_on <= settings_updated_at\n      @cached_settings.clear\n      @cached_cleared_on = Time.now\n    end\n  end\n\n  private\n\n  # Returns the Setting instance for the setting named name\n  # (record found in database or new record with default value)\n  def self.find_or_default(name)\n    name = name.to_s\n    raise \"There's no setting named #{name}\" unless @@available_settings.has_key?(name)\n    if @@available_settings.has_key? name\n      setting = new(:name => name)\n      setting.value = @@available_settings[name]['default']\n    end\n    setting ||= find_by_name(name)\n  end\n\nend\n\n\n"
  },
  {
    "path": "app/models/share.rb",
    "content": "class Share < ActiveRecord::Base\n\n  default_value_for :issued_on do\n    Time.now\n  end\n\n  #Constants\n  VARIATION_FOUNDER = 1 #issue when enterprise starts. don't expire\n  VARIATION_CREDIT = 2 #issued when credit is issued, expire\n\n  belongs_to :owner, :class_name => 'User', :foreign_key => 'owner_id'\n  belongs_to :project\n  named_scope :for_project, lambda { |*project_id|\n    {:conditions => {:project_id => project_id}}\n  }\n\n\n\n\n  def self.set_expiration(owner,project,amount,expiration_date)\n    remaining_amount = amount\n    Share.find(:all,:conditions => {:expires => nil, :project_id => project.id, :owner_id => owner.id, :variation => VARIATION_CREDIT}, :order => 'issued_on ASC').each do |share|\n      if share.amount <= remaining_amount\n        share.expires = expiration_date\n        remaining_amount = remaining_amount - share.amount\n        share.save\n      else\n        #More shares in this lot than we are expiring\n        unexpired_amount = Credit.round(share.amount - remaining_amount)\n        #modify the amount for this lot to the expiring amount after rounding\n        share.amount = share.amount - unexpired_amount\n        share.expires = expiration_date\n        share.save\n        #create a new lot with the remaining unexpired shares\n        Share.create! :amount => unexpired_amount, :owner => share.owner, :project => share.project, :issued_on => share.issued_on\n        break;\n      end\n    end\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/todo.rb",
    "content": "class Todo < ActiveRecord::Base\n  belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'\n  belongs_to :owner, :class_name => 'User', :foreign_key => 'owner_id'\n  belongs_to :issue\n\n  after_save :update_issue_timestamp\n\n  def update_issue_timestamp\n    issue.updated_at = DateTime.now\n    issue.save\n  end\n\nend\n\n\n"
  },
  {
    "path": "app/models/token.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Token < ActiveRecord::Base\n  belongs_to :user\n  validates_uniqueness_of :value\n\n  before_create :delete_previous_tokens\n\n  @@validity_time = 30.day\n\n  def before_create\n    self.value = Token.generate_token_value\n  end\n\n  # Return true if token has expired\n  def expired?\n    return Time.now > self.created_at + @@validity_time\n  end\n\n  # Delete all expired tokens\n  def self.destroy_expired\n    Token.delete_all [\"action <> 'feeds' AND created_at < ?\", Time.now - @@validity_time]\n  end\n\n  private\n\n  def self.generate_token_value\n    ActiveSupport::SecureRandom.hex(20)\n  end\n\n  # Removes obsolete tokens (same user and action)\n  def delete_previous_tokens\n    if user\n      Token.delete_all(['user_id = ? AND action = ?', user.id, action])\n    end\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/track.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Track < ActiveRecord::Base\n  belongs_to :user\n\n  LOGIN = 1\n\n  reportable :daily_logins, :aggregation => :count, :limit => 14, :conditions => [\"code = ?\", LOGIN]\n  reportable :weekly_logins, :aggregation => :count, :grouping => :week, :limit => 20, :conditions => [\"code = ?\", LOGIN]\n\n  def self.log(code, ip=\"\")\n    Track.send_later(:create, {:user_id => User.current.id, :code => code, :ip => ip})\n  end\nend\n"
  },
  {
    "path": "app/models/tracker.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Tracker < ActiveRecord::Base\n  before_destroy :check_integrity\n  has_many :issues\n  has_many :workflows, :dependent => :delete_all do\n    def copy(source_tracker)\n      Workflow.copy(source_tracker, nil, proxy_owner, nil)\n    end\n  end\n\n  has_and_belongs_to_many :projects\n  acts_as_list\n\n  validates_presence_of :name\n  validates_uniqueness_of :name\n  validates_length_of :name, :maximum => 30\n  validates_format_of :name, :with => /^[\\w\\s\\'\\-]*$/i\n\n  def to_s; name end\n\n  def <=>(tracker)\n    name <=> tracker.name\n  end\n\n  def self.all\n    find(:all, :order => 'position')\n  end\n\n  #All trackers except the ones that apply to the credits module\n  def self.no_credits\n    find(:all, :conditions => {:for_credits_module => false}, :order => 'position')\n  end\n\n\n  def gift?\n    name == l(:default_issue_tracker_gift)\n  end\n\n  def expense?\n    name == l(:default_issue_tracker_expense)\n  end\n\n  def recurring?\n    name == l(:default_issue_tracker_recurring)\n  end\n\n  def hourly?\n    name == l(:default_issue_tracker_hourly)\n  end\n\n  def feature?\n    name == l(:default_issue_tracker_feature)\n  end\n\n  def bug?\n    name == l(:default_issue_tracker_bug)\n  end\n\n  def chore?\n    name == l(:default_issue_tracker_chore)\n  end\n\n\n  # Returns an array of IssueStatus that are used\n  # in the tracker's workflows\n  def issue_statuses\n    if @issue_statuses\n      return @issue_statuses\n    elsif new_record?\n      return []\n    end\n\n    ids = Workflow.\n            connection.select_rows(\"SELECT DISTINCT old_status_id, new_status_id FROM #{Workflow.table_name} WHERE tracker_id = #{id}\").\n            flatten.\n            uniq\n\n    @issue_statuses = IssueStatus.find_all_by_id(ids).sort\n  end\n\n  private\n\n  def check_integrity\n    raise \"Can't delete tracker\" if Issue.find(:first, :conditions => [\"tracker_id=?\", self.id])\n  end\n\nend\n\n\n"
  },
  {
    "path": "app/models/user.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\n\nrequire \"digest/sha1\"\n\nclass User < ActiveRecord::Base\n\n  # TODO: change `mail` to `email`\n\n  # Account statuses\n  STATUS_ANONYMOUS  = 0\n  STATUS_ACTIVE     = 1\n  STATUS_REGISTERED = 2\n  STATUS_LOCKED     = 3\n  STATUS_CANCELED   = 4\n\n  USER_FORMATS = {\n    :firstname_lastname => '#{firstname} #{lastname}',\n    :firstname => '#{firstname}',\n    :lastname_firstname => '#{lastname} #{firstname}',\n    :lastname_coma_firstname => '#{lastname}, #{firstname}',\n    :username => '#{login}'\n  }\n\n  has_many :members, :foreign_key => 'user_id', :dependent => :destroy\n  has_many :memberships, :class_name => 'Member', :foreign_key => 'user_id', :include => [ :project, :roles ], :conditions => \"#{Project.table_name}.status=#{Project::STATUS_ACTIVE}\", :order => \"#{Project.table_name}.name\"\n  has_many :core_memberships, :class_name => 'Member', :foreign_key => 'user_id', :include => [ :project, :roles ], :conditions => \"#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Role.table_name}.builtin=#{Role::BUILTIN_CORE_MEMBER}\", :order => \"#{Project.table_name}.name\"\n  has_many :active_memberships, :class_name => 'Member', :foreign_key => 'user_id', :include => [ :project, :roles ], :conditions => \"#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Role.table_name}.builtin=#{Role::BUILTIN_ACTIVE}\", :order => \"#{Project.table_name}.name\"\n  has_many :projects, :through => :memberships\n  has_many :owned_projects, :class_name => 'Project', :foreign_key => 'owner_id', :include => [:all_members]\n  has_many :invitations\n  has_many :activity_streams, :foreign_key => 'actor_id', :dependent => :delete_all\n\n  # TODO: re-order relations\n  has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'\n  has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => \"action='feeds'\"\n  has_one :api_token, :dependent => :destroy, :class_name => 'Token', :conditions => \"action='api'\"\n  belongs_to :auth_source\n  belongs_to :plan\n\n  has_many :notifications, :foreign_key => 'recipient_id', :dependent => :delete_all\n\n  has_many :shares, :foreign_key => :owner_id, :dependent => :nullify\n  has_many :credits, :foreign_key => :owner_id, :dependent => :delete_all\n  has_many :issue_votes, :dependent => :delete_all\n  has_many :authored_todos, :class_name => 'Todo', :foreign_key => 'author_id', :dependent => :nullify\n  has_many :owned_todos, :class_name => 'Todo', :foreign_key => 'owner_id', :dependent => :nullify\n\n  has_many :outgoing_ratings, :class_name => 'RetroRating', :foreign_key => 'rater_id'\n  has_many :incoming_ratings, :class_name => 'RetroRating', :foreign_key => 'ratee_id'\n  has_many :credit_disributions\n  has_many :reputations, :dependent => :delete_all\n  has_many :help_sections\n  has_many :tokens\n\n  # Active non-anonymous users scope\n  # TODO: change this to use array interpolation syntax\n  named_scope :active, :conditions => \"#{User.table_name}.status = #{STATUS_ACTIVE}\"\n\n  # TODO: double check that all the columns in the :order below are indexed\n  named_scope :like, lambda {|q|\n    s = \"%#{q.to_s.strip.downcase}%\"\n    {:conditions => [\"LOWER(login) LIKE :s OR LOWER(firstname) LIKE :s OR LOWER(lastname) LIKE :s OR LOWER(mail) LIKE :s\", {:s => s}],\n     :order => 'type, login, lastname, firstname, mail'\n    }\n  }\n\n  has_private_messages :class_name => \"Mail\"\n\n  attr_accessor :password, :password_confirmation\n  attr_accessor :last_before_login_on\n  # Prevents unauthorized assignments\n  # TODO: password, password_confirmation should be mass assignable, and maybe login\n  # this would be better as attr_accessor\n  attr_protected :login, :admin, :password, :password_confirmation, :hashed_password\n\n  # BUGBUG: seems to be some bug here where it allows a nil email\n  validates_presence_of :login, :firstname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }\n  validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }\n  validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false\n  # Login must contain letters, numbers, underscores only\n  validates_format_of :login, :with => /^[a-z0-9_@\\.]*$/i\n  validates_length_of :login, :maximum => 30\n  validates_format_of :firstname, :lastname, :with => /^[\\w\\s\\'\\-\\.]*$/i\n  validates_length_of :firstname, :lastname, :maximum => 30\n  validates_format_of :mail, :with => /^([^@\\s]+)@((?:[-a-z0-9]+\\.)+[a-z]{2,})$/i, :allow_nil => true\n  validates_length_of :mail, :maximum => 60, :allow_nil => true\n  validates_confirmation_of :password, :allow_nil => true\n\n  reportable :daily_registrations, :aggregation => :count, :limit => 14\n  reportable :weekly_registrations, :aggregation => :count, :grouping => :week, :limit => 20\n\n  # ===============\n  # = CSV support =\n  # ===============\n  comma do  # implicitly named :default\n     id\n     login\n     firstname\n     lastname\n     mail\n     last_login_on\n     created_at\n     updated_at\n     plan_id\n     trial_expires_on\n     active_subscription\n  end\n\n  def <=>(user)\n    if self.class.name == user.class.name\n      self.to_s.downcase <=> user.to_s.downcase\n    else\n      # groups after users\n      user.class.name <=> self.class.name\n    end\n  end\n\n\n  def before_create\n    self.mail_notification = false\n    self.login = self.login.downcase\n    true\n  end\n\n  def before_save\n    # update hashed_password if password was set\n    self.hashed_password = User.hash_password(self.password) if self.password\n    self.mail_hash =  Digest::MD5.hexdigest(self.mail) unless mail.nil?\n  end\n\n  def after_create\n    activate_invitations\n    User.send_later(:create_recurly_account,self.id)\n  end\n\n  def activate_invitations\n    Invitation.all(:conditions => {:new_mail => self.mail}).each do |invite|\n      invite.accept\n    end\n  end\n\n\n  def after_update\n    User.send_later(:update_recurly_account,self.id)\n  end\n\n  def self.create_recurly_account(id)\n    @user = User.find(id)\n    begin\n      @account = Recurly::Account.find(@user.id)\n    rescue ActiveResource::ResourceNotFound\n      @account = Recurly::Account.create(\n        :account_code => @user.id,\n        :first_name => @user.firstname,\n        :last_name => @user.lastname,\n        :email => @user.mail,\n        :username => @user.login)\n    end\n  end\n\n  def self.update_recurly_account(id)\n    @user = User.find(id)\n\n    begin\n      @account = Recurly::Account.find(@user.id)\n    rescue ActiveResource::ResourceNotFound\n      @account = User.create_recurly_account(id)\n    end\n\n    @account.account_code = @user.id\n    @account.first_name = @user.firstname\n    @account.last_name = @user.lastname\n    @account.email = @user.mail\n    @account.username = @user.login\n    @account.save\n    @result_object = Recurly::Account.find(@account.account_code)\n  end\n\n  def save_billing(cc,ccverify,ip)\n    User.send_later(:update_recurly_billing,self.id,cc,ccverify,ip)\n  end\n\n  def self.update_recurly_billing(id,cc,ccverify,ip)\n    @user = User.find(id)\n    begin\n      @account = Recurly::Account.find(@user.id)\n    rescue ActiveResource::ResourceNotFound\n      @account = User.create_recurly_account(id)\n    end\n\n    cc.gsub!(/[^0-9]/,'') if cc\n\n    if cc && cc.length > 14\n      @account.billing_info = Recurly::BillingInfo.create(\n        :account_code => @account.account_code,\n        :first_name => @account.first_name,\n        :last_name => @account.last_name,\n        :address1 => @user.b_address1,\n        :zip => @user.b_zip,\n        :country => @user.b_country,\n        :city => \"none\",\n        :state => \"none\",\n        :phone => @user.b_phone,\n        :ip_address => ip,\n        :credit_card => {\n          :number => cc,\n          :year => @user.b_cc_year,\n          :month => @user.b_cc_month,\n          :verification_value => ccverify\n        })\n\n        return @account if @account.billing_info.errors\n\n        @user.b_cc_type = @account.billing_info.credit_card.attributes[\"type\"]\n        @user.b_cc_last_four = \"XXXX - \" + @account.billing_info.credit_card.attributes[\"last_four\"] + \" \" + @account.billing_info.credit_card.attributes[\"type\"]\n        @user.save\n      else\n        @account.billing_info = Recurly::BillingInfo.create(\n          :account_code => @account.account_code,\n          :first_name => @account.first_name,\n          :last_name => @account.last_name,\n          :address1 => @user.b_address1,\n          :zip => @user.b_zip,\n          :country => @user.b_country,\n          :city => \"none\",\n          :state => \"none\",\n          :phone => @user.b_phone,\n          :ip_address => ip)\n    end\n\n    return @account\n\n  end\n\n\n  def reload(*args)\n    @name = nil\n    super\n  end\n\n  def lock_workstreams?\n    (self.usage_over_at && self.usage_over_at.advance(:days => -1 * Setting::WORKSTREAM_LOCK_THRESHOLD) > DateTime.now) || (self.trial_expired_at && self.trial_expired_at.advance(:days => -1 *  Setting::WORKSTREAM_LOCK_THRESHOLD) > DateTime.now)\n  end\n\n  #detects if usage is way over, or trial has expired for a while, and locks out private workstreams belonging to user\n  def lock_workstreams\n    if self.lock_workstreams?\n      self.owned_projects.each {|p| p.lock unless p.is_public?}\n    end\n  end\n\n  def unlock_workstreams\n    unless self.lock_workstreams?\n      self.owned_projects.each {|p| p.unlock unless p.is_public?}\n    end\n  end\n\n  def usage_over?\n    self.project_storage_total > self.plan.storage_max || self.private_project_total > self.plan.private_workstream_max || self.private_contributor_total > self.plan.contributor_max\n  end\n\n  #detects if usage is over, and sets date of going over\n  def update_usage_over\n    is_over = self.usage_over?\n\n    self.lock_workstreams if is_over\n\n    if is_over && !self.usage_over_at\n      logger.info { \"we are over\" }\n      Notification.create :recipient_id => self.id,\n                          :variation => 'usage_over',\n                          :sender_id => User.sysadmin.id,\n                          :source_id => self.id,\n                          :source_type => \"User\"\n\n      self.update_attribute(:usage_over_at, DateTime.now)\n    end\n\n    if !is_over && self.usage_over_at\n      logger.info { \"we are not over\" }\n      Notification.delete_all(:variation => 'usage_over', :source_id => self.id)\n      self.update_attribute(:usage_over_at, nil)\n      self.unlock_workstreams\n    end\n\n  end\n\n  #detects if trial expired, and sets date of trial expiring\n  def update_trial_expiration\n    return if self.plan.free?\n\n    if !self.trial_expires_on\n      if self.trial_expired_at\n        self.update_attribute(:trial_expired_at, nil)\n        self.unlock_workstreams\n      end\n      return\n    end\n\n    if self.trial_expired_at\n      self.lock_workstreams\n      return\n    end\n\n    if DateTime.now > self.trial_expires_on\n      Notification.create :recipient_id => self.id,\n                          :variation => 'trial_expired',\n                          :sender_id => User.sysadmin.id,\n                          :source_id => self.id,\n                          :source_type => \"User\"\n\n      self.update_attribute(:trial_expired_at, DateTime.now)\n    end\n  end\n\n  def identity_url=(url)\n    if url.blank?\n      write_attribute(:identity_url, '')\n    else\n      begin\n        write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))\n      rescue OpenIdAuthentication::InvalidOpenId\n        # Invlaid url, don't save\n      end\n    end\n    self.read_attribute(:identity_url)\n  end\n\n  # Returns the user that matches provided login and password, or nil\n  def self.try_to_login(login, password)\n    # Make sure no one can sign in with an empty password\n    return nil if password.to_s.empty?\n    user = find(:first, :conditions => [\"login=?\", login.downcase])\n    if user\n      if user.auth_source\n        # user has an external authentication method\n        return nil unless user.auth_source.authenticate(login, password)\n      else\n        # authentication with local password\n        return nil unless User.hash_password(password) == user.hashed_password\n      end\n    else\n      # user is not yet registered, try to authenticate with available sources\n      attrs = AuthSource.authenticate(login, password)\n      if attrs\n        user = new(*attrs)\n        user.login = login\n        user.language = Setting.default_language\n        if user.save\n          user.reload\n        end\n      end\n    end\n    user.update_attribute(:last_login_on, Time.now) if user && !user.new_record?\n    user\n  rescue => text\n    raise text\n  end\n\n  # Returns the user who matches the given autologin +key+ or nil\n  def self.try_to_autologin(key)\n    tokens = Token.find_all_by_action_and_value('autologin', key)\n    # Make sure there's only 1 token that matches the key\n    if tokens.size == 1\n      token = tokens.first\n      if (token.created_at > Setting.autologin.to_i.day.ago) && token.user && token.user.active?\n        token.user.update_attribute(:last_login_on, Time.now)\n        token.user\n      end\n    end\n  end\n\n  # Return user's full name for display\n  def name(formatter = nil)\n    if formatter\n      eval('\"' + (USER_FORMATS[formatter] || USER_FORMATS[:firstname_lastname]) + '\"').strip\n    else\n      @name ||= eval('\"' + (USER_FORMATS[Setting.user_format] || USER_FORMATS[:firstname_lastname]) + '\"').strip\n    end\n  end\n\n  def active?\n    self.status == STATUS_ACTIVE\n  end\n\n  def reactivate\n    # TODO: don't use update_attribute, as it bypasses validations\n    self.update_attribute(:status, User::STATUS_ACTIVE)\n    newmail = []\n    # TODO: get rid of this logic\n    self.mail.split('.').each do |s|\n      break if s == 'canceled'\n      newmail.push(s)\n    end\n    newmail = newmail.join(\".\")\n    # TODO: don't use update_attribute, as it bypasses validations\n    self.update_attribute(:mail, newmail) if self.mail != newmail\n  end\n\n  def registered?\n    self.status == STATUS_REGISTERED\n  end\n\n  def lock\n    # TODO: don't use update_attribute, as it bypasses validations\n    self.update_attribute(:status, STATUS_LOCKED)\n  end\n\n  def cancel\n    self.update_attribute(:status, STATUS_CANCELED)\n    # TODO: get rid of this, not sure why we change the email\n    self.update_attribute(:mail, self.mail + \".canceled.#{rand(1000)}\")\n  end\n\n  def cancel_account!\n    cancel\n  end\n\n  def canceled?\n    status == STATUS_CANCELED\n  end\n\n  def locked?\n    self.status == STATUS_LOCKED\n  end\n\n  def check_password?(clear_password)\n    User.hash_password(clear_password) == self.hashed_password\n  end\n\n  # Generate and set a random password.  Useful for automated user creation\n  # Based on Token#generate_token_value\n  #\n  def random_password\n    chars = (\"a\"..\"z\").to_a + (\"A\"..\"Z\").to_a + (\"0\"..\"9\").to_a\n    password = ''\n    40.times { |i| password << chars[rand(chars.size-1)] }\n    self.password = password\n    self.password_confirmation = password\n    self\n  end\n\n  def pref\n    self.preference ||= UserPreference.new(:user => self)\n  end\n\n  def time_zone\n    @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])\n  end\n\n  def wants_comments_in_reverse_order?\n    self.pref[:comments_sorting] == 'desc'\n  end\n\n  # Return user's RSS key (a 40 chars long string), used to access feeds\n  def rss_key\n    token = self.rss_token || Token.create(:user => self, :action => 'feeds')\n    token.value\n  end\n\n  # Return user's API key (a 40 chars long string), used to access the API\n  def api_key\n    token = self.api_token || Token.create(:user => self, :action => 'api')\n    token.value\n  end\n\n  # Return an array of project ids for which the user has explicitly turned mail notifications on\n  def notified_projects_ids\n    @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)\n  end\n\n  def notified_project_ids=(ids)\n    Member.update_all(\"mail_notification = #{connection.quoted_false}\", ['user_id = ?', id])\n    Member.update_all(\"mail_notification = #{connection.quoted_true}\", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?\n    @notified_projects_ids = nil\n    notified_projects_ids\n  end\n\n  def self.find_by_rss_key(key)\n    token = Token.find_by_value(key)\n    token && token.user.active? ? token.user : nil\n  end\n\n  def self.find_by_api_key(key)\n    token = Token.find_by_action_and_value('api', key)\n    token && token.user.active? ? token.user : nil\n  end\n\n  # Makes find_by_mail case-insensitive\n  def self.find_by_mail(mail)\n    find(:first, :conditions => [\"LOWER(mail) = ?\", mail.to_s.downcase])\n  end\n\n  # Makes find_by_login case-insensitive\n  def self.find_by_login(login)\n    find(:first, :conditions => [\"LOWER(login) = ?\", login.to_s.downcase])\n  end\n\n  def to_s\n    name\n  end\n\n  # Returns the current day according to user's time zone\n  def today\n    if time_zone.nil?\n      Date.today\n    else\n      Time.now.in_time_zone(time_zone).to_date\n    end\n  end\n\n  def logged?\n    true\n  end\n\n  def anonymous?\n    !logged?\n  end\n\n  # Return user's roles for project\n  def roles_for_project(child_project)\n    project = child_project.root\n    roles = []\n    # No role on archived projects\n    return roles unless project && project.active?\n    if logged?\n      # Find project membership\n      membership = memberships.detect {|m| m.project_id == project.id}\n      if membership\n        roles = membership.roles\n      else\n        @role_non_member ||= Role.non_member\n        roles << @role_non_member\n      end\n    else\n      @role_anonymous ||= Role.anonymous\n      roles << @role_anonymous\n    end\n    roles\n  end\n\n  # Return true if the user is a communitymember of project\n  def community_member_of?(project)\n    !roles_for_project(project.root).detect {|role| role.community_member?}.nil?\n  end\n\n  # Return true if the user is an enterprise member of project\n  def enterprise_member_of?(project)\n    !roles_for_project(project.root).detect {|role| role.enterprise_member?}.nil?\n  end\n\n  # Return true if the user is admin of project\n   def admin_of?(project)\n     !roles_for_project(project.root).detect {|role| role.admin?}.nil?\n   end\n\n\n  # Return true if the user is a member of project\n  def member_of?(project)\n    !roles_for_project(project.root).detect {|role| role.member?}.nil?\n  end\n\n  # Return true if the user is a core member of project\n   def core_member_of?(project)\n     !roles_for_project(project.root).detect {|role| role.core_member?}.nil?\n   end\n\n   # Return true if the user is a contributor of project\n  def contributor_of?(project)\n     !roles_for_project(project.root).detect {|role| role.contributor?}.nil?\n  end\n\n  # Return true if the user's votes are binding\n  def binding_voter_of?(project)\n    !roles_for_project(project.root).detect {|role| role.binding_member?}.nil?\n  end\n\n  # Return true if the user's votes are binding for this motion\n  def binding_voter_of_motion?(motion)\n    position_for(motion.project) <= motion.binding_level.to_f\n  end\n\n  # Return true if the user is allowed to see motion\n  def allowed_to_see_motion?(motion)\n    return true if User.current == User.sysadmin\n    position_for(motion.project) <= motion.visibility_level.to_f\n  end\n\n  # Return true if the user is a allowed to see project\n  #If root project is public, then we check that user has been given explicit clearance\n  #If root project is private, then all contributors have access\n  def allowed_to_see_project?(project)\n    return true if project.is_public?\n    if project.root.is_public?\n      roles_for_project(project).detect {|role| role.binding_member? || role.clearance?}\n    else\n      roles_for_project(project).detect {|role| role.community_member?}\n    end\n  end\n\n\n  # Returns position level for user's role in project's enterprise (the lower number, the higher in heirarchy the user)\n  def position_for(project)\n    roles_for_project(project.root).sort{|x,y| x.position <=> y.position}.first.position\n  end\n\n  # Return true if the user is allowed to do the specified action on project\n  # action can be:\n  # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')\n  # * a permission Symbol (eg. :edit_project)\n  def allowed_to?(action, project, options={})\n    if project\n      # No action allowed on archived projects except unarchive\n      return false unless project.active? || project.locked? || (action.class.to_s == \"Hash\" && action[:action] == \"unarchive\")\n      # No action allowed on disabled modules\n      return false unless project.allows_to?(action)\n      # Admin users are authorized for anything else\n      return true if admin?\n\n      # #Check if user is a citizen of the enterprise, and the citizen role is allowed to take that action\n      # return true if citizen_of?(project) && Role.citizen.allowed_to?(action)\n      roles = roles_for_project(project)\n      return false unless roles\n      roles.detect {|role| role.allowed_to?(action)} && allowed_to_see_project?(project)\n    elsif options[:global]\n      # Admin users are always authorized\n      return true if admin?\n      # authorize if user has at least one role that has this permission\n      roles = memberships.collect {|m| m.roles}.flatten.uniq\n      roles.detect {|r| r.allowed_to?(action)} || (self.logged? ? Role.non_member.allowed_to?(action) : Role.anonymous.allowed_to?(action))\n    else\n      false\n    end\n  end\n\n  #Adds current user to core team of project\n  def add_as_core(project, options={})\n    #Add as core member of current project\n    add_to_project project, Role.core_member\n    drop_from_project(project, Role.contributor)\n    drop_from_project(project, Role.member)\n  end\n\n  def add_as_member(project, options={})\n    #Add as core member of current project\n    add_to_project project, Role.member\n    drop_from_project(project, Role.contributor)\n    drop_from_project(project, Role.core_member)\n  end\n\n\n  #Adds current user as contributor of project\n  def add_as_contributor(project, options={})\n      add_to_project project, Role.contributor\n      drop_from_project(project, Role.core_member)\n      drop_from_project(project, Role.member)\n  end\n\n  #Adds current user as contributor of project if they aren't a binding member\n  def add_as_contributor_if_new(project, options={})\n      add_as_contributor project unless self.binding_voter_of?(project)\n  end\n\n  #Adds user to that project as that role\n  def add_to_project(project, role, options={})\n    project = project.root if role.enterprise_member?\n    m = Member.find(:first, :conditions => {:user_id => id, :project_id => project}) #First we see if user is already a member of this project\n    if m.nil?\n      #User isn't a member let's create a membership\n      member_role = Role.find(:first, :conditions => {:id => role.id})\n      m = Member.new(:user => self, :roles => [member_role])\n      p = Project.find(project)\n      result = p.all_members << m\n    else\n      #User is already a member, we just add a role (but make sure role doesn't exist already)\n      MemberRole.create! :member_id => m.id, :role_id => role.id if MemberRole.first(:conditions => {:member_id => m.id, :role_id => role.id}) == nil\n    end\n  end\n\n  #Drops user from role of that project\n  def drop_from_project(project, role, options={})\n    m = Member.find(:first, :conditions => {:user_id => id, :project_id => project}) #First we see if user is already a member of this project\n    m.member_roles.each {|r|\n      r.destroy if r.role_id == role.id\n    } unless m.nil?\n  end\n\n  #Drops current user from core team of project\n  def drop_from_core(project, options={})\n    drop_from_project project, Role::BUILTIN_CORE_MEMBER\n  end\n\n  def self.current=(user)\n    @current_user = user\n  end\n\n  def self.current\n    @current_user ||= User.anonymous\n  end\n\n  # Returns the anonymous user.  If the anonymous user does not exist, it is created.  There can be only\n  # one anonymous user per database.\n  def self.anonymous\n    anonymous_user = AnonymousUser.find(:first)\n    if anonymous_user.nil?\n      anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)\n      raise 'Unable to create the anonymous user.' if anonymous_user.new_record?\n    end\n    anonymous_user\n  end\n\n  def self.sysadmin\n    User.find_by_login(\"admin\")\n  end\n\n  #total owned public projects\n  def public_project_total\n    self.owned_projects.find_all{|p| p.is_public  && (p.active? || p.locked?) }.length\n  end\n\n  def private_project_total\n    self.owned_projects.find_all{|p| !p.is_public && (p.active? || p.locked?) }.length\n  end\n\n  def public_contributor_total\n    @all_users = []\n    self.owned_projects.find_all{|p| p.is_public && (p.active? || p.locked?) }.each {|p| @all_users = @all_users | p.all_members.collect{|m| m.user_id}}\n    @all_users.length\n  end\n\n  def private_contributor_total\n    @all_users = []\n    self.owned_projects.find_all{|p| !p.is_public && (p.active? || p.locked?) }.each {|p| @all_users = @all_users | p.all_members.collect{|m| m.user_id}}\n    @all_users.length\n  end\n\n  def project_storage_total\n    self.owned_projects.inject(0){|sum,item| sum + item.storage}\n  end\n\n  #projects user belongs to but doesnt own\n  def belongs_to_projects\n    self.projects.does_not_belong_to(self.id)\n  end\n\n  #returns list of recent projects with a max count\n  def recent_projects(max = 10)\n    project_ids = ActivityStream.find_by_sql(\"SELECT project_id FROM activity_streams WHERE actor_id = #{self.id} AND updated_at > '#{Time.now.advance :days => (Setting::DAYS_FOR_RECENT_PROJECTS * -1)}' GROUP BY project_id ORDER BY MAX(updated_at) DESC LIMIT #{max}\").collect {|a| a.project_id}.join(\",\")\n    return [] unless project_ids.length > 0\n    Project.find(:all, :conditions => \"id in (#{project_ids})\")\n  end\n\n  #returns list of recent items with a max count of 10\n  def recent_items(max = 10)\n    item_ids = ActivityStream.find_by_sql(\"SELECT object_id FROM activity_streams WHERE actor_id = #{self.id} AND object_type = 'Issue' AND object_id is not null GROUP BY object_id ORDER BY MAX(updated_at) DESC LIMIT #{max}\").collect {|a| a[\"object_id\"]}.join(\",\")\n    return [] if item_ids.empty?\n    Issue.find(:all, :conditions => \"id in (#{item_ids})\",\n              :include => [:project, :tracker ],\n              :order => \"#{Issue.table_name}.updated_at DESC\")\n  end\n\n  def self.find_available_login(array)\n    array.each do |string|\n      string = string.gsub(/ /,\"_\").gsub(/'|\\\"|<|>/,\"_\")\n      # TODO: this can probably be optimized into a single database query\n      return string unless find_by_login(string)\n    end\n    nil\n  end\n\n  def delete_autologin_tokens\n    tokens.find_all_by_action('autologin').collect(&:delete)\n  end\n\n  def activate\n    self.status = STATUS_ACTIVE\n  end\n\n  protected\n\n  def validate\n    # Password length validation based on setting\n    if !password.nil? && password.size < Setting.password_min_length.to_i\n      errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)\n    end\n  end\n\n  private\n\n  # Return password digest\n  def self.hash_password(clear_password)\n    # TODO: somehow switch this out, SHA is not recommended for passwords\n    Digest::SHA1.hexdigest(clear_password || \"\")\n  end\n\nend\n\nclass AnonymousUser < User\n\n  def validate_on_create\n    # There should be only one AnonymousUser in the database\n    errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first)\n  end\n\n  # Overrides a few properties\n  def logged?; false end\n  def admin; false end\n  def name(*args); I18n.t(:label_user_anonymous) end\n  def mail; nil end\n  def time_zone; nil end\n  def rss_key; nil end\n  def delete_autologin_tokens; nil end\n\nend\n"
  },
  {
    "path": "app/models/user_preference.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass UserPreference < ActiveRecord::Base\n  belongs_to :user\n  serialize :others\n\n  attr_protected :others\n\n  DEFAULTS = {:no_self_notified=>true, :daily_digest=>true, :no_emails=>false,  :comments_sorting=>\"asc\", :active_only_jumps=>false}\n\n  # BUGBUG: this initialize won't work consistently\n  # when extending from ActiveRecord initialize doesn't always get called\n  # http://blog.dalethatcher.com/2008/03/rails-dont-override-initialize-on.html\n  # better to make this an after_initialize\n  def initialize(attributes = nil)\n    super\n    self.others ||= DEFAULTS\n  end\n\n  def before_save\n    self.others ||= DEFAULTS\n  end\n\n  def [](attr_name)\n    if attribute_present? attr_name\n      super\n    else\n      others ? others[attr_name] : nil\n    end\n  end\n\n  def []=(attr_name, value)\n    if attribute_present? attr_name\n      super\n    else\n      h = read_attribute(:others).dup || DEFAULTS\n      h.update(attr_name => value)\n      write_attribute(:others, h)\n      value\n    end\n  end\n\n  def comments_sorting; self[:comments_sorting] end\n  def comments_sorting=(order); self[:comments_sorting]=order end\nend\n\n\n"
  },
  {
    "path": "app/models/watcher.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Watcher < ActiveRecord::Base\n  belongs_to :watchable, :polymorphic => true\n  belongs_to :user\n\n  validates_presence_of :user\n  validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id]\n\n  # Unwatch things that users are no longer allowed to view\n  def self.prune(options={})\n    if options.has_key?(:user)\n      prune_single_user(options[:user], options)\n    else\n      pruned = 0\n      User.find(:all, :conditions => \"id IN (SELECT DISTINCT user_id FROM #{table_name})\").each do |user|\n        pruned += prune_single_user(user, options)\n      end\n      pruned\n    end\n  end\n\n  protected\n\n  def validate\n    errors.add :user_id, :invalid unless user.nil? || user.active?\n  end\n\n  private\n\n  def self.prune_single_user(user, options={})\n    return unless user.is_a?(User)\n    pruned = 0\n    find(:all, :conditions => {:user_id => user.id}).each do |watcher|\n      next if watcher.watchable.nil?\n\n      if options.has_key?(:project)\n        next unless watcher.watchable.respond_to?(:project) && watcher.watchable.project == options[:project]\n      end\n\n      if watcher.watchable.respond_to?(:visible?)\n        unless watcher.watchable.visible?(user)\n          watcher.destroy\n          pruned += 1\n        end\n      end\n    end\n    pruned\n  end\n\nend\n\n"
  },
  {
    "path": "app/models/wiki.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Wiki < ActiveRecord::Base\n  belongs_to :project\n  has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title'\n  has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all\n\n  acts_as_watchable\n\n  validates_presence_of :start_page\n  validates_format_of :start_page, :with => /^[^,\\.\\/\\?\\;\\|\\:]*$/\n\n  def visible?(user=User.current)\n    !user.nil? && user.allowed_to?(:view_wiki_pages, project)\n  end\n\n  # find the page with the given title\n  # if page doesn't exist, return a new page\n  def find_or_new_page(title)\n    title = start_page if title.blank?\n    find_page(title) || WikiPage.new(:wiki => self, :title => Wiki.titleize(title))\n  end\n\n  # find the page with the given title\n  def find_page(title, options = {})\n    title = start_page if title.blank?\n    title = Wiki.titleize(title)\n    page = pages.find_by_title(title)\n    if !page && !(options[:with_redirect] == false)\n      # search for a redirect\n      redirect = redirects.find_by_title(title)\n      page = find_page(redirect.redirects_to, :with_redirect => false) if redirect\n    end\n    page\n  end\n\n  # Finds a page by title\n  # The given string can be of one of the forms: \"title\" or \"project:title\"\n  # Examples:\n  #   Wiki.find_page(\"bar\", project => foo)\n  #   Wiki.find_page(\"foo:bar\")\n  def self.find_page(title, options = {})\n    project = options[:project]\n    if title.to_s =~ %r{^([^\\:]+)\\:(.*)$}\n      project_identifier, title = $1, $2\n      project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier)\n    end\n    if project && project.wiki\n      page = project.wiki.find_page(title)\n      if page && page.content\n        page\n      end\n    end\n  end\n\n  # turn a string into a valid page title\n  def self.titleize(title)\n    # replace spaces with _ and remove unwanted caracters\n    title = title.gsub(/\\s+/, '_').delete(',./?;|:') if title\n    # upcase the first letter\n    title = (title.slice(0..0).upcase + (title.slice(1..-1) || '')) if title\n    title\n  end\nend\n\n"
  },
  {
    "path": "app/models/wiki_content.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nrequire 'zlib'\n\nclass WikiContent < ActiveRecord::Base\n  set_locking_column :version\n  belongs_to :page, :class_name => 'WikiPage', :foreign_key => 'page_id'\n  belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'\n  validates_presence_of :text\n  validates_length_of :comments, :maximum => 255, :allow_nil => true\n\n  acts_as_versioned\n\n  def visible?(user=User.current)\n    page.visible?(user)\n  end\n\n  def project\n    page.project\n  end\n\n  # Returns the mail adresses of users that should be notified\n  def recipients\n    notified = project.notified_users\n    notified.reject! {|user| !visible?(user) || user.pref[:no_emails]}\n    notified.collect(&:mail)\n  end\n\n  class Version\n    belongs_to :page, :class_name => '::WikiPage', :foreign_key => 'page_id'\n    belongs_to :author, :class_name => '::User', :foreign_key => 'author_id'\n    attr_protected :data\n\n    acts_as_event :title => Proc.new {|o| \"#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})\"},\n                  :description => :comments,\n                  :datetime => :updated_at,\n                  :type => 'wiki-page',\n                  :url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}}\n\n    def text=(plain)\n      case Setting.wiki_compression\n      when 'gzip'\n      begin\n        self.data = Zlib::Deflate.deflate(plain, Zlib::BEST_COMPRESSION)\n        self.compression = 'gzip'\n      rescue\n        self.data = plain\n        self.compression = ''\n      end\n      else\n        self.data = plain\n        self.compression = ''\n      end\n      plain\n    end\n\n    def text\n      @text ||= case compression\n      when 'gzip'\n         Zlib::Inflate.inflate(data)\n      else\n        # uncompressed data\n        data\n      end\n    end\n\n    def project\n      page.project\n    end\n\n    # Returns the previous version or nil\n    def previous\n      @previous ||= WikiContent::Version.find(:first,\n                                              :order => 'version DESC',\n                                              :include => :author,\n                                              :conditions => [\"wiki_content_id = ? AND version < ?\", wiki_content_id, version])\n    end\n  end\nend\n\n\n"
  },
  {
    "path": "app/models/wiki_content_observer.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass WikiContentObserver < ActiveRecord::Observer\n  def after_create(wiki_content)\n    Mailer.deliver_wiki_content_added(wiki_content) if Setting.notified_events.include?('wiki_content_added')\n  end\n\n  def after_update(wiki_content)\n    if wiki_content.text_changed?\n      Mailer.deliver_wiki_content_updated(wiki_content) if Setting.notified_events.include?('wiki_content_updated')\n    end\n  end\nend\n"
  },
  {
    "path": "app/models/wiki_page.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nrequire 'diff'\nrequire 'enumerator'\n\nclass WikiPage < ActiveRecord::Base\n  belongs_to :wiki\n  has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy\n  acts_as_attachable :delete_permission => :delete_wiki_pages_attachments\n  acts_as_tree :dependent => :nullify, :order => 'title'\n\n  acts_as_watchable\n  acts_as_event :title => Proc.new {|o| \"#{l(:label_wiki)}: #{o.title}\"},\n                :description => :text,\n                :datetime => :created_at,\n                :url => Proc.new {|o| {:controller => 'wiki', :id => o.wiki.project, :page => o.title}}\n\n  acts_as_searchable :columns => ['title', 'text'],\n                     :include => [{:wiki => :project}, :content],\n                     :project_key => \"#{Wiki.table_name}.project_id\"\n\n  attr_accessor :redirect_existing_links\n\n  validates_presence_of :title\n  validates_format_of :title, :with => /^[^,\\.\\/\\?\\;\\|\\s]*$/\n  validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false\n  validates_associated :content\n\n  def project_id\n    wiki.project.id\n  end\n\n  def visible?(user=User.current)\n    !user.nil? && user.allowed_to?(:view_wiki_pages, project)\n  end\n\n  def title=(value)\n    value = Wiki.titleize(value)\n    @previous_title = read_attribute(:title) if @previous_title.blank?\n    write_attribute(:title, value)\n  end\n\n  def before_save\n    self.title = Wiki.titleize(title)\n    # Manage redirects if the title has changed\n    if !@previous_title.blank? && (@previous_title != title) && !new_record?\n      # Update redirects that point to the old title\n      wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r|\n        r.redirects_to = title\n        r.title == r.redirects_to ? r.destroy : r.save\n      end\n      # Remove redirects for the new title\n      wiki.redirects.find_all_by_title(title).each(&:destroy)\n      # Create a redirect to the new title\n      wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == \"0\"\n      @previous_title = nil\n    end\n  end\n\n  def before_destroy\n    # Remove redirects to this page\n    wiki.redirects.find_all_by_redirects_to(title).each(&:destroy)\n  end\n\n  def pretty_title\n    WikiPage.pretty_title(title)\n  end\n\n  def content_for_version(version=nil)\n    result = content.versions.find_by_version(version.to_i) if version\n    result ||= content\n    result\n  end\n\n  def diff(version_to=nil, version_from=nil)\n    version_to = version_to ? version_to.to_i : self.content.version\n    version_from = version_from ? version_from.to_i : version_to - 1\n    version_to, version_from = version_from, version_to unless version_from < version_to\n\n    content_to = content.versions.find_by_version(version_to)\n    content_from = content.versions.find_by_version(version_from)\n\n    (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil\n  end\n\n  def annotate(version=nil)\n    version = version ? version.to_i : self.content.version\n    c = content.versions.find_by_version(version)\n    c ? WikiAnnotate.new(c) : nil\n  end\n\n  def self.pretty_title(str)\n    (str && str.is_a?(String)) ? str.tr('_', ' ') : str\n  end\n\n  def project\n    wiki.project\n  end\n\n  def text\n    content.text if content\n  end\n\n  # Returns true if usr is allowed to edit the page, otherwise false\n  def editable_by?(usr)\n    !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)\n  end\n\n  def attachments_deletable?(usr=User.current)\n    editable_by?(usr) && super(usr)\n  end\n\n  def parent_title\n    @parent_title || (self.parent && self.parent.pretty_title)\n  end\n\n  def parent_title=(t)\n    @parent_title = t\n    parent_page = t.blank? ? nil : self.wiki.find_page(t)\n    self.parent = parent_page\n  end\n\n  protected\n\n  def validate\n    errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil?\n    errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self))\n    errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id)\n  end\nend\n\nclass WikiDiff\n  attr_reader :diff, :words, :content_to, :content_from\n\n  def initialize(content_to, content_from)\n    @content_to = content_to\n    @content_from = content_from\n    @words = content_to.text.split(/(\\s+)/)\n    @words = @words.select {|word| word != ' '}\n    words_from = content_from.text.split(/(\\s+)/)\n    words_from = words_from.select {|word| word != ' '}\n    @diff = words_from.diff @words\n  end\nend\n\nclass WikiAnnotate\n  attr_reader :lines, :content\n\n  def initialize(content)\n    @content = content\n    current = content\n    current_lines = current.text.split(/\\r?\\n/)\n    @lines = current_lines.collect {|t| [nil, nil, t]}\n    positions = []\n    current_lines.size.times {|i| positions << i}\n    while (current.previous)\n      d = current.previous.text.split(/\\r?\\n/).diff(current.text.split(/\\r?\\n/)).diffs.flatten\n      d.each_slice(3) do |s|\n        sign, line = s[0], s[1]\n        if sign == '+' && positions[line] && positions[line] != -1\n          if @lines[positions[line]][0].nil?\n            @lines[positions[line]][0] = current.version\n            @lines[positions[line]][1] = current.author\n          end\n        end\n      end\n      d.each_slice(3) do |s|\n        sign, line = s[0], s[1]\n        if sign == '-'\n          positions.insert(line, -1)\n        else\n          positions[line] = nil\n        end\n      end\n      positions.compact!\n      # Stop if every line is annotated\n      break unless @lines.detect { |line| line[0].nil? }\n      current = current.previous\n    end\n    @lines.each { |line| line[0] ||= current.version }\n  end\nend\n\n"
  },
  {
    "path": "app/models/wiki_redirect.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass WikiRedirect < ActiveRecord::Base\n  belongs_to :wiki\n\n  validates_presence_of :title, :redirects_to\n  validates_length_of :title, :redirects_to, :maximum => 255\nend\n\n"
  },
  {
    "path": "app/models/workflow.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Workflow < ActiveRecord::Base\n  belongs_to :role\n  belongs_to :old_status, :class_name => 'IssueStatus', :foreign_key => 'old_status_id'\n  belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id'\n\n  validates_presence_of :role, :old_status, :new_status\n\n  # Returns workflow transitions count by tracker and role\n  def self.count_by_tracker_and_role\n    counts = connection.select_all(\"SELECT role_id, tracker_id, count(id) AS c FROM #{Workflow.table_name} GROUP BY role_id, tracker_id\")\n    roles = Role.find(:all, :order => 'builtin, position')\n    trackers = Tracker.find(:all, :order => 'position')\n\n    result = []\n    trackers.each do |tracker|\n      t = []\n      roles.each do |role|\n        row = counts.detect {|c| c['role_id'] == role.id.to_s && c['tracker_id'] == tracker.id.to_s}\n        t << [role, (row.nil? ? 0 : row['c'].to_i)]\n      end\n      result << [tracker, t]\n    end\n\n    result\n  end\n\n  # Find potential statuses the user could be allowed to switch issues to\n  def self.available_statuses(project, user=User.current)\n    Workflow.find(:all,\n                  :include => :new_status,\n                  :conditions => {:role_id => user.roles_for_project(project).collect(&:id)}).\n      collect(&:new_status).\n      compact.\n      uniq.\n      sort\n  end\n\n  # Copies workflows from source to targets\n  def self.copy(source_tracker, source_role, target_trackers, target_roles)\n    unless source_tracker.is_a?(Tracker) || source_role.is_a?(Role)\n      raise ArgumentError.new(\"source_tracker or source_role must be specified\")\n    end\n\n    target_trackers = [target_trackers].flatten.compact\n    target_roles = [target_roles].flatten.compact\n\n    target_trackers = Tracker.all if target_trackers.empty?\n    target_roles = Role.all if target_roles.empty?\n\n    target_trackers.each do |target_tracker|\n      target_roles.each do |target_role|\n        copy_one(source_tracker || target_tracker,\n                   source_role || target_role,\n                   target_tracker,\n                   target_role)\n      end\n    end\n  end\n\n  # Copies a single set of workflows from source to target\n  def self.copy_one(source_tracker, source_role, target_tracker, target_role)\n    unless source_tracker.is_a?(Tracker) && !source_tracker.new_record? &&\n      source_role.is_a?(Role) && !source_role.new_record? &&\n      target_tracker.is_a?(Tracker) && !target_tracker.new_record? &&\n      target_role.is_a?(Role) && !target_role.new_record?\n\n      raise ArgumentError.new(\"arguments can not be nil or unsaved objects\")\n    end\n\n    if source_tracker == target_tracker && source_role == target_role\n      false\n    else\n      transaction do\n        delete_all :tracker_id => target_tracker.id, :role_id => target_role.id\n        connection.insert \"INSERT INTO #{Workflow.table_name} (tracker_id, role_id, old_status_id, new_status_id)\" +\n                          \" SELECT #{target_tracker.id}, #{target_role.id}, old_status_id, new_status_id\" +\n                          \" FROM #{Workflow.table_name}\" +\n                          \" WHERE tracker_id = #{source_tracker.id} AND role_id = #{source_role.id}\"\n      end\n      true\n    end\n  end\nend\n\n"
  },
  {
    "path": "app/views/account/login.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n   <%= render :partial => '/home/header', :locals => {:page => 'login'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <%= render_flash_messages %>\n\n\n\n<!--[if lt IE 11]>\n<div style='border: 1px solid #F7941D; background: #FEEFDA; text-align: center; clear: both; height: 75px; position: relative;'>\n  <div style='position: absolute; right: 3px; top: 3px; font-family: courier new; font-weight: bold;'><a href='#' onclick='javascript:this.parentNode.parentNode.style.display=\"none\"; return false;'><img src='/images/static/ie6nomore-cornerx.jpg' style='border: none;' alt='Close this notice'/></a></div>\n  <div style='width: 640px; margin: 0 auto; text-align: left; padding: 0; overflow: hidden; color: black;'>\n    <div style='width: 75px; float: left;'><img src='/images/static/ie6nomore-warning.jpg' alt='Warning!'/></div>\n    <div style='width: 275px; float: left; font-family: Arial, sans-serif;'>\n      <div style='font-size: 14px; font-weight: bold; margin-top: 12px;'>You are using an unsuported browser</div>\n      <div style='font-size: 12px; margin-top: 6px; line-height: 12px;'>For a better experience using this site, please switch to a supported web browser.</div>\n    </div>\n    <div style='width: 75px; float: left;'><a href='http://www.firefox.com' target='_blank'><img src='/images/static/ie6nomore-firefox.jpg' style='border: none;' alt='Get Firefox 3.5'/></a></div>\n    <div style='width: 73px; float: left;'><a href='http://www.apple.com/safari/download/' target='_blank'><img src='/images/static/ie6nomore-safari.jpg' style='border: none;' alt='Get Safari 4'/></a></div>\n    <div style='float: left;'><a href='http://www.google.com/chrome' target='_blank'><img src='/images/static/ie6nomore-chrome.jpg' style='border: none;' alt='Get Google Chrome'/></a></div>\n  </div>\n</div>\n<![endif]-->\n\n    <div class=\"gt-login-hd\">\n      &nbsp;&nbsp;&nbsp;&nbsp;You're here, that makes us happy\n    </div>\n\n    <div class=\"gt-login-box\">\n        <%=RPXNow.embed_code('bettermeans', url_for(:controller=>:accounts, :action=>:rpx_token, :only_path => false, :protocol => login_protocol))%>\n        <br><br><br>\n        <div class=\"signup-header\">or login using your account</div>\n\n      <p class=\"space\">\n        <% if Setting.autologin? %>\n        <span><label for=\"autologin\"></label>\n        </span>\n        <% end %>\n      </p>\n\n      <% form_tag({:action=> \"login\"}, :class => \"gt-form\") do %>\n        <%= back_url_hidden_field_tag %>\n        <%= hidden_field_tag 'invitation_token', @invitation_token %>\n        <div class=\"gt-form-row\">\n          <label for=\"username\" class=\"gt-login-label\"><%=l(:field_login)%></label>\n          <%= text_field_tag 'username', nil, :tabindex => '1', :class => \"gt-form-text\" %>\n        </div>\n\n        <div class=\"gt-form-row\">\n          <label for=\"password\" class=\"gt-login-label\"><%=l(:field_password)%></label>\n          <%= password_field_tag 'password', nil, :tabindex => '2', :class => \"gt-form-text\" %>\n        </div>\n\n        <div class=\"gt-form-row\">\n\n          <label class=\"gt-remember-me\"><%= check_box_tag 'autologin', 1, false, :tabindex => 4, :class => \"gt-form-checkbox\" %> <%= l(:label_stay_logged_in, {:class => \"gt-remember-me\"}) %></label>\n\n          <input type=\"submit\" name=\"login\" class=\"gt-btn-gray-medium gt-btn-right\" style=\"float:right\" value=\"<%=l(:button_login)%> &#187;\" tabindex=\"5\"/>\n        </div>\n\n        <p class=\"gt-forgot-password\"><%= link_to l(:label_register), { :controller => 'account', :action => 'register' } %>\n        <span class=\"lost\">&nbsp;|&nbsp; </span>\n        <%= link_to l(:label_password_lost), {:controller => 'account', :action => 'lost_password'} %>\n        </p>\n\n      <% end %>\n    </div>\n<%= javascript_tag \"$('#username').focus();\" %>\n</div></div></div>\n"
  },
  {
    "path": "app/views/account/lost_password.html.erb",
    "content": "<h2><%=l(:label_password_lost)%></h2>\n\n<div class=\"gt-content-box padded\">\n<% form_tag({:action=> \"lost_password\"}, :class => \"tabular\") do %>\n\n<p><label for=\"mail\"><%=l(:field_mail)%> <span class=\"required\">*</span></label>\n<%= text_field_tag 'mail', nil, :size => 40 %>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_submit), :disable_with => l(:button_working) %></p>\n</div>\n<% end %>\n</div>\n"
  },
  {
    "path": "app/views/account/password_recovery.html.erb",
    "content": "<h2><%=l(:label_password_lost)%></h2>\n\n<%= error_messages_for 'user' %>\n\n<% form_tag({:token => @token.value}) do %>\n<div class=\"gt-content-box tabular\">\n<p><label for=\"new_password\"><%=l(:field_new_password)%> <span class=\"required\">*</span></label>\n<%= password_field_tag 'new_password', nil, :size => 25 %><br />\n<em><%= l(:text_caracters_minimum, 4) %></em></p>\n\n<p><label for=\"new_password_confirmation\"><%=l(:field_password_confirmation)%> <span class=\"required\">*</span></label>\n<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %></p>\n</div>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/account/register.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n   <%= render :partial => '/home/header', :locals => {:page => 'register'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n<%= render_flash_messages %>\n<div class=\"gt-login-box\">\n\n  <%=RPXNow.embed_code('bettermeans', url_for(:controller=>:accounts, :action=>:rpx_token, :invitation_token => params[:invitation_token], :only_path => false, :protocol => login_protocol))%>\n<% form_tag({:action => 'register'}, :class => \"tabular\") do %>\n<%= error_messages_for 'user' %>\n\n<div class=\"signup-header\">or create an account</div><br>\n\n<% if @user.auth_source_id.nil? %>\n<p><label for=\"user_login\"><%=l(:field_login)%> <span class=\"required\">*</span></label>\n<%= text_field 'user', 'login', :size => 25 %></p>\n\n<p><label for=\"password\"><%=l(:field_password)%> <span class=\"required\">*</span></label>\n<%= password_field_tag 'password', nil, :size => 25  %><br />\n<em><%= l(:text_caracters_minimum, :count => Setting.password_min_length) %></em></p>\n\n<p><label for=\"password_confirmation\"><%=l(:field_password_confirmation)%> <span class=\"required\">*</span></label>\n<%= password_field_tag 'password_confirmation', nil, :size => 25  %></p>\n<% end %>\n\n<p><label for=\"user_firstname\"><%=l(:field_firstname)%> <span class=\"required\">*</span></label>\n<%= text_field 'user', 'firstname'  %></p>\n\n<p><label for=\"user_lastname\"><%=l(:field_lastname)%> <span class=\"required\">*</span></label>\n<%= text_field 'user', 'lastname'  %></p>\n\n<p><label for=\"user_mail\"><%=l(:field_mail)%> <span class=\"required\">*</span></label>\n</p>\n<%= text_field 'user', 'mail' %></p>\n\n<div class=\"gt-form-row\">\n  <%= submit_tag l(:button_signup), :class => \"gt-btn-gray-medium gt-btn-right right\", :style => \"float:right;\", :disable_with => l(:button_working)  %>\n  <p>&nbsp;</p>\n</div>\n\n<%= hidden_field_tag 'invitation_token', params[:invitation_token] %>\n<%= hidden_field_tag 'plan_id', @plan_id %>\n<br><br>\n<div class=\"gt-form-row\">\n  <br>\n  <label>By signing up you indicate that you have read and agreed to the <a href=\"/front/user_agreement.html\" target=\"_blank\">User Agreement</a> and <a href=\"/front/open_enterprise_governance_model.html\" target=\"blank\">Open Enterprise Governance Model</a>\n  </label>\n\n  </div>\n\n  </div></div></div>\n\n\n</div>\n<% end %>\n\n\n<script type=\"text/javascript\">\nfunction check_agreement(){\n  if ($('#agreement_checkbox').is(':checked')){\n    return true;\n  }\n  else{\n    alert('Please check Use Agreement box');\n    return false;\n  }\n}\n</script>\n"
  },
  {
    "path": "app/views/activity_stream_preferences/index.html.erb",
    "content": "<% html_title('Configure Your Activity Stream Access') %>\n\n<script type='text/javascript'>\nfunction all_clicked(checkbox, location_id) {\n  prefs = $('new_activity_stream_preference').getElementsByTagName('input')\n  for (var i=0; i<prefs.length;i++) {\n     if ( prefs[i].id == location_id )\n       prefs[i].checked = checkbox.checked;\n  }\n}\n</script>\n\n<div class = \"static\">\n\n<% if flash.now[:success] %><%= flash.now[:success] %><% end %>\n<%= error_messages_for :activity_stream_preference %>\n\n<h3>Activity Feed Access Preferences</h3>\nCheck = activities are printed.\n<br/>\n<br/>\n<br/>\n<% form_for(ActivityStreamPreference.new) do |f| %>\n  <%= hidden_field_tag \"#{ACTIVITY_STREAM_USER_MODEL_ID}\", @user_id %>\n  <table>\n    <tr>\n      <th>Activity</th>\n      <% ACTIVITY_STREAM_LOCATIONS.each_value do |location| %>\n        <th><%=h location %></th>\n      <% end %>\n    </tr>\n      <td>[Toggle All]</td>\n      <% ACTIVITY_STREAM_LOCATIONS.each_key do |location| %>\n        <td><%= check_box_tag \"all\", location, false, {:onclick => \"all_clicked(this, '#{location}')\"} %></td>\n      <% end %>\n    <tr>\n    <tr>\n<td colspan = 6><hr></td>\n    </tr>\n    </tr>\n      <% ACTIVITY_STREAM_ACTIVITIES.each do |sym,activity| %>\n        <tr>\n          <td><%=h activity %></td>\n          <% ACTIVITY_STREAM_LOCATIONS.each_key do |location| %>\n            <% key = \"#{sym}.#{location}\" %>\n            <td><%= check_box_tag \"locations[]\", key, @activities[key].nil?, {:id => location} %></td>\n          <% end %>\n        </tr>\n      <% end %>\n    </table>\n<br/>\n<br/>\n<p>\n<br/>\n<br/>\n<%= f.submit 'Save My Activity Stream Access Preferences' %>\n<% end %>\n</form>\n</div>\n\n<br />\n"
  },
  {
    "path": "app/views/activity_streams/_activity_comment.html.erb",
    "content": "<tr id=\"input_comment_<%= as.object_id %>\" class=\"hidden\">\n  <td class=\"gt-avatar\" id=\"gravatar_for_comment_<%= as.object_id %>\">\n    <%= avatar(User.current, :size => \"24\") %>\n    </td>\n    <td colspan=2>\n      <textarea id=\"input_comment_textarea_<%= as.object_id %>\" rows=\"3\" cols=\"30\" style=\"width:100%\" class=\"autogrow\" autocomplete-mentions-projectid=\"<%= as.project_id %>\" ></textarea>\n      <input type=\"submit\" onclick=\"post_comment(<%= as.object_id %>,'<%= as.object_type.downcase %>');return false;\" value=\"Comment\"/>\n    </td>\n</tr>\n<tr id=\"add_comment_trigger_<%= as.object_id %>\">\n  <td colspan=3>\n    <input type=\"text\" value=\"Add a comment...\" class=\"activity-comment\" onfocus=\"prepare_input(<%= as.object_id %>);\"></input>\n  </td>\n</tr>\n"
  },
  {
    "path": "app/views/activity_streams/_activity_stream.html.erb",
    "content": "<tr class=\"gt-activity-header\">\n  <td colspan=\"2\">\n    <h4 class=\"long-words\">\n    <%= link_to as.actor_name, {:controller => :users, :action => :show, :id => as.actor_id} %>\n    <span class='verb'>\n      <%= as.verb.tr('_', ' ') %>\n    </span>\n    <%= link_to_activity(as) %>\n    <%= action_times(as.count) %>\n    <% if @project.nil? || @project.id != as.project_id %>\n      in\n      <%=link_to h(as.project_name), :controller => 'projects', :action => 'show', :id => as.project_id  %><% end %>\n      <span class=\"right\"><%= refresh_link %></span>\n    </h4>\n  </td>\n</tr>\n<tr class=\"gt-activity-detail\">\n  <td class=\"gt-avatar <%= User.current.logged? && User.current.id == as.actor_id ? 'me' : nil %>\"><%= avatar(as.actor_email, :size => '44') %>\n    </td>\n    <td class=\"gt-activity-details main\">\n      <table class=\"gt-table gt-user-table activity-item\">\n        <tbody>\n          <tr>\n            <td class=\"long-words\">\n              <h5 class=\"<%= as.object_type.downcase %> border\"><%= link_to title_for_activity_stream(as) , url_for_activity_stream(as), :class => class_for_activity_stream(as) %></h5>\n              <span>\n                <%= format_activity_description(as.object_description) %>\n              </span>\n            </td>\n          <tr>\n        </tbody>\n      </table>\n<div class=\"activity-tag\">\n&nbsp;&nbsp;<%= since_tag(as.created_at) %> ago in\n<%= link_to h(as.project_name), :controller => 'projects', :action => 'show', :id => as.project_id  %>\n<%= link_to \" - #{as.tracker_name} ##{as.object_id}\", url_for_activity_stream(as), {:class => class_for_activity_stream(as)} if as.tracker_name%>\n\n</div>\n"
  },
  {
    "path": "app/views/activity_streams/_activity_stream_feed.atom.builder",
    "content": "\nthis_url = \"http://#{request.host_with_port}/feeds/your_activities/#{@user.activity_stream_token}\"\n\natom_feed(:url => this_url) do |feed|\n  feed.title(\"#{ACTIVITY_STREAM_SERVICE_STRING}: Activity Stream for #{@user.send(ACTIVITY_STREAM_USER_MODEL_NAME)}\")\n  feed.updated(@activity_streams.first ? @activity_streams.first.created_at : Time.now.utc)\n\n  for activity_stream in @activity_streams\n    feed.entry(activity_stream.object ?\n              activity_stream.object : activity_stream) do |entry|\n      entry.title(activity_stream.activity.humanize)\n      entry.content(render(:partial => 'activity_streams/activity_stream.html.erb',\n        :locals => {:activity_stream => activity_stream}),\n        :type => 'html')\n\n      entry.author do |author|\n        author.name(activity_stream.actor ? activity_stream.actor.send(activity_stream.actor_name_method) : '(deleted)' )\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/views/activity_streams/_activity_stream_group.erb",
    "content": "<%= render :partial => 'activity_streams/activity_stream', :locals => {:as => asg[0], :refresh_link => refresh_link} %>\n    <table class=\"gt-table gt-user-table activity-sub\" id=\"comments_table_<%= asg[0].object_id %>\">\n      <tbody>\n      <% for as in asg.to_a.reverse %>\n        <%= render :partial => 'activity_streams/activity_stream_sub', :locals => {:as => as} %>\n      <% end unless asg.length == 1 && !asg[0].indirect_object_id %>\n      </tbody>\n    </table>\n    <%  if User.current.logged? and (asg[0].object_type.downcase == \"issue\" || asg[0].object_type.downcase == \"message\") %>\n    <table class=\"gt-table gt-user-table activity-sub\">\n      <tbody>\n        <%= render :partial => 'activity_streams/activity_comment', :locals => {:as => asg[0]} %>\n      </tbody>\n    </table>\n    <% end %>\n  </td>\n</tr>\n\n\n\n"
  },
  {
    "path": "app/views/activity_streams/_activity_stream_list.html.erb",
    "content": "   <% activities_by_item = ActivityStream.fetch(user_id,project_id, with_subprojects, limit, max_created_at) %>\n    <%link = link_to_remote \"refresh\", {\n                                :url => {:controller => :activity_streams,\n                                        :action => :index,\n                                        :user_id => user_id,\n                                        :project_id => project_id,\n                                        :with_subprojects => with_subprojects,\n                                        :limit => limit,\n                                        :max_created_at => nil,\n                                        :refresh => true\n                                        },\n                                :method => :get, :class => \"right\"\n                                } unless (defined? show_refresh) && !show_refresh %>\n<span id=\"activity_stream_list\">\n <table border=\"0\" class=\"gt-table gt-user-table gt-activity-table\">\n    <tbody>\n      <% activities_by_item.each_with_index do |asg, count| %>\n        <%= render :partial => 'activity_streams/activity_stream_group', :locals => {:asg => asg[1], :refresh_link => (count == 0 ? link : nil)} %>\n      <% end %>\n    </tbody>\n  </table>\n  <% unless activities_by_item.empty? %>\n  <div id=\"activity_stream_bottom\" class=\"activity-bottom\">\n    <%= link_to_remote \"Show more ...\", {\n                                :url => {:controller => :activity_streams,\n                                        :action => :index,\n                                        :user_id => user_id,\n                                        :project_id => project_id,\n                                        :with_subprojects => with_subprojects,\n                                        :limit => limit,\n                                        :max_created_at => activities_by_item.last[1].last.created_at\n                                        },\n                                :method => :get\n                                } unless activities_by_item.last.nil? %>\n  </div>\n  <% end %>\n\n<%= content_tag('p', l(:label_no_data), :class => 'nodata') if activities_by_item.empty? %>\n\n<script type=\"text/javascript\">\n\nfunction prepare_input(object_id){\n  $(\"#input_comment_\" + object_id).show();\n  $(\"#input_comment_textarea_\" + object_id).focus();\n  $(\"#input_comment_textarea_\" + object_id).autogrow();\n  $(\"#add_comment_trigger_\" + object_id).hide();\n\n}\n\nfunction post_comment(object_id, comment_type){\n  $(\"#input_comment_\" + object_id).hide();\n  $(\"#add_comment_trigger_\" + object_id).show();\n\n    var text = $(\"#input_comment_textarea_\" + object_id).val();\n\n    if ((text == null) || (text.length < 2)){\n      return false;\n    }\n    else\n    {\n      $(\"#comments_table_\" + object_id).append(generate_comment(object_id,text));\n      $(\"#input_comment_textarea_\" + object_id).val('');\n\n      if (comment_type==\"issue\")\n      {\n        var data = \"commit=Create&issue_id=\" + object_id + \"&comment=\" + text;\n\n        var url = url_for({ controller: 'comments',\n                                 action    : 'create'\n                                });\n      }\n      else if (comment_type==\"message\")\n      {\n        var data = \"commit=Submit&reply[content]=\" + text;\n        var url = \"/boards/guess/topics/\" + object_id + \"/replies\"\n      }\n\n\n      $.ajax({\n         type: \"POST\",\n         dataType: \"json\",\n         url: url,\n         data: data,\n         success:   function(html){\n        },\n        timeout: 30000 //30 seconds\n       });\n\n      return false;\n    }\n}\n\nfunction generate_comment(object_id, text){\n  var html = '<tr>';\n  html = html +  '    <td class=\"gt-avatar\">';\n  html = html +  '      <%= avatar(User.current, :size => \"24\") %>';\n  html = html +  '      </td>';\n  html = html +  '      <td>';\n  html = html +  '        <span class=\"author\"><%= link_to User.current.name, \"user_path\", :id => User.current.id %></span>';\n  html = html +  '        <span class=\"verb\">Updated this seconds ago</span>';\n  html = html +  '          <span class=\"long-words\"><p>';\n  html = html +  text;\n  html = html +  '          </p></span>';\n  html = html +  '      </td>';\n  html = html +  '  </tr>';\n  return html;\n}\n\n</script>\n</span>\n"
  },
  {
    "path": "app/views/activity_streams/_activity_stream_sub.html.erb",
    "content": "<tr>\n  <td class=\"gt-avatar\">\n    <%= avatar(as.actor_email, :size => \"24\") %>\n\n    </td>\n    <td>\n    <span class=\"author\"><%= link_to as.actor_name, self.send(\"#{as.actor_type.downcase}_path\", as.actor_id) %></span>\n    <span class='verb'><%= as.verb.tr('_', ' ') %> this<%= action_times(as.count) %> <%= since_tag(as.created_at) %> ago</span>\n      <% if as.indirect_object_id -%>\n      <span class='long-words'>\n        <p>\n        <%= render :partial => 'activity_streams/indirect_object', :locals => {:as => as} %>\n        </p>\n      </span>\n      <% end %>\n\n  </td>\n</tr>\n"
  },
  {
    "path": "app/views/activity_streams/_indirect_object.html.erb",
    "content": "<% if as.indirect_object_type.to_s == \"Journal\" && as.indirect_object_phrase == \"GENERATEDETAILS\" %>\n  <%= render_journal_details(as.indirect_object)%>\n<% else %>\n  <%= as.indirect_object_phrase %>\n  <%= format_activity_description(as.indirect_object_description) %>\n<% end %>\n"
  },
  {
    "path": "app/views/activity_streams/_table_header.html.erb",
    "content": "<tr>\n<th>Date</th>\n<th>Activity</th>\n</tr>\n"
  },
  {
    "path": "app/views/activity_streams/edit.html.erb",
    "content": "<h1>Editing activity_stream</h1>\n\n<% form_for(@activity_stream) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :activity %><br />\n    <%= f.text_field :activity %>\n  </p>\n  <p>\n    <%= f.label :actor_id %><br />\n    <%= f.text_field :actor_id %>\n  </p>\n  <p>\n    <%= f.label :actor_type %><br />\n    <%= f.text_field :actor_type %>\n  </p>\n  <p>\n    <%= f.label :count %><br />\n    <%= f.text_field :count %>\n  </p>\n  <p>\n    <%= f.label :object_id %><br />\n    <%= f.text_field :object_id %>\n  </p>\n  <p>\n    <%= f.label :object_type %><br />\n    <%= f.text_field :object_type %>\n  </p>\n  <p>\n    <%= f.label :status %><br />\n    <%= f.text_field :status %>\n  </p>\n  <p>\n    <%= f.submit \"Update\" %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @activity_stream %> |\n<%= link_to 'Back', activity_streams_path %>\n"
  },
  {
    "path": "app/views/activity_streams/index.html.erb",
    "content": "<% @page_header_name = l(:label_browse_activity) %>\n<div class = \"clear\">\n<h2>All Site ActivityStreams</h2>\n\n<% @grouped_by_item.each do |key, value| %>\n<%= render :partial => 'activity_streams/activity_stream_group', :locals => {:activity_stream_group_name => key, :activity_stream_group => value} %>\n<% end %>\n\n</div>\n"
  },
  {
    "path": "app/views/activity_streams/new.html.erb",
    "content": "<h1>New activity_stream</h1>\n\n<% form_for(@activity_stream) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :activity %><br />\n    <%= f.text_field :activity %>\n  </p>\n  <p>\n    <%= f.label :actor_id %><br />\n    <%= f.text_field :actor_id %>\n  </p>\n  <p>\n    <%= f.label :actor_type %><br />\n    <%= f.text_field :actor_type %>\n  </p>\n  <p>\n    <%= f.label :count %><br />\n    <%= f.text_field :count %>\n  </p>\n  <p>\n    <%= f.label :object_id %><br />\n    <%= f.text_field :object_id %>\n  </p>\n  <p>\n    <%= f.label :object_type %><br />\n    <%= f.text_field :object_type %>\n  </p>\n  <p>\n    <%= f.label :status %><br />\n    <%= f.text_field :status %>\n  </p>\n  <p>\n    <%= f.submit \"Create\" %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', activity_streams_path %>\n"
  },
  {
    "path": "app/views/activity_streams/show.html.erb",
    "content": "<p>\n  <b>Activity:</b>\n  <%=h @activity_stream.activity %>\n</p>\n\n<p>\n  <b>Actor:</b>\n  <%=h @activity_stream.actor_id %>\n</p>\n\n<p>\n  <b>Actor type:</b>\n  <%=h @activity_stream.actor_type %>\n</p>\n\n<p>\n  <b>Count:</b>\n  <%=h @activity_stream.count %>\n</p>\n\n<p>\n  <b>Object:</b>\n  <%=h @activity_stream.object_id %>\n</p>\n\n<p>\n  <b>Object type:</b>\n  <%=h @activity_stream.object_type %>\n</p>\n\n<p>\n  <b>Status:</b>\n  <%=h @activity_stream.status %>\n</p>\n\n\n<%= link_to 'Edit', edit_activity_stream_path(@activity_stream) %> |\n<%= link_to 'Back', activity_streams_path %>\n"
  },
  {
    "path": "app/views/admin/_menu.html.erb",
    "content": "<div id=\"admin-menu\">\n  <ul>\n    <li><%= link_to l(:label_project_plural), {:controller => 'admin', :action => 'projects'}, :class => 'projects' %></li>\n    <li><%= link_to l(:label_user_plural), {:controller => 'users'}, :class => 'users' %></li>\n    <li><%= link_to l(:label_role_and_permissions), {:controller => 'roles'}, :class => 'roles' %></li>\n    <li><%= link_to l(:label_tracker_plural), {:controller => 'trackers'}, :class => 'trackers' %></li>\n    <li><%= link_to l(:label_issue_status_plural), {:controller => 'issue_statuses'}, :class => 'issue_statuses' %></li>\n    <li><%= link_to l(:label_workflow), {:controller => 'workflows', :action => 'edit'}, :class => 'workflows' %></li>\n    <li><%= link_to l(:label_enumerations), {:controller => 'enumerations'}, :class => 'enumerations' %></li>\n    <li><%= link_to l(:label_settings), {:controller => 'settings'}, :class => 'settings' %></li>\n    <% menu_items_for(:admin_menu) do |item| -%>\n      <li><%= link_to h(item.caption), item.url, item.html_options %></li>\n    <% end -%>\n    <li><%= link_to l(:label_plugins), {:controller => 'admin', :action => 'plugins'}, :class => 'plugins' %></li>\n    <li><%= link_to l(:label_information_plural), {:controller => 'admin', :action => 'info'}, :class => 'info' %></li>\n    <li><%= link_to :Stats, {:controller => 'admin', :action => 'user_stats'}, :class => 'info' %></li>\n    <li><%= link_to :User_Data_Dump, {:controller => 'admin', :action => 'user_data_dump', :format => :csv}, :class => 'settings' %></li>\n  </ul>\n</div>\n"
  },
  {
    "path": "app/views/admin/_no_data.html.erb",
    "content": "<div class=\"nodata\">\n<% form_tag({:action => 'default_configuration'}) do %>\n    <%= simple_format(l(:text_no_configuration_data)) %>\n    <p><%= l(:field_language) %>:\n    <%= select_tag 'lang', options_for_select(lang_options_for_select(false), current_language.to_s) %>\n    <div class=\"gt-table-buttons\">\n    <%= submit_tag l(:text_load_default_configuration), :disable_with => l(:button_working) %></p>\n    </div>\n\n<% end %>\n</div>\n"
  },
  {
    "path": "app/views/admin/index.html.erb",
    "content": "<h2><%=l(:label_administration)%></h2>\n\n<div id=\"admin-index\">\n  <%= render :partial => 'no_data' if @no_configuration_data %>\n  <%= render :partial => 'menu' %>\n</div>\n\n<% html_title(l(:label_administration)) -%>\n"
  },
  {
    "path": "app/views/admin/info.html.erb",
    "content": "<h2><%=l(:label_information_plural)%></h2>\n\n<p><strong><%= Redmine::Info.versioned_name %></strong> (<%= @db_adapter_name %>)</p>\n\n<table class=\"gt-table\">\n<% @checklist.each do |label, result| %>\n  <tr class=\"<%= cycle 'odd', 'even' %>\">\n    <td><%= l(label) %></td>\n    <td width=\"30px\"><%= image_tag((result ? 'true.png' : 'exclamation.png'), :style => \"vertical-align:bottom;\") %></td>\n  </tr>\n<% end %>\n</table>\n\n<% html_title(l(:label_information_plural)) -%>\n"
  },
  {
    "path": "app/views/admin/plugins.html.erb",
    "content": "<h2><%= l(:label_plugins) %></h2>\n\n<% if @plugins.any? %>\n<table class=\"gt-table plugins\">\n    <% @plugins.each do |plugin| %>\n        <tr class=\"<%= cycle('odd', 'even') %>\">\n        <td><span class=\"name\"><%=h plugin.name %></span>\n            <%= content_tag('span', h(plugin.description), :class => 'description') unless plugin.description.blank? %>\n            <%= content_tag('span', link_to(h(plugin.url), plugin.url), :class => 'url') unless plugin.url.blank? %>\n        </td>\n        <td class=\"author\"><%= plugin.author_url.blank? ? h(plugin.author) : link_to(h(plugin.author), plugin.author_url) %></td>\n        <td class=\"version\"><%=h plugin.version %></td>\n        <td class=\"configure\"><%= link_to(l(:button_configure), :controller => 'settings', :action => 'plugin', :id => plugin.id) if plugin.configurable? %></td>\n        </tr>\n    <% end %>\n</table>\n<% else %>\n<p class=\"nodata\"><%= l(:label_no_data) %></p>\n<% end %>\n"
  },
  {
    "path": "app/views/admin/projects.html.erb",
    "content": "<div class=\"contextual\">\n<%= link_to l(:label_project_new), {:controller => 'projects', :action => 'add'}, :class => 'icon icon-add' %>\n</div>\n\n<h2><%=l(:label_project_plural)%></h2>\n\n<% form_tag({}, :method => :get) do %>\n<fieldset><legend><%= l(:label_filter_plural) %></legend>\n<label><%= l(:field_status) %> :</label>\n<%= select_tag 'status', project_status_options_for_select(@status), :class => \"small\", :onchange => \"this.form.submit(); return false;\"  %>\n<label><%= l(:label_project) %>:</label>\n<%= text_field_tag 'name', params[:name], :size => 30 %>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_apply), :class => \"small\", :name => nil, :disable_with => l(:button_working) %>\n</div>\n</fieldset>\n<% end %>\n&nbsp;\n\n<table class=\"gt-table\">\n  <thead><tr>\n  <th><%=l(:label_project)%></th>\n  <th><%=l(:field_description)%></th>\n  <th><%=l(:field_is_public)%></th>\n  <th><%=l(:field_created_at)%></th>\n  <th></th>\n  </tr></thead>\n  <tbody>\n<% for project in @projects %>\n  <tr class=\"<%= cycle(\"odd\", \"even\") %> <%= css_project_classes(project) %>\">\n  <td class=\"name\" style=\"padding-left: <%= project.level %>em;\"><%= project.active? ? link_to(h(project.name), :controller => 'projects', :action => 'settings', :id => project) : h(project.name) %></td>\n  <td><%= textilizable project.short_description, :project => project %></td>\n  <td align=\"center\"><%= image_tag 'true.png' if project.is_public? %></td>\n  <td align=\"center\"><%= format_date(project.created_at) %></td>\n  <td class=\"buttons\">\n    <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project, :status => params[:status] }, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-lock') if project.active? %>\n    <%= link_to(l(:button_unarchive), { :controller => 'projects', :action => 'unarchive', :id => project, :status => params[:status] }, :method => :post, :class => 'icon icon-unlock') if project.archived? && (project.parent.nil? || project.parent.active?) %>\n    <%= link_to(l(:button_copy), { :controller => 'projects', :action => 'copy', :id => project }, :class => 'icon icon-copy') %>\n    <%= link_to(l(:button_delete), { :controller => 'projects', :action => 'destroy', :id => project }, :class => 'icon icon-del') %>\n  </td>\n  </tr>\n<% end %>\n  </tbody>\n</table>\n\n<% html_title(l(:label_project_plural)) -%>\n"
  },
  {
    "path": "app/views/admin/user_stats.html.erb",
    "content": "<%= javascript_include_tag 'raphael.min', 'g.raphael.min', 'g.line.min', 'g.bar.min' %>\n\n<div class=\"gt-content-box padded\">\n  <h2>Signups</h2>\n  Daily signups for the last 14 days<br>\n  <%= raphael_report_tag(User.daily_registrations_report,{:width => 600, :height => 150},{ :shade => false }) %>\n  <br>\n  Weekly signups\n  <%= raphael_report_tag(User.weekly_registrations_report,{:width => 600, :height => 150},{}) %>\n  <h2>Logins</h2>\n  Daily logins for the last 14 days<br>\n  <%= raphael_report_tag(Track.daily_logins_report,{:width => 600, :height => 150},{ :shade => false }) %><br>\n  Weekly logins\n  <%= raphael_report_tag(Track.weekly_logins_report,{:width => 600, :height => 150},{}) %>\n  <h2>New Projects</h2>\n  Daily new projects for the last 14 days<br>\n  <%= raphael_report_tag(Project.daily_new_projects_report,{:width => 600, :height => 150},{ :shade => false }) %><br>\n  Weekly new projects\n  <%= raphael_report_tag(Project.weekly_new_projects_report,{:width => 600, :height => 150},{\"smooth\" => true}) %>\n</div>\n"
  },
  {
    "path": "app/views/attachments/_form.html.erb",
    "content": "<div id=\"attachments_form_link\">\n  <a href=\"#\" class=\"icon icon-attachment\" onclick=\"$('#attachments_form_details').show();$('#attachments_form_link').hide();return false;\">Attach files</a>\n</div>\n<div id=\"attachments_form_details\" class=\"hidden\">\n  <span id=\"attachments_fields\">\n  <%= file_field_tag 'attachments[1][file]', :size => 30  -%>\n  <%= text_field_tag 'attachments[1][description]', '', :size => 60 %>\n  <em><%= l(:label_optional_description) %></em>\n  </span>\n  <br />\n  <small><%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;' %>\n  (<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)\n  </small>\n</div>\n"
  },
  {
    "path": "app/views/attachments/_links.html.erb",
    "content": "<div class=\"attachments\">\n<% for attachment in attachments %>\n<p><%= link_to_attachment attachment, :class => 'icon icon-attachment' -%>\n<%= h(\" - #{attachment.description}\") unless attachment.description.blank? %>\n  <span class=\"size\">(<%= number_to_human_size attachment.filesize %>)</span>\n  <% if options[:deletable] %>\n    <%= link_to image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => attachment},\n                                         :confirm => l(:text_are_you_sure),\n                                         :method => :post,\n                                         :class => 'delete',\n                                         :title => l(:button_delete) %>\n  <% end %>\n  <% if options[:author] %>\n    <span class=\"author\"><%= attachment.author %>, <%= format_time(attachment.created_at) %></span>\n  <% end %>\n  </p>\n<% end %>\n</div>\n"
  },
  {
    "path": "app/views/attachments/_table.erb",
    "content": "<table class=\"attachments\">\n<% for attachment in attachments %>\n<tr>\n  <td>\n<%= link_to_attachment attachment, :class => 'icon icon-attachment' -%>\n<%= h(\" - #{attachment.description}\") unless attachment.description.blank? %>\n  <span class=\"size\">(<%= number_to_human_size attachment.filesize %>)</span>\n  <% if options[:deletable] %>\n    <%= link_to image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => attachment},\n                                         :confirm => l(:text_are_you_sure),\n                                         :method => :post,\n                                         :class => 'delete',\n                                         :title => l(:button_delete) %>\n  <% end %>\n  <% if options[:author] %>\n    <span class=\"author\"><%= attachment.author %>, <%= format_time(attachment.created_at) %></span>\n  <% end %>\n  </td>\n</tr>\n<% end %>\n</table>\n"
  },
  {
    "path": "app/views/attachments/diff.html.erb",
    "content": "<h2><%=h @attachment.filename %></h2>\n\n<div class=\"attachments\">\n<p><%= h(\"#{@attachment.description} - \") unless @attachment.description.blank? %>\n   <span class=\"author\"><%= @attachment.author %>, <%= format_time(@attachment.created_at) %></span></p>\n<p><%= link_to_attachment @attachment, :text => l(:button_download), :download => true -%>\n   <span class=\"size\">(<%= number_to_human_size @attachment.filesize %>)</span></p>\n\n</div>\n&nbsp;\n<%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type} %>\n\n<% html_title @attachment.filename %>\n\n<% content_for :header_tags do -%>\n    <%= stylesheet_link_tag \"scm\" -%>\n<% end -%>\n"
  },
  {
    "path": "app/views/attachments/file.html.erb",
    "content": "<h2><%=h @attachment.filename %></h2>\n\n<div class=\"attachments\">\n<p><%= h(\"#{@attachment.description} - \") unless @attachment.description.blank? %>\n   <span class=\"author\"><%= @attachment.author %>, <%= format_time(@attachment.created_at) %></span></p>\n<p><%= link_to_attachment @attachment, :text => l(:button_download), :download => true -%>\n   <span class=\"size\">(<%= number_to_human_size @attachment.filesize %>)</span></p>\n\n</div>\n&nbsp;\n<%= render :partial => 'common/file', :locals => {:content => @content, :filename => @attachment.filename} %>\n\n<% html_title @attachment.filename %>\n\n<% content_for :header_tags do -%>\n    <%= stylesheet_link_tag \"scm\" -%>\n<% end -%>\n"
  },
  {
    "path": "app/views/auth_sources/_form.html.erb",
    "content": "<%= error_messages_for 'auth_source' %>\n\n<div class=\"gt-content-box\">\n<p><label for=\"auth_source_name\"><%=l(:field_name)%> <span class=\"required\">*</span></label>\n<%= text_field 'auth_source', 'name'  %></p>\n\n<p><label for=\"auth_source_host\"><%=l(:field_host)%> <span class=\"required\">*</span></label>\n<%= text_field 'auth_source', 'host'  %></p>\n\n<p><label for=\"auth_source_port\"><%=l(:field_port)%> <span class=\"required\">*</span></label>\n<%= text_field 'auth_source', 'port', :size => 6 %> <%= check_box 'auth_source', 'tls'  %> LDAPS</p>\n\n<p><label for=\"auth_source_account\"><%=l(:field_account)%></label>\n<%= text_field 'auth_source', 'account'  %></p>\n\n<p><label for=\"auth_source_account_password\"><%=l(:field_password)%></label>\n<%= password_field 'auth_source', 'account_password', :name => 'ignore',\n                                           :value => ((@auth_source.new_record? || @auth_source.account_password.blank?) ? '' : ('x'*15)),\n                                           :onfocus => \"this.value=''; this.name='auth_source[account_password]';\",\n                                           :onchange => \"this.name='auth_source[account_password]';\" %></p>\n\n<p><label for=\"auth_source_base_dn\"><%=l(:field_base_dn)%> <span class=\"required\">*</span></label>\n<%= text_field 'auth_source', 'base_dn', :size => 60 %></p>\n\n<p><label for=\"auth_source_onthefly_register\"><%=l(:field_onthefly)%></label>\n<%= check_box 'auth_source', 'onthefly_register' %></p>\n</div>\n\n<fieldset class=\"gt-content-box\"><legend><%=l(:label_attribute_plural)%></legend>\n<p><label for=\"auth_source_attr_login\"><%=l(:field_login)%> <span class=\"required\">*</span></label>\n<%= text_field 'auth_source', 'attr_login', :size => 20  %></p>\n\n<p><label for=\"auth_source_attr_firstname\"><%=l(:field_firstname)%></label>\n<%= text_field 'auth_source', 'attr_firstname', :size => 20  %></p>\n\n<p><label for=\"auth_source_attr_lastname\"><%=l(:field_lastname)%></label>\n<%= text_field 'auth_source', 'attr_lastname', :size => 20  %></p>\n\n<p><label for=\"auth_source_attr_mail\"><%=l(:field_mail)%></label>\n<%= text_field 'auth_source', 'attr_mail', :size => 20  %></p>\n</fieldset>\n"
  },
  {
    "path": "app/views/auth_sources/edit.html.erb",
    "content": "<h2><%=l(:label_auth_source)%> (<%= @auth_source.auth_method_name %>)</h2>\n\n<% form_tag({:action => 'update', :id => @auth_source}, :class => \"tabular\") do %>\n  <%= render :partial => 'form' %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_save) %>\n  </div>\n<% end %>\n\n"
  },
  {
    "path": "app/views/auth_sources/list.html.erb",
    "content": "<div class=\"contextual\">\n<%= link_to l(:label_auth_source_new), {:action => 'new'}, :class => 'icon icon-add' %>\n</div>\n\n<h2><%=l(:label_auth_source_plural)%></h2>\n\n<table class=\"gt-table\">\n  <thead><tr>\n    <th><%=l(:field_name)%></th>\n    <th><%=l(:field_type)%></th>\n    <th><%=l(:field_host)%></th>\n    <th><%=l(:label_user_plural)%></th>\n    <th></th>\n    <th></th>\n  </tr></thead>\n  <tbody>\n<% for source in @auth_sources %>\n  <tr class=\"<%= cycle(\"odd\", \"even\") %>\">\n    <td><%= link_to source.name, :action => 'edit', :id => source%></td>\n    <td align=\"center\"><%= source.auth_method_name %></td>\n    <td align=\"center\"><%= source.host %></td>\n    <td align=\"center\"><%= source.users.count %></td>\n    <td align=\"center\"><%= link_to l(:button_test), :action => 'test_connection', :id => source %></td>\n    <td align=\"center\"><%= button_to l(:button_delete), { :action => 'destroy', :id => source },\n                                                        :confirm => l(:text_are_you_sure),\n                                                        :class => \"button-small\",\n                                                        :disabled => source.users.any? %></td>\n  </tr>\n<% end %>\n  </tbody>\n</table>\n\n<p class=\"pagination\"><%= pagination_links_full @auth_source_pages %></p>\n"
  },
  {
    "path": "app/views/auth_sources/new.html.erb",
    "content": "<h2><%=l(:label_auth_source_new)%> (<%= @auth_source.auth_method_name %>)</h2>\n\n<% form_tag({:action => 'create'}, :class => \"tabular\") do %>\n  <%= render :partial => 'form' %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_create) %>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/boards/_form.html.erb",
    "content": "<%= error_messages_for 'board' %>\n\n<div class=\"gt-content-box\">\n<p><%= f.text_field :name, :required => true %></p>\n<p><%= f.text_field :description, :required => true, :size => 80 %></p>\n</div>\n"
  },
  {
    "path": "app/views/boards/edit.html.erb",
    "content": "<h2><%= l(:label_board) %></h2>\n\n<% labelled_tabular_form_for :board, @board, :url => {:action => 'edit', :id => @board} do |f| %>\n  <%= render :partial => 'form', :locals => {:f => f} %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/boards/index.html.erb",
    "content": "<%= help_section \"project_discussion\" %>\n<h2><%= l(:label_board_plural) %></h2>\n\n<table class=\"gt-table boards\">\n  <thead><tr>\n    <th><%= l(:label_board) %></th>\n    <th><%= l(:label_topic_plural) %></th>\n    <th><%= l(:label_message_plural) %></th>\n    <th><%= l(:label_message_last) %></th>\n  </tr></thead>\n  <tbody>\n<% for board in @boards %>\n  <tr class=\"<%= cycle 'odd', 'even' %>\">\n    <td>\n      <%= link_to h(board.name), {:action => 'show', :id => board}, :class => \"board\"  %><br />\n      <%=h board.description %>\n    </td>\n    <td align=\"center\"><%= board.topics_count %></td>\n    <td align=\"center\"><%= board.messages_count %></td>\n    <td>\n    <small>\n      <% if board.last_message %>\n      <%= authoring board.last_message.created_at, board.last_message.author %><br />\n      <%= link_to_message board.last_message %>\n      <% end %>\n    </small>\n    </td>\n  </tr>\n<% end %>\n  </tbody>\n</table>\n\n<% html_title l(:label_board_plural) %>\n"
  },
  {
    "path": "app/views/boards/new.html.erb",
    "content": "<h2><%= l(:label_board_new) %></h2>\n\n<% labelled_tabular_form_for :board, @board, :url => {:action => 'new'} do |f| %>\n  <%= render :partial => 'form', :locals => {:f => f} %>\n  <div class=\"gt-table-buttons\">\n      <%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/boards/show.html.erb",
    "content": "<%= help_section \"project_discussion\" %>\n<%= breadcrumb link_to(l(:label_board_plural), {:controller => 'boards', :action => 'index', :project_id => @project}) %>\n\n<div id=\"add-message\" style=\"display:none;\">\n<% if authorize_for('messages', 'new') %>\n<h2><%= link_to h(@board.name), :controller => 'boards', :action => 'show', :project_id => @project, :id => @board %> &#187; <%= l(:label_message_new) %></h2>\n<% form_for :message, @message, :url => {:controller => 'messages', :action => 'new', :board_id => @board}, :html => {:multipart => true, :id => 'message-form'} do |f| %>\n  <%= render :partial => 'messages/form', :locals => {:f => f} %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n  <p class=\"gt-cancel\">\n  <%= link_to_remote l(:label_preview),\n                     { :url => { :controller => 'messages', :action => 'preview', :board_id => @board },\n                       :method => 'post',\n                       :update => 'preview',\n                       :with => \"$('#message-form').serialize()\",\n                       :complete => \"$('body').scrollTo('#preview')\"\n                     }, :accesskey => accesskey(:preview) %> |\n  <%= link_to l(:button_cancel), \"#\", :onclick => 'Element.hide(\"add-message\")' %>\n  </p>\n  </div>\n<% end %>\n<div id=\"preview\" class=\"wiki\"></div>\n<% end %>\n</div>\n\n<h2><%=h @board.name %></h2>\n<p class=\"subtitle\"><%=h @board.description %></p>\n\n<% if @topics.any? %>\n<div class=\"gt-content-box\">\n<table class=\"gt-table\">\n  <thead><tr>\n    <th><%= l(:field_subject) %></th>\n    <th><%= l(:field_author) %></th>\n    <%= sort_header_tag('created_at', :caption => l(:field_created_at)) %>\n    <%= sort_header_tag('replies', :caption => l(:label_reply_plural)) %>\n    <%= sort_header_tag('updated_at', :caption => l(:label_message_last)) %>\n  </tr></thead>\n  <tbody>\n  <% @topics.each do |topic| %>\n    <tr class=\"message <%= cycle 'odd', 'even' %> <%= topic.sticky? ? 'sticky' : '' %> <%= topic.locked? ? 'locked' : '' %>\">\n      <td class=\"subject\"><%= link_to h(topic.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => topic } %></td>\n      <td class=\"author\"><%= topic.author %></td>\n      <td class=\"created_at\"><%= format_time(topic.created_at) %></td>\n      <td class=\"replies\"><%= topic.replies_count %></td>\n      <td class=\"last_message\">\n        <% if topic.last_reply %>\n        <%= authoring topic.last_reply.created_at, topic.last_reply.author %><br />\n        <%= link_to_message topic.last_reply %>\n        <% end %>\n      </td>\n    </tr>\n  <% end %>\n  </tbody>\n</table>\n<div class=\"gt-table-controls gt-table-controls-btm clearfix\">\n          <p class=\"gt-table-pager\"><%= pagination_links_full @topic_pages, @topic_count %></p>\n</div>\n</div>\n<% else %>\n<div class=\"gt-content-box\">\n  <p class=\"nodata\"><%= l(:label_no_data) %></p>\n</div>\n<% end %>\n\n<% html_title h(@board.name) %>\n\n<% content_for :actionmenu do %>\n  <ul>\n  <li>\n    <%= link_to_if_authorized l(:label_topic_new),\n                              {:controller => 'messages', :action => 'new', :board_id => @board},\n                              :class => 'icon icon-add',\n                              :onclick => '$(\"#add-message\").show(); $(\"#message_subject\").focus(); return false;' %>\n  </li>\n  <li>\n    <%= watcher_tag(@board, User.current) %>\n  </li>\n  </ul>\n<% end %>\n"
  },
  {
    "path": "app/views/common/403.html.erb",
    "content": "<h2>403</h2>\n\n<p><%= l(:notice_not_authorized) %></p>\n<p><a href=\"javascript:history.back()\">Back</a></p>\n\n<% html_title '403' %>\n"
  },
  {
    "path": "app/views/common/404.html.erb",
    "content": "<h2>404</h2>\n<p><%= l(:notice_file_not_found) %></p>\n<p><a href=\"javascript:history.back()\">Back</a></p>\n\n<% html_title '404' %>\n"
  },
  {
    "path": "app/views/common/_calendar.html.erb",
    "content": "<table class=\"cal\">\n<thead>\n<tr><td></td><% 7.times do |i| %><th><%= day_name( (calendar.first_wday+i)%7 ) %></th><% end %></tr>\n</thead>\n<tbody>\n<tr>\n<% day = calendar.startdt\nwhile day <= calendar.enddt %>\n<%= \"<th>#{day.cweek}</th>\" if day.cwday == calendar.first_wday %>\n<td class=\"<%= day.month==calendar.month ? 'even' : 'odd' %><%= ' today' if Date.today == day %>\">\n<p class=\"day-num\"><%= day.day %></p>\n<% calendar.events_on(day).each do |i| %>\n  <% if i.is_a? Issue %>\n  <div class=\"<%= i.css_classes %> tooltip\">\n  <%= if day == i.start_date && day == i.due_date\n        image_tag('arrow_bw.png')\n      elsif day == i.start_date\n        image_tag('arrow_from.png')\n      elsif day == i.due_date\n    image_tag('arrow_to.png')\n      end %>\n  <%= h(\"#{i.project} -\") unless @project && @project == i.project %>\n  <%= link_to_issue i, :truncate => 30 %>\n  <span class=\"tip\"><%= render_issue_tooltip i %></span>\n  </div>\n  <% else %>\n  <span class=\"icon icon-package\">\n    <%= h(\"#{i.project} -\") unless @project && @project == i.project %>\n  </span>\n  <% end %>\n<% end %>\n</td>\n<%= '</tr><tr>' if day.cwday==calendar.last_wday and day!=calendar.enddt %>\n<% day = day + 1\nend %>\n</tr>\n</tbody>\n</table>\n"
  },
  {
    "path": "app/views/common/_diff.html.erb",
    "content": "<% diff = Redmine::UnifiedDiff.new(diff, :type => diff_type, :max_lines => Setting.diff_max_lines_displayed.to_i) -%>\n<% diff.each do |table_file| -%>\n<div class=\"autoscroll\">\n<% if diff_type == 'sbs' -%>\n<table class=\"filecontent CodeRay\">\n<thead>\n<tr><th colspan=\"4\" class=\"filename\"><%= table_file.file_name %></th></tr>\n</thead>\n<tbody>\n<% prev_line_left, prev_line_right = nil, nil -%>\n<% table_file.keys.sort.each do |key| -%>\n<% if prev_line_left && prev_line_right && (table_file[key].nb_line_left != prev_line_left+1) && (table_file[key].nb_line_right != prev_line_right+1) -%>\n<tr class=\"spacing\">\n<th class=\"line-num\">...</th><td></td><th class=\"line-num\">...</th><td></td>\n<% end -%>\n<tr>\n  <th class=\"line-num\"><%= table_file[key].nb_line_left %></th>\n  <td class=\"line-code <%= table_file[key].type_diff_left %>\">\n    <pre><%=to_utf8 table_file[key].line_left %></pre>\n  </td>\n  <th class=\"line-num\"><%= table_file[key].nb_line_right %></th>\n  <td class=\"line-code <%= table_file[key].type_diff_right %>\">\n    <pre><%=to_utf8 table_file[key].line_right %></pre>\n  </td>\n</tr>\n<% prev_line_left, prev_line_right = table_file[key].nb_line_left.to_i, table_file[key].nb_line_right.to_i -%>\n<% end -%>\n</tbody>\n</table>\n\n<% else -%>\n<table class=\"filecontent CodeRay\">\n<thead>\n<tr><th colspan=\"3\" class=\"filename\"><%= table_file.file_name %></th></tr>\n</thead>\n<tbody>\n<% prev_line_left, prev_line_right = nil, nil -%>\n<% table_file.keys.sort.each do |key, line| %>\n<% if prev_line_left && prev_line_right && (table_file[key].nb_line_left != prev_line_left+1) && (table_file[key].nb_line_right != prev_line_right+1) -%>\n<tr class=\"spacing\">\n<th class=\"line-num\">...</th><th class=\"line-num\">...</th><td></td>\n</tr>\n<% end -%>\n<tr>\n  <th class=\"line-num\"><%= table_file[key].nb_line_left %></th>\n  <th class=\"line-num\"><%= table_file[key].nb_line_right %></th>\n  <% if table_file[key].line_left.empty? -%>\n  <td class=\"line-code <%= table_file[key].type_diff_right %>\">\n    <pre><%=to_utf8 table_file[key].line_right %></pre>\n  </td>\n  <% else -%>\n  <td class=\"line-code <%= table_file[key].type_diff_left %>\">\n    <pre><%=to_utf8 table_file[key].line_left %></pre>\n  </td>\n  <% end -%>\n</tr>\n<% prev_line_left = table_file[key].nb_line_left.to_i if table_file[key].nb_line_left.to_i > 0 -%>\n<% prev_line_right = table_file[key].nb_line_right.to_i if table_file[key].nb_line_right.to_i > 0 -%>\n<% end -%>\n</tbody>\n</table>\n<% end -%>\n\n</div>\n<% end -%>\n\n<%= l(:text_diff_truncated) if diff.truncated? %>\n"
  },
  {
    "path": "app/views/common/_file.html.erb",
    "content": "<div class=\"autoscroll\">\n<table class=\"filecontent CodeRay\">\n<tbody>\n<% line_num = 1 %>\n<% syntax_highlight(filename, to_utf8(content)).each_line do |line| %>\n<tr><th class=\"line-num\" id=\"L<%= line_num %>\"><a href=\"#L<%= line_num %>\"><%= line_num %></a></th><td class=\"line-code\"><pre><%= line %></pre></td></tr>\n<% line_num += 1 %>\n<% end %>\n</tbody>\n</table>\n</div>\n"
  },
  {
    "path": "app/views/common/_main_menu_home.html.erb",
    "content": "<ul>\n  <li>\n    <%= link_to l(:label_my_page), {:controller => \"welcome\", :action => \"index\"}, :class => (active_page == :mypage ? 'gt-active' : '') %>\n  </li>\n  <li>\n    <%= link_to l(:label_my_issues), {:controller => \"my\", :action => \"issues\"}, :class => (active_page == :myissues ? 'gt-active' : '') %>\n  </li>\n  <li>\n    <%= link_to l(:label_my_projects), {:controller => \"my\", :action => \"projects\"}, :class => (active_page == :myprojects ? 'gt-active' : '') %>\n  </li>\n  <li>\n    <%= link_to l(:label_my_account), {:controller => \"my\", :action => \"account\"}, :class => (active_page == :myaccount ? 'gt-active' : '') %>\n  </li>\n  <li>\n    <%= link_to l(:label_notifications), {:controller => \"notifications\", :action => \"index\"}, :class => (active_page == :notifications ? 'gt-active' : '') %>\n  </li>\n</ul>\n"
  },
  {
    "path": "app/views/common/_preview.html.erb",
    "content": "<fieldset class=\"preview\"><legend><%= l(:label_preview) %></legend>\n<%= textilizable @text, :attachments => @attachements, :object => @previewed %>\n</fieldset>\n"
  },
  {
    "path": "app/views/common/_tabs.html.erb",
    "content": "<% selected_tab = params[:tab] ? params[:tab].to_s : tabs.first[:name] %>\n\n<div class=\"tabs\">\n  <ul>\n\n  <% tabs.each do |tab| -%>\n    <% tab[:label_ending] ||=\"\"  %>\n    <li><%= link_to (l(tab[:label])+ tab[:label_ending]), { :tab => tab[:name] },\n                                    :id => \"tab-#{tab[:name]}\",\n                                    :class => \"tab-top #{(tab[:name] != selected_tab ? nil : 'selected')}\",\n                                    :onclick => \"showTab('#{tab[:name]}'); this.blur(); return false;\" %></li>\n  <% end -%>\n  </ul>\n  <div class=\"tabs-buttons\" style=\"display:none;\">\n    <button class=\"tab-left\" onclick=\"moveTabLeft(this);\"></button>\n    <button class=\"tab-right\" onclick=\"moveTabRight(this);\"></button>\n  </div>\n</div>\n\n<% tabs.each do |tab| -%>\n  <%= content_tag('div', render(:partial => tab[:partial], :locals => tab[:locals] ),\n                       :id => \"tab-content-#{tab[:name]}\",\n                       :class => \"tab-content #{(tab[:name] != selected_tab ? 'hidden' : nil)}\") %>\n<% end -%>\n"
  },
  {
    "path": "app/views/common/feed.atom.rxml",
    "content": "xml.instruct!\nxml.feed \"xmlns\" => \"http://www.w3.org/2005/Atom\" do\n  xml.title   truncate_single_line(@title, :length => 100)\n  xml.link    \"rel\" => \"self\", \"href\" => url_for(params.merge(:only_path => false))\n  xml.link    \"rel\" => \"alternate\", \"href\" => url_for(params.merge(:only_path => false, :format => nil, :key => nil))\n  xml.id      url_for(:controller => 'welcome', :only_path => false)\n  xml.updated((@items.first ? @items.first.event_datetime : Time.now).xmlschema)\n  xml.author  { xml.name \"#{Setting.app_title}\" }\n  xml.generator(:uri => Redmine::Info.url) { xml.text! Redmine::Info.app_name; }\n  @items.each do |item|\n    xml.entry do\n      url = url_for(item.event_url(:only_path => false))\n      if @project\n        xml.title truncate_single_line(item.event_title, :length => 100)\n      else\n        xml.title truncate_single_line(\"#{item.project} - #{item.event_title}\", :length => 100)\n      end\n      xml.link \"rel\" => \"alternate\", \"href\" => url\n      xml.id url\n      xml.updated item.event_datetime.xmlschema\n      author = item.event_author if item.respond_to?(:event_author)\n      xml.author do\n        xml.name(author)\n        xml.email(author.mail) if author.is_a?(User) && !author.mail.blank? && !author.pref.hide_mail\n      end if author\n      xml.content \"type\" => \"html\" do\n        xml.text! textilizable(item, :event_description, :only_path => false)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/views/credit_distributions/edit.html.erb",
    "content": "<h1>Editing credit_distribution</h1>\n\n<% form_for(@credit_distribution) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :user_id %><br />\n    <%= f.text_field :user_id %>\n  </p>\n  <p>\n    <%= f.label :project_id %><br />\n    <%= f.text_field :project_id %>\n  </p>\n  <p>\n    <%= f.label :retro_id %><br />\n    <%= f.text_field :retro_id %>\n  </p>\n  <p>\n    <%= f.label :amount %><br />\n    <%= f.text_field :amount %>\n  </p>\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @credit_distribution %> |\n<%= link_to 'Back', credit_distributions_path %>\n"
  },
  {
    "path": "app/views/credit_distributions/index.html.erb",
    "content": "<h1>Listing credit_distributions</h1>\n\n<table>\n  <tr>\n    <th>User</th>\n    <th>Workstream</th>\n    <th>translation missing: en, field_retro</th>\n    <th>translation missing: en, field_amount</th>\n  </tr>\n\n<% @credit_distributions.each do |credit_distribution| %>\n  <tr>\n    <td><%=h credit_distribution.user_id %></td>\n    <td><%=h credit_distribution.project_id %></td>\n    <td><%=h credit_distribution.retro_id %></td>\n    <td><%=h credit_distribution.amount %></td>\n    <td><%= link_to 'Show', credit_distribution %></td>\n    <td><%= link_to 'Edit', edit_credit_distribution_path(credit_distribution) %></td>\n    <td><%= link_to 'Destroy', credit_distribution, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New credit_distribution', new_credit_distribution_path %>\n"
  },
  {
    "path": "app/views/credit_distributions/new.html.erb",
    "content": "<h1>New credit_distribution</h1>\n\n<% form_for(@credit_distribution) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :user_id %><br />\n    <%= f.text_field :user_id %>\n  </p>\n  <p>\n    <%= f.label :project_id %><br />\n    <%= f.text_field :project_id %>\n  </p>\n  <p>\n    <%= f.label :retro_id %><br />\n    <%= f.text_field :retro_id %>\n  </p>\n  <p>\n    <%= f.label :amount %><br />\n    <%= f.text_field :amount %>\n  </p>\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', credit_distributions_path %>\n"
  },
  {
    "path": "app/views/credit_distributions/show.html.erb",
    "content": "<p>\n  <b>User:</b>\n  <%=h @credit_distribution.user_id %>\n</p>\n\n<p>\n  <b>Workstream:</b>\n  <%=h @credit_distribution.project_id %>\n</p>\n\n<p>\n  <b>translation missing: en, field_retro:</b>\n  <%=h @credit_distribution.retro_id %>\n</p>\n\n<p>\n  <b>translation missing: en, field_amount:</b>\n  <%=h @credit_distribution.amount %>\n</p>\n\n\n<%= link_to 'Edit', edit_credit_distribution_path(@credit_distribution) %> |\n<%= link_to 'Back', credit_distributions_path %>\n"
  },
  {
    "path": "app/views/credit_transfers/_credit_transfer_history.html.erb",
    "content": "  <div class=\"gt-content-box\">\n    <%  if credit_transfers.length == 0 %>\n        <p class=\"nodata\"><%= l(:label_no_data) %></p>\n    <% else %>\n\n    <table border=\"0\" class=\"gt-table gt-user-table\">\n      <tbody>\n      <tr>\n        <th>Date</th>\n        <th>Amount</th>\n        <th>Sender</th>\n        <th>Recipient</th>\n        <th>Workstream</th>\n      </tr>\n      <%\n          credit_transfers.sort { |b,a| a.created_at <=> b.created_at }\n          credit_transfers.each do |ct|\n      %>\n      <tr class=\"<%= cycle 'odd', 'even' %>\"id=\"m_<%= ct.id %>\">\n      <td> <%= format_date ct.created_at %> </td>\n       <td class=\"currency\"><%=h number_to_currency ct.amount.round.to_i, :unit => \"\", :separator => \".\", :delimiter => \",\", :precision => 0 %></td>\n        <td><%= link_to_user_or_you ct.sender %></td>\n        <td><%= link_to_user_or_you ct.recipient %></td>\n        <td><%= link_to_project ct.project %></td>\n      </tr>\n      <% end %>\n\n      </tbody>\n    </table>\n\n    <% end %>\n\n\n  </div>\n"
  },
  {
    "path": "app/views/credit_transfers/_eligible_recipients.erb",
    "content": "Available credits: <%= @total_credits %><br><br>\n\n<% if @user_list.length > 0 %>\n\n<p id=\"select_concerned_user\">\n  <label><%= l(:label_select_recipient) %></label><%= collection_select(:credit_transfer, :recipient_id, @user_list, :user_id, :name, :prompt => l(:label_select)) %><br><br>\n  <label><%= l(:label_amount_to_transfer) %></label>\n  <%= text_field_tag 'amount', nil, :size => 10, :style => \"width:40%\" %><br><br>\n  <label><%= l(:label_note_to_recipient) %></label>\n  <%= text_area('note', nil, :cols => 30, :rows => 6) %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_submit), :disable_with => l(:button_working) %></p>\n  </div>\n</p>\n<% else %>\n  There are no eligible recipients for credits from this project workstream.\n <br><a href=\"http://help.bettermeans.com/membership\" target=\"blank\">Learn more about how membership rules work</a>\n <br>\n<% end %>\n\n\n"
  },
  {
    "path": "app/views/credit_transfers/_new_credit_transfer.html.erb",
    "content": "  <h2 class=\"gt-table-head\"><%=l(:label_new_credit_transfer) %></h2>\n  <% form_tag({:action => :create}) do %>\n  <% if project_list %>\n  <label><%= l(:label_select_project) %></label>\n  <%= collection_select(:credit_transfer, :project_id, project_list, :project_id, :name,{:prompt => l(:label_select), :selected => @selected_project_id.to_i}) %>\n  <% else %>\n  <div class=\"gt-content-box\">\n    <%= content_tag 'p', l(:label_no_credits), :class => \"nodata\" %>\n  </div>\n  <% end %>\n\n  <div id=\"users_container\">\n    <% if @selected_project_id %>\n      <%= render :partial => \"eligible_recipients\" %>\n    <% end %>\n  </div>\n\n  <%= observe_field :credit_transfer_project_id, :url => {:controller => :credit_transfers, :action => :eligible_recipients, :only_path => :false }, :update => :users_container, :with => 'project_id' %>\n\n  <% end %>\n"
  },
  {
    "path": "app/views/credit_transfers/index.html.erb",
    "content": "<h1><%= l(:label_credit_transfers) %></h1>\n<div class=\"splitcontentleft\">\n<%= render :partial => 'new_credit_transfer', :locals => {:project_list => @project_list} %>\n</div>\n<div class=\"splitcontentright\">\n  <h2 class=\"gt-table-head\"><%=l(:label_previous_credit_transfers) %></h2>\n    <%= render :partial => 'credit_transfer_history', :locals => {:credit_transfers => @credit_transfers} %>\n</div>\n"
  },
  {
    "path": "app/views/credits/_credit_breakdown.html.erb",
    "content": "<div class=\"gt-content-box\">\n<%\npie_data = []\npie_labels = []\ntotal_points = 0\nunit = unit_for(@project)\nunit = '' if unit != '$'\n\n\ngroup_credits.each_value {|credits| total_points += credits.collect(&:amount).sum }\n\ngroup_credits.keys.sort.each do |owner_id|\n  total_amount = group_credits[owner_id].collect(&:amount).sum.round.to_i\n  percentage_points = total_points == 0 ? 0  : (total_amount / total_points * 100).round_to(1).to_i\n  pie_data << percentage_points.round.to_i\n  pie_labels << User.find(owner_id).firstname + \" #{number_to_currency total_amount, :unit => unit, :separator => \".\", :delimiter => \",\", :precision => 0}\"\nend\n %>\n\n <img src=\"<%=  Gchart.pie(:title => \"#{title} - #{number_to_currency total_points.round.to_i, :unit => unit, :separator => \".\", :delimiter => \",\", :precision => 0}\",\n                :size => '400x200',\n                :data => pie_data, :labels => pie_labels )\n  %>\"/>\n\n</div>\n"
  },
  {
    "path": "app/views/credits/_credit_history.html.erb",
    "content": "<span id=\"credit_history_partial\">\n<h2 class=\"gt-table-head\"><%=l(:label_credit_history) %></h2>\n<div class=\"gt-content-box\">\n  <%  @credits_by_day = @credits.group_by{|credit| credit.issued_on.to_date}\n    unit = unit_for(@project)\n\n    if @credits_by_day.length == 0\n   %>\n  <%=     content_tag 'p', l(:label_no_data), :class => \"nodata\" %>\n  <% else %>\n\n  <table border=\"0\" class=\"gt-table gt-user-table\">\n    <tbody>\n    <%\n        @credits_by_day.sort { |b,a| a[0] <=> b[0] }\n        @credits_by_day.each do |cbd|\n    %>\n    <tr>\n        <th><%= cbd[0].to_s %></th>\n      </tr>\n         <% cbd[1].each do |credit|%>\n   <tr id=\"h_<%= credit.id %>\">\n      <td class=\"currency\"><%=h number_to_currency credit.amount.round.to_i, :unit => unit, :separator => \".\", :delimiter => \",\", :precision => 0 %></td>\n      <td><%=link_to_user_from_id credit.owner_id %></td>\n      <td><%=h credit.settled_on.nil? ? credit.enabled ? \"Active\" : \"Inactive\" : \"Settled\" %></td>\n      <% if authorize_for(:credits, :edit) %>\n      <td><%= link_to 'Edit', :controller => :credits, :action => :edit, :id => credit %> | <%= link_to 'Delete', :controller => :credits, :action => :destroy, :id => credit %></td>\n      <% end %>\n    </tr>\n  <% end %>\n  <% end %>\n  </tbody>\n  </table>\n  <% end %>\n</div>\n</span>\n"
  },
  {
    "path": "app/views/credits/_credit_queue.html.erb",
    "content": "<span id=\"credit_queue_partial\">\n<h2 class=\"gt-table-head\"><%=l(:label_credit_queue) %></h2>\n<div class=\"gt-content-box\">\n  <% @credits_by_day = @credits.group_by{|credit| credit.issued_on.to_date}\n    unit = unit_for(@project)\n\n    if @credits_by_day.length == 0\n   %>\n  <%=     content_tag 'p', l(:label_no_data), :class => \"nodata\" %>\n  <% else %>\n\n  <table border=\"0\" class=\"gt-table gt-user-table\">\n    <tbody>\n<%\n    @credits_by_day.sort { |b,a| a[0] <=> b[0] }\n    @credits_by_day.each do |cbd|\n%>\n<tr>\n    <th><%= cbd[0].to_s %></th>\n  </tr>\n     <% cbd[1].each do |credit|\n\n      next if !credit.enabled || !credit.settled_on.nil?\n  %>\n  <tr id=\"q_<%= credit.id %>\">\n    <td class=\"currency\"><%=h number_to_currency credit.amount.round.to_i, :unit => unit, :separator => \".\", :delimiter => \",\", :precision => 0 %></td>\n    <td><%=link_to_user_from_id credit.owner_id %></td>\n  </tr>\n<% end %>\n<% end %>\n  </tbody>\n  </table>\n<% end %>\n</div>\n</span>\n"
  },
  {
    "path": "app/views/credits/_my_credits.html.erb",
    "content": "<span id=\"my_credits_partial\">\n<h2 class=\"gt-table-head\"><%=l(:label_my_credits) %></h2>\n<div class=\"gt-content-box\">\n  <%  @credits_by_day = @credits.group_by{|credit| credit.issued_on.to_date}\n  unit = unit_for(@project)\n\n    display_no_data = true;\n\n    if @credits_by_day.length == 0\n      display_no_data = true;\n    else %>\n\n\n  <table border=\"0\" class=\"gt-table gt-user-table\">\n    <tbody>\n    <%\n        @credits_by_day.sort { |b,a| a[0] <=> b[0] }\n        @credits_by_day.each do |cbd|\n    %>\n    <tr>\n        <% @date = \"<th> #{cbd[0].to_s} </th>\"%>\n      </tr>\n         <% cbd[1].each do |credit|\n    next if credit.owner_id != User.current.id\n      display_no_data = false;\n   %>\n   <tr class=\"<%= cycle 'odd', 'even' %>\"id=\"m_<%= credit.id %>\">\n     <%= @date %>\n     <td class=\"currency\"><%=h number_to_currency credit.amount.round.to_i, :unit => unit, :separator => \".\", :delimiter => \",\", :precision => 0 %></td>\n      <td><%=h credit.settled_on.nil? ? credit.enabled ? \"Active\" : \"Inactive\" : \"Settled\" %></td>\n      <td><%= credit_activation_link(credit, @project.id, params[:with_subprojects]) %></td>\n    </tr>\n    <% @date = \"<td></td>\" %>\n  <% end %>\n  <% end %>\n  </tbody>\n  </table>\n  <% end %>\n\n  <% if display_no_data %>\n  <p class=\"nodata\"><%= l(:label_no_data) %></p>\n  <% end %>\n\n</div>\n</span>\n"
  },
  {
    "path": "app/views/credits/edit.html.erb",
    "content": "<h1>Editing credit</h1>\n\n<% form_for @credit, :url => {:action => 'update', :id => @credit} do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :amount %><br />\n    <%= f.text_field :amount %>\n  </p>\n  <p>\n    <%= f.label :owner_id %><br />\n    <%= f.text_field :owner_id %>\n  </p>\n  <p>\n    <%= f.label :project_id %><br />\n    <%= f.text_field :project_id %>\n  </p>\n  <p>\n    <%= f.label :enabled %><br />\n    <%= f.check_box :enabled %>\n  </p>\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n"
  },
  {
    "path": "app/views/credits/index.html.erb",
    "content": "<h1>Listing credits</h1>\n\n<table>\n  <tr>\n    <th>Amount</th>\n    <th>Owner</th>\n    <th>Workstream</th>\n    <th>Enabled</th>\n  </tr>\n\n<% @credits.each do |credit| %>\n  <tr>\n    <td><%=h credit.amount %></td>\n    <td><%=h credit.owner_id %></td>\n    <td><%=h credit.project_id %></td>\n    <td><%=h credit.enabled %></td>\n    <td><%= link_to 'Show', credit %></td>\n    <td><%= link_to 'Edit', edit_credit_path(credit) %></td>\n    <td><%= link_to 'Destroy', credit, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New credit', new_credit_path %>\n"
  },
  {
    "path": "app/views/credits/new.html.erb",
    "content": "<h1>New credit</h1>\n\n<% form_for @credit, :url => {:action => 'create'} do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :amount %><br />\n    <%= f.text_field :amount %>\n  </p>\n  <p>\n    <%= f.label :owner_id %><br />\n    <%= f.text_field :owner_id %>\n  </p>\n  <p>\n    <%= f.label :project_id %><br />\n    <%= f.text_field :project_id %>\n  </p>\n  <p>\n    <%= f.label :enabled %><br />\n    <%= f.check_box :enabled %>\n  </p>\n  <p>\n    <%= f.label :created_at %><br />\n    <%= f.text_field :created_at %>\n  </p>\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to \"Back\", :controller => \"credits\" %>\n"
  },
  {
    "path": "app/views/credits/show.html.erb",
    "content": "<h2><%=l(:label_team) %></h2>\n\n<%= error_messages_for 'member' %>\n\n<div class=\"splitcontentleft\">\n  <p>\n    <b>Amount:</b>\n    <%=h @credit.amount %>\n  </p>\n\n  <p>\n    <b>Owner:</b>\n    <%=h @credit.owner_id %>\n  </p>\n\n  <p>\n    <b>Workstream:</b>\n    <%=h @credit.project_id %>\n  </p>\n\n  <p>\n    <b>Enabled:</b>\n    <%=h @credit.enabled %>\n  </p>\n\n\n  <%= link_to 'Edit', edit_credit_path(@credit) %> |\n  <%= link_to 'Back', credits_path %>\n</div>\n\n\n<% html_title(l(:label_team)) %>\n"
  },
  {
    "path": "app/views/documents/_document.html.erb",
    "content": "<p><%= link_to h(document.title), :controller => 'documents', :action => 'show', :id => document %><br />\n<% unless document.description.blank? %><%=h(truncate(document.description, :length => 250)) %><br /><% end %>\n<em><%= format_time(document.updated_at) %></em></p>\n"
  },
  {
    "path": "app/views/documents/_form.html.erb",
    "content": "<%= error_messages_for 'document' %>\n<div class=\"gt-content-box\">\n<p><label for=\"document_title\"><%=l(:field_title)%> <span class=\"required\">*</span></label>\n<%= text_field 'document', 'title', :size => 60 %></p>\n\n<p><label for=\"document_description\"><%=l(:field_description)%></label>\n<%= textile_editor 'document', 'description', :cols => 60, :rows => 15, :class => 'wiki-edit' %></p>\n<%= textile_editor_initialize(:framework => :jquery) %>\n</div>\n"
  },
  {
    "path": "app/views/documents/edit.html.erb",
    "content": "<h2><%=l(:label_document)%></h2>\n\n<% form_tag({:action => 'edit', :id => @document}, :class => \"tabular\") do %>\n  <%= render :partial => 'form' %>\n    <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n  </div>\n<% end %>\n\n\n"
  },
  {
    "path": "app/views/documents/index.html.erb",
    "content": "<div id=\"add-document\" style=\"display:none;\">\n<h2><%=l(:label_document_new)%></h2>\n<% form_tag({:controller => 'documents', :action => 'new', :project_id => @project}, :class => \"tabular\", :multipart => true) do %>\n<%= render :partial => 'documents/form' %>\n<div class=\"gt-content-box\">\n<p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p>\n</div>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n<p class=\"gt-cancel\">\n<%= link_to l(:button_cancel), \"#\", :onclick => '$(\"#add-document\").hide();' %>\n</p>\n</div>\n<% end %>\n</div>\n\n<% if @grouped.empty? %>\n<div class=\"gt-content-box\">\n  <p class=\"nodata\"><%= l(:label_no_data) %></p>\n</div>\n<% end %>\n\n<% @grouped.keys.sort.each do |group| %>\n    <h3><%= group %></h3>\n    <div class=\"gt-content-box padded\">\n      <%= render :partial => 'documents/document', :collection => @grouped[group] %>\n    </div>\n<% end %>\n\n<% html_title(l(:label_document_plural)) -%>\n\n<% content_for :actionmenu do %>\n  <ul>\n  <li>\n    <%= link_to_if_authorized l(:label_document_new),\n                              {:controller => 'documents', :action => 'new', :project_id => @project},\n                              :class => 'icon icon-add',\n                              :onclick => '$(\"#add-document\").show(); $(\"#document_title\").focus(); return false;' %>\n\n  </li>\n  </ul>\n<% end %>\n\n<% content_for :sidebar do %>\n  <% form_tag({}, :method => :get) do %>\n  <div class=\"gt-sidebar-nav gt-sidebar-nav-gray\">\n    <h3><%= l(:label_sort_by, '') %></h3>\n    <ul>\n    <li>\n      <a style=\"color:#fff\"><%= radio_button_tag 'sort_by', 'date', (@sort_by == 'date'), :onclick => 'this.form.submit();' %> <%= l(:label_date) %></a>\n    </li>\n    <li>\n      <a style=\"color:#fff\"><%= radio_button_tag 'sort_by', 'title', (@sort_by == 'title'), :onclick => 'this.form.submit();' %> <%= l(:field_title) %></a>\n    </li>\n    <li>\n      <a style=\"color:#fff\"><%= radio_button_tag 'sort_by', 'author', (@sort_by == 'author'), :onclick => 'this.form.submit();' %> <%= l(:field_author) %></a>\n    </li>\n    </ul>\n  </div>\n  <% end %>\n<% end %>\n\n"
  },
  {
    "path": "app/views/documents/new.html.erb",
    "content": "<h2><%=l(:label_document_new)%></h2>\n\n<% form_tag({:controller => 'documents', :action => 'new', :project_id => @project}, :class => \"tabular\", :multipart => true) do %>\n<%= render :partial => 'documents/form' %>\n\n<div class=\"gt-content-box\">\n<p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p>\n</div>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n\n\n"
  },
  {
    "path": "app/views/documents/show.html.erb",
    "content": "<h2><%=h @document.title %></h2>\n<p><em><%= format_date @document.created_at %></em></p>\n<div class=\"gt-content-box wiki\">\n<%= textilizable @document.description, :attachments => @document.attachments %>\n</div>\n\n<h3><%= l(:label_attachment_plural) %></h3>\n<%= link_to_attachments @document %>\n\n<% if authorize_for('documents', 'add_attachment') %>\n<p><%= link_to l(:label_attachment_new), {},\n              :onclick => \"$('#add_attachment_form').show(); $('#' + this.id).hide(); $('body').scrollTo('#add_attachment_form'); return false;\",\n              :id => 'attach_files_link',\n              :class => \"gt-btn-gray-large\" %></p>\n  <% form_tag({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :id => \"add_attachment_form\", :style => \"display:none;\") do %>\n  <div class=\"gt-content-box\">\n  <p><%= render :partial => 'attachments/form' %></p>\n  </div>\n    <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_add), :disable_with => l(:button_working) %>\n  </div>\n  <% end %>\n<% end %>\n\n<% html_title @document.title -%>\n\n<% content_for :sidebar do %>\n<h2>&nbsp;</h2>\n<div class=\"gt-sidebar-nav gt-sidebar-nav-gray\">\n  <ul>\n  <li>\n    <%= link_to_if_authorized l(:button_edit), {:controller => 'documents', :action => 'edit', :id => @document}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %>\n  </li>\n  <li>\n    <%= link_to_if_authorized l(:button_delete), {:controller => 'documents', :action => 'destroy', :id => @document}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>\n  </li>\n  </ul>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/email_updates/new.html.erb",
    "content": "<% content_for :mainmenu do %>\n  <%= render :partial => 'common/main_menu_home', :locals => {:active_page => :myaccount} %>\n<% end %>\n\n<h2><%= l(:label_email_update)  %></h2>\n<% form_for(@email_update) do |f| %>\n<div class=\"gt-left-col\">\n  <%= f.text_field :mail %>\n  <p>\n    <%= submit_tag l(:button_submit), :disable_with => l(:button_working) %>\n  </p>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/enterprises/edit.html.erb",
    "content": "<h1>Editing enterprise</h1>\n\n<% form_for(@enterprise) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @enterprise %> |\n<%= link_to 'Back', enterprises_path %>\n"
  },
  {
    "path": "app/views/enterprises/index.html.erb",
    "content": "<h1>Listing enterprises</h1>\n\n<table>\n  <tr>\n  </tr>\n\n<% @enterprises.each do |enterprise| %>\n  <tr>\n    <td><%= link_to 'Show', enterprise %></td>\n    <td><%= link_to 'Edit', edit_enterprise_path(enterprise) %></td>\n    <td><%= link_to 'Destroy', enterprise, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New enterprise', new_enterprise_path %>\n"
  },
  {
    "path": "app/views/enterprises/new.html.erb",
    "content": "<h1>New enterprise</h1>\n\n<% form_for(@enterprise) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', enterprises_path %>\n"
  },
  {
    "path": "app/views/enterprises/show.html.erb",
    "content": "\n<%= link_to 'Edit', edit_enterprise_path(@enterprise) %> |\n<%= link_to 'Back', enterprises_path %>\n"
  },
  {
    "path": "app/views/enumerations/_form.html.erb",
    "content": "<%= error_messages_for 'enumeration' %>\n<div class=\"gt-content-box\">\n<%= hidden_field 'enumeration', 'type'  %>\n\n<p><label for=\"enumeration_name\"><%=l(:field_name)%></label>\n<%= text_field 'enumeration', 'name'  %></p>\n\n<p><label for=\"enumeration_active\"><%=l(:field_active)%></label>\n<%= check_box 'enumeration', 'active'  %></p>\n\n<p><label for=\"enumeration_is_default\"><%=l(:field_is_default)%></label>\n<%= check_box 'enumeration', 'is_default'  %></p>\n\n</div>\n"
  },
  {
    "path": "app/views/enumerations/destroy.html.erb",
    "content": "<h2><%= l(@enumeration.option_name) %>: <%=h @enumeration %></h2>\n\n<% form_tag({}) do %>\n<div class=\"gt-content-box\">\n<p><strong><%= l(:text_enumeration_destroy_question, @enumeration.objects_count) %></strong></p>\n<p><%= l(:text_enumeration_category_reassign_to) %>\n<%= select_tag 'reassign_to_id', (\"<option>--- #{l(:actionview_instancetag_blank_option)} ---</option>\" + options_from_collection_for_select(@enumerations, 'id', 'name')) %></p>\n</div>\n  <div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_apply), :disable_with => l(:button_working) %>\n<p class=\"gt-cancel\">\n<%= link_to l(:button_cancel), :controller => 'enumerations', :action => 'index' %>\n</p>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/enumerations/edit.html.erb",
    "content": "<h2><%= link_to l(@enumeration.option_name), :controller => 'enumerations', :action => 'index' %> &#187; <%=h @enumeration %></h2>\n\n<% form_tag({:action => 'update', :id => @enumeration}, :class => \"tabular\") do %>\n  <%= render :partial => 'form' %>\n  <%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n<% end %>\n\n<% form_tag({:action => 'destroy', :id => @enumeration}) do %>\n  <%= submit_tag l(:button_delete), :disable_with => l(:button_working) %>\n<% end %>\n"
  },
  {
    "path": "app/views/enumerations/list.html.erb",
    "content": "<h2><%=l(:label_enumerations)%></h2>\n\n<% Enumeration.get_subclasses.each do |klass| %>\n<h3><%= l(klass::OptionName) %></h3>\n\n<% enumerations = klass.shared %>\n<% if enumerations.any? %>\n<table class=\"gt-table\">\n<tr>\n    <th><%= l(:field_name) %></th>\n    <th style=\"width:15%;\"><%= l(:field_is_default) %></th>\n    <th style=\"width:15%;\"><%= l(:field_active) %></th>\n    <th style=\"width:15%;\"></th>\n    <th align=\"center\" style=\"width:10%;\"> </th>\n</tr>\n<% enumerations.each do |enumeration| %>\n<tr class=\"<%= cycle('odd', 'even') %>\">\n    <td><%= link_to h(enumeration), :action => 'edit', :id => enumeration %></td>\n    <td class=\"center\" style=\"width:15%;\"><%= image_tag('true.png') if enumeration.is_default? %></td>\n    <td class=\"center\" style=\"width:15%;\"><%= image_tag('true.png') if enumeration.active? %></td>\n    <td style=\"width:15%;\"><%= reorder_links('enumeration', {:action => 'update', :id => enumeration}) %></td>\n    <td class=\"buttons\">\n    <%= link_to l(:button_delete), { :action => 'destroy', :id => enumeration },\n                                   :method => :post,\n                                   :confirm => l(:text_are_you_sure),\n                                   :class => 'icon icon-del' %>\n    </td>\n</tr>\n<% end %>\n</table>\n<% reset_cycle %>\n<% end %>\n\n<p><%= link_to l(:label_enumeration_new), { :action => 'new', :type => klass.name } %></p>\n<% end %>\n\n<% html_title(l(:label_enumerations)) -%>\n"
  },
  {
    "path": "app/views/enumerations/new.html.erb",
    "content": "<h2><%= link_to l(@enumeration.option_name), :controller => 'enumerations', :action => 'index' %> &#187; <%=l(:label_enumeration_new)%></h2>\n\n<% form_tag({:action => 'create'}, :class => \"tabular\") do %>\n  <%= render :partial => 'form' %>\n  <%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n<% end %>\n"
  },
  {
    "path": "app/views/help/show.html.erb",
    "content": "<div id=\"help_dialogue\" class=\"help_dialogue\">\n<h2><%= l('help_' + @help_key + '_title') %></h2>\n<%= l('help_' + @help_key + '_description') %>\n<br /><br />\n<div style=\"vertical-align:bottom, float:right\">\n<a href=\"#\" class=\"lbAction\" rel=\"deactivate\"><%= l(:button_close) %></a>\n</div>\n</div>\n"
  },
  {
    "path": "app/views/help_sections/_show.html.erb",
    "content": "<% content_for :help_section do -%>\n  <p>\n    <%= l(\"help_section_#{name}\") %>\n  </p>\n\n<% end %>\n"
  },
  {
    "path": "app/views/help_sections/_show_popup.html.erb",
    "content": "<div id=\"help_section_container\" style=\"display:none\">\n<div class=\"help-section\" id=\"help_section\" style=\"margin-bottom:0;width:630px;\">\n<h3><%= l(\"help_section_#{help_section.name}\").split(\"|\")[0] %></h3>\n<a href=\"#\" onclick=\"$.fancybox.close(); return false;\" class=\"help-section-link\">Close</a>\n<%= link_to_remote \"Don't show again\", {:url => {:controller => :help_sections, :action => :dont_show, :id => help_section.id}}, {:class => \"help-section-link\", :onclick => \"$.fancybox.close()\"} %>\n<div class=\"clear\"></div>\n\n<p>\n  <%= l(\"help_section_#{help_section.name}\").split(\"|\")[1] %>\n</p>\n</div>\n</div>\n<script type=\"text/javascript\">\n$(document).ready(function(){\n\n  $.fancybox({\n        'content'      : $('#help_section_container').html(),\n        'padding'    : 0,\n        'margin'  : 0,\n        'transitionIn'  : 'elastic',\n        'transitionOut'  : 'elastic',\n      });\n\n});\n\n</script>\n"
  },
  {
    "path": "app/views/help_sections/edit.html.erb",
    "content": "<h1>Editing help_section</h1>\n\n<% form_for(@help_section) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @help_section %> |\n<%= link_to 'Back', help_sections_path %>\n"
  },
  {
    "path": "app/views/help_sections/index.html.erb",
    "content": "<h1>Listing help_sections</h1>\n\n<table>\n  <tr>\n  </tr>\n\n<% @help_sections.each do |help_section| %>\n  <tr>\n    <td><%= link_to 'Show', help_section %></td>\n    <td><%= link_to 'Edit', edit_help_section_path(help_section) %></td>\n    <td><%= link_to 'Destroy', help_section, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New help_section', new_help_section_path %>\n"
  },
  {
    "path": "app/views/help_sections/new.html.erb",
    "content": "<h1>New help_section</h1>\n\n<% form_for(@help_section) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', help_sections_path %>\n"
  },
  {
    "path": "app/views/help_sections/show.html.erb",
    "content": "<p>help section</p>\n<%= @help_section.id %>\n<%= @help_section.name %>\n<%= @help_section.show %>\n<%= link_to 'Edit', edit_help_section_path(@help_section) %> |\n<%= link_to 'Back', help_sections_path %>\n"
  },
  {
    "path": "app/views/home/_footer.html.erb",
    "content": "<div class=\"clear last clearfix\" id=\"footer\">\n  <div class=\"clear last\" id=\"top-footer\">\n    <a href=\"#\"><img class=\"footer-logo clear\" src=\"/images/static/footer-logo.png\" alt=\"\" width=\"252\" height=\"81\"></a>\n    <div class=\"span-3 copyright\">\n      <p>\n        We run cage-free open source software. <a href=\"https://github.com/Bettermeans/bettermeans\" target=\"new\">Fork us on github</a>\n      </p>\n      <p>\n        Help content available under <a href=\"http://creativecommons.org/licenses/by-sa/3.0/\" target=\"new\">CreativeCommons Attribution-Share Alike</a>\n      </p>\n    </div>\n    <div class=\"span-3 footer-list\">\n      <h3>\n        Quick Links\n      </h3>\n      <ul>\n        <li>\n          <a href=\"/\">Home</a>\n        </li>\n        <li>\n          <a href=\"/front/index.html\">Front Page</a>\n        </li>\n        <li>\n          <a href=\"/front/why.html\">Why</a>\n        </li>\n        <li>\n          <a href=\"/front/how.html\">How</a>\n        </li>\n        <li>\n          <a href=\"/front/what.html\">What</a>\n        </li>\n        <li>\n          <a href=\"/front/pricing.html\">Plans and Pricing</a>\n        </li>\n        <li>\n          <a href=\"/front/privacy.html\">Privacy Policy</a>\n        </li>\n      </ul>\n    </div>\n    <div class=\"span-3 footer-list\">\n      <h3>\n        Company\n      </h3>\n      <ul>\n        <li>\n          <a href=\"http://bettermeans.org/front\" target=\"_blank\">BetterMeans.org</a>\n        </li>\n        <li>\n          <a href=\"http://bettermeans.org/front/?cat=3\" target=\"_blank\">Blog</a>\n        </li>\n        <li>\n          <a href=\"http://bettermeans.org/front/?page_id=318\" target=\"_blank\">Open Enterprise</a>\n        </li>\n        <li>\n          <a href=\"http://bettermeans.org/front/?page_id=34\" target=\"_blank\">Team</a>\n        </li>\n        <li>\n          <a href=\"http://bettermeans.org/front/?page_id=31\" target=\"_blank\">Mission</a>\n        </li>\n        <li>\n          <a href=\"http://bettermeans.org/front/?page_id=253\" target=\"_blank\">Join Us</a>\n        </li>\n      </ul>\n    </div>\n    <div class=\"span-3 last footer-list\">\n      <h3>\n        Library\n      </h3>\n      <ul>\n        <li>\n          <a href=\"http://www.youtube.com/user/BetterMeans\" target=\"_blank\">Video</a>\n        </li>\n        <li>\n          <a href=\"http://bettermeans.org/front/?page_id=306\" target=\"_blank\">Open Enterprise Manifesto</a>\n        </li>\n        <li>\n          <a href=\"/front/open_enterprise_governance_model.html\" target=\"_blank\">Open Enterprise Governance Model</a>\n        </li>\n        <li>\n          <div>\n            <br>\n            <a href=\"http://facebook.com/bettermeans\" rel=\"alternate\" target=\"_blank\"><img src=\"/images/static/i_facebook.png\" alt=\"facebook\" style=\"vertical-align:middle;border:0\"></a> <a href=\"http://twitter.com/bettermeans\" rel=\"alternate\" target=\"_blank\"><img src=\"/images/static/i_twitter.png\" alt=\"facebook\" style=\"vertical-align:middle;border:0\"></a> <a href=\"http://www.linkedin.com/search?search=&amp;sortCriteria=R&amp;keepFacets=keepFacets&amp;company=BetterMeans&amp;currentCompany=co\" rel=\"alternate\" target=\"_blank\"><img src=\"/images/static/i_linkedin.png\" alt=\"facebook\" style=\"vertical-align:middle;border:0\"></a> <a href=\"http://feeds.feedburner.com/bettermeans\" rel=\"alternate\" type=\"application/rss+xml\" target=\"_blank\"><img src=\"/images/static/feed-icon32x32.png\" alt=\"\" style=\"vertical-align:middle;border:0\"></a>\n          </div>\n        </li>\n      </ul>\n    </div>\n  </div>\n  <a href=\"#\" id=\"toTop\" name=\"toTop\">^ Scroll to Top</a>\n</div>\n"
  },
  {
    "path": "app/views/home/_header.html.erb",
    "content": "    <div class=\"span-12 last\" id=\"header\">\n      <div class=\"span-2\" id=\"logo\"><a href=\"/\" title=\"BetterMeans\">BetterMeans</a></div>\n      <div class=\"span-10 last\">\n<% if User.current.logged? %>\n        <ul class=\"sf-menu\" id=\"topnav\">\n          <li <%= \"class='active'\" if page == \"/\" %>> <a href=\"/\"><span><Dashboard>Home</span></a>\n          </li>\n          <li <%= \"class='active'\" if page == \"account\" %>> <a href=\"/my/account\"><span>Account</span></a>\n          </li>\n          <li> <a href=\"/logout\"><span>Logout</span></a>\n          <li> <a href=\"/\"><span style=\"color:#ccc\"><%= current_user.name %></span></a></li>\n        </ul>\n\n<% else %>\n        <ul class=\"sf-menu\" id=\"topnav\">\n          <li <%= \"class='active'\" if page == \"home\" %>> <a href=\"/front/index.html\"><span>home</span></a> </li>\n          <li <%= \"class='active'\" if page == \"why\" %>> <a href=\"/front/why.html\"><span>why</span></a> </li>\n          <li <%= \"class='active'\" if page == \"how\" %>> <a href=\"/front/how.html\"><span>how it works</span></a> </li>\n          <li <%= \"class='active'\" if page == \"what\" %>> <a href=\"/front/what.html\"><span>features</span></a> </li>\n          <li <%= \"class='active'\" if page == \"login\" %>>  <a  href=\"/login\"><span>login</span></a>\n          <li <%= \"class='active'\" if page == \"register\" %>><a href=\"/front/pricing.html\"><span>sign up</span><img src=\"/images/static/blue_arrow_left.png\" id=\"inviteArrow\"/></a></li>\n        </ul>\n\n<% end %>\n      </div>\n    </div>\n"
  },
  {
    "path": "app/views/home/about.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n    <%= render :partial => 'header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"span-8 left-content-secondary\">\n        <div class=\"span-8 first inner-page-title\">\n          <h2 class=\"main-title-2\">This is a little overview about us</h2>\n          <span>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. </span> </div>\n        <p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus.</p>\n        <p>Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. <a href=\"#\">Aenean imperdiet</a>. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. </p>\n        <p>Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Nullam accumsan lorem in dui. Cras ultricies mi eu turpis hendrerit fringilla. <a href=\"#\">Vestibulum ante ipsum primis in faucibus orci luctus </a> et ultrices posuere cubilia Curae; In ac dui quis mi consectetuer lacinia. Nam pretium turpis et arcu. Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum. Sed aliquam ultrices mauris. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Praesent adipiscing. Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut.</p>\n        <img class=\"laptop\" src=\"/images/static/laptop.png\" alt=\"\" width=\"314\" height=\"185\"/>\n        <div class=\"product-quote\">\n          <h4>Beautiful, useful, gorgeous.</h4>\n          <p>“Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet.\n            Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus.\n            Maecenas tempus.”</p>\n        </div>\n        <div class=\"notice\">This is a great option to post notices to your users, is great for the important information.</div>\n      </div>\n      <div class=\"span-4 last right-content-secondary\">\n        <ul>\n          <li> <a href=\"#\"> <img src=\"/images/static/thumb1.png\" alt=\"\" width=\"45\" height=\"45\"/> Overview <span class=\"meta\"> <span class=\"sub-meta\">See our main information</span> </span> </a> </li>\n          <li> <a href=\"#\"> <img src=\"/images/static/thumb1.png\" alt=\"\" width=\"45\" height=\"45\" /> Websites <span class=\"meta\"> <span class=\"sub-meta\">See our sites too</span> </span> </a> </li>\n          <li> <a href=\"#\"> <img src=\"/images/static/thumb1.png\" alt=\"\" width=\"45\" height=\"45\" /> Extend <span class=\"meta\"> <span class=\"sub-meta\">Our WordPress plugins</span> </span> </a> </li>\n          <li> <a href=\"#\"> <img src=\"/images/static/thumb1.png\" alt=\"\" width=\"45\" height=\"45\" /> Email Marketing <span class=\"meta\"> <span class=\"sub-meta\">See our Themeforest themes</span> </span> </a> </li>\n          <li> <a href=\"#\"> <img src=\"/images/static/thumb1.png\" alt=\"\" width=\"45\" height=\"45\" /> Analytics <span class=\"meta\"> <span class=\"sub-meta\">See our main information</span> </span> </a> </li>\n          <li> <a href=\"#\"> <img src=\"/images/static/thumb1.png\" alt=\"\" width=\"45\" height=\"45\" /> ThemeForest <span class=\"meta\"> <span class=\"sub-meta\">Our templates</span> </span> </a> </li>\n          <li> <a href=\"#\"> <img src=\"/images/static/thumb1.png\" alt=\"\" width=\"45\" height=\"45\" /> Photography <span class=\"meta\"> <span class=\"sub-meta\">See our photoportfolio</span> </span> </a> </li>\n        </ul>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/home/apps.html.erb",
    "content": "<script type=\"text/javascript\">\n    $(document).ready(function() {\n      $(\"a.example\").fancybox({\n        'titleShow'     : false,\n        'transitionIn'  : 'elastic',\n        'transitionOut'  : 'elastic'\n      });\n    });\n  </script>\n<div id=\"inner-page\">\n  <div class=\"container\">\n    <%= render :partial => 'header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"clear span-12\">\n        <div class=\"span-8 first inner-page-title\">\n          <h2 class=\"main-title-2\">See our latest applications</h2>\n          <span>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. </span> </div>\n        <div class=\"clear\"></div>\n        <div class=\"span-12\" id=\"gallery\">\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-1_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-2_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-2.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-3_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-3.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-4_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-4.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n\n<script type=\"text/javascript\">\n      $(document).ready(function() {\n        $('.viewport').mouseenter(function(e) {\n          $(this).children('a').children('img').animate({ height: '268', left: '-20', top: '-20', width: '480'}, 100);\n          $(this).children('a').children('span').fadeIn(300);\n        }).mouseleave(function(e) {\n          $(this).children('a').children('img').animate({ height: '268', left: '-20', top: '-20', width: '480'}, 100);\n          $(this).children('a').children('span').fadeOut(200);\n        });\n      });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "app/views/home/contact.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n    <%= render :partial => 'header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"span-8 left-content-secondary\">\n        <div class=\"span-8 first inner-page-title\">\n          <h2 class=\"main-title-2\">Contact Us or say Hi</h2>\n          <span>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. </span> </div>\n        <p class=\"contact-intro\">Like all true geeks, we love receiving emails. You may just want to say “Hi” or you think I kinda rock and are interested in working with us. Well it’s pretty easy to get in touch, just fill out this handy little form with your info and I will get back to you.</p>\n        <div class=\"trib\">.</div>\n        <div id=\"message\"></div>\n        <form id=\"contact-form\" method=\"post\" action=\"contact.php\">\n          <h3>Contact us if you need further assistance</h3>\n          <p>\n            <label for=\"first\">Name</label>\n            <input type=\"text\" name=\"name\" id=\"name\"/>\n          </p>\n          <p>\n            <label for=\"first\">Email</label>\n            <input type=\"text\" name=\"email\" id=\"email\" />\n          </p>\n          <p>\n            <label for=\"first\">Website</label>\n            <input type=\"text\" name=\"website\" id=\"website\" />\n          </p>\n          <p>\n            <label for=\"first\">Phone</label>\n            <input type=\"text\" name=\"phone\" id=\"phone\" />\n          </p>\n       <p>\n            <label for=\"first\">Subject</label>\n            <input type=\"text\" name=\"subject\" id=\"subject\" />\n          </p>\n          <p>\n            <label for=\"first\">Comments</label>\n            <textarea name=\"comments\" id=\"comments\"></textarea>\n          </p>\n          <input style=\"margin:0\" id=\"contact-submit\" type=\"submit\" name=\"submit\" value=\"submit\"/>\n        </form>\n      </div>\n      <div class=\"span-4 last right-content-secondary sidebar\">\n        <div id=\"map\">\n          <div class=\"sidebar-title\">\n            <h1>Where are we?</h1>\n            <div class=\"arrow\">.</div>\n          </div>\n          <img src=\"/images/map.png\" alt=\"\"/> </div>\n        <div id=\"details\">\n          <div class=\"sidebar-title\">\n            <h1>Contact Details</h1>\n            <div class=\"arrow\">.</div>\n          </div>\n          <p class=\"mail\"> <a href=\"mailto:contact@BetterMeans.com\">E-mail: contact@BetterMeans.com</a></p>\n          <p class=\"tel\">Tel: +1 510 2132990</p>\n        </div>\n        <div id=\"text-widget-contact\">\n          <div class=\"sidebar-title\">\n            <h1>Text Widget</h1>\n            <div class=\"arrow\">.</div>\n          </div>\n          <div class=\"boxxx\">\n            <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>\n          </div>\n        </div>\n        <div id=\"ads\">\n          <div class=\"sidebar-title\">\n            <h1>Advertisement</h1>\n            <div class=\"arrow\">.</div>\n          </div>\n          <div class=\"ad-boxes\"> <a href=\"#\" class=\"adhere100px center\">Advertise Here</a> <a href=\"#\" class=\"adhere100px\">Advertise Here</a> <a href=\"#\" class=\"adhere100px\">Advertise Here</a> <a href=\"#\" class=\"adhere100px\">Advertise Here</a> </div>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/home/elements.html.erb",
    "content": "        <style type=\"text/css\">\ninput[type=\"text\"]\n{\n  -moz-border-radius:4px 4px 4px 4px;\n  -webkit-border-radius:4px;\n  float:right;margin:1.5em 0;\n  padding:10px 11px;\n  width:362px;\n  background: url(images/static/text-form-bg.jpg) repeat-x\n}\n\ninput[type=\"password\"]\n{\n  -moz-border-radius:4px 4px 4px 4px;\n  -webkit-border-radius:4px;\n  float:right;\n  margin:1.5em 0;\n  padding:10px 11px;\n  width:362px;\n  background: url(images/static/text-form-bg.jpg) repeat-x\n}\ntextarea {\n  -webkit-border-radius:4px;\n  -moz-border-radius:4px 4px 4px 4px;\n  float:right;\n  height:100px;\n  width:373px;\n  background: #fff url(images/static/text-form-bg.jpg) repeat-x;\n  }\n    </style>\n<div id=\"inner-page\">\n  <div class=\"container\">\n    <%= render :partial => 'header', :locals => {:page => 'about'} %>\n\n      <div class=\"clear span-12 last\" id=\"main-inner\">\n        <div class=\"span-8 left-content-secondary\">\n\n         <div class=\"span-8 first inner-page-title\">\n          <h2 class=\"main-title-2\">CSS Basic Elements</h2>\n          <span>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. </span>\n      </div>\n\n<p>The purpose of this HTML is to help determine what default settings are with CSS and to make sure that all possible HTML Elements are included in this HTML so as to not miss any possible Elements when designing a site.</p>\n\n<hr />\n\n<h1 id=\"headings\">Headings</h1>\n\n<h1>Heading 1</h1>\n<h2>Heading 2</h2>\n<h3>Heading 3</h3>\n<h4>Heading 4</h4>\n<h5>Heading 5</h5>\n<h6>Heading 6</h6>\n\n<small><a href=\"#wrapper\">[top]</a></small>\n<hr />\n\n\n<h1 id=\"paragraph\">Paragraph</h1>\n\n<img style=\"float:right\" src=\"/images/static/image.jpg\" alt=\"\" />\n<p>Lorem ipsum dolor sit amet, <a href=\"#\" title=\"test link\">test link</a> adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec, gravida vehicula, nisl. Praesent mattis, massa quis luctus fermentum, turpis mi volutpat justo, eu volutpat enim diam eget metus. Maecenas ornare tortor. Donec sed tellus eget sapien fringilla nonummy. Mauris a ante. Suspendisse quam sem, consequat at, commodo vitae, feugiat in, nunc. Morbi imperdiet augue quis tellus.</p>\n\n<p>Lorem ipsum dolor sit amet, <em>emphasis</em> consectetuer adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec, gravida vehicula, nisl. Praesent mattis, massa quis luctus fermentum, turpis mi volutpat justo, eu volutpat enim diam eget metus. Maecenas ornare tortor. Donec sed tellus eget sapien fringilla nonummy. Mauris a ante. Suspendisse quam sem, consequat at, commodo vitae, feugiat in, nunc. Morbi imperdiet augue quis tellus.</p>\n\n<small><a href=\"#wrapper\">[top]</a></small>\n<hr />\n\n<h1 id=\"list_types\">List Types</h1>\n\n<h3>Definition List</h3>\n<dl>\n  <dt>Definition List Title</dt>\n  <dd>This is a definition list division.</dd>\n</dl>\n\n<h3>Ordered List</h3>\n<ol>\n  <li>List Item 1</li>\n  <li>List Item 2</li>\n  <li>List Item 3</li>\n</ol>\n\n<h3>Unordered List</h3>\n<ul>\n  <li>List Item 1</li>\n  <li>List Item 2</li>\n  <li>List Item 3</li>\n</ul>\n\n<small><a href=\"#wrapper\">[top]</a></small>\n<hr />\n\n<h1 id=\"form_elements\">Fieldsets, Legends, and Form Elements</h1>\n\n<fieldset>\n  <legend>Legend</legend>\n\n  <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec, gravida vehicula, nisl. Praesent mattis, massa quis luctus fermentum, turpis mi volutpat justo, eu volutpat enim diam eget metus.</p>\n\n  <form>\n    <h2>Form Element</h2>\n\n    <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui.</p>\n\n    <p><label for=\"text_field\">Text Field:</label><br />\n    <input type=\"text\" id=\"text_field\" /></p>\n\n    <p><label for=\"text_area\">Text Area:</label><br />\n    <textarea id=\"text_area\">Text Area</textarea></p>\n\n    <p><label for=\"select_element\">Select Element:</label><br />\n      <select name=\"select_element\">\n      <optgroup label=\"Option Group 1\">\n        <option value=\"1\">Option 1</option>\n        <option value=\"2\">Option 2</option>\n        <option value=\"3\">Option 3</option>\n      </optgroup>\n      <optgroup label=\"Option Group 2\">\n        <option value=\"1\">Option 1</option>\n        <option value=\"2\">Option 2</option>\n        <option value=\"3\">Option 3</option>\n      </optgroup>\n    </select></p>\n\n    <p><label for=\"radio_buttons\">Radio Buttons:</label><br />\n      <input type=\"radio\" class=\"radio\" name=\"radio_button\" value=\"radio_1\" /> Radio 1<br/>\n        <input type=\"radio\" class=\"radio\" name=\"radio_button\" value=\"radio_2\" /> Radio 2<br/>\n        <input type=\"radio\" class=\"radio\" name=\"radio_button\" value=\"radio_3\" /> Radio 3<br/>\n    </p>\n\n    <p><label for=\"checkboxes\">Checkboxes:</label><br />\n      <input type=\"checkbox\" class=\"checkbox\" name=\"checkboxes\" value=\"check_1\" /> Radio 1<br/>\n        <input type=\"checkbox\" class=\"checkbox\" name=\"checkboxes\" value=\"check_2\" /> Radio 2<br/>\n        <input type=\"checkbox\" class=\"checkbox\" name=\"checkboxes\" value=\"check_3\" /> Radio 3<br/>\n    </p>\n\n    <p><label for=\"password\">Password:</label><br />\n      <input type=\"password\" class=\"password\" name=\"password\" />\n    </p>\n\n    <p><label for=\"file\">File Input:</label><br />\n      <input type=\"file\" class=\"file\" name=\"file\" />\n    </p>\n\n\n    <p> <input style=\"float:left; margin:0\" id=\"contact-submit\" type=\"submit\" name=\"submit\" value=\"submit\"/>\n    </p>\n\n\n\n  </form>\n\n</fieldset>\n\n<small><a href=\"#wrapper\">[top]</a></small>\n<hr />\n\n<h1 id=\"tables\">Tables</h1>\n\n<table cellspacing=\"0\" cellpadding=\"0\">\n  <tr>\n    <th>Table Header 1</th><th>Table Header 2</th><th>Table Header 3</th>\n  </tr>\n  <tr>\n    <td>Division 1</td><td>Division 2</td><td>Division 3</td>\n  </tr>\n  <tr class=\"even\">\n    <td>Division 1</td><td>Division 2</td><td>Division 3</td>\n  </tr>\n  <tr>\n    <td>Division 1</td><td>Division 2</td><td>Division 3</td>\n  </tr>\n\n</table>\n\n<small><a href=\"#wrapper\">[top]</a></small>\n<hr />\n\n<h1 id=\"misc\">Misc Stuff - abbr, acronym, pre, code, sub, sup, etc.</h1>\n\n<p>Lorem <sup>superscript</sup> dolor <sub>subscript</sub> amet, consectetuer adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. <cite>cite</cite>. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec, gravida vehicula, nisl. Praesent mattis, massa quis luctus fermentum, turpis mi volutpat justo, eu volutpat enim diam eget metus. Maecenas ornare tortor. Donec sed tellus eget sapien fringilla nonummy. <acronym title=\"National Basketball Association\">NBA</acronym> Mauris a ante. Suspendisse quam sem, consequat at, commodo vitae, feugiat in, nunc. Morbi imperdiet augue quis tellus.  <abbr title=\"Avenue\">AVE</abbr></p>\n\n<pre><p>Lorem ipsum dolor sit amet, nisl.<acronym title=\"National Basketball Association\">NBA</acronym> Mauris a ante. <abbr title=\"Avenue\">AVE</abbr></p></pre>\n\n<blockquote>\n  \"This stylesheet is going to help so freaking much.\" <br />-Blockquote\n</blockquote>\n\n<small><a href=\"#wrapper\">[top]</a></small>\n\n        </div>\n        <div class=\"span-4 last right-content-secondary\">\n              <h1>Hello World</h1>\n\n              <br />\n               <p>\n        Lorem ipsum dolor sit amet, test link adipiscing elit. Nullam dignissim convallis est. Quisque aliquam. Donec faucibus. Nunc iaculis suscipit dui. Nam sit amet sem. Aliquam libero nisi, imperdiet at, tincidunt nec, gravida vehicula, nisl. Praesent mattis, massa quis luctus fermentum, turpis mi volutpat justo, eu volutpat enim diam eget metus. Maecenas ornare tortor. Donec sed tellus eget sapien fringilla nonummy. Mauris a ante. Suspendisse quam sem, consequat at, commodo vitae, feugiat in, nunc. Morbi imperdiet augue quis tellus.\n </p>\n      </div>\n    </div>\n\n\n\n  </div>\n      <div class=\"clear last clearfix\" id=\"footer\">\n\n    <div class=\"clear last\" id=\"top-footer\">\n        <a href=\"#\"><img class=\"footer-logo clear\" src=\"/images/static/footer-logo.png\" alt=\"\" width=\"252\" height=\"81\" /></a>\n      <div class=\"span-3 copyright\">\n\n        <p>Portions of this content are ©2008–2009 by individual Ivor Padilla. Content available under a Creative Commons license.</p>\n        <a href=\"#\">Privacy Policy</a>  | <a href=\"#\"> Contact Us</a>\n      </div>\n      <div class=\"span-3 footer-list\">\n      <h3>Products</h3>\n        <ul>\n        <li><a href=\"#\">Meet the Company</a></li>\n        <li><a href=\"#\">Pricings</a></li>\n        <li><a href=\"#\">Examples</a></li>\n        <li><a href=\"#\">Features</a></li>\n        <li><a href=\"#\">Sign up</a></li>\n        <li><a href=\"#\">Latest Products</a></li>\n        <li><a href=\"#\">Our Showcase</a></li>\n        <li><a href=\"#\">Lorem Ipsum Dolor</a></li>\n        </ul>\n      </div>\n      <div class=\"span-3 footer-list\">\n        <h3>Company</h3>\n        <ul>\n        <li><a href=\"#\">About Us</a></li>\n        <li><a href=\"#\">Contact Us</a></li>\n        <li><a href=\"#\">Term of Services</a></li>\n        <li><a href=\"#\">Privacy</a></li>\n        <li><a href=\"#\">Be Our Fan in Facebook</a></li>\n        <li><a href=\"#\">We are also in Twitter</a></li>\n        </ul>\n      </div>\n      <div class=\"span-3 last footer-list\">\n        <h3>Our Projects</h3>\n        <ul>\n        <li><a href=\"#\">Envato Pty Ltd.</a></li>\n        <li><a href=\"#\">ThemeForest</a></li>\n        <li><a href=\"#\">SmashingMagazine</a></li>\n        <li><a href=\"#\">Loon Design</a></li>\n        <li><a href=\"#\">BetterMeans Bug Trac</a></li>\n        <li><a href=\"#\">ActiveDen Redesign</a></li>\n        <li><a href=\"#\">Workawesome iPhone App</a></li>\n        </ul>\n      </div>\n    </div>\n\n    <div class=\"clear last\" id=\"bottom-footer\">\n      <div class=\"span-6 append-6 last menu-lite\">\n      <ul>\n  <li><a href=\"#\">Home</a></li>\n  <li><a href=\"#\">About Us</a></li>\n  <li><a href=\"#\">Pricing</a></li>\n  <li><a href=\"#\">Products</a></li>\n  <li><a href=\"#\">Contact Us</a></li>\n</ul>\n"
  },
  {
    "path": "app/views/home/features_original.html.erb",
    "content": "<script type=\"text/javascript\">\n    $(document).ready(function() {\n      $(\"a.example\").fancybox({\n        'titleShow'     : false,\n        'transitionIn'  : 'elastic',\n        'transitionOut'  : 'elastic'\n      });\n    });\n  </script>\n<div id=\"inner-page\">\n  <div class=\"container\">\n   <%= render :partial => 'header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"clear span-12\">\n        <div class=\"span-8 first inner-page-title\">\n          <h2 class=\"main-title-2\">See our latest products</h2>\n          <span>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. </span> </div>\n        <div class=\"clear\"></div>\n        <div class=\"span-12\" id=\"gallery\">\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-1_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-2_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-2.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-3_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-3.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-4_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-4.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n\n<script type=\"text/javascript\">\n      $(document).ready(function() {\n        $('.viewport').mouseenter(function(e) {\n          $(this).children('a').children('img').animate({ height: '268', left: '-20', top: '-20', width: '480'}, 100);\n          $(this).children('a').children('span').fadeIn(300);\n        }).mouseleave(function(e) {\n          $(this).children('a').children('img').animate({ height: '268', left: '-20', top: '-20', width: '480'}, 100);\n          $(this).children('a').children('span').fadeOut(200);\n        });\n      });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "app/views/home/how.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n   <%= render :partial => 'header', :locals => {:page => 'how'} %>\n\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div>\n      <h1>how does an open enterprise work?</h1>\n      <span class=\"span-12 left whitebox\">\n        <span class=\"span-6 left colborder\">\n          <h2>New Team Structure</h2>\n                      <p>No more pyramids, job titles or direct reports. </p>\n                      <p>Everyone is a member, and every member gets an equal binding vote. When people first join they are contributors. Votes are recorded, but are non-binding. This way, teams can get a sense of the crowd’s voice but ultimately the team members drive the direction of the project.</p>\n                      <p>Contributors are nominated to be members, and are voted in by the core team. The core team is a subset of the members who can vote in new members.</p>\n                      <p>Anyone can be nominated to any level in an open enterprise, and everyone is accountable to eachother. The result is <strong>a healthy and dynamic hierarchy replaces the rigid proscribed one.</strong></p>\n        </span>\n        <span class=\"span-6 left last\">\n          <span class=\"viewport\">\n          <a class=\"videolink\" href=\"http://www.youtube.com/v/IdcAxGGRafc&hl=en&fs=1&autoplay=1&fmt=6\" target=\"blank\" title=\"open enterprise governance\">\n          <img src=\"/images/static/openenterprisegovernance.jpg\" />\n          </a>\n          </span>\n          <blockquote>You never change things by fighting the existing reality. To change something, build a new model that makes the existing model obsolete<author>Buckminster Fuller</author></blockquote>\n        </span>\n\n\n      </span>\n      </div>\n\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <blockquote>Greater transparency is an unstoppable force… the Internet makes it far easier for firms to supply information, and harder for them to keep secrets.  With greater transparency will come greater accountability and better corporate behaviour. Rather than engage in futile resistance to it, firms should actively embrace transparency and rethink their values and generally get in better shape<author>Don Tapscott, The Naked Corporation</author></blockquote>\n              </span>\n              <span class=\"span-6 left last\">\n                <h2>Full Transparency</h2>\n                            <p>Take away secrets, and different levels of access to information, and you take away two of the most common ways power is abused.</p>\n                            <p>Clear, simple governance rules, keeps people and teams accountable to themselves and each other. All resulting in less internal politics, and abuse of power</p>\n              </span>\n            </span>\n      </div>\n\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <h2>Distributed Leadership. Not Management</h2>\n                            <p>Work is arranged in project workstreams. Members and contributors move freely from one project workstream to another. Choosing the work that has been collectively prioritized. Doing only what they are convinced needs doing.</p>\n                            <p>Situational leadership emerges through influence, instead of pre-set management through coersion</p>\n                            <p>No departments, ceos, or managers.</p><p> No committees, or predefined roles or areas of responsibility. No one is told what to do.</p>\n              </span>\n              <span class=\"span-6 left last\">\n                    <span class=\"viewport\">\n                <a class=\"fancy_image\" HREF=\"/images/static/mindmap.jpg\" title=\"Open Enterprise Principles Mindmap\"> <span class=\"dark-background\"></span> <img src=\"/images/static/mindmap-medium.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a></span>\n                <blockquote>This era doesn't call for better management. It calls for a renaissance of self-direction<author>Daniel Pink</author></blockquote>\n              </span>\n\n            </span>\n      </div>\n      <div class=\"paint\">\n        <p>\n        take a look at our<br><a href=\"/front/pricing.html\">plans and pricing</a>\n        </p>\n      </div>\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <br><br><br>\n                <blockquote>They must find it difficult, those who have taken authority as truth rather than truth as authority.<author>Massey Massey</author></blockquote>\n              </span>\n              <span class=\"span-6 left last\">\n                <h2>Efficient &amp; Inclusive<br>Decision-Making</h2>\n                            <p>Using a lazy-majority voting system, not everyone has to vote. And those who show up are the ones who influence what happens</p>\n                            <p>Learn about the details in the <a href=\"/front/open_enterprise_governance_model.html\" target=\"_blank\">Open Enterprise Governance Model</a></p>\n              </span>\n            </span>\n      </div>\n\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <h2>Contribution-Based Compensation</h2>\n                            <p>The Open Enterprise model is a <strong>peer-managed, self-correcting, results-only work environment.</strong> No salaries, bonuses, annual-reviews, or time-tracking needed. Compensation is based on contribution, as assessed by peers.</p>\n                            <p>Here is how it works:</p>\n                              <p>After a group of work items is completed, a retrospective automatically starts. Each person who worked on this group of item assesses:</p>\n                              <ul>\n                                    <li>the percentage of the work they think they did</li>\n                                    <li>the percentage of the work they think others did</li>\n                                    <li>how confident they are of their esitmate</li>\n                              </ul>\n\n                              <p>Everyone is compensated based on the average assessment they recieve from their peers. A reputation matrix tracks how accurately each person assesses themselves and others over time.</p>\n                              <p style=\"font-style:italic\">Note: This is an optional module that can be toggled for any project workstream.</p>\n                            </span>\n\n                            <span class=\"span-6 left last\">\n                              <span class=\"viewport\">\n                              <a class=\"videolink\" href=\"http://www.youtube.com/v/ydHazAMogaw&hl=en&fs=1&autoplay=1&fmt=6\" target=\"blank\" title=\"retrospectives\">\n                              <img src=\"/images/static/retro_video.png\" />\n                              </a>\n                              </span>\n                              <br><br>\n                              <blockquote>Heaven is purpose, principle, and people. Purgatory is paper and procedure. Hell is rules and regulations<author>Dee Hock, Founder and CEO of VISA</author></blockquote>\n\n            </span>\n      </div>\n\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <blockquote>In the age of hand-crafting, the dominant forms of organization were the all-powerful churches, kingdoms, and hand-craftsmen guilds. Just as the age of machine-crafting led to the emergence of today’s organizations, ending the dominance of guilds, kingdoms, and churches, so too will the age of mind-crafting give rise to new, more chaordic concepts of organization that will end the dominance of today’s organizational structures<br><author>Dee Hock, CEO and Founder of VISA</author></blockquote>\n              </span>\n              <span class=\"span-6 left last\">\n                <h2>Low Barrier to Joining</h2>\n                            <p>No interviews, resumes, or references.</p>\n                            <p>Transparency, public knowledge, and a set governance structure allow anyone who wants to get involved to do so.</p>\n                            <p>Non-binding votes keep the integrity and direction of the organization. Public knowledge allows people to be onboarded in days, with minimal cost to existing members.</p>\n                            <p>The semi-permeable membrane of the governance model makes it easy for folks to volunteer, and for an open enterprise to scale.</p>\n              </span>\n            </span>\n      </div>\n\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <h2>Shared Values:<br>Purpose is Primary</h2>\n                            <p>An Open Enterprise is a community that forms around a shared value and purpose. Agreement around a shared value or set of values is the fundamental cohesive force that binds the organization.</p><p><strong>Purpose is primary, goals secondary</strong> because as the organization moves towards a goal, new experiences may inform the group to change the goal. </p><p>The goals, therefore, must be allowed to evolve. Values change much much slower, so they become the guiding principles which determine when new goals need to be added added, and old ones altered or let go.</p>\n              </span>\n              <span class=\"span-6 left last\">\n                <h2>Order Derived from Cohesive Intent, Not Control.</h2>\n                <p>Old ways of thought suggest that order only happens when one person is in control, or when an executive few make informed decisions for the entire group. This assumption ignores nature and countless situations in which order arrives out of chaos. </p>\n                <p>By contrast, in an Open Enterprise, all actions arise organically and through self-motivation to further the shared values of the group. This principle is at the very heart of the Open Enterprise because self-driven action is far more powerful, efficient, and innovative than coerced action. It gives the Open Enterprise it’s sheer power to get 10 times the work done in half the time as a conventional organization.</p>\n              </span>\n            </span>\n      </div>\n      <div class=\"paint\">\n        <p>\n        &nbsp; <br>checkout the <a href=\"/front/what.html\">platform features</a>\n        </p>\n      </div>\n      <div id=\"pricing-col\" class=\"span-12 clear\">\n        <h2>Frequently Asked Questions</h2>\n        <div class=\"column span-5 left first\">\n          <h4>Is this a proven model?</h4>\n          <p>Various aspects of the Open Enterprise Model have been used successfully by other organizations including Visa, Goretex, Apache Software, Wikipedia, Linux, Spain’s Mondragón Corporación Cooperativa and many others.</p><p> While such companies have pioneered these concepts with excellent results, BetterMeans is revolutionary in bringing these various techniques together in a single, cohesive model.</p>\n          <p>Leading business thinkers such as Gary Hamel and Margaret Wheately see the change in organizational design coming, and are advising companies today to embrace more self-organizing structures.</p>\n          <p>The Open Enterprise model builds on their theories and research, and provides a new way for people to work together that governs all major aspects of managing a business, including capital allocation, strategic decision-making, compensation, and human resource management.</p>\n          <p>We ourselves have been running as an Open Enterprise since 2009. You can <a href=\"http://secure.bettermeans.com/projects/bm\">checkout our project page here</a></p>\n          <h4>Is your code open source.</h4>\n          <p>Yes!</p>\n          <p>Please fork us here: <a href=\"http://github.com/bettermeans/bettermeans\">http://github.com/bettermeans/bettermeans</a></p>\n        </div>\n        <div class=\"column span-5 left last\">\n          <h4>Can we still use salaries?</h4>\n          <p>Absolutely. We love <a href=\"http://help.bettermeans.com/retrospectives\">our retrospective system</a>, but understand that many people will prefer to use standard salary systems (or others) to manage compensation.</p>\n          <p>The credits system is an optional module that you can turn on or off at will.</p>\n\n          <h4>Is this for only volunteer-run projects?</h4>\n          <p>Not at all. Our mission is help people earn right livelihood in the world.</p>\n          <p>Having said that, our governance structures were heavily influenced by the open source world, and therefore work really well for volunteer run efforts.</p>\n          <h4>Does everything have to be public?</h4>\n          <p>Nope. We think fully public orgs are the way forward, but we understand the need for privacy. It is possible to run some (or all) of your projects as private workstreams.</p>\n          <p>All members will still have access to these private project workstreams, but you can be selective about which contributors get access to them, and the general public will not be able to see them.</p>\n          <h4>What kind of organization is this best for?</h4>\n          <p>Social enterprises and movements. Open source software projects. Volunteer-based orgs. Content production. Knowledge-based collaboration. Event planning. And hopefully other applications that will surprise us!</p>\n          <h4>I have more questions...</h4>\n          <p>Great! We love talking about this stuff. Get in touch at <a href=\"mailto:support@bettermeans.com\">support@bettermeans.com</a></p>\n           <blockquote>Even though worker capacity and motivation are destroyed when leaders choose power over productivity, it appears that bosses would rather be in control than have the organization work well.<author>Margaret Wheatley</author></blockquote>\n\n        </div>\n      </div>\n\n      <div class=\"clear\"></div>\n    </div>\n  </div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "app/views/home/hq.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n    <%= render :partial => 'header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"span-8 first inner-page-title\">\n        <h2 class=\"main-title-2\">Our great headquarters, come and see</h2>\n        <span>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. </span> </div>\n      <div id=\"hq-main\">\n        <div class=\"span-6 first clear\" id=\"hq-left-intro\">\n          <p class=\"strong\">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. </p>\n          <p>Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus.</p>\n          <img src=\"/images/static/findus.png\" alt=\"\" /> </div>\n        <div class=\"span-3 hq-info\"> <img src=\"/images/static/hq-1.jpg\" alt=\"Dummy Image\" />\n          <h3>Our Headplex</h3>\n          <span>Meet our offices</span>\n          <p>Lorem ipsum dolor sit amet dolor sit, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem.</p>\n        </div>\n        <div class=\"span-3 last hq-info\"> <img src=\"/images/static/hq-2.jpg\" alt=\"Dummy Image\" />\n          <h3>Magic HQ's</h3>\n          <span>Meet our offices</span>\n          <p>Lorem ipsum dolor sit amet dolor sit, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem.</p>\n        </div>\n        <div class=\"clear\"></div>\n        <hr />\n        <div id=\"video-add\">\n          <div class=\"span-5 first clear\">\n            <h3>See our latest video</h3>\n            <p><strong>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</strong></p>\n            <p> Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus.</p>\n            <p>Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus.</p>\n          </div>\n          <div class=\"span-7 last video\">\n            <object width=\"530\" height=\"285\">\n              <param name=\"allowfullscreen\" value=\"true\" />\n              <param name=\"allowscriptaccess\" value=\"always\" />\n              <param name=\"movie\" VALUE=\"../../../vimeo.com/moogaloop.swf@clip_id=4740824&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1\" />\n              <embed SRC=\"../../../vimeo.com/moogaloop.swf@clip_id=4740824&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1\" type=\"application/x-shockwave-flash\" allowfullscreen=\"true\" allowscriptaccess=\"always\" width=\"530\" height=\"285\"></embed>\n            </object>\n            <p><a HREF=\"../../../vimeo.com/4740824\">Sci-Fi Bumber</a> from <a HREF=\"../../../vimeo.com/user1701783\">Aaron Houston</a> on <a HREF=\"../../../vimeo.com/index.htm\">Vimeo</a>.</p>\n          </div>\n        </div>\n        <div class=\"clear\"></div>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/home/index.html.erb",
    "content": "<div id=\"page\">\n  <div class=\"container\">\n    <%= render :partial => 'home/header', :locals => {:page => 'home'} %>\n      <div class=\"learnMore span-12\">\n      </div>\n    <div class=\"span-12 left\" id=\"homebanner\">\n      <span class=\"span-5 left colborder\">\n        <h1>Open, Democratic Project Management</h1>\n        <h2>\n          Decide together.<br>\n          Get things done.<br>\n          No bosses needed.\n        </h2>\n        <h3>Use open-source decision-making rules,<br>and self-organizing principles<br> to run your real-world projects.</h3>\n        <div class=\"signup-area\">\n        <div class=\"signup-button left\">\n          <a href=\"/front/pricing.html\">See plans &amp; pricing</a>\n        </div>\n        </div>\n\n      </span>\n    </div>\n    <div class=\"clear span-12 last\" id=\"main-inner-testimonial\" style=\"margin-top:0px\">\n      <img src=\"/images/static/forbes_logo.png\" class=\"right\" width=\"120px\" style=\"padding-left:20px\"/>\n      <p>\"Bettermeans paints an image of a modern business\"</p>\n    </div>\n    <div class=\"clear span-12 last\" id=\"main-inner\" style=\"margin-top:0px\">\n      <div>\n      <span class=\"span-12 left\">\n        <span class=\"span-6 left colborder\">\n          <h2>We need a new agreement of how we work together.</h2>\n          <p>How we make decisions. How we decide on who gets to work on what. And who gets paid what.</p>\n          <p>\n            Groups of people can work together intelligently, without getting bogged down in endless meetings, or slow decision making. No bossing needed.\n          </p>\n          <p>\n            <strong>Open source software and Wikipedia</strong>, are just two examples of large groups working together efficiently without fixed hierarchy.</p>\n          <p>Bettermeans lets you <strong>use the same decision-making rules, and self-organizing principles behind open source</strong> to run your project.\n          </p>\n          <div class=\"side-paint\">\n            <p>learn about <br><a href=\"/front/how.html\">how an open enterprise works</a></p>\n          </div>\n\n        </span>\n        <span class=\"span-6 left last\">\n          <p>\n            <span class=\"viewport\">\n              <a class=\"videolink\" href=\"http://www.youtube.com/v/MAlnMWlvw9g&amp;autoplay=1&amp;fmt=6\" target=\"blank\" title=\"bettermeans introduction\" name=\"videolink\">\n                <img src=\"/images/static/intro_video_image.png\">\n              </a></span>\n          </p>\n        <blockquote>Bettermeans is truly a new way of working within a team, and organizing projects.<br><br> It is a great way to promote collaborative, democratic decision making and cut out the traditional hierarchy of business.</blockquote>\n          <a target=\"blank\" href=\"http://thenextweb.com/apps/2010/11/04/try-this-better-means-a-democratic-open-approach-to-teamwork/\"><img src=\"/images/static/thenextweb.png\" height=\"50px\" style=\"float:right;margin-right:90px;\" /></a>\n        </span>\n      </span>\n      </div>\n      </div>\n    </div>\n\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/home/library.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n    <%= render :partial => 'header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"span-8 left-content-secondary\">\n        <div class=\"blog-post-single\"> <a class=\"blog-post-title\">Holiday Giveaways, Freebies and More!</a>\n          <div class=\"meta\">\n            <p class=\"sub-meta\">Posted December 6, 2009 in <a href=\"#\">Business</a>, <a href=\"#\">Productivity </a></p>\n          </div>\n          <div class=\"comments-counter\"> <a href=\"#\">40 Comments &raquo;</a> </div>\n          <div class=\"blog-content\"> <a href=\"#\"><img src=\"/images/static/image-post1.jpg\" alt=\"Image Post\"  /></a>\n            <p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis,   ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. </p>\n            <p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis,   ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.</p>\n            <h3>Lorem ipsum dolor sit amet</h3>\n            <p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis,   ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. </p>\n            <p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis,   ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.</p>\n          </div>\n          <p class=\"rating\">(8 votes, average: 4.88 out of 5)</p>\n          <div class=\"tweetmemebutton tweetmeme right overflow\"> <a class=\"count\" href=\"#\" title=\"View Details\"><span class=\"c\">80</span><br />\n            <span class=\"t\">tweets</span> </a> <a class=\"retweet\" title=\"Retweet this\" href=\"#\"> retweet </a> </div>\n          <div id=\"author\" class=\"overflow clear\"> <img src=\"/images/static/author.jpg\" alt=\"\" width=\"43\" height=\"43\" />\n            <p>Hi, my name is Collis and I work at Envato where I provide general vision, design, marketing, new business ideas, and generally work very hard. Lorem ipsum dolor sit amet consequectur.</p>\n          </div>\n          <div id=\"comments-content\">\n            <h1>Discussion</h1>\n            <a class=\"comment-counter\" href=\"#comments-content\">10 comments</a>\n            <div>\n              <ol>\n                <li class=\"reader-comment\"> <img SRC=\"../../../ivor.bz/i/50x50\" alt=\"\" width=\"50\" height=\"50\"/> <a href=\"#\">Ivor Padilla</a> <span>on Thursday 19, 2010</span>\n                  <div class=\"clear\"></div>\n                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit vestibulum nibh, eu porttitor lorem scelerisque non. Nulla sed lorem metus. Integer eget nisi nulla, vitae euismod arcu. Morbi neque lorem, tempor non condimentum eu, commodo vel mi.</p>\n                </li>\n                <li class=\"reader-comment\"> <img SRC=\"../../../ivor.bz/i/50x50\" alt=\"\" width=\"50\" height=\"50\"/> <a href=\"#\">Ivor Padilla</a> <span>on Thursday 19, 2010</span>\n                  <div class=\"clear\"></div>\n                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit vestibulum nibh, eu porttitor lorem scelerisque non. Nulla sed lorem metus. Integer eget nisi nulla, vitae euismod arcu. Morbi neque lorem, tempor non condimentum eu, commodo vel mi.</p>\n                </li>\n                <li class=\"reader-comment\"> <img SRC=\"../../../ivor.bz/i/50x50\" alt=\"\" width=\"50\" height=\"50\"/> <a href=\"#\">Ivor Padilla</a> <span>on Thursday 19, 2010</span>\n                  <div class=\"clear\"></div>\n                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit vestibulum nibh, eu porttitor lorem scelerisque non. Nulla sed lorem metus. Integer eget nisi nulla, vitae euismod arcu. Morbi neque lorem, tempor non condimentum eu, commodo vel mi.</p>\n                </li>\n                <li class=\"reader-comment\"> <img SRC=\"../../../ivor.bz/i/50x50\" alt=\"\" width=\"50\" height=\"50\"/> <a href=\"#\">Ivor Padilla</a> <span>on Thursday 19, 2010</span>\n                  <div class=\"clear\"></div>\n                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit vestibulum nibh, eu porttitor lorem scelerisque non. Nulla sed lorem metus. Integer eget nisi nulla, vitae euismod arcu. Morbi neque lorem, tempor non condimentum eu, commodo vel mi.</p>\n                </li>\n                <li class=\"reader-comment\"> <img SRC=\"../../../ivor.bz/i/50x50\" alt=\"\" width=\"50\" height=\"50\"/> <a href=\"#\">Ivor Padilla</a> <span>on Thursday 19, 2010</span>\n                  <div class=\"clear\"></div>\n                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit vestibulum nibh, eu porttitor lorem scelerisque non. Nulla sed lorem metus. Integer eget nisi nulla, vitae euismod arcu. Morbi neque lorem, tempor non condimentum eu, commodo vel mi.</p>\n                </li>\n                <li class=\"reader-comment\"> <img SRC=\"../../../ivor.bz/i/50x50\" alt=\"\" width=\"50\" height=\"50\"/> <a href=\"#\">Ivor Padilla</a> <span>on Thursday 19, 2010</span>\n                  <div class=\"clear\"></div>\n                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit vestibulum nibh, eu porttitor lorem scelerisque non. Nulla sed lorem metus. Integer eget nisi nulla, vitae euismod arcu. Morbi neque lorem, tempor non condimentum eu, commodo vel mi.</p>\n                </li>\n                <li class=\"reader-comment\"> <img SRC=\"../../../ivor.bz/i/50x50\" alt=\"\" width=\"50\" height=\"50\"/> <a href=\"#\">Ivor Padilla</a> <span>on Thursday 19, 2010</span>\n                  <div class=\"clear\"></div>\n                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit vestibulum nibh, eu porttitor lorem scelerisque non. Nulla sed lorem metus. Integer eget nisi nulla, vitae euismod arcu. Morbi neque lorem, tempor non condimentum eu, commodo vel mi.</p>\n                </li>\n                <li class=\"reader-comment\"> <img SRC=\"../../../ivor.bz/i/50x50\" alt=\"\" width=\"50\" height=\"50\"/> <a href=\"#\">Ivor Padilla</a> <span>on Thursday 19, 2010</span>\n                  <div class=\"clear\"></div>\n                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit vestibulum nibh, eu porttitor lorem scelerisque non. Nulla sed lorem metus. Integer eget nisi nulla, vitae euismod arcu. Morbi neque lorem, tempor non condimentum eu, commodo vel mi.</p>\n                </li>\n                <li class=\"reader-comment\"> <img SRC=\"../../../ivor.bz/i/50x50\" alt=\"\" width=\"50\" height=\"50\"/> <a href=\"#\">Ivor Padilla</a> <span>on Thursday 19, 2010</span>\n                  <div class=\"clear\"></div>\n                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit vestibulum nibh, eu porttitor lorem scelerisque non. Nulla sed lorem metus. Integer eget nisi nulla, vitae euismod arcu. Morbi neque lorem, tempor non condimentum eu, commodo vel mi.</p>\n                </li>\n                <li class=\"reader-comment\"> <img SRC=\"../../../ivor.bz/i/50x50\" alt=\"\" width=\"50\" height=\"50\"/> <a href=\"#\">Ivor Padilla</a> <span>on Thursday 19, 2010</span>\n                  <div class=\"clear\"></div>\n                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit vestibulum nibh, eu porttitor lorem scelerisque non. Nulla sed lorem metus. Integer eget nisi nulla, vitae euismod arcu. Morbi neque lorem, tempor non condimentum eu, commodo vel mi.</p>\n                </li>\n              </ol>\n            </div>\n          </div>\n          <div id=\"comment-box\">\n            <h3>Leave a comment</h3>\n            <div class=\"comment-intro\">\n              <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>\n            </div>\n            <form id=\"blog-comment-form\"  action=\"\" method=\"post\">\n              <p>\n                <label for=\"first\">Name</label>\n                <input type=\"text\" name=\"first\" id=\"first\" value=\"Name\" onFocus=\"if (this.value == 'Name') {this.value = '';}\" onBlur=\"if (this.value == '') {this.value = 'Name';}\"/>\n              </p>\n              <p>\n                <label for=\"first\">Email</label>\n                <input type=\"text\" name=\"first\" value=\"Email\" onFocus=\"if (this.value == 'Email') {this.value = '';}\" onBlur=\"if (this.value == '') {this.value = 'Email';}\" />\n              </p>\n              <p>\n                <label for=\"first\">Website</label>\n                <input type=\"text\" name=\"first\" value=\"Website\" onFocus=\"if (this.value == 'Website') {this.value = '';}\" onBlur=\"if (this.value == '') {this.value = 'Website';}\"/>\n              </p>\n              <p>\n                <label for=\"first\">Comments</label>\n                <textarea>\n\n  </textarea>\n              </p>\n              <input style=\"margin:0\" id=\"contact-submit\" class=\"comments\" type=\"submit\" name=\"submit\" value=\"submit\"/>\n            </form>\n          </div>\n        </div>\n      </div>\n      <div class=\"span-4 last right-content-secondary sidebar\">\n        <div id=\"categories\">\n          <div class=\"sidebar-title\">\n            <h1>Categories</h1>\n            <div class=\"arrow\">.</div>\n          </div>\n          <ul class=\"blog-sidebar-a\">\n            <li> <a href=\"#\">ThemeForest Giveaways</a> </li>\n            <li> <a href=\"#\">PSDTuts Giveaways</a> </li>\n            <li> <a href=\"#\">Photoshop</a> </li>\n            <li> <a href=\"#\">Adobe Fireworks</a> </li>\n            <li> <a href=\"#\">NewsFlash</a> </li>\n            <li> <a href=\"#\">Apple iMac</a> </li>\n            <li> <a href=\"#\">Haiti Earthquake</a> </li>\n          </ul>\n        </div>\n        <div id=\"archives\">\n          <div class=\"sidebar-title\">\n            <h1>Archives</h1>\n            <div class=\"arrow\">.</div>\n          </div>\n          <ul class=\"blog-sidebar-a\">\n            <li> <a href=\"#\">January</a> </li>\n            <li> <a href=\"#\">February</a> </li>\n            <li> <a href=\"#\">March</a> </li>\n            <li> <a href=\"#\">April</a> </li>\n            <li> <a href=\"#\">May</a> </li>\n            <li> <a href=\"#\">June</a> </li>\n            <li> <a href=\"#\">July</a> </li>\n          </ul>\n        </div>\n        <div id=\"text-widget\">\n          <div class=\"sidebar-title\">\n            <h1>Text Widget</h1>\n            <div class=\"arrow\">.</div>\n          </div>\n          <div class=\"boxxx\">\n            <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>\n          </div>\n        </div>\n        <div id=\"ads\">\n          <div class=\"sidebar-title\">\n            <h1>Advertisement</h1>\n            <div class=\"arrow\">.</div>\n          </div>\n          <div class=\"ad-boxes\"> <a href=\"#\" class=\"adhere100px center\">Advertise Here</a> <a href=\"#\" class=\"adhere100px\">Advertise Here</a> <a href=\"#\" class=\"adhere100px\">Advertise Here</a> <a href=\"#\" class=\"adhere100px\">Advertise Here</a> </div>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/home/old_index.html.erb",
    "content": "<div id=\"page\">\n  <div class=\"container\">\n    <%= render :partial => 'home/header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"banner\">\n      <div  class=\"span-7\" id=\"description\">\n        <p><br>Start your project now<br>Run it democratically<br>Make your impact</p><br>\n        <a class=\"pricing-buttom\" HREF=\"/front/pricing.html\" title=\"Signup for free\">Signup for free</a> <span>or&nbsp;&nbsp;&nbsp;&nbsp;<a HREF=\"/account/register\">sign up for free</a></span> <small>sign up in 60 seconds. fast and secure.</small>\n         </div>\n      <div class=\"span-5 last\" id=\"\" style=\"text-align:center;\"><br><br>\n        <object width=\"350\" height=\"287\"><param name=\"movie\" value=\"http://www.youtube.com/v/mMbpejV3NTg&amp;hl=en_US&amp;fs=1\"></param><param name=\"allowFullScreen\" value=\"true\"></param><param name=\"allowscriptaccess\" value=\"always\"></param><embed src=\"http://www.youtube.com/v/mMbpejV3NTg&amp;hl=en_US&amp;fs=1\" type=\"application/x-shockwave-flash\" allowscriptaccess=\"always\" allowfullscreen=\"true\" width=\"350\" height=\"287\"></embed></object>\n      </div>\n    </div>\n    <br><br>\n    <div style=\"text-align:center;\">\n    <img src=\"/images/landingmockup.png\" alt=\"\" style=\"padding:33px\">\n    </div>\n\n    <div class=\"clear span-12 last\" id=\"main\">\n      <div class=\"span-12 last\" id=\"columns\">\n        <div class=\"span-4 cols\">\n          <a id=\"single_image\" class=\"fancy_image\" href=\"/images/static/home.png\"><img src=\"/images/static/home_small.png\" alt=\"\"/></a>\n          <h3>Run your project, don't just document it</h3>\n          <p>Using BetterMeans you can openly collaborate on projects, sharing ideas, discussing vision. All in a democratic way.</p>\n          <a class=\"readmore\" href=\"/front/features.html\" title=\"Read More\">Read More</a>\n          </div>\n        <div class=\"span-4 cols\">\n          <a id=\"single_image\" class=\"fancy_image\" href=\"/images/static/dashboard.png\"><img src=\"/images/static/dashboard_small.png\" alt=\"\"/></a>\n          <h3>Vote on ideas and prioritize work</h3>\n          <p>Everyone has a voice and every member has a vote.<br>\n          Work with each other towards a shared goal, fairly.</p>\n          <a class=\"readmore\" href=\"/front/features.html\" title=\"Read More\">Read More</a>\n          </div>\n        <div class=\"span-4 last cols\">\n          <a id=\"single_image\" class=\"fancy_image\" href=\"/images/static/activity.png\"><img src=\"/images/static/activity_small.png\" alt=\"\"/></a>\n          <h3>Democracy minus the bureaucracy</h3>\n          <p>Get rid of bottlenecks and make decisions with active members to move your work forward, fast. Decide together quickly. </p>\n          <a class=\"readmore\" href=\"/front/features.html\" title=\"Read More\">Read More</a>\n          </div>\n      </div>\n    </div>\n  </div>\n</div>\n<script type=\"text/javascript\">\n$(document).ready(function() {\n\n  /* This is basic - uses default settings */\n\n  $(\".fancy_image\").fancybox();\n});\n            $(function() {\n                $(\"#toTop\").scrollToTop({speed:500,start:700});\n            });\n        </script>\n\n"
  },
  {
    "path": "app/views/home/old_index2.html.erb",
    "content": "<div id=\"page\">\n  <div class=\"container\">\n    <%= render :partial => 'home/header', :locals => {:page => 'home'} %>\n      <div class=\"learnMore span-12\">\n        <h1 id=\"captio\">open, democratic, decentralized<br>social enterprise management</h1>\n\n\n\n\n        <div class=\"feature\">\n            <div onclick=\"slideShow(-1);\" class=\"fade-left\">\n              <img src=\"/images/static/fade-arrow-left.png\">\n            </div>\n            <div class=\"screenshot\">\n              <a class=\"videolink\" href=\"http://www.youtube.com/v/MAlnMWlvw9g&autoplay=1&fmt=6\" target=\"blank\" title=\"bettermeans in 3 minutes\">\n              <img src=\"/images/static/goals.png\" />\n              </a>\n            </div>\n            <div onclick=\"slideShow(1);\" class=\"fade\">\n              <img src=\"/images/static/fade-arrow.png\">\n            </div>\n        </div>\n      </div>\n\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div>\n      <span class=\"span-12 left whitebox\">\n        <span class=\"span-6 left colborder\">\n          <h2>To change our world, the way we work together needs upgrading</h2>\n                      <p>We are facing mounting social, environmental and economic problems.\n                        A lot of us want to work toward solving them and we are learning that these problems are interconnected, and complex.</p>\n                      <p>We are trying to solve these problems using organizational structures that were invented before the light bulb! Industrial-age organizations are not smart or flexible enough to navigate the challenges we are facing. </p>\n                        <p><strong>To change our world, we need a new agreement of how we work together.</strong> How we make decisions. How we decide on who gets to work on what. And who gets paid what.</p>\n\n\n        </span>\n        <span class=\"span-6 left last\">\n\n          <span class=\"viewport\">\n          <a class=\"fancy_image\" title=\"Principles of an Open Enterprise\" HREF=\"/images/static/principles.png\"> <span class=\"dark-background\"></span> <img src=\"/images/static/principles_medium.png\" alt=\"\" width=\"460\" height=\"247\"/> </a></span>\n          <blockquote>The significant problems we have cannot be solved at the same level of thinking with which we created them<author>Albert Einstein</author></blockquote>\n\n        </span>\n\n\n      </span>\n      </div>\n      <div class=\"paint\">\n        <p>\n        learn about <br><a href=\"/front/how.html\">how an open enterprise works</a></p>\n      </div>\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <h2>Social Entrepreneurs: Helping others do great work</h2>\n                <p>Two thirds of Americans have an idea for an entrepreneurial venture but only a tenth of them will carry through with it.  <strong>There are very few real sources of capital available for social entrepreneurs,</strong> and the current capital market, with very few exceptions, demands exponential growth from young startups with oppressive contractual agreements.</p>\n                <p>Innovations in social entrepreneurship are choked by the lack of supportive funding channels and the difficulty of finding and recruiting the appropriate workforce.  <strong>Entrepreneurs need better access to capital and talent,</strong> they need passionate people who will work because they believe in the idea, and commit to projects without being told what to do.</p>\n                <p>The Open Enterprise Model is <strong>a way for people with ideas to connect to others and get those ideas off the ground with minimal bureaucracy or resistance.</strong>  It harnesses the collective wisdom, creativity, passion, and productivity of a dispersed crowd - whether in one city block or across oceans - and channels their efforts in order to simply get good work done! Which is the real reason the majority of us wake up in the morning, to do good work in this world.</p>\n              </span>\n              <span class=\"span-6 left last\">\n                <span class=\"viewport\">\n                <a class=\"videolink\" href=\"http://www.youtube.com/v/OZaxoRi6IlE&autoplay=1&fmt=22\" target=\"blank\" title=\"tale of two tales\">\n                <img src=\"/images/static/taleoftwotales.jpg\" />\n                </a>\n                </span>\n                <br><br>\n                <blockquote>We will need a willingness to question our most deeply held habitual ways of seeing organizations and management. We will need a willingness eventually to embrace the seeming chaos of an organization that no one ‘runs’ and where we all share responsibility. We will need to embrace continual mistake-making and correcting, nature’s learning process. And we will need a willingness to surrender the personal need to control—‘the closet Newtonian’ that resides in all of us.<author>Dee Hock, CEO and Founder of Visa</author></blockquote>\n              </span>\n            </span>\n      </div>\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\"><br><br>\n                <blockquote>For thousands of years, markets and hierarchies were the only alternatives when it came to aggregating human effort. Now there's a third option: real-time, distributed networks.\n                <author>Gary Hamel<br> Voted #1 business thinker by the Wall Street Journal</author></blockquote>\n              </span>\n              <span class=\"span-6 left last\">\n                <h2>The Engagement Gap</h2>\n                <p> Our organizations are failing to engage us, and provide a place where our purpose comes alive.</p>\n                <p><strong>85% of people are disengaged from their work. Two of the top five reasons given are management and misalignment of values.</strong></p>\n                <p>The Internet provides us with tools to connect and work together, but the management system we're using cannot keep up; it's over 100 years old and was modeled after old military thinking.</p>\n              </span>\n            </span>\n      </div>\n      <div>\n            <h1>Collapse of the Corporate Model</h1>\n            <span class=\"span-12 left whitebox\">\n              <h2>Simply put, today's corporate organizational structure is outdated. The conventional business model is broken.</h2>\n              <h3>It’s broken because 67% of American workers are actively unhappy with their jobs.</h3>\n              <p>In fact, job dissatisfaction has increased steadily by a whopping 16% over the past 20 years. And this trend shows no sign of slowing. Notably, the <strong>most dissatisfied portion of the work force is the upcoming Generation Y</strong>—those under the age of 25.</p>\n              <h3>It’s broken because the current organizational structure cannot adapt as fast as the world is changing.</h3>\n              <p>Today's business model originated before plumbing and electricity—long before a global marketplace, multi-national competitors, and rapid technological change. The pace is quickening. In 2008 the number of patent applications received was over twice the number of applications in 1998, just 10 years prior. The current top-down model makes it impossible for a single leader or small team of decision-makers to discover, research, implement and dictate new protocols as fast the global landscape is demanding adaptation.</p>\n              <h3>It’s broken because in a top-down system, innovation is being smothered.</h3>\n              <p>The top must dictate behavior by creating endless manuals covering corporate procedures, protocols and policies. Threatened with punitive actions or loss of paycheck, workers throw away common sense in favor of a rigid adherence to the rules... leaving entire organizations nearly bereft of clear-minded decision makers, and <strong>stamping out intelligent risk-taking</strong> and the innovations that would follow.</p>\n              <blockquote class=\"middle\">For me, this is a familiar image - people in the organization ready and willing to do good work, wanting to contribute their ideas, ready to take responsibility, and leaders holding them back, insisting that they wait for decisions or instructions.<author>Margarate J. Wheatley</author></blockquote>\n              <h3>It’s broken because mistrust between the general public and corporate entities is at an all-time high.</h3>\n              <p>U.S. law entitles corporate entities the same legal rights as human citizens-- at the same time it lacks a clear means to hold these corporate citizens accountable. The resutl is <strong>power without responsibility</strong>, and we have only to look to Enron, Halliburton, or the recent housing crisis to understand the ill effects of this lopsided agreement.</p>\n              <h3>It’s broken because a workforce driven, coerced, and manipulated by a system of punishments and rewards, leaves very little room for ingenuity, cooperation, honesty, or respect. That is, our humanity.</h3>\n              <p>It creates a culture that sees people (both customers and coworkers) as objects to be manipulated for profit. It rewards office politics and unethical behavior—often at the expense of the company’s true goals. The result is <strong>resentment from both employees and customers</strong> alike—and resentment erodes profits.</p>\n              <h3>It’s broken because the current business model focuses on goals, and thus acts as if the ends can justify the means.</h3>\n              <p>In such an organization, the what to do is never lost. Only the why it is being done. And when the why gets lost, Merck ends up selling poison in the name of \"healing the sick\"... Monsanto keeps a strangle-hold on the world’s supply of seeds and uses profoundly unethical and illegal practices to ruin traditional farmers in the name of \"feeding the hungry\"... And Nike uses sweatshop labor, abuses workers, and pays well below 3rd world minimum wages—even circumventing local laws to do so... all in the name of \"inspiring today's youth to reach their highest potential.\"</p>\n              <blockquote class=\"middle\">Ethics is the new competitive environment<author>Peter Robinson, CEO Mountain Equipment Co-op</author></blockquote>\n            </span>\n      </div>\n\n      <div class=\"paint\">\n        <p>\n        take a look at our<br><a href=\"/front/pricing.html\">plans and pricing</a>\n        </p>\n      </div>\n\n\n      </div>\n    </div>\n\n  </div>\n</div>\n\n<script type=\"text/javascript\">\nvar captions = [\n    \"Leadership. Not management.\",\n    \"Democratic and transparent project management.\",\n    \"Inclusive and efficient decision making.\",\n    \"Full transparancy.\",\n    \"Peer-assessed, contribution-based compensation.\"];\n\nvar imgIdx = 0;\n\nfunction md(i, n) {\n  if (i < 0) i = n-1; else\n  if (i >= n) i = 0;\n  return (i);\n}\n\nfunction slideShow(dir) {\n  var images = [\"dashboard_front.png\", \"home_front.png\", \"motion_front.png\", \"activity_front.png\", \"retro_front.png\"];\n  imgIdx = md(imgIdx + dir, images.length);\n  var prev = md(imgIdx - 1, images.length);\n  var next = md(imgIdx + 1, images.length);\n  $('#caption').html(captions[imgIdx]);\n  $('.screenshot img').attr('src', '/images/static/' + images[imgIdx]);\n  $('.fade-left').css('background-image', 'url(/images/static/' + images[prev] + ')');\n  $('.fade').css('background-image', 'url(/images/static/' + images[next] + ')');\n}\n</script>\n\n"
  },
  {
    "path": "app/views/home/old_inviteonline.html.erb",
    "content": "\n\n<div id=\"inner-page\">\n  <div class=\"container\">\n    <div class=\"container\">\n        <%= render :partial => 'header', :locals => {:page => 'pricing'} %>\n      <div class=\"clear span-12 last\" id=\"main-inner\">\n\n    <script type=\"text/javascript\">var host = ((\"https:\" == document.location.protocol) ? \"https://secure.\" : \"http://\");document.write(unescape(\"%3Cscript src='\" + host + \"wufoo.com/scripts/embed/form.js' type='text/javascript'%3E%3C/script%3E\"));</script>\n\n    <script type=\"text/javascript\">\n    var r7x3s5 = new WufooForm();\n    r7x3s5.initialize({\n    'userName':'bettermeans',\n    'formHash':'r7x3s5',\n    'autoResize':true,\n    'height':'260'});\n    r7x3s5.display();\n    </script>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/home/open_enterprise_governance_model.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n   <%= render :partial => 'header', :locals => {:page => 'howitworks'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"about\">\n      <h1>Open Enterprise Governance Model</h1>\n      <section class=\"span-12 left whitebox\">\n\n<h2> 1. Overview</h2>\n<p>\nAn Open Enterprise is a meritocratic community-based organization. Every aspect of the Open Enterprise is governed by an opt-in engagement model: Anyone with an interest in its work can join the community, contribute to the enterprise and participate in the decision making process. Revenue, decisions, and control are shared based on contribution and peer-review. This document describes how that participation takes place and how to set about earning merit within the community.\n</p>\n<h2> 2. Roles and responsibilities\n</h2>\n<h3> 2.1 Users</h3>\n<p>\nAnyone who is a stakeholder in an enterprise is a user. This includes (but is not limited to): customers, investors, neighbors, and anyone in the enterprise’s community.\nAnyone can be a user; there are no special requirements.\nUsers are welcome to participate in an Open Enterprise as much as possible.\nUser contributions help ensure that the enterprise succeeds in accomplishing its mission while remaining true to its values . Common user contributions include (but are not limited to):\n</p><p>\n    * evangelizing about the enterprise (e.g. a link on a website and word-of-mouth awareness raising)\n    * providing feedback : informing the organization of strengths and weaknesses from a new user perspective, and keeping the Open Enterprise accountable to its mission and values\n    * providing moral support (a ‘thank you’ goes a long way)\n    * providing financial support\n    * supporting other users\n    * adding new ideas to Work Streams\n    * participating in the discussion: commenting on Work Items, and in the forums\n    * starting or joining Work Items (via requests)\n</p><p>\nUsers engage with the enterprise through the Work Stream dashboards. They can request to start (or join) any open Work Item. Their request will be considered for inclusion in the project by existing Members (see below).\n</p><p>\nIn addition to starting and joining Work Items, users can use the dashboard to vote in the following ways:\n\n    * prioritizing existing Work Items\n    * voting on new ideas (agree/disagree)\n    * estimating the effort for suggested Work Items\n    * accepting completed Work Items (accept/reject)\n</p><p>\nAll these votes are non-binding (see below)\n\nUsers who continue to engage with the enterprise and its community will often become more and more involved. Such users may find themselves becoming Contributors. Once a user has worked on a Work Item that has been completed and accepted by the community, they are automatically considered a Contributor.\n</p>\n<h3> 2.2 Contributors\n</h3><p>\nContributors are users who have earned credits (see below) in an enterprise. Any user can become a Contributor; there is no expectation of commitment to the enterprise, no specific skill requirements and no selection process.\n\nContributors are eligible to be nominated for Membership:\n\nAs Contributors gain experience and familiarity with the enterprise, their profile within, and commitment to, the community will increase. At some stage, they may find themselves being nominated for Membership, as described in the next section.\n</p>\n<h3> 2.3 Members\n</h3>\n<p>\nMembers are Contributors who have shown that they are committed to the continued development of the enterprise through ongoing engagement with the enterprise and its community.\n\nAny Contributor can become a Member; there are no special requirements, other than to have shown a willingness and ability to participate in the enterprise as a team player. Typically, a potential Member will need to show that they have an understanding of the enterprise, its objectives and its strategy. Most importantly, they need to demonstrate that they are aligned with the enterprise’s core principles and values. They will also have provided valuable contributions to the enterprise over a period of time.\n\nNew Members can be nominated in one of two ways:\n1. By any existing Member\n2. By completing a certain amount of accepted work as Contributors to the enterprise\n\nOnce they have been nominated, there will be a vote by the Core Team (see below). Voting in a Member is one of the few activities that takes place in private. This is to allow Core Team Members to freely express their opinions about a nominee without causing embarrassment. Once the vote has been held, the aggregated voting results are published on the public forum. The nominee is entitled to request an explanation of any ‘no’ votes against them, regardless of the outcome of the vote. This explanation will be anonymous and constructive in nature.\n\nNominees may decline their appointment as a Member. However, this is unusual, as the enterprise does not expect any specific time or resource commitment from its Members. The intention behind the role of Member is to allow people to contribute to the enterprise more easily, not to tie them in to the enterprise in any formal way.\n\nMembership allows Contributors to more easily carry on with their enterprise related activities by giving them direct access to the enterprise’s resources. That is, they have the autonomy to participate directly to the enterprise outputs.\n\nThis does not mean that a Member is free to do what they want. While Membership indicates a valued Member of the community who has demonstrated a healthy respect for the enterprise’s values and objectives, their work continues to be reviewed by the community before acceptance. The key difference between a Member and a Contributor is when this approval is sought from the community. A Member seeks approval after the contribution is made, rather than before.\n\nAnother way to look at it is that Contributors ask for permission while Members ask for review.\n\nSeeking approval after making a contribution is known as a commit-then-review process. It is more efficient to allow trusted people to make direct contributions, as the majority of those contributions will be accepted by the enterprise. The Work Stream dashboards ensure that all contributions are reviewed by the community as a whole.\n\nBy the time a Contributor is invited to become a Member, they will have been guided through the use of the enterprise’s various tools as a user and then as a Contributor.\n\nIn addition to their actions as Contributors, Members will also find themselves doing one or more of the following:\n\n    * enrolling and allowing users and Contributors to start/join Work Items\n    * nominating Contributors for Membership\n    * voting on Core Team Membership (see below)\n\nAlso Members’ votes are binding, and they need not ask for permission to join/start Work Items.\n\nIt is important to recognize that Membership is a privilege, not a right. That privilege must be earned and once earned it can be removed by the Core Team (see next section) in extreme circumstances. However, under normal circumstances Membership exists for as long as the Member wishes to continue engaging with the enterprise.\n\nA Member who shows an above-average level of contribution to the enterprise, particularly with respect to its strategic direction and long-term health, may be nominated to become a Member of the Core Team. This role is described in the next section.\n</p>\n<h3> 2.4 Core Team\n</h3>\n<p>\nThe Core Team consists of those individuals identified as ‘enterprise representatives’. The Core Team has additional responsibilities over and above those of a Member. These responsibilities ensure the smooth running of the enterprise. Core Team Members are expected to participate in strategic planning, approve changes to the governance model, and formally represent the enterprise to the outside world. First and foremost, they are the guardians and keepers of the enterprise’s principles and values, and are accountable to all stakeholders.\n\nCore Team Members do not have significant authority over other Members of the community, although it is the Core Team that votes new Members in. In addition, the Core Team has access to the enterprise’s private Work Streams. These Work Streams are used sparingly for sensitive issues, such as votes for a new Member, and sensitive IP and legal matters that cannot be discussed in public. It is rarely –if ever– used for enterprise management or planning.\n\nIn addition to their actions as Members, Core Team Members will also find themselves doing one or more of the following: * voting on nominated Members * voting on changes to the governance model * nominating Members to the Core Team\n\nMembership of the Core Team is by invitation from the existing Core Team Members. A nomination will result in discussion and then a vote by ALL existing Members of the enterprise. Core Team Membership votes are subject to consensus approval (see below) of enterprise Members.\n</p>\n<h3> 2.5 Non-Profit Board of Directors</h3>\n<p>\nA board of directors is traditionally the governing body of a non-profit organization. in a Non-Profit Open Enterprise the Board retains many of their traditional rights, even though governance is more distributed.\n\nThe Board can initiate a Board Vote on any issue, whether that be a work item or the induction of a new member. This vote is open for any user to contribute in a non-binding voice, and only Board Members’ votes will be binding, its results are binding for the Enterprise and override any decisions made by its Members.\n\nA Member can also be a Board Member, but this is limited to one, i.e. no more than one Member of an Open Enterprise should serve as a voting member of the board of directors and that member should not serve as chair or treasurer of the Board.\n\nTo allow for significant deliberation and diversity, the majority of the board should be made up of at least seven persons unrelated to each other or Members.\n\nThe organization’s bylaws should determine term limits that establish individual terms of no more than three years, allow individuals to serve no more than three consecutive terms, and require at least one year intervening before eligibility for re-election after serving the maximum number of consecutive terms.\n\nBoard membership should reflect the diversity of the organization’s constituencies.\n\nBoard Members (who are not Contributors to the Enterprise) should not receive compensation for their board service, other than reimbursement for expenses directly related to board duties.\n\nOpen board positions are announced publicly, and any user can nominate themselves or any one else to become a Board Member.\n\nVoting in new Board Members is done by the existing Board Members only.\n</p>\n<h2> 3. Decision making process</h2>\n<p>\nDecisions about the future of the enterprise are made through discussion by the entire community, from the newest user to the most experienced Core Team Member. All non-sensitive project management discussion takes place in public Work Stream dashboards and forum. Occasionally, sensitive discussion occurs on a private Work Stream.\n\nIn order to ensure that the enterprise is not bogged down by endless discussion and continual voting, the enterprise operates a policy of lazy consensus. This allows the majority of decisions to be made without resorting to a formal vote, and keeps the work agile and red-tape free.\n</p>\n<h3> 3.1 Lazy consensus\n</h3>\n<p>\nDecision making typically involves the following steps:\n1. Proposal\n2. Discussion\n3. Vote\n4. Decision\n\nAnyone can make a proposal for consideration by the community. In order to initiate a discussion about a new idea, they should add the idea to the appropriate Work Stream dashboard or forum (work-item ideas go in the dashboard, big-picture strategy is discussed in the forums). This will prompt a review and discussion of the idea. The goal of this review and discussion is to gain approval for the contribution.\n\nIn general, as long as nobody explicitly opposes a proposal, it is recognized as having the support of the community. This is called lazy consensus – that is, those who have not stated their opinion explicitly have implicitly agreed to the implementation of the proposal.\n\nLazy consensus is a very important concept within the project. It is this process that allows a large group of people to efficiently reach consensus, as someone with nothing to add to a proposal need not spend time stating their position, and others need not spend time reviewing it.\n\nFor lazy consensus to be effective, it is necessary to allow at least 72 hours before assuming that there are no objections to the proposal. This requirement ensures that everyone is given enough time to read, digest and respond to the proposal. This time period is chosen so as to be as inclusive as possible of all participants, regardless of their location and time commitments.\n</p>\n<h3> 3.2 Lazy majority</h3>\n<p>\nNot all decisions are made using lazy consensus. Issues such as those affecting the strategic direction or legal standing of the enterprise must gain explicit approval in the form of a vote. This section describes how a vote is conducted. Section 3.4 discusses when a vote is needed.\n\nIf a formal vote on a proposal is called, all users may express an opinion and vote.\n\nThere are 4 types of votes: * ‘agree’: agrees that the action should move forward * ‘disagree’: disagree but will not oppose the action’s going forward * ‘block’: opposes the action’s going forward and must propose an alternative action to address the issue (or a justification for not addressing the issue) * ‘neutral’: indicates that attention has been given to the action but abstaining from voting one way or another\n\nAnother way to abstain from the vote is for participants to simply not participate. However, it is more helpful to cast a ‘neutral’ vote to abstain, since this allows the team to gauge the general feeling of the community if the proposal should be controversial.\n\nThe entire community, from interested user to the most active Core Team Member, has a vote. The enterprise encourages everyone to express their opinions in all discussion and all votes. However, only Members of the enterprise (as defined above) and/or Core Team Members have binding votes for the purposes of decision making. It is therefore their responsibility to ensure that the opinions of the entire community are considered. While only Members and Core Team Members have a binding vote, a well-justified ‘block’ from a non-Member must be considered by the community, and if appropriate, supported by a binding ‘block’.\n\nA ‘block’, when cast by a Member or Core Team Member, essentially becomes a ‘veto’.\n\nWhen a vote receives a ‘block’, it is the responsibility of the community as a whole to address the objection. Such discussion will continue until the objection is either rescinded, overruled (in the case of a non-binding block) or the proposal itself is altered in order to achieve consensus (possibly by withdrawing it altogether). In the rare circumstance that consensus cannot be achieved, the Core Team will decide the forward course of action.\n\nIn summary: * Those who don’t agree with the proposal and feel it would be detrimental to the enterprise if pursued should vote ‘block’. However, they will be expected to submit and defend a counter-proposal. * Those who don’t agree, don’t find it detrimental, and don’t have a better idea should vote ‘disagree’. * Those who agree should vote ‘agree’. * Those who do not care either way or who find themselves on the fence should vote ‘neutral’.\n</p>\n<h3> 3.3 Type of approval</h3>\n<p>\nDifferent actions require different types of approval, ranging from lazy consensus to a majority decision by the Core Team. These are summarized below. The next section describes which type of approval should be used in common situations.\n</p>\n<h4> 1. Lazy consensus: Immediate</h4>\n<p>\nAn action with lazy consensus is implicitly allowed, unless a binding ‘block’ vote is received. Depending on the type of action, a vote will then be called. Note that even though a binding ‘block’ is required to prevent the action, anyone is is free to cast a ‘block’ vote with supporting argument. Members are expected to evaluate the argument and, if necessary, support it with a binding ‘block’.\n</p>\n<h4> 2. Lazy majority: 72 hours</h4>\n<p>\nA lazy majority vote requires more binding ‘agree’ votes than binding ‘disagree’ votes and no vetoes (binding ‘block’ votes). Once 72 hours have passed, the decision moves in the direction of the majority.\n\nNaturally if an actual majority of Members vote before the 72 hours are up, the decision moves in that direction immediately.\n\nSometimes a lazy majority is tied with a vote threshold. This allows for decisions to be made quicker than 72 hours if enough Members vote. If the vote threshold is reached before the 72 hours are up, the decision moves in the direction of the majority.\n</p>\n<h4> 3. Unanimous consensus: 120 hours</h4>\n<p>\nAll of the binding votes that are cast are to be ‘agree’ and there can be no ‘disagree’ votes or vetoes (binding ‘block’ votes)\n</p>\n<h4> 4. Credit majority</h4>\n<p>\nSome strategic actions are decided by giving each credit-holder 1 vote per credit; Such actions typically affect the foundation of the project (e.g. adopting a new governance model)\n</p>\n<h3> 3.4 When is a vote required?</h3>\n<p>\nEvery effort is made to allow the majority of decisions to be taken through lazy consensus. That is, simply stating one’s intentions is assumed to be enough to proceed, unless an objection is raised. Activities that require more control are taken through lazy majority, which is still informal enough for team to stay agile.\n\nHowever, some activities require a more formal approval process in order to ensure the health and cohesiveness of the enterprise.\n\nThis section identifies which type of vote should be called when:\n\n    * User/Contributor requests to join/start a Work Item: Lazy consensus of any Member\n    * New Contributor: Lazy consensus of any Member\n    * Work Item moving to open queue and Work Item acceptance is dependent on the estimated value of that item:\n      *0-1 points: Lazy majority of all Members, vote threshold: 1\n      *2-4 points: Lazy majority of all Members, vote threshold: 2\n      *5-6 points: Lazy majority of all Members, vote threshold: 3\n    * New Work Stream: Lazy majority of all Members\n    * New Member: Unanimous approval of Core Team\n    * Member removal: Unanimous consensus of Core Team\n    * New Core Team Member: Unanimous consensus of all Members\n    * Core Team Member removal: Unanimous consensus of Core Team\n    * Governance model change: Credit majority\n    * Legal structure changes: Credit majority\n    * Big picture strategy: Credit majority\n\nAnomaly: Estimation is done by lazy averaging: Any Member can estimate a Work Item that is new or open. Estimation is closed once the item is in progress.\n</p>\n<h2> 4. Money matters for a for-profit Open Enterprise</h2>\n\n<h3> 4.1 Credits</h3>\n<p>\nAnyone who’s done work for an Open Enterprise is paid for that work in credits. Credits are a promise by the enterprise to pay their owner as soon as funds are made available, each credit is worth $1.\n\nThe payment of credits owed is tracked in the payment pipeline, which shows exactly who is owed money, where they are in the placement in comparison to other creditors, and how periodically is the enterprise making payments to its creditors.\n\nWhen any Member in the enterprise commits cash to revenue sharing (see below), this cash is used first to pay out the payment pipeline, i.e. the enterprise cannot share any profits before all its money owed to contributors is paid out in full.\n\nCredits are not only money owed, they also give their owner profit-sharing, budgeting, and voting rights.\n\nCredits do not immediately expire once paid out. Once credits are paid out however, they have an expiration date, the expiration period begins from the time the creditor receives cash for their credits, and lasts as long as it took this creditor to cash out their credits. E.g. if a participant received $20,000 in credits, and 4 months later their $20,000 credits were paid out in cash, then 4 months after that (8 months from the original date of receipt) would be when their credits would expire. Creditors have the choice to commit some or all of their credits to equity, i.e. taking them out of the payment pipeline and ensuring that they never expire.\n</p>\n<h3> 4.2 Estimation</h3>\n<p>\nEach Work Item in an Open Enterprise is estimated independently, in terms of how many credits will be awarded for its completion. Any member is free to give an estimate of how much should be given for any open Work Item, and their estimation will affect the average estimate of that item. And once work starts on a Work Item and it is being executed, its estimation can no longer be changed.\n</p>\n<h3> 4.3 Retrospectives\n</h3>\n<p>\nIn order to ensure that all Contributors to a Work Stream get adequately compensated for their work, and that compensation be as fair as possible, the compensation system in an Open Enterprise is based on several tenants:\n\n    * There are no fixed salaries in an Open Enterprise\n    * Participants are compensated based on Work Items completed, not time spent – This is to provide everyone the freedom to contribute as much or as little as they choose, and for the Enterprise to be billed fairly.\n    * Contribution is assessed by one’s peers, seeing as coworkers and co-team members are the most likely to know how valuable someone’s contributions were – This is to provide the most fair assessment of one’s contribution, using the wisdom of the crowd in assessing work done.\n    * Peer assessment is compared with self-assessment – This is to provide an opportunity for each participant to self-reflect and learn about their assessment of their own work, as well as an indicator to all users of each participant’s self-assessment abilities.\n\nThis system of compensation is executed using the Retrospective, which occurs once a number of Work Items worth a certain amount of credits are completed and accepted in any given Work Stream.\n\nDuring the Retrospective, each person who has contributed any amount of work to any of the Work Items involved is asked to assess their own percentage contribution to the completion of these items, as well as every other participant’s. Once all participants have stated their opinion, each one receives the average of their team’s assessment of their work. That figure is also compared with their own assessment of themselves, which affects their self-assessment reputation.\n\nThe percentage each participant receives is then applied to the total amount of credits associated with the retrospective and these credits are distributed accordingly.\n</p>\n<h3> 4.4. Budgeting and Profit Sharing</h3>\n<p>\nBudgeting in an Open Enterprise is distributed, trusting that the emergent intelligence of the crowd will decide how best to spend the organization’s cash.\n\nAs spending cash, either through funds raised, revenues, or loans, comes to the enterprise, its spending allowance is distributed to all members according to their relative credit ownership. Each Member has the autonomy to allocate their budget to whichever items they feel need it the most.\n\nA member can also decide to allocate some or all of their budget towards profit sharing. This cash will be used first to pay out the credits in the payment pipeline and then distributed to all credit owners, whether members or not, according to their relative credit ownership.\n</p>\n<h2> 5. Money matters for a Non-profit Open Enterprise</h2>\n\n<h3> 5.1 Credits\n  </h3>\n<p>\nAnyone who’s done work for an Non-Profit Open Enterprise is rewarded for that work in credits.\nThere are two types of Credits:\n\n1. Cash Credits: Cash Credits are a promise by the Enterprise to pay their owner as soon as funds are made available, each credit is worth $1.\n\n2. Volunteer Credits: Volunteer Credits give the owner the recognition and decision-making ability of a credit, but have no monetary value.\n\nThe payment of Cash Credits owed is tracked in the payment pipeline, which shows exactly who is owed money, where they are in the placement in comparison to other creditors, and how periodically is the Enterprise making payments to its creditors.\n\nWhen any Member in the Enterprise commits cash to the Credit Pipeline (see below), this cash is used to fulfill the debt owed to their owners.\n\nCredits are not only money owed, they also give their owner profit-sharing, budgeting, and voting rights.\n\nCredits do not immediately expire once paid out. Once credits are paid out however, they have an expiration date, the expiration period begins from the time the creditor receives cash for their credits, and lasts as long as it took this creditor to cash out their credits. E.g. if a participant received $20,000 in credits, and 4 months later their $20,000 credits were paid out in cash, then 4 months after that (8 months from the original date of receipt) would be when their credits would expire.\n\nCreditors have the choice to commit some or all of their credits as decision-making credits, i.e. taking them out of the payment pipeline and ensuring that they never expire.\n</p>\n<h3> 5.2 Estimation</h3>\n<p>\nEach Work Item in an Non-Profit Open Enterprise is estimated independently, in terms of how many credits will be awarded for its completion. Any member is free to give an estimate of how much should be given for any open Work Item, and their estimation will affect the average estimate of that item. And once work starts on a Work Item and it is being executed, its estimation can no longer be changed.\n</p>\n<h3> 5.3 Retrospectives</h3>\n<p>\nIn order to ensure that all Contributors to a Work Stream get adequately compensated for their work, and that compensation be as fair as possible, the compensation system in an Non-Profit Open Enterprise is based on several tenants:\n\n    * There are no fixed salaries in an Non-Profit Open Enterprise\n    * Participants are compensated based on Work Items completed, not time spent – This is to provide everyone the freedom to contribute as much or as little as they choose, and for the Enterprise to be billed fairly.\n    * Contribution is assessed by one’s peers, seeing as coworkers and co-team members are the most likely to know how valuable someone’s contributions were – This is to provide the most fair assessment of one’s contribution, using the wisdom of the crowd in assessing work done.\n    * Peer assessment is compared with self-assessment – This is to provide an opportunity for each participant to self-reflect and learn about their assessment of their own work, as well as an indicator to all users of each participant’s self-assessment abilities.\n\nThis system of compensation is executed using the Retrospective, which occurs once a number of Work Items worth a certain amount of credits are completed and accepted in any given Work Stream.\n\nDuring the Retrospective, each person who has contributed any amount of work to any of the Work Items involved is asked to assess their own percentage contribution to the completion of these items, as well as every other participant’s. Once all participants have stated their opinion, each one receives the average of their team’s assessment of their work. That figure is also compared with their own assessment of themselves, which affects their self-assessment reputation.\n\nThe percentage each participant receives is then applied to the total amount of credits associated with the retrospective and these credits are distributed accordingly.\n</p>\n<h3> 5.4. Spending Cash</h3>\n<p>\nSpending in an Non-Profit Open Enterprise is distributed, trusting that the emergent intelligence of the crowd will decide how best to spend the organization’s cash.\n\nAs spending cash, either through funds raised, revenues, or loans, comes to the Enterprise, its spending allowance is distributed to all members according to their relative credit ownership.\n\nEach Member has the autonomy to allocate their budget to whichever items they feel need it the most.\n\nA Member can also decide to allocate some or all of their budget towards the Credit Pipeline.\n</p>\n<h2> 6. Conclusion\n  </h2>\n<p>\nThe Open Enterprise governance model comes from the more democratic end of the spectrum of control. But it is not a democracy, it is a meritocracy. It is a model that passes control on to those who are most likely to wield it for the benefit of all, rather than a minority interest.\n\nWork organization is (generally) emergent. People emerge to do the work by simply doing it. If they are helpful, other people begin to trust them. In a healthy enterprise, this trust eventually results in explicit authority and responsibilities. This is called leadership. In traditional management structures, authority is granted from the top down regardless of any existing trust or respect. This is what most people would call a manager. Managers may also be leaders, but this is unfortunately more rare than it should be.\n\nGiven the nature of open participation in Open Enterprises, they don’t have managers, but they do have leaders.\n\nThere is a big difference between a leadership culture and a management culture. In most corporations, management = status = power. The people who have the most people working for them have the loudest voices in the direction of the organization.\n\nIn a healthy Open Enterprise, the people who 1) have good ideas or 2) get things done, are the ones that have the status and power. These are the people who tend to have lots of folks start to willingly follow them.\n\nFirst you earn leadership, and then you are allowed to manage.\n</p>\n</section></div></div></div></div>\n"
  },
  {
    "path": "app/views/home/pricing.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n      <%= render :partial => 'header', :locals => {:page => 'pricing'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"span-12 clear\">\n        <div class=\"span-8 first\">\n          <h2>Plans and Pricing</h2>\n          <p>Get setup in 60 seconds. No credit card needed. 30-day free trial.</p>\n          </div>\n\n      </div>\n    <div class=\"clear\"></div>\n    <div class=\"gt-pls-row foured\">\n      <div class=\"gt-pl pro free-box\">\n        <h3>\n                <div class=\"gt-pr\">\n            <span class=\"symbol\">$</span><span class=\"amount\">0</span><span class=\"duration\">/mo</span>\n          </div>\n\n          Free\n        </h3>\n        <div class=\"gt-r\"></div>\n        <ul class=\"gt-bp\">\n          <li>Unlimited public users</li>\n          <li><strong>No private workstreams</strong></li>\n          <li>1 gb of storage</li>\n        </ul>\n        <ul class=\"gt-sp\">\n          <li><strong>Unlimited</strong> public workstreams</li>\n        </ul>\n\n          <a href=\"/account/register?plan=0\" class=\"button classy pro-gt-pl\"><span>Sign up</span></a>\n\n      </div>\n\n      <div class=\"gt-pl pro middleleft\">\n        <h3>\n                <div class=\"gt-pr\">\n            <span class=\"symbol\">$</span><span class=\"amount\">5</span><span class=\"duration\">/mo</span>\n          </div>\n          Starter\n        </h3>\n        <div class=\"gt-r\"></div>\n        <ul class=\"gt-bp\">\n          <li><strong>1</strong> private workstream</li>\n          <li>5 private users</li>\n          <li>1 gb of storage</li>\n        </ul>\n        <ul class=\"gt-sp\">\n          <li><strong>Unlimited</strong> public workstreams</li>\n        </ul>\n\n          <a href=\"/account/register?plan=10\" class=\"button classy pro-gt-pl\"><span>Sign up</span></a>\n\n      </div>\n\n      <div class=\"gt-pl pro middleleft\">\n        <h3>\n                <div class=\"gt-pr\">\n            <span class=\"symbol\">$</span><span class=\"amount\">25</span><span class=\"duration\">/mo</span>\n          </div>\n\n          Basic\n        </h3>\n        <div class=\"gt-r\"></div>\n        <ul class=\"gt-bp\">\n          <li><strong>5</strong> private workstreams</li>\n          <li>10 private users</li>\n          <li>2 gb of storage</li>\n        </ul>\n        <ul class=\"gt-sp\">\n          <li><strong>Unlimited</strong> public workstreams</li>\n        </ul>\n\n          <a href=\"/account/register?plan=20\" class=\"button classy pro-gt-pl\"><span>Sign up</span></a>\n\n      </div>\n\n      <div class=\"gt-pl pro middleleft\">\n        <h3>\n                <div class=\"gt-pr\">\n            <span class=\"symbol\">$</span><span class=\"amount\">50</span><span class=\"duration\">/mo</span>\n          </div>\n\n          Better\n        </h3>\n        <div class=\"gt-r\"></div>\n        <ul class=\"gt-bp\">\n          <li><strong>20</strong> private workstreams</li>\n          <li>25 private users</li>\n          <li>5 gb of storage</li>\n        </ul>\n        <ul class=\"gt-sp\">\n          <li><strong>Unlimited</strong> public workstreams</li>\n        </ul>\n\n          <a href=\"/account/register?plan=30\" class=\"button classy pro-gt-pl\"><span>Sign up</span></a>\n\n      </div>\n\n      <div class=\"gt-pl pro\">\n        <h3>\n                <div class=\"gt-pr\">\n            <span class=\"symbol\">$</span><span class=\"amount\">100</span><span class=\"duration\">/mo</span>\n          </div>\n\n          Super\n        </h3>\n        <div class=\"gt-r\"></div>\n        <ul class=\"gt-bp\">\n          <li><strong>100</strong> private workstreams</li>\n          <li>60 private users</li>\n          <li>50 gb of storage</li>\n        </ul>\n        <ul class=\"gt-sp\">\n          <li><strong>Unlimited</strong> public workstreams</li>\n        </ul>\n\n          <a href=\"/account/register?plan=40\" class=\"button classy pro-gt-pl\"><span>Sign up</span></a>\n\n      </div>\n\n      <div class=\"gt-pl pro\">\n        <h3>\n                <div class=\"gt-pr\">\n            <span class=\"symbol\">$</span><span class=\"amount\">200</span><span class=\"duration\">/mo</span>\n          </div>\n\n          Go Nuts!\n        </h3>\n        <div class=\"gt-r\"></div>\n        <ul class=\"gt-bp\">\n          <li><strong>300</strong> private workstreams</li>\n          <li><strong>Unlimited</strong> users</li>\n          <li>100 gb of storage</li>\n        </ul>\n        <ul class=\"gt-sp\">\n          <li><strong>Unlimited</strong> public workstreams</li>\n        </ul>\n\n          <a href=\"/account/register?plan=50\" class=\"button classy pro-gt-pl\"><span>Sign up</span></a>\n\n      </div>\n    </div>\n\n    <div class=\"clear\"></div>\n\n\n    <div class=\"gt-pl hgt-pl free\">\n            <div class=\"gt-pr\">\n          <span class=\"symbol\">$</span><span class=\"amount\">0</span><span class=\"duration\">/mo</span>\n        </div>\n\n      <a href=\"/account/register?plan=0\" class=\"button classy\"><span>Create a free account</span></a>\n      <h3><strong>Unlimited</strong> public workstreams and <strong>unlimited</strong> public users</h3>\n      <p>Keep your work open and inclusive, and we won't charge you a dime no matter how large you grow.</p>\n    </div>\n\n    <ul class=\"gt-pls-features\">\n      <li class=\"intro\">All plans come with&hellip;</li>\n      <li>Free setup</li>\n      <li>30-day trial</li>\n      <li>SSL security</li>\n      <li>Community support</li>\n      <li>Wikis</li>\n      <li>Discussion boards</li>\n      <li>Doc storage &amp; <a href=\"/front/what.html\" target=\"blank\">more</a></li>\n    </ul>\n\n    <div class=\"clear\"></div>\n\n\n     <div class=\"clear\"></div>\n    <br><br>\n\n      <div id=\"pricing-col\" class=\"span-12 clear\">\n        <h2>Pricing FAQ’s</h2>\n        <div class=\"column span-5 first\">\n          <h4>Who is behind bettermeans?</h4>\n          <p>Bettermeans started out as a business run by Bettermeans LLC, but is now\n            a <a href='https://github.com/Bettermeans/bettermeans'>community-supported open source</a> software project.</p>\n          <h4>What are workstreams?</h4>\n          <p>Workstream is our word for Project: a group or set of work. A workstream\n          could be a department of your organization or it could be a specific\n          project that you are working on by your self or with others.</p>\n\n          <h4>What are users?</h4>\n          <p>Users are all the people that you work with on all the different\n          work streams you create.</p>\n\n          <h4>What's are public vs. private workstreams?</h4>\n          <p>Access to a private workstream is determined by the creator of that\n          workstream. However public workstreams are available for anyone\n          to see, comment on, contribute to. We are excited about openness\n          and transparency and the richness that it can bring to all of our work\n          – hence unlimited public workstreams for all.</p>\n\n          <h4>What are publc vs. private users</h4>\n          <p>Public users are those people working with you on public\n          workstreams. Similarly, private users are those working with\n          you on private workstreams.</p>\n\n          <h4>Can I change my plans at any time?</h4>\n          <p>Yes. Simply click on the “Account” tab on your dashboard and you’ll see your options</p>\n\n          <h4>Which web browsers do you support?</h4>\n          <p>Internet Explorer 7 or 8, Firefox 3 and higher, Safari 4, and Chrome 4</p>\n\n          <h4>I have more questions...</h4>\n          <p>Got more questions?  <a href=\"http://bettermeans.com/projects/20\">Visit the bettermeans workstream for community support</a></p>\n        </div>\n        <div class=\"column span-5\">\n          <h4>Do I have to sign a long term contract?</h4>\n          <p>No. BetterMeans is a pay-as-you-go service. There are no contracts or commitments on your part. Simply pay month-to-month. Cancel anytime, and you'll be billed only for the current month</p>\n          <h4>What types of payment do you accept?</h4>\n          <p>We only accept payments online. You can use all major credit cards (Visa, Mastercard, and American Express). We do not accept Paypal.</p>\n          <h4>How secure is my data?</h4>\n          <p>BetterMeans uses <a href=\"http://heroku.com\" target=\"_blank\">Heroku</a> and <a href=\"http://aws.amazon.com/s3/faqs/\" target=\"_blank\">Amazon.com's S3 data services</a> for hosting. These cloud services use enterprise-class firewall and encryption to keep your data safe and secure.</p>\n          <p>Data is backed up on an hourly basis to multiple physical locations.</p>\n\n          <h4>How does the 30-day free trial work?</h4>\n          <p>If you cancel a paying plan within 30 days of signing up you won’t be charged a thing. Refunds can not be issued after your initial 30 day trial and we don’t prorate for partial months.</p>\n          <h4>Do I get a 30-day free trial if I upgrade?</h4>\n          <p>If you upgrade from a free account to a pay account you are not eligible for the 30-day free trial. The 30-day free trial on paying plans only applies if you sign up for a paying plan now. You can always downgrade later if you choose.</p>\n\n          <h4>Fine print please...</h4>\n          <p>Here is our <a href=\"/front/user_agreement.html\" target=\"_blank\">User Agreement</a> and our <a href=\"/front/privacy.html\" target=\"_blank\">Privacy Policy</a></p>\n        </div>\n      </div>\n\n      <div class=\"clear\"></div>\n      <div class=\"span-3\">&nbsp;</div>\n      <div class=\"span-6 last\" style=\"align:center;\"> <blockquote>For thousands of years, markets and hierarchies were the only alternatives when it came to aggregating human effort. Now there's a third option: real-time, distributed networks.<br>\n      <author>Gary Hamel<br> Voted #1 business thinker by the Wall Street Journal</author></blockquote>\n       </div>\n       <div class=\"span-3\">&nbsp;</div>\n\n    </div>\n\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/home/privacy.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n    <%= render :partial => 'header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"span-8 left-content-secondary\">\n        <div class=\"blog-post-single\"> <a class=\"blog-post-title\" HREF=\"/front/privacy.html\" onclick=\"return false();\">BetterMeans Privacy Policy</a>\n          <div class=\"blog-content\"> <a href=\"#\"><img src=\"/images/static/privacy.jpg\" alt=\"Image Post\"  /></a>\n\n            <p>BetterMeans is committed to securing the privacy of survey data and of keeping email addresses and other identifying information confidential.</p>\n\n\n            <p>We collect the e-mail addresses of those who communicate with us via e-mail, aggregate information on what pages consumers access or visit, and information volunteered by the consumer (such as survey information and/or site registrations). The information we collect is used to improve the content of our Web pages and the quality of our service, and is not shared with or sold to other organizations for commercial purposes, except to provide products or services you've requested, when we have your permission, or under the following circumstances:</p>\n\n            <p>It is necessary to share information in order to investigate, prevent, or take action regarding illegal activities, suspected fraud, situations involving potential threats to the physical safety of any person, violations of Terms of Service, or as otherwise required by law.\n            We transfer information about you if BetterMeans is acquired by or merged with another company. In this event, BetterMeans will notify you before information about you is transferred and becomes subject to a different privacy policy.\n            </p>\n\n\n\n            <a name='infogathering'></a><h2>Information Gathering and Use</h2>\n\n\n\n            <p>When you register for BetterMeans we ask for information such as your name, company name, email address, billing address, credit card information. Members who sign up for the free account are not required to enter a credit card.\n            BetterMeans uses collected information for the following general purposes: products and services provision, billing, identification and authentication, services improvement, contact, and research.\n            </p>\n\n\n\n\n            <a name='cookies'></a><h2>Cookies</h2>\n\n\n\n            <p>A cookie is a small amount of data, which often includes an anonymous unique identifier, that is sent to your browser from a web site's computers and stored on your computer's hard drive.\n            Cookies are required to use the BetterMeans service.\n            We use cookies to record current session information, but do not use permanent cookies. You are required to log-in to your BetterMeans Project Site after a certain period of time has elapsed to protect you against others accidentally accessing your account contents.\n            </p>\n\n            <a name='datastorage'></a><h2>Data Storage</h2>\n\n            <p>BetterMeans uses third party vendors and hosting partners to provide the necessary hardware, software, networking, storage, and related technology required to run BetterMeans. Although BetterMeans owns the code, databases, and all rights to the BetterMeans application, you retain all rights to your data.</p>\n\n            <a name='disclosure'></a><h2>Disclosure</h2>\n            <p>BetterMeans may disclose personally identifiable information under special circumstances, such as to comply with subpoenas or when your actions violate the Terms of Service.\n            </p>\n\n            <a name='changes'></a><h2>Changes</h2>\n            <p>BetterMeans may periodically update this policy. We will notify you about significant changes in the way we treat personal information by sending a notice to the primary email address specified in your BetterMeans primary account holder account or by placing a prominent notice on our site.</p>\n\n            <a name='questions'></a><h2>Questions</h2>\n            <p>Any questions about this Privacy Policy should be addressed to <a href=\"support@betterMeans.com\">support@bettermeans.com</a>\n            </p>\n\n          </div>\n        </div>\n      </div>\n      <div class=\"span-4 last right-content-secondary sidebar\">\n        <div id=\"categories\">\n          <div class=\"sidebar-title\">\n            <h1>Sections</h1>\n            <div class=\"arrow\">.</div>\n          </div>\n          <ul class=\"blog-sidebar-a\">\n            <li> <a href=\"#infogathering\">Information Gathering</a> </li>\n            <li> <a href=\"#cookies\">Cookies</a> </li>\n            <li> <a href=\"#datastorage\">Data Storage</a> </li>\n            <li> <a href=\"#disclosure\">Disclosure</a> </li>\n            <li> <a href=\"#changes\">Changes</a> </li>\n            <li> <a href=\"#questions\">Questions</a> </li>\n          </ul>\n        </div>\n        <div id=\"text-widget\">\n          <div class=\"sidebar-title\">\n            <h1>Copy Left</h1>\n            <div class=\"arrow\">.</div>\n          </div>\n          <div class=\"boxxx\">\n            <p>This privacy policy is shared under <a href=\"http://creativecommons.org/licenses/by-sa/3.0/\" target=\"new\">CreativeCommons Attribution-Share Alike</a></p>\n            <p>Feel free to copy-paste what you need and please attribute the source to BetterMeans.com</p>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/home/services.html.erb",
    "content": "<script type=\"text/javascript\">\n    $(document).ready(function() {\n      $(\"a.example\").fancybox({\n        'titleShow'     : false,\n        'transitionIn'  : 'elastic',\n        'transitionOut'  : 'elastic'\n      });\n    });\n  </script>\n<div id=\"inner-page\">\n  <div class=\"container\">\n    <%= render :partial => 'header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"clear span-12\">\n        <div class=\"span-8 first inner-page-title\">\n          <h2 class=\"main-title-2\">This are some of our services</h2>\n          <span>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. </span> </div>\n        <div class=\"clear\"></div>\n        <div class=\"span-12\" id=\"gallery\">\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-1_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-2_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-2.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-3_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-3.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-4_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-4.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n<script type=\"text/javascript\">\n      $(document).ready(function() {\n        $('.viewport').mouseenter(function(e) {\n          $(this).children('a').children('img').animate({ height: '268', left: '-20', top: '-20', width: '480'}, 100);\n          $(this).children('a').children('span').fadeIn(300);\n        }).mouseleave(function(e) {\n          $(this).children('a').children('img').animate({ height: '268', left: '-20', top: '-20', width: '480'}, 100);\n          $(this).children('a').children('span').fadeOut(200);\n        });\n      });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "app/views/home/signup.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n    <%= render :partial => 'header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"span-8 left-content-secondary\">\n        <div class=\"span-8 first inner-page-title\">\n          <h2 class=\"main-title-2\">Create your account</h2>\n          <span>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. </span> </div>\n        <form id=\"sign-up-top\" name=\"sign-up-top\" action=\"\" method=\"post\">\n          <h3>Fill your personal information</h3>\n          <p>\n            <label for=\"first\">First Name</label>\n            <input type=\"text\" name=\"first\" id=\"first\"/>\n          </p>\n          <p>\n            <label for=\"first\">Last Name</label>\n            <input type=\"text\" name=\"first\" id=\"first\"/>\n          </p>\n          <p>\n            <label for=\"first\">Email</label>\n            <input type=\"text\" name=\"first\" id=\"first\"/>\n          </p>\n        </form>\n        <form id=\"sign-up-bottom\" name=\"sign-up-bottom\" action=\"\" method=\"post\">\n          <h3>Check this information carefully</h3>\n          <p>\n            <label for=\"first\">Usename</label>\n            <input type=\"text\" name=\"first\" id=\"first\"/>\n          </p>\n          <p>\n            <label for=\"first\">Password</label>\n            <input type=\"password\" name=\"first\" id=\"first\"/>\n          </p>\n          <p>\n            <label for=\"first\">Confirm</label>\n            <input type=\"password\" name=\"first\" id=\"first\"/>\n          </p>\n          <p>\n            <label for=\"first\">Company</label>\n            <input type=\"text\" name=\"first\" id=\"first\"/>\n          </p>\n        </form>\n            <input type=\"submit\" name=\"submit\" value=\"submit\" id=\"create\"/>\n      </div>\n\n      <div class=\"span-4 last right-content-secondary sidebar\">\n        <div id=\"thanks\"> <img src=\"/images/static/thanks.png\" alt=\"\" /> </div>\n        <hr />\n        <div id=\"trial\">\n          <h3>30-day Free Trial</h3>\n          <p>We need your billing information to reduce fraud and verify you have a valid credit card should you keep your account open.</p>\n        </div>\n        <hr />\n        <div id=\"text-widget\">\n          <div class=\"cloud\">\n            <h3>Meedo are simply the best</h3>\n            <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. </p>\n          </div>\n          <p class=\"client\"><strong>Collis Taeed</strong>, Envato Marketplaces</p>\n        </div>\n        <hr />\n        <div id=\"widget-4\">\n          <h3>Who use BetterMeans?</h3>\n          <a href=\"#\"><img src=\"/images/static/vh.jpg\" alt=\"\"/></a> <a href=\"#\"><img src=\"/images/static/tf.jpg\" alt=\"\"/></a> <a href=\"#\"><img src=\"/images/static/fd.jpg\" alt=\"\"/></a> </div>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/home/tour.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n    <%= render :partial => 'header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"clear span-12\">\n        <h2 class=\"main-title\">Watch the Tour</h2>\n\n      Coming soon...\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/home/user_agreement.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n   <%= render :partial => 'header', :locals => {:page => 'howitworks'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"about\">\n      <h1>Platform User Agreement</h1>\n      <section class=\"span-12 left whitebox\">\n        <h2>OPEN ENTERPRISE AGREEMENT</h2>\n<p>\n        This Agreement is a legal agreement between You (\"You\") and the other Open Enterprise Participants (as defined below) of the Open Enterprise (as defined below) that You join as a Open Enterprise Participant, with respect to the work that You, together with these other Open Enterprise Participants, perform for that Open Enterprise. This Agreement sets forth the licenses You grant, and certain obligations You have, to other Open Enterprise Participants regarding Your contributions to the Open Enterprise and sets forth certain rights You have as a Open Enterprise Participant of the Open Enterprise regarding contributions of other Open Enterprise Participants. You must accept the terms of this Agreement before participating in the Open Enterprise or contributing any Open Enterprise Contribution (as defined below), or before receiving any Open Enterprise Contributions from other Open Enterprise Participants.\n</p>\n        <h2>OPEN ENTERPRISE GOVERNANCE</h2>\n        <p>\n\n        This Agreement sets forth the legal terms under which You participate in the Open Enterprise. This Agreement is based on the Open Enterprise Governance Model:\n</p>        <p>\n\n        Under the principle of Open Enterprise Governance, every Open Enterprise Participant can be part of the decision-making processes that affect the Open Enterprise and such Open Enterprise Participant's contribution to the Open Enterprise. This participation in the decision-making processes of the Open Enterprise can be exercised by voting. The Open Enterprise Governance is defined below.\n</p>        <p>\n\n        Individually and collectively, the Open Enterprise Governance Model is aimed at creating a framework or fairness, within which the Open Enterprise Participants will cooperate to achieve the Open Enterprise Result through providing their individual contributions.\n</p>\n\n        <h2>AGREEMENT:</h2>\n\n        <h2>1. Open Enterprise STRUCTURE; JOINING A Open Enterprise.</h2>\n        <h3>1.1 Open Enterprise.</h3>\n<p>\n        A \"Open Enterprise\" is a development Open Enterprise organized and managed through the BetterMeans.com website that has at least one Open Enterprise Participant, has a purpose stated on the BetterMeans.com website, and has a unique Open Enterprise ID on the BetterMeans.com website .\n</p>\n        <h3>1.2 Open Enterprise Result.</h3>\n<p>\n        The stated purpose of a Open Enterprise is called a \"Open Enterprise Result.\" The Open Enterprise Result can be a product, software, service, or other goal that the Open Enterprise Assembly (as defined below) for an Open Enterprise decides to pursue. The Open Enterprise Assembly for a Open Enterprise may change and further refine a Open Enterprise Result from time to time.\n</p>\n        <h3>1.3 Open Enterprise Governance.</h3>\n<p>\n        This Agreement describes some of the terms governing Open Enterprises, but You should review the Open Enterprise Governance Model and Open Enterprise-related pages of the BetterMeans.com website for more details. Each Open Enterprise is governed by the Open Enterprise Assembly for that Open Enterprise, in accordance with this Agreement and the Open Enterprise Governance Model for the BetterMeans.com website . The \"Open Enterprise Assembly\" is the collective of all Open Enterprise Participants, which collectively can make binding decisions for the Open Enterprise. The Open Enterprise Assembly makes binding decisions for the Open Enterprise through a voting process that is further described and defined in the Open Enterprise Governance Model (this process is referred to as \"Voting\"), except to the extent otherwise decided by the Open Enterprise Assembly through Voting prior to a decision.\n</p>\n        <h3>1.4 Open Enterprise Participants.</h3>\n<p>\n        Each Open Enterprise is undertaken by one or more Open Enterprise Participants. A \"Open Enterprise Participant\" means, for any Open Enterprise, (a) You, if You have satisfied all of the conditions set forth in Section 1.5 for that Open Enterprise or (b) another person who has satisfied such conditions for participation set forth in the Software Bill of Rights Agreement entered into by such person for the applicable Open Enterprise. A \"Software Bill of Rights Agreement\" means an agreement substantially similar to this Agreement, or any prior or subsequent version of this Agreement published by [the hosting agent].\n</p>\n        <h3>1.5 Joining a Open Enterprise.</h3>\n<p>\n        You become a Open Enterprise Participant for a particular Open Enterprise by meeting all of the following conditions:\n</p><p>\n        (a) You register on the BetterMeans.com website to become a Open Enterprise Participant for that Open Enterprise;<br>\n        (b) via the BetterMeans.com website , You agree with the Open Enterprise Assembly for the Open Enterprise (or the Open Enterprise Assembly's designee) on a number of Open Enterprise Units you will receive in consideration for one or more Open Enterprise Contributions; and<br>\n        (c) either (i) Your Open Enterprise Contribution is accepted by the Open Enterprise Assembly for the Open Enterprise (or by the Open Enterprise Assembly's designee) via the BetterMeans.com website or (ii) You and the Open Enterprise Assembly (or the Open Enterprise Assembly's designee) agree, via the BetterMeans.com website to a task or tasks that You will perform to provide Your Open Enterprise Contribution.\n        </p>\n\n        <h3>1.6 Open Enterprise Units.</h3>\n<p>\n        The Open Enterprise Assembly may grant you Open Enterprise Units for your Open Enterprise Contributions. As determined by the Open Enterprise Assembly, Open Enterprise Units are granted when the events described in Section 1.5(c)(i) or Section 1.5(c)(ii) occur or the Open Enterprise Contribution resulting from tasks performed under Section 1.5(c)(ii) are accepted under Section 2.1(c). A \"Open Enterprise Unit\" is an intangible token granted by the Open Enterprise Assembly that (a) entitles a Open Enterprise Participant to certain Voting participation in the Open Enterprise Assembly and (b) entitles a Open Enterprise Participant to receive compensation in case the Open Enterprise Assembly decides to commercialize the Open Enterprise Result or any part thereof. The Open Enterprise Governance Model and pages of the BetterMeans.com website that describe the Open Enterprise provide more details about the Open Enterprise Units for a particular Open Enterprise.\n</p>\n        <h3>1.7 Acceptance of Agreement.</h3>\n<p>\n        You accept, and agree to comply with, the terms of each other Open Enterprise Participant's Software Bill of Rights Agreement as follows:<br><br>\n\n        (a) Upon You becoming a Open Enterprise Participant, you accept the terms of the Software Bill of Rights Agreements of all existing Open Enterprise Participants and agree to comply with the terms of that Software Bill of Rights Agreement with respect to the Contributions of those Open Enterprise Participants;<br>\n\n        (b) Upon each subsequent Open Enterprise Participant's becoming a Open Enterprise Participant, you accept the terms of that Open Enterprise Participant's Software Bill of Rights Agreement and agree to comply with the terms of that Software Bill of Rights Agreement with respect to the Contributions of that Open Enterprise Participant.<br>\n        </p>\n        <h2>2. YOUR Open Enterprise CONTRIBUTION.</h2>\n        <h3>2.1 Contributions and Acceptance.</h3>\n<p>\n        (a) A \"Open Enterprise Contribution\" means the ideas, inventions (whether or not patentable), discoveries, know-how, technical information, methods, processes, designs, schematics, content, documents, materials, tools, software programs or parts thereof (whether in source code, object code, or any other form), and other works of authorship and other forms of technology, as well as services and support, in each case which are contributed by a Open Enterprise Participant to a Open Enterprise.<br>\n\n        (b) After You have become a Open Enterprise Participant, You may (i) provide Your Open Enterprise Contributions to other Open Enterprise Participants and (ii) receive Open Enterprise Contributions from other Open Enterprise Participants.<br>\n\n        (c) After You have provided Your Open Enterprise Contribution to one or more Open Enterprise Participants for acceptance, the Open Enterprise Assembly may accept You Open Enterprise Contribution through Voting.<br>\n        </p>\n\n        <h3>2.2 Development License Grant.</h3>\n<p>\n        You hereby grant to each current and future Open Enterprise Participant a worldwide, perpetual and irrevocable (except as set forth in Sections 2.4 and Section 3), non-exclusive, royalty-free and fully-paid license, without the right to sublicense, limited to the purpose of development of the Open Enterprise Result, including the testing of Open Enterprise Contributions:<br>\n\n        (a) under all intellectual property rights (other than patent or trademark) Licensable by You, to use, reproduce, modify, and create derivative works of Your Open Enterprise Contributions that have been accepted as set forth in Section 2.1(c); and<br>\n\n        (b) under any one or more patent claims (including method, process, and apparatus claims) in any patent which are currently or in the future Licensable by You (\"Patent Claims\") that are infringed by the making and using of Your Open Enterprise Contributions (either alone or in combination with other Open Enterprise Participants' Open Enterprise Contributions), to make, have made, and use (i) Your Open Enterprise Contributions that have been accepted as set forth in Section 2.1(c) and (ii) combinations of Your Open Enterprise Contributions that have been accepted as set forth in Section 2.1(c) (or portions thereof) with one or more Open Enterprise Contributions of one or more other Open Enterprise Participants.<br>\n</p><p>\n        As used herein, \"Licensable\" means, with respect to any intellectual property right, that the grantor has, or subsequently obtains, the right to grant licenses to the licensee hereunder within the scope granted herein without such grant or the exercise of rights thereunder resulting in the payment of royalties or other consideration by the grantor to a third party (except for payments among grantor and its affiliates, and payments to third parties for inventions made by said third parties while employed by the grantor).\n</p><p>\n        The licenses granted in this Section 2.2 are effective on the date You first provide the applicable Open Enterprise Contribution to another Open Enterprise Participant of the Open Enterprise. For avoidance of doubt, the licenses granted in this Section 2.2 do not include the right to distribute or make available the licensed Open Enterprise Contribution to, or to use the licensed Open Enterprise Contribution to provide services for, any party other than a Open Enterprise Participant.\n</p>\n        <h3>2.3 Commercialization License Grant.</h3>\n<p>\n        Effective at the time, and solely to the extent that, the Open Enterprise Assembly decides to commercialize the Open Enterprise Result by distributing or making available the Open Enterprise Result (or parts thereof) to, or using the Open Enterprise Result (or parts thereof) to provide services for, parties other than Open Enterprise Participants, You hereby grant to the current and future Open Enterprise Participants a worldwide, perpetual and irrevocable (except as set forth in Sections 2.4 and 3), non-exclusive, royalty-free and fully-paid license, with the right to sublicense through multiple levels of sublicensees,\n</p><p>\n        (a) under all intellectual property rights (other than patent or trademark) Licensable by You, to use, reproduce, distribute, publicly perform and display in any form and medium, whether now known or later developed, Your Open Enterprise Contributions that have been accepted as set forth in Section 2.1(c), and<br>\n\n        (b) under any one or more Patent Claims that are infringed by the making, having made, using, selling, offering for sale, or importing Your Open Enterprise Contributions (either alone or in combination with other Open Enterprise Participants' Open Enterprise Contributions), to make, have made, use, sell, offer for sale, and import (i) Your Open Enterprise Contributions that have been accepted as set forth in Section 2.1(c) and (ii) combinations of Your Open Enterprise Contributions that have been accepted as set forth in Section 2.1(c) (or portions thereof) with one or more Open Enterprise Contributions of one or more other Open Enterprise Participants, in each case solely as part of the Open Enterprise Result.<br>\n</p><p>\n        The licenses granted in this Section 2.3 are limited to (i) each version, development stage, or phase of the Open Enterprise Result that the Open Enterprise Assembly has decided to provide to parties other than Open Enterprise Participants and (ii) the scope, method(s) and channel(s) that the Open Enterprise Assembly has decided to employ to provide the Open Enterprise Result to such parties.\n</p>\n        <h3>2.4 Contribution Non-Acceptance.</h3>\n<p>\n        If Your Open Enterprise Contribution is not accepted by the Open Enterprise Assembly as set forth in Section 2.1(c), other Open Enterprise Participants retain the right to use any information about, or contained in, Your Open Enterprise Contribution that they retain in their unaided memories.\n</p>\n        <h3>2.5 Restrictions.</h3>\n<p>\n        Except as necessary in furtherance of the Open Enterprise and expressly authorized by the licenses that You grant to other Open Enterprise Participants hereunder, Open Enterprise Participants agree not to (a) modify, adapt, alter, translate, or create derivative works from Your Open Enterprise Contributions, (b) reverse engineer, decompile, disassemble, or otherwise attempt to derive the source code for Your Open Enterprise Contributions, (c) sublicense, lease, rent, loan, or otherwise transfer Your Open Enterprise Contributions to any third party, or (d) reproduce, distribute, publicly perform or display, or otherwise use or exploit Your Open Enterprise Contributions.\n</p>\n        <h3>2.6 Proprietary Rights.</h3>\n<p>\n        Your Open Enterprise Contributions and all intellectual property rights therein, are the exclusive property of You [and Your suppliers]. All rights in and to the Open Enterprise Contributions not expressly granted to others in this Agreement are reserved by You [and Your suppliers], and there are no implied licenses granted under this Agreement. The licenses granted in this Section 2 are non-transferable and non-assignable, except as provided in Section 3.\n</p>\n        <h3>2.7 Rules of Open Enterprise.</h3>\n<p>\n        You agree to comply with the Open Enterprise Governance Model and all other then-current rules and decisions of the Open Enterprise Assembly for Your Open Enterprise as they may be modified and/or amended from time to time by the Open Enterprise Assembly in accordance with the Open Enterprise Governance Model. Unless expressly authorized, no Open Enterprise Participant shall make any representations or warranties, or enter into any agreements, on behalf of another Open Enterprise Participant.\n</p>\n        <h2>3. END OF PARTICIPATION.</h2>\n        <h3>3.1 Transfer of the Open Enterprise.</h3>\n<p>\n        The licenses granted hereunder to Your Open Enterprise Contributions may be assigned or transferred to an entity (a \"Transferee\") as determined by the Open Enterprise Assembly through Voting by a majority of all Open Enterprise Participants [as set forth in the Open Enterprise Governance Model]; provided, however, that any such assignment or transfer shall be on the condition that the equity ownership in such Transferee reflects the distribution of Open Enterprise Units among the Open Enterprise Participants at the time of the assignment or transfer. Any assignment or transfer, or attempted assignment or transfer, in violation of this Section 3.1 is void and terminates the licenses granted under Section 2 of the Agreement. You hereby agree to assist and cooperate with the Open Enterprise Assembly and other Open Enterprise Participants in every reasonable way, both during and after the assignment or transfer, to carry our and perfect an assignment or transfer permitted under this Section 3.1.\n</p>\n        <h3>3.2 Dissolving the Open Enterprise.</h3>\n<p>\n        If the Open Enterprise Assembly decides by Voting that the Open Enterprise will finally be dissolved, the licenses You have granted under the Agreement and the licenses granted to You by other Open Enterprise Participants in connection with the Open Enterprise, shall be terminated effective upon the date on which the Open Enterprise is finally dissolved.\n</p>\n        <h3>3.3 Banning of Open Enterprise Participants.</h3>\n<p>\n        If the Open Enterprise Assembly decides by Voting to ban a Open Enterprise Participant from the Open Enterprise, any and all licenses granted to such Open Enterprise Participant in connection with the Open Enterprise shall be terminated upon the effective date of the banning of that Open Enterprise Participant. Open Enterprise Units granted to the banned Open Enterprise Participant are not affected by the banning of that Open Enterprise Participant.\n</p>\n        <h2>4. CONFIDENTIALITY</h2>\n\n        <h3>4.1 Terms and Conditions</h3>\n<p>\n        The terms and conditions of this Agreement protect your Confidential Information only after you have become a Open Enterprise Participant, unless you enter into a separate agreements with the recipient of your Confidential Information. \"Confidential Information\" means any information disclosed by one Open Enterprise Participant (the \"Disclosing Participant\") to another Open Enterprise Participant (the \"Receiving Participant\") in connection with the Open Enterprise that the Receiving Participant knows or reasonably should know is confidential or proprietary to the Disclosing Participant, or should be held confidential or proprietary by all Open Enterprise Participants in their dealings with a party that is not a Open Enterprise Participant, due to the nature or importance of such information for the Open Enterprise or Open Enterprise Result. In any case, Confidential Information includes Open Enterprise Contributions of other Open Enterprise Participants. The obligations of confidentiality under this Section 4 will automatically terminate with respect to any information that (a) was already known by the Receiving Participant at the time of such disclosure; (b) was disclosed to the Receiving Participant by a third party (including another Open Enterprise Participant) who had the right to make such disclosure without any confidentiality restrictions; (c) is, or through no fault of the Receiving Participant has become, generally available to the public; or (d) was independently developed by the Receiving Participant without the use of or reference to Confidential Information of the Disclosing Participant.\n</p>\n        <h3>4.2 Obligations.</h3>\n<p>\n        The Receiving Participant will not use any Confidential Information of the Disclosing Participant except to perform Open Enterprise tasks or responsibilities or to exercise licenses granted to the Receiving Participant by the Disclosing Participant. The Receiving Participant will disclose the Confidential Information of the Disclosing Participant only to (a) other Open Enterprise Participants who have a need to know such Confidential Information in furtherance of the Open Enterprise, (b) in case of a commercialization of the Open Enterprise Result, any intended recipient of the Open Enterprise Result to the extent necessary to receive and use the Open Enterprise Result as decided by the Open Enterprise Assembly, and (c) as otherwise authorized by the Disclosing Recipient. If Open Enterprise Contributions (including Code) are deposited in a repository, any Open Enterprise Participant that is granted access to such repository is deemed to have the right to use any Open Enterprise Contribution contained in the repository as set forth in the preceding sentence. The Receiving Participant will protect the Disclosing Participant's Confidential Information in the same manner as the Receiving Participant protects its own confidential or proprietary information of a similar nature, and in no event with less than reasonable care. Notwithstanding the foregoing, the Receiving Participant may disclose Confidential Information of the Disclosing Participant to the extent that such disclosure is required by law or by the order of a court or similar judicial or administrative body, provided that the Receiving Participant notifies the Disclosing Participant of such required disclosure promptly and in writing, and cooperates with the Disclosing Participant, at the Disclosing Participant's request and expense, in any lawful action to contest or limit the scope of such required disclosure.\n</p>\n        <h2>5. REPRESENTATION AND WARRANTIES.</h2>\n<p>\n        You represent and warrant to each Open Enterprise Participant that (a) Your Open Enterprise Contribution is an original work of authorship and that You have the authority to grant the licenses set forth in Sections 2.2 and 2.3, (b) to the best of Your knowledge, Your Open Enterprise Contribution does not violate any laws and regulations or rights of any third party, (c) to the best of Your knowledge, Your Open Enterprise Contribution does not infringe the patents, copyrights, trade secrets, or other intellectual property rights of any third party, (d) to the extent Your Open Enterprise Contribution consists of or contains Code, such Code does not (i) contain any Open Source Code, or (ii) contain any \"back door,\" \"time bomb,\" \"Trojan Horse,\" \"worm,\" \"drop-dead device,\" \"virus\" (as these terms are commonly used in the computer software field), or other software code designed to permit unauthorized access, to disable or erase software, hardware, or data, or to perform any other similar type of function, unless the specifications of Your Code defined by the Open Enterprise Assembly require Your Code to have or contain such functionality. \"Open Source Code\" means any software code that is distributed as \"free software\" or \"open source software\" or is otherwise distributed publicly in source code form under terms that permit modification and redistribution of such software. Open Source Code includes software code that is licensed under the GNU General Public License, GNU Lesser General Public License, Mozilla License, Common Public License, Apache License, BSD License, Artistic License, or Sun Community Source License.\n</p>\n        <h2>6. DISCLAIMER.</h2>\n<p>\n        EXCEPT AS EXPRESSLY SET FORTH IN SECTION 5, THE Open Enterprise CONTRIBUTION THAT YOU CONTRIBUTE UNDER THIS AGREEMENT IS PROVIDED BY YOU \"AS IS\" AND \"AS AVAILABLE\" AND YOU HEREBY DISCLAIM ALL WARRANTIES, WHETHER EXPRESS, IMPLIED, OR STATUTORY, ARISING IN CONNECTION WITH YOUR Open Enterprise CONTRIBUTION, INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NONINFRINGEMENT.\n</p>\n        <h2>7. GENERAL</h2>\n        <h3>7.1 Independent Contractors.</h3>\n<p>\n        You and the other Open Enterprise Participants are and at all times will be and remain independent contractors as to each other, and at no time will either Open Enterprise Participant be deemed to be the agent, employee, or partner of the other, or an agent or employee of the Open Enterprise, which is not an entity. No joint venture, partnership, agency, or other relationship will be created or implied as a result of this Agreement.\n</p>\n        <h3>7.2 Indemnification.</h3>\n<p>\n        You will indemnify and hold harmless each and every Open Enterprise Participant from and against all liabilities, losses, damages, costs, and other expenses (including attorneys' and expert witnesses' costs and fees) arising from or relating to any third party claim based upon (a) any breach by You of any of Your representations or warranties set forth in Section 5 above or (b) any breach by You of Section 2.7 or Section 4.\n</p>\n        <h3>7.3 Assignment.</h3>\n<p>\n        No party to this Agreement may assign this Agreement (including the license granted herein) to any third party without approval of the Open Enterprise Assembly as set forth in the Open Enterprise Governance Model, except as provided in Section 3.1. Any assignment or attempted assignment in violation of this Section 7.3 will be void.\n</p>\n        <h3>7.4 Waivers; Amendment.</h3>\n<p>\n        No waiver of any terms or conditions of this Agreement will be valid or binding on You unless You make the waiver in writing. Your failure to enforce any of the provisions of this Agreement, or the failure to require at any time the performance of another party of any of the provisions of this Agreement, will in no way be construed to be a present or future waiver of such provisions, nor in any way affect Your ability to enforce each and every provision thereafter. This Agreement may not be altered, amended, modified, or otherwise changed in any way except by a written instrument signed by You.\n</p>\n        <h3>7.5 Severability.\n          </h3>\n<p>\n        If any provision of this Agreement is found or held to be invalid or unenforceable by any tribunal of competent jurisdiction, then the meaning of such provision will be construed, to the extent feasible, so as to render the provision enforceable, and if no feasible interpretation would save such provision, it will be severed from the\n        remainder of this Agreement, which will remain in full force and effect.\n</p>\n        <h3>7.6 Construction.</h3>\n<p>\n        The headings of sections of this Agreement are included solely for convenience of reference and are not to be used to interpret, construe, define, or describe the scope of any aspect of this Agreement. As used in this Agreement, the word \"including\" means \"including but not limited to.\"\n</p>\n        <h3>7.7 Entire Agreement.</h3>\n<p>\n        This Agreement constitutes the entire agreement and final understanding of You and the other Open Enterprise Participants with respect to the subject matter hereof, and supersedes any other and all prior or contemporaneous negotiations, representations, understandings, discussions, offers, and agreements between You and the other Open Enterprise Participants, whether written or oral, express or implied, relating in any way to the subject matter hereof. This Agreement is intended by You and the other Open Enterprise Participants to be a complete and wholly integrated expression of their understanding and agreement.\n</p>\n\n</section></div></div></div></div>\n"
  },
  {
    "path": "app/views/home/webdesign.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n    <%= render :partial => 'header', :locals => {:page => 'about'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div class=\"clear span-12\">\n        <div class=\"span-8 first inner-page-title\">\n          <h2 class=\"main-title-2\">See our latest websites</h2>\n          <span>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. </span> </div>\n        <div class=\"clear\"></div>\n        <div class=\"span-12\" id=\"gallery\">\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-1_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-2_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-2.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-3_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-3.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n          <div class=\"gallery-content\">\n            <div class=\"span-5 gallery-left\">\n              <h3>Suspendisse posuere libero quis</h3>\n              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus non ultricies sapien. Etiam eget sapien eget quam lacinia mollis venenatis non urna.</p>\n              <ul>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n                <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </li>\n              </ul>\n              <a class=\"readmore\" href=\"#\">Read more</a> </div>\n            <div class=\"viewport span-6\"> <a class=\"example\" HREF=\"/images/static/image-4_b.jpg\"> <span class=\"dark-background\"></span> <img src=\"/images/static/product-ph-4.jpg\" alt=\"\" width=\"460\" height=\"247\"/> </a> </div>\n          </div>\n          <div class=\"hr\"></div>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n<script type=\"text/javascript\">\n      $(document).ready(function() {\n        $('.viewport').mouseenter(function(e) {\n          $(this).children('a').children('img').animate({ height: '268', left: '-20', top: '-20', width: '480'}, 100);\n          $(this).children('a').children('span').fadeIn(300);\n        }).mouseleave(function(e) {\n          $(this).children('a').children('img').animate({ height: '268', left: '-20', top: '-20', width: '480'}, 100);\n          $(this).children('a').children('span').fadeOut(200);\n        });\n      });\n    </script>\n"
  },
  {
    "path": "app/views/home/what.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n   <%= render :partial => 'header', :locals => {:page => 'what'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div>\n      <h1>Get things done together efficiently</h1>\n      <span class=\"span-12 left whitebox\">\n        <span class=\"span-6 left colborder\">\n          <h2>Home Screen and Workstreams</h2>\n          <p>The home screen of your project is the first page you will see. It shows an overview of your team’s work with:\n          </p>\n          <ul>\n            <li>Lastest Activity </li>\n            <li>Workstreams </li>\n            <li>Lastest News </li>\n            <li>Team Members </li>\n            <li>Quicklinks </li>\n            <li>Work Breakdown </li>\n          </ul>\n        </span>\n        <span class=\"span-6 left last\">\n          <span class=\"viewport\">\n          <a class=\"videolink\" href=\"http://www.youtube.com/v/0wJAf229YUs&hl=en&fs=1&autoplay=1&fmt=6\" target=\"blank\" title=\"open enterprise governance\">\n          <img src=\"/images/static/tutorialvideo.jpg\" />\n          </a>\n          </span>\n          <blockquote>The significant problems we have cannot be solved at the same level of thinking with which we created them<author>Albert Einstein</author></blockquote>\n\n        </span>\n\n      </span>\n      </div>\n\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <h2>Dashboard</h2>\n                <p>The dashboard provides a full view of all the items in a workstream.\n                From the dashboard you can:\n                </p>\n                <ul>\n                  <li>Propose new ideas </li>\n                  <li>Comment on other people's ideas </li>\n                  <li>Vote for or against ideas </li>\n                  <li>Prioritize important work </li>\n                  <li>Estimate complexity/cost </li>\n                  <li>Manage a Todo list for each item </li>\n                  <li>Start or join teams </li>\n                  <li>Report on finished items </li>\n                  <li>Accept or reject other's work </li>\n                </ul>\n              </span>\n              <span class=\"span-6 left last\">\n                <span class=\"viewport\">\n                  <a class=\"videolink\" href=\"http://www.youtube.com/v/GRUDSoR12s8&hl=en&fs=1&autoplay=1&fmt=6\" target=\"blank\" title=\"Worksrtream Dashboard\">\n                  <img src=\"/images/static/dashboard_video.png\" />\n                  </a>\n                </span>\n              </span>\n            </span>\n      </div>\n      <div class=\"paint\">\n        <p>\n        learn about <br><a href=\"/front/how.html\">how an open enterprise works</a></p>\n      </div>\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <h2>Lightbox</h2>\n                <p>The lightbox allows you to view all the specifics of an item without navigating away from the page you are on. <br>\n                A lightbox opens from the activity page or the dashboard, allowing you to do everything that you do in the dashboard (listed above) but with more information.\n                </p>\n              </span>\n              <span class=\"span-6 left last\">\n                <span class=\"viewport\">\n                <a class=\"videolink\" href=\"http://www.youtube.com/v/dkFamGHd2qw&hl=en&fs=1&autoplay=1&fmt=6\" target=\"blank\" title=\"lightbox view\">\n                <img src=\"/images/static/lightbox_video_background.png\" />\n                </a>\n                </span>\n              </span>\n      </div>\n\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <h2>Activity</h2>\n                <p>The activity is a news feed of all of the activity for that workstream.<br>\n                From the activity page you can\n                </p>\n                <ul>\n                  <li>See the latest buzz, comments, and discussions</li>\n                  <li>Comment on items</li>\n                  <li>Open any item in a lightbox and take action</li>\n                </ul>\n                </span>\n\n                  <span class=\"span-6 left last\">\n                    <span class=\"viewport\">\n                    <a class=\"videolink\" href=\"http://www.youtube.com/v/_aAEQGB40gU&hl=en&fs=1&autoplay=1&fmt=6\" target=\"blank\" title=\"activity stream\">\n                    <img src=\"/images/static/activity_video_background.jpg\" />\n                    </a>\n                    </span>\n                </span>\n            </span>\n      </div>\n\n          <div>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <h2>Item Estimation</h2>\n                <p>Work items' complexity can be collectively estimated via the dashboard.<br>Here's how it works:\n                </p>\n                <p>Members of a team who choose to, can estimate the item's complexity on a scale from one to six. The assessment of all members with a binding vote is averaged. Non-binding assessments are logged but don't affect the final complexity of an item.</p>\n                <p>Depending on how complex an item has been estimated, it needs fewer or more votes to move from one state to another. <strong>This allows big-item decisions to move slower, giving more people a chance to weigh in on it, while small-item decisions can move quickly without being blocked.</strong></p>\n                <p>Knowing an item's complexity also better informs the team to properly prioritize it. </p>\n              </span>\n              <span class=\"span-6 left last\">\n                <span class=\"viewport\">\n                <a class=\"videolink\" href=\"http://www.youtube.com/v/ydHazAMogaw&hl=en&fs=1&autoplay=1&fmt=6\" target=\"blank\" title=\"retrospectives\">\n                <img src=\"/images/static/estimation_video.png\" />\n                </a>\n                </span>\n                <blockquote>We have created trouble for ourselves in organizations by confusing control with order<author>Margarate J. Wheatley</author></blockquote>\n\n\n            </span>\n      </div>\n      <div class=\"paint\">\n        <p>\n        take a look at our<br><a href=\"/front/pricing.html\">plans and pricing</a>\n        </p>\n      </div>\n\n      <div>\n          <h1></h1>\n          <span class=\"span-12 left whitebox\">\n            <span class=\"span-6 left colborder\">\n              <h2>Motions</h2>\n              <p>Motions are a way to make big organizational decisions together. They can be used for thinks like</p>\n              <ul>\n                <li>Nominating a new member</li>\n                <li>Nominating a core team member</li>\n                <li>Revised mission statement</li>\n                <li>New strategic direction</li>\n                <li>New hourly work type</li>\n              </ul>\n              </p>\n            </span>\n            <span class=\"span-6 left last\">\n              <span class=\"viewport\">\n                <a class=\"fancy_image\" HREF=\"/images/static/motion.png\" title=\"Work Item Estimation\"> <span class=\"dark-background\"></span> <img src=\"/images/static/motion_medium.png\" alt=\"\" width=\"460\" height=\"247\"/> </a></span>\n\n                </span>\n            </span>\n          </span>\n      </div>\n\n\n      <div>\n          <h1></h1>\n          <span class=\"span-12 left whitebox\">\n            <span class=\"span-6 left colborder\">\n              <h2>Discussion Boards</h2>\n              <p>If you have an idea that you are not yet ready to propose and want to talk to folks about it, start a discussion.</p>\n              <p>Topics you might discuss:</p>\n              <ul>\n                <li>General strategy</li>\n                <li>New possible workstreams</li>\n                <li>New target audience</li>\n                <li>Anything else that comes to mind...</li>\n              </ul>\n            </span>\n            <span class=\"span-6 left last\">\n              <span class=\"viewport\">\n                <a class=\"fancy_image\" HREF=\"/images/static/discussion.png\" title=\"Work Item Estimation\"> <span class=\"dark-background\"></span> <img src=\"/images/static/discussion_medium.png\" alt=\"\" width=\"460\" height=\"247\"/> </a></span>\n                </span>\n            </span>\n          </span>\n      </div>\n\n\n      <div class=\"paint\">\n        <p>\n        &nbsp;<br><a href=\"/front/pricing.html\">get started by signing up</a>\n        </p>\n      </div>\n\n      <div>\n          <h1></h1>\n          <span class=\"span-12 left whitebox\">\n            <span class=\"span-6 left colborder\">\n              <h2>Wiki</h2>\n              <p>Yup, we have wikis too. </p>\n              <p>A wiki is a tool that allows the easy creation and collaboration of any number of interlinked documents.</p>\n              <p>You can create a document and collect information together. Edit and work with each other to build knowledge and move forward. </p>\n            </span>\n            <span class=\"span-6 left last\">\n              <h2>Document Storage</h2>\n              <p>You have the ability to:</p>\n              <ul>\n                <li>Attach documents to a specific work item</li>\n                <li>Gather documents within a workstream</li>\n                <li>Store documents at the root workstream level</li>\n              </ul>\n               <p>Note: Storage limits exist for private workstreams. For more information on this <a href=\"/front/pricing.html\">see our Pricing and Plans</a>. </p>\n            </span>\n          </span>\n      </div>\n\n\n      <div>\n          <h1></h1>\n          <span class=\"span-12 left whitebox\">\n            <span class=\"span-6 left colborder\">\n              <h2>Data Security &amp; Backup</h2>\n              <p>We treat your data royally. Its religiously backed up to Amazon’s weapons-grade data centers. Don’t worry.</p>\n              <p>All traffic to and from our servers is encrypted using 128-bit SSL (that’s geek-speak for really really safe).</p>\n              <p>We've got you covered.</p>\n              <span style=\"margin-left:160px\">\n              <img src=\"/images/static/lock.jpg\"/>\n              </span>\n\n            </span>\n            <span class=\"span-6 left last\">\n              <h2>Browser Compatibility</h2>\n              <span style=\"margin-left:60px\">\n              <img src=\"/images/static/browsers_no_ie.jpg\"/>\n              </span>\n              <p>Currently BetterMeans.com is compatible with the following browsers:</p>\n              <ul>\n                  <li>Firefox 3 and higher</li>\n                  <li>Safari 4 and higher</li>\n                  <li>Chrome 4</li>\n              </ul>\n\n            </span>\n          </span>\n      </div>\n\n      <div class=\"paint\">\n        <p>\n        take a look at our<br><a href=\"/front/pricing.html\">plans and pricing</a>\n        </p>\n      </div>\n\n    </div>\n  </div>\n</div>\n\n</body>\n</html>\n"
  },
  {
    "path": "app/views/home/why.html.erb",
    "content": "<div id=\"inner-page\">\n  <div class=\"container\">\n   <%= render :partial => 'header', :locals => {:page => 'why'} %>\n    <div class=\"clear span-12 last\" id=\"main-inner\">\n      <div>\n      <h1>why bettermeans?</h1>\n      <span class=\"span-12 left whitebox\">\n        <span class=\"span-6 left colborder\">\n          <h2>The way we work together, needs an upgrade</h2>\n                      <p>We are facing mounting social, environmental and economic problems.\n                        A lot of us want to work toward solving them and we are learning that these problems are interconnected, and complex.</p>\n                      <p>We are trying to solve these problems using organizational structures that were invented before the light bulb! Industrial-age organizations are not smart or flexible enough to navigate the challenges we are facing. </p>\n                        <p><strong>To change our world, we need a new agreement of how we work together.</strong> How we make decisions. How we decide on who gets to work on what. And who gets paid what.</p>\n        </span>\n        <span class=\"span-6 left last\">\n\n          <span class=\"viewport\">\n          <a class=\"videolink\" href=\"http://www.youtube.com/v/OZaxoRi6IlE&autoplay=1&fmt=22\" target=\"blank\" title=\"tale of two tales\">\n          <img src=\"/images/static/taleoftwotales.jpg\" />\n          </a>\n          </span>\n          <blockquote>The significant problems we have cannot be solved at the same level of thinking with which we created them<author>Albert Einstein</author></blockquote>\n\n        </span>\n\n\n      </span>\n      </div>\n      <div class=\"paint\">\n        <p>\n        learn about <br><a href=\"/front/how.html\">how an open enterprise works</a></p>\n      </div>\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\">\n                <h2>Social Entrepreneurs: Helping others do great work</h2>\n                <p>Two thirds of Americans have an idea for an entrepreneurial venture but only a tenth of them will carry through with it.  <strong>There are very few real sources of capital available for social entrepreneurs,</strong> and the current capital market, with very few exceptions, demands exponential growth from young startups with oppressive contractual agreements.</p>\n                <p>Innovations in social entrepreneurship are choked by the lack of supportive funding channels and the difficulty of finding and recruiting the appropriate workforce.  <strong>Entrepreneurs need better access to capital and talent,</strong> they need passionate people who will work because they believe in the idea, and commit to projects without being told what to do.</p>\n                <p>The Open Enterprise Model is <strong>a way for people with ideas to connect to others and get those ideas off the ground with minimal bureaucracy or resistance.</strong>  It harnesses the collective wisdom, creativity, passion, and productivity of a dispersed crowd - whether in one city block or across oceans - and channels their efforts in order to simply get good work done! Which is the real reason the majority of us wake up in the morning, to do good work in this world.</p>\n              </span>\n              <span class=\"span-6 left last\">\n                <span class=\"viewport\">\n                <a class=\"fancy_image\" title=\"Principles of an Open Enterprise\" HREF=\"/images/static/principles.png\"> <span class=\"dark-background\"></span> <img src=\"/images/static/principles_medium.png\" alt=\"\" width=\"460\" height=\"247\"/> </a></span>\n                <br><br>\n                <blockquote>We will need a willingness to question our most deeply held habitual ways of seeing organizations and management. We will need a willingness eventually to embrace the seeming chaos of an organization that no one ‘runs’ and where we all share responsibility. We will need to embrace continual mistake-making and correcting, nature’s learning process. And we will need a willingness to surrender the personal need to control—‘the closet Newtonian’ that resides in all of us.<author>Dee Hock, CEO and Founder of Visa</author></blockquote>\n              </span>\n            </span>\n      </div>\n      <div>\n            <h1></h1>\n            <span class=\"span-12 left whitebox\">\n              <span class=\"span-6 left colborder\"><br><br>\n                <blockquote>For thousands of years, markets and hierarchies were the only alternatives when it came to aggregating human effort. Now there's a third option: real-time, distributed networks.\n                <author>Gary Hamel<br> Voted #1 business thinker by the Wall Street Journal</author></blockquote>\n              </span>\n              <span class=\"span-6 left last\">\n                <h2>The Engagement Gap</h2>\n                <p> Our organizations are failing to engage us, and provide a place where our purpose comes alive.</p>\n                <p><strong>85% of people are disengaged from their work. Two of the top five reasons given are management and misalignment of values.</strong></p>\n                <p>The Internet provides us with tools to connect and work together, but the management system we're using cannot keep up; it's over 100 years old and was modeled after old military thinking.</p>\n              </span>\n            </span>\n      </div>\n      <span class=\"span-12 left\">\n        <br>\n        <h1>Collapse of the Corporate Model</h1>\n      </span>\n      <div>\n            <span class=\"span-12 left whitebox\">\n              <h2>Simply put, today's corporate organizational structure is outdated. The conventional business model is broken.</h2>\n              <h3>It’s broken because 67% of American workers are actively unhappy with their jobs.</h3>\n              <p>In fact, job dissatisfaction has increased steadily by a whopping 16% over the past 20 years. And this trend shows no sign of slowing. Notably, the <strong>most dissatisfied portion of the work force is the upcoming Generation Y</strong>—those under the age of 25.</p>\n              <h3>It’s broken because the current organizational structure cannot adapt as fast as the world is changing.</h3>\n              <p>Today's business model originated before plumbing and electricity—long before a global marketplace, multi-national competitors, and rapid technological change. The pace is quickening. In 2008 the number of patent applications received was over twice the number of applications in 1998, just 10 years prior. The current top-down model makes it impossible for a single leader or small team of decision-makers to discover, research, implement and dictate new protocols as fast the global landscape is demanding adaptation.</p>\n              <h3>It’s broken because in a top-down system, innovation is being smothered.</h3>\n              <p>The top must dictate behavior by creating endless manuals covering corporate procedures, protocols and policies. Threatened with punitive actions or loss of paycheck, workers throw away common sense in favor of a rigid adherence to the rules... leaving entire organizations nearly bereft of clear-minded decision makers, and <strong>stamping out intelligent risk-taking</strong> and the innovations that would follow.</p>\n              <blockquote class=\"middle\">For me, this is a familiar image - people in the organization ready and willing to do good work, wanting to contribute their ideas, ready to take responsibility, and leaders holding them back, insisting that they wait for decisions or instructions.<author>Margarate J. Wheatley</author></blockquote>\n              <h3>It’s broken because mistrust between the general public and corporate entities is at an all-time high.</h3>\n              <p>U.S. law entitles corporate entities the same legal rights as human citizens-- at the same time it lacks a clear means to hold these corporate citizens accountable. The resutl is <strong>power without responsibility</strong>, and we have only to look to Enron, Halliburton, or the recent housing crisis to understand the ill effects of this lopsided agreement.</p>\n              <h3>It’s broken because a workforce driven, coerced, and manipulated by a system of punishments and rewards, leaves very little room for ingenuity, cooperation, honesty, or respect. That is, our humanity.</h3>\n              <p>It creates a culture that sees people (both customers and coworkers) as objects to be manipulated for profit. It rewards office politics and unethical behavior—often at the expense of the company’s true goals. The result is <strong>resentment from both employees and customers</strong> alike—and resentment erodes profits.</p>\n              <h3>It’s broken because the current business model focuses on goals, and thus acts as if the ends can justify the means.</h3>\n              <p>In such an organization, the what to do is never lost. Only the why it is being done. And when the why gets lost, Merck ends up selling poison in the name of \"healing the sick\"... Monsanto keeps a strangle-hold on the world’s supply of seeds and uses profoundly unethical and illegal practices to ruin traditional farmers in the name of \"feeding the hungry\"... And Nike uses sweatshop labor, abuses workers, and pays well below 3rd world minimum wages—even circumventing local laws to do so... all in the name of \"inspiring today's youth to reach their highest potential.\"</p>\n              <blockquote class=\"middle\">Ethics is the new competitive environment<author>Peter Robinson, CEO Mountain Equipment Co-op</author></blockquote>\n            </span>\n      </div>\n\n      <div class=\"paint\">\n        <p>\n        take a look at our<br><a href=\"/front/pricing.html\">plans and pricing</a>\n        </p>\n      </div>\n\n      </div>\n    </div>\n  </div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "app/views/hourly_types/_form.html.erb",
    "content": "<%= error_messages_for 'hourly_type' %>\n\n<div class=\"gt-content-box\">\n<p><%= f.text_field :name, :required => true %></p>\n<p><%= f.text_field :hourly_rate_per_person, :required => true %></p>\n<p><%= f.text_field :hourly_cap, :required => true %></p>\n</div>\n"
  },
  {
    "path": "app/views/hourly_types/edit.html.erb",
    "content": "<h2><%= l(:label_hourly_type) %></h2>\n\n<% labelled_tabular_form_for :hourly_type, @hourly_type, :url => {:action => 'edit', :id => @hourly_type} do |f| %>\n  <%= render :partial => 'form', :locals => {:f => f} %>\n  <div class=\"gt-table-buttons\">\n      <%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/hourly_types/new.html.erb",
    "content": "<h2><%= l(:label_hourly_type_new) %></h2>\n\n<% labelled_tabular_form_for :hourly_type, @hourly_type, :url => {:action => 'new'} do |f| %>\n  <%= render :partial => 'form', :locals => {:f => f} %>\n  <div class=\"gt-table-buttons\">\n      <%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/invitations/_generic_invitation.html.erb",
    "content": "<div class=\"clip-notice\" id=\"generic-invitation\">\n  <div class=\"generic-link-reset\">\n  <%= link_to_remote(l(:text_reset_link), :url => {:controller => 'projects', :action => 'reset_invitation_token', :id => project.id}, :confirm => \"Are you sure? This will render all previous global invitations inactive. This action cannot be undone.\") %><%= help_bubble(:help_reset_link) %>  </div>\n  <div class=\"generic-link-text\">\n  <p><%= l(:text_generic_invitation) %></p>\n  <span id=\"generic-link\"><strong><%= url_for(:controller => 'projects', :action => 'join', :id => project.id, :token => project.invitation_token, :only_path => false) %><br></strong></span>\n  <br>\n  <p><%= l(:text_generic_invitation_2) %></p>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/invitations/edit.html.erb",
    "content": "<h1>Editing invitation</h1>\n\n<% form_for(@invitation) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :user_id %><br />\n    <%= f.text_field :user_id %>\n  </p>\n  <p>\n    <%= f.label :project_id %><br />\n    <%= f.text_field :project_id %>\n  </p>\n  <p>\n    <%= f.label :token %><br />\n    <%= f.text_field :token %>\n  </p>\n  <p>\n    <%= f.label :status %><br />\n    <%= f.text_field :status %>\n  </p>\n  <p>\n    <%= f.label :role %><br />\n    <%= f.text_field :role %>\n  </p>\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @invitation %> |\n<%= link_to 'Back', invitations_path %>\n"
  },
  {
    "path": "app/views/invitations/index.html.erb",
    "content": "<h2>Invitations sent by you for <%= @project.name %></h2>\n\n<table border=\"0\" class=\"gt-table gt-user-table\">\n  <tbody>\n  <tr>\n    <th>User</th>\n    <th>Role</th>\n    <th>Sent</th>\n    <th>Accepted</th>\n  </tr>\n\n<% @invitations.each do |invitation| %>\n  <tr id=\"row-<%= invitation.id %>\">\n    <td><%=h invitation.mail %></td>\n    <td><%=h invitation.role.name %></td>\n    <td><%=format_time_ago invitation.created_at %></td>\n\n    <%if invitation.status == Invitation::ACCEPTED %>\n      <td><div class=\"icon icon-cr-accept\"><%= format_time_ago invitation.updated_at  %></div></td>\n    <% else %>\n    <td><%= link_to_remote l(:button_resend),\n      :url => {:controller => :invitations, :action => :resend, :id => invitation, :project_id => @project},\n      :html => {:class => \"icon icon-cr-offer\", :id => \"resend-#{invitation.id}\"}\n     %>\n    &nbsp;&nbsp;&nbsp;&nbsp;\n      <%= link_to_remote l(:button_delete),\n        :url => {:controller => :invitations, :action => :destroy, :id => invitation, :project_id => @project},\n        :confirm => \"Are you sure?\",\n        :html => {:class => \"icon icon-del\"}\n       %>\n       </td>\n    <% end %>\n  </tr>\n<% end %>\n</tbody>\n</table>\n<div class=\"gt-table-controls gt-table-controls-btm clearfix\">\n  <p class=\"gt-table-pager\"><%= pagination_links_full @all_invites %></p>\n</div>\n\n\n<br />\n\n<% content_for :sidebar do %>\n<h2>&nbsp;</h2>\n<div class=\"gt-sidebar-nav gt-sidebar-nav-blue\">\n  <h3><%=l(:label_quick_links)%></h3>\n  <ul>\n  <li>\n    <%= link_to l(:label_login), {:controller => :account, :action => :login} unless User.current.logged? %>\n  </li>\n  <li>\n    <%= link_to l(:label_dashboard), {:controller => :projects, :action => :dashboard, :id => @project} %>\n  </li>\n  <% if User.current.allowed_to?(:send_invitations, @project) %>\n  <li>\n    <%= link_to l(:label_invitation_new), new_project_invitation_url(@project) %>\n  </li>\n  <% end %>\n  </ul>\n</div>\n<% end %>\n\n<script type=\"text/javascript\">\nfunction send_remote(url,param,note){\n  $.ajax({\n     type: \"POST\",\n     dataType: \"json\",\n     url: url,\n     data: '&note=' + note + param,\n    timeout: 30000 //30 seconds\n   });\n}\n</script>\n"
  },
  {
    "path": "app/views/invitations/new.html.erb",
    "content": "<h2><%= l(:text_invite_others_to_contribute)  %>&nbsp;<%= @project.name %><%= help_bubble(:text_generic_invitation_long) %></h2>\n  <%= render :partial => 'generic_invitation', :locals => {:project => @project} %>\n  <br><br>\n<h2><%= l(:text_invite_others_to_contribute_personal)  %><%= help_bubble(:text_personal_invitation) %></h2>\n<% form_tag({:action => 'create', :project => @project}, :method => 'post') do %>\n<div class=\"gt-left-col\">\n\n  <label><%= l(:text_email_instruction) %></label>\n  <%= text_area_tag :emails, @emails, :class => 'wiki-edit', :rows => 10, :colums => 60 %><br><br >\n  <label><%= l(:text_personalize_invitations) %></label>\n  <%= text_area_tag :note, @note, :class => 'wiki-edit', :rows => 10, :colums => 60 %>\n\n\n</div>\n<div class=\"gt-right-col\">\n  <% @roles = Role.find(:all, :conditions => {:level => 1}, :order => \"position DESC\") %>\n  <label><%= l(:text_invite_role_instruction) %> <%= collection_select( :invitation, :role_id, @roles, :id, :name, :selected => Role.contributor.id ) %></label>\n\n  <%= observe_field(:invitation_role_id, :frequency => 0.25, :function => \"update_description();\") %>\n\n  <div class=\"gt-content-box padded\" id=\"role-description\">\n  </div>\n\n  <p>\n    <%= submit_tag 'Send Invitations' %>\n  </p>\n\n</div>\n<% end %>\n\n<% content_for :sidebar do %>\n<% end %>\n\n<% content_for :sidebar do %>\n<h2 class=\"gt-table-head\">&nbsp;</h2>\n<%= help_section \"invitation_new\" %>\n<div class=\"gt-sidebar-nav gt-sidebar-nav-blue\">\n  <h3><%=l(:label_quick_links)%></h3>\n  <ul>\n    <li>\n      <%= link_to l(:label_login), {:controller => :account, :action => :login} unless User.current.logged? %>\n    </li>\n    <li>\n      <%= link_to l(:label_dashboard), {:controller => :projects, :action => :dashboard, :id => @project} %>\n    </li>\n    <% if User.current.allowed_to?(:manage_invitations, @project) %>\n      <li><%= link_to(l(:label_track_invites), {:controller => :invitations, :action => :index}) %>\n      </li>\n    <% end %>\n  </ul>\n</div>\n<% end %>\n\n<script type=\"text/javascript\">\n  <% @roles.each do |r| %>\n    var <%= r.name.gsub(/ /,\"_\")  %>_description = \"<%= l(\"text_role_invitation_description_#{r.name.gsub(/ /,\"_\")}\") %>\";\n  <% end  %>\n\n  $(document).ready(function(){\n    update_description();\n  });\n\n  function update_description(){\n    var id = $('#invitation_role_id').val();\n    var name = $('#invitation_role_id option[value=\\'' +  id + '\\']').text();\n    var html = \"\";\n    html = html + \"<strong>\" + name + \"</strong><br><br>\";\n    html = html + eval(name.replace(\" \",\"_\") + '_description') + \"<br><br>\";\n\n    $('#role-description').html(html);\n  }\n</script>\n"
  },
  {
    "path": "app/views/invitations/show.html.erb",
    "content": "<p>\n  <b>User:</b>\n  <%=h @invitation.user_id %>\n</p>\n\n<p>\n  <b>Workstream:</b>\n  <%=h @invitation.project_id %>\n</p>\n\n<p>\n  <b>translation missing: en, field_token:</b>\n  <%=h @invitation.token %>\n</p>\n\n<p>\n  <b>Status:</b>\n  <%=h @invitation.status %>\n</p>\n\n<p>\n  <b>Role:</b>\n  <%=h @invitation.role %>\n</p>\n\n\n<%= link_to 'Edit', edit_invitation_path(@invitation) %> |\n<%= link_to 'Back', invitations_path %>\n"
  },
  {
    "path": "app/views/issue_relations/_form.html.erb",
    "content": "<%= error_messages_for 'relation' %>\n\n<p><%= f.select :relation_type, collection_for_relation_type_select, {}, :onchange => \"setPredecessorFieldsVisibility();\" %>\n<%= l(:label_issue) %> #<%= f.text_field :issue_to_id, :size => 10, :class => \"short issue-relation\" %>\n<span id=\"predecessor_fields\" style=\"display:none;\">\n<%= l(:field_delay) %>: <%= f.text_field :delay, :size => 3, :class => \"short\" %> <%= l(:label_day_plural) %>\n</span>\n<%= submit_tag l(:button_add), :disable_with => l(:button_working) %>\n<%= toggle_link l(:button_cancel), 'new-relation-form'%>\n</p>\n\n<%= javascript_tag \"bind_relations_autocomplete(#{@project.id});\" %>\n"
  },
  {
    "path": "app/views/issue_statuses/_form.html.erb",
    "content": "<%= error_messages_for 'issue_status' %>\n\n<div class=\"gt-content-box\">\n<p><label for=\"issue_status_name\"><%=l(:field_name)%><span class=\"required\"> *</span></label>\n<%= text_field 'issue_status', 'name'  %></p>\n\n<p><label for=\"issue_status_is_closed\"><%=l(:field_is_closed)%></label>\n<%= check_box 'issue_status', 'is_closed' %></p>\n\n<p><label for=\"issue_status_is_default\"><%=l(:field_is_default)%></label>\n<%= check_box 'issue_status', 'is_default' %></p>\n\n</div>\n"
  },
  {
    "path": "app/views/issue_statuses/edit.html.erb",
    "content": "<h2><%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses', :action => 'index' %> &#187; <%=h @issue_status %></h2>\n\n<% form_tag({:action => 'update', :id => @issue_status}, :class => \"tabular\") do %>\n  <%= render :partial => 'form' %>\n  <div class=\"gt-table-buttons\">\n    <%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/issue_statuses/list.html.erb",
    "content": "<div class=\"contextual\">\n<%= link_to l(:label_issue_status_new), {:action => 'new'}, :class => 'icon icon-add' %>\n</div>\n\n<h2><%=l(:label_issue_status_plural)%></h2>\n\n<table class=\"gt-table\">\n  <thead><tr>\n  <th><%=l(:field_status)%></th>\n  <th><%=l(:field_is_default)%></th>\n  <th><%=l(:field_is_closed)%></th>\n  <th><%=l(:button_sort)%></th>\n  <th></th>\n  </tr></thead>\n  <tbody>\n<% for status in @issue_statuses %>\n  <tr class=\"<%= cycle(\"odd\", \"even\") %>\">\n  <td><%= link_to status.name, :action => 'edit', :id => status %></td>\n  <td align=\"center\"><%= image_tag 'true.png' if status.is_default? %></td>\n  <td align=\"center\"><%= image_tag 'true.png' if status.is_closed? %></td>\n  <td align=\"center\" style=\"width:15%;\"><%= reorder_links('issue_status', {:action => 'update', :id => status}) %></td>\n  <td class=\"buttons\">\n    <%= link_to(l(:button_delete), { :action => 'destroy', :id => status },\n                                   :method => :post,\n                                   :confirm => l(:text_are_you_sure),\n                                   :class => 'icon icon-del') %>\n  </td>\n  </tr>\n<% end %>\n  </tbody>\n</table>\n\n<p class=\"pagination\"><%= pagination_links_full @issue_status_pages %></p>\n\n<% html_title(l(:label_issue_status_plural)) -%>\n"
  },
  {
    "path": "app/views/issue_statuses/new.html.erb",
    "content": "<h2><%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses', :action => 'index' %> &#187; <%=l(:label_issue_status_new)%></h2>\n\n<% form_tag({:action => 'create'}, :class => \"tabular\") do %>\n  <%= render :partial => 'form' %>\n  <div class=\"gt-table-buttons\">\n      <%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/issue_votes/edit.html.erb",
    "content": "<h1>Editing issue_vote</h1>\n\n<% form_for(@issue_vote) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @issue_vote %> |\n<%= link_to 'Back', issue_votes_path %>\n"
  },
  {
    "path": "app/views/issue_votes/index.html.erb",
    "content": "<h1>Listing issue_votes</h1>\n\n<table>\n  <tr>\n  </tr>\n\n<% @issue_votes.each do |issue_vote| %>\n  <tr>\n    <td><%= link_to 'Show', issue_vote %></td>\n    <td><%= link_to 'Edit', edit_issue_vote_path(issue_vote) %></td>\n    <td><%= link_to 'Destroy', issue_vote, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New issue_vote', new_issue_vote_path %>\n"
  },
  {
    "path": "app/views/issue_votes/new.html.erb",
    "content": "<h1>New issue_vote</h1>\n\n<% form_for(@issue_vote) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', issue_votes_path %>\n"
  },
  {
    "path": "app/views/issue_votes/show.html.erb",
    "content": "\n<%= link_to 'Edit', edit_issue_vote_path(@issue_vote) %> |\n<%= link_to 'Back', issue_votes_path %>\n"
  },
  {
    "path": "app/views/issues/_action_menu.html.erb",
    "content": "<%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo(\"update\", \"issue_description\"); return false;', :class => 'icon icon-edit action-state-button', :accesskey => accesskey(:edit)) if @issue.editable? %>\n<%= link_to_if_anon(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'ask_for_login(); return false;', :class => 'icon icon-edit action-state-button', :accesskey => accesskey(:edit)) %>\n<%= link_to(l(:button_dashboard), {:controller => 'projects', :action => 'dashboard', :id => @issue.project_id}, :class => 'icon icon-dashboard  action-state-button') %>\n<%= link_to_if_authorized l(:button_move), {:controller => 'issues', :action => 'move', :id => @issue }, :class => 'icon icon-move action-state-button', :target => '_top' %>\n<% replace_watcher ||= 'watcher' %>\n<%= watcher_tag(@issue, User.current, {:id => replace_watcher, :replace => ['watcher','watcher2']}) %>\n"
  },
  {
    "path": "app/views/issues/_attributes.html.erb",
    "content": "<% fields_for :issue, @issue, :builder => TabularFormBuilder do |f| %>\n\n<div class=\"splitcontentleft\">\n<% if @issue.new_record? || @allowed_statuses.any? %>\n<p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %></p>\n<% else %>\n<p><label><%= l(:field_status) %></label> <%= @issue.status.name %></p>\n<% end %>\n\n</div>\n\n<div class=\"splitcontentright\">\n<p><%= f.text_field :due_date, :size => 10 %><%= calendar_for('issue_due_date') %></p>\n<p><%= f.text_field :estimated_hours, :size => 3 %> <%= l(:field_hours) %></p>\n</div>\n\n<div style=\"clear:both;\"> </div>\n\n<% end %>\n"
  },
  {
    "path": "app/views/issues/_edit.html.erb",
    "content": "<% labelled_tabular_form_for :issue, @issue,\n                             :url => {:action => 'edit', :id => @issue},\n                             :html => {:id => 'issue-form',\n                                       :class => nil,\n                                       :multipart => true} do |f| %>\n    <%= error_messages_for 'issue' %>\n    <%= error_messages_for 'time_entry' %>\n    <div class=\"gt-content-box\">\n    <% if @edit_allowed %>\n        <fieldset class=\"tabular\">\n        <%= render :partial => 'form', :locals => {:f => f} %>\n        </fieldset>\n    <% end %>\n    </div>\n\n    <%= f.hidden_field :lock_version %>\n  <div class=\"gt-table-buttons\">\n        <%= submit_tag l(:button_submit), :disable_with => l(:button_working) %>\n     </div>\n     <%= textile_editor_initialize(:framework => :jquery) %>\n<% end %>\n\n<div id=\"preview\" class=\"wiki\"></div>\n"
  },
  {
    "path": "app/views/issues/_form.html.erb",
    "content": "<div id=\"issue_descr_fields\">\n<p>\n<% if @project.credits_enabled? %>\n<%= f.select :tracker_id, Tracker.all.collect {|t| [t.name, t.id]}, :required => true %>\n<% else %>\n<%= f.select :tracker_id, Tracker.no_credits.collect {|t| [t.name, t.id]}, :required => true %>\n<% end %>\n\n</p>\n<%= observe_field :issue_tracker_id, :url => { :action => :update_form, :project_id => @project, :id => @issue },\n                                     :update => :attributes,\n                                     :with => \"$('#issue-form').serialize()\" %>\n\n<p><%= f.text_field :subject, :size => 80, :required => true %></p>\n<p><%= f.textile_editor :description,\n                   :cols => 60,\n                   :rows => (@issue.description.blank? ? 10 : [[10, @issue.description.length / 50].max, 100].min),\n                   :accesskey => accesskey(:edit),\n                   :id => \"issue_description\",\n                   :class => 'wiki-edit autocomplete-mentions' %></p>\n</div>\n\n<script type=\"text/javascript\">\nprojectId = <%= @project.id %>;\n</script>\n"
  },
  {
    "path": "app/views/issues/_form_add_team_member.html.erb",
    "content": "&nbsp;\n<%= select :issue_vote, :user_id, collection_for_project_members_select %>\n&nbsp;\n<%= submit_tag l(:button_add), :disable_with => l(:button_working) %>\n<%= toggle_link l(:button_cancel), 'new-team-member-form'%>\n</p>\n"
  },
  {
    "path": "app/views/issues/_form_update.html.erb",
    "content": "<div class=\"attributes\">\n<div class=\"splitcontentleft\">\n\n</div>\n\n</div>\n"
  },
  {
    "path": "app/views/issues/_history.html.erb",
    "content": "<% for journal in journals %>\n<div class=\"comment\" id=\"change-<%= journal.id %>\">\n    <div class=\"comment-body\">\n        <div class=\"comment-body-wrapper\">\n            <div class=\"comment-accessory-shadow\"></div>\n            <div class=\"comment-accessory\"></div>\n            <ul>\n            <% for detail in journal.details %>\n               <li><%= show_detail(detail) %></li>\n            <% end %>\n            </ul>\n            <%= render_notes(journal,journal == journals.last && User.current.id == journal.user_id) unless journal.notes.blank? %>\n        </div>\n    </div>\n    <div class=\"comment-meta\">\n        <div class=\"comment-meta-wrapper\">\n            <div class=\"comment-author-image\"><%= avatar(journal.user, :size => \"28\", :class => \"none\") %></div>\n            <div class=\"comment-meta-meta\">\n                <div class=\"comment-author\"><%= link_to_user journal.user %></div>\n                <div class=\"comment-date\"><%= time_tag(journal.updated_at) %> ago</div>\n            </div>\n        </div>\n    </div>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/issues/_joined_by.html.erb",
    "content": "  <div class=\"issue-meta-box first-box\" id=\"joined_by_partial\">\n      <h3 class=\"issue-meta-title\"><%=l(:field_joined_by)%></h3>\n      <span class=\"issue-meta-content\">\n        <span id=\"joined_by\">\n          <% @issue.team_votes.each do |issue_vote| %>\n          <% next if issue_vote.user_id == @issue.assigned_to_id  %>\n            <%= avatar(issue_vote.user, :size => \"18\") %>&nbsp; &nbsp;<%= link_to_user_from_id(issue_vote.user_id) %>&nbsp;&nbsp;\n            <%= link_to_remote \"remove\", :url => {:controller => 'issues', :action => 'remove_team_member', :id => @issue.id, :user_id => issue_vote.user_id} if User.current.id == @issue.assigned_to_id  %>\n            <br>\n          <% end %>\n        </span>\n        <% if User.current.id == @issue.assigned_to_id %>\n          <span id=\"add_member_link\">\n          <%= toggle_link l(:button_add_team_member), 'new-team-member-form', {:second_toggle => 'add_member_link'}%>\n          </span>\n\n          <% remote_form_for(:issue, @issue,\n                           :url => {:controller => 'issues', :action => 'add_team_member', :id => @issue.id},\n                           :method => :post,\n                           :html => {:id => 'new-team-member-form', :style => 'display: none;'}) do |f| %>\n\n           &nbsp;\n           <%= select :issue_vote, :user_id, collection_for_project_members_select %>\n           &nbsp;\n             <%= submit_tag l(:button_add), :disable_with => l(:button_working) %>\n             <p class=\"gt-cancel\">\n           <%= toggle_link l(:button_cancel), 'new-team-member-form', {:second_toggle => 'add_member_link'}%>\n           </p>\n           </p>\n          <% end %>\n        <% end %>\n\n      </span>\n  </div>\n"
  },
  {
    "path": "app/views/issues/_list.html.erb",
    "content": "<% form_tag({}) do -%>\n<%= hidden_field_tag 'back_url', url_for(params) %>\n<div class=\"gt-content-box\">\n<table class=\"gt-table\">\n    <thead><tr>\n    <%= sort_header_tag('id', :caption => '#', :default_order => 'desc') %>\n        <% query.columns.each do |column| %>\n          <%= column_header(column) %>\n        <% end %>\n  </tr></thead>\n  <% previous_group = false %>\n  <tbody>\n  <% issues.each do |issue| -%>\n  <% if @query.grouped? && (group = @query.group_by_column.value(issue)) != previous_group %>\n    <% reset_cycle %>\n    <tr class=\"group open\">\n      <td colspan=\"<%= query.columns.size + 2 %>\">\n        <span class=\"expander\" onclick=\"toggleRowGroup(this); return false;\">&nbsp;</span>\n        <%= group.blank? ? 'None' : column_content(@query.group_by_column, issue) %> <span class=\"count\">(<%= @issue_count_by_group[group] %>)</span>\n      </td>\n    </tr>\n    <% previous_group = group %>\n  <% end %>\n  <tr id=\"issue-<%= issue.id %>\" class=\"hascontextmenu <%= cycle('odd', 'even') %> <%= issue.css_classes %>\">\n    <td><%= link_to issue.id, {:controller => 'issues', :action => 'show', :id => issue}, :class => \"fancyframe\" %></td>\n        <% query.columns.each do |column| %><%= content_tag 'td', column_content(column, issue), :class => column.name %><% end %>\n  </tr>\n  <% end -%>\n  </tbody>\n</table>\n</div>\n<% end -%>\n"
  },
  {
    "path": "app/views/issues/_list_simple.html.erb",
    "content": "<% if issues && issues.any? %>\n<% form_tag({}) do %>\n  <table class=\"gt-table issues\">\n    <thead><tr>\n    <th>#</th>\n    <th><%=l(:field_project)%></th>\n    <th><%=l(:field_tracker)%></th>\n    <th><%=l(:field_subject)%></th>\n    </tr></thead>\n    <tbody>\n    <% for issue in issues %>\n    <tr id=\"issue-<%= issue.id %>\" class=\"hascontextmenu <%= cycle('odd', 'even') %> <%= issue.css_classes %>\">\n      <td class=\"id\">\n        <%= check_box_tag(\"ids[]\", issue.id, false, :style => 'display:none;') %>\n        <%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %>\n      </td>\n      <td class=\"project\"><%= link_to(h(issue.project), :controller => 'projects', :action => 'show', :id => issue.project) %></td>\n      <td class=\"tracker\"><%=h issue.tracker %></td>\n      <td class=\"subject\">\n        <%= link_to h(truncate(issue.subject, :length => 60)),  {:controller => 'issues', :action => 'show', :id => issue}, :class => \"fancyframe\" %> (<%=h issue.status %>)\n      </td>\n    </tr>\n    <% end %>\n    </tbody>\n  </table>\n<% end %>\n<% else %>\n  <p class=\"nodata\"><%= l(:label_no_data) %></p>\n<% end %>\n"
  },
  {
    "path": "app/views/issues/_list_very_simple.html.erb",
    "content": "<div class=\"gt-content-box\">\n<% if issues && issues.any? %>\n<% form_tag({}) do %>\n  <table class=\"gt-table issues\">\n    <tbody>\n    <% for issue in issues %>\n    <tr id=\"issue-<%= issue.id %>\" class=\"hascontextmenu <%= cycle('odd', 'even') %> <%= issue.css_classes %>\">\n      <td class=\"id\">\n      <% unless defined? no_workstream %>\n        <%= link_to(h(issue.project), :controller => 'projects', :action => 'show', :id => issue.project) %>\n      <% end %>\n      </td>\n      <td class=\"icon icon-<%= issue.tracker.to_s.downcase %> id\">\n        <%= link_to \"#{issue.id} - \" + h(truncate(issue.subject, :length => 120)) ,  {:controller => 'issues', :action => 'show', :id => issue}, :class => \"fancyframe\" %>\n      </td>\n    </tr>\n    <% end %>\n    </tbody>\n  </table>\n<% end %>\n<% else %>\n  <p class=\"nodata\"><%= l(:label_no_data) %></p>\n<% end %>\n</div>\n"
  },
  {
    "path": "app/views/issues/_relations.html.erb",
    "content": "<p><strong><%=l(:label_related_issues)%></strong>&nbsp;&nbsp;\n<% if authorize_for('issue_relations', 'new') %>\n    <%= toggle_link l(:button_add), 'new-relation-form'%>\n<% end %>\n</p>\n\n<% if @issue.relations.any? %>\n<table style=\"width:100%\">\n<% @issue.relations.select {|r| r.other_issue(@issue).visible? }.each do |relation| %>\n<tr>\n<td><%= l(relation.label_for(@issue)) %> <%= \"(#{l('datetime.distance_in_words.x_days', :count => relation.delay)})\" if relation.delay && relation.delay != 0 %>\n    <%= h(relation.other_issue(@issue).project) + ' - ' if Setting.cross_project_issue_relations? %>\n    <%= link_to_issue relation.other_issue(@issue) %>\n</td>\n<td><%= relation.other_issue(@issue).status.name %></td>\n<td><%= format_date(relation.other_issue(@issue).start_date) %></td>\n<td><%= format_date(relation.other_issue(@issue).due_date) %></td>\n<td><%= link_to_remote(image_tag('delete.png'), { :url => {:controller => 'issue_relations', :action => 'destroy', :issue_id => @issue, :id => relation},\n                                                  :method => :post\n                                                }, :title => l(:label_relation_delete)) if authorize_for('issue_relations', 'destroy') %></td>\n</tr>\n<% end %>\n</table>\n<% end %>\n\n<% remote_form_for(:relation, @relation,\n                 :url => {:controller => 'issue_relations', :action => 'new', :issue_id => @issue},\n                 :method => :post,\n                 :html => {:id => 'new-relation-form', :style => (@relation ? '' : 'display: none;')}) do |f| %>\n<%= render :partial => 'issue_relations/form', :locals => {:f => f}%>\n<% end %>\n"
  },
  {
    "path": "app/views/issues/_sidebar.html.erb",
    "content": "<h3><%= l(:label_issue_plural) %></h3>\n<%= link_to l(:label_issue_view_all), { :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 } %><br />\n<% if @project %>\n<%= link_to l(:field_summary), :controller => 'reports', :action => 'issue_report', :id => @project %><br />\n<% end %>\n\n<% if User.current.allowed_to?(:view_calendar, @project, :global => true) %>\n  <%= link_to(l(:label_calendar), :controller => 'issues', :action => 'calendar', :project_id => @project) %><br />\n<% end %>\n<% if User.current.allowed_to?(:view_gantt, @project, :global => true) %>\n  <%= link_to(l(:label_gantt), :controller => 'issues', :action => 'gantt', :project_id => @project) %><br />\n<% end %>\n\n<% unless sidebar_queries.empty? -%>\n<h3><%= l(:label_query_plural) %></h3>\n\n<% sidebar_queries.each do |query| -%>\n<%= link_to(h(query.name), :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query) %><br />\n<% end -%>\n<% end -%>\n"
  },
  {
    "path": "app/views/issues/calendar.html.erb",
    "content": "<h2><%= l(:label_calendar) %></h2>\n\n<% form_tag({}, :id => 'query_form') do %>\n<fieldset id=\"filters\" class=\"collapsible\">\n  <legend onclick=\"toggleFieldset(this);\"><%= l(:label_filter_plural) %></legend>\n  <div>\n    <%= render :partial => 'queries/filters', :locals => {:query => @query} %>\n  </div>\n</fieldset>\n\n<p style=\"float:right;\">\n<%= link_to_remote ('&#171; ' + (@month==1 ? \"#{month_name(12)} #{@year-1}\" : \"#{month_name(@month-1)}\")),\n                        {:update => \"content\", :url => { :year => (@month==1 ? @year-1 : @year), :month =>(@month==1 ? 12 : @month-1) }},\n                        {:href => url_for(:action => 'calendar', :year => (@month==1 ? @year-1 : @year), :month =>(@month==1 ? 12 : @month-1))}\n                        %> |\n<%= link_to_remote ((@month==12 ? \"#{month_name(1)} #{@year+1}\" : \"#{month_name(@month+1)}\") + ' &#187;'),\n                        {:update => \"content\", :url => { :year => (@month==12 ? @year+1 : @year), :month =>(@month==12 ? 1 : @month+1) }},\n                        {:href => url_for(:action => 'calendar', :year => (@month==12 ? @year+1 : @year), :month =>(@month==12 ? 1 : @month+1))}\n                        %>\n</p>\n\n<p class=\"buttons\">\n<%= select_month(@month, :prefix => \"month\", :discard_type => true) %>\n<%= select_year(@year, :prefix => \"year\", :discard_type => true) %>\n\n<%= link_to_remote l(:button_apply),\n                   { :url => { :set_filter => (@query.new_record? ? 1 : nil) },\n                     :update => \"content\",\n                     :with => \"Form.serialize('query_form')\"\n                   }, :class => 'icon icon-checked' %>\n\n<%= link_to_remote l(:button_clear),\n                   { :url => { :set_filter => (@query.new_record? ? 1 : nil) },\n                     :update => \"content\",\n                   }, :class => 'icon icon-reload' if @query.new_record? %>\n</p>\n<% end %>\n\n<%= error_messages_for 'query' %>\n<% if @query.valid? %>\n<%= render :partial => 'common/calendar', :locals => {:calendar => @calendar} %>\n\n<%= image_tag 'arrow_from.png' %>&nbsp;&nbsp;<%= l(:text_tip_task_begin_day) %><br />\n<%= image_tag 'arrow_to.png' %>&nbsp;&nbsp;<%= l(:text_tip_task_end_day) %><br />\n<%= image_tag 'arrow_bw.png' %>&nbsp;&nbsp;<%= l(:text_tip_task_begin_end_day) %><br />\n<% end %>\n\n<% content_for :sidebar do %>\n    <%= render :partial => 'issues/sidebar' %>\n<% end %>\n\n<% html_title(l(:label_calendar)) -%>\n"
  },
  {
    "path": "app/views/issues/changes.rxml",
    "content": "xml.instruct!\nxml.feed \"xmlns\" => \"http://www.w3.org/2005/Atom\" do\n  xml.title   @title\n  xml.link    \"rel\" => \"self\", \"href\" => url_for(:format => 'atom', :key => User.current.rss_key, :only_path => false)\n  xml.link    \"rel\" => \"alternate\", \"href\" => home_url(:only_path => false)\n  xml.id      url_for(:controller => 'welcome', :only_path => false)\n  xml.updated((@journals.first ? @journals.first.event_datetime : Time.now).xmlschema)\n  xml.author  { xml.name \"#{Setting.app_title}\" }\n  @journals.each do |change|\n    issue = change.issue\n    xml.entry do\n      xml.title   \"#{issue.project.name} - #{issue.tracker.name} ##{issue.id}: #{issue.subject}\"\n      xml.link    \"rel\" => \"alternate\", \"href\" => url_for(:controller => 'issues' , :action => 'show', :id => issue, :only_path => false)\n      xml.id      url_for(:controller => 'issues' , :action => 'show', :id => issue, :journal_id => change, :only_path => false)\n      xml.updated change.created_at.xmlschema\n      xml.author do\n        xml.name change.user.name\n        xml.email(change.user.mail) if change.user.is_a?(User) && !change.user.mail.blank? && !change.user.pref.hide_mail\n      end\n      xml.content \"type\" => \"html\" do\n        xml.text! '<ul>'\n        change.details.each do |detail|\n          xml.text! '<li>' + show_detail(detail, false) + '</li>'\n        end\n        xml.text! '</ul>'\n        xml.text! textilizable(change, :notes, :only_path => false) unless change.notes.blank?\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/views/issues/context_menu.html.erb",
    "content": "<ul>\n\n<% if !@issue.nil? -%>\n  <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue},\n          :class => 'icon-edit', :disabled => !@can[:edit] %></li>\n  <li class=\"folder\">\n    <a href=\"#\" class=\"submenu\" onclick=\"return false;\"><%= l(:field_status) %></a>\n    <ul>\n    <% @statuses.each do |s| -%>\n        <li><%= context_menu_link s.name, {:controller => 'issues', :action => 'edit', :id => @issue, :issue => {:status_id => s}, :back_to => @back}, :method => :post,\n                                  :selected => (s == @issue.status), :disabled => !(@can[:update] && @allowed_statuses.include?(s)) %></li>\n    <% end -%>\n    </ul>\n  </li>\n<% else %>\n  <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)},\n          :class => 'icon-edit', :disabled => !@can[:edit] %></li>\n<% end %>\n\n  <% unless @trackers.nil? %>\n  <li class=\"folder\">\n    <a href=\"#\" class=\"submenu\"><%= l(:field_tracker) %></a>\n    <ul>\n    <% @trackers.each do |t| -%>\n        <li><%= context_menu_link t.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), 'tracker_id' => t, :back_to => @back}, :method => :post,\n                                  :selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %></li>\n    <% end -%>\n    </ul>\n  </li>\n  <% end %>\n  <% unless @assignables.nil? || @assignables.empty? -%>\n  <li class=\"folder\">\n    <a href=\"#\" class=\"submenu\"><%= l(:field_assigned_to) %></a>\n    <ul>\n    <% @assignables.each do |u| -%>\n        <li><%= context_menu_link u.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), 'assigned_to_id' => u, :back_to => @back}, :method => :post,\n                                  :selected => (@issue && u == @issue.assigned_to), :disabled => !@can[:update] %></li>\n    <% end -%>\n        <li><%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), 'assigned_to_id' => 'none', :back_to => @back}, :method => :post,\n                                  :selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %></li>\n    </ul>\n  </li>\n  <% end %>\n  <% unless @project.nil? || @project.issue_categories.empty? -%>\n  <% end -%>\n    </ul>\n  </li>\n  <% end %>\n<% if !@issue.nil? %>\n  <% if @can[:log_time] -%>\n  <li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue},\n          :class => 'icon-time-add' %></li>\n  <% end %>\n  <% if User.current.logged? %>\n  <li><%= watcher_link(@issue, User.current) %></li>\n  <% end %>\n<% end %>\n\n<% if @issue.present? %>\n  <li><%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},\n          :class => 'icon-duplicate', :disabled => !@can[:copy] %></li>\n<% end %>\n  <li><%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'move', :ids => @issues.collect(&:id), :copy_options => {:copy => 't'}},\n                          :class => 'icon-copy', :disabled => !@can[:move]  %></li>\n  <li><%= context_menu_link l(:button_move), {:controller => 'issues', :action => 'move', :ids => @issues.collect(&:id)},\n                          :class => 'icon-move', :disabled => !@can[:move]  %></li>\n  <li><%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id)},\n                            :method => :post, :confirm => l(:text_issues_destroy_confirmation), :class => 'icon-del', :disabled => !@can[:delete] %></li>\n\n</ul>\n"
  },
  {
    "path": "app/views/issues/edit.html.erb",
    "content": "<h2><%=h \"#{@issue.tracker.name} ##{@issue.id}\" %></h2>\n\n<%= render :partial => 'edit' %>\n"
  },
  {
    "path": "app/views/issues/gantt.html.erb",
    "content": "<h2><%= l(:label_gantt) %></h2>\n\n<% form_tag(params.merge(:month => nil, :year => nil, :months => nil), :id => 'query_form') do %>\n<fieldset id=\"filters\" class=\"collapsible\">\n  <legend onclick=\"toggleFieldset(this);\"><%= l(:label_filter_plural) %></legend>\n  <div>\n    <%= render :partial => 'queries/filters', :locals => {:query => @query} %>\n  </div>\n</fieldset>\n\n<p style=\"float:right;\">\n<%= if @gantt.zoom < 4\n    link_to_remote image_tag('zoom_in.png'), {:url => @gantt.params.merge(:zoom => (@gantt.zoom+1)), :update => 'content'}, {:href => url_for(@gantt.params.merge(:zoom => (@gantt.zoom+1)))}\n  else\n    image_tag 'zoom_in_g.png'\n  end %>\n<%= if @gantt.zoom > 1\n    link_to_remote image_tag('zoom_out.png'), {:url => @gantt.params.merge(:zoom => (@gantt.zoom-1)), :update => 'content'}, {:href => url_for(@gantt.params.merge(:zoom => (@gantt.zoom-1)))}\n  else\n    image_tag 'zoom_out_g.png'\n  end %>\n</p>\n\n<p class=\"buttons\">\n<%= text_field_tag 'months', @gantt.months, :size => 2 %>\n<%= l(:label_months_from) %>\n<%= select_month(@gantt.month_from, :prefix => \"month\", :discard_type => true) %>\n<%= select_year(@gantt.year_from, :prefix => \"year\", :discard_type => true) %>\n<%= hidden_field_tag 'zoom', @gantt.zoom %>\n\n<%= link_to_remote l(:button_apply),\n                   { :url => { :set_filter => (@query.new_record? ? 1 : nil) },\n                     :update => \"content\",\n                     :with => \"Form.serialize('query_form')\"\n                   }, :class => 'icon icon-checked' %>\n\n<%= link_to_remote l(:button_clear),\n                   { :url => { :set_filter => (@query.new_record? ? 1 : nil) },\n                     :update => \"content\",\n                   }, :class => 'icon icon-reload' if @query.new_record? %>\n</p>\n<% end %>\n\n<%= error_messages_for 'query' %>\n<% if @query.valid? %>\n<% zoom = 1\n@gantt.zoom.times { zoom = zoom * 2 }\n\nsubject_width = 330\nheader_heigth = 18\n\nheaders_height = header_heigth\nshow_weeks = false\nshow_days = false\n\nif @gantt.zoom >1\n    show_weeks = true\n    headers_height = 2*header_heigth\n    if @gantt.zoom > 2\n        show_days = true\n        headers_height = 3*header_heigth\n    end\nend\n\ng_width = (@gantt.date_to - @gantt.date_from + 1)*zoom\ng_height = [(20 * @gantt.events.length + 6)+150, 206].max\nt_height = g_height + headers_height\n%>\n\n<table width=\"100%\" style=\"border:0; border-collapse: collapse;\">\n<tr>\n<td style=\"width:<%= subject_width %>px; padding:0px;\">\n\n<div style=\"position:relative;height:<%= t_height + 24 %>px;width:<%= subject_width + 1 %>px;\">\n<div style=\"right:-2px;width:<%= subject_width %>px;height:<%= headers_height %>px;background: #eee;\" class=\"gantt_hdr\"></div>\n<div style=\"right:-2px;width:<%= subject_width %>px;height:<%= t_height %>px;border-left: 1px solid #c0c0c0;overflow:hidden;\" class=\"gantt_hdr\"></div>\n<%\n#\n# Tasks subjects\n#\ntop = headers_height + 8\n@gantt.events.each do |i| %>\n    <div style=\"position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;left:4px;overflow:hidden;\"><small>\n    <% if i.is_a? Issue %>\n        <%= h(\"#{i.project} -\") unless @project && @project == i.project %>\n        <%= link_to_issue i %>\n    <% else %>\n    <span class=\"icon icon-package\">\n          <%= h(\"#{i.project} -\") unless @project && @project == i.project %>\n    </span>\n    <% end %>\n    </small></div>\n    <% top = top + 20\nend %>\n</div>\n</td>\n<td>\n\n<div style=\"position:relative;height:<%= t_height + 24 %>px;overflow:auto;\">\n<div style=\"width:<%= g_width-1 %>px;height:<%= headers_height %>px;background: #eee;\" class=\"gantt_hdr\">&nbsp;</div>\n<%\n#\n# Months headers\n#\nmonth_f = @gantt.date_from\nleft = 0\nheight = (show_weeks ? header_heigth : header_heigth + g_height)\n@gantt.months.times do\n  width = ((month_f >> 1) - month_f) * zoom - 1\n  %>\n  <div style=\"left:<%= left %>px;width:<%= width %>px;height:<%= height %>px;\" class=\"gantt_hdr\">\n  <%= link_to \"#{month_f.year}-#{month_f.month}\", @gantt.params.merge(:year => month_f.year, :month => month_f.month), :title => \"#{month_name(month_f.month)} #{month_f.year}\"%>\n  </div>\n  <%\n  left = left + width + 1\n  month_f = month_f >> 1\nend %>\n\n<%\n#\n# Weeks headers\n#\nif show_weeks\n  left = 0\n  height = (show_days ? header_heigth-1 : header_heigth-1 + g_height)\n  if @gantt.date_from.cwday == 1\n      # @date_from is monday\n        week_f = @gantt.date_from\n  else\n      # find next monday after @date_from\n    week_f = @gantt.date_from + (7 - @gantt.date_from.cwday + 1)\n    width = (7 - @gantt.date_from.cwday + 1) * zoom-1\n    %>\n    <div style=\"left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;\" class=\"gantt_hdr\">&nbsp;</div>\n    <%\n    left = left + width+1\n  end %>\n  <%\n  while week_f <= @gantt.date_to\n    width = (week_f + 6 <= @gantt.date_to) ? 7 * zoom -1 : (@gantt.date_to - week_f + 1) * zoom-1\n    %>\n    <div style=\"left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;\" class=\"gantt_hdr\">\n    <small><%= week_f.cweek if width >= 16 %></small>\n    </div>\n    <%\n    left = left + width+1\n    week_f = week_f+7\n  end\nend %>\n\n<%\n#\n# Days headers\n#\nif show_days\n  left = 0\n  height = g_height + header_heigth - 1\n  wday = @gantt.date_from.cwday\n  (@gantt.date_to - @gantt.date_from + 1).to_i.times do\n  width =  zoom - 1\n  %>\n  <div style=\"left:<%= left %>px;top:37px;width:<%= width %>px;height:<%= height %>px;font-size:0.7em;<%= \"background:#f1f1f1;\" if wday > 5 %>\" class=\"gantt_hdr\">\n  <%= day_name(wday).first %>\n  </div>\n  <%\n  left = left + width+1\n  wday = wday + 1\n  wday = 1 if wday > 7\n  end\nend %>\n\n<%\n#\n# Tasks\n#\ntop = headers_height + 10\n@gantt.events.each do |i|\n  if i.is_a? Issue\n  i_start_date = (i.start_date >= @gantt.date_from ? i.start_date : @gantt.date_from )\n  i_end_date = (i.due_before <= @gantt.date_to ? i.due_before : @gantt.date_to )\n\n  i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor\n  i_done_date = (i_done_date <= @gantt.date_from ? @gantt.date_from : i_done_date )\n  i_done_date = (i_done_date >= @gantt.date_to ? @gantt.date_to : i_done_date )\n\n  i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today\n\n  i_left = ((i_start_date - @gantt.date_from)*zoom).floor\n  i_width = ((i_end_date - i_start_date + 1)*zoom).floor - 2                  # total width of the issue (- 2 for left and right borders)\n  d_width = ((i_done_date - i_start_date)*zoom).floor - 2                     # done width\n  l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width\n  %>\n  <div style=\"top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;\" class=\"task task_todo\">&nbsp;</div>\n  <% if l_width > 0 %>\n      <div style=\"top:<%= top %>px;left:<%= i_left %>px;width:<%= l_width %>px;\" class=\"task task_late\">&nbsp;</div>\n  <% end %>\n  <% if d_width > 0 %>\n      <div style=\"top:<%= top %>px;left:<%= i_left %>px;width:<%= d_width %>px;\" class=\"task task_done\">&nbsp;</div>\n  <% end %>\n  <div style=\"top:<%= top %>px;left:<%= i_left + i_width + 5 %>px;background:#fff;\" class=\"task\">\n  <%= i.status.name %>\n  <%= (i.done_ratio).to_i %>%\n  </div>\n  <div class=\"tooltip\" style=\"position: absolute;top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;height:12px;\">\n  <span class=\"tip\">\n    <%= render_issue_tooltip i %>\n  </span></div>\n<% else\n    i_left = ((i.start_date - @gantt.date_from)*zoom).floor\n    %>\n    <div style=\"top:<%= top %>px;left:<%= i_left %>px;width:15px;\" class=\"task milestone\">&nbsp;</div>\n  <div style=\"top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;\" class=\"task\">\n    <%= h(\"#{i.project} -\") unless @project && @project == i.project %>\n    <strong><%=h i %></strong>\n  </div>\n<% end %>\n  <% top = top + 20\nend %>\n\n<%\n#\n# Today red line (excluded from cache)\n#\nif Date.today >= @gantt.date_from and Date.today <= @gantt.date_to %>\n    <div style=\"position: absolute;height:<%= g_height %>px;top:<%= headers_height + 1 %>px;left:<%= ((Date.today-@gantt.date_from+1)*zoom).floor-1 %>px;width:10px;border-left: 1px dashed red;\">&nbsp;</div>\n<% end %>\n\n</div>\n</td>\n</tr>\n</table>\n\n<table width=\"100%\">\n<tr>\n<td align=\"left\"><%= link_to_remote ('&#171; ' + l(:label_previous)), {:url => @gantt.params_previous, :update => 'content', :complete => 'window.scrollTo(0,0)'}, {:href => url_for(@gantt.params_previous)} %></td>\n<td align=\"right\"><%= link_to_remote (l(:label_next) + ' &#187;'), {:url => @gantt.params_next, :update => 'content', :complete => 'window.scrollTo(0,0)'}, {:href => url_for(@gantt.params_next)} %></td>\n</tr>\n</table>\n\n<% other_formats_links do |f| %>\n  <%= f.link_to 'PDF', :url => @gantt.params %>\n  <%= f.link_to('PNG', :url => @gantt.params) if @gantt.respond_to?('to_image') %>\n<% end %>\n<% end # query.valid? %>\n\n<% content_for :sidebar do %>\n    <%= render :partial => 'issues/sidebar' %>\n<% end %>\n\n<% html_title(l(:label_gantt)) -%>\n"
  },
  {
    "path": "app/views/issues/index.html.erb",
    "content": "<div class=\"contextual\">\n<% if !@query.new_record? && @query.editable_by?(User.current) %>\n  <%= link_to l(:button_edit), {:controller => 'queries', :action => 'edit', :id => @query}, :class => 'icon icon-edit' %>\n  <%= link_to l(:button_delete), {:controller => 'queries', :action => 'destroy', :id => @query}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>\n<% end %>\n</div>\n\n<h2><%= @query.new_record? ? l(:label_issue_plural) : h(@query.name) %></h2>\n<% html_title(@query.new_record? ? l(:label_issue_plural) : @query.name) %>\n\n<% form_tag({ :controller => 'queries', :action => 'new' }, :id => 'query_form') do %>\n    <%= hidden_field_tag('project_id', @project.to_param) if @project %>\n    <div id=\"query_form_content\">\n    <fieldset id=\"filters\" class=\"collapsible collapsed hidden\">\n      <legend onclick=\"toggleFieldset(this);\"><%= l(:label_filter_plural) %></legend>\n      <div>\n        <%= render :partial => 'queries/filters', :locals => {:query => @query} %>\n      </div>\n    </fieldset>\n    <fieldset class=\"collapsible collapsed hidden\">\n      <legend onclick=\"toggleFieldset(this);\"><%= l(:label_options) %></legend>\n      <div style=\"display: none;\">\n        <table>\n          <tr>\n            <td><%= l(:field_column_names) %></td>\n            <td><%= render :partial => 'queries/columns', :locals => {:query => @query} %></td>\n          </tr>\n          <tr>\n            <td><%= l(:field_group_by) %></td>\n            <td><%= select_tag('group_by', options_for_select([[]] + @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, @query.group_by)) %></td>\n          </tr>\n        </table>\n      </div>\n    </fieldset>\n    </div>\n    <p class=\"buttons hidden\">\n\n    <%= link_to_remote l(:button_apply),\n                       { :url => { :set_filter => 1 },\n                         :before => 'selectAllOptions(\"selected_columns\");',\n                         :update => \"content\",\n                         :with => \"Form.serialize('query_form')\"\n                       }, :class => 'icon icon-checked' %>\n\n    <%= link_to_remote l(:button_clear),\n                       { :url => { :set_filter => 1, :project_id => @project },\n                         :method => :get,\n                         :update => \"content\",\n                       }, :class => 'icon icon-reload'  %>\n\n    <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %>\n    <%= link_to l(:button_save), {}, :onclick => \"selectAllOptions('selected_columns'); $('query_form').submit(); return false;\", :class => 'icon icon-save' %>\n    <% end %>\n    </p>\n<% end %>\n<%= error_messages_for 'query' %>\n<% if @query.valid? %>\n<% if @issues.empty? %>\n<div class=\"gt-content-box\">\n  <p class=\"nodata\"><%= l(:label_no_data) %></p>\n</div>\n<% else %>\n<%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %>\n<p class=\"pagination\"><%= pagination_links_full @issue_pages, @issue_count %></p>\n<% end %>\n\n<% end %>\n"
  },
  {
    "path": "app/views/issues/move.html.erb",
    "content": "<h2><%= @copy ? l(:button_copy) : l(:button_move) %></h2>\n\n\n<% form_tag({}, :id => 'move_form') do %>\n<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %>\n\n<div class=\"gt-content-box tabular\">\n  <p>\n  <% @issues.each do |issue| -%>\n    <%= link_to_issue issue %>\n  <% end -%>\n  </p>\n<p><label for=\"new_project_id\"><%=l(:field_project)%>:</label>\n<%= select_tag \"new_project_id\",\n               project_tree_options_for_select(@allowed_projects, :selected => @target_project),\n               :onchange => remote_function(:url => { :action => 'move' },\n                                            :method => :get,\n                                            :update => 'content',\n                                            :with => \"Form.serialize('move_form')\") %></p>\n\n<p><label for=\"new_tracker_id\"><%=l(:field_tracker)%>:</label>\n<%= select_tag \"new_tracker_id\", \"<option value=\\\"\\\">#{l(:label_no_change_option)}</option>\" + options_from_collection_for_select(@trackers, \"id\", \"name\") %></p>\n\n</div>\n\n<% if @copy %>\n  <%= hidden_field_tag(\"copy_options[copy]\", \"1\") %>\n  <%= submit_tag l(:button_copy), :disable_with => l(:button_working) %>\n  <%= submit_tag l(:button_copy_and_follow), :name => 'follow', :disable_with => l(:button_working) %>\n<% else %>\n  <%= submit_tag l(:button_move), :disable_with => l(:button_working) %>\n  <%= submit_tag l(:button_move_and_follow), :name => 'follow', :disable_with => l(:button_working) %>\n<% end %>\n<% end %>\n"
  },
  {
    "path": "app/views/issues/new.html.erb",
    "content": "<h2><%=l(:label_issue_new)%></h2>\n\n<% labelled_tabular_form_for :issue, @issue,\n                             :html => {:multipart => true, :id => 'issue-form'} do |f| %>\n    <%= error_messages_for 'issue' %>\n    <div class=\"gt-content-box\">\n    <%= render :partial => 'issues/form', :locals => {:f => f} %>\n    </div>\n    <div class=\"gt-table-buttons\">\n    <%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n    <%= submit_tag l(:button_create_and_continue), :name => 'continue', :disable_with => l(:button_working) %>\n    <p class=\"gt-cancel\">\n    <%= link_to_remote l(:label_preview),\n                       { :url => { :controller => 'issues', :action => 'preview', :project_id => @project },\n                         :method => 'post',\n                         :update => 'preview',\n                         :with => \"$('#issue-form').serialize()\",\n                         :complete => \"$('body').scrollTo('#preview')\"\n                       }, :accesskey => accesskey(:preview) %>\n     </p>\n    </div>\n    <%= javascript_tag \"$('#issue_subject').focus();\" %>\n<% end %>\n\n<div id=\"preview\" class=\"wiki\"></div>\n\n<% content_for :header_tags do %>\n    <%= stylesheet_link_tag 'scm' %>\n<% end %>\n"
  },
  {
    "path": "app/views/issues/show.html.erb",
    "content": "<div id=\"first-issue\" class=\"issue\">\n    <div class=\"issue-wrapper\">\n\n        <div id=\"issue-stamp\" class=\"issue-closed-placeholder stamp-{{state}}\"></div>\n        <div class=\"issue-left-border-placeholder\"></div>\n\n        <div class=\"issue-content\">\n            <div class=\"issue-content-wrapper\">\n              <span id=\"item_header\"><h3 class=\"issue-title\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<%= @issue.subject %></h3>\n                </span>\n\n                <div class=\"issue-body\">\n                    <p>\n                      <%= textilizable @issue, :description, :attachments => @issue.attachments %>\n                    </p>\n                    <p>\n                      <div id=\"todo_wrapper\"></div>\n                    </p>\n\n                    <p>\n                      <strong><%=l(:label_attachment_plural)%></strong>\n                      <%= link_to_attachments_table @issue %>\n                      <table id=\"files\" class=\"attachments\"></table>\n                      <form id=\"file_upload\" action=\"<%= url_for({:controller => :attachments, :action => :create, :container_id => @issue.id, :container_type => \"Issue\"}) %>\" method=\"POST\" enctype=\"multipart/form-data\">\n                          <input type=\"file\" name=\"file\" multiple>\n                          <button>Upload</button>\n                          <a class=\"icon icon-attachment\" href=\"#\">Upload files</a>\n                      </form>\n                    </p>\n\n\n                    <% if authorize_for('issue_relations', 'new') || @issue.relations.any? %>\n                    <div id=\"relations\">\n                    <%= render :partial => 'relations' %>\n                    </div>\n                    <% end %>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"issue-meta\">\n            <div class=\"issue-meta-wrapper\">\n                <div class=\"issue-image-area\">\n                  <% if @issue.assigned_to %>\n                  <%= avatar(@issue.assigned_to, :size => \"68\", :class=>\"issue-author-image\") %>\n                  <% else %>\n                  <%= avatar(@issue.author, :size => \"68\", :class=>\"issue-author-image\") %>\n                  <% end %>\n                  <div class=\"issue-image-paperclip-placeholder\"></div>\n                </div>\n\n                <div class=\"issue-meta-box first-box\">\n                    <h3 class=\"issue-meta-title\"><%= l(:label_project) %></h3>\n                    <span class=\"issue-meta-content\"><%= link_to(@issue.project.name, {:controller => 'projects', :action => 'show', :id => @issue.project_id}) %> - #<%= @issue.id %></span>\n                </div>\n                <div class=\"issue-meta-box first-box\">\n                    <h3 class=\"issue-meta-title\"><%=l(:field_tags)%></h3>\n                    <span class=\"issue-meta-content\"><table style=\"width:100%\" id=\"issue_tags_container\"><tr><td><%= tags @issue, authorize_for('issues', 'edit') %></td></tr></table>\n                    </span>\n                </div>\n                <div class=\"issue-meta-box first-box\">\n                    <h3 class=\"issue-meta-title\"><%=l(:field_status)%></h3>\n                    <span class=\"issue-meta-content\"><span id=\"issue_status\"><%= @issue.status.name %></span></span>\n                </div>\n                <div class=\"issue-meta-box first-box\">\n                    <h3 class=\"issue-meta-title\"><%= l(:label_created_time_by, :age => time_tag(@issue.created_at)) %></h3>\n                    <span class=\"issue-meta-content\"><span id=\"author\">\n                      <table class=\"author\">\n                        <tr>\n                          <td><%= avatar(@issue.author, :size => \"28\") %> </td>\n                          <td class=\"author-name\"><%= link_to_user(@issue.author)%></td>\n                        </tr>\n                    </table>\n                    </span></span>\n                </div>\n                <div class=\"issue-meta-box first-box\">\n                    <h3 class=\"issue-meta-title\"><%=l(:field_assigned_to)%></h3>\n                    <span class=\"issue-meta-content\"><span id=\"assigned_to\">\n                      <table class=\"author\">\n                        <tr>\n                          <td><%= avatar(@issue.assigned_to, :size => \"28\") %></td>\n                          <td class=\"author-name\"><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : \"-\" %></td>\n                        </tr>\n                    </table>\n                  </span></span>\n                </div>\n                <%= render :partial => \"joined_by\"  %>\n                <div class=\"issue-meta-box last-box\">\n                    <h3 class=\"issue-meta-title\"><%=l(:field_item_url)%> <%= help_bubble :help_item_url %></h3>\n                    <span class=\"issue-meta-content\"><%= url_for(:action => 'dashboard', :controller => 'projects', :show_issue_id => @issue.id, :only_path => false, :protocol => 'http') %></span>\n                </div>\n                <div class=\"issue-meta-action-wrapper\">\n                  <%= render :partial => 'action_menu' %>\n                </div>\n            </div>\n        </div>\n\n    </div>\n</div>\n\n<% if @journals.any? %>\n<div id=\"comments\" class=\"comments\">\n<%= render :partial => 'history', :locals => { :journals => @journals } %>\n</div>\n<% else %>\n<div id=\"comments\" class=\"comments\">\n</div>\n<% end %>\n\n<div id=\"add-comment-area\" class=\"comment\">\n  <div id=\"add-comment-textarea-wrapper\" class=\"comment-body\">\n        <div><p>Comment on this item:</p></div>\n        <textarea id=\"add-comment-textarea\" class=\"comment-body-wrapper autocomplete-mentions\"></textarea>\n        <div class=\"comment-form-wrapper\">\n            <a class=\"fakebutton\" href=\"#\" onclick=\"post_comment(); return false;\">Comment</a>\n        </div>\n    </div>\n</div>\n\n<% if authorize_for('issues', 'edit') %>\n  <div id=\"update\" style=\"display:none;\">\n  <h3><%= l(:button_update) %></h3>\n  <%= render :partial => 'edit' %>\n  </div>\n<% end %>\n\n\n<% html_title \"##{@issue.id}: #{@issue.subject}\" %>\n\n<% content_for :header_tags do %>\n    <%= stylesheet_link_tag 'scm' %>\n<% end %>\n\n\n<div id='flyovers' style=\"display:none;\">\n\n  <% if !params[:update].nil? %>\n    <%= javascript_tag 'showAndScrollTo(\"update\", \"attachments_1_file\");' %>\n  <% end %>\n\n<%= render :partial => 'projects/dashboard_javascript_variables', :locals => {:project => @project} %>\n\n<script type=\"text/javascript\">\n\n  projectId = <%= @project.id %>;\n\n  $('document').ready(function(){\n    highest_pri = <%= @project.highest_pri %>\n    show_item(<%= @issue.startable? %>);\n    initialize();\n\n    $('.issue-tags').tagsInput({\n       'autocomplete_url': '/projects/<%= @issue.project.id %>/all_tags',\n       'autocomplete':{selectFirst:true,width:'100px',autoFill:true},\n       'issue_id':'<%= @issue.id %>',\n       'height':'20px',\n       'width':$('#issue_tags_container').width(),\n       'defaultText':'add a tag'\n    });\n\n    $('#file_upload').fileUploadUI({\n        uploadTable: $('#files'),\n        downloadTable: $('#files'),\n        buildUploadRow: function (files, index) {\n            return $('<tr><td>' + files[index].name + '<\\/td>' +\n                    '<td class=\"file_upload_progress\"><div><\\/div><\\/td>' +\n                    '<td class=\"file_upload_cancel\">' +\n                    '<button class=\"ui-state-default ui-corner-all\" title=\"Cancel\">' +\n                    '<span class=\"ui-icon ui-icon-cancel\">Cancel<\\/span>' +\n                    '<\\/button><\\/td><\\/tr>');\n        },\n        buildDownloadRow: function (attachment) {\n            return $('<tr><td><a class=\"icon icon-attachment\" href=\"/attachments/' + attachment.id + '/' + attachment.filename + '\">' + attachment.filename + '</a> (' + attachment.filesize + ' Bytes)<\\/td><\\/tr>');\n        }\n    });\n  });\n\n  function generate_comment(text){\n    var html = '';\n    html = html +  '      <div class=\"comment\" id=\"change-new\">';\n    html = html +  '          <div class=\"comment-body\">';\n    html = html +  '              <div class=\"comment-body-wrapper\">';\n    html = html +  '                  <div class=\"comment-accessory-shadow\"></div>';\n    html = html +  '                  <div class=\"comment-accessory\"></div>';\n    html = html +  '                    <div id=\"journal-new-notes\" class=\"wiki editable gravatar-margin\"> ';\n    html = html +  '                        <div class=\"contextual hidden\" id=\"new_comment_edit\">';\n    html = html +  '<a title=\"Edit\" class=\"icon icon-edit icon-edit-new\" id=\"new_comment_edit_link\" href=\"#\">Edit</a>';\n    html = html +  '                            </div> ';\n    html = html +                          '<p>' + h(text).replace(/\\r\\n/g,\"<br>\").replace(/\\n/g,\"<br>\") + '</p>';\n    html = html +  '                    </div> ';\n    html = html +  '              </div>';\n    html = html +  '          </div>';\n    html = html +  '          <div class=\"comment-meta\">';\n    html = html +  '              <div class=\"comment-meta-wrapper\">';\n    html = html +  '                  <div class=\"comment-author-image\"><%= avatar(User.current, :size => \"28\", :class => \"none\") %></div>';\n    html = html +  '                  <div class=\"comment-meta-meta\">';\n    html = html +  '                      <div class=\"comment-author\"><%= link_to_user User.current %></div>';\n    html = html +  '                      <div class=\"comment-date\">Just now</div>';\n    html = html +  '                  </div>';\n    html = html +  '              </div>';\n    html = html +  '          </div>';\n    html = html +  '      </div>';\n    return html;\n  }\n\n  function post_comment(){\n      var text = $(\"#add-comment-textarea\").val();\n\n      if ((text == null) || (text.length < 2)){\n        return false;\n      }\n      else\n      {\n        $(\"#comments\").append(generate_comment(text));\n        $(\"#add-comment-textarea\").val('');\n\n        var data = \"commit=Create&issue_id=<%= @issue.id %>&comment=\" + encodeURIComponent(text);\n\n        var url = url_for({ controller: 'comments',\n                                 action    : 'create'\n                                });\n\n        $.ajax({\n           type: \"POST\",\n           dataType: \"json\",\n           url: url,\n           data: data,\n           success:   function(issue){\n             $('.icon-edit').hide();\n             $('.icon-edit-new').show();\n             $('#new_comment_edit').show();\n             var new_journal_id = issue.journals[issue.journals.length-1].id\n             var onclick = \"$.ajax({type: 'GET', url: '/journals/edit/\" + new_journal_id + \"'});return false;\";\n             $(\"#journal-new-notes\").attr('id','journal-' + new_journal_id + '-notes'); //updated id\n              $('#new_comment_edit_link').attr('onclick',onclick);\n          },\n          timeout: 30000 //30 seconds\n         });\n\n        return false;\n      }\n  }\n\n  function show_item(startable){\n    timer_active = false;\n    D = [];\n    D.push(item);\n    $(\"#item_header\").html(generate_item_lightbox(0));\n    $(\"#todo_wrapper\").replaceWith(generate_todo_section_lightbox(0));\n    if (startable){\n      $(\"#item_content_buttons_start_button_0\").show();\n    }\n\n  }\n\n\n\n</script>\n"
  },
  {
    "path": "app/views/journals/_notes_form.html.erb",
    "content": "<% form_remote_tag(:url => {}, :html => { :id => \"journal-#{@journal.id}-form\" }) do %>\n    <%= text_area_tag :notes, @journal.notes, :class => 'wiki-edit',\n                                              :rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %>\n    <%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n     <span class=\"\">\n    <%= link_to l(:button_cancel), '#', :onclick => \"$('#journal-#{@journal.id}-form').remove(); \" +\n                                                    \"$('#journal-#{@journal.id}-notes').show(); return false;\" %></span>\n<% end %>\n"
  },
  {
    "path": "app/views/journals/edit.rjs",
    "content": "page.hide \"journal-#{@journal.id}-notes\"\npage.insert_html :after, \"journal-#{@journal.id}-notes\",\n                 :partial => 'notes_form'\n"
  },
  {
    "path": "app/views/journals/update.rjs",
    "content": "if @journal.frozen?\n  # journal was destroyed\n  page.remove \"change-#{@journal.id}\"\nelse\n  page.replace \"journal-#{@journal.id}-notes\", render_notes(@journal, true, :reply_links => authorize_for('issues', 'edit'))\n  page.show \"journal-#{@journal.id}-notes\"\n  page.remove \"journal-#{@journal.id}-form\"\nend\n"
  },
  {
    "path": "app/views/layouts/_account_menu.html.erb",
    "content": "<% if User.current.logged? %>\n<%= render :partial => \"notifications/unresponded\" %>\n  <%= link_to_user(User.current, :format => :username) %>\n  <span class=\"gt-util-separator\">|</span>\n  <%= link_to \"account\", {:controller => :my, :action => :account} %>\n  <span class=\"gt-util-separator\">|</span>\n  <%= link_to \"sign out\", :signout %>\n<% else %>\n  <%= link_to \"home\", :home %>\n  <span class=\"gt-util-separator\">|</span>\n  <%= link_to :login, :signin %>\n  <span class=\"gt-util-separator\">|</span>\n  <%= link_to \"sign up\", {:controller => :account, :action => :register} %>\n<% end %>\n<span class=\"gt-util-separator\">|</span>\n<a href=\"http://help.bettermeans.com\" target=\"blank\">help</a>\n"
  },
  {
    "path": "app/views/layouts/activescaffold.html.erb",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n      \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n <meta http-equiv=\"content-type\" content=\"text/html;charset=UTF-8\" />\n <title>Generic ActiveScaffold Layout</title>\n <%= javascript_include_tag :defaults %>\n</head>\n<body>\n  <script type=\"text/javascript\">\n\n    var _gaq = _gaq || [];\n    _gaq.push(['_setAccount', 'UA-1630609-6']);\n    _gaq.push(['_trackPageview']);\n\n    (function() {\n      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n    })();\n\n  </script>\n<%= yield  %>\n\n</body>\n</html>\n"
  },
  {
    "path": "app/views/layouts/admin.html.erb",
    "content": "<% unless controller_name == 'admin' && action_name == 'index' ||  controller_name == 'admin' && action_name == 'user_stats' %>\n  <% content_for :sidebar do %>\n    <h3><%=l(:label_administration)%></h3>\n    <%= render :partial => 'admin/menu' %>\n  <% end %>\n<% end %>\n\n<%= render :file => \"layouts/gooey\" %>\n"
  },
  {
    "path": "app/views/layouts/base.html.erb",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<head>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n<title><%=h html_title %></title>\n<meta name=\"description\" content=\"<%= Redmine::Info.app_name %>\" />\n<meta name=\"keywords\" content=\"issue,bug,tracker\" />\n<link rel=\"shortcut icon\" href=\"/images/favicon.ico\"  mce_href=\"/images/favicon.ico\" />\n\n\n<%= stylesheet_link_tag 'application', :media => 'all' %>\n<%= stylesheet_link_tag 'jquery.fancybox-1.3.4' %>\n<%= stylesheet_link_tag 'jquery-ui-1.8.8.custom' %>\n\n<link href=\"/stylesheets/bubbletip.css\" rel=\"stylesheet\" type=\"text/css\" />\n<!--[if IE]>\n<link href=\"/stylesheets/bubbletip-IE.css\" rel=\"stylesheet\" type=\"text/css\" />\n<![endif]-->\n\n\n<%= javascript_include_tag :defaults %>\n<%= javascript_include_tag  'jquery.jgrowl_minimized.js' %>\n<%= javascript_include_tag  'jquery.scrollTo-min' %>\n<%= javascript_include_tag  'jquery.fancybox-1.3.4.pack' %>\n<%= javascript_include_tag  'jquery.sparkline.min' %>\n<%= javascript_include_tag  'store' %>\n<!--[if IE]>\n    <style type=\"text/css\">\n      * html body{ width: expression( document.documentElement.clientWidth < 900 ? '900px' : '100%' ); }\n      body {behavior: url(<%= stylesheet_path \"csshover.htc\" %>);}\n    </style>\n<![endif]-->\n<%= yield :header_tags -%>\n</head>\n<body>\n  <script type=\"text/javascript\">\n\n    var _gaq = _gaq || [];\n    _gaq.push(['_setAccount', 'UA-1630609-6']);\n    _gaq.push(['_trackPageview']);\n\n    (function() {\n      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n    })();\n\n  </script>\n<%= javascript_tag \"var AUTH_TOKEN = #{form_authenticity_token.inspect};\" if protect_against_forgery? %>\n<%= javascript_tag \"$(document).ready(function() {initialize();});\"%>\n\n<div id=\"wrapper\">\n<div id=\"top-menu\">\n    <div id=\"account\">\n        <%= render_menu :account_menu -%>\n    </div>\n    <%= content_tag('div', \"#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}\", :id => 'loggedas') if User.current.logged? %>\n    <%= render_menu :top_menu -%>\n    <%= render :partial => \"notifications/unresponded\" %>\n</div>\n\n<div id=\"header\">\n    <div id=\"quick-search\">\n        <% form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %>\n        <%= hidden_field_tag(controller.default_search_scope, 1, :id => nil) if controller.default_search_scope %>\n        <%= link_to \"#{l(:label_search)}:\", {:controller => 'search', :action => 'index', :id => @project}, :id=> \"search-label\", :accesskey => accesskey(:search) %>\n        <%= text_field_tag 'q', @question, :size => 20, :class => 'small', :accesskey => accesskey(:quick_search) %>\n        <%= render_project_jump_box %>\n        <% end %>\n    </div>\n\n    <h1><%= page_header_title %></h1>\n\n    <div id=\"main-menu\">\n        <%= render_main_menu(@project) %>\n    </div>\n</div>\n\n<%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? '' : 'nosidebar')}, true) %>\n\n<% if (has_content?(:sidebar)) %>\n    <div id=\"sidebar\">\n        <%= yield :sidebar %>\n    </div>\n<%   end   %>\n\n    <div id=\"content\">\n        <%= render_flash_messages %>\n        <%= yield %>\n        <div style=\"clear:both;\"></div>\n    </div>\n</div>\n\n<div id=\"ajax-indicator\" style=\"display:none;\"><span><%= l(:label_loading) %></span></div>\n\n<div id=\"center\" style=\"align:center\" align=\"center\">\n<div id=\"footer\">\n    Powered by <a href=\"http://BetterMeans.com\" target=\"new\">BetterMeans.com</a> <%= Date.today.year %>  <a href=\"http://creativecommons.org/licenses/by-sa/3.0/\" target=\"new\">[cc] CreativeCommons Attribution-Share Alike</a>\n</div>\n</div>\n\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "app/views/layouts/blank.html.erb",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<head>\n\n<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n<title><%=h html_title %></title>\n<meta name=\"description\" content=\"<%= Redmine::Info.app_name %>\" />\n<meta name=\"keywords\" content=\"issue,bug,tracker\" />\n<link rel=\"shortcut icon\" href=\"/images/favicon.ico\"  mce_href=\"/images/favicon.ico\" />\n\n\n<%= stylesheet_link_tag 'reset-fonts' %>\n<%= stylesheet_link_tag 'jquery.fancybox-1.3.4' %>\n<%= stylesheet_link_tag 'jquery-ui-1.8.8.custom' %>\n<%= stylesheet_link_tag 'gt-styles' %>\n\n\n<link href=\"/stylesheets/bubbletip.css\" rel=\"stylesheet\" type=\"text/css\" />\n<!--[if IE]>\n<link href=\"/stylesheets/bubbletip-IE.css\" rel=\"stylesheet\" type=\"text/css\" />\n<![endif]-->\n\n\n<%= javascript_include_tag :defaults %>\n<%= javascript_include_tag  'jquery.jgrowl_minimized.js' %>\n<%= javascript_include_tag  'jquery.scrollTo-min' %>\n<%= javascript_include_tag  'jquery.fancybox-1.3.4.pack' %>\n<%= javascript_include_tag  'jquery.sparkline.min' %>\n<%= javascript_include_tag  'store' %>\n<!--[if IE]>\n    <style type=\"text/css\">\n      * html body{ width: expression( document.documentElement.clientWidth < 900 ? '900px' : '100%' ); }\n      body {behavior: url(<%= stylesheet_path \"csshover.htc\" %>);}\n    </style>\n<![endif]-->\n<%= yield :header_tags -%>\n</head>\n<body>\n  <!--[if IE]>\n  <div style='border: 1px solid #F7941D; background: #FEEFDA; text-align: center; clear: both; height: 75px; position: relative;'>    <div style='position: absolute; right: 3px; top: 3px; font-family: courier new; font-weight: bold;'><a href='#' onclick='javascript:this.parentNode.parentNode.style.display=\"none\"; return false;'><img src='/images/static/ie6nomore-cornerx.jpg' style='border: none;' alt='Close this notice'/></a></div>    <div style='width: 640px; margin: 0 auto; text-align: left; padding: 0; overflow: hidden; color: black;'>      <div style='width: 75px; float: left;'><img src='/images/static/ie6nomore-warning.jpg' alt='Warning!'/></div>      <div style='width: 275px; float: left; font-family: Arial, sans-serif;'>        <div style='font-size: 14px; font-weight: bold; margin-top: 12px;'>You are using an unsupported browser</div>        <div style='font-size: 12px; margin-top: 6px; line-height: 12px;'>For a better experience using bettermeans, please upgrade to a modern web browser.</div>      </div>      <div style='width: 75px; float: left;'><a href='http://www.firefox.com' target='_blank'><img src='/images/static/ie6nomore-firefox.jpg' style='border: none;' alt='Get Firefox 3.5'/></a></div>            <div style='width: 73px; float: left;'><a href='http://www.apple.com/safari/download/' target='_blank'><img src='/images/static/ie6nomore-safari.jpg' style='border: none;' alt='Get Safari 4'/></a></div>      <div style='float: left;'><a href='http://www.google.com/chrome' target='_blank'><img src='/images/static/ie6nomore-chrome.jpg' style='border: none;' alt='Get Google Chrome'/></a></div>    </div>  </div>\n  <![endif]-->\n\n  <script type=\"text/javascript\">\n\n    var _gaq = _gaq || [];\n    _gaq.push(['_setAccount', 'UA-1630609-6']);\n    _gaq.push(['_trackPageview']);\n\n    (function() {\n      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n    })();\n\n  </script>\n<%= javascript_tag \"var AUTH_TOKEN = #{form_authenticity_token.inspect};\" if protect_against_forgery? %>\n<%= javascript_tag \"$(document).ready(function() {initialize();});\"%>\n\n<%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? 'gt-bd gt-cols clearfix' : 'gt-bd clearfix')}, true) %>\n\n  <div class=\"gt-content\">\n      <%= render_flash_messages %>\n      <%= yield %>\n  </div>\n\n  <% if (has_content?(:sidebar)) %>\n      <div class=\"gt-sidebar\">\n          <%= yield :sidebar %>\n      </div>\n  <%   end   %>\n\n</div>\n\n\n<div id=\"ajax-indicator\" style=\"display:none;\"><span><%= l(:label_loading) %></span></div>\n\n\n\n</body>\n</html>\n"
  },
  {
    "path": "app/views/layouts/gooey.html.erb",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<head>\n\n<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n<title><%=h html_title %></title>\n<meta name=\"description\" content=\"<%= Redmine::Info.app_name %>\" />\n<meta name=\"keywords\" content=\"issue,bug,tracker\" />\n<link rel=\"shortcut icon\" href=\"/images/favicon.ico\"  mce_href=\"/images/favicon.ico\" />\n\n\n\n<%= stylesheet_link_tag 'reset-fonts' %>\n<%= stylesheet_link_tag 'jquery.fancybox-1.3.4' %>\n<%= stylesheet_link_tag 'jquery.tagsinput' %>\n<%= stylesheet_link_tag 'jquery-ui-1.8.8.custom' %>\n<%= stylesheet_link_tag 'gt-styles' %>\n<%= stylesheet_link_tag 'headerandfooter.css' %>\n\n<link href=\"/stylesheets/bubbletip.css\" rel=\"stylesheet\" type=\"text/css\" />\n<!--[if IE]>\n<link href=\"/stylesheets/bubbletip-IE.css\" rel=\"stylesheet\" type=\"text/css\" />\n<![endif]-->\n\n\n<%= javascript_include_tag :defaults %>\n<%= javascript_include_tag  'jquery.jgrowl_minimized' %>\n<%= javascript_include_tag  'jquery.scrollTo-min' %>\n<%= javascript_include_tag  'jquery.fancybox-1.3.4.pack' %>\n<%= javascript_include_tag  'jquery.sparkline.min' %>\n<%= javascript_include_tag  'jquery.tagsinput' %>\n<%= javascript_include_tag  'store' %>\n\n\n\n<!--[if IE]>\n    <style type=\"text/css\">\n      * html body{ width: expression( document.documentElement.clientWidth < 900 ? '900px' : '100%' ); }\n      body {behavior: url(<%= stylesheet_path \"csshover.htc\" %>);}\n    </style>\n<![endif]-->\n<%= yield :header_tags -%>\n</head>\n<body>\n  <!--[if IE]>\n  <div style='border: 1px solid #F7941D; background: #FEEFDA; text-align: center; clear: both; height: 75px; position: relative;'>    <div style='position: absolute; right: 3px; top: 3px; font-family: courier new; font-weight: bold;'><a href='#' onclick='javascript:this.parentNode.parentNode.style.display=\"none\"; return false;'><img src='/images/static/ie6nomore-cornerx.jpg' style='border: none;' alt='Close this notice'/></a></div>    <div style='width: 640px; margin: 0 auto; text-align: left; padding: 0; overflow: hidden; color: black;'>      <div style='width: 75px; float: left;'><img src='/images/static/ie6nomore-warning.jpg' alt='Warning!'/></div>      <div style='width: 275px; float: left; font-family: Arial, sans-serif;'>        <div style='font-size: 14px; font-weight: bold; margin-top: 12px;'>You are using an unsupported browser</div>        <div style='font-size: 12px; margin-top: 6px; line-height: 12px;'>For a better experience using bettermeans, please upgrade to a modern web browser.</div>      </div>      <div style='width: 75px; float: left;'><a href='http://www.firefox.com' target='_blank'><img src='/images/static/ie6nomore-firefox.jpg' style='border: none;' alt='Get Firefox 3.5'/></a></div>            <div style='width: 73px; float: left;'><a href='http://www.apple.com/safari/download/' target='_blank'><img src='/images/static/ie6nomore-safari.jpg' style='border: none;' alt='Get Safari 4'/></a></div>      <div style='float: left;'><a href='http://www.google.com/chrome' target='_blank'><img src='/images/static/ie6nomore-chrome.jpg' style='border: none;' alt='Get Google Chrome'/></a></div>    </div>  </div>\n  <![endif]-->\n\n  <script type=\"text/javascript\">\n\n    var _gaq = _gaq || [];\n    _gaq.push(['_setAccount', 'UA-1630609-6']);\n    _gaq.push(['_trackPageview']);\n\n    (function() {\n      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n    })();\n\n  </script>\n<%= javascript_tag \"var AUTH_TOKEN = #{form_authenticity_token.inspect};\" if protect_against_forgery? %>\n<%= javascript_tag \"$(document).ready(function() {initialize();});\"%>\n\n<div class=\"gt-hd clearfix\">\n  <div class=\"gt-leaf-watermark clearfix\">\n\n  <div class=\"gt-hd-top clearfix\">\n\n    <div class=\"gt-fixed-wrap clearfix\">\n\n    <div class=\"gt-logo\">\n      <a href=\"/\" style=\"text-decoration:none;\" class=\"left\">\n        <img src=\"/images/static/header_logo.png\"></a>\n      </a>\n      <div class=\"gt-logo-links\">\n        <%= link_to(l(:label_my_home).upcase, {:controller => 'welcome', :action => 'index'}, :class => 'root') %>&nbsp;\n        <%= render_project_jump_box %>\n      </div>\n    </div>\n\n    <div class=\"gt-util-box\">\n      <div class=\"gt-util-box-inner\">\n      <%= render :partial => \"layouts/account_menu\" -%>\n      </div>\n      <%= yield :buttonbar %>\n    </div>\n    </div>\n\n  </div>\n\n  <div class=\"gt-navbar clearfix\">\n\n    <div class=\"gt-fixed-wrap clearfix\">\n\n    <div class=\"gt-nav\">\n      <div class=\"gt-nav-header\">\n        <span class=\"gt-nav-breadcrumbs\"><%= page_header_title %></span>\n        <br>\n        <h1><%= page_header_name %><%= sub_workstream_project_box(@project) %></h1>\n        <% if (!has_content?(:searchbar)) %>\n      <div class=\"gt-search gt-search-wide\">\n              <div class=\"gt-search-inner\">\n              <% form_tag({:controller => 'search', :action => 'index', :id => @project}, :method => :get ) do %>\n              <%= hidden_field_tag(controller.default_search_scope, 1, :id => nil) if controller.default_search_scope %>\n              <%= hidden_field_tag(:scope, 'subprojects') %>\n              <%= text_field_tag 'q', @question, :size => 20, :class => 'gt-search-text', :onfocus => \"javascript:if(this.value=='Search')this.value='';\", :onblur=> \"javascript:if(this.value=='')this.value='Search';\", :accesskey => accesskey(:quick_search) %>\n\n              <% end %>\n              </div>\n            </div>\n            <% else %>\n              <%= yield :searchbar %>\n        <% end %>\n      </div>\n      <div class=\"gt-nav-sub\">\n      <% if @project && !@project.new_record? %>\n        <%= render_main_menu(@project) %>\n      <% else %>\n        <% if (has_content?(:mainmenu)) %>\n          <%= yield :mainmenu %>\n        <% else %>\n          <ul><li><a href=\"#\" style=\"opacity:0;\">.</a></li></ul>\n        <% end %>\n      <% end %>\n      <div class=\"gt-actionmenu\">\n      <% if (has_content?(:actionmenu)) %>\n              <%= yield :actionmenu %>\n      <%   end   %>\n      <% if (has_content?(:help_section)) %>\n        <ul>\n          <li>\n            <a class=\"top-help-tip icon icon-help\" href='' onclick=\"help_popup(); return false;\">Tip</a>\n          </li>\n        </ul>\n      <% end %>\n      </div>\n      </div>\n\n    </div>\n\n    <% if (!has_content?(:topbuttons)) %>\n    <% else %>\n      <%= yield :topbuttons %>\n    <% end %>\n\n    </div>\n  </div>\n  <% if (has_content?(:secondnav)) %>\n    <div class=\"gt-second-navbar\">\n    <%= yield :secondnav %>\n    </div>\n  <% end %>\n</div>\n</div>\n\n<%\n\nif (has_content?(:actionmenu) && false)\n  cssclass = has_content?(:sidebar) ?  'gt-bd gt-cols-2 clearfix' : 'gt-bd gt-cols-3 clearfix'\nelsif\n  cssclass = has_content?(:sidebar) ?  'gt-bd gt-cols clearfix' : 'gt-bd clearfix'\nend\n\n\n %>\n<%= tag('div', {:id => 'main', :class => cssclass }, true) %>\n\n\n  <div class=\"gt-content\" id=\"content\">\n      <%= render_global_messages %>\n      <%= render_flash_messages %>\n      <%= yield %>\n  </div>\n\n  <% if (has_content?(:sidebar)) %>\n      <div class=\"gt-sidebar\">\n          <%= yield :sidebar %>\n      </div>\n  <%   end   %>\n\n<div id=\"help_section_container\" style=\"display:none\">\n  <div class=\"help-section\" id=\"help_section\">\n    <%= yield :help_section  %>\n  </div>\n</div>\n</div>\n\n\n<div id=\"ajax-indicator\" style=\"display:none;\"><span><%= l(:label_loading) %></span></div>\n\n\n<% if (has_content?(:footer)) %>\n  <%= yield :footer %>\n<% else %>\n  <%= render :partial => '/home/footer' %>\n<% end %>\n\n\n\n\n</body>\n</html>\n"
  },
  {
    "path": "app/views/layouts/help_sections.html.erb",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n       \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"content-type\" content=\"text/html;charset=UTF-8\" />\n  <title>HelpSections: <%= controller.action_name %></title>\n  <%= stylesheet_link_tag 'scaffold' %>\n</head>\n<body>\n\n<p style=\"color: green\"><%= flash.now[:success] %></p>\n\n<%= yield %>\n\n</body>\n</html>\n"
  },
  {
    "path": "app/views/layouts/issue_blank.html.erb",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<head>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n<title><%=h html_title %></title>\n<meta name=\"description\" content=\"<%= Redmine::Info.app_name %>\" />\n<meta name=\"keywords\" content=\"issue,bug,tracker\" />\n<%= stylesheet_link_tag 'reset-fonts' %>\n<%= stylesheet_link_tag 'gt-styles' %>\n<%= stylesheet_link_tag 'jquery.fancybox-1.3.4' %>\n<%= stylesheet_link_tag 'jquery-ui-1.8.8.custom' %>\n<%= stylesheet_link_tag 'dashboard' %>\n<%= stylesheet_link_tag 'issue' %>\n<%= stylesheet_link_tag 'jquery.fileupload-ui' %>\n<%= stylesheet_link_tag 'jquery.tagsinput' %>\n\n<style type=\"text/css\">\n  body {   background:none;   }\n  html {\n    background-color: #e2eaee;\n  }\n</style>\n\n<link href=\"/stylesheets/bubbletip.css\" rel=\"stylesheet\" type=\"text/css\" />\n<!--[if IE]>\n<link href=\"/stylesheets/bubbletip-IE.css\" rel=\"stylesheet\" type=\"text/css\" />\n<![endif]-->\n\n\n<%= javascript_include_tag :defaults %>\n<%= javascript_include_tag  'jquery.jgrowl_minimized.js' %>\n<%= javascript_include_tag  'jquery.scrollTo-min' %>\n<%= javascript_include_tag  'jquery.fancybox-1.3.4.pack' %>\n<%= javascript_include_tag  'jquery.sparkline.min.js' %>\n<%= javascript_include_tag  'store' %>\n<%= javascript_include_tag 'dashboard' %>\n<%= javascript_include_tag 'jquery.fileupload.js' %>\n<%= javascript_include_tag 'jquery.fileupload-ui.js' %>\n<%= javascript_include_tag  'jquery.tagsinput.js' %>\n\n<!--[if IE]>\n    <style type=\"text/css\">\n      * html body{ width: expression( document.documentElement.clientWidth < 900 ? '900px' : '100%' ); }\n      body {behavior: url(<%= stylesheet_path \"csshover.htc\" %>);}\n    </style>\n<![endif]-->\n<%= yield :header_tags -%>\n</head>\n<body>\n  <script type=\"text/javascript\">\n\n    var _gaq = _gaq || [];\n    _gaq.push(['_setAccount', 'UA-1630609-6']);\n    _gaq.push(['_trackPageview']);\n\n    (function() {\n      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n    })();\n\n  </script>\n<%= javascript_tag \"var AUTH_TOKEN = #{form_authenticity_token.inspect};\" if protect_against_forgery? %>\n<div id=\"wrapper\">\n    <div id=\"content\" style=\"min-height:200px;\">\n        <%= render_flash_messages %>\n        <%= yield %>\n        <div style=\"clear:both;\"></div>\n    </div>\n</div>\n\n<div id=\"ajax-indicator\" style=\"display:none;\"><span><%= l(:label_loading) %></span></div>\n\n<div id=\"footer\">\n    Powered by <a href=\"http://BetterMeans.com\">BetterMeans.com</a> <%= Date.today.year %>  <a href=\"http://creativecommons.org/licenses/by-sa/3.0/\" target=\"new\">[cc] CreativeCommons Attribution-Share Alike</a>\n</div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "app/views/layouts/mailer.text.html.erb",
    "content": "<html>\n<head>\n<style>\nbody {\n  font-family: Verdana, sans-serif;\n  font-size: 0.8em;\n  color:#484848;\n}\nh1, h2, h3 { font-family: \"Trebuchet MS\", Verdana, sans-serif; margin: 0px; }\nh1 { font-size: 1em; }\nh2, h3 { font-size: 1em; }\na, a:link, a:visited { color: #2A5685;}\na:hover, a:active { color: #c61a1a; }\na.wiki-anchor { display: none; }\nhr {\n  width: 100%;\n  height: 1px;\n  background: #ccc;\n  border: 0;\n}\n.footer {\n  font-size: 0.8em;\n  font-style: italic;\n}\n</style>\n</head>\n<body>\n<%= yield %>\n<hr />\n<% @footer ||=  Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_footer)%>\n<span class=\"footer\"><%= @footer  %></span>\n</body>\n</html>\n"
  },
  {
    "path": "app/views/layouts/mailer.text.plain.erb",
    "content": "<%= yield %>\n--\n<% @footer ||=  Setting.emails_footer%>\n<%= @footer %>\n"
  },
  {
    "path": "app/views/layouts/static.html.erb",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n<meta name=\"author\" content=\"Ivor Padilla\" />\n<link rel=\"shortcut icon\" href=\"/images/favicon.ico\"  mce_href=\"/images/favicon.ico\" />\n\n<title>BetterMeans - Open and Democratic Project Management</title>\n<%= stylesheet_link_tag 'headerandfooter.css' %>\n<%= stylesheet_link_tag 'static/style.css' %>\n<%= stylesheet_link_tag 'static/screen.css' %>\n<%= stylesheet_link_tag 'static/superfish.css' %>\n<%= stylesheet_link_tag 'gt-rounded-corners.css' %>\n<%= stylesheet_link_tag 'jquery.fancybox-1.3.4' %>\n\n<%= javascript_include_tag :defaults %>\n<%= javascript_include_tag  'jquery.scrollTo-min' %>\n<%= javascript_include_tag  'jquery.fancybox-1.3.4.pack' %>\n<%= javascript_include_tag  'jquery.sparkline.min' %>\n\n<script SRC=\"/javascripts/static/jquery.easing.1.3.js\" type=\"text/javascript\"></script>\n<script SRC=\"/javascripts/static/execute.js\" type=\"text/javascript\"></script>\n<script SRC=\"/javascripts/static/jquery.scroll.pack.js\" type=\"text/javascript\"></script>\n<script SRC=\"/javascripts/static/hoverIntent.js\"></script>\n<script SRC=\"/javascripts/static/superfish.js\"></script>\n<script SRC=\"/javascripts/static/cufon-yui.js\"></script>\n<script SRC=\"/javascripts/static/Quicksand_Book_400.font.js\"></script>\n<script SRC=\"/javascripts/static/jquery-galleryview-1.1/jquery.galleryview-1.1.js\"></script>\n<script SRC=\"/javascripts/static/jquery-galleryview-1.1/jquery.timers-1.1.2.js\"></script>\n<script SRC=\"/javascripts/fancybox/jquery.mousewheel-3.0.2.pack.js\"></script>\n\n\n\n<!--[if lt IE 8]>\n<link rel=\"stylesheet\" href=\"ie.css\" type=\"text/css\" media=\"screen, projection\"/>\n<![endif]-->\n\n</head>\n<body>\n  <script type=\"text/javascript\">\n\n    var _gaq = _gaq || [];\n    _gaq.push(['_setAccount', 'UA-1630609-6']);\n    _gaq.push(['_trackPageview']);\n\n    (function() {\n      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n    })();\n\n  </script>\n\n<%= yield %>\n\n<%= render :partial => '/home/footer' %>\n\n<script type=\"text/javascript\">\n            $(function() {\n                $(\"#toTop\").scrollToTop({speed:500,start:700});\n            });\n\n    $(document).ready(function() {\n      $('.viewport').mouseenter(function(e) {\n        $(this).children('a').children('img').animate({ height: '268', left: '-10', top: '-10', width: '480'}, 100);\n        $(this).children('a').children('span').fadeIn(300);\n      }).mouseleave(function(e) {\n        $(this).children('a').children('img').animate({ height: '247', left: '0', top: '0', width: '460'}, 100);\n        $(this).children('a').children('span').fadeOut(200);\n      });\n\n      $(\".videolink\").fancybox({\n                          'titleShow'     : true,\n                          'transitionIn'  : 'elastic',\n                          'transitionOut' : 'elastic',\n                          'href' : this.href,\n                          'type'      : 'swf',\n                          'swf'       : {'wmode':'transparent','allowfullscreen':'true'}\n              });\n\n      /* This is basic - uses default settings */\n      $(\"a.fancy_image\").fancybox({\n        'transitionIn'  : 'elastic',\n        'transitionOut'  : 'elastic'\n      });\n\n    });\n\n        </script>\n</body>\n</html>\n"
  },
  {
    "path": "app/views/mailer/_issue_text_html.html.erb",
    "content": "<%= link_to \"#{issue.tracker.name} ##{issue.id}: #{issue.subject}\", issue_url %>\n\n<ul>\n<li><%=l(:field_author)%>: <%= issue.author %></li>\n<li><%=l(:field_status)%>: <%= issue.status %></li>\n<li><%=l(:field_assigned_to)%>: <%= issue.assigned_to %></li>\n</ul>\n\n<%= textilizable(issue, :description, :only_path => false) %>\n\n-----<br>\n<%= l(:text_issue_edit_footer) %>\n<br>\n"
  },
  {
    "path": "app/views/mailer/_issue_text_plain.html.erb",
    "content": "<%= \"#{issue.tracker.name} ##{issue.id}: #{issue.subject}\" %>\n<%= issue_url %>\n\n<%=l(:field_author)%>: <%= issue.author %>\n<%=l(:field_status)%>: <%= issue.status %>\n<%=l(:field_assigned_to)%>: <%= issue.assigned_to %>\n\n<%= issue.description %>\n\n-----<br>\n<%= l(:text_issue_edit_footer) %>\n<br>\n"
  },
  {
    "path": "app/views/mailer/account_activated.text.html.html.erb",
    "content": "<p><%= l(:notice_account_activated) %></p>\n<p><%= l(:label_login) %>: <%= link_to @login_url, @login_url %></p>\n"
  },
  {
    "path": "app/views/mailer/account_activated.text.plain.html.erb",
    "content": "<%= l(:notice_account_activated) %>\n<%= l(:label_login) %>: <%= @login_url %>\n"
  },
  {
    "path": "app/views/mailer/account_activation_request.text.html.html.erb",
    "content": "<p><%= l(:mail_body_account_activation_request, @user.login) %></p>\n<p><%= link_to @url, @url %></p>\n"
  },
  {
    "path": "app/views/mailer/account_activation_request.text.plain.html.erb",
    "content": "<%= l(:mail_body_account_activation_request, @user.login) %>\n<%= @url %>\n"
  },
  {
    "path": "app/views/mailer/account_information.text.html.html.erb",
    "content": "<% if @user.auth_source %>\n<p><%= l(:mail_body_account_information_external, @user.auth_source.name) %></p>\n<% else %>\n<p><%= l(:mail_body_account_information) %>:</p>\n<ul>\n    <li><%= l(:field_login) %>: <%= @user.login %></li>\n    <li><%= l(:field_password) %>: <%= @password %></li>\n</ul>\n<% end %>\n\n<p><%= l(:label_login) %>: <%= auto_link(@login_url) %></p>\n"
  },
  {
    "path": "app/views/mailer/account_information.text.plain.html.erb",
    "content": "<% if @user.auth_source %><%= l(:mail_body_account_information_external, @user.auth_source.name) %>\n<% else %><%= l(:mail_body_account_information) %>:\n* <%= l(:field_login) %>: <%= @user.login %>\n* <%= l(:field_password) %>: <%= @password %>\n<% end %>\n<%= l(:label_login) %>: <%= @login_url %>\n"
  },
  {
    "path": "app/views/mailer/attachments_added.text.html.html.erb",
    "content": "<%= link_to @added_to, @added_to_url %><br />\n\n<ul><% @attachments.each do |attachment | %>\n<li><%= attachment.filename %></li>\n<% end %></ul>\n"
  },
  {
    "path": "app/views/mailer/attachments_added.text.plain.html.erb",
    "content": "<%= @added_to %><% @attachments.each do |attachment | %>\n- <%= attachment.filename %><% end %>\n\n<%= @added_to_url %>\n"
  },
  {
    "path": "app/views/mailer/daily_digest.text.html.html.erb",
    "content": "Here's the list of system updates for work items you're involved with...<br><br>\n\n<% @journals.group_by{|j| j.issue_id}.each_pair do |issue_id, details| %>\n<% issue = Issue.find(issue_id) %>\n<%= link_to \"#{issue.tracker.name} ##{issue.id}: #{issue.subject}\", url_for(:controller => 'projects', :action => 'dashboard', :show_issue_id => issue.id, :only_path => false) %><br>\n<ul>\n<% details.each do |detail|%>\n  <% journal = Journal.find(detail.journal_id)  %>\n  <% for detail in journal.details %>\n      <li><%= show_detail(detail, true) %></li>\n  <% end %>\n<% end %>\n</ul>\n<br>-------------------------------\n<br>\n<% end %>\n"
  },
  {
    "path": "app/views/mailer/daily_digest.text.plain.html.erb",
    "content": "Here's the list of system updates for work items you're involved with...\n\n<% @journals.group_by{|j| j.issue_id}.each_pair do |issue_id, details| %>\n<% issue = Issue.find(issue_id) %>\n<%= \"#{issue.tracker.name} ##{issue.id}: #{issue.subject}\" %>\n<%= url_for(:controller => 'projects', :action => 'dashboard', :show_issue_id => issue.id, :only_path => false) %>\n<% details.each do |detail|%>\n  <% journal = Journal.find(detail.journal_id)  %>\n  <% for detail in journal.details %>\n      <%= show_detail(detail, true) %>\n  <% end %>\n<% end %>\n-------------------------------\n\n<% end %>\n"
  },
  {
    "path": "app/views/mailer/document_added.text.html.html.erb",
    "content": "<%= link_to @document.title, @document_url %><br />\n<br />\n<%= textilizable(@document, :description, :only_path => false) %>\n"
  },
  {
    "path": "app/views/mailer/document_added.text.plain.html.erb",
    "content": "<%= @document.title %>\n<%= @document_url %>\n\n<%= @document.description %>\n"
  },
  {
    "path": "app/views/mailer/email_update_activation.text.html.html.erb",
    "content": "Activate your updated email address<br>\n<a href=\"<%= @activation_url %>\"><%= @activation_url %></a><br>\n<br><br>\n--------------------\n<br><br>\nCheers!<br>\nthe folks at bettermeans.com\n"
  },
  {
    "path": "app/views/mailer/email_update_activation.text.plain.html.erb",
    "content": "Activate your updated email address\n<%= @activation_url %>\n\n--------------------\n\nCheers!\nthe folks at bettermeans.com\n"
  },
  {
    "path": "app/views/mailer/invitation_add.text.html.html.erb",
    "content": "<%= @user.name %> is inviting you to work with them on <%= @project.name %>\n<br><br>\n<% if @note %>\n--------------------<br>\n<%= @note %><br>\n--------------------<br><br>\n<% end %>\n\nTo accept their invitation follow this link:<br>\n<a href=\"<%= @invitation_url %>\"><%= @invitation_url %></a><br>\n<br><br>\nGood luck!<br>\nthe folks at bettermeans<br><br>\nopen, democratic project management<br>\nhttp://bettermeans.com\n"
  },
  {
    "path": "app/views/mailer/invitation_add.text.plain.html.erb",
    "content": "<%= @user.name %> is inviting you to work with them on <%= @project.name %>\n\n<% if @note %>\n--------------------\n<%= @note %>\n--------------------\n<% end %>\n\nTo accept their invitation follow this link:\n<%= @invitation_url %>\n\nGood luck!\nthe folks at bettermeans.com\n"
  },
  {
    "path": "app/views/mailer/invitation_remind.text.html.html.erb",
    "content": "\n<%= @user.name %> just sent you a reminder that your'e invited to work with them on <%= @project.name %>\n<br><br>\n<% if @note %>\n--------------------<br>\n<%= @note %><br>\n--------------------<br><br>\n<% end %>\n\nTo accept their invitation follow this link:<br>\n<a href=\"<%= @invitation_url %>\"><%= @invitation_url %></a><br>\n<br><br>\nGood luck!<br>\nthe folks at bettermeans<br><br>\nopen, democratic project management<br>\nhttp://bettermeans.com\n"
  },
  {
    "path": "app/views/mailer/invitation_remind.text.plain.html.erb",
    "content": "<%= @user.name %> just sent you a reminder that your'e invited to work with them on <%= @project.name %>\n\n<% if @note %>\n--------------------\n<%= @note %>\n--------------------\n<% end %>\n\nTo accept their invitation follow this link:\n<%= @invitation_url %>\n\nGood luck!\nthe folks at bettermeans\n\nopen, democratic project management\nhttp://bettermeans.com\n"
  },
  {
    "path": "app/views/mailer/issue_add.text.html.html.erb",
    "content": "<%= l(:text_issue_added, :id => \"##{@issue.id}\", :author => @issue.author) %>\n<hr />\n<%= render :partial => \"issue_text_html\", :locals => { :issue => @issue, :issue_url => @issue_url } %>\n"
  },
  {
    "path": "app/views/mailer/issue_add.text.plain.html.erb",
    "content": "<%= l(:text_issue_added, :id => \"##{@issue.id}\", :author => @issue.author) %>\n\n----------------------------------------\n<%= render :partial => \"issue_text_plain\", :locals => { :issue => @issue, :issue_url => @issue_url } %>\n"
  },
  {
    "path": "app/views/mailer/issue_edit.text.html.html.erb",
    "content": "<%= l(:text_issue_updated, :id => \"##{@issue.id}\", :author => @journal.user) %>\n\n<ul>\n<% for detail in @journal.details %>\n    <li><%= show_detail(detail, true) %></li>\n<% end %>\n</ul>\n\n<%= textilizable(@journal, :notes, :only_path => false) %>\n<hr />\n<%= render :partial => \"issue_text_html\", :locals => { :issue => @issue, :issue_url => @issue_url } %>\n"
  },
  {
    "path": "app/views/mailer/issue_edit.text.plain.html.erb",
    "content": "<%= l(:text_issue_updated, :id => \"##{@issue.id}\", :author => @journal.user) %>\n\n<% for detail in @journal.details -%>\n<%= show_detail(detail, true) %>\n<% end -%>\n\n<%= @journal.notes if @journal.notes? %>\n----------------------------------------\n<%= render :partial => \"issue_text_plain\", :locals => { :issue => @issue, :issue_url => @issue_url } %>\n"
  },
  {
    "path": "app/views/mailer/lost_password.text.html.html.erb",
    "content": "<p><%= l(:mail_body_lost_password) %><br />\n<%= auto_link(@url) %></p>\n\n<p><%= l(:field_login) %>: <b><%= @token.user.login %></b></p>\n"
  },
  {
    "path": "app/views/mailer/lost_password.text.plain.html.erb",
    "content": "<%= l(:mail_body_lost_password) %>\n<%= @url %>\n\n<%= l(:field_login) %>: <%= @token.user.login %>\n"
  },
  {
    "path": "app/views/mailer/message_posted.text.html.html.erb",
    "content": "<h1><%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to @message.subject, @message_url %></h1>\n<em><%= @message.author %></em>\n\n<%= textilizable(@message, :content, :only_path => false) %>\n\n-----<br>\n<%= l(:text_issue_edit_footer) %>\n<br>\n"
  },
  {
    "path": "app/views/mailer/message_posted.text.plain.html.erb",
    "content": "<%= @message_url %>\n<%= @message.author %>\n\n<%= @message.content %>\n\n-----<br>\n<%= l(:text_issue_edit_footer) %>\n<br>\n"
  },
  {
    "path": "app/views/mailer/news_added.text.html.html.erb",
    "content": "<h1><%= link_to @news.title, @news_url %></h1>\n<em><%= @news.author.name %></em>\n\n<%= textilizable(@news, :description, :only_path => false) %>\n"
  },
  {
    "path": "app/views/mailer/news_added.text.plain.html.erb",
    "content": "<%= @news.title %>\n<%= @news_url %>\n<%= @news.author.name %>\n\n<%= @news.description %>\n"
  },
  {
    "path": "app/views/mailer/personal_welcome.text.html.html.erb",
    "content": "Hey <%= @name %>,\n<br>\n<br>I saw that you just signed up for our site. Thanks for trying us out.\n<br>\n<br>We've been building bettermeans and the open enterprise model for\nalmost two years now, and we're just beginning to share it with a\nwider audience.\n<br>\n<br>If you have any questions at all, need a hand with anything, or would\nlike to arrange for a demo - don't hesitate to email us at support@bettermeans.com.\n<br>You can also find some useful information to help get you started here http://help.bettermeans.com\n<br>\n<br>Thanks!\n<br>\n<br>Chirag Rabari\n<br>510.457.1670\n<br>\n<br>p.s. if you run into any issues, or have a new feature that you think we should implement, you can directly add it on our platform workstream here:\n<br>http://bettermeans.com/projects/platform/dashboard\n"
  },
  {
    "path": "app/views/mailer/personal_welcome.text.plain.html.erb",
    "content": "Hey <%= @name %>,\n\nI saw that you just signed up for our site. Thanks for trying us out.\n\nWe've been building bettermeans and the open enterprise model for\nalmost two years now, and we're just beginning to share it with a\nwider audience.\n\nIf you have any questions at all, need a hand with anything, or would\nlike to arrange for a demo - don't hesitate to email us at support@bettermeans.com.\n\nYou can also find some useful information to help get you started here http://help.bettermeans.com\n\nThanks!\n\nChirag Rabari\n510.457.1670\n\np.s. if you run into any issues, or have a new feature that you think we should implement, you can directly add it on our platform workstream here: http://bettermeans.com/projects/platform/dashboard\n"
  },
  {
    "path": "app/views/mailer/register.text.html.html.erb",
    "content": "<p><%= l(:mail_body_register) %><br />\n<%= auto_link(@url) %></p>\n"
  },
  {
    "path": "app/views/mailer/register.text.plain.html.erb",
    "content": "<%= l(:mail_body_register) %>\n<%= @url %>\n"
  },
  {
    "path": "app/views/mailer/reminder.text.html.html.erb",
    "content": "<p><%= l(:mail_body_reminder, :count => @issues.size, :days => @days) %></p>\n\n<ul>\n<% @issues.each do |issue| -%>\n  <li><%=h issue.project %> - <%=link_to(\"#{issue.tracker} ##{issue.id}\", :controller => 'issues', :action => 'show', :id => issue, :only_path => false)%>: <%=h issue.subject %></li>\n<% end -%>\n</ul>\n\n<p><%= link_to l(:label_issue_view_all), @issues_url %></p>\n"
  },
  {
    "path": "app/views/mailer/reminder.text.plain.html.erb",
    "content": "<%= l(:mail_body_reminder, :count => @issues.size, :days => @days) %>:\n\n<% @issues.each do |issue| -%>\n* <%= \"#{issue.project} - #{issue.tracker} ##{issue.id}: #{issue.subject}\" %>\n<% end -%>\n\n<%= @issues_url %>\n"
  },
  {
    "path": "app/views/mailer/test.text.html.html.erb",
    "content": "<p>This is a test email sent by Redmine.<br />\nRedmine URL: <%= auto_link(@url) %></p>\n"
  },
  {
    "path": "app/views/mailer/test.text.plain.html.erb",
    "content": "This is a test email sent by Redmine.\nRedmine URL: <%= @url %>\n"
  },
  {
    "path": "app/views/mailer/wiki_content_added.text.html.html.erb",
    "content": "<p><%= l(:mail_body_wiki_content_added, :page => link_to(h(@wiki_content.page.pretty_title), @wiki_content_url),\n                                        :author => h(@wiki_content.author)) %><br />\n<em><%=h @wiki_content.comments %></em></p>\n"
  },
  {
    "path": "app/views/mailer/wiki_content_added.text.plain.html.erb",
    "content": "<%= l(:mail_body_wiki_content_added, :page => h(@wiki_content.page.pretty_title),\n                                     :author => h(@wiki_content.author)) %>\n<%= @wiki_content.comments %>\n\n<%= @wiki_content_url %>\n"
  },
  {
    "path": "app/views/mailer/wiki_content_updated.text.html.html.erb",
    "content": "<p><%= l(:mail_body_wiki_content_updated, :page => link_to(h(@wiki_content.page.pretty_title), @wiki_content_url),\n                                          :author => h(@wiki_content.author)) %><br />\n<em><%=h @wiki_content.comments %></em></p>\n\n<p><%= l(:label_view_diff) %>:<br />\n<%= link_to @wiki_diff_url, @wiki_diff_url %></p>\n"
  },
  {
    "path": "app/views/mailer/wiki_content_updated.text.plain.html.erb",
    "content": "<%= l(:mail_body_wiki_content_updated, :page => h(@wiki_content.page.pretty_title),\n                                       :author => h(@wiki_content.author)) %>\n<%= @wiki_content.comments %>\n\n<%= @wiki_content.page.pretty_title %>:\n<%= @wiki_content_url %>\n<%= l(:label_view_diff) %>:\n<%= @wiki_diff_url %>\n"
  },
  {
    "path": "app/views/mails/_inbox.html.erb",
    "content": "<h2>Inbox</h2>\n<table>\n  <tr>\n    <th>Del?</th>\n    <th>Sent</th>\n    <th>Sender</th>\n    <th>Sent</th>\n  </tr>\n  <% if @mails.size == 0 %>\n    <tr>\n      <td colspan=\"4\">\n        No messages\n      </td>\n    </tr>\n  <% else %>\n    <% for mail in @mails %>\n      <tr>\n        <td><%= check_box_tag \"delete[]\", mail.id %></td>\n        <td>\n          <% if mail.read? %>\n            <%= link_to h(mail.subject), user_mail_path(@user, mail) %>\n          <% else %>\n            <%= link_to \"#{h(mail.subject)} (unread)\", user_mail_path(@user, mail) %>\n          <% end %>\n        </td>\n        <td><%= link_to h(mail.sender.login), user_path(@user) %></td>\n        <td><%=h mail.created_at.to_s(:long) %></td>\n      </tr>\n    <% end %>\n    <tr>\n      <td colspan=\"4\">\n        <%= submit_tag \"Delete\", :disable_with => l(:button_working) %>\n      </td>\n    </tr>\n  <% end %>\n</table>\n<%= link_to \"Sent\", user_mails_path(@user, :mailbox => :sent)%> |\n<%= link_to \"Compose\", new_user_mail_path(@user)%>\n"
  },
  {
    "path": "app/views/mails/_sent.html.erb",
    "content": "<h2>Sent</h2>\n<table>\n  <tr>\n    <th>Del?</th>\n    <th>Subject</th>\n    <th>To</th>\n    <th>Sent</th>\n  </tr>\n  <% if @mails.size == 0 %>\n    <tr>\n      <td colspan=\"4\">\n        No messages\n      </td>\n    </tr>\n  <% else %>\n    <% for mail in @mails %>\n      <tr>\n        <td><%= check_box_tag \"delete[]\", mail.id %></td>\n        <td><%= link_to h(mail.subject), user_mail_path(@user, mail) %></td>\n        <td><%= link_to h(mail.recipient.login), user_path(@user) %></td>\n        <td><%=h mail.created_at.to_s(:long) %></td>\n      </tr>\n    <% end %>\n    <tr>\n      <td colspan=\"4\">\n        <%= submit_tag \"Delete\", :disable_with => l(:button_working) %>\n      </td>\n    </tr>\n   <% end %>\n</table>\n<%= link_to \"Inbox\", user_mails_path(@user)%>\n"
  },
  {
    "path": "app/views/mails/index.html.erb",
    "content": "<% form_tag delete_selected_user_mails_path(@user) do %>\n  <% if params[:mailbox] == \"sent\" %>\n      <%= render :partial => \"sent\" %>\n  <% else %>\n      <%= render :partial => \"inbox\" %>\n    <% end %>\n<% end %>\n"
  },
  {
    "path": "app/views/mails/new.html.erb",
    "content": "<% form_for @mail, :url => user_mails_path(@user) do |f| %>\n  <p>\n    To:<br />\n    <%= f.text_field :to %>\n    <%= error_message_on @mail, :to %>\n  </p>\n  <p>\n    Subject:<br />\n    <%= f.text_field :subject %>\n    <%= error_message_on @mail, :subject %>\n    </p>\n    <p>\n      Message<br />\n      <%= f.text_area :body %>\n      <%= error_message_on @mail, :body %>\n    </p>\n    <p>\n      <%= submit_tag \"Send\", :disable_with => l(:button_working) %>\n    </p>\n<% end %>\n"
  },
  {
    "path": "app/views/mails/show.html.erb",
    "content": "<p><strong>From:</strong> <%= @mail.sender == @user ? link_to(\"You\", user_path(@user)) : link_to(h(@mail.sender.login), user_path(@user)) %></p>\n<p><strong>Received:</strong> <%= @mail.created_at.to_s(:long) %></p>\n<p><strong>To:</strong> <%= @mail.recipient == @user ? link_to(\"You\", user_path(@user)) : link_to(h(@mail.recipient.login), user_path(@user)) %></p>\n<p>\n  <strong>Message</strong><br />\n  <%=h @mail.body %>\n</p>\n<p>\n  <% if @mail.recipient == @user %>\n    <%= link_to \"Reply\", new_user_mail_path(@user, :reply_to => @mail) %> |\n  <% end %>\n  <%= link_to \"Inbox\", user_mails_path(@user)%>\n</p>\n"
  },
  {
    "path": "app/views/members/autocomplete_for_member.html.erb",
    "content": "<%= users_check_box_tags 'member[user_ids][]', @users %>\n"
  },
  {
    "path": "app/views/messages/_form.html.erb",
    "content": "<%= error_messages_for 'message' %>\n<% replying ||= false %>\n\n<div class=\"gt-content-box\">\n<p><label><%= l(:field_subject) %></label><br />\n<%= f.text_field :subject, :size => 120, :id => 'message_subject' %>\n\n<% if !replying && User.current.allowed_to?(:edit_messages, @project) %>\n    <label><%= f.check_box :sticky %> Sticky</label>\n    <label><%= f.check_box :locked %> Locked</label>\n<% end %>\n</p>\n\n<% if !replying && !@message.new_record? && User.current.allowed_to?(:edit_messages, @project) %>\n  <p><label><%= l(:label_board) %></label><br />\n  <%= f.select :board_id, @project.boards.collect {|b| [b.name, b.id]} %></p>\n<% end %>\n\n<p><%= f.textile_editor :content, :cols => 80, :rows => 15, :class => 'wiki-edit autocomplete-mentions', :id => 'message_content' %></p>\n<%= textile_editor_initialize(:framework => :jquery) %>\n\n<p>\n  <%= render :partial => 'attachments/form' %>\n</p>\n</div>\n\n<script type=\"text/javascript\">\nprojectId = <%= @project.id %>;\n</script>\n"
  },
  {
    "path": "app/views/messages/_motion_topic.html.erb",
    "content": "<h2><%=h @topic.subject %></h2>\n\n<div class=\"message\">\n\n<p><span class=\"author\"><%= authoring @topic.created_at, @topic.author %></span></p>\n\n\n<div class=\"wiki\">\n<%= textilizable(@topic.content, :attachments => @topic.attachments) %>\n</div>\n</div>\n<br />\n<% unless @replies.empty? %>\n<h3 class=\"comments\"><%= l(:label_reply_plural) %></h3>\n<% @replies.each do |message| %>\n  <div class=\"message reply\" id=\"<%= \"message-#{message.id}\" %>\">\n    <div class=\"contextual\">\n      <%= link_to_remote_if_authorized image_tag('comment.png'), { :url => {:action => 'quote', :id => message} }, :title => l(:button_quote) %>\n      <%= link_to(image_tag('edit.png'), {:action => 'edit', :id => message}, :title => l(:button_edit)) if message.editable_by?(User.current) %>\n      <%= link_to(image_tag('delete.png'), {:action => 'destroy', :id => message}, :method => :post, :confirm => l(:text_are_you_sure), :title => l(:button_delete)) if message.destroyable_by?(User.current) %>\n    </div>\n  <h4>\n    <%= link_to h(message.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => @topic, :anchor => \"message-#{message.id}\" } %>\n    -\n    <%= authoring message.created_at, message.author %>\n  </h4>\n  <div class=\"wiki\"><%= textilizable message, :content, :attachments => message.attachments %></div>\n  <%= link_to_attachments message, :author => false %>\n  </div>\n<% end %>\n<% end %>\n\n<% if !@topic.locked? && authorize_for('messages', 'reply') %>\n<p><%= toggle_link l(:button_reply), \"reply\", :focus => 'message_content' %></p>\n<div id=\"reply\" style=\"display:none;\">\n<% form_for :reply, @reply, :url => {:action => 'reply', :id => @topic}, :html => {:multipart => true, :id => 'message-form'} do |f| %>\n  <%= render :partial => 'messages/form', :locals => {:f => f, :replying => true} %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_submit), :disable_with => l(:button_working) %>\n  <p class=\"gt-cancel\">\n  <%= link_to_remote l(:label_preview),\n                     { :url => { :controller => 'messages', :action => 'preview', :board_id => @board },\n                       :method => 'post',\n                       :update => 'preview',\n                       :with => \"$('#message-form').serialize()\",\n                       :complete => \"$('body').scrollTo('#preview')\"\n                     }, :accesskey => accesskey(:preview) %>\n  </p>\n  </div>\n<% end %>\n<div id=\"preview\" class=\"wiki\"></div>\n</div>\n<% end %>\n\n<% content_for :header_tags do %>\n  <%= stylesheet_link_tag 'scm' %>\n<% end %>\n\n<% html_title h(@topic.subject) %>\n"
  },
  {
    "path": "app/views/messages/edit.html.erb",
    "content": "<h2><%= link_to h(@board.name), :controller => 'boards', :action => 'show', :project_id => @project, :id => @board %> &#187; <%=h @message.subject %></h2>\n\n<% form_for :message, @message, :url => {:action => 'edit'}, :html => {:multipart => true, :id => 'message-form'} do |f| %>\n  <%= render :partial => 'form', :locals => {:f => f, :replying => !@message.parent.nil?} %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n  <p class=\"gt-cancel\">\n  <%= link_to_remote l(:label_preview),\n                     { :url => { :controller => 'messages', :action => 'preview', :board_id => @board },\n                       :method => 'post',\n                       :update => 'preview',\n                       :with => \"$('#message-form').serialize()\",\n                       :complete => \"$('body').scrollTo('#preview')\"\n                     }, :accesskey => accesskey(:preview) %>\n  </p></div>\n<% end %>\n<div id=\"preview\" class=\"wiki\"></div>\n"
  },
  {
    "path": "app/views/messages/new.html.erb",
    "content": "<h2><%= link_to h(@board.name), :controller => 'boards', :action => 'show', :project_id => @project, :id => @board %> &#187; <%= l(:label_message_new) %></h2>\n\n<% form_for :message, @message, :url => {:action => 'new'}, :html => {:multipart => true, :id => 'message-form'} do |f| %>\n  <%= render :partial => 'form', :locals => {:f => f} %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n  <p class=\"gt-cancel\">\n  <%= link_to_remote l(:label_preview),\n                     { :url => { :controller => 'messages', :action => 'preview', :board_id => @board },\n                       :method => 'post',\n                       :update => 'preview',\n                       :with => \"$('#message-form').serialize()\",\n                       :complete => \"$('body').scrollTo('#preview')\"\n                     }, :accesskey => accesskey(:preview) %>\n  </p></div>\n<% end %>\n\n<div id=\"preview\" class=\"wiki\"></div>\n"
  },
  {
    "path": "app/views/messages/show.html.erb",
    "content": "<%= breadcrumb link_to(l(:label_board_plural), {:controller => 'boards', :action => 'index', :project_id => @project}),\n               link_to(h(@board.name), {:controller => 'boards', :action => 'show', :project_id => @project, :id => @board}) %>\n\n<% content_for :sidebar do %>\n <h2 class=\"gt-table-head\">&nbsp;</h2>\n <div class=\"gt-sidebar-nav gt-sidebar-nav-blue\">\n   <h3><%=l(:label_quick_links)%></h3>\n   <ul>\n   <li>\n     <%= watcher_tag(@topic, User.current) %>\n   </li>\n   <li>\n    <%= link_to_remote_if_authorized l(:button_quote), { :url => {:action => 'quote', :id => @topic} }, :class => 'icon icon-comment' %>\n   </li>\n   <li>\n    <%= link_to(l(:button_edit), {:action => 'edit', :id => @topic}, :class => 'icon icon-edit') if @message.editable_by?(User.current) %>\n   </li>\n    <li>\n      <%= link_to(l(:button_delete), {:action => 'destroy', :id => @topic}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') if @message.destroyable_by?(User.current) %>\n    </li>\n   </ul>\n </div>\n<% end %>\n\n    <h2><%=h @topic.subject %></h2>\n\n<div class=\"message gt-content-box\" id=\"top\">\n<table class=\"gt-table gt-user-table\" border=\"0\">\n  <tbody>\n    <tr>\n      <td class=\"gt-avatar <%= User.current.logged? && User.current.id == @topic.author ? 'me' : nil %>\">\n        <%= avatar(@topic.author, :size => '53') %>\n      </td>\n      <td>\n        <div class=\"wiki\">\n        <%= textilizable(@topic.content, :attachments => @topic.attachments) %>\n        </div>\n        <%= link_to_attachments @topic, :author => false %>\n    </td>\n    <td class=\"side\">\n      <table border=\"0\" class=\"gt-table-categories\">\n        <tr>\n          <td><%= link_to_user(@topic.author) %></td>\n        </tr>\n        <tr>\n          <td><%= since_tag(@topic.created_at) %> ago</td>\n        </tr>\n      </table>\n    </td>\n   </tr>\n  </tbody>\n</table>\n</div>\n\n\n<br />\n\n<% unless @replies.empty? %>\n<h3 class=\"comments\"><%= l(:label_reply_plural) %></h3>\n<div class=\"gt-content-box\">\n<table class=\"gt-table gt-user-table\" border=\"0\">\n  <tbody>\n\n    <% @replies.each do |message| %>\n       <tr>\n         <td class=\"gt-avatar <%= User.current.logged? && User.current.id == @topic.author ? 'me' : nil %>\">\n           <%= avatar(message.author, :size => '53') %>\n         </td>\n         <td>\n           <div class=\"message reply\" id=\"<%= \"message-#{message.id}\" %>\">\n           <h4>\n             <%= link_to h(message.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => @topic, :anchor => \"message-#{message.id}\" } %>\n           </h4>\n           <div class=\"wiki\"><%= textilizable message, :content, :attachments => message.attachments %></div>\n           <%= link_to_attachments message, :author => false %>\n           </div>\n\n         </td>\n         <td class=\"side\">\n           <table border=\"0\" class=\"gt-table-categories\">\n             <tr>\n               <td><%= link_to_user(message.author) %></td>\n             </tr>\n             <tr>\n               <td><%= since_tag(message.created_at) %> ago</td>\n             </tr>\n            <tr><td>\n              <%= link_to_remote_if_authorized image_tag('comment.png'), { :url => {:action => 'quote', :id => message} }, :title => l(:button_quote) %>\n              <%= link_to(image_tag('edit.png'), {:action => 'edit', :id => message}, :title => l(:button_edit)) if message.editable_by?(User.current) %>\n              <%= link_to(image_tag('delete.png'), {:action => 'destroy', :id => message}, :method => :post, :confirm => l(:text_are_you_sure), :title => l(:button_delete)) if message.destroyable_by?(User.current) %>\n              </td>\n              </tr>\n           </table>\n         </td>\n      </tr>\n\n    <% end %>\n\n  </tbody>\n</table>\n</div>\n<% end %>\n\n<% if !@topic.locked? && authorize_for('messages', 'reply') %>\n<p><%= toggle_link l(:button_reply), \"reply\", {:focus => 'message_content', :class => 'gt-btn-gray-large', :second_toggle => 'reply_button', :id => 'reply_button'} %></p>\n<div id=\"reply\" style=\"display:none;\">\n<% form_for :reply, @reply, :url => {:action => 'reply', :id => @topic}, :html => {:multipart => true, :id => 'message-form'} do |f| %>\n  <%= render :partial => 'form', :locals => {:f => f, :replying => true} %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_submit), :disable_with => l(:button_working) %>\n  <p class=\"gt-cancel\">\n  <%= link_to_remote l(:label_preview),\n                     { :url => { :controller => 'messages', :action => 'preview', :board_id => @board },\n                       :method => 'post',\n                       :update => 'preview',\n                       :with => \"$('#message-form').serialize()\",\n                       :complete => \"$('body').scrollTo('#preview')\"\n                     }, :accesskey => accesskey(:preview) %>\n   <%= toggle_link l(:button_cancel), \"reply\", {:focus => 'message_content', :second_toggle => 'reply_button', :id => 'reply_button'} %>\n    </p>\n    </div>\n<% end %>\n<div id=\"preview\" class=\"wiki\"></div>\n</div>\n<% else %>\n  <%= link_to l(:button_reply), :controller => \"account\", :action => \"login\" %>\n<% end %>\n\n<% content_for :header_tags do %>\n  <%= stylesheet_link_tag 'scm' %>\n<% end %>\n\n<% html_title h(@topic.subject) %>\n"
  },
  {
    "path": "app/views/motion_votes/_vote.html.erb",
    "content": "<span id=\"motion_votes\">\n  <div id=\"your_vote\">\n    <% user_vote = motion.motion_votes.belong_to_user(User.current.id).first %>\n    <% if user_vote.nil? %>\n    <%= l :label_you_havent_voted %>\n    <% else %>\n    <%= l :label_you_voted, :action => user_vote.action_description %>  <%= distance_of_time_in_words(Time.now,user_vote.updated_at) %> ago\n    <% end %>\n  </div>\n<% if motion.motion_type == Motion::TYPE_SHARE && User.current.shares.for_project(motion.project_id).empty? %>\n  <%= l(:text_you_dont_have_shares_to_vote) %>\n  <span class=\"clear\"></span>\n<% elsif motion.motion_type == Motion::TYPE_SHARE && motion.active? %>\n<br>\n  <%= link_to_remote button(l(:label_agree),:agree) , :url => {:controller => :motion_votes, :action => :create, :points => 1, :motion_id => motion} if user_vote.nil? || user_vote.points < 1%>\n  <%= link_to_remote button(l(:label_neutral),:neutral) , :url => {:controller => :motion_votes, :action => :create, :points => 0, :motion_id => motion} if user_vote.nil? || user_vote.points != 0%>\n  <%= link_to_remote button(l(:label_disagree),:against) , :url => {:controller => :motion_votes, :action => :create, :points => -1, :motion_id => motion} if user_vote.nil? || user_vote.points > -1%>\n  <span class=\"clear\"></span>\n<% elsif motion.active? %>\n<br>\n  <%= link_to_remote button(l(:label_agree),:agree) , :url => {:controller => :motion_votes, :action => :create, :points => 1, :motion_id => motion} if user_vote.nil? || user_vote.points != 1%>\n  <%= link_to_remote button(l(:label_neutral),:neutral) , :url => {:controller => :motion_votes, :action => :create, :points => 0, :motion_id => motion} if user_vote.nil? || user_vote.points != 0%>\n  <%= link_to_remote button(l(:label_disagree),:against) , :url => {:controller => :motion_votes, :action => :create, :points => -1, :motion_id => motion} if user_vote.nil? || user_vote.points != -1%>\n  <%= link_to_remote button(l(:label_block),:block) , :url => {:controller => :motion_votes, :action => :create, :points => -9999, :motion_id => motion} if user_vote.nil? || user_vote.points != -9999%>\n  <span class=\"clear\"></span>\n<% end %>\n<br>\n<br>\n\n<div id=\"motion_votes_tally\">\n  <h3><%= l :label_tally %></h3>\n  <% if user_vote.nil? && motion.active? %>\n    <%= l :text_tally_hidden_until_you_vote %>\n  <% else %>\n    <div class=\"gt-content-box\">\n      <%= tally_table(motion) %>\n    </div>\n  <% end %>\n</div>\n<br>\n<br>\n\n<div id=\"motion_votes_history\">\n  <h3><%= l :label_history %></h3>\n  <% if user_vote.nil? %>\n    <%= l :text_history_hidden_until_you_vote %>\n  <% else %>\n    <% motion.motion_votes.history.each do |mv| %>\n    <%= !user_vote.isbinding && mv.isbinding ? l(:label_hidden) : link_to_user(mv.user) %>: <b><%= mv.action_description %></b> <%= distance_of_time_in_words(Time.now,mv.updated_at) %> ago <%= \"(#{l :label_non_binding})\" if !mv.isbinding %><br>\n    <% end %>\n  <% end %>\n</div>\n\n</span>\n"
  },
  {
    "path": "app/views/motion_votes/cast_vote.js.rjs",
    "content": "page.replace_html \"motion_votes\", :partial => \"motion_votes/vote\", :locals => {:motion => @motion_vote.motion}\npage[\"your_vote\"].visual_effect :highlight\n\n"
  },
  {
    "path": "app/views/motion_votes/edit.html.erb",
    "content": "<h1>Editing motion_vote</h1>\n\n<% form_for(@motion_vote) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :motion_id %><br />\n    <%= f.text_field :motion_id %>\n  </p>\n  <p>\n    <%= f.label :user_id %><br />\n    <%= f.text_field :user_id %>\n  </p>\n  <p>\n    <%= f.label :points %><br />\n    <%= f.text_field :points %>\n  </p>\n  <p>\n    <%= f.label :isbinding %><br />\n    <%= f.check_box :isbinding %>\n  </p>\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @motion_vote %> |\n<%= link_to 'Back', motion_votes_path %>\n"
  },
  {
    "path": "app/views/motion_votes/index.html.erb",
    "content": "<h1>Listing motion_votes</h1>\n\n<table>\n  <tr>\n    <th>translation missing: en, field_motion</th>\n    <th>User</th>\n    <th>translation missing: en, field_points</th>\n    <th>translation missing: en, field_isbinding</th>\n  </tr>\n\n<% @motion_votes.each do |motion_vote| %>\n  <tr>\n    <td><%=h motion_vote.motion_id %></td>\n    <td><%=h motion_vote.user_id %></td>\n    <td><%=h motion_vote.points %></td>\n    <td><%=h motion_vote.isbinding %></td>\n    <td><%= link_to 'Show', motion_vote %></td>\n    <td><%= link_to 'Edit', edit_motion_vote_path(motion_vote) %></td>\n    <td><%= link_to 'Destroy', motion_vote, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New motion_vote', new_motion_vote_path %>\n"
  },
  {
    "path": "app/views/motion_votes/new.html.erb",
    "content": "<h1>New motion_vote</h1>\n\n<% form_for(@motion_vote) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :motion_id %><br />\n    <%= f.text_field :motion_id %>\n  </p>\n  <p>\n    <%= f.label :user_id %><br />\n    <%= f.text_field :user_id %>\n  </p>\n  <p>\n    <%= f.label :points %><br />\n    <%= f.text_field :points %>\n  </p>\n  <p>\n    <%= f.label :isbinding %><br />\n    <%= f.check_box :isbinding %>\n  </p>\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', motion_votes_path %>\n"
  },
  {
    "path": "app/views/motion_votes/show.html.erb",
    "content": "<p>\n  <b>translation missing: en, field_motion:</b>\n  <%=h @motion_vote.motion_id %>\n</p>\n\n<p>\n  <b>User:</b>\n  <%=h @motion_vote.user_id %>\n</p>\n\n<p>\n  <b>translation missing: en, field_points:</b>\n  <%=h @motion_vote.points %>\n</p>\n\n<p>\n  <b>translation missing: en, field_isbinding:</b>\n  <%=h @motion_vote.isbinding %>\n</p>\n\n\n<%= link_to 'Edit', edit_motion_vote_path(@motion_vote) %> |\n<%= link_to 'Back', motion_votes_path %>\n"
  },
  {
    "path": "app/views/motions/_motions.html.erb",
    "content": "<%\n  count = 0\n %>\n <table border=\"0\" class=\"gt-table gt-user-table\">\n   <tbody>\n      <% @motions.each do |motion|\n        count = count + 1\n      %>\n      <tr class=\"motions-row <%= \"hidden\" if count > max_count %>\">\n        <td>\n          <p><strong>\n          <%= link_to(h(motion.project.name), :controller => 'projects', :action => 'show', :id => motion.project) + ': ' unless @project %>\n          <%= link_to h(motion.title), project_motion_path(motion.project_id,motion) %></strong><br><span class=\"small-text\">by <%= link_to_user(motion.author) %> <%= since_tag(motion.created_at) %> ago</span></p>\n\n        </td>\n      </tr>\n      <% end %>\n\n    <tr class=\"motions-show-more show-more <%= \"hidden\" unless count > max_count %>\">\n      <td colspan=\"2\">\n        <a href=\"\" onclick=\"$('.motions-row').show();$('.motions-show-more').hide();return false;\">Show <%= count - max_count %> more ...</a>\n      </td>\n    </tr>\n\n  </tbody>\n</table>\n"
  },
  {
    "path": "app/views/motions/edit.html.erb",
    "content": "<h1>Editing motion</h1>\n\n<% form_for(@motion) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :project_id %><br />\n    <%= f.text_field :project_id %>\n  </p>\n  <p>\n    <%= f.label :title %><br />\n    <%= f.text_field :title %>\n  </p>\n  <p>\n    <%= f.label :description %><br />\n    <%= f.text_area :description %>\n  </p>\n  <p>\n    <%= f.label :variation %><br />\n    <%= f.text_field :variation %>\n  </p>\n  <p>\n    <%= f.label :params %><br />\n    <%= f.text_area :params %>\n  </p>\n  <p>\n    <%= f.label :motion_type %><br />\n    <%= f.text_field :motion_type %>\n  </p>\n  <p>\n    <%= f.label :state %><br />\n    <%= f.text_field :state %>\n  </p>\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @motion %> |\n<%= link_to 'Back', motions_path %>\n"
  },
  {
    "path": "app/views/motions/eligible_users.html.erb",
    "content": "<% if @concerned_user_list.length > 0 %>\n\n<p id=\"select_concerned_user\">\n  <%= :Regarding %><br />\n  <%= collection_select(:motion, :concerned_user_id, @concerned_user_list, :user_id, :name, :prompt => l(:label_select)) %>\n</p>\n<% else %>\n\n<% case @variation\n  when Motion::VARIATION_NEW_MEMBER\n    %>You have no contributors to nominate for membership.<%\n  when Motion::VARIATION_NEW_CORE\n    %>You have no existing members to nominate to the core team.<%\n  when Motion::VARIATION_FIRE_MEMBER\n    %>You have no existing members to remove.<%\n  when Motion::VARIATION_FIRE_CORE\n    %>You have no existing core members to remove.<%\n  end\n%>\n <br><a href=\"http://help.bettermeans.com/membership\" target=\"blank\">Click here</a> to learn more about how membership rules work.\n <br>\n<% end %>\n"
  },
  {
    "path": "app/views/motions/index.html.erb",
    "content": "<div class=\"contextual\">\n</div>\n\n<h2>Listing motions</h2>\n\n<div class=\"gt-content-box\">\n<table class=\"gt-table\">\n  <tr>\n    <th>&nbsp;</th>\n    <th>Title</th>\n    <th>State</th>\n    <th>Vote Type</th>\n    <th>Details</th>\n  </tr>\n\n<% @motions.each do |motion| %>\n  <tr>\n    <td><%= motion.id %></td>\n    <td><%= link_to h(motion.title), project_motion_path(@project,motion) %></td>\n    <td><%=l \"label_motion_state#{h motion.state}\" %></td>\n    <td><%=l \"label_motion_vote_type#{h motion.motion_type}\" %></td>\n    <td><%=h motion.description %></td>\n  </tr>\n<% end %>\n</table>\n</div>\n\n<br />\n\n<% content_for :sidebar do %>\n<div class=\"gt-sidebar-nav gt-sidebar-nav-gray\">\n  <ul>\n  <li>\n    <%= link_to 'New motion', new_project_motion_path(@project)%>\n  </li>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/motions/new.html.erb",
    "content": "<%= help_section(\"motion_new\") %>\n\n<h2 class=\"icon icon-motion\">New motion</h2>\n\n<% form_for @motion, :url => {:action => \"create\", :project_id => @project.id} do |f| %>\n<div class=\"gt-content-box\">\n  <%= f.error_messages %>\n  <p>\n    <label>Motion type</label>\n    <%= select(:motion, :variation, Setting::MOTIONS.collect{|m| [ m[1][\"Title\"], m[0] ] }.sort,:prompt => l(:label_select)) %>\n  </p>\n  <p id=\"Description\">\n    <%= f.label :description %><br />\n    <%= f.text_area :description %>\n  </p>\n  <div id=\"eligible_users_container\"></div>\n  <%= observe_field :motion_variation, :url => {:controller => :motions, :action => :eligible_users, :only_path => :false }, :update => :eligible_users_container, :with => 'variation' %>\n  </div>\n  <p>\n  <%= f.submit 'Create' %>\n  </p>\n\n<% end %>\n\n<script type=\"text/javascript\">\n$('document').ready(function(){\n  hide_show_fields();\n  $(\"#motion_variation\").change(function(){\n    hide_show_fields();\n  });\n\n});\n\nfunction hide_show_fields(){\n  switch(parseInt($(\"#motion_variation\").val())){\n    case <%= Motion::VARIATION_NEW_MEMBER %>:\n      $(\"#select_concerned_user\").show();\n      $(\"#Description\").hide();\n      break;\n    case <%= Motion::VARIATION_NEW_CORE %>:\n      $(\"#select_concerned_user\").show();\n      $(\"#Description\").hide();\n      break;\n    case <%= Motion::VARIATION_FIRE_CORE %>:\n      $(\"#select_concerned_user\").show();\n      $(\"#Description\").hide();\n      break;\n    case <%= Motion::VARIATION_FIRE_MEMBER %>:\n      $(\"#select_concerned_user\").show();\n      $(\"#Description\").hide();\n      break;\n    default:\n      $(\"#select_concerned_user\").hide();\n      $(\"#Description\").show();\n      break;\n  }\n}\n\n</script>\n"
  },
  {
    "path": "app/views/motions/show.html.erb",
    "content": "<h2 class=\"gt-table-head\"><%= l :label_motion %> <%= h @motion.id %> : <%=h @topic.subject %></h2>\n<div class=\"gt-content-box\">\n<table class=\"gt-table gt-user-table\" border=\"0\">\n  <tbody>\n    <tr>\n    <% if @motion.concerned_user_id != nil %>\n           <td class=\"gt-avatar\">\n              <%= avatar(@motion.concerned_user, :size => '53') %><br>\n              <%= link_to_user_from_id @motion.concerned_user_id %>\n            </td>\n    <% end %>\n    <td>\n      <%= textilizable (h @motion.description) %>\n      <br><br>\n      <p>\n        <b>State:</b>\n        <%=l \"label_motion_state#{h @motion.state}\" %><br>\n        <b>Variation:</b>\n        <%=l \"label_motion_variation#{h @motion.variation}\" %><br>\n        <b>Vote Type:</b>\n        <%=l \"label_motion_vote_type#{h @motion.motion_type}\" %> (<%=l \"label_motion_vote_type#{h @motion.motion_type}_desc\" %>)<br>\n        <b>Minimum level needed to view:</b>\n        <%=\"#{h @motion.visibility_level_description}\" %><br>\n        <b>Minimum level for binding vote:</b>\n        <%=\"#{h @motion.binding_level_description}\" %><br>\n        <b>Discussion viewable by: </b>Everyone<br>\n      </p>\n\n    </td>\n         <td>\n           <table border=\"0\" class=\"gt-table-categories\">\n            <tr>\n               <th>by:</th>\n              <td><%= link_to_user(@topic.author) %></td>\n            </tr>\n            <tr>\n               <th>Added:</th>\n              <td><%= since_tag(@topic.created_at) %> ago</td>\n            </tr>\n            <tr>\n              <td colspan=\"2\"><%= render_title_date %></td>\n            </tr>\n          </table>\n         </td>\n      </tr>\n </tbody>\n</table>\n</div>\n\n\n<% unless @replies.empty? %>\n<h3 class=\"comments\"><%= l(:label_comment_plural) %></h3>\n<div class=\"gt-content-box\">\n<table class=\"gt-table gt-user-table\" border=\"0\">\n  <tbody>\n    <% @replies.each do |message| %>\n       <tr>\n         <td class=\"gt-avatar <%= User.current.logged? && User.current.id == @topic.author ? 'me' : nil %>\">\n           <%= avatar(message.author, :size => '53') %>\n         </td>\n         <td>\n           <div class=\"message reply\" id=\"<%= \"message-#{message.id}\" %>\">\n           <h4>\n             <%= link_to h(message.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => @topic, :anchor => \"message-#{message.id}\" } %>\n           </h4>\n           <div class=\"wiki\"><%= textilizable message, :content, :attachments => message.attachments %></div>\n      </div>\n\n         </td>\n         <td class=\"side\">\n           <table border=\"0\" class=\"gt-table-categories\">\n            <tr>\n              <td><%= link_to_user(message.author) %></td>\n            </tr>\n            <tr>\n              <td><%= since_tag(message.created_at) %> ago</td>\n            </tr>\n            <tr>\n              <td>\n              <%= link_to_remote_if_authorized image_tag('comment.png'), { :url => {:action => 'quote', :id => message} }, :title => l(:button_quote) %>\n              </td>\n              </tr>\n          </table>\n         </td>\n      </tr>\n    <% end %>\n </tbody>\n</table>\n</div>\n<% end %>\n\n<% if !@topic.locked? && authorize_for('messages', 'reply') %>\n<p><%= toggle_link l(:button_comment), \"reply\", {:focus => 'message_content', :class => 'gt-btn-gray-large'} %></p>\n<div id=\"reply\" style=\"display:none;\">\n<% form_for :reply, @reply, :url => {:action => 'reply', :id => @motion, :project_id => @project}, :html => {:multipart => true, :id => 'message-form'} do |f| %>\n  <%= render :partial => 'messages/form', :locals => {:f => f, :replying => true} %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_submit), :disable_with => l(:button_working) %>\n  <p class=\"gt-cancel\">\n  <%= link_to_remote l(:label_preview),\n                     { :url => { :controller => 'messages', :action => 'preview', :board_id => @board },\n                       :method => 'post',\n                       :update => 'preview',\n                       :with => \"$('#message-form').serialize()\",\n                       :complete => \"$('body').scrollTo('#preview')\"\n                     }, :accesskey => accesskey(:preview) %>\n  </p>\n  </div>\n<% end %>\n<div id=\"preview\" class=\"wiki\"></div>\n</div>\n<% end %>\n\n<% content_for :header_tags do %>\n  <%= stylesheet_link_tag 'scm' %>\n<% end %>\n\n<% html_title h(@topic.subject) %>\n\n<% content_for :sidebar do %>\n<br>\n<h3><%= render_title_date %></h3>\n<%= render :partial => \"motion_votes/vote\", :locals => {:motion => @motion} %>\n<% end %>\n\n<script type=\"text/javascript\">\n  projectId = <%= @project.id %>;\n</script>\n"
  },
  {
    "path": "app/views/my/_belong_to_projects.html.erb",
    "content": "      <table border=\"0\" class=\"gt-table gt-user-table\">\n           <%   project_tree_sorted(belong_to_projects) do |p, level|\n              name_prefix = (level > 0 ? ('&nbsp;' * 4 * level + '&#187; ') : '')\n           %>\n           <tr><td>\n           <%= name_prefix + link_to(h(p), :controller => 'projects', :action => 'show', :id => p)  %><%= volunteering p %><%= privacy p %>\n             <% array = p.activity_line_show(30) %>\n             </td><td>\n             <span class=\"spark right\" max=\"<%=  p.activity_line_max %>\"><%= p.activity_line_show(30) %></span>\n             </td></tr>\n           <% end %>\n      </table>\n"
  },
  {
    "path": "app/views/my/_billing_form.html.erb",
    "content": "<p><%= f.text_field :b_first_name %></p>\n<p><%= f.text_field :b_last_name %></p>\n<p><%= f.text_field :b_address1 %></p>\n<p><%= f.select :b_country, options_for_select(country_hash.sort, :selected => \"US\") %></p>\n<p><%= f.text_field :b_zip %></p>\n<p><%= f.text_field :b_phone %></p>\n<img width=\"27\" height=\"19\" src=\"/images/visa.png\" alt=\"Visa\">\n<img width=\"27\" height=\"19\" src=\"/images/mastercard.png\" alt=\"MasterCard\">\n<img width=\"27\" height=\"19\" src=\"/images/amex.png\" alt=\"AmEx\">\n<img width=\"27\" height=\"19\" src=\"/images/discover.png\" alt=\"Discover\">\n<p><%= f.text_field :b_cc_last_four %></p>\n<table style=\"width:100%;\"><tr><td>\n<p>\n  <%= f.select :b_cc_month, options_for_select(month_hash, :selected => @user.b_cc_month || Date.today.month) %>\n  <%= f.select :b_cc_year, options_for_select(year_hash.sort, :selected => @user.b_cc_year || Date.today.year) %>\n</p>\n</td><td style=\"vertical-align:top;\">\n<p><label><%= l(:label_b_verification_code) %></label> <%= text_field \"\", \"ccverify\", :size => 5, :class => \"verification-code\" %><img src=\"/images/cvv-glyph.png\" alt=\"CVV\"></p>\n</td></tr></table>\n"
  },
  {
    "path": "app/views/my/_block.html.erb",
    "content": "<div id=\"block_<%= block_name.dasherize %>\" class=\"mypage-box\">\n\n    <div style=\"float:right;margin-right:16px;z-index:500;\">\n    <%= link_to_remote \"\", {\n        :url => { :action => \"remove_block\", :block => block_name },\n        :complete => \"removeBlock('block_#{block_name.dasherize}')\" },\n        :class => \"close-icon\"\n         %>\n    </div>\n\n    <div class=\"handle\">\n  <%= render :partial => \"my/blocks/#{block_name}\", :locals => { :user => user } %>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/my/_my_projects.html.erb",
    "content": "<table border=\"0\" class=\"gt-table gt-user-table  project-table\" id=\"<%= table_id %>\">\n    <%   project_tree_sorted(my_projects) do |p, level|\n        name_prefix = (level > 0 ? ('&nbsp;' * 4 * level + '&#187; ') : '')\n     %>\n      <tr><td>\n      <%=name_prefix + link_to(h(p), :controller => 'projects', :action => 'show', :id => p)  %><%= volunteering p %><%= privacy p %>\n    <% if p.archived? %>\n      <% if User.current.allowed_to?({:controller => 'projects', :action => 'unarchive'}, p) %>\n        <%= link_to_remote(l(:label_unarchive_project_brackets), :url => {:controller => 'projects', :action => 'unarchive', :id => p, :table_id => table_id}, :confirm => l(:text_confirm_unarchive_project)) %>\n      <% else  %>\n        (archived)\n      <% end %>\n    <% end %>\n    <% if p.locked? %>\n       <%= link_to \"(locked)\", {:controller => 'my', :action => 'upgrade'}  %>\n    <% end %>\n        <span class=\"spark right\" max=\"<%=  p.activity_line_max %>\"><%= p.activity_line_show(60) %></span>\n        </td></tr>\n      <% end %>\n</table>\n"
  },
  {
    "path": "app/views/my/_plan_description.html.erb",
    "content": "    <ul>\n    <li><p><span style=\"float:right;width:35%\">$<%= plan.amount.round %> monthly</span><span style=\"float:right;width:65%\">Cost</span></p>\n    </li>\n    <li><p><span style=\"float:right;width:35%\"><%= describe plan.storage_max %> GB</span><span style=\"float:right;width:65%\">Storage</span></p>\n    </li>\n    <li><p><span style=\"float:right;width:35%\"><%= describe plan.private_workstream_max %></span><span style=\"float:right;width:65%\">Private Workstreams</span></p>\n    </li>\n    <li><p><span style=\"float:right;width:35%\"><%= describe plan.contributor_max %></span><span style=\"float:right;width:65%\">Private Collaborators</span></p>\n    </li>\n    <li><p><span style=\"float:right;width:35%\"><%= describe plan.public_workstream_max %></span><span style=\"float:right;width:65%\">Public Workstreams</span></p>\n    </li>\n    <li><p><span style=\"float:right;width:35%\">unlimited</span><span style=\"float:right;width:65%\">Public Collaborators</span></p>\n    </li>\n    </ul>\n"
  },
  {
    "path": "app/views/my/_plan_descriptions.html.erb",
    "content": "<div class=\"gt-sidebar-nav gt-sidebar-nav-blue\">\n  <span id=\"plan_description\">\n    <ul>\n    <li>\n      <p style=\"width:100;\">\n        <span style=\"float:right;width:20%\"><strong>Storage</strong></span>\n        <span style=\"float:right;width:25%\"><strong>Workstreams</strong></span>\n        <span style=\"float:right;width:25%\"><strong>Contributors</strong></span>\n        <span style=\"float:right;width:30%\"><strong>Plan</strong></span>\n      </p>\n    </li>\n    <% Plan.find(:all, :order => \"CODE asc\").each do |plan| %>\n    <li>\n      <p style=\"width:100;\">\n      <span style=\"float:right;width:20%\"><%= describe plan.storage_max %> GB</span>\n      <span style=\"float:right;width:25%\"><%= describe plan.private_workstream_max %></span>\n      <span style=\"float:right;width:25%\"><%= describe plan.contributor_max %></span>\n      <span style=\"float:right;width:30%\"><%= radio_button(:user,:plan_id, plan.id) %>&nbsp;<%= plan.name %>($<%= plan.amount.round %>/month)</span>\n      </p>\n    </li>\n    <% end %>\n  </ul>\n  </span>\n</div>\n"
  },
  {
    "path": "app/views/my/_project_list.html.erb",
    "content": "    <% if my_projects.length > 0 %>\n    <div class=\"gt-content-box\">\n      <%= render :partial => 'my_projects', :locals => {:my_projects => my_projects, :table_id => table_id}  %>\n    </div>\n    <div class=\"gt-table-buttons\">\n      <%= table_bottom_link %>\n    </div>\n    <% else %>\n    <div class=\"gt-content-box centered padded\">\n      <h4><%= no_data_help %></h4>\n      <p class='nodata'>\n            <h3> <%= no_data_link %> </h3>\n         </p>\n    </div>\n    <% end %>\n"
  },
  {
    "path": "app/views/my/_sidebar.html.erb",
    "content": "<div class=\"gt-sidebar-nav gt-sidebar-nav-blue\">\n  <h3>General</h3>\n  <ul>\n  <li><p><span style=\"float:right;width:70%\"><%= @user.login %></span><span style=\"float:right;width:30%\"><%=l(:field_login)%></span></p>\n  </li>\n  <li><p><span style=\"float:right;width:70%\"><%= format_time(@user.created_at) %></span><span style=\"float:right;width:30%\"><%=l(:field_created_at)%></span></p>\n  </li>\n  <li>\n  </li>\n  </ul>\n</div>\n<h3><%= l(:label_current_plan) %></h3>\n<%= render :partial => \"usage_stats\" %>\n<%= upgrade_options User.current %>\n"
  },
  {
    "path": "app/views/my/_usage_stats.html.erb",
    "content": "<% plan = User.current.plan %>\n<div class=\"gt-sidebar-nav gt-sidebar-nav-gray\">\n  <h3><%= plan.name %> Plan</h3>\n  <ul>\n    <% if @user.trial_expires_on && @user.trial_expires_on >= DateTime.now %>\n    <li><p><span style=\"float:right;width:35%\"><%= distance_of_date_in_words(DateTime.now, @user.trial_expires_on)  %> </span><span style=\"float:right;width:65%\">Trial Expires in</span></p>\n    </li>\n    <% elsif @user.trial_expires_on %>\n    <li><p><span style=\"float:right;width:35%\"><%= distance_of_date_in_words(DateTime.now, @user.trial_expires_on)  %> ago </span><span style=\"float:right;width:65%\">Trial Expired!</span></p>\n    </li>\n    <% end  %>\n  <li><p><span style=\"float:right;width:35%\">$<%= plan.amount.round %> monthly</span><span style=\"float:right;width:65%\">Cost</span></p>\n  </li>\n  <li><p><span style=\"float:right;width:35%\"><%= User.current.project_storage_total %> / <%= describe plan.storage_max %> GB</span><span style=\"float:right;width:65%\">Storage</span></p>\n  </li>\n  <li><p><span style=\"float:right;width:35%\"><%= User.current.private_project_total %> / <%= describe plan.private_workstream_max %></span><span style=\"float:right;width:65%\">Private Workstreams</span></p>\n  </li>\n  <li><p><span style=\"float:right;width:35%\"><%= User.current.private_contributor_total %> / <%= describe plan.contributor_max %></span><span style=\"float:right;width:65%\">Private Collaborators</span></p>\n  </li>\n  <li><p><span style=\"float:right;width:35%\"><%= User.current.public_project_total %> / <%= describe plan.public_workstream_max %></span><span style=\"float:right;width:65%\">Public Workstreams</span></p>\n  </li>\n  <li><p><span style=\"float:right;width:35%\"><%= User.current.public_contributor_total %> / unlimited</span><span style=\"float:right;width:65%\">Public Collaborators</span></p>\n  </li>\n  </ul>\n</div>\n"
  },
  {
    "path": "app/views/my/account.html.erb",
    "content": "<% content_for :mainmenu do %>\n  <%= render :partial => 'common/main_menu_home', :locals => {:active_page => :myaccount} %>\n<% end %>\n\n\n<%= help_section(\"my_account\") %>\n<%= error_messages_for 'user' %>\n\n<% form_for :user, @user, :url => { :action => \"account\" },\n                          :builder => TabularFormBuilder,\n                          :lang => current_language,\n                          :html => { :id => 'my_account_form' } do |f| %>\n<div class=\"splitcontentleft\">\n<h3><%=l(:label_personal_information)%></h3>\n<div class=\"gt-content-box tabular\">\n<p><%= f.text_field :firstname, :required => true %></p>\n<p><%= f.text_field :lastname, :required => true %></p>\n<p><%= f.text_field :login, :required => true %></p>\n<p><%= f.text_field :mail, :required => true, :readonly => true, :disabled => true %> <%= link_to l(:label_change), :controller => :email_updates, :action => :new %></p>\n<p><%= f.select :language, lang_options_for_select %></p>\n<div class=\"gt-table-buttons-inside\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n</div>\n\n<% if !User.current.b_cc_last_four.nil? %>\n  <h3><%=l(:label_billing_information)%></h3>\n  <div class=\"gt-content-box tabular\">\n  <%= render :partial => 'billing_form', :locals => {:f => f} %>\n    <div class=\"gt-table-buttons-inside\">\n    <%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n    </div>\n  </div>\n<% end %>\n\n</div>\n\n<div class=\"splitcontentright\">\n<h3><%=l(:field_mail_notification)%></h3>\n<div class=\"gt-content-box\">\n  <div id=\"email_notifications\">\n    <%= select_tag 'notification_option', options_for_select(@notification_options, @notification_option),\n                                          :onchange => 'if ($(\"#notification_option\").val() == \"selected\") {$(\"#notified-projects\").show();} else {$(\"#notified-projects\").hide();alert(ad)}' %>\n    <% content_tag 'div', :id => 'notified-projects', :style => (@notification_option == 'selected' ? '' : 'display:none;') do %>\n    <p><% User.current.projects.each do |project| %>\n        <label><%= check_box_tag 'notified_project_ids[]', project.id, @user.notified_projects_ids.include?(project.id) %> <%=h project.name %></label><br />\n    <% end %></p>\n    <p><em><%= l(:text_user_mail_option) %></em></p>\n    <% end %>\n    <br><br>\n    <p><label><%= check_box_tag 'no_self_notified', 1, @user.pref[:no_self_notified] %> <%= l(:label_user_mail_no_self_notified) %></label></p>\n    <p><label><%= check_box_tag 'daily_digest', 1, @user.pref[:daily_digest] %> <%= l(:label_user_mail_daily_digest) %></label></p>\n  </div>\n<p><label><%= check_box_tag 'no_emails', 1, @user.pref[:no_emails], :onclick=>\"show_hide_notification_form(this);\", :id => \"no_emails_checkbox\" %> <%= l(:label_user_mail_no_emails) %></label></p>\n<div class=\"gt-table-buttons-inside\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n</div>\n\n<h3><%=l(:label_preferences)%></h3>\n<div class=\"gt-content-box tabular\">\n<% fields_for :pref, @user.pref, :builder => TabularFormBuilder, :lang => current_language do |pref_fields| %>\n<p></p>\n<p><label><%= check_box_tag 'pref[hide_mail]', 1, @user.pref[:hide_mail] %> <%= l(:field_hide_mail) %></label></p>\n<p><label><%= check_box_tag 'pref[active_only_jumps]', 1, @user.pref[:active_only_jumps] %> <%= l(:field_active_only_jumps) %></label></p>\n<p><%= pref_fields.select :time_zone, ActiveSupport::TimeZone.all.collect {|z| [ z.to_s, z.name ]}, :include_blank => true %></p>\n<% end %>\n<div class=\"gt-table-buttons-inside\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n</div>\n\n<h3><%=l(:label_your_gravatar)%></h3>\n<div class=\"gt-content-box padded\">\n  <p width=\"100%\">\n  <%= avatar User.current, :class => \"gt-avatar-small\" %>\n  <%= l(:text_your_gravatar) %>\n  </p>\n</div>\n\n<h3><%=l(:label_data_dump)%></h3>\n<div class=\"gt-content-box padded\">\n  <p width=\"100%\">\n  <%= l(:text_data_dump) %>&nbsp;&nbsp;\n  <%= link_to l(:label_issues), {:controller => :issues, :action => :datadump, :format => :csv}, {:class => \"icon icon-attachment\"} %>\n  </p>\n</div>\n\n\n</div>\n<% end %>\n\n<% content_for :actionmenu do %>\n<ul>\n  <li>\n    <%= link_to l(:button_change_password), {:action => 'password'}, :class => \"icon icon-edit\" %>\n  </li>\n  <li>\n    <%= link_to l(:label_cancel_account), {:controller => 'account', :action => 'cancel'}, :confirm => l(:text_confirm_cancel_account), :class => \"icon icon-del\" %>\n  </li>\n</ul>\n<% end %>\n\n\n<% content_for :sidebar do %>\n<h3>&nbsp;</h3>\n<%= render :partial => 'sidebar' %>\n<% end %>\n\n<% html_title(l(:label_my_account)) -%>\n\n<script type=\"text/javascript\">\n$('document').ready(function(){\n  show_hide_notification_form();\n});\n\nfunction show_hide_notification_form(){\n  if ($('#no_emails_checkbox:checked').attr(\"checked\")) {\n  $('#email_notifications').hide();\n  }\n  else{\n    $('#email_notifications').show();\n  }\n}\n</script>\n"
  },
  {
    "path": "app/views/my/blocks/_calendar.html.erb",
    "content": "<h3><%= l(:label_calendar) %></h3>\n\n<% calendar = Redmine::Helpers::Calendar.new(Date.today, current_language, :week)\n   calendar.events = Issue.find :all,\n                     :conditions => [\"#{Issue.table_name}.project_id in (#{@user.projects.collect{|m| m.id}.join(',')}) AND ((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?))\", calendar.startdt, calendar.enddt, calendar.startdt, calendar.enddt],\n                     :include => [:project, :tracker, :assigned_to] unless @user.projects.empty? %>\n\n<%= render :partial => 'common/calendar', :locals => {:calendar => calendar } %>\n"
  },
  {
    "path": "app/views/my/blocks/_documents.html.erb",
    "content": "<h3><%=l(:label_document_plural)%></h3>\n\n<% project_ids = @user.projects.select {|p| @user.allowed_to?(:view_documents, p)}.collect(&:id) %>\n<%= render(:partial => 'documents/document',\n           :collection => Document.find(:all,\n                         :limit => 10,\n                         :order => \"#{Document.table_name}.created_at DESC\",\n                         :conditions => \"#{Document.table_name}.project_id in (#{project_ids.join(',')})\",\n                         :include => [:project])) unless project_ids.empty? %>\n"
  },
  {
    "path": "app/views/my/blocks/_issuesassignedtome.html.erb",
    "content": "<% if assigned_issues.length > 0 %>\n\n<%= render :partial => 'issues/list_very_simple', :locals => { :issues => assigned_issues } %>\n\n<% end %>\n"
  },
  {
    "path": "app/views/my/blocks/_issuesreportedbyme.html.erb",
    "content": "<h3><%=l(:label_reported_issues)%> (<%= Issue.visible.count(:conditions => { :author_id => User.current.id }) %>)</h3>\n\n<% reported_issues = Issue.visible.find(:all,\n                                :conditions => { :author_id => User.current.id },\n                                :limit => 10,\n                                :include => [ :status, :project, :tracker ],\n                                :order => \"#{Issue.table_name}.updated_at DESC\") %>\n<%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %>\n<% if reported_issues.length > 0 %>\n<p class=\"small\"><%= link_to l(:label_issue_view_all), :controller => 'issues',\n                                                       :action => 'index',\n                                                       :set_filter => 1,\n                                                       :status_id => '*',\n                                                       :author_id => 'me',\n                                                       :sort => 'updated_at:desc' %></p>\n<% end %>\n"
  },
  {
    "path": "app/views/my/blocks/_issueswatched.html.erb",
    "content": "<% unless watched_issues.length == 0  %>\n  <%= render :partial => 'issues/list_very_simple', :locals => { :issues => watched_issues } %>\n<% end %>\n"
  },
  {
    "path": "app/views/my/blocks/_news.html.erb",
    "content": "<%\nmaxcount ||= 1\nif @news && @news.any?\n  %>\n<h2 class=\"gt-table-head icon icon-news\"><%=l(:label_news_latest)%></h2>\n<div class=\"news gt-content-box\">\n  <%= render :partial => 'news/news', :locals => {:max_count => maxcount} %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/my/issues.html.erb",
    "content": "<%# @page_header_name = \"My Items\" %>\n<% content_for :mainmenu do %>\n  <%= render :partial => 'common/main_menu_home', :locals => {:active_page => :myissues} %>\n<% end %>\n\n<%= render_tabs my_issues_tabs %>\n\n<% content_for :actionmenu do %>\n    <ul>\n    <li>\n      <%= link_to l(:label_project_new), {:controller => 'projects', :action => 'add', :parent_id => @project}, :class => \"icon icon-add\" %>\n    </li>\n    </ul>\n    <ul>\n    <li>\n      <%= link_to l(:label_browse_workstreams), {:controller => 'projects', :action => 'index'}, :class => \"icon icon-projects\" %>\n    </li>\n    </ul>\n<% end %>\n"
  },
  {
    "path": "app/views/my/page.html.erb",
    "content": "<div class=\"contextual\">\n    <%= link_to l(:label_personalize_page), :action => 'page_layout' %>\n</div>\n\n<h2><%=l(:label_my_page)%></h2>\n\n<div id=\"list-top\">\n  <% @blocks['top'].each do |b|\n     next unless MyController::BLOCKS.keys.include? b  %>\n  <div class=\"mypage-box\">\n    <%= render :partial => \"my/blocks/#{b}\", :locals => { :user => @user } %>\n  </div>\n  <% end if @blocks['top'] %>\n</div>\n\n<div id=\"list-left\" class=\"splitcontentleft\">\n  <% @blocks['left'].each do |b|\n     next unless MyController::BLOCKS.keys.include? b %>\n  <div class=\"mypage-box\">\n    <%= render :partial => \"my/blocks/#{b}\", :locals => { :user => @user } %>\n  </div>\n  <% end if @blocks['left'] %>\n</div>\n\n<div id=\"list-right\" class=\"splitcontentright\">\n  <% @blocks['right'].each do |b|\n     next unless MyController::BLOCKS.keys.include? b %>\n  <div class=\"mypage-box\">\n    <%= render :partial => \"my/blocks/#{b}\", :locals => { :user => @user } %>\n  </div>\n  <% end if @blocks['right'] %>\n</div>\n\n<% content_for :header_tags do %>\n    <%= javascript_include_tag 'context_menu' %>\n    <%= stylesheet_link_tag 'context_menu' %>\n<% end %>\n\n<div id=\"context-menu\" style=\"display: none;\"></div>\n<%= javascript_tag \"new ContextMenu('#{url_for(:controller => 'issues', :action => 'context_menu')}')\" %>\n\n<% html_title(l(:label_my_page)) -%>\n"
  },
  {
    "path": "app/views/my/page_layout.html.erb",
    "content": "<script language=\"JavaScript\">\n//<![CDATA[\nfunction recreateSortables() {\n    Sortable.destroy('list-top');\n    Sortable.destroy('list-left');\n    Sortable.destroy('list-right');\n\n  Sortable.create(\"list-top\", {constraint:false, containment:['list-top','list-left','list-right'], dropOnEmpty:true, handle:'handle', onUpdate:function(){new Ajax.Request('/my/order_blocks?group=top', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(\"list-top\")})}, only:'mypage-box', tag:'div'})\n  Sortable.create(\"list-left\", {constraint:false, containment:['list-top','list-left','list-right'], dropOnEmpty:true, handle:'handle', onUpdate:function(){new Ajax.Request('/my/order_blocks?group=left', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(\"list-left\")})}, only:'mypage-box', tag:'div'})\n  Sortable.create(\"list-right\", {constraint:false, containment:['list-top','list-left','list-right'], dropOnEmpty:true, handle:'handle', onUpdate:function(){new Ajax.Request('/my/order_blocks?group=right', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(\"list-right\")})}, only:'mypage-box', tag:'div'})\n}\n\nfunction updateSelect() {\n    s = $('block-select')\n    for (var i = 0; i < s.options.length; i++) {\n        if ($('block_' + s.options[i].value)) {\n            s.options[i].disabled = true;\n        } else {\n            s.options[i].disabled = false;\n        }\n    }\n    s.options[0].selected = true;\n}\n\nfunction afterAddBlock() {\n    recreateSortables();\n    updateSelect();\n}\n\nfunction removeBlock(block) {\n    Effect.DropOut(block);\n    updateSelect();\n}\n//]]>\n</script>\n\n<div class=\"contextual\">\n<% form_tag({:action => \"add_block\"}, :id => \"block-form\") do %>\n<%= select_tag 'block', \"<option></option>\" + options_for_select(@block_options), :id => \"block-select\" %>\n<%= link_to_remote l(:button_add),\n           {:url => { :action => \"add_block\" },\n            :with => \"Form.serialize('block-form')\",\n            :update => \"list-top\",\n            :position => :top,\n            :complete => \"afterAddBlock();\"\n           }, :class => 'icon icon-add'\n             %>\n<% end %>\n<%= link_to l(:button_back), {:action => 'page'}, :class => 'icon icon-cancel' %>\n</div>\n\n<h2><%=l(:label_my_page)%></h2>\n\n<div id=\"list-top\" class=\"block-receiver\">\n  <% @blocks['top'].each do |b|\n     next unless MyController::BLOCKS.keys.include? b %>\n  <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %>\n  <% end if @blocks['top'] %>\n</div>\n\n<div id=\"list-left\" class=\"splitcontentleft block-receiver\">\n  <% @blocks['left'].each do |b|\n     next unless MyController::BLOCKS.keys.include? b %>\n  <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %>\n  <% end if @blocks['left'] %>\n</div>\n\n<div id=\"list-right\" class=\"splitcontentright block-receiver\">\n  <% @blocks['right'].each do |b|\n     next unless MyController::BLOCKS.keys.include? b %>\n  <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %>\n  <% end if @blocks['right'] %>\n</div>\n\n<%= sortable_element 'list-top',\n      :tag => 'div',\n      :only => 'mypage-box',\n      :handle => \"handle\",\n      :dropOnEmpty => true,\n      :containment => ['list-top', 'list-left', 'list-right'],\n      :constraint => false,\n      :url => { :action => \"order_blocks\", :group => \"top\" }\n       %>\n\n\n<%= sortable_element 'list-left',\n      :tag => 'div',\n      :only => 'mypage-box',\n      :handle => \"handle\",\n      :dropOnEmpty => true,\n      :containment => ['list-top', 'list-left', 'list-right'],\n      :constraint => false,\n      :url => { :action => \"order_blocks\", :group => \"left\" }\n       %>\n\n<%= sortable_element 'list-right',\n      :tag => 'div',\n      :only => 'mypage-box',\n      :handle => \"handle\",\n      :dropOnEmpty => true,\n      :containment => ['list-top', 'list-left', 'list-right'],\n      :constraint => false,\n      :url => { :action => \"order_blocks\", :group => \"right\" }\n       %>\n\n<%= javascript_tag \"updateSelect()\" %>\n"
  },
  {
    "path": "app/views/my/password.html.erb",
    "content": "<h2><%=l(:button_change_password)%></h2>\n\n<%= error_messages_for 'user' %>\n\n<% form_tag({}, :class => \"tabular\") do %>\n<div class=\"gt-content-box\">\n<p><label for=\"password\"><%=l(:field_password)%> <span class=\"required\">*</span></label>\n<%= password_field_tag 'password', nil, :size => 25 %></p>\n\n<p><label for=\"new_password\"><%=l(:field_new_password)%> <span class=\"required\">*</span></label>\n<%= password_field_tag 'new_password', nil, :size => 25 %><br />\n<em><%= l(:text_caracters_minimum, :count => Setting.password_min_length) %></em></p>\n\n<p><label for=\"new_password_confirmation\"><%=l(:field_password_confirmation)%> <span class=\"required\">*</span></label>\n<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %></p>\n</div>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_apply), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n\n<% content_for :sidebar do %>\n<%= render :partial => 'sidebar' %>\n<% end %>\n"
  },
  {
    "path": "app/views/my/projects.html.erb",
    "content": "<%# @page_header_name = \"My Workstreams\" %>\n<% content_for :mainmenu do %>\n  <%= render :partial => 'common/main_menu_home', :locals => {:active_page => :myprojects} %>\n<% end %>\n\n<%= render_tabs my_projects_tabs %>\n\n<% content_for :actionmenu do %>\n    <ul>\n    <li>\n      <%= link_to l(:label_project_new), {:controller => 'projects', :action => 'add', :parent_id => @project}, :class => \"icon icon-add\" %>\n    </li>\n    </ul>\n    <ul>\n    <li>\n      <%= link_to l(:label_browse_workstreams), {:controller => 'projects', :action => 'index'}, :class => \"icon icon-projects\" %>\n    </li>\n    </ul>\n<% end %>\n\n<script>\n  $('document').ready(function(){\n    display_sparks();\n  });\n\n  $('.tab-top').click(function(){\n    display_sparks();\n  })\n</script>\n"
  },
  {
    "path": "app/views/my/upgrade.html.erb",
    "content": "<% content_for :mainmenu do %>\n  <%= render :partial => 'common/main_menu_home', :locals => {:active_page => :myaccount} %>\n<% end %>\n<% form_for :user, @user, :url => { :action => \"upgrade\" },\n                          :builder => TabularFormBuilder,\n                          :lang => current_language,\n                          :html => { :id => 'my_upgrade_form' } do |f| %>\n\n<div class=\"gt-left-col\">\n  <h3><%= l(:label_current_plan) %></h3>\n  <%= render :partial => \"usage_stats\" %>\n  <h3><%=l(:label_select_plan)%></h3>\n  <%= render :partial => 'plan_descriptions', :locals => {:current_plan => User.current.plan} %>\n  <div class=\"gt-table-buttons-inside\" id=\"change_plan_button\">\n  <%= submit_tag l(:button_change_plan), :disable_with => \"changing plan...\" %>\n  </div>\n</div>\n\n<div class=\"gt-right-col\">\n  <h3><%=l(:label_billing_information)%></h3>\n  <div class=\"gt-content-box tabular\">\n  <%= render :partial => 'billing_form', :locals => {:f => f} %>\n    <div class=\"gt-table-buttons-inside\" id=\"change_plan_button\">\n    <%= submit_tag l(:button_update_billing), :disable_with => \"updating...\" %>\n    </div>\n  </div>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/news/_form.html.erb",
    "content": "<%= error_messages_for 'news' %>\n<div class=\"gt-content-box tabular\">\n<p><%= f.text_field :title, :required => true, :size => 60 %></p>\n<p><%= f.text_area :summary, :cols => 60, :rows => 2, \"autocomplete-mentions-projectid\" => @project.id %></p>\n<p><label>Description</label><%= f.textile_editor :description, :required => true, :cols => 60, :rows => 15, :class => 'wiki-edit', \"autocomplete-mentions-projectid\" => @project.id %></p>\n</div>\n\n"
  },
  {
    "path": "app/views/news/_news.html.erb",
    "content": "<%\n  count = 0\n %>\n <table border=\"0\" class=\"gt-table gt-user-table\">\n   <tbody>\n     <% @news.each do |news_item|\n       count = count + 1\n        %>\n       <tr class=\"news-row <%= \"hidden\" if count > max_count %>\">\n         <td>\n           <span class=\"small-text right\">&nbsp;&nbsp;<%= link_to_user(news_item.author) %>, <%= since_tag(news_item.created_at) %> ago\n             <% if news_item.comments_count > 0 %>\n               , <%=link_to l(:label_x_comments, :count => news_item.comments_count), :controller => 'news', :action => 'show', :id => news_item.id %>\n             <% end %>\n           </span>\n           <p><strong>\n           <%= link_to(h(news_item.project.name), :controller => 'projects', :action => 'show', :id => news_item.project) + ': ' unless @project %>\n           <%= link_to h(news_item.title), :controller => 'news', :action => 'show', :id => news_item.id %></strong>&nbsp;<%=h news_item.summary %>\n          </p>\n         </td>\n       </tr>\n     <% end %>\n     <tr class=\"news-show-more show-more <%= \"hidden\" unless count > max_count %>\">\n       <td colspan=\"2\">\n         <a href=\"\" onclick=\"$('.news-row').show();$('.news-show-more').hide();return false;\">Show <%= count - max_count %> more ...</a>\n       </td>\n     </tr>\n\n   </tbody>\n </table>\n\n"
  },
  {
    "path": "app/views/news/edit.html.erb",
    "content": "<h2><%=l(:label_news)%></h2>\n\n<% labelled_tabular_form_for :news, @news, :url => { :action => \"edit\" },\n                                           :html => { :id => 'news-form' } do |f| %>\n<%= render :partial => 'form', :locals => { :f => f } %>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n<p class=\"gt-cancel\">\n<%= link_to_remote l(:label_preview),\n                   { :url => { :controller => 'news', :action => 'preview', :project_id => @project },\n                     :method => 'post',\n                     :update => 'preview',\n                     :with => \"Form.serialize('news-form')\"\n                   }, :accesskey => accesskey(:preview) %>\n</p></div>\n<% end %>\n<div id=\"preview\" class=\"wiki\"></div>\n"
  },
  {
    "path": "app/views/news/index.html.erb",
    "content": "<%= help_section(\"project_news\") %>\n\n<div id=\"add-news\" style=\"display:none;\">\n<h2><%=l(:label_news_new)%></h2>\n<% labelled_tabular_form_for :news, @news, :url => { :controller => 'news', :action => 'new', :project_id => @project },\n                                           :html => { :id => 'news-form' } do |f| %>\n<%= render :partial => 'news/form', :locals => { :f => f } %>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n<p class=\"gt-cancel\">\n<%= link_to_remote l(:label_preview),\n                   { :url => { :controller => 'news', :action => 'preview', :project_id => @project },\n                     :method => 'post',\n                     :update => 'preview',\n                     :with => \"$('#news-form').serialize()\"\n                   }, :accesskey => accesskey(:preview) %> |\n<%= link_to l(:button_cancel), \"#\", :onclick => '$(\"#add-news\").hide()' %>\n</p>\n</div>\n<% end if @project %>\n<div id=\"preview\" class=\"wiki\"></div>\n<br><br>\n</div>\n\n<h2 class=\"gt-table-head\"><%=l(:label_news_plural)%></h2>\n<div class=\"gt-content-box\">\n<% if @newss.empty? %>\n<p class=\"nodata\"><%= l(:label_no_data) %></p>\n<% else %>\n<table border=\"0\" class=\"gt-table gt-user-table\">\n  <tbody>\n\n<% @newss.each do |news| %>\n<tr>\n  <td>\n  <h4>\n    <%= link_to(h(news.project.name), :controller => 'projects', :action => 'show', :id => news.project) + ': ' unless news.project == @project %>\n    <%= link_to h(news.title), :controller => 'news', :action => 'show', :id => news %>\n    <%= \"(#{l(:label_x_comments, :count => news.comments_count)})\" if news.comments_count > 0 %>\n    </h4>\n    <%= textilizable(news.description) %>\n  </td>\n  <td>\n    <table border=\"0\" class=\"gt-table-categories\">\n      <tr>\n        <td><%= link_to_user_from_id(news.author) %></td>\n      </tr>\n      <tr>\n        <td><%= since_tag(news.created_at) %> ago</td>\n      </tr>\n    </table>\n  </td>\n</tr>\n\n<% end %>\n  </tbody>\n</table>\n<div class=\"gt-table-controls gt-table-controls-btm clearfix\">\n  <p class=\"gt-table-pager\"><%= pagination_links_full @news_pages %></p>\n</div>\n<% end %>\n</div>\n\n<% content_for :actionmenu do %>\n  <ul>\n  <li>\n    <%= link_to_if_authorized(l(:label_news_new),\n                              {:controller => 'news', :action => 'new', :project_id => @project},\n                              :class => 'icon icon-add',\n                              :onclick => '$(\"#add-news\").show(); $(\"#news_title\").focus(); return false;') if @project %>\n  </li>\n  </ul>\n<% end %>\n\n<% html_title(l(:label_news_plural)) -%>\n"
  },
  {
    "path": "app/views/news/new.html.erb",
    "content": "<h2><%=l(:label_news_new)%></h2>\n\n<% labelled_tabular_form_for :news, @news, :url => { :controller => 'news', :action => 'new', :project_id => @project },\n                                           :html => { :id => 'news-form' } do |f| %>\n<%= render :partial => 'news/form', :locals => { :f => f } %>\n<%= textile_editor_initialize(:framework => :jquery) %>\n\n<div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n\n<p class=\"gt-cancel\">\n<%= link_to_remote l(:label_preview),\n                   { :url => { :controller => 'news', :action => 'preview', :project_id => @project },\n                     :method => 'post',\n                     :update => 'preview',\n                     :with => \"Form.serialize('news-form')\"\n                   }, :accesskey => accesskey(:preview) %>\n</p>\n</div>\n<% end %>\n<div id=\"preview\" class=\"wiki\"></div>\n"
  },
  {
    "path": "app/views/news/show.html.erb",
    "content": "\n<h2><%=h @news.title %></h2>\n\n<% if authorize_for('news', 'edit') %>\n<div id=\"edit-news\" style=\"display:none;\">\n<% labelled_tabular_form_for :news, @news, :url => { :action => \"edit\", :id => @news },\n                                           :html => { :id => 'news-form' } do |f| %>\n<%= render :partial => 'form', :locals => { :f => f } %>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save) %>\n<p class=\"gt-cancel\">\n<%= link_to_remote l(:label_preview),\n                   { :url => { :controller => 'news', :action => 'preview', :project_id => @project },\n                     :method => 'post',\n                     :update => 'preview',\n                     :with => \"Form.serialize('news-form')\"\n                   }, :accesskey => accesskey(:preview) %> |\n<%= link_to l(:button_cancel), \"#\", :onclick => '$(\"#edit-news\").hide(); return false;' %>\n</p></div>\n<% end %>\n<div id=\"preview\" class=\"wiki\"></div>\n</div>\n<% end %>\n\n<div class=\"message gt-content-box\">\n\n<table class=\"gt-table gt-user-table\" border=\"0\">\n  <tbody>\n    <tr>\n      <td class=\"gt-avatar <%= User.current.logged? && User.current.id == @news.author ? 'me' : nil %>\">\n        <%= avatar(@news.author, :size => '53') %>\n      </td>\n      <td>\n        <p><em><% unless @news.summary.blank? %><%=\"<strong>Summary</strong>: #{h @news.summary}\" %><br /><% end %>\n        </em></p>\n\n        <%= textilizable(@news.description) %>\n    </td>\n    <td class=\"side\">\n      <table border=\"0\" class=\"gt-table-categories\">\n        <tr>\n          <td><%= link_to_user(@news.author) %></td>\n        </tr>\n        <tr>\n          <td><%= since_tag(@news.created_at) %> ago</td>\n        </tr>\n      </table>\n    </td>\n   </tr>\n  </tbody>\n</table>\n</div>\n\n<br />\n\n<% if @comments.any? %>\n  <h3 class=\"comments\"><%= l(:label_comment_plural) %></h3>\n  <div class=\"gt-content-box\">\n  <table class=\"gt-table gt-user-table\" border=\"0\">\n    <tbody>\n\n  <% @comments.each do |comment| %>\n  <% next if comment.new_record? %>\n\n   <tr>\n     <td class=\"gt-avatar <%= User.current.logged? && User.current.id == comment.author ? 'me' : nil %>\">\n       <%= avatar(comment.author, :size => '53') %>\n     </td>\n     <td>\n       <div class=\"comment reply\" id=\"<%= \"comment-#{comment.id}\" %>\">\n         <%= textilizable comment.comments %>\n       </div>\n\n     </td>\n     <td class=\"side\">\n       <table border=\"0\" class=\"gt-table-categories\">\n         <tr>\n           <td><%= link_to_user(comment.author) %></td>\n         </tr>\n         <tr>\n           <td><%= since_tag(comment.created_at) %> ago</td>\n         </tr>\n        <tr><td>\n          <%= link_to_if_authorized image_tag('delete.png'), {:controller => 'news', :action => 'destroy_comment', :id => @news, :comment_id => comment},\n                                                             :confirm => l(:text_are_you_sure), :method => :post, :title => l(:button_delete) %>\n          </td>\n          </tr>\n       </table>\n     </td>\n  </tr>\n  <% end %>\n      </tbody>\n    </table>\n  </div>\n<% end %>\n\n<% if authorize_for 'news', 'add_comment' %>\n  <p><%= toggle_link l(:label_comment_add), \"add_comment_form\", {:focus => \"comment_comments\", :class => \"gt-btn-gray-large\"} %></p>\n  <% form_tag({:action => 'add_comment', :id => @news}, :id => \"add_comment_form\", :style => \"display:none;\") do %>\n  <div class=\"gt-content-box\">\n      <%= textile_editor 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit', \"autocomplete-mentions-projectid\" => @project.id %>\n  </div>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_add), :disable_with => l(:button_working) %>\n  </div>\n  <%= textile_editor_initialize(:framework => :jquery) %>\n  <% end %>\n<% end %>\n\n<% html_title @news.title -%>\n\n<% content_for :header_tags do %>\n  <%= stylesheet_link_tag 'scm' %>\n<% end %>\n\n<% content_for :sidebar do %>\n  <div class=\"gt-sidebar-nav gt-sidebar-nav-gray\">\n    <ul>\n      <li>\n        <%= link_to_if_authorized l(:button_edit),\n                                  {:controller => 'news', :action => 'edit', :id => @news},\n                                  :class => 'icon icon-edit',\n                                  :accesskey => accesskey(:edit),\n                                  :onclick => '$(\"#edit-news\").show(); return false;' %>\n      </li>\n      <li>\n        <%= link_to_if_authorized l(:button_delete), {:controller => 'news', :action => 'destroy', :id => @news}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>\n      </li>\n    </ul>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/notifications/_credits_distributed.erb",
    "content": "<tr class=\"notification notification-credits-distributed\" id=\"notification_<%= @notification.id %>\">\n    <td class=\"gt-avatar\">\n      <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n    </td>\n    <td>\n<h4>\n<%= link_to \"#{l(\"label_youve_got_credits\")}\", {:controller => \"projects\", :action => \"credits\", :id => enterprise_id},{:target => \"_blank\"} %>\n</h4>\n<%= l(:text_credits_distributed_for, :amount => number_to_currency(credit_distribution[\"amount\"].to_f.round, :unit => '', :separator => \".\", :delimiter => \",\", :precision => 0), :workstream => project_name) %>\n<%= \"<br><br>\" + l(:text_credits_are_a_gift) if credit_distribution[\"retro_id\"] == CreditDistribution::GIFT %>\n<%= \"<br><br>\" + l(:text_credits_are_an_expense) if credit_distribution[\"retro_id\"] == CreditDistribution::EXPENSE %>\n\n<p class=\"gt-table-action-list\">\n<%= link_to(l(:button_view), {:controller => \"projects\", :action => \"credits\", :id => enterprise_id}, {:id =>'cr_button', :class => 'icon icon-cr-offer', :target => \"_blank\"})%>\n&nbsp;\n<%= link_to_remote(l(:button_mark_as_read), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_marked_as_read}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n        <td>\n          <table border=\"0\" class=\"gt-table-categories\">\n            <tr>\n              <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n            </tr>\n            <tr>\n              <td><%= since_tag(@notification.created_at) %> ago</td>\n            </tr>\n          </table>\n        </td>\n    </tr>\n"
  },
  {
    "path": "app/views/notifications/_credits_transferred.html.erb",
    "content": "<tr class=\"notification notification-credits-transferred\" id=\"notification_<%= @notification.id %>\">\n    <td class=\"gt-avatar\">\n      <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n    </td>\n    <td>\n<h4>\n<%= link_to \"#{l(\"label_youve_got_credits\")}\", {:controller => \"projects\", :action => \"credits\", :id => project.id},{:target => \"_blank\"} %>\n</h4>\n<%= l(:text_credits_transferred, :amount => number_to_currency(amount.to_f.round, :unit => '', :separator => \".\", :delimiter => \",\", :precision => 0), :workstream => h(project.name), :sender => link_to_user(@notification.sender), :project => link_to_project(project)) %>\n<br>\n<% unless note.nil? %>\n\n------- <%= l(:text_included_note) %> -------<br>\n<%= h(note) %><br>\n<% end %>\n\n<p class=\"gt-table-action-list\">\n<%= link_to(l(:button_view), {:controller => \"projects\", :action => \"credits\", :id => project.id}, {:id =>'cr_button', :class => 'icon icon-cr-offer', :target => \"_blank\"})%>\n&nbsp;\n<%= link_to_remote(l(:button_mark_as_read), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_marked_as_read}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n        <td>\n          <table border=\"0\" class=\"gt-table-categories\">\n            <tr>\n              <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n            </tr>\n            <tr>\n              <td><%= since_tag(@notification.created_at) %> ago</td>\n            </tr>\n          </table>\n        </td>\n    </tr>\n"
  },
  {
    "path": "app/views/notifications/_invitation.erb",
    "content": "<tr class=\"notification notification-new-role\" id=\"notification_<%= @notification.id %>\">\n      <td class=\"gt-avatar\">\n        <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n      </td>\n      <td>\n<h4><%= link_to l(\"label_new_invitation\", :role_name => role_name, :project_name => project_name), {:controller => \"projects\", :action => \"team\", :id => project_id},{:target => \"_blank\"} %> </h4>\n<%= l(:text_you_are_invited) %> <%= link_to project_name, {:controller => \"projects\", :action => \"show\", :id => project_id} %>. <br><br>\n<%= l(\"text_role_description_#{role_name}\", :enterprise => project_name) %>\n<p class=\"gt-table-action-list\">\n<%= link_to(l(:button_view), {:controller => \"projects\", :action => \"team\", :id => project_id}, {:id =>'cr_button', :class => 'icon icon-cr-offer', :target => \"_blank\"})%>\n&nbsp;\n<%= link_to(l(:button_accept_invitation), {:controller => \"invitations\", :action => \"accept\", :id => @notification.source_id, :token => token}, {:id =>'cr_button', :class => 'icon icon-cr-accept'})%>\n&nbsp;\n<%= link_to_remote(l(:button_ignore), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_ignored}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n    <td>\n      <table border=\"0\" class=\"gt-table-categories\">\n        <tr>\n          <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n        </tr>\n        <tr>\n          <td><%= since_tag(@notification.created_at) %> ago</td>\n        </tr>\n      </table>\n    </td>\n</tr>\n"
  },
  {
    "path": "app/views/notifications/_issue_joined.html.erb",
    "content": "<tr class=\"notification notification-issue-joined\" id=\"notification_<%= @notification.id %>\">\n      <td class=\"gt-avatar\">\n        <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n      </td>\n      <td>\n  <h4>\n<%= l(\"label_someone_joined_your_issue\", :joiner => link_to_user_from_id(@notification.sender_id)) %>\n  </h4>\n<%= l(:text_joiner_is_now_working_with_you, :joiner => link_to_user_from_id(@notification.sender_id), :issue => link_to_issue_from_id(issue_id)) %>\n<p class=\"gt-table-action-list\">\n<%= link_to_remote(l(:button_mark_as_read), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_marked_as_read}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n    <td>\n      <table border=\"0\" class=\"gt-table-categories\">\n        <tr>\n          <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n        </tr>\n        <tr>\n          <td><%= since_tag(@notification.created_at) %> ago</td>\n        </tr>\n      </table>\n    </td>\n</tr>\n"
  },
  {
    "path": "app/views/notifications/_issue_left.html.erb",
    "content": "<tr class=\"notification notification-issue-left\" id=\"notification_<%= @notification.id %>\">\n  <td class=\"gt-avatar\">\n    <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n  </td>\n  <td>\n<h4><%= l(\"label_someone_left_your_issue\", :joiner => link_to_user(joiner)) %> </h4>\n<%= l(:text_joiner_is_no_longer_working_with_you, :joiner => link_to_user(joiner), :issue => link_to_issue(issue)) %>\n<p class=\"gt-table-action-list\">\n<%= link_to_remote(l(:button_mark_as_read), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_marked_as_read}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n    <td>\n      <table border=\"0\" class=\"gt-table-categories\">\n        <tr>\n          <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n        </tr>\n        <tr>\n          <td><%= since_tag(@notification.created_at) %> ago</td>\n        </tr>\n      </table>\n    </td>\n</tr>\n"
  },
  {
    "path": "app/views/notifications/_issue_team_member_added.html.erb",
    "content": "<tr class=\"notification notification-issue-team-member-added\" id=\"notification_<%= @notification.id %>\">\n    <td class = \"gt-avatar\">\n      <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n    </td>\n    <td>\n<h4><%= l(\"label_someone_added_you_to_their_issue\", :sender => link_to_user_from_id(@notification.sender_id)) %> </h4>\n\n<%= l(:text_you_are_now_working_with_you, :issue => link_to_issue_from_id(issue_id)) %>\n<p class=\"gt-table-action-list\">\n<%= link_to_remote(l(:button_mark_as_read), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_marked_as_read}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n    <td>\n      <table border=\"0\" class=\"gt-table-categories\">\n        <tr>\n          <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n        </tr>\n        <tr>\n          <td><%= since_tag(@notification.created_at) %> ago</td>\n        </tr>\n      </table>\n    </td>\n</tr>\n"
  },
  {
    "path": "app/views/notifications/_issue_team_member_removed.html.erb",
    "content": "<tr class=\"notification notification-issue-team-member-removed\" id=\"notification_<%= @notification.id %>\">\n    <td class = \"gt-avatar\">\n      <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n    </td>\n    <td>\n<h4><%= l(\"label_someone_removed_you_from_their_issue\", :sender => link_to_user_from_id(@notification.sender_id)) %> </h4>\n\n<%= l(:text_you_are_no_longer_working_on, :issue => link_to_issue_from_id(issue_id)) %>\n<p class=\"gt-table-action-list\">\n<%= link_to_remote(l(:button_mark_as_read), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_marked_as_read}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n    <td>\n      <table border=\"0\" class=\"gt-table-categories\">\n        <tr>\n          <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n        </tr>\n        <tr>\n          <td><%= since_tag(@notification.created_at) %> ago</td>\n        </tr>\n      </table>\n    </td>\n</tr>\n"
  },
  {
    "path": "app/views/notifications/_mention.html.erb",
    "content": "<tr class=\"notification notification-issue-mentioned\" id=\"notification_<%= @mention.id %>\">\n  <td class=\"gt-avatar\">\n    <table border=\"0\" class=\"gt-table-categories\">\n      <tr>\n        <td>\n          <%= avatar_from_id(@mention.sender_id, :size => '53') %>\n        </td>\n      </tr>\n      <tr>\n        <td><%= link_to_user_from_id(@mention.sender_id) %></td>\n      </tr>\n    </table>\n  </td>\n  <td>\n    <span class=\"icon icon-time right small-text\"<%= since_tag(@mention.created_at) %> ago</span>\n  <%= link_to (truncate(title,50),url, {:class => \"#{@mention.source_type == 'Issue' || @mention.source_type == 'Journal(Issue)' ? 'fancyframe' : ''}\"}) %>\n  <br><br>\n  <%= make_expandable mention_text %>\n<p class=\"gt-table-action-list\">\n<%= link_to_remote(l(:button_mark_as_read), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @mention.id, :message => :label_marked_as_read}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n<%= link_to(l(:button_view), url, {:id =>'cr_button', :class => \"icon icon-cr-offer #{@mention.source_type == 'Issue' || @mention.source_type == 'Journal(Issue)' ? 'fancyframe' : ''}\",  :target => \"_blank\"})%>\n</p>\n    </td>\n</tr>\n"
  },
  {
    "path": "app/views/notifications/_message.html.erb",
    "content": "<div class=\"notification notification-message\" id=\"notification_<%= notification_id %>\">\n<table>\n  <tr>\n<% unless sender_id.nil? %>\n    <td style=\"vertical-align: top; padding: 23px 10px 0px 0px\">\n    <%= avatar_from_id(sender_id) %>\n    </td>\n<% end %>\n    <td>\n<h4><%= subject %> </h4>\n<h5><%= l(:label_by, :author => link_to_user_from_id(sender_id), :age => time_tag(notification_created_at)) %></h5>\n<%= message %><br><br>\n<%= link_to_remote(l(:button_mark_as_read), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => notification_id, :message => :label_marked_as_read}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n    </td>\n    </tr>\n    </table>\n\n</div>\n"
  },
  {
    "path": "app/views/notifications/_motion_started.erb",
    "content": "<tr class=\"notification notification-motion-started\" id=\"notification_<%= @notification.id %>\">\n      <td class=\"gt-avatar\">\n        <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n      </td>\n      <td>\n<h4><%= link_to l(\"label_motion_started\", :title => motion_title, :id => @notification.source_id), {:controller => \"motions\", :action => \"show\", :id => @notification.source_id, :project_id => enterprise_id},{:target => \"_blank\"} %> </h4>\n<p class=\"gt-table-action-list\">\n<%= link_to(l(:button_participate), {:controller => \"motions\", :action => \"show\", :id => @notification.source_id, :project_id => enterprise_id}, {:id =>'cr_button', :class => 'icon icon-cr-offer', :target => \"_blank\"})%>\n<%= link_to_remote(l(:button_ignore), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_ignored}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n    <td>\n      <table border=\"0\" class=\"gt-table-categories\">\n        <tr>\n          <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n        </tr>\n        <tr>\n          <td><%= since_tag(@notification.created_at) %> ago</td>\n        </tr>\n      </table>\n    </td>\n</tr>\n"
  },
  {
    "path": "app/views/notifications/_new_role.erb",
    "content": "<tr class=\"notification notification-new-role\" id=\"notification_<%= @notification.id %>\">\n      <td class=\"gt-avatar\">\n        <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n      </td>\n      <td>\n<h4><%= link_to l(\"label_new_role\", :role_name => role_name), {:controller => \"projects\", :action => \"team\", :id => enterprise_id},{:target => \"_blank\"} %> </h4>\n<%= l(:text_you_are_now_a_role, :role_name => role_name) %> <%= link_to project_name, {:controller => \"projects\", :action => \"show\", :id => enterprise_id} %>. <br><br>\n<%= l(\"text_role_description_#{role_name}\", :enterprise => project_name) %>\n<p class=\"gt-table-action-list\">\n<%= link_to(l(:button_view), {:controller => \"projects\", :action => \"team\", :id => enterprise_id}, {:id =>'cr_button', :class => 'icon icon-cr-offer', :target => \"_blank\"})%>\n&nbsp;\n<%= link_to_remote(l(:button_ignore), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_ignored}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n    <td>\n      <table border=\"0\" class=\"gt-table-categories\">\n        <tr>\n          <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n        </tr>\n        <tr>\n          <td><%= since_tag(@notification.created_at) %> ago</td>\n        </tr>\n      </table>\n    </td>\n</tr>\n"
  },
  {
    "path": "app/views/notifications/_retro_ended.erb",
    "content": "  <tr class=\"notification notification-retro-ended\" id=\"notification_<%= @notification.id %>\">\n      <td class=\"gt-avatar\">\n        <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n      </td>\n      <td>\n  <h4>\n<%= link_to \"#{l(\"label_retro_ended\")} ##{@notification.source_id}\",  {:controller => \"retros\", :action => \"show\", :id => @notification.source_id},{:class => \"fancyframe\"} %>\n</h4>\n<%= l(:text_retro_ended_for) %>\n<strong><%= project.name %></strong>\n<%= l(:text_retro_ended) %>\n<p class=\"gt-table-action-list\">\n<%= link_to(l(:button_view), {:controller => \"retros\", :action => \"show\", :id => @notification.source_id}, {:id =>'cr_button', :class => 'icon icon-cr-offer fancyframe',  :target => \"_blank\"})%>\n&nbsp;\n<%= link_to_remote(l(:button_mark_as_read), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_marked_as_read}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n        <td>\n          <table border=\"0\" class=\"gt-table-categories\">\n            <tr>\n              <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n            </tr>\n            <tr>\n              <td><%= since_tag(@notification.created_at) %> ago</td>\n            </tr>\n          </table>\n        </td>\n    </tr>\n"
  },
  {
    "path": "app/views/notifications/_retro_started.erb",
    "content": "<tr class=\"notification notification-retro-started\" id=\"notification_<%= @notification.id %>\">\n      <td class=\"gt-avatar\">\n        <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n      </td>\n      <td>\n  <h4>\n<%= link_to \"#{l(\"label_retro_started\")} ##{@notification.source_id}\", {:controller => \"retros\", :action => \"show\", :id => @notification.source_id},{:class => \"fancyframe\"} %> </h4>\n<%= l(:text_retro_started_for) %>\n<strong><%= project.name %></strong>\n<%= l(:text_retro_started) %>\n<p class=\"gt-table-action-list\">\n<%= link_to(l(:button_participate), {:controller => \"retros\", :action => \"show\", :id => @notification.source_id}, {:id =>'cr_button', :class => 'icon icon-cr-offer fancyframe', :target => \"_blank\"})%>\n&nbsp;\n<%= link_to_remote(l(:button_ignore), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_ignored}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n    <td>\n      <table border=\"0\" class=\"gt-table-categories\">\n        <tr>\n          <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n        </tr>\n        <tr>\n          <td><%= since_tag(@notification.created_at) %> ago</td>\n        </tr>\n      </table>\n    </td>\n</tr>\n"
  },
  {
    "path": "app/views/notifications/_trial_expired.html.erb",
    "content": "  <tr class=\"notification notification-trial-expired\" id=\"notification_<%= @notification.id %>\">\n      <td class=\"gt-avatar\">\n        <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n      </td>\n      <td>\n  <h4>\n<%= link_to l(:label_trial_expired),  {:controller => \"my\", :action => \"upgrade\"} %>\n</h4>\n<%= l(:text_trial_expired) %>\n\n<p class=\"gt-table-action-list\">\n<%= link_to(l(:button_update_billing), {:controller => \"my\", :action => \"upgrade\"}, {:id =>'cr_button', :class => 'icon icon-cr-offer'})%>\n&nbsp;\n<%= link_to_remote(l(:button_mark_as_read), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_marked_as_read}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n        <td>\n          <table border=\"0\" class=\"gt-table-categories\">\n            <tr>\n              <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n            </tr>\n            <tr>\n              <td><%= since_tag(@notification.created_at) %> ago</td>\n            </tr>\n          </table>\n        </td>\n    </tr>\n"
  },
  {
    "path": "app/views/notifications/_unresponded.html.erb",
    "content": "<% if Notification.unresponded? %>\n<span id=\"notification\" class=\"notification-unresponded\">\n<%=link_to pluralize(Notification.unresponded_count,l(:label_new_notification)), {:controller => 'notifications', :action => 'index'} %>\n<span class=\"gt-util-separator\">|</span>\n</span>\n<% end %>\n"
  },
  {
    "path": "app/views/notifications/_usage_over.html.erb",
    "content": "  <tr class=\"notification notification-usage-over\" id=\"notification_<%= @notification.id %>\">\n      <td class=\"gt-avatar\">\n        <%= avatar_from_id(@notification.sender_id, :size => '53') %>\n      </td>\n      <td>\n  <h4>\n<%= link_to l(:label_usage_over),  {:controller => \"my\", :action => \"upgrade\"} %>\n</h4>\n<%= l(:text_usage_over) %>\n\n<p class=\"gt-table-action-list\">\n<%= link_to(l(:button_upgrade), {:controller => \"my\", :action => \"upgrade\"}, {:id =>'cr_button', :class => 'icon icon-cr-offer'})%>\n&nbsp;\n<%= link_to_remote(l(:button_mark_as_read), {:url => {:controller => \"notifications\", :action => \"hide\", :notification_id => @notification.id, :message => :label_marked_as_read}}, {:id =>'cr_button', :class => 'icon icon-cr-ignore'})%>\n</p>\n    </td>\n        <td>\n          <table border=\"0\" class=\"gt-table-categories\">\n            <tr>\n              <td><%= link_to_user_from_id(@notification.sender_id) %></td>\n            </tr>\n            <tr>\n              <td><%= since_tag(@notification.created_at) %> ago</td>\n            </tr>\n          </table>\n        </td>\n    </tr>\n"
  },
  {
    "path": "app/views/notifications/edit.html.erb",
    "content": "<h1>Editing notification</h1>\n\n<% form_for(@notification) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :recipient_id %><br />\n    <%= f.text_field :recipient_id %>\n  </p>\n  <p>\n    <%= f.label :partial_name %><br />\n    <%= f.text_field :partial_name %>\n  </p>\n  <p>\n    <%= f.label :params %><br />\n    <%= f.text_field :params %>\n  </p>\n  <p>\n    <%= f.label :response %><br />\n    <%= f.text_field :response %>\n  </p>\n  <p>\n    <%= f.label :expiration_date %><br />\n    <%= f.date_select :expiration_date %>\n  </p>\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @notification %> |\n<%= link_to 'Back', notifications_path %>\n"
  },
  {
    "path": "app/views/notifications/error.js.rjs",
    "content": "page.alert \"Couldn't send your response to this notification!\"\n"
  },
  {
    "path": "app/views/notifications/hide.js.rjs",
    "content": "#Checking if this update is being called through the notification page\nif (!params[:notification_id].nil?)\n  page.replace \"notification_\" + params[:notification_id], content_tag(:tr, content_tag(:td, l(params[:message] || :label_response_sent), :class => \"notification_response\", :colspan => 3, :id => \"notification_\" + params[:notification_id]))\n  page.replace \"notification\", :partial => \"notifications/unresponded\"\n  page[\"notification_\" + params[:notification_id]].visual_effect :highlight\nend\n"
  },
  {
    "path": "app/views/notifications/index.html.erb",
    "content": "<%# @page_header_name = \"My Notifications\" %>\n<% content_for :mainmenu do %>\n  <%= render :partial => 'common/main_menu_home', :locals => {:active_page => :notifications} %>\n<% end %>\n\n<h2 class=\"gt-table-head icon22 icon22-projects\"><%=l(:label_notifications)%></h2>\n<div class=\"gt-content-box\">\n<table border=\"0\" class=\"gt-table gt-user-table\">\n  <tbody>\n    <% if @notifications.empty? %>\n    <p class=\"nodata\"><%= l(:label_no_data) %></p>\n    <% else %>\n      <% @notifications.each do |@notification| %>\n          <%= render :partial => @notification.variation,\n                    :locals => @notification.params %>\n      <% end %>\n    <% end %>\n  </tbody>\n</table>\n</div>\n\n<% content_for :sidebar do %>\n  <h2 class=\"gt-table-head icon22 icon22-projects\"><%=l(:label_mentions)%> <%= help_bubble(:help_mentions,{:login => User.current.login}) %></h2>\n  <div class=\"gt-content-box\">\n  <table border=\"0\" class=\"gt-table gt-user-table\">\n    <tbody>\n      <% if @mentions.empty? %>\n      <p class=\"nodata\"><%= l(:label_no_mention) %></p>\n      <% else %>\n        <% @mentions.each do |@mention| %>\n            <%= render :partial => @mention.variation,\n                      :locals => @mention.params %>\n        <% end %>\n      <% end %>\n    </tbody>\n  </table>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/notifications/new.html.erb",
    "content": "<h1>New notification</h1>\n\n<% form_for(@notification) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :recipient_id %><br />\n    <%= f.text_field :recipient_id %>\n  </p>\n  <p>\n    <%= f.label :partial_name %><br />\n    <%= f.text_field :partial_name %>\n  </p>\n  <p>\n    <%= f.label :params %><br />\n    <%= f.text_field :params %>\n  </p>\n  <p>\n    <%= f.label :response %><br />\n    <%= f.text_field :response %>\n  </p>\n  <p>\n    <%= f.label :expiration_date %><br />\n    <%= f.date_select :expiration_date %>\n  </p>\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', notifications_path %>\n"
  },
  {
    "path": "app/views/notifications/show.html.erb",
    "content": "<p>\n  <b>translation missing: en, field_recipient:</b>\n  <%=h @notification.recipient_id %>\n</p>\n\n<p>\n  <b>translation missing: en, field_partial_name:</b>\n  <%=h @notification.partial_name %>\n</p>\n\n<p>\n  <b>translation missing: en, field_params:</b>\n  <%=h @notification.params %>\n</p>\n\n<p>\n  <b>translation missing: en, field_response:</b>\n  <%=h @notification.response %>\n</p>\n\n<p>\n  <b>translation missing: en, field_expiration_date:</b>\n  <%=h @notification.expiration_date %>\n</p>\n\n\n<%= link_to 'Edit', edit_notification_path(@notification) %> |\n<%= link_to 'Back', notifications_path %>\n"
  },
  {
    "path": "app/views/projects/_active_member_box.html.erb",
    "content": "<%\n@members_active = @project.active_members\nif @members_active.any?\n  %>\n<h2 class=\"gt-table-head icon icon-users\"><%=l(:label_active_team)%><%= help_bubble(:text_active_team_explanation) %></h2>\n<div class=\"members gt-content-box\">\n  <table border=\"0\" class=\"gt-table gt-user-table\">\n    <tbody>\n      <% @members_active.each do |member| %>\n      <tr>\n        <td class=\"gt-avatar\"><%= avatar(member.user) %></td>\n        <td>\n          <h4><%= link_to_user member.user %></h4>\n          <%\n            roles =  member.user.roles_for_project(@project).collect{|role| role.name }\n            roles.delete(Role.active.name)\n            %>\n          <%= roles.join(\",\") %>\n        </td>\n      </tr>\n      <% end %>\n      <% if User.current.allowed_to?(:send_invitations, @project)  && @project.root? %>\n      <tr><td colspan=2 style=\"text-align:center\">\n       <%= link_to l(:label_invitation_others), new_project_invitation_url(@project) %>\n      </td></tr>\n      </li>\n      <% end %>\n      <% unless @hide_view_team_link %>\n      <tr><td colspan=3 style=\"text-align:center\">\n       <%= link_to l(:label_team_view_all_enterprise), {:controller => 'projects', :action => 'team', :id => @project.root} %>\n      </td></tr>\n      <% end %>\n    </tbody>\n  </table>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/projects/_active_member_box_simple.html.erb",
    "content": "<%\n@members_active = @project.active_members\nif @members_active.any?\n  %>\n<h2 class=\"gt-table-head icon icon-users\"><%=l(:label_active_team)%><%= help_bubble(:text_active_team_explanation) %></h2>\n<div class=\"members gt-content-box\">\n  <table border=\"0\" class=\"gt-table gt-user-table\">\n    <tbody>\n      <tr>\n        <td>\n      <% @members_active.each do |member| %>\n        <div class=\"gt-avatar-box\">\n          <%= avatar(member.user) %><br>\n          <%= link_to_user member.user, {:format => :firstname} %><br>\n        </div>\n      <% end %>\n        </td>\n      </tr>\n      <% if User.current.allowed_to?(:send_invitations, @project)  && @project.root? %>\n      <tr><td colspan=2 style=\"text-align:center\">\n       <%= link_to l(:label_invitation_others), new_project_invitation_url(@project) %>\n      </td></tr>\n      </li>\n      <% end %>\n      <% unless @hide_view_team_link %>\n      <tr><td colspan=3 style=\"text-align:center\">\n       <%= link_to l(:label_team_view_all_enterprise), {:controller => 'projects', :action => 'team', :id => @project.root} %>\n      </td></tr>\n      <% end %>\n    </tbody>\n  </table>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/projects/_clearance_member_box.html.erb",
    "content": "<%\n@members_active = @project.clearance_members\nif @members_active.any?\n  %>\n<h2 class=\"gt-table-head\"><%=l(:label_team_with_access)%></h2>\n<div class=\"members gt-content-box\">\n  <table border=\"0\" class=\"gt-table gt-user-table\">\n    <tbody>\n      <% @members_active.each do |member| %>\n      <tr>\n        <td class=\"gt-avatar\"><%= avatar(member.user) %></td>\n        <td><h4><%= link_to_user member.user %></h4></td>\n      </tr>\n      <% end %>\n      <% if User.current.allowed_to?(:send_invitations, @project)  && @project.root? %>\n      <tr><td colspan=2 style=\"text-align:center\">\n       <%= link_to l(:label_invitation_others), new_project_invitation_url(@project) %>\n      </td></tr>\n      </li>\n      <% end %>\n    </tbody>\n  </table>\n</div>\n<div class=\"gt-table-buttons\">\n  <%= link_to l(:label_team_view_all_enterprise), {:controller => 'projects', :action => 'team', :id => @project.root} , :class => \"gt-btn-blue-large\" %>\n</div>\n\n<% end %>\n"
  },
  {
    "path": "app/views/projects/_dashboard_javascript_variables.html.erb",
    "content": "<script type=\"text/javascript\">\n  <%  if params[:dataId] && @issue %>\n    var item = parent.D[<%= params[:dataId] %>];\n  <% elsif @issue %>\n    var item = <%=@issue.to_dashboard%>;\n  <% end  %>\n  var adminUserId = '<%= User.sysadmin.id %>';\n  var credit_base = '<%= project.dpp %>';\n  var projectId = '<%= project.id %>';\n  var credits_to_points_array = <%= Setting::CREDITS_TO_POINTS.to_json %>;\n  var currentUserLogin = '<%= User.current.login %>';\n  var currentUserId = '<%= User.current.id %>';\n  var currentUserIsCore = '<%= User.current.core_member_of?(project) %>';\n  var currentUserIsMember = '<%= User.current.member_of?(project) %>';\n  var point_factor = <%= Setting::POINT_FACTOR.to_json %>;\n  var startable_priority_tiers = <%= Setting::NUMBER_OF_STARTABLE_PRIORITY_TIERS %>;\n  var credits_enabled = <%= project.credits_enabled? %>;\n  var ISSUE_COUNT = <%= project.issue_count %>\n  var ANONYMOUS_USER_ID = <%= User.anonymous.id %>;\n  var currentUserCanEditIssue = <%= User.current.allowed_to?({:action => :edit_issues}, project) != nil %>;\n  var LAST_LOCAL_DB_CHANGE = \"3/30/2011\" //latest code update that requires local data structure to be refreshed\n\n</script>\n"
  },
  {
    "path": "app/views/projects/_edit.html.erb",
    "content": "<% labelled_tabular_form_for :project, @project, :url => { :action => \"edit\", :id => @project }, :html => { :multipart => true }  do |f| %>\n<%= render :partial => 'form', :locals => { :f => f } %>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div><% end %>\n"
  },
  {
    "path": "app/views/projects/_form.html.erb",
    "content": "<%= error_messages_for 'project' %>\n<% include_modules ||= false %>\n\n<div class=\"gt-content-box\">\n<%= hidden_field_tag 'parent_id', params[:parent_id]%>\n\n<% unless @parent.nil? %>\n    <p><label><%= l(:field_parent) %> <%= link_to @parent.name, {:controller => 'projects', :action => 'show', :id => @parent} %></label></p>\n<% end %>\n\n<p><%= f.text_field :name, :required => true %><br /><em><%= l(:text_caracters_maximum, 50) %></em></p>\n\n\n<p><label><%= l(:field_description) %></label><%= f.textile_editor :description, :rows => 5, :class => 'wiki-edit' %></p>\n<%= textile_editor_initialize(:framework => :jquery) %>\n\n<% if @allow_logo_selection %>\n<div class=\"clear\">\n<p>\n    <label><%= l(:field_logo) %></label>\n    <div class=\"gt-content-box\">\n    <%= image_tag formatted_project_path(@project, :png) if @project.has_image? %>\n    <%= f.file_field :image_file %><br />\n    <%= f.text_field :image_file_url , :style => \"width:60%;\"%>\n    </div>\n</p>\n</div>\n<% end %>\n\n<div class=\"gt-cols-3\">\n<div class=\"gt-sidebar-left\">\n<p>\n  <fieldset><label><%= l(:label_type_of_workstream) %></label>\n      <label class=\"floating\" style=\"display:inline\">\n      <%= check_box_tag 'project[is_public]', 1, @project.is_public %>\n      <%= l(:field_is_public) %>\n      <%= help_bubble \"help_is_public\" %><br>\n      </label>\n      <label class=\"floating\" style=\"display:inline\">\n      <%= check_box_tag 'project[volunteer]', 1, @project.volunteer %>\n      <%= l(:field_volunteer) %>\n      <%= help_bubble \"help_volunteer\" %><br>\n      </label>\n  </fieldset>\n</p>\n</div>\n\n<% if include_modules  then%>\n<div class=\"gt-content\">\n<p>\n  <fieldset><label><%= l(:label_module_plural) %></label>\n  <% Redmine::AccessControl.available_project_modules.each do |m| %>\n      <label class=\"floating\" style=\"display:inline\">\n      <%= check_box_tag 'enabled_modules[]', m, @project.module_enabled?(m), :id => \"check_box_#{m}\" %>\n      <%= l_or_humanize(m, :prefix => \"project_module_\") %>\n      <%= help_bubble \"help_#{m}\" %><br>\n      </label>\n  <% end %>\n  </fieldset>\n</p>\n</div>\n\n<div id=\"point_scale_container\" class=\"gt-sidebar\" style=\"<%= @project.credits_enabled? ? nil : 'display:none'%>\">\n<p>\n  <fieldset>\n<%=  f.select(:dpp, options_for_select(Setting::PAY_SCALES, :selected => @project.dpp.nil? ? Setting::PAY_SCALES_DEFAULT : @project.dpp.round),\n                                                      { :include_blank => false},\n                                                      { :onchange => \"#{remote_function(:url  => {:action => \"update_scale\"},\n                                                                                                            :with => \"'dpp='+value\")}\"})%>\n  <span><%= help_bubble :help_select_scale %></span>\n  <%= render :partial => 'point_scale', :locals => {:unit => unit_for(@project), :dpp => @project.dpp.nil? ? Setting::PAY_SCALES_DEFAULT : @project.dpp.round } %>\n  </fieldset>\n</p>\n</div>\n<% end %>\n</div>\n\n<div class=\"clear\" />\n</div>\n\n</div>\n\n<script type=\"text/javascript\">\n  $(document).ready(function(){\n    $(\"#check_box_credits\").click(function(){\n      if($(this).is(':checked')) {\n         $(\"#point_scale_container\").show();\n       }\n       else{\n         $(\"#point_scale_container\").hide();\n       }\n    });\n  });\n</script>\n"
  },
  {
    "path": "app/views/projects/_member_box.html.erb",
    "content": "<%\n@users_by_role = @project.root.users_by_role\nif @users_by_role.any?\n  %>\n<h2 class=\"gt-table-head icon icon-users\"><%=l(:label_team)%></h2>\n<div class=\"members gt-content-box\">\n  <table border=\"0\" class=\"gt-table gt-user-table\">\n    <tbody>\n      <% @users_by_role.keys.sort.each do |role| %>\n      <% next if role.level != Role::LEVEL_ENTERPRISE %>\n      <tr>\n        <th><%=h role %><%= help_bubble(\"text_role_invitation_description_#{role.name.gsub(/ /,'_')}\") %></th>\n        <td><%= make_expandable(@users_by_role[role].sort.collect{|u| link_to_user u}.join(\", \"), 250) %></td>\n      </tr>\n      <% end %>\n      <tr><td colspan=2 class=\"gt-table-links\">\n       <%= link_to l(:label_team_view_all), {:controller => 'projects', :action => 'team', :project_id => @project} %>\n       <% if User.current.allowed_to?(:send_invitations, @project)  && @project.root? %>\n       | <%= link_to l(:label_invitation_others), new_project_invitation_url(@project) %>\n       <% end %>\n      </td></tr>\n      </li>\n    </tbody>\n  </table>\n</div>\n\n<% end %>\n"
  },
  {
    "path": "app/views/projects/_point_scale.html.erb",
    "content": "<span id=\"point_scale\" class=\"point-scale\">\n<% for i in 0..Setting::POINT_FACTOR.length - 1 do %>\n<img src=\"/images/dice_<%= i %>.png\" width=\"18\" height=\"18\" alt=\"<%= i %> Points\" class=\"dice\"/>\n<%= (Integer(dpp) * Setting::POINT_FACTOR[i]).round %><br>\n<% end %>\n</span>\n"
  },
  {
    "path": "app/views/projects/_project_list.html.erb",
    "content": "    <table border=\"0\" class=\"gt-table gt-user-table project-browse-table\">\n      <tbody>\n          <% for project in projects %>\n          <tr>\n            <td>\n              <%= render :partial => 'project_summary', :locals => {:project => project} %>\n            </td>\n          </tr>\n          <% end %>\n      </tbody>\n    </table>\n    <span id=\"project_index_bottom_<%= index_type %>\">\n      <div class=\"learn-more\">\n      <%= link_to_remote \"... load more ...\", {\n                                  :url => {:controller => :projects,\n                                          :action => \"index_#{index_type}\",\n                                          :offset => offset\n                                          },\n                                          :method => :get\n                                  }, {:id => \"#{index_type}_load_more\"} unless projects.last.nil? %>\n                                  </div>\n    </span>\n"
  },
  {
    "path": "app/views/projects/_project_summary.html.erb",
    "content": "<div class=\"project-summary\">\n<h4><%= link_to h(project.name), :controller => 'projects', :action => 'show', :id => project %><%= volunteering project %><%= privacy project %>\n  <h5 class=\"right\"><span class=\"icon icon-users\"><%= project.all_members.count %></span>&nbsp;&nbsp;<span class=\"icon icon-time\"><%= since_tag(project.created_at) %> ago</span> </h5>\n</h4>\n<p><%= make_expandable((textilizable project.description, :project => project),250) %></p>\n<div class=\"spark-container\">\n<span class=\"spark\" max=\"<%= project.activity_line_max %>\"><%= project.activity_line_show(60) %></span>\n</div>\n\n</div>\n"
  },
  {
    "path": "app/views/projects/_projects_list_simple.html.erb",
    "content": "<% count = 0\n   max_count ||= 5\n %>\n  <table class=\"gt-table gt-user-table project-table\" id=\"my_projects_table\">\n      <%   project_tree_sorted(projects) do |p, level|\n          name_prefix = (level > 0 ? ('&nbsp;' * 4 * level + '&#187; ') : '')\n          count = count + 1\n       %>\n      <tr class=\"active-project-row <%= \"hidden\" if count > max_count %>\">\n        <td>\n          <%=name_prefix + link_to(h(p), :controller => 'projects', :action => 'show', :id => p)  %><%= volunteering p %><%= privacy p %>\n          <% if !p.active? %>\n            <%= link_to_remote(l(:label_unarchive_project_brackets), :url => {:controller => 'projects', :action => 'unarchive', :id => p}, :confirm => l(:text_confirm_unarchive_project)) %>\n          <% end %>\n        </td>\n        <td>\n          <span class=\"spark\" max=\"<%= p.activity_line_max %>\"><%= p.activity_line_show(30) %></span>\n        </td>\n      </tr>\n      <% end %>\n      <tr class=\"active-project-show-more show-more <%= \"hidden\" unless count > max_count %>\">\n        <td colspan=\"2\">\n          <a href=\"\" onclick=\"$('.active-project-row').show();$('.active-project-show-more').hide();display_sparks();return false;\">Show <%= count - max_count %> more ...</a>\n        </td>\n      </tr>\n  </table>\n\n"
  },
  {
    "path": "app/views/projects/_subprojects.html.erb",
    "content": "         <% subprojects.each do |p| %>\n         <tr><td>\n         <%= (\"&nbsp;&nbsp;&#187;&nbsp;\" * level) + link_to(h(p), :action => 'show', :id => p)  %><%= volunteering p %><%= privacy p %>\n           <% array = p.activity_line_show(30) %>\n           <span class=\"spark right\" max=\"<%=  p.activity_line_max %>\"><%= p.activity_line_show(30) %></span>\n           </td></tr>\n         <% @subprojects = p.children.active.find(:all, :order => 'name ASC') %>\n         <%= render :partial => 'subprojects', :locals => {:subprojects => @subprojects, :level => level + 1} %>\n         <% end %>\n"
  },
  {
    "path": "app/views/projects/_team_link.html.erb",
    "content": "<div id=\"team_link\">\n<%= team_action_links(project) %>\n</div>\n"
  },
  {
    "path": "app/views/projects/_team_list.html.erb",
    "content": "<h2 class=\"gt-table-head icon icon-users\"><%=l(:label_team)%></h2>\n\n<%\n   members = project.enterprise_members.find(:all, :include => [:roles, :user]).sort\n   %>\n\n   <%\n   if members.any?\n     %>\n   <div class=\"members gt-content-box\">\n     <table border=\"0\" class=\"gt-table gt-user-table\">\n       <tbody>\n         <% members.each do |member| %>\n\n         <tr>\n           <td class=\"gt-avatar\"><%= avatar(member.user) %></td>\n           <td><h4><%= link_to_user member.user %></h4>\n               <%= nomination_links(member,project) %>\n           </td>\n           <td>\n            <table border=\"0\" class=\"gt-table-categories\">\n              <tr>\n                <th>Role:</th>\n                <td><%=h member.roles.sort.collect(&:to_s).join(', ') %></td>\n              </tr>\n              <tr>\n                <th>Since:</th>\n                <td><%= since_tag(member.created_at) %> ago</td>\n              </tr>\n            </table>\n\n           </td>\n         </tr>\n         <% end %>\n         <% if User.current.allowed_to?(:send_invitations, project) && project.root? %>\n        <tr><td colspan=3 style=\"text-align:center\">\n         <%= link_to l(:label_invitation_others), new_project_invitation_url(project) %>\n        </td></tr>\n        </li>\n        <% end %>\n\n       </tbody>\n     </table>\n   </div>\n   <div class=\"gt-table-buttons\">\n   </div>\n\n   <% else %>\n   <div class=\"gt-content-box\">\n   <p class=\"nodata\"><%= l(:label_no_data) %></p>\n    </div>\n   <% end %>\n"
  },
  {
    "path": "app/views/projects/_team_list_member.html.erb",
    "content": "<tr id=\"<%= member.user.login %>\" class=\"<%= cycle 'odd', 'even' %> member <%= member.user.name %>\">\n<td width=\"10px\">  <%= avatar(member.user, :size => \"64\") %></td>\n<td class=\"<%= member.user.class.name.downcase %>\"><%= link_to_user member.user %></td>\n<td class=\"roles\">\n  <span id=\"member-<%= member.id %>-roles\"><%=h member.roles.sort.collect(&:to_s).join(', ') %></span>\n</td>\n<td class=\"points\">\n  <%= nomination_links(member,@project) %>\n</td>\n</tr>\n"
  },
  {
    "path": "app/views/projects/activity.html.erb",
    "content": "<% @page_header_name = l(:label_browse_activity) %>\n<%= help_section(\"project_activity\") %>\n\n<h2 class=\"gt-table-head\"><%= @author.nil? ? \"\" : l(:label_user_activity, link_to_user(@author)) %><div class=\"spark right spark-top\" max=\"<%= @project.activity_line_max if @project %>\"><%= @project.activity_line_show(60) if @project %></div></h2>\n<div class=\"gt-content-box\">\n<%= render :partial => 'activity_streams/activity_stream_list', :locals => {\n  :user_id => params[:user_id],\n  :project_id => @project ? @project.id : nil,\n  :with_subprojects => params[:with_subprojects],\n  :limit => 50,\n  :max_created_at => nil\n  }\n%>\n</div>\n\n<% content_for :actionmenu do %>\n    <ul>\n    <li>\n      <%= link_to l(:label_project_new), {:controller => 'projects', :action => 'add', :parent_id => @project}, :class => \"icon icon-add\" %>\n    </li>\n    </ul>\n    <ul>\n    <li>\n      <%= link_to l(:label_browse_workstreams), {:controller => 'projects', :action => 'index'}, :class => \"icon icon-projects\" %>\n    </li>\n    </ul>\n<% end %>\n\n\n<% content_for :sidebar do %>\n<% end %>\n<% html_title(l(:label_activity), @author) -%>\n\n<script>\n  $('document').ready(function(){\n    display_sparks();\n  });\n</script>\n"
  },
  {
    "path": "app/views/projects/add.html.erb",
    "content": "<% @page_header_name = @parent ? l(:label_subproject_new) : l(:label_project_new) %>\n<% labelled_tabular_form_for :project, @project, :url => { :action => \"add\" }, :html => { :multipart => true }  do |f| %>\n\n<%= render :partial => 'form', :locals => { :f => f, :include_modules => true } %>\n\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n<%= javascript_tag \"$('#project_name').focus();\" %>\n<% end %>\n\n<% content_for :sidebar do %>\n<%= help_section(\"project_new\") %>\n<% end %>\n"
  },
  {
    "path": "app/views/projects/add_file.html.erb",
    "content": "<h2><%=l(:label_attachment_new)%></h2>\n\n<%= error_messages_for 'attachment' %>\n<div class=\"gt-content-box\">\n<% form_tag({ :action => 'add_file', :id => @project }, :multipart => true, :class => \"tabular\") do %>\n\n<p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p>\n</div>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_add), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/projects/copy.html.erb",
    "content": "<h2><%=l(:label_project_new)%></h2>\n\n<% labelled_tabular_form_for :project, @project, :url => { :action => \"copy\" } do |f| %>\n<%= render :partial => 'form', :locals => { :f => f } %>\n\n<fieldset class=\"gt-content-box\"><legend><%= l(:label_module_plural) %></legend>\n<% Redmine::AccessControl.available_project_modules.each do |m| %>\n    <label class=\"floating\">\n    <%= check_box_tag 'enabled_modules[]', m, @project.module_enabled?(m) %>\n    <%= l_or_humanize(m, :prefix => \"project_module_\") %>\n    </label>\n<% end %>\n</fieldset>\n\n<fieldset class=\"gt-content-box\"><legend><%= l(:button_copy) %></legend>\n  <label class=\"block\"><%= check_box_tag 'only[]', 'members', true %> <%= l(:label_member_plural) %> (<%= @source_project.all_members.count %>)</label>\n  <label class=\"block\"><%= check_box_tag 'only[]', 'issues', true %> <%= l(:label_issue_plural) %> (<%= @source_project.issues.count %>)</label>\n  <label class=\"block\"><%= check_box_tag 'only[]', 'queries', true %> <%= l(:label_query_plural) %> (<%= @source_project.queries.count %>)</label>\n  <label class=\"block\"><%= check_box_tag 'only[]', 'boards', true %> <%= l(:label_board_plural) %> (<%= @source_project.boards.count %>)</label>\n  <label class=\"block\"><%= check_box_tag 'only[]', 'wiki', true %> <%= l(:label_wiki_page_plural) %> (<%= @source_project.wiki.nil? ? 0 : @source_project.wiki.pages.count %>)</label>\n  <%= hidden_field_tag 'only[]', '' %>\n</fieldset>\n\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_copy) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/projects/core_vote.js.rjs",
    "content": "page.replace @member.user.login, :partial => 'team_list_member', :locals => {:member => @member}\n"
  },
  {
    "path": "app/views/projects/credits.html.erb",
    "content": "<% content_for :sidebar do %>\n<%= project_image @project %>\n<% if !@project.is_public %>\n  <h4><%= privacy @project %>This is a private workstream <%= help_bubble :help_this_workstream_is_private %></h4>\n<% end %>\n<% if @project.volunteer? %>\n  <h4><%= volunteering @project %>This is a volunteer-run workstream<%= help_bubble :help_volunteer %></h4>\n<% end %>\n\n<div class=\"gt-sidebar-nav gt-sidebar-nav-blue\">\n  <% if params[:with_subprojects] == 'false' %>\n  <h3>Sub Workstreams Excluded</h3>\n  <% else %>\n  <h3>Sub Workstreams Included</h3>\n  <% end %>\n\n\n  <ul>\n  <li>\n    <% if params[:with_subprojects] == 'false' %>\n    <%= link_to \"Include sub workstreams\", { :controller => 'projects', :action => 'credits', :with_subprojects => :true } %>\n    <% else %>\n    <%= link_to \"Exclude sub workstreams\", { :controller => 'projects', :action => 'credits', :with_subprojects => :false } %>\n    <% end %>\n  </li>\n  <li>\n    <%= link_to l(:label_credit_transfer), {:controller => 'credit_transfers', :action => 'index', :selected_project_id => @project.id} %>\n  </li>\n  </ul>\n</div>\n<% end %>\n\n<%= help_section(\"project_credits\") %>\n\n  <div class=\"splitcontentright\">\n      <%= render :partial => 'credits/credit_queue'%>\n  </div>\n  <div class=\"splitcontentleft\">\n      <%= render :partial => 'credits/credit_history'%>\n  </div>\n\n  <% if authorize_for(:credits, :create) %>\n  <%= link_to 'New credit', new_credit_path %>\n  <% end %>\n<% content_for :sidebar do %>\n    <div>\n    <%= render :partial => 'credits/my_credits'%>\n    </div>\n    <br><br>\n    <h2 class=\"gt-table-head\"><%=l(:label_credits_breakdown)%></h2>\n    <span id=\"active_credits_partial\">\n    <%= render :partial => 'credits/credit_breakdown', :locals => {:group_credits => @active_credits, :title => l(:label_active_credits)}%>\n    </span>\n    <br><br>\n    <%= render :partial => 'credits/credit_breakdown', :locals => {:group_credits => @oustanding_credits, :title => l(:label_outstanding_credits)}%>\n    <br><br>\n    <%= render :partial => 'credits/credit_breakdown', :locals => {:group_credits => @total_credits, :title => l(:label_total_credits_issued)}%>\n<% end %>\n\n<% html_title(l(:label_credits)) %>\n"
  },
  {
    "path": "app/views/projects/dashboard.html.erb",
    "content": "<%= javascript_include_tag  'jquery.ui.position' %>\n<%= stylesheet_link_tag 'dashboard' %>\n<%= javascript_include_tag 'dashboard' %>\n<%= javascript_include_tag 'json2.js' %>\n<%= javascript_include_tag 'jquery.fileupload.js' %>\n<%= javascript_include_tag 'jquery.fileupload-ui.js' %>\n<%= stylesheet_link_tag 'jquery.fileupload-ui' %>\n\n<!--[if lt IE 7]>\n<div style='border: 1px solid #F7941D; background: #FEEFDA; text-align: center; clear: both; height: 75px; position: relative;'>\n  <div style='position: absolute; right: 3px; top: 3px; font-family: courier new; font-weight: bold;'><a href='#' onclick='javascript:this.parentNode.parentNode.style.display=\"none\"; return false;'><img src='/images/static/ie6nomore-cornerx.jpg' style='border: none;' alt='Close this notice'/></a></div>\n  <div style='width: 640px; margin: 0 auto; text-align: left; padding: 0; overflow: hidden; color: black;'>\n    <div style='width: 75px; float: left;'><img src='/images/static/ie6nomore-warning.jpg' alt='Warning!'/></div>\n    <div style='width: 275px; float: left; font-family: Arial, sans-serif;'>\n      <div style='font-size: 14px; font-weight: bold; margin-top: 12px;'>You are using an unsuported browser</div>\n      <div style='font-size: 12px; margin-top: 6px; line-height: 12px;'>For a better experience using this site, please switch to a supported web browser.</div>\n    </div>\n    <div style='width: 75px; float: left;'><a href='http://www.firefox.com' target='_blank'><img src='/images/static/ie6nomore-firefox.jpg' style='border: none;' alt='Get Firefox 3.5'/></a></div>\n    <div style='width: 73px; float: left;'><a href='http://www.apple.com/safari/download/' target='_blank'><img src='/images/static/ie6nomore-safari.jpg' style='border: none;' alt='Get Safari 4'/></a></div>\n    <div style='float: left;'><a href='http://www.google.com/chrome' target='_blank'><img src='/images/static/ie6nomore-chrome.jpg' style='border: none;' alt='Get Google Chrome'/></a></div>\n  </div>\n</div>\n<![endif]-->\n\n<div id=\"dash_main\">\n  <%= help_section(\"project_dashboard\",true) %>\n<div id='loading' class='loading'>\n  <%= l(:text_loading_dashboard) %>\n</div>\n<div id='loading_error' class=\"hidden\">\n  <%= l(:text_loading_dashboard_error) %>\n</div>\n<div id='load_dashboard' style=\"display:none;text-align:center;width:100%\">\n  <table class=\"centeredTable\"><tr><td>\n    <a href=\"#\" onclick=\"load_dashboard();return false;\">Load Dashboard</a>\n  </td></tr></table>\n</div>\n\n<div id='panels' style=\"display: none;\">\n  <table id='main_table' class='dashboard' style='height: 100%;'>\n    <tr id='main_row'>\n\n    </tr>\n  </table>\n</div>\n\n<% content_for :secondnav do %>\n\n<div id=\"panel_buttons\">\n  <% if @project.children.any? %>\n  <div class=\"field switch\">\n      <label class=\"cb-enable\" id=\"toggle_sub_on\"><span>Include sub workstreams</span></label>\n      <label class=\"cb-disable\" id=\"toggle_sub_off\"><span>Don't include</span></label>\n      <input type=\"checkbox\" id=\"include_subworkstreams_checkbox\" class=\"checkbox\" />\n  </div>\n  <% end %>\n</div>\n<div class=\"gt-search-container\">\n  <div class=\"gt-search gt-search-narrow\">\n    <div class=\"gt-search-inner\">\n      <input id=\"fast_search\" type=\"text\" class=\"gt-search-text fast-search\" autocomplete=\"off\" size=\"20\" name=\"searchString\" value=\"\" onblur=\"searching = false;\" onfocus = \"searching = true;\">\n    </div>\n  </div>\n  <div class=\"dash-filter\">\n    <select id=\"filter_select\" class=\"filter-search\" onchange=\"filter_select();return false;\">\n      <option selected=\"selected\" value=\"all_top\">\n        Filter (show all)\n      </option>\n      <option value=\"all\">\n        Items that I&nbsp;&nbsp;»\n      </option>\n      <option value=\"untouched_by_me\">\n        &nbsp;&nbsp;» didn't touch\n      </option>\n      <option value=\"touched_by_me\">\n        &nbsp;&nbsp;» touched\n      </option>\n      <option value=\"added_by_me\">\n        &nbsp;&nbsp;» added\n      </option>\n      <option value=\"prioritized\">\n        &nbsp;&nbsp;» prioritized\n      </option>\n      <option value=\"all\">\n        Needs my&nbsp;&nbsp;»\n      </option>\n      <option value=\"unagreed\">\n        &nbsp;&nbsp;» agreement\n      </option>\n      <option value=\"unestimated\">\n        &nbsp;&nbsp;» estimate\n      </option>\n      <option value=\"unaccepted\">\n        &nbsp;&nbsp;» acceptance\n      </option>\n      <option value=\"unprioritized\">\n        &nbsp;&nbsp;» prioritization\n      </option>\n      <option value=\"all\">\n        Updated in last&nbsp;&nbsp;»\n      </option>\n      <option value=\"1\">\n        &nbsp;&nbsp;» 24 hours\n      </option>\n      <option value=\"2\">\n        &nbsp;&nbsp;» two days\n      </option>\n      <option value=\"3\">\n        &nbsp;&nbsp;» three days\n      </option>\n      <option value=\"7\">\n        &nbsp;&nbsp;» week\n      </option>\n      <option value=\"14\">\n        &nbsp;&nbsp;» two weeks\n      </option>\n      <option value=\"30\">\n        &nbsp;&nbsp;» month\n      </option>\n      <option value=\"60\">\n        &nbsp;&nbsp;» two months\n      </option>\n      <% tags = @project.all_tags %>\n      <% unless tags.empty? %>\n        <option value=\"all\">\n          Tagged with&nbsp;&nbsp;»\n        </option>\n        <% tags.each do |t| %>\n        <option value=\"<%= t %>\">\n          &nbsp;&nbsp;»&nbsp;<%= t %>\n        </option>\n        <% end %>\n      <% end %>\n    </select>\n  </div>\n  <div id='filtered_message' style=\"display:none;\" class=\"filtered-message\">\n    Filtered results&nbsp;<span id=\"filter_detail\" style=\"font-weight:bold;\"></span>\n    &nbsp;&nbsp;&nbsp;&nbsp;<a onclick=\"clear_filters();return false;\" class=\"clickable bold icon icon-x\">Clear</a>\n  </div>\n</div>\n\n\n\n<% end %>\n\n<% content_for :actionmenu do -%>\n<ul>\n  <li>\n    <a id=\"refresh_data\" onclick=\"refresh_local_data();return false;\"  href=\"#\" class=\"icon icon-refresh\">\n      Refresh\n    </a>\n  </li>\n  <li>\n    <a id=\"new_request\" onclick=\"new_item();return false;\" href=\"#\" class=\"icon icon-add\">\n      New Item\n    </a>\n  </li>\n  <li>\n    <a id=\"dash_key\" onclick=\"return false;\"  href=\"#\"  class=\"top-help-tip icon icon-help\">\n      Key\n    </a>\n  </li>\n</ul>\n\n\n<% end -%>\n\n<%# content_for :buttonbar do %>\n<%# end %>\n\n<%= render :partial => 'projects/dashboard_javascript_variables', :locals => {:project => @project} %>\n\n<script type=\"text/javascript\">\n  var show_issue_id = '<%= @show_issue_id %>';\n  var show_retro_id = '<%= @show_retro_id %>';\n\n  $('document').ready(function(){\n      start();\n  });\n\n</script>\n\n\n\n\n\n\n<div id='flyovers' style=\"display:none;\">\n\n<div id=\"help_description\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:180px\">\n    <strong>Description</strong><br>\n    A request's description should contain the criteria for the acceptance of the request.<br>\n    It should clearly answer the question: <strong>How exactly will we measure that this request is done?</strong> This may take the form of user requirements, acceptance tests, a link to an external document, etc.\n  </div>\n</div>\n\n<div id=\"help_requestid\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:180px\">\n    <strong>Permalink</strong><br>\n    You can copy the link below and use it to directly link to this request\n  </div>\n</div>\n\n<div id=\"help_feature\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <% if @project.credits_enabled? %>\n      <strong>There are 6 types of requests:</strong><br><br>\n    <% else %>\n      <strong>There are 4 types of requests:</strong><br><br>\n    <% end %>\n    A <strong>Feature</strong> provides verifiable value to the team's customer. Usually it is requested by the customer. The customer can be an internal customer to the enterprise.<br><br>\n    A <strong>Chore</strong> is used internally by the team to track items that don't directly provide value to the team's customer.<br><br>\n    A <strong>Bug</strong> describes a problem in some previously accepted feature or chore.<br><br>\n    A <strong>Recurring</strong> request occurs for repeating needs. Once a recurring request is finished, a new copy of the request is generated and added to the open panel<br><br>\n    <% if @project.credits_enabled? %>\n      A <strong>Gift</strong> gives a single user a gift of a certain amount of credits.<br>Gift items are not visible by the gift recipient until it's approved.<br><br>\n      An <strong>Expense</strong> as a fixed value, and cannot be estimated or joined. Expenses are immediately reimbursed after they are accepted, and they don't show up in retrospectives.'<br>\n    <% end %>\n  </div>\n</div>\n\n<div id=\"help_tags\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <strong>Tags</strong> are generally chosen informally and personally by the item's creator or by its viewer, depending on the system.<br><br>\n    This kind of metadata helps describe an item and allows it to be found again by browsing or searching.\n  </div>\n</div>\n\n\n<div id=\"help_complexity_credits\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <strong>Estimate Credits:</strong><br><br>\n    <p>Estimate the value of the work item to the project. In other words, how much a person/team will be awarded in credits for completing it.</p><br>\n    <p>If you don't know what kind of effort it would take to complete this task, please don't guess. Just choose \"I don't know\"</p><br>\n    <p><strong>Items that won't move to the open queue until they're estimated by at least one member.</strong></p>\n  </div>\n</div>\n\n<div id=\"help_complexity_no_credits\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <strong>Complexity:</strong><br><br>\n    <p>Estimate the size and complexity of this work item.</p><br>\n    <p>If you don't know what kind of effort it would take to complete this task, please don't guess. Just choose \"I don't know\"</p><br>\n    <p><strong>Items that won't move to the open queue until they're estimated by at least one member.</strong></p>\n  </div>\n</div>\n\n\n\n\n<div id=\"help_estimate\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <strong>Estimates</strong><br>\n    Ideas are estimated in Points. A Point is a team-specific measurement of the effort required to get the request done. Estimates are used to calculate the budget for the request.\n  </div>\n</div>\n\n<div id=\"help_panel_new\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <strong>New Ideas</strong><br>\n      New requests are fresh off of somebody's brain. They are ripe for discussion and consideration. <br><br>\n      At this stage, it's too early to try to prioritize the work. You should mainly focus on giving a new request your thumbs up (or down) indicating wether or not you think it would be useful to get it done.<br><br> And make sure that it is a concise, measurable and realistic request. This is also a good time to ensure that acceptance criteria is clear for this requests i.e. there's an indication of how the team will know that the request is done.<br><br>Once people have agreed that an idea needs to be implemented, it's now a matter of sizing them up by assigning them a number of points.<br> Once enough members have weighed in the request is moved to the open Queue.\n  </div>\n</div>\n\n<div id=\"help_panel_estimate\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <strong>Ideas In Estimation</strong><br>\n  </div>\n</div>\n\n<div id=\"help_panel_inprogress\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <strong>Ideas In Progress</strong><br>\n      In Progress requests are owned by someone who is actively working on them. All in progress requests have a maximum delivery time of 30 days. <br><br> Any request that has been in progress for more than 30 days is assumed abandoned and gets automatically pulled back into the \"open\" queue.\n  </div>\n</div>\n\n<div id=\"help_panel_open\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <strong>Open Ideas</strong><br>\n      These requests are ready to be prioritized, started or canceled. <br>\n      To prioritize a request click the up button. Every time a user prioritizes a request, it climbs higher up the queue.\n      Only the highest requests (ranked by priority) can be started. As well as all request estimated at zero points<br><br>\n      If a request hasn't been prioritized by anyone and has been sitting in the queue for more than a month you have the option of canceling it. <br>\n  </div>\n</div>\n\n<div id=\"help_panel_done\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <strong>Done Ideas</strong><br>\n      Once a request is finished its marked Done. Citizens now vote on wether or not the request has met its acceptance criteria.<br><br> Each citizen gets one vote to accept or reject a finished request. Once 3 days have passed after the last vote the request is either permanently accepted or rejected based on a tally of the votes. <br>If there's an equal number of accepts and rejects the request is considered rejected.\n  </div>\n</div>\n\n<div id=\"help_panel_canceled\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <strong>Canceled Ideas</strong><br>\n      If a request hasn't been prioritized by anyone and has been sitting in the queue for more than a month, anyone team member can cancel it.<br><br>\n      Once a request has been canceled, anyone can re-open it, effectively pushing it back as a new item for reconsideration.\n  </div>\n</div>\n\n<div id=\"help_panel_unknown\" style=\"display:none;\">\n  <div class=\"tip\" style=\"width:300px\">\n    <strong>Unsorted Ideas</strong><br>\n    Legacy requests that don't belong in the system anymore. Think of them as bugs in the matrix!\n  </div>\n</div>\n\n<div id=\"help_key\" style=\"display:none\">\n   <div class=\"tip\" style=\"width:600px\">\n     <strong>Dashboard Key</strong><br>\n     <table class=\"dash_key\">\n       <tr><td>\n     <strong>Work Items</strong><br>\n     <img src=\"/images/feature_icon.png\" class=\"storyTypeIcon hoverDetailsIcon\">&nbsp;Feature<br>\n     <img src=\"/images/bug_icon.png\" class=\"storyTypeIcon hoverDetailsIcon\">&nbsp;Bug<br>\n     <img src=\"/images/chore_icon.png\" class=\"storyTypeIcon hoverDetailsIcon\">&nbsp;Chore<br>\n     <img src=\"/images/gift_icon.png\" class=\"storyTypeIcon hoverDetailsIcon\">&nbsp;Gift<br>\n     <img src=\"/images/expense_icon.png\" class=\"storyTypeIcon hoverDetailsIcon\">&nbsp;Expense<br>\n     <img src=\"/images/recurring_icon.png\" class=\"storyTypeIcon hoverDetailsIcon\">&nbsp;Recurring<br>\n     <br><strong>Estimation</strong><br>\n     <img src=\"/images/dice_No.png\" class=\"storyPoints hoverDiceIcon\">&nbsp;Estimate needed<br>\n     <img src=\"/images/dice_4.png\" class=\"storyPoints hoverDiceIcon\">&nbsp;Average estimate<br>\n\n     <br><strong>Priority</strong><br>\n     <div class=\"pri_button_no_float pri_button_up left\"></div>&nbsp;You prioritized this<br>\n     <div class=\"pri_button_no_float pri_button_down left\"></div>&nbsp;You de-prioritized this<br>\n     <div class=\"pri_button_no_float pri_button_neutral left\"></div>&nbsp;You set this pri to neutral<br>\n     <div class=\"pri_button_no_float pri_button_none left\"></div>&nbsp;You haven't prioritized this<br>\n     <div class=\"pri_button_no_float pri_button_none left\">3</div>&nbsp;Total priority is 3<br><br>\n     <a href=\"http://help.bettermeans.com/dashboard\" target=\"blank\">Learn more</a>\n\n     </td><td>\n     <strong>Agreement Voting</strong><br>\n     <div class=\"action_button_no_float action_button_root\">agree?</div>&nbsp;You haven't voted yet<br>\n     <div class=\"action_button_no_float action_button_agree\">agreed</div>&nbsp;You agreed<br>\n     <div class=\"action_button_no_float action_button_neutral\">neutral</div>&nbsp;You are neutral<br>\n     <div class=\"action_button_no_float action_button_against\">against</div>&nbsp;You voted against<br>\n     <div class=\"action_button_no_float action_button_block\">blocked</div>&nbsp;You are blocking<br>\n\n     <br><strong>Acceptance Voting</strong><br>\n     <div class=\"action_button_no_float action_button_root\">accept?</div>&nbsp;You haven't voted yet<br>\n     <div class=\"action_button_no_float action_button_accept\">accepted</div>&nbsp;You accepted<br>\n     <div class=\"action_button_no_float action_button_neutral\">neutral</div>&nbsp;You are neutral<br>\n     <div class=\"action_button_no_float action_button_reject\">rejected</div>&nbsp;You rejected this<br>\n     <div class=\"action_button_no_float action_button_block\">blocked</div>&nbsp;You are blocking<br>\n\n     <br><strong>Actions</strong><br>\n     <div class=\"action_button_no_float action_button_start_no_hide\">start</div>&nbsp;Commit to an item and own it<br>\n     <div class=\"action_button_no_float action_button_join\">join</div>&nbsp;Join an item that already has an owner<br>\n     <div class=\"action_button_no_float action_button_finish\">finish</div>&nbsp;Complete a work item<br>\n     <div class=\"action_button_no_float action_button_cancel\">cancel</div>&nbsp;Set item state to canceled<br>\n     <div class=\"action_button_no_float action_button_release\">giveup</div>&nbsp;Release an item you own<br>\n     <div class=\"action_button_no_float action_button_leave\">leave</div>&nbsp;Leave an item you previously joined<br>\n     </td></tr>\n     </table>\n\n   </div>\n\n </div>\n\n\n</div>\n</div>\n\n<% content_for :footer do %>\n\n<% end %>\n"
  },
  {
    "path": "app/views/projects/index.html.erb",
    "content": "<% @page_header_name = l(:label_browse_workstreams) %>\n<%= help_section \"browse_workstreams\" %>\n\n<div class=\"splitcontentright\">\n    <% if @latest_enterprises.any? %>\n  <h2 class=\"gt-table-head icon icon-projects\"><%=l(:label_enterprise_latest)%></h2>\n  <div class=\"gt-content-box\">\n    <%= render :partial => 'project_list', :locals => {:projects => @latest_enterprises, :offset => 0, :index_type => 'latest', :offset => 10} %>\n  </div>\n\n  <% end %>\n</div>\n\n<div class=\"splitcontentleft\">\n    <% if @active_enterprises.any? %>\n  <h2 class=\"gt-table-head icon icon-projects\"><%=l(:label_enterprise_active)%></h2>\n  <div class=\"gt-content-box\">\n  <%= render :partial => 'project_list', :locals => {:projects => @active_enterprises, :offset => 0, :index_type => 'active', :offset => 10} %>\n  </div>\n  <% end %>\n</div>\n\n<% content_for :actionmenu do %>\n    <ul>\n    <li>\n      <%= link_to l(:label_project_new), {:controller => 'projects', :action => 'add', :parent_id => @project}, :class => \"icon icon-add\" %>\n    </li>\n    </ul>\n    <ul>\n    </ul>\n<% end %>\n\n<script>\n  $('document').ready(function(){\n    display_sparks();\n  });\n</script>\n\n<% html_title(l(:label_project_plural)) -%>\n"
  },
  {
    "path": "app/views/projects/list_files.html.erb",
    "content": "\n<h2><%=l(:label_attachment_plural)%></h2>\n\n<% delete_allowed = User.current.allowed_to?(:manage_files, @project) %>\n\n<table class=\"gt-table files\">\n  <thead><tr>\n    <%= sort_header_tag('filename', :caption => l(:field_filename)) %>\n    <%= sort_header_tag('created_at', :caption => l(:label_date), :default_order => 'desc') %>\n    <%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc') %>\n    <%= sort_header_tag('downloads', :caption => l(:label_downloads_abbr), :default_order => 'desc') %>\n    <th>MD5</th>\n    <th></th>\n  </tr></thead>\n  <tbody>\n<% @containers.each do |container| %>\n  <% next if container.attachments.empty? -%>\n  <% container.attachments.each do |file| %>\n  <tr class=\"file <%= cycle(\"odd\", \"even\") %>\">\n    <td class=\"filename\"><%= link_to_attachment file, :download => true, :title => file.description %></td>\n    <td class=\"created_at\"><%= format_time(file.created_at) %></td>\n    <td class=\"filesize\"><%= number_to_human_size(file.filesize) %></td>\n    <td class=\"downloads\"><%= file.downloads %></td>\n    <td class=\"digest\"><%= file.digest %></td>\n    <td align=\"center\">\n    <%= link_to(image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => file},\n                                         :confirm => l(:text_are_you_sure), :method => :post) if delete_allowed %>\n    </td>\n  </tr>\n  <% end\n  reset_cycle %>\n<% end %>\n  </tbody>\n</table>\n\n<% html_title(l(:label_attachment_plural)) -%>\n\n<% content_for :sidebar do %>\n  <div class=\"gt-sidebar-nav gt-sidebar-nav-gray\">\n    <ul>\n      <li>\n        <%= link_to_if_authorized l(:label_attachment_new), {:controller => 'projects', :action => 'add_file', :id => @project}, :class => 'icon icon-add' %>\n      </li>\n    </ul>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/projects/list_members.html.erb",
    "content": "<h2><%=l(:label_team)%></h2>\n\n<% if @members.empty? %><p><i><%= l(:label_no_data) %></i></p><% end %>\n\n<% members = @members.group_by {|m| m.role } %>\n<% members.keys.sort{|x,y| x.position <=> y.position}.each do |role| %>\n<h3><%= role.name %></h3>\n<ul>\n<% members[role].each do |m| %>\n<li><%= link_to_user m.user %> (<%= format_date m.created_at %>)</li>\n<% end %>\n</ul>\n<% end %>\n"
  },
  {
    "path": "app/views/projects/map.html.erb",
    "content": "<%= javascript_include_tag 'jit' %>\n<%= javascript_include_tag 'enterprise_map' %>\n<%= stylesheet_link_tag 'enterprise_map' %>\n\n<a href=\"#\" onclick=\"refresh_data();return false;\">Refresh</a>\n\n<script type=\"text/javascript\">\nvar json = <%= @project.graph_data.to_json %>;\nvar json2 = <%= @project.graph_data2.to_json %>;\n\n$('document').ready(function(){\n    init();\n});\n\n</script>\n\n<div id=\"container\">\n  <%= help_section(\"project_map\") %>\n\n<div id=\"center-container\">\n    <div id=\"infovis\"></div>\n</div>\n\n<div id=\"inner-details\"></div>\n\n</div>\n\n\n<% content_for :sidebar do %>\n<%= project_image @project %>\n<% end %>\n"
  },
  {
    "path": "app/views/projects/move.html.erb",
    "content": "<h2><%= l(:label_move_project) %></h2>\n\n\n<% form_tag({}, :id => 'move_form') do %>\n<%= hidden_field_tag('id', @project.id) %>\n\n<div class=\"gt-content-box tabular\">\n  <p>\n    <%= link_to_project @project %>\n  </p>\n<p><label for=\"parent_id\"><%=l(:field_parent_project)%>:</label>\n<%= select_tag \"parent_id\",\n               project_tree_options_for_select(@allowed_projects, :selected => @project.parent),\n               :onchange => remote_function(:url => { :action => 'move' },\n                                            :method => :get,\n                                            :update => 'content',\n                                            :with => \"Form.serialize('move_form')\") %></p>\n\n</div>\n\n  <%= submit_tag l(:button_move), :disable_with => l(:button_working) %>\n<% end %>\n\n"
  },
  {
    "path": "app/views/projects/overview.html.erb",
    "content": "<%= help_section(\"project_show\") %>\n\n<div>\n  <h2 class=\"gt-table-head icon icon-activity\"><%=l(:label_activity_latest)%></h2>\n  <div class=\"activity gt-content-box\">\n    <%= render :partial => 'activity_streams/activity_stream_list', :locals => {\n      :user_id => params[:user_id],\n      :project_id => @project.id,\n      :with_subprojects => params[:with_subprojects],\n      :limit => 20,\n      :max_created_at => nil\n    } %>\n  </div>\n</div>\n\n<% content_for :actionmenu do %>\n<ul>\n  <li>\n    <%= link_to l(:label_login), {:controller => :account, :action => :login} unless User.current.logged? %>\n  </li>\n<% if User.current.allowed_to?(:add_subprojects, @project) %>\n<li>\n  <%= link_to l(:label_subproject_new), {:controller => 'projects', :action => 'add', :parent_id => @project}, :class => \"icon icon-add\" %>\n</li>\n<% end %>\n<% if User.current.allowed_to?(:send_invitations, @project) && @project.root? %>\n<li>\n  <%= link_to l(:label_invitation_new), new_project_invitation_url(@project), :class => \"icon icon-users\" %>\n</li>\n<% end %>\n<li>\n<%= link_to_if_authorized l(:label_motions_new), {:controller => 'motions', :action => 'new', :project_id => @project}, :class => \"icon icon-motion\" %>\n</li>\n<% if @project && @project.module_enabled?(:issue_tracking) %>\n<% end %>\n</ul>\n<% end %>\n\n\n<% content_for :sidebar do %>\n<% if @project.description.length > 0 %>\n  <div class=\"gt-sidebar-content\">\n  <h2 class=\"icon icon-project\"><%=h @project.name %></h2>\n  <%= make_expandable ((textilizable @project.description), 80) %>\n  </div>\n<% end %>\n\n<% if @motions.any? %>\n<h2 class=\"icon icon-motion\"><%=l(:label_motions_active)%></h2>\n<div class=\"motions gt-content-box\">\n  <%= render :partial => 'motions/motions', :locals =>{:motions => @motions, :max_count => 2} %>\n</div>\n<% end %>\n\n<% if @news.any? && authorize_for('news', 'index') %>\n<h2 class=\"icon icon-news\"><%=l(:label_news_latest)%></h2>\n<div class=\"news gt-content-box\">\n  <%= render :partial => 'news/news', :locals => {:max_count => 2} %>\n</div>\n<% end %>\n\n<%  if @subprojects.any? %>\n  <h2 class=\"icon icon-projects\"><%= l(:label_subproject_plural) %></h2>\n  <div class=\"gt-content-box active-projects\">\n  <%= render :partial => 'projects/projects_list_simple', :locals => {:projects => @subprojects, :max_count => 7} %>\n  </div>\n<% end %>\n\n\n<% if @project.enterprise? %>\n  <%= render :partial => \"member_box\" %>\n<% else %>\n  <%= render :partial => \"active_member_box_simple\" %>\n  <%= render :partial => \"clearance_member_box\" unless @project.is_public %>\n<% end %>\n\n<% if User.current.allowed_to?(:view_issues, @project) && false %>\n    <div class=\"gt-sidebar-nav gt-sidebar-nav-gray\">\n    <h3><%=l(:label_issue_tracking)%></h3>\n    <ul>\n            <% for tracker in @trackers %>\n              <li><div style=\"float:right;width:70%\">\n                  <%= link_to l(:label_x_open_issues_abbr_on_total, :count => @open_issues_by_tracker[tracker].to_i,\n                  :total => @total_issues_by_tracker[tracker].to_i), :controller => 'issues', :action => 'index', :project_id => @project,\n                                                        :set_filter => 1,\n                                                        \"tracker_id\" => tracker.id %></div>\n                  <div style=\"width:30%;\"><%= link_to tracker.name, :controller => 'issues', :action => 'index', :project_id => @project,\n                                                        :set_filter => 1,\n                                                        \"tracker_id\" => tracker.id %></div>\n              </li>\n            <% end %>\n    </ul>\n    </div>\n<% end %>\n\n<% if @project.credits_enabled? && false%>\n\n      <div class=\"gt-sidebar-content\">\n        <h3><%= l(:label_dpp_scale) %><span><%= help_bubble :help_dpp %></span></h3>\n        <p><%= render :partial => 'point_scale', :locals => { :dpp => @project.dpp.round, :unit => unit_for(@project) } unless @project.dpp.nil? %></p>\n      </div>\n    <% end %>\n<% end %>\n\n<% html_title(l(:label_overview)) -%>\n\n<script>\n  $('document').ready(function(){\n    display_sparks();\n  });\n</script>\n"
  },
  {
    "path": "app/views/projects/settings/_boards.html.erb",
    "content": "<% if @project.boards.any? %>\n<div class=\"gt-content-box padded\">\n<table class=\"gt-table\">\n  <thead>\n    <th><%= l(:label_board) %></th>\n    <th><%= l(:field_description) %></th>\n    <th></th>\n    <th></th>\n  </thead>\n  <tbody>\n<% @project.boards.each do |board|\n  next if board.new_record? %>\n  <tr class=\"<%= cycle 'odd', 'even' %>\">\n    <td><%=h board.name %></td>\n    <td><%=h board.description %></td>\n    <td align=\"center\">\n    <% if authorize_for(\"boards\", \"edit\") %>\n      <%= reorder_links('board', {:controller => 'boards', :action => 'edit', :project_id => @project, :id => board}) %>\n    <% end %>\n    </td>\n    <td class=\"buttons\">\n      <% unless board.name == \"General\" %>\n      <%= link_to_if_authorized l(:button_edit), {:controller => 'boards', :action => 'edit', :project_id => @project, :id => board}, :class => 'icon icon-edit' %>\n      <%= link_to_if_authorized l(:button_delete), {:controller => 'boards', :action => 'destroy', :project_id => @project, :id => board}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>\n      <% end %>\n    </td>\n  </tr>\n<% end %>\n  </tbody>\n</table>\n<% else %>\n<p class=\"nodata\"><%= l(:label_no_data) %></p>\n<% end %>\n</div>\n\n<p><%= link_to_if_authorized l(:label_board_new), {:controller => 'boards', :action => 'new', :project_id => @project}, :class=>\"gt-btn-gray-large\"%></p>\n"
  },
  {
    "path": "app/views/projects/settings/_hourly_types.html.erb",
    "content": "<% if @project.hourly_types.any? %>\n<table class=\"gt-table\">\n  <thead>\n    <th><%= l(:label_hourly_type) %></th>\n    <th><%= l(:label_hourly_rate_per_person) %></th>\n    <th><%= l(:label_hourly_cap) %></th>\n    <th/>\n  </thead>\n  <tbody>\n    <% @project.hourly_types.each do |hourly_type|\n       next if hourly_type.new_record? %>\n    <tr class=\"<%= cycle 'odd', 'even' %>\">\n      <td><%=h hourly_type.name %></td>\n      <td><%=h hourly_type.hourly_rate_per_person %></td>\n      <td><%=h hourly_type.hourly_cap %></td>\n      <td class=\"buttons\">\n      <%= link_to l(:button_edit), {:controller => 'hourly_types', :action => 'edit', :project_id => @project, :id => hourly_type}, :class => 'icon icon-edit' %>\n      <%= link_to l(:button_delete), {:controller => 'hourly_types', :action => 'destroy', :project_id => @project, :id => hourly_type}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>\n      </td>\n    </tr>\n<% end %>\n  </tbody>\n</table>\n<% else %>\n<p class=\"nodata\"><%= l(:label_no_data) %></p>\n<% end %>\n<p><%= link_to l(:label_hourly_type_new), {:controller => 'hourly_types', :action => 'new', :project_id => @project} %></p>\n"
  },
  {
    "path": "app/views/projects/settings/_members.html.erb",
    "content": "<%= error_messages_for 'member' %>\n<% roles = @project.enterprise? ? Role.find_all_givable(Role::LEVEL_ENTERPRISE) : Role.find_all_givable(Role::LEVEL_PROJECT)\n   members = @project.member_users.find(:all, :include => [:roles, :user]).sort %>\n\n<div class=\"splitcontentleft\">\n<div class=\"gt-content-box padded\">\n<% if members.any? %>\n<table class=\"gt-table border='0'\">\n  <thead>\n    <th><%= l(:label_user) %> / <%= l(:label_group) %></th>\n    <th><%= l(:label_role_plural) %></th>\n    <th style=\"width:15%\"></th>\n  </thead>\n  <tbody>\n  <% members.each do |member| %>\n  <% next if member.new_record? %>\n  <tr id=\"member-<%= member.id %>\" class=\"<%= cycle 'odd', 'even' %> member\">\n  <td class=\"<%= member.user.class.name.downcase %>\"><%= link_to_user member.user %></td>\n  <td class=\"roles\">\n    <span id=\"member-<%= member.id %>-roles\"><%=h member.roles.sort.collect(&:to_s).join(', ') %></span>\n    <% if authorize_for('members', 'edit') %>\n      <% remote_form_for(:member, member, :url => {:controller => 'members', :action => 'edit', :id => member},\n                                          :method => :post,\n                                          :html => { :id => \"member-#{member.id}-roles-form\", :style => 'display:none;' }) do |f| %>\n        <p><% roles.each do |role| %>\n        <label><%= check_box_tag 'member[role_ids][]', role.id, member.roles.include?(role),\n                                                       :disabled => member.member_roles.detect {|mr| mr.role_id == role.id && !mr.inherited_from.nil?} %> <%=h role %></label><br />\n        <% end %></p>\n        <%= hidden_field_tag 'member[role_ids][]', '' %>\n        <%= submit_tag l(:button_change), :disable_with => l(:button_working) %>\n        <p class=\"gt-cancel\" style=\"float:none;\">\n        <%= link_to_function l(:button_cancel), \"$('#member-#{member.id}-roles').show(); $('#member-#{member.id}-roles-form').hide(); return false;\" %></p>\n      <% end %>\n    <% end %>\n  </td>\n  <td class=\"buttons\">\n      <%= link_to_function l(:button_edit), \"$('#member-#{member.id}-roles').hide(); $('#member-#{member.id}-roles-form').show(); return false;\", :class => 'icon icon-edit' %>\n      <%= link_to_remote(l(:button_delete), { :url => {:controller => 'members', :action => 'destroy', :id => member},\n                                              :confirm => \"Are you sure you want to remove #{member.user.name}?\",\n                                              :method => :post\n                                            }, :title => l(:button_delete),\n                                               :class => 'icon icon-del') if member.deletable? %>\n  </td>\n  </tr>\n  </tbody>\n<% end; reset_cycle %>\n</table>\n<% else %>\n<p class=\"nodata\"><%= l(:label_no_data) %></p>\n<% end %>\n</div>\n</div>\n\n<div class=\"splitcontentright\">\n  <% if User.current.allowed_to?(:send_invitations, @project) %>\n  <div class=\"gt-sidebar-nav gt-sidebar-nav-blue\">\n    <ul>\n    <li style=\"text-align:center;\">\n      <%= link_to l(:label_invitation_new), new_project_invitation_url(@project) %>\n    </li>\n    </ul>\n  </div>\n  <% end %>\n\n</div>\n"
  },
  {
    "path": "app/views/projects/settings/_modules.html.erb",
    "content": "<div class=\"gt-content-box padded\">\n\n<% form_for :project, @project,\n            :url => { :action => 'modules', :id => @project },\n            :html => {:id => 'modules-form'} do |f| %>\n\n<div class=\"gt-left-col\">\n<strong><%= l(:text_select_project_modules) %></strong>\n<br><br>\n<% Redmine::AccessControl.available_project_modules.each do |m| %>\n <label class=\"floating\" style=\"display:inline\">\n   <%= check_box_tag 'enabled_modules[]', m, @project.module_enabled?(m), :id => \"check_box_#{m}\" %>\n <%= l_or_humanize(m, :prefix => \"project_module_\") %>\n <%= help_bubble \"help_#{m}\" %><br>\n </label>\n<% end %>\n</div>\n\n<div id=\"point_scale_container\" class=\"gt-right-col\" style=\"<%= @project.credits_enabled? ? nil : 'display:none'%>\">\n<p>\n  <br><br>\n  <fieldset>\n<%=  f.select(:dpp, options_for_select(Setting::PAY_SCALES, :selected => @project.dpp.nil? ? Setting::PAY_SCALES_DEFAULT : @project.dpp.round),\n                                                      { :include_blank => false},\n                                                      { :onchange => \"#{remote_function(:url  => {:action => \"update_scale\"},\n                                                                                                            :with => \"'dpp='+value\")}\"})%>\n  <span><%= help_bubble :help_select_scale %></span>\n  <%= render :partial => 'point_scale', :locals => {:unit => unit_for(@project), :dpp => @project.dpp.nil? ? Setting::PAY_SCALES_DEFAULT : @project.dpp.round } %>\n  </fieldset>\n</p>\n</div>\n\n<div class=\"clear\" />\n</div>\n\n<br>\n<p><%= check_all_links 'modules-form' %></p>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n</div>\n\n<script type=\"text/javascript\">\n\n  function toggle_credits(){\n    if($(\"#check_box_credits\").is(':checked')) {\n       $(\"#point_scale_container\").show();\n     }\n     else{\n       $(\"#point_scale_container\").hide();\n     }\n  }\n\n  $(document).ready(function(){\n    $(\"#check_box_credits\").click(function(){\n      toggle_credits();\n    });\n    toggle_credits();\n  });\n\n</script>\n\n"
  },
  {
    "path": "app/views/projects/settings/_select_new_member.html.erb",
    "content": "<div class=\"gt-content-box padded\">\n<% users = User.active.find(:all, :limit => 100, :order => 'type, login, lastname ASC') - @project.users %>\n<% if roles.any? && users.any? %>\n  <% remote_form_for(:member, @member, :url => {:controller => 'members', :action => 'new', :id => @project}, :method => :post) do |f| %>\n    <fieldset><legend><%=l(:label_member_new)%></legend>\n\n    <p><%= text_field_tag 'user_search', nil, :size => \"40\" %></p>\n    <%= observe_field(:user_search,\n                 :frequency => 0.5,\n                 :update => :users,\n                 :url => { :controller => 'members', :action => 'autocomplete_for_member', :id => @project },\n                 :with => 'q')\n                  %>\n\n    <div id=\"users\">\n      <%= users_check_box_tags 'member[user_ids][]', users %>\n    </div>\n\n    <p><%= l(:label_role_plural) %>:\n    <% roles.each do |role| %>\n      <label><%= check_box_tag 'member[role_ids][]', role.id %> <%=h role %></label>\n     <% end %></p>\n\n    <div class=\"gt-table-buttons\">\n    <%= submit_tag l(:button_add), :disable_with => l(:button_working) %>\n    </div>\n    </fieldset>\n  <% end %>\n<% end %>\n</div>\n"
  },
  {
    "path": "app/views/projects/settings/_wiki.html.erb",
    "content": "<% remote_form_for :wiki, @wiki,\n                   :url => { :controller => 'wikis', :action => 'edit', :id => @project },\n                   :builder => TabularFormBuilder,\n                   :lang => current_language do |f| %>\n\n<%= error_messages_for 'wiki' %>\n\n<div class=\"gt-content-box tabular\">\n<p><%= f.text_field :start_page, :size => 60, :required => true %><br />\n<em><%= l(:text_unallowed_characters) %>: , . / ? ; : |</em></p>\n</div>\n\n<div class=\"contextual\">\n<%= link_to(l(:button_delete), {:controller => 'wikis', :action => 'destroy', :id => @project},\n            :class => 'icon icon-del') if @wiki && !@wiki.new_record? %>\n</div>\n<div class=\"gt-table-buttons\">\n<%= submit_tag((@wiki.nil? || @wiki.new_record?) ? l(:button_create) : l(:button_save)) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/projects/settings.html.erb",
    "content": "<%= render_tabs project_settings_tabs %>\n\n<% html_title(l(:label_settings)) -%>\n\n<% content_for :actionmenu do %>\n<ul>\n<li>\n  <% if @project.active? %>\n  <%= link_to(l(:label_archive_project), {:controller => 'projects', :action => 'archive', :id => @project}, {:confirm => l(:text_confirm_archive_project), :method => :post}) %>\n  <% else %>\n  <%= link_to(l(:label_unarchive_project), {:controller => 'projects', :action => 'unarchive', :id => @project}, {:confirm => l(:text_confirm_unarchive_project), :method => :post}) %>\n  <% end %>\n</li>\n<li>\n  <%= link_to(l(:label_delete_project), {:controller => 'projects', :action => 'destroy', :id => @project}, {:confirm => l(:text_confirm_delete_project), :method => :post}) %>\n</li>\n<% unless @project.root? %>\n<li id='move_project_link'>\n  <%= link_to(l(:label_move_project), {:controller => 'projects', :action => 'move', :id => @project}) %>\n</li>\n<% end %>\n<li>\n</li>\n</ul>\n<% end %>\n\n\n<% content_for :sidebar do %>\n<%= help_section(\"project_settings\") %>\n<% end %>\n"
  },
  {
    "path": "app/views/projects/show.png.flexi",
    "content": "@project.operate do |image|\n    image.resize '100*200'\n    #image.shadow :background  => 'white' #, :blur => 30\nend"
  },
  {
    "path": "app/views/projects/team.html.erb",
    "content": "<%= help_section(\"project_team\") %>\n<%= error_messages_for 'member' %>\n\n<div class=\"splitcontentleft\">\n<%= render :partial => 'team_list', :locals => {:project => @project} %>\n</div>\n\n<div class=\"splitcontentright\">\n  <%= render :partial => \"active_member_box\" %>\n</div>\n\n<% content_for :actionmenu do %>\n  <ul>\n  <% if User.current.allowed_to?(:send_invitations, @project) %>\n  <li>\n    <%= link_to l(:label_invitation_new), new_project_invitation_url(@project), :class => \"icon icon-users\" %>\n  </li>\n  <% end %>\n  </ul>\n<% end %>\n<% html_title(l(:label_team)) %>\n"
  },
  {
    "path": "app/views/projects/team_update.js.rjs",
    "content": "page.replace 'team_list' , :partial => 'team_list', :locals => {:project => @project}\npage.replace 'team_link' , :partial => 'team_link' , :locals => {:project => @project}\npage.call 'add_lightbox', 'help_button_core_points' #adding hook to create button for lightbox\n\npage[User.current.login].visual_effect :highlight\n"
  },
  {
    "path": "app/views/queries/_columns.html.erb",
    "content": "<table style=\"border-collapse: collapse; border:0;\">\n  <tr>\n    <td style=\"padding-left:0\"><%= select_tag 'available_columns',\n              options_for_select((query.available_columns - query.columns).collect {|column| [column.caption, column.name]}),\n              :multiple => true, :size => 10, :style => \"width:150px\" %>\n    </td>\n    <td align=\"center\" valign=\"middle\">\n      <input type=\"button\" value=\"&#8594;\"\n       onclick=\"moveOptions(this.form.available_columns, this.form.selected_columns);\" /><br />\n      <input type=\"button\" value=\"&#8592;\"\n       onclick=\"moveOptions(this.form.selected_columns, this.form.available_columns);\" />\n    </td>\n    <td><%= select_tag 'query[column_names][]',\n              options_for_select(query.columns.collect {|column| [column.caption, column.name]}),\n              :id => 'selected_columns', :multiple => true, :size => 10, :style => \"width:150px\" %>\n    </td>\n    <td align=\"center\" valign=\"middle\">\n      <input type=\"button\" value=\"&#8593;\" onclick=\"moveOptionUp(this.form.selected_columns);\" /><br />\n      <input type=\"button\" value=\"&#8595;\" onclick=\"moveOptionDown(this.form.selected_columns);\" />\n    </td>\n  </tr>\n</table>\n\n<% content_for :header_tags do %>\n<%= javascript_include_tag 'select_list_move' %>\n<% end %>\n"
  },
  {
    "path": "app/views/queries/_filters.html.erb",
    "content": "<script type=\"text/javascript\">\n//<![CDATA[\nfunction add_filter() {\n    select = $('add_filter_select');\n    field = select.value\n    $('#tr_' +  field).show();\n    check_box = $('cb_' + field);\n    check_box.checked = true;\n    toggle_filter(field);\n    select.selectedIndex = 0;\n\n    for (i=0; i<select.options.length; i++) {\n        if (select.options[i].value == field) {\n            select.options[i].disabled = true;\n        }\n    }\n}\n\nfunction toggle_filter(field) {\n    check_box = $('cb_' + field);\n\n    if (check_box.checked) {\n        $(\"#operators_\" + field).show();\n        toggle_operator(field);\n    } else {\n        $(\"#operators_\" + field).hide();\n        $(\"#div_values_\" + field).hide();\n  }\n}\n\nfunction toggle_operator(field) {\n  operator = $(\"operators_\" + field);\n  switch (operator.value) {\n    case \"!*\":\n    case \"*\":\n    case \"t\":\n    case \"w\":\n    case \"o\":\n    case \"c\":\n      $(\"#div_values_\" + field).hide();\n      break;\n    default:\n      $(\"#div_values_\" + field).show();\n      break;\n  }\n}\n\nfunction toggle_multi_select(field) {\n    select = $('values_' + field);\n    if (select.multiple == true) {\n        select.multiple = false;\n    } else {\n        select.multiple = true;\n    }\n}\n//]]>\n</script>\n\n<table width=\"100%\">\n<tr>\n<td>\n<table>\n<% query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.each do |filter| %>\n    <% field = filter[0]\n       options = filter[1] %>\n    <tr <%= 'style=\"display:none;\"' unless query.has_filter?(field) %> id=\"tr_<%= field %>\" class=\"filter\">\n    <td style=\"width:200px;\">\n        <%= check_box_tag 'fields[]', field, query.has_filter?(field), :onclick => \"toggle_filter('#{field}');\", :id => \"cb_#{field}\" %>\n        <label for=\"cb_<%= field %>\"><%= filter[1][:name] || l((\"field_\"+field.to_s.gsub(/\\_id$/, \"\")).to_sym) %></label>\n    </td>\n    <td style=\"width:150px;\">\n        <%= select_tag \"operators[#{field}]\", options_for_select(operators_for_select(options[:type]), query.operator_for(field)), :id => \"operators_#{field}\", :onchange => \"toggle_operator('#{field}');\", :class => \"select-small\", :style => \"vertical-align: top;\" %>\n    </td>\n    <td>\n    <div id=\"div_values_<%= field %>\" style=\"display:none;\">\n    <% case options[:type]\n    when :list, :list_optional, :list_status, :list_subprojects %>\n        <select <%= \"multiple=true\" if query.values_for(field) and query.values_for(field).length > 1 %> name=\"values[<%= field %>][]\" id=\"values_<%= field %>\" class=\"select-small\" style=\"vertical-align: top;\">\n        <%= options_for_select options[:values], query.values_for(field) %>\n        </select>\n        <%= link_to_function image_tag('bullet_toggle_plus.png'), \"toggle_multi_select('#{field}');\", :style => \"vertical-align: bottom;\" %>\n    <% when :date, :date_past %>\n        <%= text_field_tag \"values[#{field}][]\", query.values_for(field), :id => \"values_#{field}\", :size => 3, :class => \"select-small\" %> <%= l(:label_day_plural) %>\n    <% when :string, :text %>\n        <%= text_field_tag \"values[#{field}][]\", query.values_for(field), :id => \"values_#{field}\", :size => 30, :class => \"select-small\" %>\n    <% when :integer %>\n        <%= text_field_tag \"values[#{field}][]\", query.values_for(field), :id => \"values_#{field}\", :size => 3, :class => \"select-small\" %>\n    <% end %>\n    </div>\n    <script type=\"text/javascript\">toggle_filter('<%= field %>');</script>\n    </td>\n    </tr>\n<% end %>\n</table>\n</td>\n<td class=\"add-filter\">\n<%= l(:label_filter_add) %>:\n<%= select_tag 'add_filter_select', options_for_select([[\"\",\"\"]] + query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.collect{|field| [ field[1][:name] || l((\"field_\"+field[0].to_s.gsub(/_id$/, \"\")).to_sym), field[0]] unless query.has_filter?(field[0])}.compact),\n                                    :onchange => \"add_filter();\",\n                                    :class => \"select-small\",\n                                    :name => nil %>\n</td>\n</tr>\n</table>\n"
  },
  {
    "path": "app/views/queries/_form.html.erb",
    "content": "<%= error_messages_for 'query' %>\n<%= hidden_field_tag 'confirm', 1 %>\n\n<div class=\"gt-content-box\">\n<div class=\"tabular\">\n<p><label for=\"query_name\"><%=l(:field_name)%></label>\n<%= text_field 'query', 'name', :size => 80 %></p>\n\n<% if User.current.admin? || User.current.allowed_to?(:manage_public_queries, @project) %>\n<p><label for=\"query_is_public\"><%=l(:field_is_public)%></label>\n<%= check_box 'query', 'is_public',\n      :onchange => (User.current.admin? ? nil : 'if (this.checked) {$(\"query_is_for_all\").checked = false; $(\"query_is_for_all\").disabled = true;} else {$(\"query_is_for_all\").disabled = false;}') %></p>\n<% end %>\n\n<p><label for=\"query_is_for_all\"><%=l(:field_is_for_all)%></label>\n<%= check_box_tag 'query_is_for_all', 1, @query.project.nil?,\n      :disabled => (!@query.new_record? && (@query.project.nil? || (@query.is_public? && !User.current.admin?))) %></p>\n\n<p><label for=\"query_default_columns\"><%=l(:label_default_columns)%></label>\n<%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns',\n      :onclick => 'if (this.checked) {$(\"#columns\").hide()} else {$(\"#columns\").show()}' %></p>\n\n<p><label for=\"query_group_by\"><%= l(:field_group_by) %></label>\n<%= select 'query', 'group_by', @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, :include_blank => true %></p>\n</div>\n\n<fieldset><legend><%= l(:label_filter_plural) %></legend>\n<%= render :partial => 'queries/filters', :locals => {:query => query}%>\n</fieldset>\n\n<fieldset><legend><%= l(:label_sort) %></legend>\n<% 3.times do |i| %>\n<%= i+1 %>: <%= select_tag(\"query[sort_criteria][#{i}][]\",\n                  options_for_select([[]] + query.available_columns.select(&:sortable?).collect {|column| [column.caption, column.name.to_s]}, @query.sort_criteria_key(i))) %>\n            <%= select_tag(\"query[sort_criteria][#{i}][]\",\n                            options_for_select([[], [l(:label_ascending), 'asc'], [l(:label_descending), 'desc']], @query.sort_criteria_order(i))) %><br />\n<% end %>\n</fieldset>\n\n<% content_tag 'fieldset', :id => 'columns', :style => (query.has_default_columns? ? 'display:none;' : nil) do %>\n<legend><%= l(:field_column_names) %></legend>\n<%= render :partial => 'queries/columns', :locals => {:query => query}%>\n<% end %>\n\n</div>\n"
  },
  {
    "path": "app/views/queries/edit.html.erb",
    "content": "<h2><%= l(:label_query) %></h2>\n\n<% form_tag({:action => 'edit', :id => @query}, :onsubmit => 'selectAllOptions(\"selected_columns\");') do %>\n  <%= render :partial => 'form', :locals => {:query => @query} %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/queries/index.html.erb",
    "content": "<div class=\"contextual\">\n<%= link_to_if_authorized l(:label_query_new), {:controller => 'queries', :action => 'new', :project_id => @project}, :class => 'icon icon-add' %>\n</div>\n\n<h2><%= l(:label_query_plural) %></h2>\n\n<% if @queries.empty? %>\n  <p><i><%=l(:label_no_data)%></i></p>\n<% else %>\n  <table class=\"gt-table\">\n  <% @queries.each do |query| %>\n    <tr class=\"<%= cycle('odd', 'even') %>\">\n      <td>\n        <%= link_to query.name, :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %>\n      </td>\n      <td align=\"right\">\n        <small>\n        <% if query.editable_by?(User.current) %>\n        <%= link_to l(:button_edit), {:controller => 'queries', :action => 'edit', :id => query}, :class => 'icon icon-edit' %>\n        <%= link_to l(:button_delete), {:controller => 'queries', :action => 'destroy', :id => query}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>\n        </small>\n      <% end %>\n      </td>\n    </tr>\n  <% end %>\n  </table>\n<% end %>\n"
  },
  {
    "path": "app/views/queries/new.html.erb",
    "content": "<h2><%= l(:label_query_new) %></h2>\n\n<% form_tag({:action => 'new', :project_id => @query.project}, :onsubmit => 'selectAllOptions(\"selected_columns\");') do %>\n  <%= render :partial => 'form', :locals => {:query => @query} %>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/quotes/edit.html.erb",
    "content": "<h1>Editing quote</h1>\n\n<% form_for(@quote) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :author %><br />\n    <%= f.text_field :author %>\n  </p>\n  <p>\n    <%= f.label :body %><br />\n    <%= f.text_field :body %>\n  </p>\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @quote %> |\n<%= link_to 'Back', quotes_path %>\n"
  },
  {
    "path": "app/views/quotes/index.html.erb",
    "content": "<h1>Listing quotes</h1>\n\n<table>\n  <tr>\n    <th>Author</th>\n    <th>Body</th>\n    <th>User</th>\n  </tr>\n\n<% @quotes.each do |quote| %>\n  <tr>\n    <td><%=h quote.author %></td>\n    <td><%=h quote.body %></td>\n    <td><%=link_to_user_from_id quote.user_id %></td>\n    <td><%= link_to 'Show', quote %></td>\n    <td><%= link_to 'Edit', edit_quote_path(quote) %></td>\n    <td><%= link_to 'Destroy', quote, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New quote', new_quote_path %>\n"
  },
  {
    "path": "app/views/quotes/new.html.erb",
    "content": "<h1>New quote</h1>\n\n<% form_for(@quote) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :author %><br />\n    <%= f.text_field :author %>\n  </p>\n  <p>\n    <%= f.label :body %><br />\n    <%= f.text_area :body %>\n  </p>\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', quotes_path %>\n"
  },
  {
    "path": "app/views/quotes/show.html.erb",
    "content": "<p>\n  <b>Author:</b>\n  <%=h @quote.author %>\n</p>\n\n<p>\n  <b>translation missing: en, field_body:</b>\n  <%=h @quote.body %>\n</p>\n\n<p>\n  <b>User:</b>\n  <%=h @quote.user_id %>\n</p>\n\n\n<%= link_to 'Edit', edit_quote_path(@quote) %> |\n<%= link_to 'Back', quotes_path %>\n"
  },
  {
    "path": "app/views/reports/_details.html.erb",
    "content": "<% if @statuses.empty? or rows.empty? %>\n    <p><i><%=l(:label_no_data)%></i></p>\n<% else %>\n<% col_width = 70 / (@statuses.length+3) %>\n<table class=\"gt-table\">\n<thead><tr>\n<th style=\"width:25%\"></th>\n<% for status in @statuses %>\n<th style=\"width:<%= col_width %>%\"><%= status.name %></th>\n<% end %>\n<th align=\"center\" style=\"width:<%= col_width %>%\"><strong><%=l(:label_open_issues_plural)%></strong></th>\n<th align=\"center\" style=\"width:<%= col_width %>%\"><strong><%=l(:label_closed_issues_plural)%></strong></th>\n<th align=\"center\" style=\"width:<%= col_width %>%\"><strong><%=l(:label_total)%></strong></th>\n</tr></thead>\n<tbody>\n<% for row in rows %>\n<tr class=\"<%= cycle(\"odd\", \"even\") %>\">\n  <td><%= link_to row.name, :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),\n                                                :set_filter => 1,\n                                                \"#{field_name}\" => row.id %></td>\n  <% for status in @statuses %>\n    <td align=\"center\"><%= aggregate_link data, { field_name => row.id, \"status_id\" => status.id },\n                                                :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),\n                                                :set_filter => 1,\n                                                \"status_id\" => status.id,\n                                                \"#{field_name}\" => row.id %></td>\n  <% end %>\n  <td align=\"center\"><%= aggregate_link data, { field_name => row.id, \"closed\" => 0 },\n                                                :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),\n                                                :set_filter => 1,\n                                                \"#{field_name}\" => row.id,\n                                                \"status_id\" => \"o\" %></td>\n  <td align=\"center\"><%= aggregate_link data, { field_name => row.id, \"closed\" => 1 },\n                                                :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),\n                                                :set_filter => 1,\n                                                \"#{field_name}\" => row.id,\n                                                \"status_id\" => \"c\" %></td>\n  <td align=\"center\"><%= aggregate_link data, { field_name => row.id },\n                                                :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),\n                                                :set_filter => 1,\n                                                \"#{field_name}\" => row.id,\n                                                \"status_id\" => \"*\" %></td>\n</tr>\n<% end %>\n</tbody>\n</table>\n<% end\n  reset_cycle %>\n"
  },
  {
    "path": "app/views/reports/_simple.html.erb",
    "content": "<% if @statuses.empty? or rows.empty? %>\n    <p><i><%=l(:label_no_data)%></i></p>\n<% else %>\n<table class=\"gt-table\">\n<thead><tr>\n<th style=\"width:25%\"></th>\n<th align=\"center\" style=\"width:25%\"><%=l(:label_open_issues_plural)%></th>\n<th align=\"center\" style=\"width:25%\"><%=l(:label_closed_issues_plural)%></th>\n<th align=\"center\" style=\"width:25%\"><%=l(:label_total)%></th>\n</tr></thead>\n<tbody>\n<% for row in rows %>\n<tr class=\"<%= cycle(\"odd\", \"even\") %>\">\n  <td><%= link_to row.name, :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),\n                                                :set_filter => 1,\n                                                \"#{field_name}\" => row.id %></td>\n  <td align=\"center\"><%= aggregate_link data, { field_name => row.id, \"closed\" => 0 },\n                                                :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),\n                                                :set_filter => 1,\n                                                \"#{field_name}\" => row.id,\n                                                \"status_id\" => \"o\" %></td>\n  <td align=\"center\"><%= aggregate_link data, { field_name => row.id, \"closed\" => 1 },\n                                                :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),\n                                                :set_filter => 1,\n                                                \"#{field_name}\" => row.id,\n                                                \"status_id\" => \"c\" %></td>\n  <td align=\"center\"><%= aggregate_link data, { field_name => row.id },\n                                                :controller => 'issues', :action => 'index', :project_id => ((row.is_a?(Project) ? row : @project)),\n                                                :set_filter => 1,\n                                                \"#{field_name}\" => row.id,\n                                                \"status_id\" => \"*\" %></td>\n</tr>\n<% end %>\n</tbody>\n</table>\n<% end\n  reset_cycle %>\n"
  },
  {
    "path": "app/views/reports/issue_report.html.erb",
    "content": "<h2><%=l(:label_report_plural)%></h2>\n\n<div class=\"splitcontentleft\">\n<h3><%=l(:field_tracker)%>&nbsp;&nbsp;<%= link_to image_tag('zoom_in.png'), :detail => 'tracker' %></h3>\n<%= render :partial => 'simple', :locals => { :data => @issues_by_tracker, :field_name => \"tracker_id\", :rows => @trackers } %>\n<br />\n<h3><%=l(:field_assigned_to)%>&nbsp;&nbsp;<%= link_to image_tag('zoom_in.png'), :detail => 'assigned_to' %></h3>\n<%= render :partial => 'simple', :locals => { :data => @issues_by_assigned_to, :field_name => \"assigned_to_id\", :rows => @assignees } %>\n<br />\n<h3><%=l(:field_author)%>&nbsp;&nbsp;<%= link_to image_tag('zoom_in.png'), :detail => 'author' %></h3>\n<%= render :partial => 'simple', :locals => { :data => @issues_by_author, :field_name => \"author_id\", :rows => @authors } %>\n<br />\n</div>\n\n<div class=\"splitcontentright\">\n<% if @project.children.any? %>\n<h3><%=l(:field_subproject)%>&nbsp;&nbsp;<%= link_to image_tag('zoom_in.png'), :detail => 'subproject' %></h3>\n<%= render :partial => 'simple', :locals => { :data => @issues_by_subproject, :field_name => \"project_id\", :rows => @subprojects } %>\n<br />\n<% end %>\n<br />\n</div>\n\n"
  },
  {
    "path": "app/views/reports/issue_report_details.html.erb",
    "content": "<h2><%=l(:label_report_plural)%></h2>\n\n<h3><%=@report_title%></h3>\n<%= render :partial => 'details', :locals => { :data => @data, :field_name => @field, :rows => @rows } %>\n<br />\n<%= link_to l(:button_back), :action => 'issue_report' %>\n\n"
  },
  {
    "path": "app/views/reputations/edit.html.erb",
    "content": "<h1>Editing reputation</h1>\n\n<% form_for(@reputation) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :user_id %><br />\n    <%= f.text_field :user_id %>\n  </p>\n  <p>\n    <%= f.label :project_id %><br />\n    <%= f.text_field :project_id %>\n  </p>\n  <p>\n    <%= f.label :reputation_type %><br />\n    <%= f.text_field :reputation_type %>\n  </p>\n  <p>\n    <%= f.label :value %><br />\n    <%= f.text_field :value %>\n  </p>\n  <p>\n    <%= f.label :params %><br />\n    <%= f.text_field :params %>\n  </p>\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @reputation %> |\n<%= link_to 'Back', reputations_path %>\n"
  },
  {
    "path": "app/views/reputations/index.html.erb",
    "content": "<h1>Listing reputations</h1>\n\n<table>\n  <tr>\n    <th>User</th>\n    <th>Workstream</th>\n    <th>translation missing: en, field_reputation_type</th>\n    <th>Value</th>\n    <th>translation missing: en, field_params</th>\n  </tr>\n\n<% @reputations.each do |reputation| %>\n  <tr>\n    <td><%=h reputation.user_id %></td>\n    <td><%=h reputation.project_id %></td>\n    <td><%=h reputation.reputation_type %></td>\n    <td><%=h reputation.value %></td>\n    <td><%=h reputation.params %></td>\n    <td><%= link_to 'Show', reputation %></td>\n    <td><%= link_to 'Edit', edit_reputation_path(reputation) %></td>\n    <td><%= link_to 'Destroy', reputation, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New reputation', new_reputation_path %>\n"
  },
  {
    "path": "app/views/reputations/new.html.erb",
    "content": "<h1>New reputation</h1>\n\n<% form_for(@reputation) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :user_id %><br />\n    <%= f.text_field :user_id %>\n  </p>\n  <p>\n    <%= f.label :project_id %><br />\n    <%= f.text_field :project_id %>\n  </p>\n  <p>\n    <%= f.label :reputation_type %><br />\n    <%= f.text_field :reputation_type %>\n  </p>\n  <p>\n    <%= f.label :value %><br />\n    <%= f.text_field :value %>\n  </p>\n  <p>\n    <%= f.label :params %><br />\n    <%= f.text_field :params %>\n  </p>\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', reputations_path %>\n"
  },
  {
    "path": "app/views/reputations/show.html.erb",
    "content": "<p>\n  <b>User:</b>\n  <%=h @reputation.user_id %>\n</p>\n\n<p>\n  <b>Workstream:</b>\n  <%=h @reputation.project_id %>\n</p>\n\n<p>\n  <b>translation missing: en, field_reputation_type:</b>\n  <%=h @reputation.reputation_type %>\n</p>\n\n<p>\n  <b>Value:</b>\n  <%=h @reputation.value %>\n</p>\n\n<p>\n  <b>translation missing: en, field_params:</b>\n  <%=h @reputation.params %>\n</p>\n\n\n<%= link_to 'Edit', edit_reputation_path(@reputation) %> |\n<%= link_to 'Back', reputations_path %>\n"
  },
  {
    "path": "app/views/retro_ratings/edit.html.erb",
    "content": "<h1>Editing retro_rating</h1>\n\n<% form_for(@retro_rating) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @retro_rating %> |\n<%= link_to 'Back', retro_ratings_path %>\n"
  },
  {
    "path": "app/views/retro_ratings/index.html.erb",
    "content": "<h1>Listing retro_ratings</h1>\n\n<table>\n  <tr>\n  </tr>\n\n<% @retro_ratings.each do |retro_rating| %>\n  <tr>\n    <td><%= link_to 'Show', retro_rating %></td>\n    <td><%= link_to 'Edit', edit_retro_rating_path(retro_rating) %></td>\n    <td><%= link_to 'Destroy', retro_rating, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New retro_rating', new_retro_rating_path %>\n"
  },
  {
    "path": "app/views/retro_ratings/new.html.erb",
    "content": "<h1>New retro_rating</h1>\n\n<% form_for(@retro_rating) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', retro_ratings_path %>\n"
  },
  {
    "path": "app/views/retro_ratings/show.html.erb",
    "content": "\n<%= link_to 'Edit', edit_retro_rating_path(@retro_rating) %> |\n<%= link_to 'Back', retro_ratings_path %>\n"
  },
  {
    "path": "app/views/retros/_issue_details.html.erb",
    "content": "<tr><td class=\"issue\" colspan=\"3\">\n    <%= link_to_issue(issue, :css_class => '') %>  - <%= issue.points.round %> credits <%= image_tag \"dice_#{issue.points_from_credits}.png\", :alt => \"#{issue.points} credits\"%></td><tr>\n<tr><td class=\"subtitle\">Author:</td><td> <%= link_to_user_from_id(issue.author_id) %></td><tr>\n<tr><td class=\"subtitle\">Owner:</td><td> <%= link_to_user_from_id(issue.assigned_to_id) %></td><tr>\n  <% if issue.has_team? %>\n<tr><td class=\"subtitle\">Team:</td><td>\n<%= team_from_issue issue %>\n</td><tr>\n  <% end %>\n\n  <% if issue.has_todos? %>\n\n<tr><td class=\"subtitle\">Todos:</td><td>\n  <% issue.todos.each do |todo| %>\n  <%= todo.subject %> <%= \" - (\" + link_to_user_from_id(todo.owner_id) + \")\" unless todo.owner_id.nil? %><br>\n  <% end %>\n</td><tr>\n  <% end %>\n\n</td></tr>\n"
  },
  {
    "path": "app/views/retros/edit.html.erb",
    "content": "<h1>Editing retro</h1>\n\n<% form_for(@retro) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @retro %> |\n<%= link_to 'Back', retros_path %>\n"
  },
  {
    "path": "app/views/retros/index.html.erb",
    "content": "<h1>Listing retros</h1>\n\n<table>\n  <tr>\n  </tr>\n\n<% @retros.each do |retro| %>\n  <tr>\n    <td><%= link_to 'Show', retro %></td>\n    <td><%= link_to 'Edit', edit_retro_path(retro) %></td>\n    <td><%= link_to 'Destroy', retro, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New retro', new_retro_path %>\n"
  },
  {
    "path": "app/views/retros/new.html.erb",
    "content": "<h1>New retro</h1>\n\n<% form_for(@retro) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', retros_path %>\n"
  },
  {
    "path": "app/views/retros/show.html.erb",
    "content": "<%= javascript_include_tag  'retro' %>\n<%= help_section \"retrospective_show\" %>\n<div align=\"center\">\n  <h2>Retrospective #<%= @retro.id %> : <%= @total_points.round %> Credits - <%= render_title_date %></h2>\n<% if @user_retro_hash.has_key? User.current.id%>\n<%= javascript_tag  'var belongs = true;'%>\n<% end %>\n\n<div class=\"user_retrospective gt-content-box\">\n  <table class=\"retrospective\">\n    <tr><td class=\"avatar\">\n    </td><td class=\"title\">\n    </td><td class=\"title private hidden\">&nbsp;&nbsp;&nbsp;&nbsp;Your <%= help_bubble :help_your_assessment %><br>assessment\n    </td><td class=\"title closed hidden\">&nbsp;&nbsp;&nbsp;&nbsp;Team's<%= help_bubble :help_team_assessment %><br>assessment\n    </td><td class=\"title closed hidden\">&nbsp;&nbsp;&nbsp;&nbsp;Final <%= help_bubble :help_final_assessment %><br>distribution\n    </td><td class=\"title closed hidden\">&nbsp;&nbsp;&nbsp;&nbsp;Accuracy<%= help_bubble :help_accuracy %><br>\n    </td><td class=\"button\">\n    </td></tr>\n\n<%\n  @user_retro_hash = @user_retro_hash.sort_by {|x| [ x[1][\"total_points\"] , x[1][\"total_ideas\"] , x[1][\"total_journals\"] ] }.reverse\n  @user_retro_hash.each do |x|\n    user_id = x[0]\n    user_retro = x[1]\n%>\n  <tr><td class=\"avatar\">\n    <%= avatar_from_id(user_id) %><br>\n    <%= link_to_user_from_id(user_id) %>\n\n  </td><td class=\"stats\">\n    <strong><%= user_retro[\"total_points\"].round %> credits (<%= user_retro[\"percentage_points\"] %>%)</strong> <br>\n    <%= user_retro[\"total_ideas\"] %> ideas <br>\n    <%= user_retro[\"total_journals\"] %> comments <br>\n    <%= user_retro[\"total_votes\"] %> votes <br>\n  </td><td class=\"percentage private hidden\">\n    <label id=\"user_<%= user_id%>_percentage\" class=\"percentage_label\"><%= user_retro[\"given_percentage\"] ||=0 %>%</label>\n  <br>\n  <% if (@retro.status_id == Retro::STATUS_INPROGRESS) %>\n  <div id=\"slider_<%= user_id%>\" class=\"slider slider-per\" user_id=\"<%= user_id%>\" per=\"<%= user_retro[\"given_percentage\"] %>\"></div>\n<% end %>\n  </td><td class=\"percentage closed\">\n    <label id=\"user_<%= user_id%>_percentage\"><%= @team_hash[user_id] ||=0 %>%</label>\n  </td><td class=\"percentage closed\">\n    <label id=\"user_<%= user_id%>_percentage\"><%= @final_hash[user_id] ||=0 %>%</label>\n  </td><td class=\"accuracy closed\">\n    <label id=\"user_<%= user_id%>_accuracy\"><%= accuracy_display(user_retro[\"self_bias\"],user_retro[\"scale_bias\"]) %></label>\n  </td><td class=\"button\">\n  </td></tr>\n  <% end %>\n\n  <tr class=\"open\"><td class=\"avatar\">\n    &nbsp;\n    </td><td class=\"stats\">\n    <br><strong>Confidence</strong><%= help_bubble :help_confidence %><br><br>\n  </td><td class=\"percentage private hidden\">\n    <label id=\"user_0_percentage\" class=\"percentage_label_confidence\"><%= @confidence_percentage ||=0 %>%</label>\n  <br>\n  <div id=\"slider_confidence\" class=\"slider slider-conf\" user_id=\"0\" per=\"<%= @confidence_percentage %>\"></div>\n  </td><td class=\"percentage closed\">\n    <label id=\"confidence_percentage\">&nbsp;</label>\n  </td><td class=\"percentage closed\">\n    <label id=\"confidence_percentage\">&nbsp;</label>\n  </td><td class=\"button\">\n  </td></tr>\n\n<tr class=\"open\"><td class=\"avatar\">\n</td><td class=\"name\">\n</td><td class=\"total private hidden\" style=\"text-align:right;\">\n  Total&nbsp;\n</td><td id=\"total\" class=\"total private hidden\">\n  0%\n</td><td class=\"button private hidden\">\n  <a id=\"change_retro_link_save\" href=\"#\" onclick=\"save_retro(<%= @retro.id  %>)\" class=\"action_button action_button_save\" style=\"color:#fff;text-decoration:none;display:none;\">Save</a>\n  <label id=\"success\" style=\"display:none;\">Done!</label>\n  <div id='saving' class='loading'>saving...</div>\n</td></tr>\n\n</table>\n</div>\n</div>\n<br><br>\n\n<div align=\"center\">\n<h2 class=\"gt-table-head\">Contribution Breakdown  : <%= format_date(@retro.from_date) %> to <%= format_date(@retro.to_date)%></h2>\n</div>\n  <div class=\"user_retrospective gt-content-box\" align=\"center\">\n    <table class=\"retrospective\" style=\"width:85%\" align=\"center\">\n\n    <% @retro.issues.each do |issue| %>\n      <%= render :partial => \"issue_details\", :locals => { :issue => issue } %>\n    <% end %>\n    </table>\n    <br>\n  </div>\n\n\n\n\n<% content_for :sidebar do %>\n<br><br>\n<div style=\"overflow-x:auto;\" align=\"center\" class=\"gt-content-box\">\n  <% @chart_width = @point_totals.length*70 + 50\n   @chart_width = 1000 if @chart_width > 1000\n   %>\n\n  <img src=\"<%= Gchart.bar(\n              :title => 'Contribution Breakdown',\n              :data => [@idea_totals, @vote_totals, @journal_totals],\n              :bar_colors => 'EA7235,757668,E3A34D',\n              #:horizontal => 'true',\n              :stacked => false,\n              :orientation => 'vertical',\n              :size => \"#{@chart_width}x200\",\n              :axis_with_labels => 'x',\n              :axis_labels => @axis_labels,\n              :bar_width_and_spacing => '15,2,10',\n              :legend => ['Ideas','Votes','Comments'],\n              :custom => \"chm=N*f0*,000000,0,-1,11|N*f0*,000000,1,-1,11|N*f0*,000000,2,-1,11&chds=0,#{@max_range}\"\n              # :custom => 'chma=50,50,50,50|200,200'\n              )\n    %>\"/>\n</div>\n<br>\n<div align=\"center\" class=\"gt-content-box\">\n  <img src=\"<%=  Gchart.pie(:title => 'Credits',\n                 :size => '400x200',\n                 :data => @pie_data_points, :labels => @pie_labels_points )\n   %>\"/>\n </div>\n <br>\n <div align=\"center\" class=\"gt-content-box\">\n   <img src=\"<%=  Gchart.pie(:title => 'Ideas',\n                  :size => '400x200',\n                  :data => @pie_data_ideas, :labels => @pie_labels_ideas )\n    %>\"/>\n  </div>\n  <br>\n  <div align=\"center\" class=\"gt-content-box\">\n   <img src=\"<%=  Gchart.pie(:title => 'Comments',\n                  :size => '400x200',\n                  :data => @pie_data_journals, :labels => @pie_labels_journals )\n    %>\"/>\n  </div>\n  <br>\n  <div align=\"center\" class=\"gt-content-box\">\n    <img src=\"<%=  Gchart.pie(:title => 'Votes',\n                   :size => '400x200',\n                   :data => @pie_data_votes, :labels => @pie_labels_votes )\n     %>\"/>\n</div>\n<% end %>\n\n<script>\n  var currentUserId = '<%= User.current.id %>';\n  var retroStatus = '<%= @retro.status_id %>';\n</script>\n\n\n"
  },
  {
    "path": "app/views/retros/show_multiple.html.erb",
    "content": "<h2>Retrospective #<%= @retro.id %> : <%= @total_points %> Points (<%= format_date(@retro.from_date) %> to <%= format_date(@retro.to_date) %>)</h2>\n\n\n<%\n  @user_retro_hash.keys.each do |user_id|\n    user_retro = @user_retro_hash[user_id]\n%>\n  <div class=\"user_retrospective\">\n    <h4><%= link_to_user_from_id(user_id) %></h4>\n    <table class=\"retrospective\"><tr><td class=\"stats\">\n    <%= user_retro[\"total_points\"] %> points (<%= user_retro[\"percentage_points\"] %>%) <br>\n    <%= user_retro[\"total_journals\"] %> journals <br>\n    <%= user_retro[\"total_votes\"] %> votes <br>\n    </td>\n    <% if user_retro[\"issues\"].length > 0 %>\n    <td class=\"issues\">\n    <% user_retro[\"issues\"].each do |issue| %>\n    <%= link_to_issue(issue) %>  - <%= issue.points %> pts  <br>\n    <% end %>\n    </td>\n    <% end %>\n    </tr></table>\n    <br>\n  </div>\n<% end %>\n\n\n<% content_for :sidebar do %>\n<br><br>\n<div style=\"overflow-x:auto;\" align=\"center\">\n  <% @chart_width = @point_totals.length*70 + 50\n   @chart_width = 1000 if @chart_width > 1000\n   %>\n\n  <img src=\"<%= Gchart.bar(\n              :data => [@point_totals, @vote_totals, @journal_totals],\n              :bar_colors => 'EA7235,757668,E3A34D',\n              :stacked => false,\n              :orientation => 'vertical',\n              :size => \"#{@chart_width}x200\",\n              :axis_with_labels => 'x',\n              :axis_labels => @axis_labels,\n              :bar_width_and_spacing => '15,2,10',\n              :legend => ['Points','Votes','Journals'],\n              :custom => \"chm=N*f0*,000000,0,-1,11|N*f0*,000000,1,-1,11|N*f0*,000000,2,-1,11&chds=0,#{@max_range}\"\n              )\n    %>\"/>\n</div>\n<br>\n<br>\n<div align=\"center\">\n  <img src=\"<%=  Gchart.pie(:title => 'Points',\n                 :size => '400x200',\n                 :data => @pie_data_points, :labels => @pie_labels_points )\n   %>\"/>\n   <br>\n   <br>\n   <img src=\"<%=  Gchart.pie(:title => 'Journals',\n                  :size => '400x200',\n                  :data => @pie_data_journals, :labels => @pie_labels_journals )\n    %>\"/>\n    <br>\n    <br>\n    <img src=\"<%=  Gchart.pie(:title => 'Votes',\n                   :size => '400x200',\n                   :data => @pie_data_votes, :labels => @pie_labels_votes )\n     %>\"/>\n     <br>\n     <br>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/roles/_form.html.erb",
    "content": "<%= error_messages_for 'role' %>\n\n<% unless @role.builtin? %>\n<div class=\"gt-content-box\">\n<p><%= f.text_field :name, :required => true %></p>\n<p><%= f.check_box :assignable %></p>\n<% if @role.new_record? && @roles.any? %>\n<p><label><%= l(:label_copy_workflow_from) %></label>\n<%= select_tag(:copy_workflow_from, content_tag(\"option\") + options_from_collection_for_select(@roles, :id, :name)) %></p>\n<% end %>\n</div>\n<% end %>\n\n<h3><%= l(:label_permissions) %></h3>\n<div class=\"gt-content-box\" id=\"permissions\">\n<% perms_by_module = @permissions.group_by {|p| p.project_module.to_s} %>\n<% perms_by_module.keys.sort.each do |mod| %>\n    <fieldset><legend><%= mod.blank? ? l(:label_project) : l_or_humanize(mod, :prefix => 'project_module_') %></legend>\n    <% perms_by_module[mod].each do |permission| %>\n        <label class=\"floating\">\n        <%= check_box_tag 'role[permissions][]', permission.name, (@role.permissions.include? permission.name) %>\n        <%= l_or_humanize(permission.name, :prefix => 'permission_') %>\n        </label>\n    <% end %>\n    </fieldset>\n<% end %>\n<br /><%= check_all_links 'permissions' %>\n<%= hidden_field_tag 'role[permissions][]', '' %>\n</div>\n"
  },
  {
    "path": "app/views/roles/edit.html.erb",
    "content": "<h2><%= link_to l(:label_role_plural), :controller => 'roles', :action => 'index' %> &#187; <%=h @role.name %></h2>\n\n<% labelled_tabular_form_for :role, @role, :url => { :action => 'edit' }, :html => {:id => 'role_form'} do |f| %>\n<%= render :partial => 'form', :locals => { :f => f } %>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/roles/list.html.erb",
    "content": "<div class=\"contextual\">\n<%= link_to l(:label_role_new), {:action => 'new'}, :class => 'icon icon-add' %>\n</div>\n\n<h2><%=l(:label_role_plural)%></h2>\n\n<table class=\"gt-table\">\n  <thead><tr>\n    <th><%=l(:label_role)%></th>\n    <th><%=l(:button_sort)%></th>\n  <th></th>\n  </tr></thead>\n  <tbody>\n<% for role in @roles %>\n  <tr class=\"<%= cycle(\"odd\", \"even\") %>\">\n  <td><%= content_tag(role.builtin? ? 'em' : 'span', link_to(role.name, :action => 'edit', :id => role)) %></td>\n  <td align=\"center\" style=\"width:15%;\">\n  <% unless role.builtin? %>\n    <%= reorder_links('role', {:action => 'edit', :id => role}) %>\n  <% end %>\n  </td>\n  <td class=\"buttons\">\n    <%= link_to(l(:button_delete), { :action => 'destroy', :id => role },\n                                  :method => :post,\n                                  :confirm => l(:text_are_you_sure),\n                                  :class => 'icon icon-del') unless role.builtin? %>\n  </td>\n  </tr>\n<% end %>\n  </tbody>\n</table>\n\n<p class=\"pagination\"><%= pagination_links_full @role_pages %></p>\n\n<p><%= link_to l(:label_permissions_report), :action => 'report' %></p>\n\n<% html_title(l(:label_role_plural)) -%>\n"
  },
  {
    "path": "app/views/roles/new.html.erb",
    "content": "<h2><%= link_to l(:label_role_plural), :controller => 'roles', :action => 'index' %> &#187; <%=l(:label_role_new)%></h2>\n\n<% labelled_tabular_form_for :role, @role, :url => { :action => 'new' }, :html => {:id => 'role_form'} do |f| %>\n<%= render :partial => 'form', :locals => { :f => f } %>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/roles/report.html.erb",
    "content": "<h2><%= link_to l(:label_role_plural), :controller => 'roles', :action => 'index' %> &#187; <%=l(:label_permissions_report)%></h2>\n\n<% form_tag({:action => 'report'}, :id => 'permissions_form') do %>\n<%= hidden_field_tag 'permissions[0]', '', :id => nil %>\n<table class=\"gt-table\">\n<thead>\n    <tr>\n    <th><%=l(:label_permissions)%></th>\n    <% @roles.each do |role| %>\n    <th>\n        <%= content_tag(role.builtin? ? 'em' : 'span', h(role.name)) %>\n        <%= link_to_function(image_tag('toggle_check.png'), \"toggleCheckboxesBySelector('input.role-#{role.id}')\",\n                                                            :title => \"#{l(:button_check_all)}/#{l(:button_uncheck_all)}\") %>\n    </th>\n    <% end %>\n    </tr>\n</thead>\n<tbody>\n<% perms_by_module = @permissions.group_by {|p| p.project_module.to_s} %>\n<% perms_by_module.keys.sort.each do |mod| %>\n    <% unless mod.blank? %>\n        <tr class=\"group open\">\n          <td colspan=\"<%= @roles.size + 1 %>\">\n            <span class=\"expander\" onclick=\"toggleRowGroup(this); return false;\">&nbsp;</span>\n            <%= l_or_humanize(mod, :prefix => 'project_module_') %>\n          </td>\n        </tr>\n    <% end %>\n    <% perms_by_module[mod].each do |permission| %>\n        <tr class=\"<%= cycle('odd', 'even') %> permission-<%= permission.name %>\">\n        <td>\n            <%= link_to_function(image_tag('toggle_check.png'), \"toggleCheckboxesBySelector('.permission-#{permission.name} input')\",\n                                                                :title => \"#{l(:button_check_all)}/#{l(:button_uncheck_all)}\") %>\n            <%= l_or_humanize(permission.name, :prefix => 'permission_') %>\n        </td>\n        <% @roles.each do |role| %>\n        <td align=\"center\">\n        <% if role.setable_permissions.include? permission %>\n          <%= check_box_tag \"permissions[#{role.id}][]\", permission.name, (role.permissions.include? permission.name), :id => nil, :class => \"role-#{role.id}\" %>\n        <% end %>\n        </td>\n        <% end %>\n        </tr>\n    <% end %>\n<% end %>\n</tbody>\n</table>\n<p><%= check_all_links 'permissions_form' %></p>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/search/index.html.erb",
    "content": "<% @page_header_name = l(:label_search) %>\n\n<% form_tag({}, {:method => :get, :class=>\"search-form\"}) do %>\n<div class=\"gt-content-box padded\">\n<p><%= text_field_tag 'q', @question, :size => 60, :id => 'search-input' %>\n<%= javascript_tag \"Field.focus('search-input')\" %>\n<%= project_select_tag %>\n<label><%= check_box_tag 'all_words', 1, @all_words %> <%= l(:label_all_words) %></label>\n<label><%= check_box_tag 'titles_only', 1, @titles_only %> <%= l(:label_search_titles_only) %></label>\n</p>\n<p>\n<% @object_types.each do |t| %>\n<label><%= check_box_tag t, 1, @scope.include?(t) %> <%= type_label(t) %></label>\n<% end %>\n<%= submit_tag l(:button_search), :name => 'submit', :class => \"gt-btn-gray-large\"%>\n\n</p>\n</div>\n\n<% end %>\n\n<% content_for :sidebar do %>\n    <div class=\"gt-sidebar-nav gt-sidebar-nav-blue\">\n      <%= render_results_by_type(@results_by_type) unless @scope.size == 1 %>\n    </div>\n<% end %>\n\n\n<% if @results %>\n    <h3 class=\"gt-table-head\"><%= l(:label_result_plural) %> (<%= @results_by_type.values.sum %>)</h3>\n    <div class=\"gt-content-box padded\">\n    <dl id=\"search-results\">\n      <% @results.each do |e| %>\n        <dt class=\"<%= e.event_type %>\"><%= content_tag('span', h(e.project), :class => 'project') unless @project == e.project %> <%= link_to highlight_tokens(truncate(e.event_title, :length => 255), @tokens), e.event_url, :class => (e.event_type.match(/^issue/)) ? \"fancyframe\" : \"noframe\" %></dt>\n        <dd><span class=\"description\"><%= highlight_tokens(e.event_description, @tokens) %></span>\n        <span class=\"author\"><%= format_time(e.event_datetime) %></span></dd>\n      <% end %>\n    </dl>\n    </div>\n<% end %>\n\n<p><center>\n<% if @pagination_previous_date %>\n<%= link_to_remote ('&#171; ' + l(:label_previous)),\n                   {:update => :content,\n                    :url => params.merge(:previous => 1, :offset => @pagination_previous_date.strftime(\"%Y%m%d%H%M%S\"))\n                   }, :href => url_for(params.merge(:previous => 1, :offset => @pagination_previous_date.strftime(\"%Y%m%d%H%M%S\"))) %>&nbsp;\n<% end %>\n<% if @pagination_next_date %>\n<%= link_to_remote (l(:label_next) + ' &#187;'),\n                   {:update => :content,\n                    :url => params.merge(:previous => nil, :offset => @pagination_next_date.strftime(\"%Y%m%d%H%M%S\"))\n                   }, :href => url_for(params.merge(:previous => nil, :offset => @pagination_next_date.strftime(\"%Y%m%d%H%M%S\"))) %>\n<% end %>\n</center></p>\n\n<% html_title(l(:label_search)) -%>\n"
  },
  {
    "path": "app/views/settings/_authentication.html.erb",
    "content": "<% form_tag({:action => 'edit', :tab => 'authentication'}) do %>\n\n<div class=\"gt-content-box tabular settings\">\n<p><%= setting_check_box :login_required %></p>\n\n<p><%= setting_select :autologin, [1, 7, 30, 365].collect{|days| [l('datetime.distance_in_words.x_days', :count => days), days.to_s]}, :blank => :label_disabled %></p>\n\n<p><%= setting_select :self_registration, [[l(:label_disabled), \"0\"],\n                                           [l(:label_registration_activation_by_email), \"1\"],\n                                           [l(:label_registration_manual_activation), \"2\"],\n                                           [l(:label_registration_automatic_activation), \"3\"]] %></p>\n\n<p><%= setting_text_field :password_min_length, :size => 6 %></p>\n\n<p><%= setting_check_box :lost_password, :label => :label_password_lost %></p>\n\n<p><%= setting_check_box :openid, :disabled => !Object.const_defined?(:OpenID) %></p>\n\n<p><%= setting_check_box :rest_api_enabled %></p>\n</div>\n\n<div style=\"float:right;\">\n    <%= link_to l(:label_ldap_authentication), :controller => 'auth_sources', :action => 'list' %>\n</div>\n\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/settings/_display.html.erb",
    "content": "<% form_tag({:action => 'edit', :tab => 'display'}) do %>\n\n<div class=\"gt-content-box tabular settings\">\n<p><%= setting_select :ui_theme, Redmine::Themes.themes.collect {|t| [t.name, t.id]}, :blank => :label_default, :label => :label_theme %></p>\n\n<p><%= setting_select :default_language, lang_options_for_select(false) %></p>\n\n<p><%= setting_select :start_of_week, [[day_name(1),'1'], [day_name(7),'7']], :blank => :label_language_based %></p>\n\n<p><%= setting_select :date_format, Setting::DATE_FORMATS.collect {|f| [Date.today.strftime(f), f]}, :blank => :label_language_based %></p>\n\n<p><%= setting_select :time_format, Setting::TIME_FORMATS.collect {|f| [Time.now.strftime(f), f]}, :blank => :label_language_based %></p>\n\n<p><%= setting_select :user_format, @options[:user_format] %></p>\n\n<p><%= setting_check_box :gravatar_enabled %></p>\n\n<p><%= setting_select :gravatar_default, [[\"Wavatars\", 'wavatar'], [\"Identicons\", 'identicon'], [\"Monster ids\", 'monsterid']], :blank => :label_none %></p>\n</div>\n\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/settings/_general.html.erb",
    "content": "<% form_tag({:action => 'edit'}) do %>\n\n<div class=\"gt-content-box tabular settings\">\n<p><%= setting_text_field :app_title, :size => 30 %></p>\n\n<p><%= setting_text_area :welcome_text, :cols => 60, :rows => 5, :class => 'wiki-edit' %></p>\n\n<p><%= setting_text_field :attachment_max_size, :size => 6 %> KB</p>\n\n<p><%= setting_text_field :per_page_options, :size => 20 %><br />\n<em><%= l(:text_comma_separated) %></em></p>\n\n<p><%= setting_text_field :activity_days_default, :size => 6 %> <%= l(:label_day_plural) %></p>\n\n<p><%= setting_text_field :host_name, :size => 60 %><br />\n<em><%= l(:label_example) %>: <%= @guessed_host_and_path %></em></p>\n\n<p><%= setting_select :protocol, [['HTTP', 'http'], ['HTTPS', 'https']] %></p>\n\n<p><%= setting_select :text_formatting, Redmine::WikiFormatting.format_names.collect{|name| [name, name.to_s]}, :blank => :label_none %></p>\n\n<p><%= setting_select :wiki_compression, [['Gzip', 'gzip']], :blank => :label_none %></p>\n\n<p><%= setting_text_field :feeds_limit, :size => 6 %></p>\n\n<p><%= setting_text_field :file_max_size_displayed, :size => 6 %> KB</p>\n\n<p><%= setting_text_field :diff_max_lines_displayed, :size => 6 %></p>\n</div>\n\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n<%= textile_editor_initialize(:framework => :jquery) %>\n<% end %>\n"
  },
  {
    "path": "app/views/settings/_issues.html.erb",
    "content": "<% form_tag({:action => 'edit', :tab => 'issues'}) do %>\n\n<div class=\"gt-content-box tabular settings\">\n<p><%= setting_check_box :cross_project_issue_relations %></p>\n\n<p><%= setting_check_box :display_subprojects_issues %></p>\n\n\n<p><%= setting_text_field :issues_export_limit, :size => 6 %></p>\n</div>\n\n<fieldset class=\"gt-content-box settings\"><legend><%= l(:setting_issue_list_default_columns) %></legend>\n<%= setting_multiselect(:issue_list_default_columns,\n        Query.new.available_columns.collect {|c| [c.caption, c.name.to_s]}, :label => false) %>\n</fieldset>\n\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/settings/_mail_handler.html.erb",
    "content": "<% form_tag({:action => 'edit', :tab => 'mail_handler'}) do %>\n\n<div class=\"gt-content-box tabular settings\">\n  <p>\n    <%= setting_text_area :mail_handler_body_delimiters, :rows => 5 %>\n    <br /><em><%= l(:text_line_separated) %></em>\n  </p>\n</div>\n\n<div class=\"gt-content-box tabular settings\">\n<p><%= setting_check_box :mail_handler_api_enabled,\n         :onclick => \"if (this.checked) { Form.Element.enable('settings_mail_handler_api_key'); } else { Form.Element.disable('settings_mail_handler_api_key'); }\"%></p>\n\n<p><%= setting_text_field :mail_handler_api_key, :size => 30,\n                                                 :id => 'settings_mail_handler_api_key',\n                                                 :disabled => !Setting.mail_handler_api_enabled? %>\n  <%= link_to_function l(:label_generate_key), \"if ($('settings_mail_handler_api_key').disabled == false) { $('settings_mail_handler_api_key').value = randomKey(20) }\" %>\n</p>\n</div>\n\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/settings/_notifications.html.erb",
    "content": "<% if @deliveries %>\n<% form_tag({:action => 'edit', :tab => 'notifications'}) do %>\n\n<div class=\"gt-content-box tabular settings\">\n<p><%= setting_text_field :mail_from, :size => 60 %></p>\n\n<p><%= setting_check_box :bcc_recipients %></p>\n\n<p><%= setting_check_box :plain_text_mail %></p>\n</div>\n\n<fieldset class=\"gt-content-box settings\" id=\"notified_events\"><legend><%=l(:text_select_mail_notifications)%></legend>\n  <%= setting_multiselect(:notified_events,\n        @notifiables.collect {|notifiable| [l_or_humanize(notifiable, :prefix => 'label_'), notifiable]}, :label => false) %>\n\n  <p><%= check_all_links('notified_events') %></p>\n</fieldset>\n\n<fieldset class=\"gt-content-box\"><legend><%= l(:setting_emails_footer) %></legend>\n<%= setting_text_area :emails_footer, :label => false, :class => 'wiki-edit', :rows => 5 %>\n</fieldset>\n\n<div style=\"float:right;\">\n<%= link_to l(:label_send_test_email), :controller => 'admin', :action => 'test_email' %>\n</div>\n\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n<% else %>\n<div class=\"nodata\">\n<%= simple_format(l(:text_email_delivery_not_configured)) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/settings/_projects.html.erb",
    "content": "<% form_tag({:action => 'edit', :tab => 'projects'}) do %>\n\n<div class=\"gt-content-box tabular settings\">\n<p><%= setting_check_box :default_projects_public %></p>\n\n<p><%= setting_multiselect(:default_projects_modules,\n        Redmine::AccessControl.available_project_modules.collect {|m| [l_or_humanize(m, :prefix => \"project_module_\"), m.to_s]}) %></p>\n\n<p><%= setting_check_box :sequential_project_identifiers %></p>\n\n<p><%= setting_select :new_project_user_role_id,\n                      Role.find_all_givable(Role::LEVEL_PROJECT).collect {|r| [r.name, r.id.to_s]},\n                      :blank => \"--- #{l(:actionview_instancetag_blank_option)} ---\" %></p>\n</div>\n\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/settings/edit.html.erb",
    "content": "<h2><%= l(:label_settings) %></h2>\n\n<%= render_tabs administration_settings_tabs %>\n\n<% html_title(l(:label_settings), l(:label_administration)) -%>\n"
  },
  {
    "path": "app/views/settings/plugin.html.erb",
    "content": "<h2><%= l(:label_settings) %>: <%=h @plugin.name %></h2>\n\n<div id=\"settings\">\n<% form_tag({:action => 'plugin'}) do %>\n<div class=\"gt-content-box tabular\">\n<%= render :partial => @partial, :locals => {:settings => @settings}%>\n</div>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_apply), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n</div>\n"
  },
  {
    "path": "app/views/shares/edit.html.erb",
    "content": "<h1>Editing share</h1>\n\n<% form_for(@share) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @share %> |\n<%= link_to 'Back', shares_path %>\n"
  },
  {
    "path": "app/views/shares/index.html.erb",
    "content": "<h2><%=l(:label_team) %></h2>\n\n\n<table>\n  <tr>\n  </tr>\n\n<% @shares.each do |share| %>\n  <tr>\n    <td><%= link_to 'Show', share %></td>\n    <td><%= link_to 'Edit', edit_share_path(share) %></td>\n    <td><%= link_to 'Destroy', share, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New share', new_share_path %>\n"
  },
  {
    "path": "app/views/shares/new.html.erb",
    "content": "<h1>New share</h1>\n\n<% form_for(@share) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', shares_path %>\n"
  },
  {
    "path": "app/views/shares/show.html.erb",
    "content": "\n<%= link_to 'Edit', edit_share_path(@share) %> |\n<%= link_to 'Back', shares_path %>\n"
  },
  {
    "path": "app/views/todos/edit.html.erb",
    "content": "<h1>Editing todo</h1>\n\n<% form_for(@todo) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :subject %><br />\n    <%= f.text_field :subject %>\n  </p>\n  <p>\n    <%= f.label :author_id %><br />\n    <%= f.text_field :author_id %>\n  </p>\n  <p>\n    <%= f.label :owner_id %><br />\n    <%= f.text_field :owner_id %>\n  </p>\n  <p>\n    <%= f.label :completed_on %><br />\n    <%= f.datetime_select :completed_on %>\n  </p>\n  <p>\n    <%= f.submit 'Update' %>\n  </p>\n<% end %>\n\n<%= link_to 'Show', @todo %> |\n<%= link_to 'Back', todos_path %>\n"
  },
  {
    "path": "app/views/todos/index.html.erb",
    "content": "<h1>Listing todos</h1>\n\n<table>\n  <tr>\n    <th>Subject</th>\n    <th>Author</th>\n    <th>translation missing: en, field_owner</th>\n    <th>translation missing: en, field_completed_on</th>\n  </tr>\n\n<% @todos.each do |todo| %>\n  <tr>\n    <td><%=h todo.subject %></td>\n    <td><%=h todo.author_id %></td>\n    <td><%=h todo.owner_id %></td>\n    <td><%=h todo.completed_on %></td>\n    <td><%= link_to 'Show', todo %></td>\n    <td><%= link_to 'Edit', edit_todo_path(todo) %></td>\n    <td><%= link_to 'Destroy', todo, :confirm => 'Are you sure?', :method => :delete %></td>\n  </tr>\n<% end %>\n</table>\n\n<br />\n\n<%= link_to 'New todo', new_todo_path %>\n"
  },
  {
    "path": "app/views/todos/new.html.erb",
    "content": "<h1>New todo</h1>\n\n<% form_for(@todo) do |f| %>\n  <%= f.error_messages %>\n\n  <p>\n    <%= f.label :subject %><br />\n    <%= f.text_field :subject %>\n  </p>\n  <p>\n    <%= f.label :author_id %><br />\n    <%= f.text_field :author_id %>\n  </p>\n  <p>\n    <%= f.label :owner_id %><br />\n    <%= f.text_field :owner_id %>\n  </p>\n  <p>\n    <%= f.label :completed_on %><br />\n    <%= f.datetime_select :completed_on %>\n  </p>\n  <p>\n    <%= f.submit 'Create' %>\n  </p>\n<% end %>\n\n<%= link_to 'Back', todos_path %>\n"
  },
  {
    "path": "app/views/todos/show.html.erb",
    "content": "<p>\n  <b>Subject:</b>\n  <%=h @todo.subject %>\n</p>\n\n<p>\n  <b>Author:</b>\n  <%=h @todo.author_id %>\n</p>\n\n<p>\n  <b>translation missing: en, field_owner:</b>\n  <%=h @todo.owner_id %>\n</p>\n\n<p>\n  <b>translation missing: en, field_completed_on:</b>\n  <%=h @todo.completed_on %>\n</p>\n\n\n<%= link_to 'Edit', edit_todo_path(@todo) %> |\n<%= link_to 'Back', todos_path %>\n"
  },
  {
    "path": "app/views/trackers/_form.html.erb",
    "content": "<%= error_messages_for 'tracker' %>\n\n<div class=\"splitcontentleft\">\n<div class=\"gt-content-box tabular\">\n<p><%= f.text_field :name, :required => true %></p>\n\n<% if @tracker.new_record? && @trackers.any? %>\n<p><label><%= l(:label_copy_workflow_from) %></label>\n<%= select_tag(:copy_workflow_from, content_tag(\"option\") + options_from_collection_for_select(@trackers, :id, :name)) %></p>\n<% end %>\n</div>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(@tracker.new_record? ? :button_create : :button_save) %>\n</div>\n</div>\n\n<div class=\"splitcontentright\">\n<% if @projects.any? %>\n<fieldset class=\"gt-content-box\" id=\"tracker_project_ids\"><legend><%= l(:label_project_plural) %></legend>\n<%= project_nested_ul(@projects) do |p|\n  content_tag('label', check_box_tag('tracker[project_ids][]', p.id, @tracker.projects.include?(p), :id => nil) + ' ' + h(p))\nend %>\n<%= hidden_field_tag('tracker[project_ids][]', '', :id => nil) %>\n<p><%= check_all_links 'tracker_project_ids' %></p>\n</fieldset>\n<% end %>\n</div>\n"
  },
  {
    "path": "app/views/trackers/edit.html.erb",
    "content": "<h2><%= link_to l(:label_tracker_plural), :controller => 'trackers', :action => 'index' %> &#187; <%=h @tracker %></h2>\n\n<% form_for :tracker, @tracker, :url => { :action => 'edit' }, :builder => TabularFormBuilder do |f| %>\n<%= render :partial => 'form', :locals => { :f => f } %>\n<% end %>\n"
  },
  {
    "path": "app/views/trackers/list.html.erb",
    "content": "<div class=\"contextual\">\n<%= link_to l(:label_tracker_new), {:action => 'new'}, :class => 'icon icon-add' %>\n</div>\n\n<h2><%=l(:label_tracker_plural)%></h2>\n\n<table class=\"gt-table\">\n  <thead><tr>\n  <th><%=l(:label_tracker)%></th>\n  <th></th>\n  <th><%=l(:button_sort)%></th>\n  <th></th>\n  </tr></thead>\n  <tbody>\n<% for tracker in @trackers %>\n  <tr class=\"<%= cycle(\"odd\", \"even\") %>\">\n  <td><%= link_to tracker.name, :action => 'edit', :id => tracker %></td>\n  <td align=\"center\"><% unless tracker.workflows.count > 0 %><span class=\"icon icon-warning\"><%= l(:text_tracker_no_workflow) %> (<%= link_to l(:button_edit), {:controller => 'workflows', :action => 'edit', :tracker_id => tracker} %>)</span><% end %></td>\n  <td align=\"center\" style=\"width:15%;\"><%= reorder_links('tracker', {:action => 'edit', :id => tracker}) %></td>\n  <td class=\"buttons\">\n    <%= link_to(l(:button_delete), { :action => 'destroy', :id => tracker },\n                                   :method => :post,\n                                   :confirm => l(:text_are_you_sure),\n                                   :class => 'icon icon-del') %>\n  </td>\n  </tr>\n<% end %>\n  </tbody>\n</table>\n\n<p class=\"pagination\"><%= pagination_links_full @tracker_pages %></p>\n\n<% html_title(l(:label_tracker_plural)) -%>\n"
  },
  {
    "path": "app/views/trackers/new.html.erb",
    "content": "<h2><%= link_to l(:label_tracker_plural), :controller => 'trackers', :action => 'index' %> &#187; <%=l(:label_tracker_new)%></h2>\n\n<% form_for :tracker, @tracker, :url => { :action => 'new' }, :builder => TabularFormBuilder do |f| %>\n<%= render :partial => 'form', :locals => { :f => f } %>\n<% end %>\n"
  },
  {
    "path": "app/views/users/_activity.html.erb",
    "content": "<% unless @events_by_day.empty? %>\n<h3><%= link_to l(:label_activity), :controller => 'projects', :action => 'activity', :id => nil, :user_id => @user, :from => @events_by_day.keys.first %></h3>\n\n<p>\n<%=l(:label_reported_issues)%>: <%= Issue.count(:conditions => [\"author_id=?\", @user.id]) %>\n</p>\n\n<div id=\"activity\">\n<% @events_by_day.keys.sort.reverse.each do |day| %>\n<h4><%= format_activity_day(day) %></h4>\n<dl>\n<% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%>\n  <dt class=\"<%= e.event_type %>\">\n  <span class=\"time\"><%= format_time(e.event_datetime, false) %></span>\n  <%= content_tag('span', h(e.project), :class => 'project') %>\n  <%= link_to format_activity_title(e.event_title), e.event_url, :class => (e.event_type.match(/^issue/)) ? \"fancyframe\" : \"noframe\" %></dt>\n  <dd><span class=\"description\"><%= format_activity_description(e.event_description) %></span></dd>\n<% end -%>\n</dl>\n<% end -%>\n</div>\n\n<% end %>\n"
  },
  {
    "path": "app/views/users/_form.html.erb",
    "content": "<%= error_messages_for 'user' %>\n<div class=\"gt-content-box tabular\">\n<p><%= f.text_field :login, :required => true, :size => 25  %></p>\n<p><%= f.text_field :firstname, :required => true %></p>\n<p><%= f.text_field :lastname, :required => true %></p>\n<p><%= f.text_field :mail, :required => true %></p>\n<p><%= f.select :language, lang_options_for_select %></p>\n<% if Setting.openid? %>\n<p><%= f.text_field :identity_url  %></p>\n<% end %>\n\n<p><%= f.check_box :admin, :disabled => (@user == User.current) %></p>\n</div>\n\n<div class=\"gt-content-box tabular\">\n<h3><%=l(:label_authentication)%></h3>\n<% unless @auth_sources.empty? %>\n<p><%= f.select :auth_source_id, ([[l(:label_internal), \"\"]] + @auth_sources.collect { |a| [a.name, a.id] }), {}, :onchange => \"if (this.value=='') {Element.show('password_fields');} else {Element.hide('password_fields');}\" %></p>\n<% end %>\n<div id=\"password_fields\" style=\"<%= 'display:none;' if @user.auth_source %>\">\n<p><label for=\"password\"><%=l(:field_password)%><span class=\"required\"> *</span></label>\n<%= password_field_tag 'password', nil, :size => 25  %><br />\n<em><%= l(:text_caracters_minimum, :count => Setting.password_min_length) %></em></p>\n<p><label for=\"password_confirmation\"><%=l(:field_password_confirmation)%><span class=\"required\"> *</span></label>\n<%= password_field_tag 'password_confirmation', nil, :size => 25  %></p>\n</div>\n</div>\n"
  },
  {
    "path": "app/views/users/_general.html.erb",
    "content": "<% labelled_tabular_form_for :user, @user, :url => { :controller => 'users', :action => \"edit\", :tab => nil }, :html => { :class => nil } do |f| %>\n  <%= render :partial => 'form', :locals => { :f => f } %>\n  <% if @user.active? -%>\n    <p><label><%= check_box_tag 'send_information', 1, true %> <%= l(:label_send_information) %></label>\n  <% end -%>\n  <div class=\"gt-table-buttons\">\n  <%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/users/_general_info.html.erb",
    "content": "<span class=\"left\" style=\"padding-right:10px\"><%= avatar @user %></span>\n<ul>\n    <li><%=l(:field_login)%>: <%= @user.login %></li>\n  <% unless @user.pref.hide_mail %>\n    <li><%=l(:field_mail)%>: <%= mail_to(h(@user.mail), nil, :encode => 'javascript') %></li>\n  <% end %>\n    <li><%=l(:label_registered_on)%>: <%= format_date(@user.created_at) %></li>\n  <% unless @user.last_login_on.nil? %>\n    <li><%=l(:field_last_login_on)%>: <%= format_date(@user.last_login_on) %></li>\n  <% end %>\n</ul>\n"
  },
  {
    "path": "app/views/users/_membership.html.erb",
    "content": "<% unless @memberships.empty? %>\n<h3 class=\"icon icon-users\"><%=l(:label_project_plural)%></h3>\n<div class=\"gt-content-box padded\">\n<ul>\n<% for membership in @memberships %>\n  <li><%= link_to(h(membership.project.name_with_ancestors), :controller => 'projects', :action => 'show', :id => membership.project) %><%= volunteering membership.project %><%= privacy membership.project %>&nbsp;\n   <%=h membership.roles.sort.collect(&:to_s).join(', ') %></li>\n<% end %>\n</ul>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/users/_memberships.html.erb",
    "content": "<% roles = Role.find_all_givable(Role::LEVEL_PROJECT) %>\n<% projects = Project.active.find(:all, :order => 'lft') %>\n\n<div class=\"splitcontentleft\">\n<% if @user.memberships.any? %>\n<table class=\"gt-table memberships\">\n  <thead>\n    <th><%= l(:label_project) %></th>\n    <th><%= l(:label_role_plural) %></th>\n    <th style=\"width:15%\"></th>\n  </thead>\n  <tbody>\n  <% @user.memberships.each do |membership| %>\n  <% next if membership.new_record? %>\n  <tr id=\"member-<%= membership.id %>\" class=\"<%= cycle 'odd', 'even' %> class\">\n  <td class=\"project\"><%=h membership.project %></td>\n  <td class=\"roles\">\n    <span id=\"member-<%= membership.id %>-roles\"><%=h membership.roles.sort.collect(&:to_s).join(', ') %></span>\n    <% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @user, :membership_id => membership },\n                                    :html => { :id => \"member-#{membership.id}-roles-form\", :style => 'display:none;'}) do %>\n        <p><% roles.each do |role| %>\n        <label><%= check_box_tag 'membership[role_ids][]', role.id, membership.roles.include?(role),\n                                                           :disabled => membership.member_roles.detect {|mr| mr.role_id == role.id && !mr.inherited_from.nil?} %> <%=h role %></label><br />\n        <% end %></p>\n        <%= hidden_field_tag 'membership[role_ids][]', '' %>\n        <div class=\"gt-table-buttons\">\n        <%= submit_tag l(:button_change) %>\n        <p class=\"gt-cancel\"><%= link_to_function l(:button_cancel), \"$('member-#{membership.id}-roles').show(); $('member-#{membership.id}-roles-form').hide(); return false;\" %></p>\n        </div>\n    <% end %>\n  </td>\n  <td class=\"buttons\">\n      <%= link_to_function l(:button_edit), \"$('member-#{membership.id}-roles').hide(); $('member-#{membership.id}-roles-form').show(); return false;\", :class => 'icon icon-edit' %>\n      <%= link_to_remote(l(:button_delete), { :url => { :controller => 'users', :action => 'destroy_membership', :id => @user, :membership_id => membership },\n                                              :method => :post },\n                                              :class => 'icon icon-del') if membership.deletable? %>\n  </td>\n  </tr>\n  </tbody>\n<% end; reset_cycle %>\n</table>\n<% else %>\n<p class=\"nodata\"><%= l(:label_no_data) %></p>\n<% end %>\n</div>\n\n<div class=\"splitcontentright\">\n<% if projects.any? %>\n<fieldset><legend><%=l(:label_project_new)%></legend>\n<% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @user }) do %>\n<%= select_tag 'membership[project_id]', options_for_membership_project_select(@user, projects) %>\n<p><%= l(:label_role_plural) %>:\n<% roles.each do |role| %>\n  <label><%= check_box_tag 'membership[role_ids][]', role.id %> <%=h role %></label>\n<% end %></p>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_add), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n</fieldset>\n<% end %>\n</div>\n"
  },
  {
    "path": "app/views/users/_reputation.html.erb",
    "content": "<h3><%= l(:label_general) %></h3>\n<div class=\"gt-content-box padded\">\n<%= render :partial => \"general_info\" %>\n</div>\n\n<% unless @reputations.empty? %>\n  <h3><%= l(:label_assessment_accuracy) %> <%= help_bubble :help_assessment_accuracy %></h3>\n  <div class=\"gt-content-box padded\">\n  <ul>\n  <% for reputation in @reputations %>\n    <li><%= reputation_value(reputation.reputation_type, reputation.value) %>\n       - <%= reputation_project(reputation) %>\n      </li>\n  <% end %>\n  </ul>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/users/add.html.erb",
    "content": "<h2><%= link_to l(:label_user_plural), :controller => 'users', :action => 'index' %> &#187; <%=l(:label_user_new)%></h2>\n\n<% labelled_tabular_form_for :user, @user, :url => { :action => \"add\" }, :html => { :class => nil } do |f| %>\n  <%= render :partial => 'form', :locals => { :f => f } %>\n  <p><label><%= check_box_tag 'send_information', 1, true %> <%= l(:label_send_information) %></label></p>\n  <div class=\"gt-table-buttons\">\n    <%= submit_tag l(:button_create), :disable_with => l(:button_working) %>\n    <%= submit_tag l(:button_create_and_continue), :name => 'continue', :disable_with => l(:button_working) %>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/users/edit.html.erb",
    "content": "<div class=\"contextual\">\n<%= change_status_link(@user) %>\n</div>\n\n<h2><%= link_to l(:label_user_plural), :controller => 'users', :action => 'index' %> &#187; <%=h @user.login %></h2>\n\n<%= render_tabs user_settings_tabs %>\n\n<% html_title(l(:label_user), @user.login, l(:label_administration)) -%>\n"
  },
  {
    "path": "app/views/users/index.html.erb",
    "content": "<div class=\"contextual\">\n<%= link_to l(:label_user_new), {:action => 'add'}, :class => 'icon icon-add' %>\n</div>\n\n<h2><%=l(:label_user_plural)%></h2>\n\n<% form_tag({}, :method => :get) do %>\n<fieldset><legend><%= l(:label_filter_plural) %></legend>\n<label><%= l(:field_status) %>:</label>\n<%= select_tag 'status', users_status_options_for_select(@status), :class => \"small\", :onchange => \"this.form.submit(); return false;\"  %>\n<label><%= l(:label_user) %>:</label>\n<%= text_field_tag 'name', params[:name], :size => 30 %>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_apply), :class => \"small\", :name => nil, :disable_with => l(:button_working) %>\n</div>\n</fieldset>\n<% end %>\n&nbsp;\n\n<table class=\"gt-table\">\n  <thead><tr>\n  <%= sort_header_tag('login', :caption => l(:field_login)) %>\n  <%= sort_header_tag('firstname', :caption => l(:field_firstname)) %>\n  <%= sort_header_tag('lastname', :caption => l(:field_lastname)) %>\n  <%= sort_header_tag('mail', :caption => l(:field_mail)) %>\n  <%= sort_header_tag('admin', :caption => l(:field_admin), :default_order => 'desc') %>\n  <%= sort_header_tag('created_at', :caption => l(:field_created_at), :default_order => 'desc') %>\n  <%= sort_header_tag('last_login_on', :caption => l(:field_last_login_on), :default_order => 'desc') %>\n    <th></th>\n  </tr></thead>\n  <tbody>\n<% for user in @users -%>\n  <tr class=\"user <%= cycle(\"odd\", \"even\") %> <%= %w(anon active registered locked)[user.status] %>\">\n  <td class=\"username\"><%= avatar(user, :size => \"14\") %><%= link_to h(user.login), :action => 'edit', :id => user %></td>\n  <td class=\"firstname\"><%= h(user.firstname) %></td>\n  <td class=\"lastname\"><%= h(user.lastname) %></td>\n  <td class=\"email\"><%= mail_to(h(user.mail)) %></td>\n  <td align=\"center\"><%= image_tag('true.png') if user.admin? %></td>\n  <td class=\"created_at\" align=\"center\"><%= format_time(user.created_at) %></td>\n  <td class=\"last_login_on\" align=\"center\"><%= format_time(user.last_login_on) unless user.last_login_on.nil? %></td>\n    <td><small><%= change_status_link(user) %></small></td>\n  </tr>\n<% end -%>\n  </tbody>\n</table>\n\n<p class=\"pagination\"><%= pagination_links_full @user_pages, @user_count %></p>\n\n<% html_title(l(:label_user_plural)) -%>\n"
  },
  {
    "path": "app/views/users/show.html.erb",
    "content": "<% @page_header_name = @user.name %>\n<div class=\"contextual\">\n<%= link_to(l(:button_edit), {:controller => 'users', :action => 'edit', :id => @user}, :class => 'icon icon-edit') if User.current.admin? %>\n</div>\n\n<div class=\"splitcontentleft\">\n  <h2 class=\"gt-table-head icon icon-activity\">Recent Activity</h2>\n  <div class=\"gt-content-box padded\">\n  <%= render :partial => \"activity_streams/activity_stream_list\", :locals => {\n      :user_id => @user.id,\n      :project_id => nil,\n      :with_subprojects => nil,\n      :limit => nil,\n      :max_created_at => nil\n      } %>\n  </div>\n</div>\n\n<div class=\"splitcontentright\">\n  <%= render :partial => \"reputation\" %>\n  <%= render :partial => \"membership\" %>\n</div>\n\n<% html_title @user.name %>\n"
  },
  {
    "path": "app/views/watchers/_watchers.html.erb",
    "content": "<p><strong><%= l(:label_issue_watchers) %></strong></p>\n<%= watchers_list(watched) %>\n\n<% unless @watcher.nil? %>\n<% remote_form_for(:watcher, @watcher,\n                   :url => {:controller => 'watchers',\n                            :action => 'new',\n                            :object_type => watched.class.name.underscore,\n                            :object_id => watched},\n                   :method => :post,\n                   :html => {:id => 'new-watcher-form'}) do |f| %>\n<p><%= f.select :user_id, (watched.addable_watcher_users.collect {|m| [m.name, m.id]}), :prompt => true %>\n\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_add), :disable_with => l(:button_working) %>\n<p class=\"gt-cancel\">\n<%= toggle_link l(:button_cancel), 'new-watcher-form'%></p>\n</div></p>\n<% end %>\n<% end %>\n\n\n<% content_for :sidebar do %>\n  <div class=\"gt-sidebar-nav gt-sidebar-nav-gray\">\n    <ul>\n      <li>\n        <%= link_to_remote l(:button_add),\n                           :url => {:controller => 'watchers',\n                                    :action => 'new',\n                                    :object_type => watched.class.name.underscore,\n                                    :object_id => watched} if User.current.allowed_to?(:add_issue_watchers, @project) %>\n      </li>\n      <li>\n      </li>\n    </ul>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/welcome/_list_workstreams.html.erb",
    "content": "    <% if workstreams.any? %>\n  <h2 class=\"gt-table-head icon22 icon22-projects\"><%=l(:label_enterprise_latest)%></h2>\n  <div class=\"gt-content-box\">\n    <table border=\"0\" class=\"gt-table gt-user-table\">\n      <tbody>\n          <% for project in workstreams %>\n          <tr>\n            <td>\n            <h4><%= link_to h(project.name), :controller => 'projects', :action => 'show', :id => project %></h4>\n            <p><%= textilizable project.short_description, :project => project %></p>\n            </td>\n            <td>\n              <table border=\"0\" class=\"gt-table-categories\">\n                <tr>\n                  <td colspan=\"2\"><span class=\"spark right\" max=\"<%= project.activity_line_max %>\"><%= project.activity_line_show(30) %></span></td>\n                </tr>\n                <tr>\n                  <td colspan=\"2\">&nbsp;</td>\n                </tr>\n                <tr>\n                  <th>Created:</th>\n                  <td><%= since_tag(project.created_at) %> ago</td>\n                </tr>\n                <tr>\n                  <th>Team:</th>\n                  <td><%= project.all_members.count %> members</td>\n                </tr>\n              </table>\n            </td>\n          </tr>\n          <% end %>\n\n      </tbody>\n    </table>\n  </div>\n  <div class=\"gt-table-buttons\">\n    <%= link_to l(:label_browse_workstreams), {:controller => :projects, :action => :index}, :class => \"gt-btn-blue-large\" %>\n  </div>\n  <% end %>\n"
  },
  {
    "path": "app/views/welcome/index.html.erb",
    "content": "<% content_for :mainmenu do %>\n  <%= render :partial => 'common/main_menu_home', :locals => {:active_page => :mypage} %>\n<% end %>\n\n<%= help_section(\"welcome_index\",true) %>\n\n<% if Notification.unresponded? %>\n<div class=\"flash notice\">\n  <%=link_to l(:label_waiting_for_you, :notifications => pluralize(Notification.unresponded_count,l(:label_new_notification))) , {:controller => 'notifications', :action => 'index'} %>\n</div>\n<% end %>\n\n<div class=\"gt-left-col\">\n  <% if @my_projects.length == 0 %>\n  <div class=\"gt-content-box centered padded\">\n    <h4><%= l(:help_no_workstreams) %></h4>\n    <p class='nodata'>\n          <h3> <%= link_to(l(:label_project_new), {:controller => 'projects', :action => 'add'})%> </h3>\n          <h3><%= link_to l(:label_browse_workstreams), {:controller => :projects, :action => :index}%></h3>\n       </p>\n  </div>\n  <% else %>\n    <h2 class=\"gt-table-head icon icon-activity\"><%=l(:label_activities_i_belong_to)%></h2>\n    <div class=\"activity gt-content-box\">\n      <%= render :partial => 'activity_streams/activity_stream_list', :locals => {\n        :user_id => User.current.id,\n        :project_id => nil,\n        :with_subprojects => \"custom\",\n        :limit => 30,\n        :max_created_at => nil\n      } %>\n    </div>\n    <% end %>\n</div>\n\n<div class=\"gt-right-col\">\n  <%  if @my_projects.length > 0 %>\n    <h2 class=\"icon icon-projects\"><%= l(:label_projects_recent) %> <%= link_to l(:label_view_all), {:controller => \"my\", :action => \"projects\"}, :class => \"floating-h-link\" %></h2>\n    <div class=\"gt-content-box active-projects\">\n    <%= render :partial => 'projects/projects_list_simple', :locals => {:projects => @my_projects, :max_count => 10} %>\n    </div>\n  <% end %>\n\n  <%= render :partial => \"my/blocks/news\", :locals => {:news => @news, :maxcount => 2 } %>\n\n  <%  if @assigned_issues.length > 0 %>\n    <h2 class=\"icon icon-issues\"><%= l(:label_my_issues) %><%= link_to l(:label_view_all), {:controller => \"my\", :action => \"issues\"}, :class => \"floating-h-link\" %></h2>\n    <%= render :partial => \"issues/list_very_simple\", :locals => {:issues => @assigned_issues} %>\n  <% end  %>\n</div>\n\n<% content_for :actionmenu do %>\n    <ul>\n    <li>\n      <%= link_to l(:label_project_new), {:controller => 'projects', :action => 'add', :parent_id => @project}, :class => \"icon icon-add\" %>\n    </li>\n    </ul>\n    <ul>\n    <li>\n      <%= link_to l(:label_browse_workstreams), {:controller => 'projects', :action => 'index'}, :class => \"icon icon-projects\" %>\n    </li>\n    </ul>\n<% end %>\n\n<script>\n  $('document').ready(function(){\n    display_sparks();\n  });\n</script>\n"
  },
  {
    "path": "app/views/welcome/robots.html.erb",
    "content": "User-agent: *\nDisallow: /boards\nDisallow: /issues\nDisallow: /activity\nDisallow: /projects\nDisallow: /news\n<% @projects.each do |p| -%>\nDisallow: /projects/<%= p.to_param %>/issues\nDisallow: /projects/<%= p.to_param %>/activity\nDisallow: /projects/<%= p.to_param %>\nDisallow: /projects/<%= p.identifier %>/issues\nDisallow: /projects/<%= p.identifier %>/activity\nDisallow: /projects/<%= p.identifier %>\n<% end -%>\n"
  },
  {
    "path": "app/views/wiki/_content.html.erb",
    "content": "<div class=\"wiki gt-content-box\">\n  <%= textilizable content, :text, :attachments => content.page.attachments %>\n</div>\n"
  },
  {
    "path": "app/views/wiki/_sidebar.html.erb",
    "content": "<div class=\"gt-sidebar-nav gt-sidebar-nav-blue\">\n<h3><%= l(:label_wiki) %></h3>\n<ul>\n  <li>\n    <a href=\"#\" onclick=\"show_prompt_for_new_page(); return false\"><%= l(:label_new_page) %></a>\n  </li>\n  <li>\n  <%= link_to l(:field_start_page), {:action => 'index', :page => nil} %>\n  </li>\n\n<li>\n<%= link_to l(:label_index_by_title), {:action => 'special', :page => 'Page_index'} %>\n</li><li>\n<%= link_to l(:label_index_by_date), {:action => 'special', :page => 'Date_index'} %>\n</li></ul>\n\n</div>\n\n<script type=\"text/javascript\">\nfunction show_prompt_for_new_page()\n{\nvar name=prompt(\"Choose a name for your new page\",\"New Page Name\");\nif (name!=null && name!=\"\")\n  {\n    var location = []\n    location = window.location.href.replace(\"#\",\"\").split('/');\n    for (var i=0; i < location.length; i++){\n      if (location[i] == 'wiki'){\n        for (var j=location.length - 1 ; j > i; j--){\n          location.pop();\n        }\n        break;\n      }\n    }\n    location.push(name.replace(\" \", \"_\"));\n    window.location.href = location.join(\"/\");\n  }\n}\n</script>\n"
  },
  {
    "path": "app/views/wiki/annotate.html.erb",
    "content": "<h2><%= @page.pretty_title %></h2>\n\n<p>\n<%= l(:label_version) %> <%= link_to @annotate.content.version, :action => 'index', :page => @page.title, :version => @annotate.content.version %>\n<em>(<%= @annotate.content.author ? @annotate.content.author.name : \"anonyme\" %>, <%= format_time(@annotate.content.updated_at) %>)</em>\n</p>\n\n<% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %>\n\n<table class=\"filecontent annotate CodeRay \">\n<tbody>\n<% line_num = 1 %>\n<% @annotate.lines.each do |line| -%>\n<tr class=\"bloc-<%= colors[line[0]] %>\">\n    <th class=\"line-num\"><%= line_num %></th>\n    <td class=\"revision\"><%= link_to line[0], :controller => 'wiki', :action => 'index', :id => @project, :page => @page.title, :version => line[0] %></td>\n    <td class=\"author\"><%= h(line[1]) %></td>\n    <td class=\"line-code\"><pre><%=h line[2] %></pre></td>\n</tr>\n<% line_num += 1 %>\n<% end -%>\n</tbody>\n</table>\n\n<% content_for :header_tags do %>\n<%= stylesheet_link_tag 'scm' %>\n<% end %>\n\n<% content_for :sidebar do %>\n  <div class=\"gt-sidebar-nav gt-sidebar-nav-gray\">\n    <ul>\n      <li>\n        <%= link_to(l(:button_edit), {:action => 'edit', :page => @page.title}, :class => 'icon icon-edit') %>\n      </li>\n      <li>\n        <%= link_to(l(:label_history), {:action => 'history', :page => @page.title}, :class => 'icon icon-history') %>\n      </li>\n    </ul>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/wiki/destroy.html.erb",
    "content": "<h2><%=h @page.pretty_title %></h2>\n\n<% form_tag({}) do %>\n<div class=\"gt-content-box\">\n<p><strong><%= l(:text_wiki_page_destroy_question, :descendants => @descendants_count) %></strong></p>\n<p><label><%= radio_button_tag 'todo', 'nullify', true %> <%= l(:text_wiki_page_nullify_children) %></label><br />\n<label><%= radio_button_tag 'todo', 'destroy', false %> <%= l(:text_wiki_page_destroy_children) %></label>\n<% if @reassignable_to.any? %>\n<br />\n<label><%= radio_button_tag 'todo', 'reassign', false %> <%= l(:text_wiki_page_reassign_children) %></label>:\n<%= select_tag 'reassign_to_id', wiki_page_options_for_select(@reassignable_to),\n                                 :onclick => \"$('todo_reassign').checked = true;\" %>\n<% end %>\n</p>\n</div>\n\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_apply), :disable_with => l(:button_working) %>\n</div>\n<%= link_to l(:button_cancel), :controller => 'wiki', :action => 'index', :id => @project, :page => @page.title %>\n<% end %>\n"
  },
  {
    "path": "app/views/wiki/diff.html.erb",
    "content": "\n<h2><%= @page.pretty_title %></h2>\n\n<p>\n<%= l(:label_version) %> <%= link_to @diff.content_from.version, :action => 'index', :page => @page.title, :version => @diff.content_from.version %>\n<em>(<%= @diff.content_from.author ? @diff.content_from.author.name : \"anonyme\" %>, <%= format_time(@diff.content_from.updated_at) %>)</em>\n&#8594;\n<%= l(:label_version) %> <%= link_to @diff.content_to.version, :action => 'index', :page => @page.title, :version => @diff.content_to.version %>/<%= @page.content.version %>\n<em>(<%= @diff.content_to.author ? @diff.content_to.author.name : \"anonyme\" %>, <%= format_time(@diff.content_to.updated_at) %>)</em>\n</p>\n\n<hr />\n\n<% content_for :sidebar do %>\n  <div class=\"gt-sidebar-nav gt-sidebar-nav-gray\">\n    <ul>\n      <li>\n        <%= link_to(l(:label_history), {:action => 'history', :page => @page.title}, :class => 'icon icon-history') %>\n      </li>\n    </ul>\n  </div>\n<% end %>\n\n\n<%= html_diff(@diff) %>\n"
  },
  {
    "path": "app/views/wiki/edit.html.erb",
    "content": "<h2><%=h @page.pretty_title %></h2>\n\n<% form_for :content, @content, :url => {:action => 'edit', :page => @page.title}, :html => {:id => 'wiki_form'} do |f| %>\n<%= f.hidden_field :version %>\n<%= error_messages_for 'content' %>\n<p><%= f.textile_editor :text, :cols => 100, :rows => 25, :class => 'wiki-edit', :accesskey => accesskey(:edit), \"autocomplete-mentions-projectid\" => @project.id %></p>\n<p><label><%= l(:field_wiki_comments) %><%= help_bubble :help_revision_notes %></label><br /><%= f.text_field :comments, :size => 120, \"autocomplete-mentions-projectid\" => @project.id %></p>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n<p class=\"gt-cancel\">   <%= link_to_remote l(:label_preview),\n                       { :url => { :controller => 'wiki', :action => 'preview', :id => @project, :page => @page.title },\n                         :method => 'post',\n                         :update => 'preview',\n                         :with => \"$('#wiki_form').serialize()\",\n                         :complete => \"$('body').scrollTo('#preview')\"\n                       }, :accesskey => accesskey(:preview) %></p>\n</div>\n<%= textile_editor_initialize(:framework => :jquery) %>\n<% end %>\n\n<div id=\"preview\" class=\"wiki\"></div>\n\n<% content_for :header_tags do %>\n  <%= stylesheet_link_tag 'scm' %>\n<% end %>\n\n<% html_title @page.pretty_title %>\n"
  },
  {
    "path": "app/views/wiki/export.html.erb",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<head>\n<title><%=h @page.pretty_title %></title>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n<style>\nbody { font:80% Verdana,Tahoma,Arial,sans-serif; }\nh1, h2, h3, h4 {  font-family: \"Trebuchet MS\",Georgia,\"Times New Roman\",serif; }\nul.toc { padding: 4px; margin-left: 0; }\nul.toc li { list-style-type:none; }\nul.toc li.heading2 { margin-left: 1em; }\nul.toc li.heading3 { margin-left: 2em; }\na.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }\na.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }\nh1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }\n</style>\n</head>\n<body>\n<%= textilizable @content, :text, :wiki_links => :local %>\n</body>\n</html>\n"
  },
  {
    "path": "app/views/wiki/export_multiple.html.erb",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<head>\n<title><%=h @wiki.project.name %></title>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n<style>\nbody { font:80% Verdana,Tahoma,Arial,sans-serif; }\nh1, h2, h3, h4 {  font-family: \"Trebuchet MS\",Georgia,\"Times New Roman\",serif; }\nul.toc { padding: 4px; margin-left: 0; }\nul.toc li { list-style-type:none; }\nul.toc li.heading2 { margin-left: 1em; }\nul.toc li.heading3 { margin-left: 2em; }\na.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }\na.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }\nh1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }\n</style>\n</head>\n<body>\n\n<strong><%= l(:label_index_by_title) %></strong>\n<ul>\n<% @pages.each do |page| %>\n    <li><a href=\"#<%= page.title %>\"><%= page.pretty_title %></a></li>\n<% end %>\n</ul>\n\n<% @pages.each do |page| %>\n<hr />\n<a name=\"<%= page.title %>\" />\n<%= textilizable page.content ,:text, :wiki_links => :anchor %>\n<% end %>\n\n</body>\n</html>\n"
  },
  {
    "path": "app/views/wiki/history.html.erb",
    "content": "<h2><%= @page.pretty_title %></h2>\n\n<h3><%= l(:label_history) %></h3>\n\n<% form_tag({:action => \"diff\"}, :method => :get) do %>\n<table class=\"gt-table\">\n<thead><tr>\n    <th>#</th>\n    <th></th>\n    <th></th>\n    <th><%= l(:field_updated_at) %></th>\n    <th><%= l(:field_author) %></th>\n    <th><%= l(:field_comments) %></th>\n    <th></th>\n</tr></thead>\n<tbody>\n<% show_diff = @versions.size > 1 %>\n<% line_num = 1 %>\n<% @versions.each do |ver| %>\n<tr class=\"<%= cycle(\"odd\", \"even\") %>\">\n    <td class=\"id\"><%= link_to ver.version, :action => 'index', :page => @page.title, :version => ver.version %></td>\n    <td class=\"checkbox\"><%= radio_button_tag('version', ver.version, (line_num==1), :id => \"cb-#{line_num}\", :onclick => \"$('cbto-#{line_num+1}').checked=true;\") if show_diff && (line_num < @versions.size) %></td>\n    <td class=\"checkbox\"><%= radio_button_tag('version_from', ver.version, (line_num==2), :id => \"cbto-#{line_num}\", :onclick => \"if ($('cb-#{line_num}').checked==true || $('version_from').value > #{ver.version}) {$('cb-#{line_num-1}').checked=true;}\") if show_diff && (line_num > 1) %></td>\n    <td align=\"center\"><%= format_time(ver.updated_at) %></td>\n    <td><em><%= ver.author ? ver.author.name : \"anonyme\" %></em></td>\n    <td><%=h ver.comments %></td>\n    <td align=\"center\"><%= link_to l(:button_annotate), :action => 'annotate', :page => @page.title, :version => ver.version %></td>\n</tr>\n<% line_num += 1 %>\n<% end %>\n</tbody>\n</table>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:label_view_diff), :class => 'small', :disable_with => l(:button_working) if show_diff %>\n</div>\n<span class=\"pagination\"><%= pagination_links_full @version_pages, @version_count, :page_param => :p %></span>\n<% end %>\n"
  },
  {
    "path": "app/views/wiki/rename.html.erb",
    "content": "<h2><%= l(:button_rename) %>: <%= @original_title %></h2>\n\n<%= error_messages_for 'page' %>\n\n<% labelled_tabular_form_for :wiki_page, @page, :url => { :action => 'rename' } do |f| %>\n<div class=\"gt-content-box\">\n<p><%= f.text_field :title, :required => true, :size => 100  %></p>\n<p><%= f.check_box :redirect_existing_links %></p>\n<p><%= f.text_field :parent_title, :size => 100  %></p>\n</div>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_rename), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/wiki/show.html.erb",
    "content": "<%= help_section \"project_wiki\" %>\n<%= breadcrumb(@page.ancestors.reverse.collect {|parent| link_to h(parent.pretty_title), {:page => parent.title}}) %>\n\n<% if @content.version != @page.content.version %>\n    <p>\n    <%= link_to(('&#171; ' + l(:label_previous)), :action => 'index', :page => @page.title, :version => (@content.version - 1)) + \" - \" if @content.version > 1 %>\n    <%= \"#{l(:label_version)} #{@content.version}/#{@page.content.version}\" %>\n    <%= '(' + link_to('diff', :controller => 'wiki', :action => 'diff', :page => @page.title, :version => @content.version) + ')' if @content.version > 1 %> -\n    <%= link_to((l(:label_next) + ' &#187;'), :action => 'index', :page => @page.title, :version => (@content.version + 1)) + \" - \" if @content.version < @page.content.version %>\n    <%= link_to(l(:label_current_version), :action => 'index', :page => @page.title) %>\n    <br />\n    <em><%= @content.author ? @content.author.name : \"anon\" %>, <%= format_time(@content.updated_at) %> </em><br />\n    <%=h @content.comments %>\n    </p>\n    <hr />\n<% end %>\n\n<%= render(:partial => \"wiki/content\", :locals => {:content => @content}) %>\n\n<% if @editable && authorize_for('wiki', 'add_attachment') %>\n<div id=\"wiki_add_attachment\">\n<p></p>\n<% form_tag({ :controller => 'wiki', :action => 'add_attachment', :page => @page.title }, :multipart => true, :id => \"add_attachment_form\", :style => \"display:none;\") do %>\n  <div class=\"gt-content-box\">\n  <p><%= render :partial => 'attachments/form' %></p>\n  </div>\n  <div class=\"gt-table-buttons\">\n    <%= submit_tag l(:button_add), :disable_with => l(:button_working) %>\n  </div>\n<%= link_to l(:button_cancel), {}, :onclick => \"Element.hide('add_attachment_form'); Element.show('attach_files_link'); return false;\" %>\n<% end %>\n</div>\n<% end %>\n\n<div class=\"gt-table-controls gt-table-controls-btm clearfix\">\n    <p class=\"gt-table-pager\">\n      <% other_formats_links do |f| %>\n        <%= f.link_to 'HTML', :url => {:page => @page.title, :version => @content.version} %>\n        <%= f.link_to 'TXT', :url => {:page => @page.title, :version => @content.version} %>\n      <% end %>\n    </p>\n</div>\n\n<% content_for :header_tags do %>\n  <%= stylesheet_link_tag 'scm' %>\n<% end %>\n\n<% content_for :sidebar do %>\n <div class=\"gt-sidebar-nav gt-sidebar-nav-gray\">\n   <ul>\n     <% if @editable %>\n     <li>\n     <%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :page => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit)) if @content.version == @page.content.version %>\n</li>\n<li>\n     <%= watcher_tag(@page, User.current) %>\n</li>\n<li>\n     <%= link_to_if_authorized(l(:button_lock), {:action => 'protect', :page => @page.title, :protected => 1}, :method => :post, :class => 'icon icon-lock') if !@page.protected? %>\n</li>     <li>\n     <%= link_to_if_authorized(l(:button_unlock), {:action => 'protect', :page => @page.title, :protected => 0}, :method => :post, :class => 'icon icon-unlock') if @page.protected? %>\n</li>     <li>\n     <%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :page => @page.title}, :class => 'icon icon-move') if @content.version == @page.content.version %>\n</li>     <li>\n     <%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :page => @page.title}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') %>\n</li>     <li>\n     <%= link_to_if_authorized(l(:button_rollback), {:action => 'edit', :page => @page.title, :version => @content.version }, :class => 'icon icon-cancel') if @content.version < @page.content.version %>\n</li>\n     <% end %>\n     <li>\n     <%= link_to_if_authorized(l(:label_history), {:action => 'history', :page => @page.title}, :class => 'icon icon-history') %>\n\n</li>\n   </ul>\n </div>\n\n  <%= render :partial => 'sidebar' %>\n<% end %>\n\n<% html_title @page.pretty_title %>\n"
  },
  {
    "path": "app/views/wiki/special_date_index.html.erb",
    "content": "<div class=\"contextual\">\n<%= watcher_tag(@wiki, User.current) %>\n</div>\n\n<h2><%= l(:label_index_by_date) %></h2>\n\n<% if @pages.empty? %>\n<p class=\"nodata\"><%= l(:label_no_data) %></p>\n<% end %>\n\n<% @pages_by_date.keys.sort.reverse.each do |date| %>\n<h3><%= format_date(date) %></h3>\n<ul>\n<% @pages_by_date[date].each do |page| %>\n    <li><%= link_to page.pretty_title, :action => 'index', :page => page.title %></li>\n<% end %>\n</ul>\n<% end %>\n\n<% content_for :sidebar do %>\n  <%= render :partial => 'sidebar' %>\n<% end %>\n\n<% unless @pages.empty? %>\n<% other_formats_links do |f| %>\n  <%= f.link_to 'HTML', :url => {:action => 'special', :page => 'export'} %>\n<% end %>\n<% end %>\n\n<% content_for :header_tags do %>\n<%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :id => @project, :show_wiki_edits => 1, :format => 'atom', :key => User.current.rss_key) %>\n<% end %>\n"
  },
  {
    "path": "app/views/wiki/special_page_index.html.erb",
    "content": "<div class=\"contextual\">\n<%= watcher_tag(@wiki, User.current) %>\n</div>\n\n<h2><%= l(:label_index_by_title) %></h2>\n\n<% if @pages.empty? %>\n<p class=\"nodata\"><%= l(:label_no_data) %></p>\n<% end %>\n\n<%= render_page_hierarchy(@pages_by_parent_id) %>\n\n<% content_for :sidebar do %>\n  <%= render :partial => 'sidebar' %>\n<% end %>\n\n<% unless @pages.empty? %>\n<% other_formats_links do |f| %>\n  <%= f.link_to 'HTML', :url => {:action => 'special', :page => 'export'} %>\n<% end %>\n<% end %>\n\n<% content_for :header_tags do %>\n<% end %>\n"
  },
  {
    "path": "app/views/wikis/destroy.html.erb",
    "content": "<h2><%=l(:label_confirmation)%></h2>\n\n<div class=\"gt-content-box\"><center>\n<p><strong><%= @project.name %></strong><br /><%=l(:text_wiki_destroy_confirmation)%></p>\n\n<% form_tag({:controller => 'wikis', :action => 'destroy', :id => @project}) do %>\n<%= hidden_field_tag \"confirm\", 1 %>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_delete), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n</center></div>\n"
  },
  {
    "path": "app/views/workflows/_action_menu.html.erb",
    "content": "<div class=\"contextual\">\n<%= link_to l(:button_edit), {:action => 'edit'}, :class => 'icon icon-edit' %>\n<%= link_to l(:button_copy), {:action => 'copy'}, :class => 'icon icon-copy' %>\n<%= link_to l(:field_summary), {:action => 'index'}, :class => 'icon icon-summary' %>\n</div>\n"
  },
  {
    "path": "app/views/workflows/copy.html.erb",
    "content": "<%= render :partial => 'action_menu' %>\n\n<h2><%=l(:label_workflow)%></h2>\n\n<% form_tag({}, :id => 'workflow_copy_form') do %>\n<div class=\"tabular box\">\n<p>\n  <label><%= l(:label_copy_source) %></label>\n  <%= l(:label_tracker) %><br />\n  <%= select_tag('source_tracker_id',\n                  \"<option value=\\\"\\\">--- #{l(:actionview_instancetag_blank_option)} ---</option>\" +\n                  \"<option value=\\\"any\\\">--- #{ l(:label_copy_same_as_target) } ---</option>\" +\n                  options_from_collection_for_select(@trackers, 'id', 'name', @source_tracker && @source_tracker.id)) %><br />\n  <%= l(:label_role) %><br />\n  <%= select_tag('source_role_id',\n                  \"<option value=\\\"\\\">--- #{l(:actionview_instancetag_blank_option)} ---</option>\" +\n                  \"<option value=\\\"any\\\">--- #{ l(:label_copy_same_as_target) } ---</option>\" +\n                  options_from_collection_for_select(@roles, 'id', 'name', @source_role && @source_role.id)) %>\n</p>\n<p>\n  <label><%= l(:label_copy_target) %></label>\n  <%= l(:label_tracker) %><br />\n  <%= select_tag 'target_tracker_ids',\n                  \"<option value=\\\"\\\" disabled=\\\"disabled\\\">--- #{l(:actionview_instancetag_blank_option)} ---</option>\" +\n                  options_from_collection_for_select(@trackers, 'id', 'name', @target_trackers && @target_trackers.map(&:id)), :multiple => true %><br />\n  <%= l(:label_role) %><br />\n  <%= select_tag 'target_role_ids',\n                  \"<option value=\\\"\\\" disabled=\\\"disabled\\\">--- #{l(:actionview_instancetag_blank_option)} ---</option>\" +\n                  options_from_collection_for_select(@roles, 'id', 'name', @target_roles && @target_roles.map(&:id)), :multiple => true %>\n</p>\n</div>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_copy), :disable_with => l(:button_working) %>\n</div>\n<% end %>\n"
  },
  {
    "path": "app/views/workflows/edit.html.erb",
    "content": "<%= render :partial => 'action_menu' %>\n\n<h2><%=l(:label_workflow)%></h2>\n\n<p><%=l(:text_workflow_edit)%>:</p>\n\n<% form_tag({}, :method => 'get') do %>\n<p>\n  <label><%=l(:label_role)%>:</label>\n  <%= select_tag 'role_id', options_from_collection_for_select(@roles, \"id\", \"name\", @role && @role.id) %>\n\n  <label><%=l(:label_tracker)%>:</label>\n  <%= select_tag 'tracker_id', options_from_collection_for_select(@trackers, \"id\", \"name\", @tracker && @tracker.id) %>\n\n  <%= hidden_field_tag 'used_statuses_only', '0' %>\n  <label><%= check_box_tag 'used_statuses_only', '1', @used_statuses_only %> <%= l(:label_display_used_statuses_only) %></label>\n</p>\n<p>\n<div class=\"gt-table-buttons\">\n<%= submit_tag l(:button_edit), :name => nil %>\n</div>\n</p>\n<% end %>\n\n\n<% if @tracker && @role && @statuses.any? %>\n<% form_tag({}, :id => 'workflow_form' ) do %>\n<%= hidden_field_tag 'tracker_id', @tracker.id %>\n<%= hidden_field_tag 'role_id', @role.id %>\n<table class=\"gt-table\">\n<thead>\n  <tr>\n    <th align=\"left\"><%=l(:label_current_status)%></th>\n    <th align=\"center\" colspan=\"<%= @statuses.length %>\"><%=l(:label_new_statuses_allowed)%></th>\n  </tr>\n  <tr>\n    <td></td>\n    <% for new_status in @statuses %>\n    <td width=\"<%= 75 / @statuses.size %>%\" align=\"center\"><%= new_status.name %></td>\n    <% end %>\n  </tr>\n</thead>\n<tbody>\n  <% for old_status in @statuses %>\n  <tr class=\"<%= cycle(\"odd\", \"even\") %>\">\n    <td><%= old_status.name %></td>\n    <% new_status_ids_allowed = old_status.find_new_statuses_allowed_to([@role], @tracker).collect(&:id) -%>\n    <% for new_status in @statuses -%>\n    <td align=\"center\">\n      <%= check_box_tag \"issue_status[#{ old_status.id }][]\", new_status.id, new_status_ids_allowed.include?(new_status.id) %>\n    </td>\n    <% end -%>\n  </tr>\n  <% end %>\n</tbody>\n</table>\n<p><%= check_all_links 'workflow_form' %></p>\n\n<%= submit_tag l(:button_save), :disable_with => l(:button_working) %>\n<% end %>\n<% end %>\n\n<% html_title(l(:label_workflow)) -%>\n"
  },
  {
    "path": "app/views/workflows/index.html.erb",
    "content": "<%= render :partial => 'action_menu' %>\n\n<h2><%=l(:label_workflow)%></h2>\n\n<% if @workflow_counts.empty? %>\n<p class=\"nodata\"><%= l(:label_no_data) %></p>\n<% else %>\n<table class=\"gt-table\">\n<thead>\n    <tr>\n    <th></th>\n    <% @workflow_counts.first.last.each do |role, count| %>\n    <th>\n        <%= content_tag(role.builtin? ? 'em' : 'span', h(role.name)) %>\n    </th>\n\n    <% end %>\n    </tr>\n</thead>\n<tbody>\n<% @workflow_counts.each do |tracker, roles| -%>\n<tr class=\"<%= cycle('odd', 'even') %>\">\n  <td><%= h tracker %></td>\n  <% roles.each do |role, count| -%>\n    <td align=\"center\">\n      <%= link_to((count > 1 ? count : image_tag('false.png')), {:action => 'edit', :role_id => role, :tracker_id => tracker}, :title => l(:button_edit)) %>\n    </td>\n  <% end -%>\n</tr>\n<% end -%>\n</tbody>\n</table>\n<% end %>\n"
  },
  {
    "path": "config/additional_environment.rb.example",
    "content": "# Copy this file to additional_environment.rb and add any statements\n# that need to be passed to the Rails::Initializer.  `config` is\n# available in this context.\n#\n# Example:\n#\n#   config.log_level = :debug\n#   config.gem \"example_plugin\", :lib => false\n#   config.gem \"timesheet_plugin\", :lib => false, :version => '0.5.0'\n#   config.gem \"aws-s3\", :lib => \"aws/s3\"\n#   ...\n#\n\n"
  },
  {
    "path": "config/boot.rb",
    "content": "# Don't change this file!\n# Configure your app in config/environment.rb and config/environments/*.rb\nrequire 'thread'\n\nRAILS_ROOT = \"#{File.dirname(__FILE__)}/..\" unless defined?(RAILS_ROOT)\n\nmodule Rails\n  class << self\n    def boot!\n      unless booted?\n        preinitialize\n        pick_boot.run\n      end\n    end\n\n    def booted?\n      defined? Rails::Initializer\n    end\n\n    def pick_boot\n      (vendor_rails? ? VendorBoot : GemBoot).new\n    end\n\n    def vendor_rails?\n      File.exist?(\"#{RAILS_ROOT}/vendor/rails\")\n    end\n\n    def preinitialize\n      load(preinitializer_path) if File.exist?(preinitializer_path)\n    end\n\n    def preinitializer_path\n      \"#{RAILS_ROOT}/config/preinitializer.rb\"\n    end\n  end\n\n  class Boot\n    def run\n      load_initializer\n\n      Rails::Initializer.class_eval do\n        def load_gems\n          @bundler_loaded ||= Bundler.require :default, Rails.env\n        end\n      end\n\n      Rails::Initializer.run(:set_load_path)\n    end\n  end\n\n  class VendorBoot < Boot\n    def load_initializer\n      require \"#{RAILS_ROOT}/vendor/rails/railties/lib/initializer\"\n      Rails::Initializer.run(:install_gem_spec_stubs)\n      Rails::GemDependency.add_frozen_gem_path\n    end\n  end\n\n  class GemBoot < Boot\n    def load_initializer\n      self.class.load_rubygems\n      load_rails_gem\n      require 'initializer'\n    end\n\n    def load_rails_gem\n      if version = self.class.gem_version\n        gem 'rails', version\n      else\n        gem 'rails'\n      end\n    rescue Gem::LoadError => load_error\n      $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)\n      exit 1\n    end\n\n    class << self\n      def rubygems_version\n        Gem::RubyGemsVersion rescue nil\n      end\n\n      def gem_version\n        if defined? RAILS_GEM_VERSION\n          RAILS_GEM_VERSION\n        elsif ENV.include?('RAILS_GEM_VERSION')\n          ENV['RAILS_GEM_VERSION']\n        else\n          parse_gem_version(read_environment_rb)\n        end\n      end\n\n      def load_rubygems\n        min_version = '1.3.2'\n        require 'rubygems'\n        unless rubygems_version >= min_version\n          $stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)\n          exit 1\n        end\n\n      rescue LoadError\n        $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)\n        exit 1\n      end\n\n      def parse_gem_version(text)\n        $1 if text =~ /^[^#]*RAILS_GEM_VERSION\\s*=\\s*[\"']([!~<>=]*\\s*[\\d.]+)[\"']/\n      end\n\n      private\n        def read_environment_rb\n          File.read(\"#{RAILS_ROOT}/config/environment.rb\")\n        end\n    end\n  end\nend\n\n# All that for this:\nRails.boot!\n"
  },
  {
    "path": "config/database.yml.example",
    "content": "production:\n  adapter: mysql2\n  database: bettermeans_production\n  host: localhost\n  username: root\n  password: tree\n  encoding: utf8\n\ndevelopment:\n  adapter: postgresql\n  database: bettermeans_development\n  host: localhost\n  min_messages: WARNING\n  username: postgres\n  password: tree\n\ntest: &TEST\n  adapter: postgresql\n  database: bettermeans_test\n  host: localhost\n  min_messages: WARNING\n  username: postgres\n  password: tree\n\ntest_pgsql:\n  adapter: postgresql\n  database: bettermeans_test\n  host: localhost\n  min_messages: WARNING\n  username: postgres\n  password: \"postgres\"\n\ntest_sqlite3:\n  adapter: sqlite3\n  dbfile: db/test.db\n\ndemo:\n  adapter: sqlite3\n  dbfile: db/demo.db\n\n\ncucumber:\n  <<: *TEST\n\nselenium:\n  <<: *TEST\n"
  },
  {
    "path": "config/email.yml.example",
    "content": "# Outgoing email settings\n\nproduction:\n  delivery_method: :smtp\n  smtp_settings:\n    address: smtp.example.net\n    port: 25\n    domain: example.net\n    authentication: :login\n    user_name: \"redmine@example.net\"\n    password: \"redmine\"\n  \ndevelopment:\n  delivery_method: :smtp\n  smtp_settings:\n    address: 127.0.0.1\n    port: 25\n    domain: example.net\n    authentication: :login\n    user_name: \"redmine@example.net\"\n    password: \"redmine\"\n"
  },
  {
    "path": "config/environment.rb",
    "content": "# Be sure to restart your web server when you modify this file.\n\n# Uncomment below to force Rails into production mode when\n# you don't control web/app server and can't set it the proper way\n# ENV['RAILS_ENV'] ||= 'production'\n\n#For ruby debug\nSCRIPT_LINES__ = {} if ENV['RAILS_ENV'] == 'development'\n\n# Bootstrap the Rails environment, frameworks, and default configuration\nrequire File.join(File.dirname(__FILE__), 'boot')\n\n# Load Engine plugin if available\nbegin\n  require File.join(File.dirname(__FILE__), '../vendor/plugins/engines/boot')\nrescue LoadError\n  # Not available\nend\n\nRails::Initializer.run do |config|\n\n  # Settings in config/environments/* take precedence those specified here\n\n  # Skip frameworks you're not going to use\n  # config.frameworks -= [ :action_web_service, :action_mailer ]\n\n  # Add additional load paths for sweepers\n  config.autoload_paths += %W( #{RAILS_ROOT}/app/sweepers )\n\n  # Force all environments to use the same logger level\n  # (by default production uses :info, the others :debug)\n  # config.log_level = :debug\n\n  # Enable page/fragment caching by setting a file-based store\n  # (remember to create the caching directory and make it readable to the application)\n  # config.action_controller.fragment_cache_store = :file_store, \"#{RAILS_ROOT}/cache\"\n\n  # Activate observers that should always be running\n  # config.active_record.observers = :cacher, :garbage_collector\n  config.active_record.observers = :message_observer, :issue_observer, :journal_observer, :news_observer, :document_observer, :wiki_content_observer\n\n  # Make Active Record use UTC-base instead of local time\n  # config.active_record.default_timezone = :utc\n\n  # Use Active Record's schema dumper instead of SQL when creating the test database\n  # (enables use of different database adapters for development and test environments)\n  # config.active_record.schema_format = :ruby\n\n  # Deliveries are disabled by default. Do NOT modify this section.\n  # Define your email configuration in email.yml instead.\n  # It will automatically turn deliveries on\n  # config.action_mailer.perform_deliveries = false\n\n  #Added this to bypass error\n  config.action_controller.session = { :key => \"_bettermeans_session\", :secret => \"95fd75499b43ada8cfbc538558d74312asdf\" }\n\n  # config.gem \"rpx_now\"\n\n  config.after_initialize do # so rake gems:install works\n     RPXNow.api_key = ENV['RPXNOW_KEY']\n  end\n\n  # Load any local configuration that is kept out of source control\n  # (e.g. gems, patches).\n  if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb'))\n    instance_eval File.read(File.join(File.dirname(__FILE__), 'additional_environment.rb'))\n  end\nend\n\n\n"
  },
  {
    "path": "config/environments/cucumber.rb",
    "content": "# IMPORTANT: This file was generated by Cucumber 0.4.3\n# Edit at your own peril - it's recommended to regenerate this file\n# in the future when you upgrade to a newer version of Cucumber.\n\nconfig.cache_classes = true # This must be true for Cucumber to operate correctly!\n\n# Log error messages when you accidentally call methods on nil.\nconfig.whiny_nils = true\n\n# Show full error reports and disable caching\nconfig.action_controller.consider_all_requests_local = true\nconfig.action_controller.perform_caching             = false\n\n# Disable request forgery protection in test environment\nconfig.action_controller.allow_forgery_protection    = false\n\n# Tell Action Mailer not to deliver emails to the real world.\n# The :test delivery method accumulates sent emails in the\n# ActionMailer::Base.deliveries array.\nconfig.action_mailer.delivery_method = :test\n\nconfig.gem 'cucumber',    :lib => false,        :version => '>=0.4.3' unless File.directory?(File.join(Rails.root, 'vendor/plugins/cucumber'))\nconfig.gem 'webrat',      :lib => false,        :version => '>=0.5.3' unless File.directory?(File.join(Rails.root, 'vendor/plugins/webrat'))\nconfig.gem 'rspec',       :lib => false,        :version => '>=1.2.9' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec'))\nconfig.gem 'rspec-rails', :lib => false,        :version => '>=1.2.9' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec-rails'))\n\n"
  },
  {
    "path": "config/environments/demo.rb",
    "content": "# Settings specified here will take precedence over those in config/environment.rb\n\n# The production environment is meant for finished, \"live\" apps.\n# Code is not reloaded between requests\nconfig.cache_classes = true\n\n# Use a different logger for distributed setups\n# config.logger        = SyslogLogger.new\nconfig.log_level = :info\n\n# Full error reports are disabled and caching is turned on\nconfig.action_controller.consider_all_requests_local = false\nconfig.action_controller.perform_caching             = true\n\n# Enable serving of images, stylesheets, and javascripts from an asset server\n# config.action_controller.asset_host                  = \"http://assets.example.com\"\n\n# Disable mail delivery\nconfig.action_mailer.perform_deliveries = false\nconfig.action_mailer.raise_delivery_errors = false\n\n"
  },
  {
    "path": "config/environments/development.rb",
    "content": "# Settings specified here will take precedence over those in config/environment.rb\n\n# In the development environment your application's code is reloaded on\n# every request.  This slows down response time but is perfect for development\n# since you don't have to restart the webserver when you make code changes.\nconfig.cache_classes     = false\n\n# Log error messages when you accidentally call methods on nil.\nconfig.whiny_nils        = true\n\n# Show full error reports and disable caching\nconfig.action_controller.consider_all_requests_local = true\nconfig.action_controller.perform_caching             = false\n\n# Don't care if the mailer can't send\nconfig.action_mailer.raise_delivery_errors = false\n\nconfig.action_view.debug_rjs = true\n\n# config.gem \"rails-footnotes\", :source => \"http://gemcutter.org\"\n\n"
  },
  {
    "path": "config/environments/production.rb",
    "content": "# Settings specified here will take precedence over those in config/environment.rb\n\n# The production environment is meant for finished, \"live\" apps.\n# Code is not reloaded between requests\nconfig.cache_classes = true\n\n# Use a different logger for distributed setups\n# config.logger        = SyslogLogger.new\n\n\n# Full error reports are disabled and caching is turned on\nconfig.action_controller.consider_all_requests_local = false\nconfig.action_controller.perform_caching             = true\n\n# Enable serving of images, stylesheets, and javascripts from an asset server\n# config.action_controller.asset_host                  = \"http://assets.example.com\"\n\n# Disable delivery errors if you bad email addresses should just be ignored\nconfig.action_mailer.raise_delivery_errors = false\n\nActionMailer::Base.smtp_settings = {\n  :address        => \"smtp.sendgrid.net\",\n  :port           => \"25\",\n  :authentication => :plain,\n  :user_name      => ENV['SENDGRID_USERNAME'],\n  :password       => ENV['SENDGRID_PASSWORD'],\n  :domain         => ENV['SENDGRID_DOMAIN'],\n}\n\n# No email in production log\nconfig.action_mailer.logger = nil\n"
  },
  {
    "path": "config/environments/selenium.rb",
    "content": "# IMPORTANT: This file was generated by Cucumber 0.4.3\n# Edit at your own peril - it's recommended to regenerate this file\n# in the future when you upgrade to a newer version of Cucumber.\n\nconfig.cache_classes = true # This must be true for Cucumber to operate correctly!\n\n# Log error messages when you accidentally call methods on nil.\nconfig.whiny_nils = true\n\n# Show full error reports and disable caching\nconfig.action_controller.consider_all_requests_local = true\nconfig.action_controller.perform_caching             = false\n\n# Disable request forgery protection in test environment\nconfig.action_controller.allow_forgery_protection    = false\n\n# Tell Action Mailer not to deliver emails to the real world.\n# The :test delivery method accumulates sent emails in the\n# ActionMailer::Base.deliveries array.\nconfig.action_mailer.delivery_method = :test\n"
  },
  {
    "path": "config/environments/test.rb",
    "content": "# Settings specified here will take precedence over those in config/environment.rb\n\n# The test environment is used exclusively to run your application's\n# test suite.  You never need to work with it otherwise.  Remember that\n# your test database is \"scratch space\" for the test suite and is wiped\n# and recreated between test runs.  Don't rely on the data there!\nconfig.cache_classes = false\n\n# Log error messages when you accidentally call methods on nil.\nconfig.whiny_nils    = true\n\n# Show full error reports and disable caching\nconfig.action_controller.consider_all_requests_local = true\nconfig.action_controller.perform_caching             = false\n\nconfig.action_mailer.perform_deliveries = true\nconfig.action_mailer.delivery_method = :test\n\nconfig.action_controller.session = {\n  :session_key => \"_test_session\",\n  :secret => \"some secret phrase for the tests.\"\n}\n\n# Skip protect_from_forgery in requests http://m.onkey.org/2007/9/28/csrf-protection-for-your-existing-rails-application\nconfig.action_controller.allow_forgery_protection  = false\n"
  },
  {
    "path": "config/environments/test_pgsql.rb",
    "content": "# Settings specified here will take precedence over those in config/environment.rb\n\n# The test environment is used exclusively to run your application's\n# test suite.  You never need to work with it otherwise.  Remember that\n# your test database is \"scratch space\" for the test suite and is wiped\n# and recreated between test runs.  Don't rely on the data there!\nconfig.cache_classes = true\n\n# Log error messages when you accidentally call methods on nil.\nconfig.whiny_nils    = true\n\n# Show full error reports and disable caching\nconfig.action_controller.consider_all_requests_local = true\nconfig.action_controller.perform_caching             = false\n\nconfig.action_mailer.perform_deliveries = true\nconfig.action_mailer.delivery_method = :test\n\nconfig.action_controller.session = {\n  :session_key => \"_test_session\",\n  :secret => \"some secret phrase for the tests.\"\n}\n\n# Skip protect_from_forgery in requests http://m.onkey.org/2007/9/28/csrf-protection-for-your-existing-rails-application\nconfig.action_controller.allow_forgery_protection  = false\n"
  },
  {
    "path": "config/environments/test_sqlite3.rb",
    "content": "# Settings specified here will take precedence over those in config/environment.rb\n\n# The test environment is used exclusively to run your application's\n# test suite.  You never need to work with it otherwise.  Remember that\n# your test database is \"scratch space\" for the test suite and is wiped\n# and recreated between test runs.  Don't rely on the data there!\nconfig.cache_classes = true\n\n# Log error messages when you accidentally call methods on nil.\nconfig.whiny_nils    = true\n\n# Show full error reports and disable caching\nconfig.action_controller.consider_all_requests_local = true\nconfig.action_controller.perform_caching             = false\n\nconfig.action_mailer.perform_deliveries = true\nconfig.action_mailer.delivery_method = :test\n\nconfig.action_controller.session = {\n  :session_key => \"_test_session\",\n  :secret => \"some secret phrase for the tests.\"\n}\n\n# Skip protect_from_forgery in requests http://m.onkey.org/2007/9/28/csrf-protection-for-your-existing-rails-application\nconfig.action_controller.allow_forgery_protection  = false\n"
  },
  {
    "path": "config/exceptional.yml",
    "content": "# here are the settings that are common to all environments\ncommon: &default_settings\n  # You must specify your Exceptional API key here.\n  # api-key: 6e2a223d45e17bdeac6914c20665b26524ad6344\n  api-key: ac8e10d6f6c96ae1dee0d6e6999bcfd1c86bddd9\n  # Exceptional creates a separate log file from your application's logs\n  # available levels are debug, info, warn, error, fatal\n  log-level: info\n  # The exceptional agent sends data via regular http by default\n  # Setting this value to true will send data over SSL, increasing security\n  # There will be an additional CPU overhead in encrypting the data, however\n  # as long as your deployment environment is not Passenger (mod_rails), this\n  # happens in the background so as not to incur a page wait for your users.\n  ssl: false\n\ndevelopment:\n  <<: *default_settings\n  # Normally no reason to collect exceptions in development\n  # NOTE: for trial purposes you may want to enable exceptional in development\n  enabled: false\n\ntest:\n  <<: *default_settings\n  # No reason to collect exceptions when running tests by default\n  enabled: false\n\n\nproduction:\n  <<: *default_settings\n  enabled: true\n\nstaging:\n  # It's common development practice to have a staging environment that closely\n  # mirrors production, by default catch errors in this environment too.\n  <<: *default_settings\n  enabled: true\n\ncucumber:\n    <<: *default_settings\n    # No reason to collect exceptions when running cucmber tests by default\n    enabled: false\n\nselenium:\n    <<: *default_settings\n    # No reason to collect exceptions when running cucmber tests by default\n    enabled: false\n"
  },
  {
    "path": "config/initializers/10-patches.rb",
    "content": "\nrequire 'active_record'\n\nmodule ActiveRecord\n  class Base\n    include Redmine::I18n\n\n    # Translate attribute names for validation errors display\n    def self.human_attribute_name(attr)\n      l(\"field_#{attr.to_s.gsub(/_id$/, '')}\")\n    end\n  end\nend\n\nmodule ActiveRecord\n  class Errors\n    def full_messages(options = {})\n      full_messages = []\n\n      @errors.each_key do |attr|\n        @errors[attr].each do |message|\n          next unless message\n\n          if attr == \"base\"\n            full_messages << message\n          else\n            attr_name = @base.class.human_attribute_name(attr)\n            full_messages << attr_name + ' ' + message.to_s\n          end\n        end\n      end\n      full_messages\n    end\n  end\nend\n\nmodule ActionView\n  module Helpers\n    module DateHelper\n      # distance_of_time_in_words breaks when difference is greater than 30 years\n      def distance_of_date_in_words(from_date, to_date = 0, options = {})\n        from_date = from_date.to_date if from_date.respond_to?(:to_date)\n        to_date = to_date.to_date if to_date.respond_to?(:to_date)\n        distance_in_days = (to_date - from_date).abs\n\n        I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|\n          case distance_in_days\n            when 0..60     then locale.t :x_days,             :count => distance_in_days.round\n            when 61..720   then locale.t :about_x_months,     :count => (distance_in_days / 30).round\n            else                locale.t :over_x_years,       :count => (distance_in_days / 365).floor\n          end\n        end\n      end\n    end\n  end\nend\n\nActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| \"#{html_tag}\" }\n\n# Adds :async_smtp and :async_sendmail delivery methods\n# to perform email deliveries asynchronously\nmodule AsynchronousMailer\n  %w(smtp sendmail).each do |type|\n    define_method(\"perform_delivery_async_#{type}\") do |mail|\n      Thread.start do\n        send \"perform_delivery_#{type}\", mail\n      end\n    end\n  end\nend\n\nActionMailer::Base.send :include, AsynchronousMailer\n"
  },
  {
    "path": "config/initializers/20-mime_types.rb",
    "content": "# Add new mime types for use in respond_to blocks:\n\nMime::SET << Mime::CSV unless Mime::SET.include?(Mime::CSV)\nMime::Type.register 'application/pdf', :pdf\nMime::Type.register 'image/png', :png\n"
  },
  {
    "path": "config/initializers/30-redmine.rb",
    "content": "I18n.default_locale = 'en'\n\nrequire 'redmine'\n"
  },
  {
    "path": "config/initializers/40-email.rb",
    "content": "# Loads action_mailer settings from email.yml\n# and turns deliveries on if configuration file is found\n\nfilename = File.join(File.dirname(__FILE__), '..', 'email.yml')\nif File.file?(filename)\n  mailconfig = YAML::load_file(filename)\n\n  if mailconfig.is_a?(Hash) && mailconfig.has_key?(Rails.env)\n    # Enable deliveries\n    ActionMailer::Base.perform_deliveries = true\n\n    mailconfig[Rails.env].each do |k, v|\n      v.symbolize_keys! if v.respond_to?(:symbolize_keys!)\n      ActionMailer::Base.send(\"#{k}=\", v)\n    end\n  end\nend\n"
  },
  {
    "path": "config/initializers/activity_streams.rb",
    "content": "require 'activity_streams'\n\n\n#--\n# Copyright (c) 2008 Matson Systems, Inc.\n# Released under the BSD license found in the file\n# LICENSE included with this ActivityStreams plug-in.\n#++\n# ActivityStreams configuration/initilization\n\n# NOTE: The activites keys must be unique\nACTIVITY_STREAM_ACTIVITIES = {\n    :issues => 'Issues',\n    :news => 'News',\n    :documents => 'Documents',\n    :wikis => 'Wikis',\n    :messages => 'Discussion',\n    :workstreams => 'Workstreams',\n    :download => 'Download a torrent'\n    }\n\n# NOTE: These have hard coded meanings\nACTIVITY_STREAM_LOCATIONS = {\n    :public_location => 'Public Portion of of this site',\n    :logged_in_location => 'Logged In Portion of this site',\n    :feed_location => 'Your Activity Stream Atom Feed' }\n\nACTIVITY_STREAM_SERVICE_STRING=\"MyServiceName\"\nACTIVITY_STREAM_USER_MODEL='User'\nACTIVITY_STREAM_USER_MODEL_ID='user_id'\nACTIVITY_STREAM_USER_MODEL_NAME='name'\n"
  },
  {
    "path": "config/initializers/admin_data.rb",
    "content": "AdminData::Config.set = {\n  :is_allowed_to_view => lambda {|controller| controller.send('data_admin_logged_in?') },\n  :is_allowed_to_update => lambda {|controller| controller.send('data_admin_logged_in?') },\n}\n\n"
  },
  {
    "path": "config/initializers/aws_s3.rb",
    "content": "AWS::S3::Base.establish_connection!(\n  # :access_key_id     => ENV['s3_access_key_id'],\n  #    :secret_access_key => ENV['s3_secret_access_key']\n  #\n  :access_key_id     => 'AKIAI7GAIRZ5YAWMYD2A',\n  :secret_access_key => 'M6GZWxStw4tYpQbEE75ahYUm7sVUx587DAatl/JZ'\n)\n"
  },
  {
    "path": "config/initializers/backtrace_silencers.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.\n# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }\n\n# You can also remove all the silencers if you're trying do debug a problem that might steem from framework code.\n# Rails.backtrace_cleaner.remove_silencers!\n"
  },
  {
    "path": "config/initializers/bigdecimal-segfault-fix.rb",
    "content": "# Copyright (c) 2009 Michael Koziarski <michael@koziarski.com>\n#\n# Permission to use, copy, modify, and/or distribute this software for any\n# purpose with or without fee is hereby granted, provided that the above\n# copyright notice and this permission notice appear in all copies.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\nrequire 'bigdecimal'\n\nalias BigDecimalUnsafe BigDecimal\n\n\n# This fixes CVE-2009-1904 however it removes legitimate functionality that your\n# application may depend on.  You are *strongly* advised to upgrade your ruby\n# rather than relying on this fix for an extended period of time.\n\ndef BigDecimal(initial, digits=0)\n  if initial.size > 255 || initial =~ /e/i\n    raise \"Invalid big Decimal Value\"\n  end\n  BigDecimalUnsafe(initial, digits)\nend\n\n"
  },
  {
    "path": "config/initializers/hash.rb",
    "content": "class Hash\n  def +(hash2)\n    hash2.each do |key, value|\n      if self.has_key? key\n        self[key] += value\n      else\n        self[key] = value\n      end\n    end\n  end\n\n  def to_array_conditions\n    new_conditions = []\n    new_conditions[0] = self.map {|k,v| v.is_a?(Array) ? \"#{k} in (?)\" : \"#{k} = ?\"}.join(\" AND \")\n    self.values.each do |v|\n      v.is_a?(Array) ? new_conditions.push(v.flatten) : new_conditions.push(\"#{v}\")\n    end\n    new_conditions\n  end\nend\n"
  },
  {
    "path": "config/initializers/inflections.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# Add new inflection rules using the following format\n# (all these examples are active by default):\n# ActiveSupport::Inflector.inflections do |inflect|\n#   inflect.plural /^(ox)$/i, '\\1en'\n#   inflect.singular /^(ox)en/i, '\\1'\n#   inflect.irregular 'person', 'people'\n#   inflect.uncountable %w( fish sheep )\n# end\n"
  },
  {
    "path": "config/initializers/recurly_config.rb",
    "content": "require 'recurly'\n\nRecurly.configure do |c|\n  # c.username = 'recurly-api@bettermeans.com'\n  # c.password = 'd893b5c0b61142f9af4729bc6e831e7d'\n  # c.site = 'https://bettermeans-test.recurly.com'\n  c.username = ENV['RECURLY_USERNAME']\n  c.password = ENV['RECURLY_PASSWORD']\n  c.site = 'https://bettermeans.recurly.com'\nend\n"
  },
  {
    "path": "config/initializers/timeout.rb",
    "content": "Rack::Timeout.timeout = 30  # seconds\n"
  },
  {
    "path": "config/locales/en.yml",
    "content": "en:\n  date:\n    formats:\n      # Use the strftime parameters for formats.\n      # When no format has been given, it uses default.\n      # You can provide other formats here if you like!\n      default: \"%m/%d/%Y\"\n      short: \"%b %d\"\n      long: \"%B %d, %Y\"\n\n    day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]\n    abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]\n\n    # Don't forget the nil at the beginning; there's no such thing as a 0th month\n    month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]\n    abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]\n    # Used in date_select and datime_select.\n    order:\n      - :year\n      - :month\n      - :day\n\n  time:\n    formats:\n      default: \"%m/%d/%Y %I:%M %p\"\n      time: \"%I:%M %p\"\n      short: \"%d %b %H:%M\"\n      long: \"%B %d, %Y %H:%M\"\n    am: \"am\"\n    pm: \"pm\"\n\n  datetime:\n    distance_in_words:\n      half_a_minute: \"half a minute\"\n      less_than_x_seconds:\n        one:   \"less than 1 second\"\n        other: \"less than #{{count}} seconds\"\n      x_seconds:\n        one:   \"1 second\"\n        other: \"#{{count}} seconds\"\n      less_than_x_minutes:\n        one:   \"less than a minute\"\n        other: \"less than #{{count}} minutes\"\n      x_minutes:\n        one:   \"1 minute\"\n        other: \"#{{count}} minutes\"\n      about_x_hours:\n        one:   \"about 1 hour\"\n        other: \"about #{{count}} hours\"\n      x_days:\n        one:   \"1 day\"\n        other: \"#{{count}} days\"\n      about_x_months:\n        one:   \"about 1 month\"\n        other: \"about #{{count}} months\"\n      x_months:\n        one:   \"1 month\"\n        other: \"#{{count}} months\"\n      about_x_years:\n        one:   \"about 1 year\"\n        other: \"about #{{count}} years\"\n      over_x_years:\n        one:   \"over 1 year\"\n        other: \"over #{{count}} years\"\n\n  number:\n    human:\n      format:\n        delimiter: \"\"\n        precision: 1\n      storage_units:\n        format: \"%n %u\"\n        units:\n          byte:\n            one: \"Byte\"\n            other: \"Bytes\"\n          kb: \"KB\"\n          mb: \"MB\"\n          gb: \"GB\"\n          tb: \"TB\"\n\n\n# Used in array.to_sentence.\n  support:\n    array:\n      sentence_connector: \"and\"\n      skip_last_comma: false\n\n  activerecord:\n    errors:\n      messages:\n        inclusion: \"is not included in the list\"\n        exclusion: \"is reserved\"\n        invalid: \"is invalid\"\n        confirmation: \"doesn't match confirmation\"\n        accepted: \"must be accepted\"\n        empty: \"can't be empty\"\n        blank: \"can't be blank\"\n        too_long: \"is too long (maximum is #{{count}} characters)\"\n        too_short: \"is too short (minimum is #{{count}} characters)\"\n        wrong_length: \"is the wrong length (should be #{{count}} characters)\"\n        taken: \"has already been taken\"\n        not_a_number: \"is not a number\"\n        not_a_date: \"is not a valid date\"\n        greater_than: \"must be greater than #{{count}}\"\n        greater_than_or_equal_to: \"must be greater than or equal to #{{count}}\"\n        equal_to: \"must be equal to #{{count}}\"\n        less_than: \"must be less than #{{count}}\"\n        less_than_or_equal_to: \"must be less than or equal to #{{count}}\"\n        odd: \"must be odd\"\n        even: \"must be even\"\n        greater_than_start_date: \"must be greater than start date\"\n        not_same_project: \"doesn't belong to the same workstream\"\n        circular_dependency: \"This relation would create a circular dependency\"\n\n  actionview_instancetag_blank_option: Please select\n\n  general_text_No: 'No'\n  general_text_Yes: 'Yes'\n  general_text_no: 'no'\n  general_text_yes: 'yes'\n  general_lang_name: 'English'\n  general_csv_separator: ','\n  general_csv_decimal_separator: '.'\n  general_csv_encoding: ISO-8859-1\n  general_pdf_encoding: ISO-8859-1\n  general_first_day_of_week: '7'\n\n  notice_account_reactivated: Your account has been reactivated.<br> Welcome back!<br><br> <a href=\"/\">Home</a>\n  notice_account_canceled: Your account is now canceled. Thanks for trying us out.<br><br>We would love your feedback on how we can do better.<br><br><a href=\"mailto:feedback@bettermeans.com\">feedback@bettermeans.com</a>\n  notice_account_inactive_user: Account has not yet been activated. Please check your email for activation link\n  notice_account_updated: Account was successfully updated.\n  notice_account_invalid_creditentials: Invalid user or password\n  notice_account_password_updated: Password was successfully updated.\n  notice_account_wrong_password: Wrong password\n  notice_account_register_done: Account was successfully created. To activate your account, click on the link that was emailed to you.\n  notice_account_unknown_email: Unknown user.\n  notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password.\n  notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you.\n  notice_account_activated: Your account has been activated. You can now log in.\n  notice_successful_create: Successful creation.\n  notice_successful_update: Successful update.\n  notice_successful_delete: Successful deletion.\n  notice_successful_connection: Successful connection.\n  notice_file_not_found: The page you were trying to access doesn't exist or has been removed.\n  notice_locking_conflict: Data has been updated by another user.\n  notice_not_authorized: You are not authorized to access this page.\n  notice_email_sent: \"An email was sent to #{{value}}\"\n  notice_email_error: \"An error occurred while sending mail (#{{value}})\"\n  notice_feeds_access_key_reseted: Your RSS access key was reset.\n  notice_failed_to_save_issues: \"Failed to save #{{count}} item(s) on #{{total}} selected: #{{ids}}.\"\n  notice_no_issue_selected: \"No item is selected! Please, check the items you want to edit.\"\n  notice_account_pending: \"Your account was created and is now pending administrator approval.\"\n  notice_default_data_loaded: Default configuration successfully loaded.\n  notice_unable_delete_version: Unable to delete deliverable.\n  notice_issue_done_ratios_updated: Issue done ratios updated.\n  notice_this_is_your_profie: \"This is your public profile. To manage your account <a href='/my/account'>click here</a>\"\n\n  error_old_invite : \"Old or bad invitation\"\n  error_bad_email_update : \"Poorly formed email update\"\n  error_can_t_load_default_data: \"Default configuration could not be loaded: #{{value}}\"\n  error_issue_not_found_in_project: 'The item was not found or does not belong to this workstream'\n  error_no_tracker_in_project: 'No issue type is associated to this workstream. Please check the Workstream settings.'\n  error_no_default_issue_status: 'No default item status is defined. Please check your configuration (Go to \"Administration -> Item statuses\").'\n  error_can_not_reopen_issue_on_closed_version: 'An item assigned to a closed deliverable can not be reopened'\n  error_can_not_archive_project: This project can not be archived\n  error_issue_done_ratios_not_updated: \"Issue done ratios not updated.\"\n  error_workflow_copy_source: 'Please select a source tracker or role'\n  error_workflow_copy_target: 'Please select target tracker(s) and role(s)'\n  error_general: 'Something went wrong.'\n\n  warning_attachments_not_saved: \"#{{count}} file(s) could not be saved.\"\n\n  mail_subject_lost_password: \"Your #{{value}} password\"\n  mail_body_lost_password: 'To change your password, click on the following link:'\n  mail_subject_register: \"Your #{{value}} account activation\"\n  mail_body_register: 'To activate your account, click on the following link:'\n  mail_body_account_information_external: \"You can use your #{{value}} account to log in.\"\n  mail_body_account_information: Your account information\n  mail_subject_account_activation_request: \"#{{value}} account activation request\"\n  mail_subject_email_update_activation: \"#{{value}} new email activation\"\n  mail_body_account_activation_request: \"A new user (#{{value}}) has registered. The account is pending your approval:\"\n  mail_subject_reminder: \"#{{count}} item(s) due in the next days\"\n  mail_body_reminder: \"#{{count}} item(s) that are owned by you are due in the next #{{days}} days:\" #updated\n  mail_subject_wiki_content_added: \"'#{{page}}' wiki page has been added\"\n  mail_body_wiki_content_added: \"The '#{{page}}' wiki page has been added by #{{author}}.\"\n  mail_subject_wiki_content_updated: \"'#{{page}}' wiki page has been updated\"\n  mail_body_wiki_content_updated: \"The '#{{page}}' wiki page has been updated by #{{author}}.\"\n\n  gui_validation_error: 1 error\n  gui_validation_error_plural: \"#{{count}} errors\"\n\n  field_tags : \"Tags\"\n  field_points : \"Avg estimated credits\"\n  field_logo : \"Logo\"\n  field_image_file: \"Upload local file\"\n  field_image_file_url: \"or image URL\"\n  field_retro: Retrospective\n  field_volunteer: Volunteer\n  field_name: Name\n  field_description: Description\n  field_summary: Summary\n  field_is_required: Required\n  field_firstname: Firstname\n  field_lastname: Lastname\n  field_mail: Email\n  field_filename: File\n  field_filesize: Size\n  field_downloads: Downloads\n  field_author: Author\n  field_created_at: Created\n  field_updated_at: Updated\n  field_field_format: Format\n  field_is_for_all: For all workstreams\n  field_possible_values: Possible values\n  field_regexp: Regular expression\n  field_min_length: Minimum length\n  field_max_length: Maximum length\n  field_value: Value\n  field_category: Category\n  field_title: Title\n  field_project: Workstream\n  field_item: Item\n  field_status: Status\n  field_notes: Notes\n  field_is_closed: Item closed\n  field_is_default: Default value\n  field_tracker: Type\n  field_subject: Subject\n  field_due_date: Due by\n  field_expected_date: Expected by\n  field_assigned_to: Owner #Changed\n  field_priority: Priority\n  field_fixed_version: Deliverable\n  field_user: User\n  field_role: Role\n  field_homepage: Homepage\n  field_is_public: Public\n  field_parent: Sub workstream of\n  field_is_in_roadmap: Items displayed in roadmap\n  field_login: Username\n  field_mail_notification: Email Notifications\n  field_admin: Administrator\n  field_last_login_on: Last connection\n  field_language: Language\n  field_effective_date: Date\n  field_password: Password\n  field_new_password: New password\n  field_password_confirmation: Retype Password\n  field_version: Deliverable\n  field_type: Type\n  field_host: Host\n  field_port: Port\n  field_account: Account\n  field_base_dn: Base DN\n  field_attr_login: Login attribute\n  field_attr_firstname: Firstname attribute\n  field_attr_lastname: Lastname attribute\n  field_attr_mail: Email attribute\n  field_onthefly: On-the-fly user creation\n  field_start_date: Start Date\n  field_done_ratio: \"% Done\"\n  field_auth_source: Authentication mode\n  field_hide_mail: Hide my email address\n  field_active_only_jumps: \"Show only workstreams I'm active in for top jump menu\"\n  field_comments: Comment\n  field_wiki_comments: Revision notes\n  field_url: URL\n  field_start_page: Home page\n  field_subproject: Sub workstream\n  field_hours: Hours\n  field_activity: Activity\n  field_spent_on: Date\n  field_identifier: Identifier\n  field_is_filter: Used as a filter\n  field_issue_to: Related item\n  field_issue: Related Item\n  field_delay: Delay\n  field_assignable: Items can be owned by this role\n  field_redirect_existing_links: Redirect existing links\n  field_estimated_hours: Estimated time\n  field_column_names: Columns\n  field_time_zone: Time zone\n  field_searchable: Searchable\n  field_default_value: Default value\n  field_comments_sorting: Display comments\n  field_parent_title: Parent page\n  field_parent_project: Parent workstream\n  field_editable: Editable\n  field_watcher: Watcher\n  field_identity_url: OpenID URL\n  field_content: Content\n  field_group_by: Group results by\n  field_sharing: Sharing\n  field_dpp: Estimation Scale\n  field_hourly_rate_per_person: Hourly rate per person\n  field_hourly_cap: Hourly cap\n  field_pri: Pri\n\n  setting_app_title: Application title\n  setting_app_subtitle: Application subtitle\n  setting_welcome_text: Welcome text\n  setting_default_language: Default language\n  setting_login_required: Authentication required\n  setting_self_registration: Self-registration\n  setting_attachment_max_size: Attachment max. size\n  setting_issues_export_limit: Items export limit\n  setting_mail_from: Emission email address\n  setting_bcc_recipients: Blind carbon copy recipients (bcc)\n  setting_plain_text_mail: Plain text mail (no HTML)\n  setting_host_name: Host name and path\n  setting_text_formatting: Text formatting\n  setting_wiki_compression: Wiki history compression\n  setting_feeds_limit: Feed content limit\n  setting_default_projects_public: New workstreams are public by default\n  setting_autofetch_changesets: Autofetch commits\n  setting_commit_ref_keywords: Referencing keywords\n  setting_commit_fix_keywords: Fixing keywords\n  setting_autologin: Autologin\n  setting_date_format: Date format\n  setting_time_format: Time format\n  setting_cross_project_issue_relations: Allow cross-workstream item relations\n  setting_issue_list_default_columns: Default columns displayed on the item list\n  setting_commit_logs_encoding: Commit messages encoding\n  setting_emails_footer: Emails footer\n  setting_protocol: Protocol\n  setting_per_page_options: Objects per page options\n  setting_user_format: Users display format\n  setting_activity_days_default: Days displayed on workstream activity\n  setting_display_subprojects_issues: Display sub workstreams items on main workstreams by default\n  setting_enabled_scm: Enabled SCM\n  setting_mail_handler_body_delimiters: \"Truncate emails after one of these lines\"\n  setting_mail_handler_api_enabled: Enable WS for incoming emails\n  setting_mail_handler_api_key: API key\n  setting_sequential_project_identifiers: Generate sequential workstream identifiers\n  setting_gravatar_enabled: Use Gravatar user icons\n  setting_gravatar_default: Default Gravatar image\n  setting_diff_max_lines_displayed: Max number of diff lines displayed\n  setting_file_max_size_displayed: Max size of text files displayed inline\n  setting_openid: Allow OpenID login and registration\n  setting_password_min_length: Minimum password length\n  setting_new_project_user_role_id: Role given to a non-admin user who creates a workstream\n  setting_default_projects_modules: Default enabled modules for new workstreams\n  setting_issue_done_ratio: Calculate the item done ratio with\n  setting_issue_done_ratio_issue_field: Use the item field\n  setting_issue_done_ratio_issue_status: Use the item status\n  setting_start_of_week: Start calendars on\n  setting_rest_api_enabled: Enable REST web service\n\n  permission_view_project : View workstream\n  permission_add_project: Create workstream\n  permission_add_subprojects: Create sub workstream\n  permission_edit_project: Edit workstream\n  permission_move_project: Move workstream\n  permission_select_project_modules: Select workstream modules\n  permission_manage_members: Manage members\n  permission_manage_versions: Manage deliverables\n  permission_manage_categories: Manage item categories\n  permission_add_issues: Add items\n  permission_edit_issues: Edit items\n  permission_manage_issue_relations: Manage item relations\n  permission_add_issue_notes: Add notes\n  permission_edit_issue_notes: Edit notes\n  permission_edit_own_issue_notes: Edit own notes\n  permission_move_issues: Move items\n  permission_delete_issues: Delete items\n  permission_manage_public_queries: Manage public queries\n  permission_save_queries: Save queries\n  permission_view_gantt: View gantt chart\n  permission_view_calendar: View calendar\n  permission_view_issue_watchers: View watchers list\n  permission_add_issue_watchers: Add watchers\n  permission_delete_issue_watchers: Delete watchers\n  permission_log_time: Log spent time\n  permission_view_time_entries: View spent time\n  permission_edit_time_entries: Edit time logs\n  permission_edit_own_time_entries: Edit own time logs\n  permission_manage_news: Manage news\n  permission_comment_news: Comment news\n  permission_manage_documents: Manage documents\n  permission_view_documents: View documents\n  permission_manage_files: Manage files\n  permission_view_files: View files\n  permission_manage_wiki: Manage wiki\n  permission_rename_wiki_pages: Rename wiki pages\n  permission_delete_wiki_pages: Delete wiki pages\n  permission_view_wiki_pages: View wiki\n  permission_view_wiki_edits: View wiki history\n  permission_edit_wiki_pages: Edit wiki pages\n  permission_delete_wiki_pages_attachments: Delete attachments\n  permission_protect_wiki_pages: Protect wiki pages\n  permission_view_changesets: View changesets\n  permission_commit_access: Commit access\n  permission_manage_boards: Manage discussions\n  permission_view_messages: View messages\n  permission_add_messages: Post messages\n  permission_edit_messages: Edit messages\n  permission_edit_own_messages: Edit own messages\n  permission_delete_messages: Delete messages\n  permission_delete_own_messages: Delete own messages\n\n  project_module_issue_tracking: Item tracking\n  project_module_time_tracking: Time tracking\n  project_module_news: News\n  project_module_documents: Documents\n  project_module_files: Files\n  project_module_wiki: Wiki\n  project_module_boards: Discussions\n\n  title_member_nomination : \"Motion to elect #{{user}} as a member\"\n  title_core_member_nomination : \"Motion to elect #{{user}} to the Core Team\"\n  title_core_member_removal : \"Motion to remove #{{user}} from the Core Team\"\n  title_member_removal : \"Motion to remove #{{user}} as a member\"\n\n  label_usage_over : \"Your usage is over your plan's limits\"\n  label_trial_expired : \"Your trial period has expired\"\n  label_email_update: Your new email address\n  label_new_page: New page\n  label_my_issues: My items\n  label_joined_issues: Joined\n  label_joined: Joined\n  label_projects_recent: Recent workstreams\n  label_projects_active_in: Workstreams I'm active in\n  label_projects_all : All my workstreams\n  label_view_all : View all\n  label_track_invites: Track sent invites\n  label_unarchive_project: Un-archive workstream\n  label_unarchive_project_brackets: (unarchive)\n  label_archive_project: Archive workstream\n  label_delete_project: Delete workstream\n  label_move_project: Move workstream\n  label_note_to_recipient: Note for recipient (optional)\n  label_amount_to_transfer: Amount to Transfer\n  label_select_recipient: Select Recipient\n  label_credit_transfers: Credit Transfers\n  label_credit_transfer: \"Transfer credits\"\n  label_new_credit_transfer: New Transfer\n  label_select_project: Select Project Workstream\n  label_previous_credit_transfers: Your History\n  label_data_dump: Data Dump\n  text_data_dump: Download a local copy of all issues that belong to workstreams that you own\n  label_issues: datadump.csv\n  label_type_of_workstream: Workstream Options\n  label_your_gravatar: Profile Picture\n  label_team_with_access: Members with clearance (to this workstream)\n  label_select_plan: Select New Plan\n  label_current_plan: Current Plan\n  label_user: User\n  label_user_plural: Users\n  label_user_new: New user\n  label_user_anonymous: Anonymous\n  label_project: Workstream\n  label_project_new: New workstream\n  label_project_plural: Workstreams\n  label_x_projects:\n    zero:  no workstreams\n    one:   1 workstream\n    other: \"#{{count}} workstreams\"\n  label_project_all: All Workstreams\n  label_project_latest: Latest Workstreams\n  label_enterprise_latest: Latest Public Workstreams\n  label_enterprise_active: Most Active Public Workstreams\n  label_enterprise_plural: Open enterprises\n  label_issue: Item\n  label_issue_new: New item\n  label_issue_plural: Items\n  label_issue_view_all: View all items\n  label_issues_by: \"Items by #{{value}}\"\n  label_issue_added: Item added\n  label_issue_updated: Item updated\n  label_document: Document\n  label_document_new: New document\n  label_document_plural: Docs\n  label_document_added: Document added\n  label_quick_links: Quick links\n  label_role: Role\n  label_role_plural: Roles\n  label_role_new: New role\n  label_role_and_permissions: Roles and permissions\n  label_member: Member\n  label_member_new: New member\n  label_member_plural: Members\n  label_team : Team\n  label_team_plural : Teams\n  label_active_team : Active people\n  label_dashboard : Dashboard\n  label_tracker: Type\n  label_tracker_plural: Types\n  label_tracker_new: New type\n  label_workflow: Workflow\n  label_issue_status: Item status\n  label_issue_status_plural: Item statuses\n  label_issue_status_new: New status\n  label_enumerations: Enumerations\n  label_enumeration_new: New value\n  label_information: Information\n  label_information_plural: Information\n  label_personal_information: Personal Info\n  label_billing_information: Billing Info\n  label_please_login: Please log in\n  label_register: Sign up\n  label_login_with_open_id_option: or login with OpenID\n  label_password_lost: Lost password\n  label_home: Home\n  label_my_home: My Home\n  label_my_page: Summary\n  label_new_project: New Workstream\n  label_my_account: Account\n  label_my_projects: My workstreams\n  label_projects_i_belong_to: Workstreams I belong to\n  label_projects_i_started: Workstreams I started\n  label_activities_i_belong_to: Recent activity\n  label_administration: Administration\n  label_login: Sign in\n  label_logout: Sign out\n  label_help: Help\n  label_reported_issues: Reported items\n  label_assigned_to_me_issues: Committed\n  label_added_issues: Created\n  label_recent_issues: Recent\n  label_assigned: Own\n  label_last_login: Last connection\n  label_registered_on: Signed up on\n  label_activity: Activity\n  label_overall_activity: Overall activity\n  label_user_activity: \"#{{value}}'s activity\"\n  label_new: New\n  label_logged_as: Logged in as\n  label_environment: Environment\n  label_authentication: Authentication\n  label_auth_source: Authentication mode\n  label_auth_source_new: New authentication mode\n  label_auth_source_plural: Authentication modes\n  label_subproject : Sub workstream\n  label_subproject_plural: Sub workstreams\n  label_subproject_new: New sub workstream\n  label_new_item_in: New item in\n  label_and_its_subprojects: \"#{{value}} and its sub workstreams\"\n  label_waiting_for_you: \"#{{notifications}} waiting for you\"\n  label_min_max_length: Min - Max length\n  label_list: List\n  label_date: Date\n  label_integer: Integer\n  label_float: Float\n  label_boolean: Boolean\n  label_string: Text\n  label_text: Long text\n  label_attribute: Attribute\n  label_attribute_plural: Attributes\n  label_download: \"#{{count}} Download\"\n  label_download_plural: \"#{{count}} Downloads\"\n  label_no_data: Nothing here yet\n  label_no_credits: You have no credits to transfer\n  label_change_status: Change status\n  label_history: History\n  label_attachment: File\n  label_attachment_new: New file\n  label_attachment_delete: Delete file\n  label_attachment_plural: Files\n  label_file_added: File added\n  label_report: Report\n  label_report_plural: Reports\n  label_news: News\n  label_news_new: Add news\n  label_news_plural: News\n  label_news_latest: Latest news\n  label_news_view_all: View all news\n  label_activity_latest: Latest activity\n  label_activity_view_all: View all activity\n  label_news_added: News added\n  label_settings: Settings\n  label_overview: Overview\n  label_version: Deliverable\n  label_version_new: New deliverable\n  label_version_plural: Deliverables\n  label_confirmation: Confirmation\n  label_export_to: 'Also available in:'\n  label_read: Read...\n  label_public_projects: Public workstreams\n  label_open_issues: open\n  label_open_issues_plural: open\n  label_closed_issues: closed\n  label_closed_issues_plural: closed\n  label_x_open_issues_abbr_on_total:\n    zero:  0 open / #{{total}}\n    one:   1 open / #{{total}}\n    other: \"#{{count}} open / #{{total}}\"\n  label_x_open_issues_abbr:\n    zero:  0 open\n    one:   1 open\n    other: \"#{{count}} open\"\n  label_x_closed_issues_abbr:\n    zero:  0 closed\n    one:   1 closed\n    other: \"#{{count}} closed\"\n  label_total: Total\n  label_permissions: Permissions\n  label_current_status: Current status\n  label_new_statuses_allowed: New statuses allowed\n  label_all: all\n  label_none: none\n  label_nobody: nobody\n  label_next: Next\n  label_previous: Previous\n  label_used_by: Used by\n  label_details: Details\n  label_add_note: Add a note\n  label_per_page: Per page\n  label_calendar: Calendar\n  label_months_from: months from\n  label_gantt: Gantt\n  label_internal: Internal\n  label_last_changes: \"last #{{count}} changes\"\n  label_change_view_all: View all changes\n  label_personalize_page: Personalize this page\n  label_comment: Comment\n  label_comment_plural: Comments\n  label_x_comments:\n    zero: no comments\n    one: 1 comment\n    other: \"#{{count}} comments\"\n  label_comment_add: Add a comment\n  label_comment_added: Comment added\n  label_comment_delete: Delete comments\n  label_query: Custom query\n  label_query_plural: Custom queries\n  label_query_new: New query\n  label_filter_add: Add filter\n  label_filter_plural: Filters\n  label_equals: is\n  label_not_equals: is not\n  label_in_less_than: in less than\n  label_in_more_than: in more than\n  label_greater_or_equal: '>='\n  label_less_or_equal: '<='\n  label_in: in\n  label_today: today\n  label_Today: Today\n  label_same_day: Same day\n  label_all_time: all time\n  label_yesterday: yesterday\n  label_this_week: this week\n  label_last_week: last week\n  label_last_n_days: \"last #{{count}} days\"\n  label_this_month: this month\n  label_last_month: last month\n  label_this_year: this year\n  label_date_range: Date range\n  label_less_than_ago: less than days ago\n  label_more_than_ago: more than days ago\n  label_ago: days ago\n  label_ago_simple: ago\n  label_contains: contains\n  label_not_contains: doesn't contain\n  label_day: day\n  label_day_plural: days\n  label_browse: Browse\n  label_browse_workstreams: Browse bettermeans\n  label_browse_activity: Browse activity\n  label_modification: \"#{{count}} change\"\n  label_modification_plural: \"#{{count}} changes\"\n  label_branch: Branch\n  label_tag: Tag\n  label_revision: Revision\n  label_revision_plural: Revisions\n  label_revision_id: \"Revision #{{value}}\"\n  label_associated_revisions: Associated revisions\n  label_added: added\n  label_modified: modified\n  label_copied: copied\n  label_renamed: renamed\n  label_deleted: deleted\n  label_moved: moved\n  label_archived: archived\n  label_unarchived: un-archived\n  label_project_description: Description\n  label_message: Discussion\n  label_latest_revision: Latest revision\n  label_latest_revision_plural: Latest revisions\n  label_view_revisions: View revisions\n  label_view_all_revisions: View all revisions\n  label_max_size: Maximum size\n  label_sort_highest: Move to top\n  label_sort_higher: Move up\n  label_sort_lower: Move down\n  label_sort_lowest: Move to bottom\n  label_roadmap: Roadmap\n  label_roadmap_due_in: \"Due in #{{value}}\"\n  label_roadmap_overdue: \"#{{value}} late\"\n  label_roadmap_no_issues: No items for this deliverable\n  label_search: Search\n  label_result_plural: Results\n  label_all_words: All words\n  label_wiki: Wiki\n  label_wiki_edit: Wiki edit\n  label_wiki_edit_plural: Wiki edits\n  label_wikipage: Wiki page\n  label_wiki_page: Wiki page\n  label_wiki_page_plural: Wiki pages\n  label_index_by_title: Index by title\n  label_index_by_date: Index by date\n  label_current_version: Current deliverable\n  label_preview: Preview\n  label_feed_plural: Feeds\n  label_changes_details: Details of all changes\n  label_issue_tracking: Work Breakdown\n  label_boards: Discussion\n  label_spent_time: Spent time\n  label_f_hour: \"#{{value}} hour\"\n  label_f_hour_plural: \"#{{value}} hours\"\n  label_time_tracking: Time tracking\n  label_change_plural: Changes\n  label_change : Change\n  label_statistics: Statistics\n  label_commits_per_month: Commits per month\n  label_commits_per_author: Commits per author\n  label_view_diff: View differences\n  label_diff_inline: inline\n  label_diff_side_by_side: side by side\n  label_options: Options\n  label_copy_workflow_from: Copy workflow from\n  label_permissions_report: Permissions report\n  label_watched_issues: Watched\n  label_watched: Watched\n  label_related_issues: Related items\n  label_applied_status: Applied status\n  label_loading: Working...\n  label_relation_new: New relation\n  label_relation_delete: Delete relation\n  label_relates_to: related to\n  label_duplicates: duplicates\n  label_duplicated_by: duplicated by\n  label_blocks: blocks\n  label_blocked_by: blocked by\n  label_precedes: precedes\n  label_follows: follows\n  label_end_to_start: end to start\n  label_end_to_end: end to end\n  label_start_to_start: start to start\n  label_start_to_end: start to end\n  label_stay_logged_in: Stay logged in\n  label_disabled: disabled\n  label_show_completed_versions: Show completed deliverables\n  label_me: me\n  label_board: Discussion\n  label_board_new: New discussion\n  label_board_plural: Discussions\n  label_topic_plural: Topics\n  label_message_plural: Messages\n  label_message_last: Last message\n  label_message_new: New message\n  label_topic_new: New topic\n  label_message_posted: Message added\n  label_reply_plural: Replies\n  label_comments_plural: Comments\n  label_send_information: Send account information to the user\n  label_year: Year\n  label_month: Month\n  label_week: Week\n  label_date_from: From\n  label_date_to: To\n  label_language_based: Based on user's language\n  label_sort_by: \"Sort by #{{value}}\"\n  label_send_test_email: Send a test email\n  label_feeds_access_key: RSS access key\n  label_missing_feeds_access_key: Missing a RSS access key\n  label_feeds_access_key_created_at: \"RSS access key created #{{value}} ago\"\n  label_module_plural: Modules\n  label_added_time_by: \"Added by #{{author}} #{{age}} ago\"\n  label_updated_time_by: \"Updated by #{{author}} #{{age}} ago\"\n  label_created_time_by: \"Created #{{age}} ago by\"\n  label_updated_time: \"Updated #{{value}} ago\"\n  label_jump_to_a_project: MY WORKSTREAMS\n  label_file_plural: Files\n  label_changeset_plural: Changesets\n  label_default_columns: Default columns\n  label_no_change_option: (No change)\n  label_bulk_edit_selected_issues: Bulk edit selected items\n  label_theme: Theme\n  label_default: Default\n  label_search_titles_only: Titles only\n  label_user_mail_option_all: \"For any event on all my workstreams\"\n  label_user_mail_option_selected: \"For any event on the selected workstreams only...\"\n  label_user_mail_option_none: \"Only for things I watch or I'm involved in\"\n  label_user_mail_no_self_notified: \"I don't want to be notified of changes that I make myself\"\n  label_user_mail_no_emails: \"Disable email notification\"\n  label_user_mail_daily_digest: \"Send me a daily summary of system updates to issues I'm involved in\"\n  label_registration_activation_by_email: account activation by email\n  label_registration_manual_activation: manual account activation\n  label_registration_automatic_activation: automatic account activation\n  label_display_per_page: \"Per page: #{{value}}\"\n  label_age: Age\n  label_change_properties: Change properties\n  label_general: General\n  label_more: More\n  label_scm: SCM\n  label_plugins: Plugins\n  label_ldap_authentication: LDAP authentication\n  label_downloads_abbr: D/L\n  label_optional_description: Optional description\n  label_add_another_file: Add another file\n  label_preferences: Preferences\n  label_chronological_order: In chronological order\n  label_reverse_chronological_order: In reverse chronological order\n  label_planning: Planning\n  label_incoming_emails: Incoming emails\n  label_generate_key: Generate a key\n  label_issue_watchers: Watchers\n  label_example: Example\n  label_display: Display\n  label_sort: Sort\n  label_ascending: Ascending\n  label_descending: Descending\n  label_date_from_to: From #{{start}} to #{{end}}\n  label_wiki_content_added: Wiki page added\n  label_wiki_content_updated: Wiki page updated\n  label_group: Group\n  label_group_plural: Groups\n  label_group_new: New group\n  label_time_entry_plural: Spent time\n  label_commit_request_history: Ownership History #new\n  label_by: \"by #{{author}} #{{age}} ago\" #new\n  label_requested_by: \"Requested by #{{author}} #{{age}} ago\" #new\n  label_offered_by: \"Offered by #{{author}} to #{{responder}} #{{age}} ago\" #new\n  label_accepted_by: \"Accepted by #{{responder}} #{{age}} ago\" #new\n  label_declined_by: \"Declined by #{{responder}} #{{age}} ago\" #new\n  label_from_ago: \"from #{{author}} #{{age}} ago\" #new\n  label_taken_by: \"Taken by #{{responder}} #{{age}} ago\" #news\n  label_declined: \"Declined #{{age}} ago\" #new\n  label_accepted: \"Accepted #{{age}} ago\" #new\n  label_recinded: \"Withdrawn #{{age}} ago\" #new\n  label_released: \"Released #{{age}} ago\" #new\n  label_not_sure: \"Not sure\"\n  label_commitment: \"Commitment\"\n  label_commitment_offer: \"Ownership Offer\"\n  label_commitment_request: \"Ownership Request\"\n  label_notification : \"Notification\"\n  label_notifications : \"Notifications\"\n  label_new_notification : \"notification\"\n  label_new_notifications : \"notifications\"\n  label_response_sent : \"Response sent\"\n  label_response_ignored : \"Request ignored\"\n  label_you : \"you\"\n  label_for : \"for\"\n  label_from : \"from\"\n  label_ignored : \"Ignored\"\n  label_marked_as_read : \"Marked as read\"\n  label_ownership_offered : \"Ownership offered\"\n  label_ownership_offered_to : \"Ownership offered to #{{user}}\"\n  label_ownership_offer_declined : \"Ownership offer declined\"\n  label_ownership_offer_accepted : \"Ownership offer accepted\"\n  label_ownership_offer_declined_from : \"#{{user}}'s ownership offer was declined\"\n  label_ownership_offer_accepted_from : \"#{{user}}'s ownership offer was accepted\"\n  label_ownership_offer_withdrawn : \"Ownership offer withdrawn\"\n  label_ownership_offer_withdrawn_to : \"Ownership offer to #{{user}} was withdrawn\"\n  label_ownership_requested : \"Ownership requested\"\n  label_ownership_request_accepted : \"Ownership request accepted\"\n  label_ownership_request_auto_accepted : \"Ownership request auto accepted\"\n  label_ownership_request_declined : \"Ownership request declined\"\n  label_ownership_request_accepted_from : \"#{{user}}'s ownership request accepted\"\n  label_ownership_request_declined_from : \"#{{user}}'s ownership request declined\"\n  label_ownership_request_recinded : \"Ownership request recinded\"\n  label_ownership_released : \"Ownership released\"\n  label_ownership_taken : \"Ownership taken\"\n  label_commit_request_plural : \"Task ownership\"\n  label_team_offer : \"Core Team Invitation\"\n  label_team_offer_plural : \"Team members\"\n  label_team_plural : \"Team\"\n  label_team_invitation : \"Core Team Invitation\"\n  label_team_request : \"Core Team Request\"\n  label_team_request_plural : \"Core Team requests\"\n  label_accepted : \"accepted\"\n  label_sent : \"sent\"\n  label_withdrawn : \"withdrawn\"\n  label_declined : \"declined\"\n  label_to_join_core_team_of : \"to join the #{{project}} core team\"\n  label_request : \"Request\"\n  label_invitation : \"Invitation\"\n  label_was : \"was\"\n  label_your : 'Your'\n  label_to : \"to\"\n  label_note_from : \"Note from #{{author}}\"\n  label_sending_team_invitation : \"#{{author}} wants you to join the Core Team for the #{{project}} workstream\"\n  label_sending_team_request : \"#{{author}} wants to join the Core Team for the #{{project}} workstream\"\n  label_team_view_all : \"View team details\"\n  label_team_view_all_enterprise : \"View entire team\"\n  label_member_role_plural : \"Team Changes\"\n  label_join_core_team : \"Join Core Team\"\n  label_leave_core_team : \"Leave Core Team\"\n  label_request_to_join_core_team : \"Request to join Core Team\"\n  label_invitation_to_join_core_team : \"Invite to Core Team\"\n  label_team_points : \"Core Points\"\n  label_share : \"Share\"\n  label_share_plural : \"Shares\"\n  label_credit_plural : \"Credits\"\n  label_credit : \"Credit\"\n  label_retro_started : \"Retrospective Started\"\n  label_retro_ended : \"Retrospective Ended\"\n  label_motion_started : \"New motion: #{{title}}\"\n  label_credits : Credits\n  label_shares : Shares\n  label_credit_queue : Credit Queue (Active Credits)\n  label_credit_history : Credit History (All Credits)\n  label_my_credits : My Credits\n  label_credits_breakdown : Credit Breakdown\n  label_active_credits : Active Credits\n  label_outstanding_credits : Oustanding Credits\n  label_total_credits_issued : Total Issued\n  label_youve_got_credits : \"You've got credits!\"\n  label_someone_joined_your_issue : \"#{{joiner}} joined an issue assigned to you\"\n  label_someone_added_you_to_their_issue : \"#{{sender}} added you to an issue they own\"\n  label_someone_removed_you_from_their_issue : \"#{{sender}} removed you from an issue they own\"\n  label_someone_left_your_issue : \"#{{joiner}} left an issue assigned to you\"\n  label_someone_mentioned_you : \"#{{mentioner}} mentioned you\"\n  label_agree : \"Agree\"\n  label_disagree : \"Disagree\"\n  label_block : \"Block\"\n  label_neutral : \"Neutral\"\n  label_history : \"History\"\n  label_select : \"Select\"\n  label_no_mention : \"No unread mentions\"\n  label_mentions : \"Mentions\"\n\n  label_version_sharing_none: Not shared\n  label_version_sharing_descendants: With workstreams\n  label_version_sharing_hierarchy: With workstream hierarchy\n  label_version_sharing_tree: With workstream tree\n  label_version_sharing_system: With all workstreams\n  label_update_issue_done_ratios: Update item done ratios\n  label_copy_source: Source\n  label_copy_target: Target\n  label_copy_same_as_target: Same as target\n  label_display_used_statuses_only: Only display statuses that are used by this tracker\n  label_api_access_key: API access key\n  label_missing_api_access_key: Missing an API access key\n  label_api_access_key_created_at: \"API access key created #{{value}} ago\"\n  label_dpp_scale: \"Estimation Scale\"\n\n  label_motion: \"Motion\"\n  label_motions_new: New motion\n\n\n  label_motion_state0: \"In Progress\"\n  label_motion_state1: \"Passed\"\n  label_motion_state2: \"Defeated\"\n  label_motion_state3: \"Cancelled\"\n\n  label_motion_vote_type1 : \"Unanimous Consensus\"\n  label_motion_vote_type2 : \"Lazy Majority\"\n  label_motion_vote_type3 : \"Share Majority\"\n\n  label_motion_vote_type1_desc : \"no blocks or disagrees\"\n  label_motion_vote_type2_desc : \"more agrees than disagree, no blocks\"\n  label_motion_vote_type3_desc : \"1 share = 1 vote. minimum 2/3 agree\"\n\n  label_motion_vote_action1 : \"Block\"\n  label_motion_vote_action9999 : \"Disagree\"\n  label_motion_vote_action10000 : \"Neutral\"\n  label_motion_vote_action10001 : \"Agree\"\n  label_motion_vote_action_share_agree : \"Agree with #{{points}} shares\"\n  label_motion_vote_action_share_disagree : \"Disagree with #{{points}} shares\"\n  label_motion_vote_action_share_neutral : \"Neutral with #{{points}} shares\"\n  label_you_voted : \"You voted: <b>#{{action}}</b>\"\n  label_voted : \"voted\"\n  label_you_havent_voted : \"You haven't cast your vote yet\"\n  label_tally : \"Tally\"\n\n  label_motion_variation0 : \"General Motion\"\n  label_motion_variation1 : \"Extraordinary Motion\"\n  label_motion_variation2 : \"New Member Nomination\"\n  label_motion_variation3 : \"New Core Team Member Nomination\"\n  label_motion_variation4 : \"Motion to Remove Member\"\n  label_motion_variation5 : \"Motion to Remove Core Team Member\"\n  label_motion_variation6 : \"Board Motion (public)\"\n  label_motion_variation7 : \"Board Motion (private)\"\n  label_motion_variation8 : \"Motion to Add Hourly Activity Type\"\n\n  label_binding : \"Binding\"\n  label_non_binding : \"Non binding\"\n\n  label_agree_total : \"Agree Total\"\n  label_disagree_total : \"Disagree Total\"\n  label_hidden : \"(user hidden)\"\n\n  label_motions_active : \"Active Motions\"\n  label_motions_view_all : \"View all Motions\"\n  label_new_role : \"New role: #{{role_name}}\"\n  5label_new_invitation : \"Invitation to join #{{project_name}} as a #{{role_name}}\"\n\n  label_drop_from_core_team : \"Remove from Core\"\n  label_nominate_to_core_team : \"Nominate to Core\"\n  label_drop_from_member : \"Remove Membership\"\n  label_nominate_to_member : \"Nominate to Membership\"\n\n  label_reputation : \"Reputation Matrix\"\n  label_assessment_accuracy : \"Assessment Accuracy\"\n\n  label_hourly_type: \"Hourly type\"\n  label_hourly_type_plural: \"Hourly types\"\n  label_hourly_type_new: \"New hourly type\"\n  label_hourly_rate_per_person: \"Hourly rate per person\"\n  label_hourly_cap: \"Hourly cap\"\n\n  label_invitation_new: \"Invite people\"\n  label_invitation_others: \"Invite others\"\n\n  label_all_activity: \"Browse all activity\"\n\n  label_cancel_account: \"Cancel my account\"\n\n  field_b_first_name: \"First name\"\n  field_b_last_name: \"Last name\"\n  field_b_address1: \"Street Address\"\n  field_b_address2: \"Address (line 2)\"\n  field_b_city: \"City\"\n  field_b_state: \"State\"\n  field_b_zip: \"Zip/Postal Code\"\n  field_b_country: \"Country\"\n  field_b_phone: \"Phone\"\n  field_b_cc_type: \"Type\"\n  field_b_cc_month: \"Expiration Date\"\n  field_b_cc_year: \"\"\n  field_b_cc_last_four: \"Credit Card\"\n  label_b_expiration: \"Expiration Date\"\n  label_b_verification_code: \"Verification Code\"\n\n  label_memberrole: \"membership\"\n\n\n  button_upgrade : Upgrade\n  button_update_billing : Update Billing\n  button_accept_invitation : Accept Invitation\n  button_working : working...\n  button_change_plan: Change Plan\n  button_update_billing: Update billing\n  button_login: Login\n  button_submit: Submit\n  button_search: Search\n  button_save: Save\n  button_check_all: Check all\n  button_uncheck_all: Uncheck all\n  button_delete: Delete\n  button_create: Create\n  button_resend: Resend\n  button_create_and_continue: Create and continue\n  button_test: Test\n  button_edit: Edit\n  button_add: Add\n  button_add_team_member: + Add Someone\n  button_change: Change\n  button_apply: Apply\n  button_clear: Clear\n  button_lock: Lock\n  button_unlock: Unlock\n  button_download: Download\n  button_list: List\n  button_view: View\n  button_move: Move\n  button_move_and_follow: Move and follow\n  button_back: Back\n  button_cancel: Cancel\n  button_close: Close\n  button_activate: Activate\n  button_sort: Sort\n  button_log_time: Log time\n  button_rollback: Rollback to this deliverable\n  button_watch: Watch\n  button_unwatch: Unwatch\n  button_reply: Reply\n  button_reply: Comment\n  button_archive: Archive\n  button_unarchive: Unarchive\n  button_reset: Reset\n  button_rename: Rename\n  button_change_password: Change password\n  button_copy: Copy\n  button_copy_and_follow: Copy and follow\n  button_annotate: Annotate\n  button_update: Update\n  button_comment: Comment\n  button_signup: Sign up\n  button_configure: Configure\n  button_quote: Quote\n  button_participate: Participate\n  button_request_commitment_request: Request Ownership #new\n  button_request_commitment_take: Take Ownership #new\n  button_request_commitment_remove: Withdraw Ownership Request #new\n  button_request_commitment_withdraw: Withdraw #new\n  button_request_commitment_remove_offer: Withdraw Ownership Offer #new\n  button_request_commitment_giveup: Release Ownership #new\n  button_request_commitment_transfer: Transfer Ownership #new\n  button_request_commitment_accept: Accept #new\n  button_request_commitment_decline: Decline #new\n  button_request_commitment_offer: Offer Ownership #new\n\n  button_team_offer_request: Request to join Core Team #new\n  button_team_offer_take: Get on the Core Team #new\n  button_team_offer_withdraw_request: Withdraw Core Team request  #new\n  button_team_offer_withdraw_invitation: Withdraw Core Team invitation #new\n  button_team_offer_giveup: Resign from Core Team #new\n  button_team_offer_accept: Accept #new\n  button_team_offer_decline: Decline #new\n  button_team_offer_invite: Send invitation to join Core Team #new\n\n  button_ignore: Ignore\n  button_mark_as_read: Mark as read\n  button_duplicate: Duplicate\n  button_show: Show\n\n  button_activate: Activate\n  button_deactivate: Deactivate\n\n  button_dashboard: Dashboard\n\n  status_active: active\n  status_registered: registered\n  status_locked: locked\n\n  version_status_open: open\n  version_status_locked: locked\n  version_status_closed: closed\n\n  field_active: Active\n  field_body: Body\n  field_joined_by: Joined by\n  field_item_url: Permalink\n\n  text_invite_role_instruction: Invite people to this role\n  text_resend_invite_message: \"Add a personal comment to the invitation reminder\"\n  text_reset_link: \"Reset invitation code\"\n  text_personalize_invitations: \"Personalize your invitation\"\n  text_email_instruction: \"Enter up to 50 emails, one email per line\"\n  text_invite_others_to_contribute: \"Invite anyone to contribute to\"\n  text_invite_others_to_contribute_personal: \"OR - Send personalized, individual invitations\"\n  text_confirm_delete_project: \"Are you sure you want to delete this workstream? This action cannot be undone!\"\n  text_confirm_cancel_account: \"Are you sure you want to cancel your account? This action cannot be undone!\"\n  text_confirm_archive_project: \"Are you sure you want to archive this workstream? Nobody will be able to see it anymore. You can unarchive it in the future.\"\n  text_confirm_unarchive_project: \"Are you sure you want to unarchive this workstream?\"\n  text_included_note: note\n  text_failed_to_transfer: Failed to transfer credits.<br>\n  text_your_gravatar: We use <a href=\"http://gravatar.com\" target=\"blank\">Gravatar</a> to display your profile picture. <br>To add/update your picture <a href=\"http://gravatar.com\" target=\"blank\">create an account here</a> using the same email you used to signup for BetterMeans\n  text_select_mail_notifications: Select actions for which email notifications should be sent.\n  text_regexp_info: eg. ^[A-Z0-9]+$\n  text_min_max_length_info: 0 means no restriction\n  text_project_destroy_confirmation: Are you sure you want to delete this workstream and related data ?\n  text_subprojects_destroy_warning: \"Its sub workstream(s): #{{value}} will be also deleted.\"\n  text_workflow_edit: Select a role and a type to edit the workflow\n  text_are_you_sure: Are you sure ?\n  text_journal_changed: \"#{{label}} changed from #{{old}} to #{{new}}\"\n  text_journal_set_to: \"#{{label}} set to #{{value}}\"\n  text_journal_deleted: \"#{{label}} deleted (#{{old}})\"\n  text_journal_added: \"#{{label}} #{{value}} added\"\n  text_tip_task_begin_day: task beginning this day\n  text_tip_task_end_day: task ending this day\n  text_tip_task_begin_end_day: task beginning and ending this day\n  text_project_identifier_info: 'Only lower case letters (a-z), numbers and dashes are allowed.<br />Once saved, the identifier can not be changed.'\n  text_caracters_maximum: \"#{{count}} characters maximum.\"\n  text_caracters_minimum: \"Must be at least #{{count}} characters long.\"\n  text_length_between: \"Length between #{{min}} and #{{max}} characters.\"\n  text_tracker_no_workflow: No workflow defined for this type\n  text_unallowed_characters: Unallowed characters\n  text_comma_separated: Multiple values allowed (comma separated).\n  text_issues_ref_in_commit_messages: Referencing and fixing items in commit messages\n  text_issue_added: \"Item #{{id}} has been reported by #{{author}}.\"\n  text_issue_updated: \"Item #{{id}} has been updated by #{{author}}.\"\n  text_line_separated: Multiple values allowed (one line for each value).\n  text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content ?\n  text_user_mail_option: \"For unselected workstreams, you will only receive notifications about things you watch or you're involved in (eg. items you're the author or owner).\" #updated\n  text_no_configuration_data: \"Roles, types, item statuses and workflow have not been configured yet.\\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded.\"\n  text_load_default_configuration: Load the default configuration\n  text_status_changed_by_changeset: \"Applied in changeset #{{value}}.\"\n  text_issues_destroy_confirmation: 'Are you sure you want to delete the selected item(s) ?'\n  text_select_project_modules: 'Select modules to enable for this workstream:'\n  text_default_administrator_account_changed: Default administrator account changed\n  text_file_repository_writable: Attachments directory writable\n  text_plugin_assets_writable: Plugin assets directory writable\n  text_rmagick_available: RMagick available (optional)\n  text_destroy_time_entries_question: \"#{{hours}} hours were reported on the items you are about to delete. What do you want to do ?\"\n  text_destroy_time_entries: Delete reported hours\n  text_assign_time_entries_to_project: Assign reported hours to the workstream\n  text_reassign_time_entries: 'Reassign reported hours to this item:'\n  text_user_wrote: \"#{{value}} wrote:\"\n  text_enumeration_destroy_question: \"#{{count}} objects are assigned to this value.\"\n  text_enumeration_category_reassign_to: 'Reassign them to this value:'\n  text_email_delivery_not_configured: \"Email delivery is not configured, and notifications are disabled.\\nConfigure your SMTP server in config/email.yml and restart the application to enable them.\"\n  text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.'\n  text_wiki_page_destroy_question: \"This page has #{{descendants}} child page(s) and descendant(s). What do you want to do?\"\n  text_wiki_page_nullify_children: \"Keep child pages as root pages\"\n  text_wiki_page_destroy_children: \"Delete child pages and all their descendants\"\n  text_wiki_page_reassign_children: \"Reassign child pages to this parent page\"\n  text_create_dialogue_choose_days: \"How much time to you need to get this done <br />(from the time you own it)?\"\n  text_select_user_dialogue_choose_user: \"Choose someone to send this request to\"\n  text_you_are_the_new_owner_of : \"You are the new proud owner of\"\n  text_is_asking_ownership_for : \"is asking for ownership of a task you\"\n  text_is_offering_ownership_for : \"is offering you ownership of a task\"\n  text_ownership_request_declined : \"Ownership request declined\"\n  text_ownership_request_accepted : \"Ownership request accepted\"\n  text_your_ownsership_request_declined_for : \"You request for ownership has been declined for \"\n  text_ownership_offer_accepted : \"Ownership offer accepted\"\n  text_your_offer_was_accepted_for : \"Your offer was accepted for \"\n  text_ownership_offer_declined : \"Ownership offer declined\"\n  text_your_offer_was_declined_for : \"Your offer was declined for \"\n  text_loading_dashboard : \"Loading dashboard data...\"\n  text_loading_dashboard_error : \"Failed to load data... please check your internet connectivity and <a href='#' onclick='refresh_local_data();return false;'>refresh</a>\"\n  text_retro_started_for : \"A retrospective for the \"\n  text_retro_started : \" workstream has started. <br/>You have 3 days to give your team feedback on their contribution\"\n  text_retro_ended_for : \"A retrospective for the\"\n  text_retro_ended : \" workstream has ended. <br/>Click below to see your team's feedback, and your final contribution\"\n  text_credits_transferred: \"#{{sender}} just transferred #{{amount}} credits to you in #{{project}}\"\n  text_credits_distributed_for : \"You earned #{{amount}} credits for your work on <strong>#{{workstream}}</strong>. Congrats!\"\n  text_credits_are_a_gift : \"These credits were gifted to you by your peers for your contribution. They're not a part of any retrospective.\"\n  text_credits_are_an_expense : \"These credits are a reimbursment for an expense item. They're not a part of any retrospective.\"\n  text_joiner_is_now_working_with_you : \"#{{joiner}} is now working with you on<br/>#{{issue}}\"\n  text_joiner_is_no_longer_working_with_you : \"#{{joiner}} is no longer working with you on<br/>#{{issue}}\"\n  text_you_are_now_working_with_you : \"You are now part of the team working on<br/>#{{issue}}\"\n  text_you_are_no_longer_working_on : \"You are no longer part of the team working on<br/>#{{issue}}\"\n  text_history_hidden_until_you_vote : \"Voting history is hidden since you haven't cast your vote\"\n  text_tally_hidden_until_you_vote : \"Voting tally is hidden until you cast your vote\"\n  text_you_dont_have_shares_to_vote : \"You need to have shares to weigh in on this motion.\"\n  text_you_are_now_a_role : \"You are now a <b>#{{role_name}}</b> of\"\n  text_role_description_Administrator : \"As an Admin, you can bypass governance rules and directly add/remove members and workstreams.<br> Use this role sparingly as you are setting up your structures, <br>and then remove yourself from the admin role when you're ready to fully adopt the Open Enterprise governance model.\"\n  text_role_description_Contributor : \"As a contributor, you can now earn credits and own a stake in <b>#{{enterprise}}.</b><br>Your votes on all matters will be visible to everyone, and will be non-binding.\"\n  text_role_description_Member : \"As a member, all your votes are now binding. <br>In addition you can nominate contributors for membership,<br>and vote on Core Team elections.\"\n  text_role_description_Core Team : \"As a member of the Core Team you have binding votes in all matters,<br>including the selection of new members.<br>Congratulations!\"\n  text_role_description_Core_Team : \"As a member of the Core Team you have binding votes in all matters,<br>including the selection of new members.<br>Congratulations!\"\n  text_role_description_Board : \"As a board member,all your votes are binding.\"\n  text_member_nomination : \"#{{user}} is being nominated to be a member of #{{enterprise}}. As a member, all their votes would be binding. In addition they will be able to nominate contributors for membership, and vote on Core Team elections. The votes on this motion will not be visible to to #{{user}}, but they will be able to see the discussion.\"\n  text_core_member_nomination : \"#{{user}} is being nominated for the Core Team of #{{enterprise}}. As a member of the Core Team they would have binding votes in all matters, including the selection of new members. The votes on this motion will not be visible to to #{{user}}, but they will be able to see the discussion.\"\n  text_core_member_removal : \"This motion is to remove #{{user}} from the Core Team of #{{enterprise}}. If the motion passes #{{user}} would become a Member. As a Member, their votes will remain binding and their shares and credits would be unaffected. The votes on this motion will not be visible to to #{{user}}, but they will be able to see the discussion.\"\n  text_member_removal : \"This motion is to remove #{{user}} as a member of #{{enterprise}}. If the motion passes #{{user}} would become a Contributor. As a Contributor, their votes will be non-binding. Their shares and credits would be unaffected. The votes on this motion will not be visible to to #{{user}}, but they will be able to see the discussion.\"\n  text_issue_edit_footer : \"You can comment on this issue via email, by replying to this email directly.\"\n  text_message_edit_footer : \"You can reply to this message via email, by replying to this email directly.\"\n  text_invitation_note_default : \"Hey,\\r\\n\\r\\nWe've been using bettermeans.com to work on #{{project}}.\\r\\n\\r\\nBettermeans lets us work together as equals, and is a transparent, democratic way to get things done together. \\r\\n\\r\\nPlease accept this invitation to join us.\\r\\n\\r\\nWarm regards\\r\\n#{{user}}\"\n  text_you_are_invited : \"You are being invited to join\"\n  text_generic_invitation : \"This link allows anybody to get started as a <strong>contributor</strong> to this workstream.\"\n  text_generic_invitation_2 : \"You can also use the form below to send personalized invitations for folks to join as other roles\"\n  text_generic_invitation_long : \"The link below allows anybody to become a contributor to this workstream.<br><br>It can be used an infinite amount of times. And doesn't expire until you change it.<br>Send it out via email, or post it somewhere where folks can follow it to join your workstream.\"\n  text_personal_invitation : \"Use the form below to send personalized invitations to potential team members.<br><br>This is the better way to go since people are more likely to respond to an exclusive invite, and don't need to validate their email.<br><br> This is also the more secure option since each invitation can be used only once and expires after a while.\"\n  text_active_team_explanation : \"<strong>Active Members (for this workstream)</strong><br><br>Active members are people that have been involved in this specific workstream in the past 2 weeks. <br><br> Contributors, members, and core team roles are defined at the parent(root) workstream and apply to all it's sub workstreams.<br><br>For example: if someone is a core team member of a workstream then they will have the same role for all sub workstreams. However, they might be active in some and not others.\"\n  text_email_updated : \"Email successfully updated\"\n  text_usage_over : \"You have exceeded your usage for your current plan.<br> Please upgrade as soon as possible.\"\n  text_trial_expired : \"Your trial period has expired.<br> Please update your billing info so we can start charging you.\"\n\n  text_role_invitation_description_Administrator : \"Admins have the most power.<br><br> An Admin can bypass governance rules and directly add/remove members and workstreams, and all their votes are binding.<br><br> Use this role sparingly as you are setting up your structures. Then transition to using other roles for day to day collaboration.\"\n  text_role_invitation_description_Contributor : \"This the first level of participation in an open enterprise.<br><br>Contributors' votes on all matters will be visible to everyone, and will be non-binding.<br><br> Meaning a contributor's voice is here, but their voting doesn't directly affect the items they are weighing in on.<br><br> A contributor can earn credits and contribute to a workstream.\"\n  text_role_invitation_description_Member : \"Members are at the heart of an open enterprise.<br><br> All members' votes are binding.<br><br>In addition members can nominate contributors for membership, and vote on Core Team elections.<br><br> Only invite members whose principles and values are aligned with yours.\"\n  text_role_invitation_description_Core_Team : \"A member of the Core Team has binding votes in all matters, and is very similar to a member.<br><br> The main difference is a Core Team member can vote on the election of new members.<br><br> Essentially, they are the custodians of the organization's principles, and hold the bar for membership.<br><br> Core Team Members are accountable to all members, and their role is to represent their voice.\"\n  text_role_invitation_description_Board : \"As a board member,all your votes are binding, and you have equal priveleges to a Core Team Member.<br><br> Being on the board though, indicates a lesser commitment to being involved in day to day work.\"\n  text_project_locked: \"This workstream is temporarily locked due to non payment.\"\n\n\n  default_role_administrator: Administrator\n  default_role_citizen: Core Member\n  default_role_contributor: Contributor\n  default_tracker_task: Task\n  default_tracker_subtask: Subtask\n  default_issue_status_new: New\n  default_issue_status_open: Open\n  default_issue_status_assigned: Committed\n  default_issue_status_done: Done\n  default_issue_status_closed: Closed\n  default_issue_status_blocked: Blocked\n  default_issue_status_inprogress: Committed\n  default_issue_status_canceled: Canceled\n  default_issue_status_estimate: Estimate\n  default_issue_status_archived: Archived\n  default_issue_status_accepted: Accepted\n  default_issue_status_rejected: Rejected\n  default_doc_category_public: Public documentation\n  default_doc_category_private: Private documentation\n  default_priority_low: Low\n  default_priority_normal: Normal\n  default_priority_high: High\n  default_priority_urgent: Urgent\n  default_activity_default: Misc\n  default_activity_planning: Planning\n  default_activity_execution: Execution\n  default_issue_tracker_gift: Gift\n  default_issue_tracker_expense: Expense\n  default_issue_tracker_recurring: Recurring\n  default_issue_tracker_hourly: Hourly\n  default_issue_tracker_feature: Feature\n  default_issue_tracker_bug: Bug\n  default_issue_tracker_chore: Chore\n\n  enumeration_issue_priorities: Item priorities\n  enumeration_doc_categories: Document categories\n  enumeration_activities: Activities (time tracking)\n  enumeration_system_activity: System Activity\n\n  help_reset_link : Resetting this link changes the invitation code. This deactivates the previous link(s) and prevents anybody from signing in using it.<br><br>This action does not affect the personalized invitations you sent out.\n  help_how_do_i_join_a_team : How do I join this team?\n  help_how_do_i_join_a_team_title : Joining a Team\n  help_how_do_i_join_a_team_description : \"There are two levels of team membership: Contributor, and Core Team. <br /><br /><strong>Becoming a contributor</strong><br />Before getting on a core team you must first contribute to the team. </br>You become a contributor for a workstream by requesting and getting ownership of an existing tasks. <br /> Another way to become a contributor, is to be a core team member of any sub workstream.<br /><br /><strong>Become a core team member</strong><br />Once you are a contributor, you may request (or be invited) to join the Core Team by an existing Core Team member. <br /><br /> You can also join a workstream's core team directly if your a core team member of its parent workstream.\"\n  help_core_points_title : Core Points\n  help_core_points_description : \"Core points are a way of team members endorsing each other, and signaling confidence in each other's abilities and core values. <br /><br /> When someone on a core team feels that the team is better off with someone on it they can give that person a core point. It also works the other way: If someone feels that someone is hurting the team, they can give them a negative-core point. <br /><br />When a member's total core points exceeds zero, they're invited to be on the core team. If their total falls below zero, they revert back to contributor status. <br /><br />All voting is confidential to minimize internal politics as much as possible.<br />Total core points is calculated by adding up the votes of existing core team members of a workstream and its parent.\"\n  help_dpp: Items in a workstream are estimated in credits.<br/><br/>Each workstream has a different scale for possible estimations. The scale varies based on the complexity/granulatiry of the type of work for that workstream.\n  help_select_scale: Items in a workstream are estimated in points.<br/><br/>Each workstream can have a different payment scale.<br/><br/>Select a scale that best covers the range of work item sizes. This changes based on the nature of work for a particular workstream.\n  help_assessment_accuracy: \"Shows the accuracy with which this user was able to assess their contribution, and their team's contribution in retrospectives. <br><br>Assessment accuracy is averaged over time. More weight is given to the more recent retrospectives, and more weight is given to retrospectives with more credits.<br><br>For example: A postive self assessment accuracy score of +7 means the user tends to overrate themselves by 7 percentage points on average. <br><br> An 'other' assessment score of &plusmn 16 means the user tends have a total bias of plus or minus 16 percentage points when rating their peers. <br><br> The closer both these numbers are to zero, the more accurate the user is in their assessment of self and other. \"\n  help_your_assessment: \"<strong>Your assessment</strong><br>Your view of how much you and your team mates contributed to the execution of the items completed in this retrospective overall. What percentage of the work did you accomplish, compared to your team mates.During the retrospective, every team member is asked to assess everyone's contribution. Once the retrospective is complete, the assessments will be averaged out and displayed here.\"\n  help_team_assessment: \"<strong>Team assessment</strong><br>This is the average percentage contribution the work item as assessed by your peers. Each person's self-assessment is taken out of the average and only their team mates' assessment counts towards this number.\"\n  help_final_assessment: \"All the Team averages are used to be proportionally distributed over 100%\"\n  help_confidence: \"<strong>Assessment confidence</strong><br>Adjust this slider depending on how confident you are of your assessment of yourself and your peer.<br>Lower confidence, means your ratings will be given less weight, and your self assessment index will be less impact by team-self discrepancies.\"\n  help_accuracy: \"<strong>Accuracy and Bias</strong><br>This column shows the accuracy with which users who participated in this retrospective where able to assess themselves and their peers.\"\n  help_item_url: \"<strong>Item Permalink</strong><br>You can copy this link and use it to directly link to this item\"\n  help_volunteer: \"All work done on this workstream is on a volunteer basis. It will not be compensated for in money, barter, or any other monetary means.<br><br> That's not to say good karma won't come your way!<br><br>This is our small contribution to the volunteer world. Please report any abuse to abuse@bettermeans.com\"\n  help_volunteer_credits: \"All work done on this workstream is on a volunteer basis. It will not be compensated for in money, barter, or any other monetary means.<br><br> Credits are being used here to track user contribution, and show who did what for this workstream over time. These credits are not a promise for any rewards, or payment\"\n  help_no_my_workstreams: \"You haven't created any workstreams yet.\"\n  help_no_workstreams_i_belong_to: \"You are not yet a member of any workstreams that you didn't start.\"\n  help_no_workstreams_active: \"You have not been recently active in any workstreams.\"\n  help_no_workstreams: \"You haven't yet gotten involved in any workstreams.<br> Create or join something to get started...\"\n  help_no_workstreams_archived: \"You have no archived workstreams.\"\n  help_activities_i_belong_to: \"This activity stream shows all activity in workstreams that you own and/or belong to\"\n  help_this_workstream_is_private: \"This is private workstream. When a workstream is made private, all binding members (i.e. members, core team, board, and admins) are given permanent clearance to it. Also, all active contributors to the workstream are given clearance.<br><br> If you want to manage users' clearance to a private workstream, use the members tab under settings.\"\n\n  help_issue_tracking: \"This is the essential element of the platform in that it allows you to track all work items using the dashboard and item views. However one situation in which you might turn this off is if you are creating a root workstream for your organization and you are planning on creating lots of subworkstreams where all the work and item tracking would take place. This would leave the other elements such as discussion and wiki but without the dashboard or item tracking.\"\n  help_news: \"This module allows you to check out or report on the latest news. News is used to broadcast events to your team. For example winning a bid, or a new product release.\"\n  help_documents: \"This module allows you to upload document to share with your team.\"\n  help_files: \"This module allows you to upload files to share with your team.\"\n  help_wiki: \"Wikis are great tools for collaboration and therefore we provide the option for each workstream to have a wiki. Wikis are essentially online documents and everyone that has access can not only read but also edit and improve online.\"\n  help_boards: \"This module creates a discussion board for your workstream and like so many discussion boards before it, you can talk about stuff here. If someone has an idea that they are not yet ready to propose as a motion or work item and want to talk to folks about it, they can start a new topic. You might use the discussion board to discuss general strategy, new possible workstreams, or anything that comes to mind.\"\n  help_motions: \"Motions are used to make large important decisions that are project-wide. This is a democratic mechanism to make decisions together. There are different types of motions, to learn more about motions <a href='http://help.bettermeans.com/motions' target='blank'>click here</a>.\"\n  help_credits: \"Credits are a more open and democratic way of valuing work and awarding compensation. We are really excited about offering this as an option and we strongly encourage you to <a href='http://help.bettermeans.com/faq/credits' target='blank'>learn more about credits</a>.\"\n  help_revision_notes: \"Optional: Add notes to this revision of the wiki. These notes will appear in the version history of the wiki\"\n  help_mentions: \"Mentions happen when someone mentions you by using the '@' symbol before your username in any comments or descriptions. <br><br>For example if somebody adds this comment to an issue:<br><strong>'I think @#{{login}} should take a look at this'</strong><br>it would appear in your mentions\"\n\n\n  help_section_project_show: \"<strong>Welcome to the Overview Page.</strong>  From here you can get working and invite others to join in the fun. Take a look around <br> If you want to start a new workstream and are not sure what to do next or want tips for getting started <a href= 'http://help.bettermeans.com/quickstart' target='blank'>click here.</a><br> If you are joining an existing workstream and you are unsure what you are looking at, we are here to help, <a href= 'http://help.bettermeans.com/quickstart' target='blank'>click here.</a><br>We would recommend following the links above and/or taking <a href= 'http://help.bettermeans.com' target='blank'> the tour</a> before you begin.\"\n  help_section_project_dashboard: \"Welcome to your dashboard!|<strong>This is where the magic happens.</strong> Here you get a full view of all the work within a workstream. Each workstream and subworkstream has its own dashboard. <br><br><strong>Get started by adding a new item</strong> (click on the New Item Link at the top of the New column).<br><br>You can also <strong>offer new ideas/requests, comment, agree and disagree with ideas, prioritize, and estimate</strong>.<br><br>Click on the little key next to the New Item button for a little cheat sheet that shows the meaning of all the icons you see in the Dashboard. As you get rolling with your work, explore <strong>the filters and the search functions on the upper right corner.</strong><br><br> To learn more about voting and how it works in the dashboard <a href= 'http://help.bettermeans.com/dashboard' target='blank'> checkout our help section</a>, or this 9 minute tour of the site.<br><br><object width='560' height='340'><param name='movie' value='http://www.youtube.com/v/0wJAf229YUs?fs=1&amp;hl=en_US&amp;rel=0'></param><param name='allowFullScreen' value='true'></param><param name='allowscriptaccess' value='always'></param><embed src='http://www.youtube.com/v/0wJAf229YUs?fs=1&amp;hl=en_US&amp;rel=0' type='application/x-shockwave-flash' allowscriptaccess='always' allowfullscreen='true' width='560' height='340'></embed></object><br><br><br>\"\n  help_section_project_wiki: \"<strong>Wikis are great tools for collaboration and therefore each workstream has a wiki.</strong> You can start building your wiki here and you can create multiple pages by clicking <a href='wiki'>Start Page</a> (in blue to the right). Wikis are essentially online documents and everyone that has access can not only read but also edit and contribute to online. <br>Note the different action buttons (on the right in grey), these will be helpful when working on the Wiki.\"\n  help_section_project_news: \"<strong>Check out or report on the latest news here.</strong> News is used to broadcast events to your team. For example winning a bid, or a new product release.\"\n  help_section_project_discussion: \"Like so many discussion boards before it, you can talk about stuff here. If you have an idea that you are not yet ready to propose as a motion or work item and want to talk to folks about it, <strong>start a new topic.</strong> You might use the discussion board to discuss general strategy, new possible workstream, new target audience, or anything that comes to mind.\"\n  help_section_project_activity: \"<strong>Stay current on what's hot in your work using the activity stream.</strong> The activity stream is a very useful way of seeing what is the latest activity in your workstreams and subworkstreams. Any updates or comments or new items or status changes to items basically when anything changes in your workstream, it will appear here. For more information, <a href= 'http://help.bettermeans.com/activity_stream' target='blank'> click here. </a>\"\n  help_section_project_team: \"<strong>How great is your team!</strong> Use this page to track the roles people are playing for this workstream. Remember, these roles apply to all sub workstreams as well.<br><br>You can also use the links on the right to invite more team members. <a href='http://help.bettermeans.com/invitations' target='blank'> Learn more about invitations here</a>.<br><br> There are no job titles in an Open Enterprise, but there are levels of engagement that each come with different voting privileges, <a href= 'http://help.bettermeans.com/membership' target='blank'> learn more about that here.</a><br><br> \"\n  help_section_project_credits: \"<strong>This page tracks all the credits for your project.</strong> Credits are a way of tracking relative contribution. They are an indicator of what peers have given each other. <br>Credits can be used in many ways depending on how your organization or project runs. They can represent actual money in which case this is an accounts payable page, or they could represent relative contribution in which case this is a contribution tracking page. To learn more about how credits can work, <a href= 'http://help.bettermeans.com/credits' target='blank'> click here.</a>\"\n  help_section_my_account: \"<strong>This is your account page.</strong> Unlike your public profile this page is private to you.<br><br> Here you can do important things like change your password, email settings and other preferences. You can also see your current usage levels and if needed you can change your subscription plan with BetterMeans.<br><br> If you have questions about your account, please email <a href='mailto:billing@bettermeans.com'>billing@bettermeans.com</a>\"\n  help_section_welcome_index: \"Welcome on board!|<strong>Get started by creating your own workstream, or browsing around and contributing to existing ones</strong><br><br>We highly recommend this overview of how things work on bettermeans:<br><br><object width='560' height='340'><param name='movie' value='http://www.youtube.com/v/0wJAf229YUs?fs=1&amp;hl=en_US&amp;rel=0'></param><param name='allowFullScreen' value='true'></param><param name='allowscriptaccess' value='always'></param><embed src='http://www.youtube.com/v/0wJAf229YUs?fs=1&amp;hl=en_US&amp;rel=0' type='application/x-shockwave-flash' allowscriptaccess='always' allowfullscreen='true' width='560' height='340'></embed></object><br><br>You can also <a href='http://help.bettermeans.com' target='blank'>visit our help site for a more info</a> and answers to frequently asked questions.<br><br>Please don't forget to send as all the feedback you have!<br><br><br>\"\n  help_section_project_map: \"This is the map\"\n  help_section_project_settings: \"Use settings sparingly. If you're admin and core team, make sure to use core team tools when possible in order for things to stay democratic.\"\n  help_section_motion_new: \"Motions are used to make large important decisions that are project-wide. Notice the dropdown menu with the different types of motions. This is a democratic mechanism to make decisions together. To learn more about motions <a href= 'http://help.bettermeans.com/motions' >click here</a>\"\n  help_section_project_new: \"A Workstream is our lingo for a group or set of work.<br><br> A workstream could be a <strong>department</strong> of your organization or it could be a <strong>specific project</strong> that you are working on by your self or with others. In creating a workstreams there are a few important things to pay attention to:<br><br><ul><li> <strong>Public</strong>: A public workstream means that anyone can see your work and can comment and contribute. If you do not want to have this transparency with the community, you can uncheck this box and you are then creating a private workstream. As the creator, you control who has access, but also note that you have to pay for private workstreams. <a href= 'http://help.bettermeans.com/workstreams' target='blank'> Read more about tradeoffs. </a> </li><li> <strong>Volunteer</strong>: This is a signal to everyone working with you that all work in this workstream is fully volunteer.</li><li> <strong>Credits</strong>: Credits are a more open and democratic way of valuing work and awarding compensation. We are really excited about offering this as an option and we strongly encourage you to <a href= 'http://help.bettermeans.com/credits' target='blank'> learn more about credits. </a></li></ul> Still have questions, <a href= 'http://help.bettermeans.com/support' target='blank'> get in touch</a><br><br>\"\n  help_section_invitation_new: \"Use invitations to enroll team members to join your workstream.<br><br> When you send someone an invitation, they will be prompted to create a bettermeans account (if they don't have one already), and <strong>automatically added as a contributor</strong> to your workstream.<br><br>You can only invite people to a root workstream. Their membership in a workstream applies to all sub work streams as well. In other words,<strong> a person can't belong to a sub workstream, and not belong to its parent workstream.</strong><br><br> <a href='http://help.bettermeans.com/invitations' target='blank'>Learn more in our help section.</a><br><br><br>\"\n  help_section_browse_workstreams: \"<strong>Welcome to the BetterMeans Community.</strong> Unlike your home page, this page is the overview of the whole BetterMeans platform. You can look around at other public workstreams and comment and join other people's projects. <a href='http://help.bettermeans.com/' target='blank'>Learn more about the BetterMeans platform</a>\"\n  help_section_retrospective_show: \"<strong>This is a retrospective.</strong> In a retrospective compensation is awarded by your peers and your own self-assessment. This is an opportunity to be fairly compensated for your contribution. <br>You want to look at all of the completed items and then give your best assessment of what percentage you think each person contributed. You also have a chance to say how sure you are using the slider at the bottom. For more information about retrospectives, <a href='http://help.bettermeans.com/retrospectives' target='blank'>click here.</a>\"\n  help_section_free: Keep your work open and inclusive, and we won't charge you a dime no matter how large you grow.\n"
  },
  {
    "path": "config/preinitializer.rb",
    "content": "begin\n  require \"rubygems\"\n  require \"bundler\"\nrescue LoadError\n  raise \"Could not load the bundler gem. Install it with `gem install bundler`.\"\nend\n\nif Gem::Version.new(Bundler::VERSION) <= Gem::Version.new(\"0.9.24\")\n  raise RuntimeError, \"Your bundler version is too old for Rails 2.3.\" +\n   \"Run `gem install bundler` to upgrade.\"\nend\n\nbegin\n  # Set up load paths for all bundled gems\n  ENV[\"BUNDLE_GEMFILE\"] = File.expand_path(\"../../Gemfile\", __FILE__)\n  Bundler.setup\nrescue Bundler::GemNotFound\n  raise RuntimeError, \"Bundler couldn't find some gems.\" +\n    \"Did you run `bundle install`?\"\nend\n"
  },
  {
    "path": "config/rails_best_practices.yml",
    "content": "AddModelVirtualAttributeCheck: { }\nAlwaysAddDbIndexCheck: { }\nDryBundlerInCapistranoCheck: { }\nIsolateSeedDataCheck: { }\nKeepFindersOnTheirOwnModelCheck: { }\nLawOfDemeterCheck: { }\nLongLineCheck: { max_line_length: 80 }\nMoveCodeIntoControllerCheck: { }\nMoveCodeIntoHelperCheck: { array_count: 3 }\nMoveCodeIntoModelCheck: { use_count: 2 }\nMoveFinderToNamedScopeCheck: { }\nMoveModelLogicIntoModelCheck: { use_count: 4 }\nNeedlessDeepNestingCheck: { nested_count: 2 }\nNotUseDefaultRouteCheck: { }\nNotUseTimeAgoInWordsCheck: { }\nOveruseRouteCustomizationsCheck: { customize_count: 3 }\nProtectMassAssignmentCheck: { }\nRemoveEmptyHelpersCheck: { }\nRemoveTabCheck: { }\nRemoveTrailingWhitespaceCheck: { }\nRemoveUnusedMethodsInControllersCheck: { except_methods: [] }\nRemoveUnusedMethodsInHelpersCheck: { except_methods: [] }\nRemoveUnusedMethodsInModelsCheck: { except_methods: [] }\nReplaceComplexCreationWithFactoryMethodCheck: { attribute_assignment_count: 2 }\nReplaceInstanceVariableWithLocalVariableCheck: { }\nRestrictAutoGeneratedRoutesCheck: { }\nSimplifyRenderInControllersCheck: { }\nSimplifyRenderInViewsCheck: { }\nUseBeforeFilterCheck: { customize_count: 2 }\nUseModelAssociationCheck: { }\nUseMultipartAlternativeAsContentTypeOfEmailCheck: { }\nUseParenthesesInMethodDefCheck: { }\nUseObserverCheck: { }\nUseQueryAttributeCheck: { }\nUseSayWithTimeInMigrationsCheck: { }\nUseScopeAccessCheck: { }\n"
  },
  {
    "path": "config/routes.rb",
    "content": "ActionController::Routing::Routes.draw do |map|\n\n  map.resources :help_sections\n  map.resources :reputations\n  map.resources :credit_distributions\n  map.resources :quotes\n\n  map.signin 'login', :controller => 'account', :action => 'login'\n  map.signout 'logout', :controller => 'account', :action => 'logout'\n  map.connect 'accounts/rpx_token',:controller => 'account', :action => 'rpx_token'\n\n  # TODO: remove this route, seems to no longer be used\n  map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow'\n  map.connect 'help/:ctrl/:page', :controller => 'help' #What's this?\n  map.connect 'help/:id', :controller => 'help', :action => 'show'\n\n  map.connect 'time_entries/:id/edit', :action => 'edit', :controller => 'timelog'\n  map.connect 'projects/:project_id/time_entries/new', :action => 'edit', :controller => 'timelog'\n  map.connect 'projects/:project_id/issues/:issue_id/time_entries/new', :action => 'edit', :controller => 'timelog'\n\n  map.with_options :controller => 'timelog' do |timelog|\n    timelog.connect 'projects/:project_id/time_entries', :action => 'details'\n\n    timelog.with_options :action => 'details', :conditions => {:method => :get}  do |time_details|\n      time_details.connect 'time_entries'\n      time_details.connect 'issues/:issue_id/time_entries'\n      time_details.connect 'projects/:project_id/issues/:issue_id/time_entries'\n    end\n    timelog.connect 'projects/:project_id/time_entries/report', :action => 'report'\n    timelog.with_options :action => 'report',:conditions => {:method => :get} do |time_report|\n      time_report.connect 'time_entries/report'\n    end\n\n    timelog.with_options :action => 'edit', :conditions => {:method => :get} do |time_edit|\n      time_edit.connect 'issues/:issue_id/time_entries/new'\n    end\n\n    timelog.connect 'time_entries/:id/destroy', :action => 'destroy', :conditions => {:method => :post}\n  end\n\n  map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}\n  map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}\n  map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}\n  map.with_options :controller => 'wiki' do |wiki_routes|\n    wiki_routes.with_options :conditions => {:method => :get} do |wiki_views|\n      wiki_views.connect 'projects/:id/wiki/:page', :action => 'special', :page => /page_index|date_index|export/i\n      wiki_views.connect 'projects/:id/wiki/:page', :action => 'index', :page => nil\n      wiki_views.connect 'projects/:id/wiki/:page/edit', :action => 'edit'\n      wiki_views.connect 'projects/:id/wiki/:page/rename', :action => 'rename'\n      wiki_views.connect 'projects/:id/wiki/:page/history', :action => 'history'\n      wiki_views.connect 'projects/:id/wiki/:page/diff/:version/vs/:version_from', :action => 'diff'\n      wiki_views.connect 'projects/:id/wiki/:page/annotate/:version', :action => 'annotate'\n    end\n\n    wiki_routes.connect 'projects/:id/wiki/:page/:action',\n      :action => /edit|rename|destroy|preview|protect/,\n      :conditions => {:method => :post}\n  end\n\n  map.with_options :controller => 'messages' do |messages_routes|\n    messages_routes.with_options :conditions => {:method => :get} do |messages_views|\n      messages_views.connect 'boards/:board_id/topics/new', :action => 'new'\n      messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'\n      messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'\n    end\n    messages_routes.with_options :conditions => {:method => :post} do |messages_actions|\n      messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'\n      messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'\n      messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/\n    end\n  end\n\n  map.with_options :controller => 'invitations' do |invitations_routes|\n    invitations_routes.with_options :conditions => {:method => :get} do |invitations_views|\n      invitations_views.connect 'invitations/:id', :action => 'accept'\n    end\n    invitations_routes.with_options :conditions => {:method => :post} do |invitations_actions|\n      invitations_actions.connect 'projects/:project_id/invitations/:id/:action', :action => /destroy|resend/\n    end\n  end\n\n  map.with_options :controller => 'email_updates' do |email_updates_routes|\n    email_updates_routes.with_options :conditions => {:method => :get} do |invitations_views|\n      email_updates_routes.connect 'email_updates/activate', :action => 'activate'\n    end\n  end\n\n  map.resources :email_updates\n\n  map.with_options :controller => 'boards' do |board_routes|\n    board_routes.with_options :conditions => {:method => :get} do |board_views|\n      board_views.connect 'projects/:project_id/boards', :action => 'index'\n      board_views.connect 'projects/:project_id/boards/new', :action => 'new'\n      board_views.connect 'projects/:project_id/boards/:id', :action => 'show'\n      board_views.connect 'projects/:project_id/boards/:id/edit', :action => 'edit'\n    end\n    board_routes.with_options :conditions => {:method => :post} do |board_actions|\n      board_actions.connect 'projects/:project_id/boards', :action => 'new'\n      board_actions.connect 'projects/:project_id/boards/:id/:action', :action => /edit|destroy/\n    end\n  end\n\n  map.with_options :controller => 'documents' do |document_routes|\n    document_routes.with_options :conditions => {:method => :get} do |document_views|\n      document_views.connect 'projects/:project_id/documents', :action => 'index'\n      document_views.connect 'projects/:project_id/documents/new', :action => 'new'\n      document_views.connect 'documents/:id', :action => 'show'\n      document_views.connect 'documents/:id/edit', :action => 'edit'\n    end\n    document_routes.with_options :conditions => {:method => :post} do |document_actions|\n      document_actions.connect 'projects/:project_id/documents', :action => 'new'\n      document_actions.connect 'documents/:id/:action', :action => /destroy|edit/\n    end\n  end\n\n  map.with_options :controller => 'issues' do |issues_routes|\n    issues_routes.with_options :conditions => {:method => :get} do |issues_views|\n      issues_views.connect 'issues', :action => 'index'\n      issues_views.connect 'issues/datadump.:format', :action => 'datadump'\n      issues_views.connect 'issues.:format', :action => 'index'\n      issues_views.connect 'projects/:project_id/issues', :action => 'index'\n      issues_views.connect 'projects/:project_id/issues.:format', :action => 'index'\n      issues_views.connect 'projects/:project_id/issues/new', :action => 'new'\n      issues_views.connect 'projects/:project_id/issues/gantt', :action => 'gantt'\n      issues_views.connect 'projects/:project_id/issues/calendar', :action => 'calendar'\n      issues_views.connect 'projects/:project_id/issues/:copy_from/copy', :action => 'new'\n      issues_views.connect 'issues/:id/edit', :action => 'edit', :id => /\\d+/\n      issues_views.connect 'issues/:id/move', :action => 'move', :id => /\\d+/\n      issues_views.connect 'issues/:id/show', :action => 'show', :id => /\\d+/\n    end\n    issues_routes.with_options :conditions => {:method => :post} do |issues_actions|\n      issues_actions.connect 'projects/:project_id/issues', :action => 'new'\n      issues_actions.connect 'issues/:id/quoted', :action => 'reply', :id => /\\d+/\n      # BUGBUG: :disagree and :reject don't seem to be used anymore\n      issues_actions.connect 'issues/:id/:action', :action => /edit|move|destroy|start|finish|release|cancel|restart|prioritize|agree|disagree|estimate|accept|reject|join|leave|add_team_member|update_tags/, :id => /\\d+/\n      issues_actions.connect 'issues/:container_id/attachments/create', :controller => 'attachments', :action => 'create'\n    end\n  end\n\n  map.with_options  :controller => 'issue_relations', :conditions => {:method => :post} do |relations|\n    relations.connect 'issues/:issue_id/relations/:id', :action => 'new'\n    relations.connect 'issues/:issue_id/relations/:id/destroy', :action => 'destroy'\n  end\n\n  map.with_options :controller => 'reports', :action => 'issue_report', :conditions => {:method => :get} do |reports|\n    reports.connect 'projects/:id/issues/report'\n    reports.connect 'projects/:id/issues/report/:detail'\n  end\n\n  map.with_options :controller => 'news' do |news_routes|\n    news_routes.with_options :conditions => {:method => :get} do |news_views|\n      news_views.connect 'news', :action => 'index'\n      news_views.connect 'projects/:project_id/news', :action => 'index'\n      news_views.connect 'projects/:project_id/news.:format', :action => 'index'\n      news_views.connect 'news.:format', :action => 'index'\n      news_views.connect 'projects/:project_id/news/new', :action => 'new'\n      news_views.connect 'news/:id', :action => 'show'\n      news_views.connect 'news/:id/edit', :action => 'edit'\n    end\n    # BUGBUG: this should probably be `:conditions => { :method => :post }`\n    news_routes.with_options do |news_actions|\n      news_actions.connect 'projects/:project_id/news', :action => 'new'\n      news_actions.connect 'news/:id/edit', :action => 'edit'\n      news_actions.connect 'news/:id/destroy', :action => 'destroy'\n    end\n  end\n\n  map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'\n\n    map.resources :users do |users|\n      users.resources :mails, :collection => { :delete_selected => :post }\n    end\n\n  map.with_options :controller => 'users' do |users|\n    users.with_options :conditions => {:method => :get} do |user_views|\n      user_views.connect 'users', :action => 'index'\n      user_views.connect 'users/:id', :action => 'show', :id => /\\d+/\n      user_views.connect 'users/new', :action => 'add'\n      user_views.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil\n    end\n    users.with_options :conditions => {:method => :post} do |user_actions|\n      user_actions.connect 'users', :action => 'add'\n      user_actions.connect 'users/new', :action => 'add'\n      user_actions.connect 'users/:id/edit', :action => 'edit'\n      user_actions.connect 'users/:id/memberships', :action => 'edit_membership'\n      user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership'\n      user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership'\n    end\n  end\n\n  map.with_options :controller => 'retros' do |retro_routes|\n    retro_routes.with_options :conditions => {:method => :get} do |retro_views|\n      retro_views.connect 'projects/:project_id/retros', :action => 'index'\n      retro_views.connect 'projects/:project_id/retros/new', :action => 'new'\n      retro_views.connect 'projects/:project_id/retros/:action', :action => /index_json/\n      retro_views.connect 'projects/:project_id/retros/:id/:action', :action => /show|dashdata/\n      retro_views.connect 'projects/:project_id/retros/:id.:format', :action => 'show'\n      retro_views.connect 'projects/:project_id/retros/:id/edit', :action => 'edit'\n    end\n    retro_routes.with_options :conditions => {:method => :post} do |retro_actions|\n      retro_actions.connect 'projects/:project_id/retros', :action => 'new'\n      retro_actions.connect 'projects/:project_id/retros/:id/:action', :action => /edit|destroy/\n    end\n  end\n\n  map.with_options :controller => 'projects' do |projects|\n    projects.with_options :conditions => {:method => :get} do |project_views|\n      project_views.connect 'projects', :action => 'index'\n      project_views.connect 'projects.:format', :action => 'index'\n      project_views.connect 'projects/new', :action => 'add'\n      project_views.connect 'projects/index_latest', :action => 'index_latest'\n      project_views.connect 'projects/index_active', :action => 'index_active'\n      project_views.connect 'projects/update_scale', :action => 'update_scale'\n      project_views.connect 'projects/:id', :action => 'overview'\n      project_views.connect 'projects/:id/show', :action => 'overview'\n      project_views.connect 'projects/:id/overview', :action => 'overview'\n      # TODO: remove unused: :roadmap, :wiki, :changelog, :leave_core_team,\n      # :core_vote, :agree, :disagree, :accept, :reject, :shares,\n      # :reset_invitation_code\n      project_views.connect 'projects/:id/:action', :action => /roadmap|changelog|destroy|settings|team|wiki|join_core_team|leave_core_team|core_vote|dashdata|new_dashdata|dashboard|mypris|agree|disagree|accept|reject|credits|shares|community_members|community_members_array|issue_search|hourly_types|map|join|overview|reset_invitation_code|all_tags/\n      project_views.connect 'projects/:id/files', :action => 'list_files'\n      project_views.connect 'projects/:id/files/new', :action => 'add_file'\n      project_views.connect 'projects/:id/settings/:tab', :action => 'settings'\n      project_views.connect 'issues/:show_issue_id', :action => 'dashboard'\n    end\n\n    projects.with_options :conditions => {:method => :post} do |project_actions|\n      project_actions.connect 'projects/new', :action => 'add'\n      project_actions.connect 'projects', :action => 'add'\n      project_actions.connect 'projects/:id/:action', :action => /destroy|archive|unarchive|edit/\n      # TODO: remove this route\n      project_actions.connect 'projects/:id/wiki', :action => 'wiki'\n      project_actions.connect 'projects/:id/files/new', :action => 'add_file'\n      project_actions.connect 'projects/:id/activities/save', :action => 'save_activities'\n    end\n\n    projects.with_options :action => 'activity', :conditions => {:method => :get} do |activity|\n      activity.connect 'projects/:id/activity'\n      activity.connect 'activity', :id => nil\n    end\n  end\n\n  map.with_options :controller => 'hourly_types' do |hourly_type_routes|\n    hourly_type_routes.with_options :conditions => {:method => :get} do |hourly_type_views|\n      hourly_type_views.connect 'projects/:project_id/hourly_types/new', :action => 'new'\n      hourly_type_views.connect 'projects/:project_id/hourly_types/:id/edit', :action => 'edit'\n    end\n    hourly_type_routes.with_options :conditions => {:method => :post} do |hourly_type_action|\n      hourly_type_action.connect 'projects/:project_id/hourly_types/new', :action => 'new'\n      hourly_type_action.connect 'projects/:project_id/hourly_types/:id/:action', :action => /new|edit|destroy/\n    end\n  end\n\n  map.with_options :controller => 'recurly_notifications' do |recurly_routes|\n    recurly_routes.with_options :conditions => {:method => :post} do |recurly_action|\n      recurly_action.connect 'recurly_notifications/listen', :action => 'listen'\n    end\n  end\n\n  map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\\d+/\n  map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\\d+/, :filename => /.*/\n  map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\\d+/, :filename => /.*/\n\n\n  map.resources :groups\n  map.resources :activity_streams\n\n  map.resources :projects, :has_many => :shares\n  map.resources :projects, :has_many => :credits\n  map.resources :projects, :has_many => :motions\n  map.resources :projects, :has_many => :invitations\n\n\n  #left old routes at the bottom for backwards compat\n  map.connect 'projects/:project_id/issues/:action', :controller => 'issues'\n  map.connect 'projects/:project_id/documents/:action', :controller => 'documents'\n  map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards'\n  map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'\n  map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'\n  map.connect 'issues/:issue_id/relations/:action/:id', :controller => 'issue_relations'\n  map.connect 'projects/:project_id/news/:action', :controller => 'news'\n  map.connect 'projects/:project_id/motions/:action', :controller => 'motions'\n  map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/\n\n  #semi-static pages\n  map.root :controller => 'home'\n  map.home '', :controller => 'home', :action => 'index'\n  map.static '/front/:page', :controller => 'home', :action => 'show', :page => /index.html|about.html|howitworks.html|contact.html|hq.html|pricing.html|signup.html|apps.html|products.html|services.html|single.html|tour.html|webdesign.html|index.htm|elements.html|privacy.html|library.html|testimonials.html|irb.html|open_enterprise_governance_model.html|user_agreement.html|why.html|how.html|what.html|inviteonly.html/\n\n\n  # Install the default route as the lowest priority.\n  # TODO: remove these default routes once integration specs are complete\n  map.connect ':controller/:action/:id'\n\n  # BUGBUG:  everything below the default routes above will be eclipsed by them\n  map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'\n\n  map.resources :pages, :only => :show\n\n  map.resources :todos\n  map.resources :issue_votes\n\n  map.resources :credits\n  map.resources :shares\n  map.resources :enterprises\n  map.resources :comments\n  map.resources :retro_ratings\n  map.resources :retros\n  map.resources :notifications\n  map.resources :issues\n  map.resources :credit_transfers\nend\n"
  },
  {
    "path": "config/s3.yml",
    "content": "production:\n  access_key_id: <%=ENV['s3_access_key_id'] %>\n  secret_access_key: <%=ENV['s3_secret_access_key'] %>\n  bucket: bettermeans_production\n  cname_bucket: false\n\ndevelopment:\n    access_key_id: <%=ENV['s3_access_key_id'] %>\n    secret_access_key: <%=ENV['s3_secret_access_key'] %>\n    bucket: bettermeans_development\n    cname_bucket: false\n\ntest: &TEST\n    access_key_id: <%=ENV['s3_access_key_id'] %>\n    secret_access_key: <%=ENV['s3_secret_access_key'] %>\n    bucket: bettermeans_development\n    cname_bucket: false\n\ncucumber:\n  <<: *TEST\n\nselenium:\n  <<: *TEST\n\n"
  },
  {
    "path": "config/selenium.yml",
    "content": "# Please read as our directions have changed:\n# Move this file to your rails apps config directory and rename it to selenium.yml in order to configure the plugin\n\n#\n# General settings\n#\n\nenvironments:\n  - test\n#  - development # Uncomment this line to enable in development environment. N.B. your development database will likely be altered/destroyed/abducted\n\n#selenium_path: 'c:\\selenium' #path to selenium installation. only needed if you for some reason don't want to use the bundled version of selenium core\n\n#\n# rake test:acceptance settings\n#\n\nbrowsers:\n  # Windows\n  # firefox: 'c:\\Program Files\\Mozilla Firefox\\firefox.exe'\n  # ie: 'c:\\Program Files\\Internet Explorer\\iexplore.exe'\n\n  # Mac OS X\n  firefox: '/Applications/Firefox.app/Contents/MacOS/firefox-bin'\n  safari: '/Applications/Safari.app/Contents/MacOS/Safari'\n\n#host: 'localhost'\n#port_start: 3000\n#port_end: 3005\n#base_url_path: '/'\n#max_browser_duration: 120\n#multi_window: false\n\n#result_dir: 'c:\\result' # the directory where the results will be stored after a test:acceptance run\n\n#fixtures_path: <%= \"#{RAILS_ROOT}/spec/fixtures\" %>\n#selenium_tests_path: <%= \"#{RAILS_ROOT}/spec/selenium\" %>\n"
  },
  {
    "path": "config/settings.yml",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\n\n# DO NOT MODIFY THIS FILE !!!\n# Settings can be defined through the application in Admin -> Settings\n\napp_title:\n  default: BetterMeans\napp_subtitle:\n  default: Work re-invented\nwelcome_text:\n  default: 'Welcome to BetterMeans!'\nlogin_required:\n  default: 0\nself_registration:\n  default: '1'\nlost_password:\n  default: 1\npassword_min_length:\n  format: int\n  default: 6\nattachment_max_size:\n  format: int\n  default: 51200\nissues_export_limit:\n  format: int\n  default: 500\nactivity_days_default:\n  format: int\n  default: 5\nper_page_options:\n  default: '25,50,100'\nmail_from:\n  default: BetterMeans<administrator@bettermeans.com>\nmail_from_raw:\n  default: administrator@bettermeans.com\nbcc_recipients:\n  default: 1\nplain_text_mail:\n  default: 0\ntext_formatting:\n  default: textile\nwiki_compression:\n  default: \"\"\ndefault_language:\n  default: en\nhost_name:\n  default: bettermeans.com\nprotocol:\n  default: http\nfeeds_limit:\n  format: int\n  default: 25\n# Maximum size of files that can be displayed\n# inline through the file viewer (in KB)    mat\nfile_max_size_displayed:\n  format: int\n  default: 512\ndiff_max_lines_displayed:\n  format: int\n  default: 1500\ncommit_ref_keywords:\n  default: 'refs,references,IssueID'\ncommit_fix_keywords:\n  default: 'fixes,closes'\ncommit_fix_status_id:\n  format: int\n  default: 0\ncommit_fix_done_ratio:\n  default: 100\n# autologin duration in days\n# 0 means autologin is disabled\nautologin:\n  format: int\n  default: 30\n# date format\ndate_format:\n  default: '%m/%d/%Y'\ntime_format:\n  default: '%I:%M %p'\nuser_format:\n  default: :firstname_lastname\n  format: symbol\ncross_project_issue_relations:\n  default: 1\nnotified_events:\n  serialized: true\n  default:\n  - issue_added\n  - issue_updated\n  - news_added\n  - message_posted\nmail_handler_body_delimiters:\n  default: administrator@bettermeans.com\nmail_handler_api_enabled:\n  default: 1\nmail_handler_api_key:\n  default: gX7EBfIyc9orWdXzQ9vM\nissue_list_default_columns:\n  serialized: true\n  default:\n  - tracker\n  - status\n  - subject\n  - pri\n  - updated_at\ndisplay_subprojects_issues:\n  default: 1\nissue_done_ratio:\n  default: 'issue_field'\ndefault_projects_public:\n  default: 1\ndefault_projects_modules:\n  serialized: true\n  default:\n  - issue_tracking\n  - documents\n  - wiki\n  - boards\n  - motions\n\n# Role given to a non-admin user who creates a project\nnew_project_user_role_id:\n  format: int\n  default: 7\nsequential_project_identifiers:\n  default: 1\n# encoding used to convert commit logs to UTF-8\ncommit_logs_encoding:\n  default: 'UTF-8'\nui_theme:\n  default: 'bettermeans'\nemails_footer:\n  default: |-\n    You have received this notification because you have either subscribed to it, or are involved in it.\n    To change your notification preferences, please click here: http://bettermeans.com/my/account\nemails_footer_nospam:\n  default: |-\n    You are receiving this email via bettermeans.com\n    We have zero tolerance for spam.\n    Please forward this email to abuse@bettermeans.com if you feel you are recieving it in error. Thanks!\ngravatar_enabled:\n  default: 1\nopenid:\n  default: 0\nforum_name:\n  default: |-\n    General Discussion\nforum_description:\n  default: |-\n    General Discussion for Workstream :\ngravatar_default:\n  default: identicon\nstart_of_week:\n  default: ''\nrest_api_enabled:\n  default: 0\nenabled_scm:\n  default: ''\nsys_api_enabled:\n  default: true\nrepositories_encodings:\n  default: ''\nrepository_log_display_limit:\n  default: ''\nautofetch_changesets:\n  default: true\n"
  },
  {
    "path": "cucumber.yml",
    "content": "default: --tags ~@selenium -r features/support/env.rb -r features/step_definitions features\nselenium: --tags @selenium -r features/support/env.rb -r features/support/selenium.rb -r features/step_definitions features"
  },
  {
    "path": "db/migrate/20110320055526_acts_as_taggable_on_migration.rb",
    "content": "class ActsAsTaggableOnMigration < ActiveRecord::Migration\n  def self.up\n    create_table :tags do |t|\n      t.column :name, :string\n    end\n\n    create_table :taggings do |t|\n      t.column :tag_id, :integer\n      t.column :taggable_id, :integer\n      t.column :tagger_id, :integer\n      t.column :tagger_type, :string\n\n      # You should make sure that the column created is\n      # long enough to store the required class names.\n      t.column :taggable_type, :string\n      t.column :context, :string\n\n      t.column :created_at, :datetime\n    end\n\n    add_index :taggings, :tag_id\n    add_index :taggings, [:taggable_id, :taggable_type, :context]\n  end\n\n  def self.down\n    drop_table :taggings\n    drop_table :tags\n  end\nend\n"
  },
  {
    "path": "db/migrate/20110329230314_add_projectid_to_taggable.rb",
    "content": "class AddProjectidToTaggable < ActiveRecord::Migration\n  def self.up\n    add_column :taggings, :project_id, :integer\n  end\n\n  def self.down\n    remove_column :taggings, :project_id\n  end\nend\n"
  },
  {
    "path": "db/migrate/20110330041648_add_tags_to_issue.rb",
    "content": "class AddTagsToIssue < ActiveRecord::Migration\n  def self.up\n    add_column :issues, :tags_copy, :string\n  end\n\n  def self.down\n    remove_column :issues, :tags_copy\n  end\nend\n"
  },
  {
    "path": "db/schema.rb",
    "content": "# This file is auto-generated from the current state of the database. Instead of editing this file, \n# please use the migrations feature of Active Record to incrementally modify your database, and\n# then regenerate this schema definition.\n#\n# Note that this schema.rb definition is the authoritative source for your database schema. If you need\n# to create the application database on another system, you should be using db:schema:load, not running\n# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations\n# you'll amass, the slower it'll run and the greater likelihood for issues).\n#\n# It's strongly recommended to check this file into your version control system.\n\nActiveRecord::Schema.define(:version => 20110330041648) do\n\n  create_table \"activity_stream_preferences\", :force => true do |t|\n    t.string   \"activity\"\n    t.string   \"location\"\n    t.integer  \"user_id\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  add_index \"activity_stream_preferences\", [\"activity\", \"user_id\"], :name => \"activity_stream_preferences_idx\"\n\n  create_table \"activity_stream_totals\", :force => true do |t|\n    t.string   \"activity\"\n    t.integer  \"object_id\"\n    t.string   \"object_type\"\n    t.float    \"total\",       :default => 0.0\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  add_index \"activity_stream_totals\", [\"activity\", \"object_id\", \"object_type\"], :name => \"activity_stream_totals_idx\"\n\n  create_table \"activity_streams\", :force => true do |t|\n    t.string   \"verb\"\n    t.string   \"activity\"\n    t.integer  \"actor_id\"\n    t.string   \"actor_type\"\n    t.string   \"actor_name_method\"\n    t.integer  \"count\",                       :default => 1\n    t.integer  \"object_id\"\n    t.string   \"object_type\"\n    t.string   \"object_name_method\"\n    t.integer  \"indirect_object_id\"\n    t.string   \"indirect_object_type\"\n    t.string   \"indirect_object_name_method\"\n    t.string   \"indirect_object_phrase\"\n    t.integer  \"status\",                      :default => 0\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.integer  \"project_id\",                  :default => 0\n    t.string   \"actor_name\"\n    t.string   \"object_name\"\n    t.text     \"object_description\"\n    t.string   \"indirect_object_name\"\n    t.text     \"indirect_object_description\"\n    t.string   \"tracker_name\"\n    t.string   \"project_name\"\n    t.string   \"actor_email\"\n    t.boolean  \"is_public\",                   :default => false\n    t.integer  \"hidden_from_user_id\",         :default => 0\n  end\n\n  add_index \"activity_streams\", [\"actor_id\", \"actor_type\"], :name => \"activity_streams_by_actor\"\n  add_index \"activity_streams\", [\"indirect_object_id\", \"indirect_object_type\"], :name => \"activity_streams_by_indirect_object\"\n  add_index \"activity_streams\", [\"object_id\", \"object_type\"], :name => \"activity_streams_by_object\"\n\n  create_table \"attachments\", :force => true do |t|\n    t.integer  \"container_id\",                 :default => 0,  :null => false\n    t.string   \"container_type\", :limit => 30, :default => \"\", :null => false\n    t.string   \"filename\",                     :default => \"\", :null => false\n    t.string   \"disk_filename\",                :default => \"\", :null => false\n    t.integer  \"filesize\",                     :default => 0,  :null => false\n    t.string   \"content_type\",                 :default => \"\"\n    t.string   \"digest\",         :limit => 40, :default => \"\", :null => false\n    t.integer  \"downloads\",                    :default => 0,  :null => false\n    t.integer  \"author_id\",                    :default => 0,  :null => false\n    t.datetime \"created_at\"\n    t.string   \"description\"\n  end\n\n  add_index \"attachments\", [\"author_id\"], :name => \"index_attachments_on_author_id\"\n  add_index \"attachments\", [\"container_id\", \"container_type\"], :name => \"index_attachments_on_container_id_and_container_type\"\n  add_index \"attachments\", [\"created_at\"], :name => \"index_attachments_on_created_at\"\n\n  create_table \"auth_sources\", :force => true do |t|\n    t.string  \"type\",              :limit => 30, :default => \"\",    :null => false\n    t.string  \"name\",              :limit => 60, :default => \"\",    :null => false\n    t.string  \"host\",              :limit => 60\n    t.integer \"port\"\n    t.string  \"account\"\n    t.string  \"account_password\",  :limit => 60\n    t.string  \"base_dn\"\n    t.string  \"attr_login\",        :limit => 30\n    t.string  \"attr_firstname\",    :limit => 30\n    t.string  \"attr_lastname\",     :limit => 30\n    t.string  \"attr_mail\",         :limit => 30\n    t.boolean \"onthefly_register\",               :default => false, :null => false\n    t.boolean \"tls\",                             :default => false, :null => false\n  end\n\n  add_index \"auth_sources\", [\"id\", \"type\"], :name => \"index_auth_sources_on_id_and_type\"\n\n  create_table \"boards\", :force => true do |t|\n    t.integer \"project_id\",                      :null => false\n    t.string  \"name\",            :default => \"\", :null => false\n    t.string  \"description\"\n    t.integer \"position\",        :default => 1\n    t.integer \"topics_count\",    :default => 0,  :null => false\n    t.integer \"messages_count\",  :default => 0,  :null => false\n    t.integer \"last_message_id\"\n  end\n\n  add_index \"boards\", [\"last_message_id\"], :name => \"index_boards_on_last_message_id\"\n  add_index \"boards\", [\"project_id\"], :name => \"boards_project_id\"\n\n  create_table \"comments\", :force => true do |t|\n    t.string   \"commented_type\", :limit => 30, :default => \"\", :null => false\n    t.integer  \"commented_id\",                 :default => 0,  :null => false\n    t.integer  \"author_id\",                    :default => 0,  :null => false\n    t.text     \"comments\"\n    t.datetime \"created_at\",                                   :null => false\n    t.datetime \"updated_at\",                                   :null => false\n  end\n\n  add_index \"comments\", [\"author_id\"], :name => \"index_comments_on_author_id\"\n  add_index \"comments\", [\"commented_id\", \"commented_type\"], :name => \"index_comments_on_commented_id_and_commented_type\"\n\n  create_table \"credit_distributions\", :force => true do |t|\n    t.integer  \"user_id\"\n    t.integer  \"project_id\"\n    t.integer  \"retro_id\"\n    t.float    \"amount\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"credit_transfers\", :force => true do |t|\n    t.integer  \"sender_id\"\n    t.integer  \"recipient_id\"\n    t.integer  \"project_id\"\n    t.float    \"amount\"\n    t.string   \"note\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"credits\", :force => true do |t|\n    t.float    \"amount\",                       :null => false\n    t.datetime \"issued_on\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.integer  \"owner_id\"\n    t.integer  \"project_id\"\n    t.datetime \"settled_on\"\n    t.boolean  \"enabled\",    :default => true\n  end\n\n  add_index \"credits\", [\"owner_id\"], :name => \"index_credits_on_owner_id\"\n  add_index \"credits\", [\"project_id\"], :name => \"index_credits_on_project_id\"\n\n  create_table \"daily_digests\", :force => true do |t|\n    t.integer  \"issue_id\"\n    t.integer  \"journal_id\"\n    t.string   \"mail\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"delayed_jobs\", :force => true do |t|\n    t.integer  \"priority\",   :default => 0\n    t.integer  \"attempts\",   :default => 0\n    t.text     \"handler\"\n    t.text     \"last_error\"\n    t.datetime \"run_at\"\n    t.datetime \"locked_at\"\n    t.datetime \"failed_at\"\n    t.string   \"locked_by\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"documents\", :force => true do |t|\n    t.integer  \"project_id\",                :default => 0,  :null => false\n    t.string   \"title\",       :limit => 60, :default => \"\", :null => false\n    t.text     \"description\"\n    t.datetime \"created_at\"\n  end\n\n  add_index \"documents\", [\"created_at\"], :name => \"index_documents_on_created_on\"\n  add_index \"documents\", [\"project_id\"], :name => \"documents_project_id\"\n\n  create_table \"email_updates\", :force => true do |t|\n    t.integer  \"user_id\"\n    t.string   \"mail\"\n    t.string   \"token\"\n    t.boolean  \"activated\",  :default => false\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"enabled_modules\", :force => true do |t|\n    t.integer \"project_id\"\n    t.string  \"name\",       :null => false\n  end\n\n  add_index \"enabled_modules\", [\"project_id\"], :name => \"enabled_modules_project_id\"\n\n  create_table \"enterprises\", :force => true do |t|\n    t.string   \"name\"\n    t.text     \"description\"\n    t.string   \"homepage\",    :default => \"\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"enumerations\", :force => true do |t|\n    t.string  \"opt\",        :limit => 4,  :default => \"\",    :null => false\n    t.string  \"name\",       :limit => 30, :default => \"\",    :null => false\n    t.integer \"position\",                 :default => 1\n    t.boolean \"is_default\",               :default => false, :null => false\n    t.string  \"type\"\n    t.boolean \"active\",                   :default => true,  :null => false\n    t.integer \"project_id\"\n    t.integer \"parent_id\"\n  end\n\n  add_index \"enumerations\", [\"id\", \"type\"], :name => \"index_enumerations_on_id_and_type\"\n  add_index \"enumerations\", [\"project_id\"], :name => \"index_enumerations_on_project_id\"\n\n  create_table \"help_sections\", :force => true do |t|\n    t.integer  \"user_id\",    :default => 0,    :null => false\n    t.string   \"name\"\n    t.boolean  \"show\",       :default => true\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"hourly_types\", :force => true do |t|\n    t.integer  \"project_id\"\n    t.string   \"name\"\n    t.decimal  \"hourly_rate_per_person\", :precision => 8, :scale => 2\n    t.decimal  \"hourly_cap\",             :precision => 8, :scale => 2\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"invitations\", :force => true do |t|\n    t.integer  \"user_id\"\n    t.integer  \"project_id\"\n    t.string   \"token\"\n    t.integer  \"status\",     :default => 0\n    t.integer  \"role_id\"\n    t.string   \"mail\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.string   \"new_mail\"\n  end\n\n  create_table \"issue_relations\", :force => true do |t|\n    t.integer \"issue_from_id\",                 :null => false\n    t.integer \"issue_to_id\",                   :null => false\n    t.string  \"relation_type\", :default => \"\", :null => false\n    t.integer \"delay\"\n  end\n\n  add_index \"issue_relations\", [\"issue_from_id\"], :name => \"index_issue_relations_on_issue_from_id\"\n  add_index \"issue_relations\", [\"issue_to_id\"], :name => \"index_issue_relations_on_issue_to_id\"\n\n  create_table \"issue_statuses\", :force => true do |t|\n    t.string  \"name\",               :limit => 30, :default => \"\",    :null => false\n    t.boolean \"is_closed\",                        :default => false, :null => false\n    t.boolean \"is_default\",                       :default => false, :null => false\n    t.integer \"position\",                         :default => 1\n    t.integer \"default_done_ratio\"\n  end\n\n  add_index \"issue_statuses\", [\"is_closed\"], :name => \"index_issue_statuses_on_is_closed\"\n  add_index \"issue_statuses\", [\"is_default\"], :name => \"index_issue_statuses_on_is_default\"\n  add_index \"issue_statuses\", [\"position\"], :name => \"index_issue_statuses_on_position\"\n\n  create_table \"issue_votes\", :force => true do |t|\n    t.float    \"points\",                        :null => false\n    t.integer  \"user_id\",                       :null => false\n    t.integer  \"issue_id\",                      :null => false\n    t.integer  \"vote_type\",                     :null => false\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.boolean  \"isbinding\",  :default => false\n  end\n\n  add_index \"issue_votes\", [\"issue_id\"], :name => \"index_issue_votes_on_issue_id\"\n  add_index \"issue_votes\", [\"user_id\"], :name => \"index_issue_votes_on_user_id\"\n  add_index \"issue_votes\", [\"vote_type\"], :name => \"index_issue_votes_on_vote_type\"\n\n  create_table \"issues\", :force => true do |t|\n    t.integer  \"tracker_id\",           :default => 0,  :null => false\n    t.integer  \"project_id\",           :default => 0,  :null => false\n    t.string   \"subject\",              :default => \"\", :null => false\n    t.text     \"description\"\n    t.date     \"due_date\"\n    t.integer  \"status_id\",            :default => 0,  :null => false\n    t.integer  \"assigned_to_id\"\n    t.integer  \"author_id\",            :default => 0,  :null => false\n    t.integer  \"lock_version\",         :default => 0,  :null => false\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.date     \"start_date\"\n    t.integer  \"done_ratio\",           :default => 0,  :null => false\n    t.float    \"estimated_hours\"\n    t.date     \"expected_date\"\n    t.float    \"points\"\n    t.integer  \"pri\",                  :default => 0\n    t.integer  \"accept\",               :default => 0\n    t.integer  \"reject\",               :default => 0\n    t.integer  \"accept_total\",         :default => 0\n    t.integer  \"agree\",                :default => 0\n    t.integer  \"disagree\",             :default => 0\n    t.integer  \"agree_total\",          :default => 0\n    t.integer  \"retro_id\"\n    t.integer  \"accept_nonbind\",       :default => 0\n    t.integer  \"reject_nonbind\",       :default => 0\n    t.integer  \"accept_total_nonbind\", :default => 0\n    t.integer  \"agree_nonbind\",        :default => 0\n    t.integer  \"disagree_nonbind\",     :default => 0\n    t.integer  \"agree_total_nonbind\",  :default => 0\n    t.integer  \"points_nonbind\",       :default => 0\n    t.integer  \"pri_nonbind\",          :default => 0\n    t.integer  \"hourly_type_id\"\n    t.integer  \"num_hours\",            :default => 0\n    t.string   \"tags_copy\"\n  end\n\n  add_index \"issues\", [\"assigned_to_id\"], :name => \"index_issues_on_assigned_to_id\"\n  add_index \"issues\", [\"author_id\"], :name => \"index_issues_on_author_id\"\n  add_index \"issues\", [\"created_at\"], :name => \"index_issues_on_created_at\"\n  add_index \"issues\", [\"project_id\"], :name => \"issues_project_id\"\n  add_index \"issues\", [\"status_id\"], :name => \"index_issues_on_status_id\"\n  add_index \"issues\", [\"tracker_id\"], :name => \"index_issues_on_tracker_id\"\n\n  create_table \"journal_details\", :force => true do |t|\n    t.integer \"journal_id\",               :default => 0,  :null => false\n    t.string  \"property\",   :limit => 30, :default => \"\", :null => false\n    t.string  \"prop_key\",   :limit => 30, :default => \"\", :null => false\n    t.string  \"old_value\"\n    t.string  \"value\"\n  end\n\n  add_index \"journal_details\", [\"journal_id\"], :name => \"journal_details_journal_id\"\n\n  create_table \"journals\", :force => true do |t|\n    t.integer  \"journalized_id\",                 :default => 0,  :null => false\n    t.string   \"journalized_type\", :limit => 30, :default => \"\", :null => false\n    t.integer  \"user_id\",                        :default => 0,  :null => false\n    t.text     \"notes\"\n    t.datetime \"created_at\",                                     :null => false\n    t.datetime \"updated_at\"\n  end\n\n  add_index \"journals\", [\"created_at\"], :name => \"index_journals_on_created_at\"\n  add_index \"journals\", [\"journalized_id\", \"journalized_type\"], :name => \"journals_journalized_id\"\n  add_index \"journals\", [\"journalized_id\"], :name => \"index_journals_on_journalized_id\"\n  add_index \"journals\", [\"user_id\"], :name => \"index_journals_on_user_id\"\n\n  create_table \"mail_handlers\", :force => true do |t|\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"mails\", :force => true do |t|\n    t.integer  \"sender_id\"\n    t.integer  \"recipient_id\"\n    t.boolean  \"sender_deleted\",    :default => false\n    t.boolean  \"recipient_deleted\", :default => false\n    t.string   \"subject\"\n    t.text     \"body\"\n    t.datetime \"read_at\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"member_roles\", :force => true do |t|\n    t.integer  \"member_id\"\n    t.integer  \"role_id\"\n    t.integer  \"inherited_from\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  add_index \"member_roles\", [\"member_id\"], :name => \"index_member_roles_on_member_id\"\n  add_index \"member_roles\", [\"role_id\"], :name => \"index_member_roles_on_role_id\"\n\n  create_table \"members\", :force => true do |t|\n    t.integer  \"user_id\",           :default => 0,     :null => false\n    t.integer  \"project_id\",        :default => 0,     :null => false\n    t.datetime \"created_at\"\n    t.boolean  \"mail_notification\", :default => false, :null => false\n  end\n\n  add_index \"members\", [\"project_id\"], :name => \"index_members_on_project_id\"\n  add_index \"members\", [\"user_id\"], :name => \"index_members_on_user_id\"\n\n  create_table \"messages\", :force => true do |t|\n    t.integer  \"board_id\",                         :null => false\n    t.integer  \"parent_id\"\n    t.string   \"subject\",       :default => \"\",    :null => false\n    t.text     \"content\"\n    t.integer  \"author_id\"\n    t.integer  \"replies_count\", :default => 0,     :null => false\n    t.integer  \"last_reply_id\"\n    t.datetime \"created_at\",                       :null => false\n    t.datetime \"updated_at\",                       :null => false\n    t.boolean  \"locked\",        :default => false\n    t.integer  \"sticky\",        :default => 0\n  end\n\n  add_index \"messages\", [\"author_id\"], :name => \"index_messages_on_author_id\"\n  add_index \"messages\", [\"board_id\"], :name => \"messages_board_id\"\n  add_index \"messages\", [\"created_at\"], :name => \"index_messages_on_created_at\"\n  add_index \"messages\", [\"last_reply_id\"], :name => \"index_messages_on_last_reply_id\"\n  add_index \"messages\", [\"parent_id\"], :name => \"messages_parent_id\"\n\n  create_table \"motion_votes\", :force => true do |t|\n    t.integer  \"motion_id\"\n    t.integer  \"user_id\"\n    t.integer  \"points\"\n    t.boolean  \"isbinding\",  :default => false\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"motions\", :force => true do |t|\n    t.integer  \"project_id\"\n    t.string   \"title\"\n    t.text     \"description\"\n    t.text     \"params\"\n    t.integer  \"variation\",           :default => 0\n    t.integer  \"motion_type\",         :default => 2\n    t.integer  \"visibility_level\",    :default => 5\n    t.integer  \"binding_level\",       :default => 5\n    t.integer  \"state\",               :default => 0\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.date     \"ends_on\"\n    t.integer  \"topic_id\"\n    t.integer  \"author_id\"\n    t.integer  \"agree\",               :default => 0\n    t.integer  \"disagree\",            :default => 0\n    t.integer  \"agree_total\",         :default => 0\n    t.integer  \"agree_nonbind\",       :default => 0\n    t.integer  \"disagree_nonbind\",    :default => 0\n    t.integer  \"agree_total_nonbind\", :default => 0\n    t.integer  \"concerned_user_id\"\n  end\n\n  create_table \"news\", :force => true do |t|\n    t.integer  \"project_id\"\n    t.string   \"title\",          :limit => 60, :default => \"\", :null => false\n    t.string   \"summary\",                      :default => \"\"\n    t.text     \"description\"\n    t.integer  \"author_id\",                    :default => 0,  :null => false\n    t.datetime \"created_at\"\n    t.integer  \"comments_count\",               :default => 0,  :null => false\n  end\n\n  add_index \"news\", [\"author_id\"], :name => \"index_news_on_author_id\"\n  add_index \"news\", [\"created_at\"], :name => \"index_news_on_created_at\"\n  add_index \"news\", [\"project_id\"], :name => \"news_project_id\"\n\n  create_table \"notifications\", :force => true do |t|\n    t.integer  \"recipient_id\"\n    t.string   \"variation\"\n    t.text     \"params\"\n    t.integer  \"state\",        :default => 0\n    t.integer  \"source_id\"\n    t.datetime \"expiration\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.integer  \"sender_id\"\n    t.string   \"source_type\"\n  end\n\n  add_index \"notifications\", [\"recipient_id\"], :name => \"index_notifications_on_recipient_id\"\n\n  create_table \"open_id_authentication_associations\", :force => true do |t|\n    t.integer \"issued\"\n    t.integer \"lifetime\"\n    t.string  \"handle\"\n    t.string  \"assoc_type\"\n    t.binary  \"server_url\"\n    t.binary  \"secret\"\n  end\n\n  create_table \"open_id_authentication_nonces\", :force => true do |t|\n    t.integer \"timestamp\",  :null => false\n    t.string  \"server_url\"\n    t.string  \"salt\",       :null => false\n  end\n\n  create_table \"personal_welcomes\", :force => true do |t|\n    t.integer  \"user_id\"\n    t.datetime \"created_at\"\n  end\n\n  create_table \"plans\", :force => true do |t|\n    t.string   \"name\"\n    t.integer  \"code\"\n    t.text     \"description\"\n    t.float    \"amount\"\n    t.integer  \"storage_max\"\n    t.integer  \"contributor_max\"\n    t.integer  \"private_workstream_max\"\n    t.integer  \"public_workstream_max\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"plugin_schema_info\", :id => false, :force => true do |t|\n    t.string  \"plugin_name\"\n    t.integer \"version\"\n  end\n\n  create_table \"projects\", :force => true do |t|\n    t.string   \"name\",                     :limit => 50, :default => \"\",    :null => false\n    t.text     \"description\"\n    t.string   \"homepage\",                               :default => \"\"\n    t.boolean  \"is_public\",                              :default => true,  :null => false\n    t.integer  \"parent_id\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.string   \"identifier\",               :limit => 20\n    t.integer  \"status\",                                 :default => 1,     :null => false\n    t.integer  \"lft\"\n    t.integer  \"rgt\"\n    t.integer  \"enterprise_id\"\n    t.datetime \"last_item_updated_on\"\n    t.float    \"dpp\",                                    :default => 100.0\n    t.text     \"activity_line\"\n    t.boolean  \"volunteer\",                              :default => false\n    t.integer  \"owner_id\"\n    t.float    \"storage\",                                :default => 0.0\n    t.integer  \"issue_count\",                            :default => 0\n    t.integer  \"activity_total\"\n    t.string   \"invitation_token\"\n    t.integer  \"issue_count_sub\",                        :default => 0,     :null => false\n    t.datetime \"last_item_sub_updated_on\"\n  end\n\n  add_index \"projects\", [\"enterprise_id\"], :name => \"index_projects_on_enterprise_id\"\n  add_index \"projects\", [\"lft\"], :name => \"index_projects_on_lft\"\n  add_index \"projects\", [\"rgt\"], :name => \"index_projects_on_rgt\"\n\n  create_table \"projects_trackers\", :id => false, :force => true do |t|\n    t.integer \"project_id\", :default => 0, :null => false\n    t.integer \"tracker_id\", :default => 0, :null => false\n  end\n\n  add_index \"projects_trackers\", [\"project_id\", \"tracker_id\"], :name => \"projects_trackers_unique\", :unique => true\n  add_index \"projects_trackers\", [\"project_id\"], :name => \"projects_trackers_project_id\"\n\n  create_table \"queries\", :force => true do |t|\n    t.integer \"project_id\"\n    t.string  \"name\",          :default => \"\",    :null => false\n    t.text    \"filters\"\n    t.integer \"user_id\",       :default => 0,     :null => false\n    t.boolean \"is_public\",     :default => false, :null => false\n    t.text    \"column_names\"\n    t.text    \"sort_criteria\"\n    t.string  \"group_by\"\n  end\n\n  add_index \"queries\", [\"project_id\"], :name => \"index_queries_on_project_id\"\n  add_index \"queries\", [\"user_id\"], :name => \"index_queries_on_user_id\"\n\n  create_table \"quotes\", :force => true do |t|\n    t.integer  \"user_id\"\n    t.string   \"author\"\n    t.text     \"body\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"reportable_cache\", :force => true do |t|\n    t.string   \"model_name\",       :limit => 100,                  :null => false\n    t.string   \"report_name\",      :limit => 100,                  :null => false\n    t.string   \"grouping\",         :limit => 10,                   :null => false\n    t.string   \"aggregation\",      :limit => 10,                   :null => false\n    t.string   \"conditions\",       :limit => 100,                  :null => false\n    t.float    \"value\",                           :default => 0.0, :null => false\n    t.datetime \"reporting_period\",                                 :null => false\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  add_index \"reportable_cache\", [\"model_name\", \"report_name\", \"grouping\", \"aggregation\", \"conditions\", \"reporting_period\"], :name => \"name_model_grouping_aggregation_period\", :unique => true\n  add_index \"reportable_cache\", [\"model_name\", \"report_name\", \"grouping\", \"aggregation\", \"conditions\"], :name => \"name_model_grouping_agregation\"\n\n  create_table \"reputations\", :force => true do |t|\n    t.integer  \"user_id\"\n    t.integer  \"project_id\"\n    t.integer  \"reputation_type\"\n    t.float    \"value\"\n    t.string   \"params\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"retro_ratings\", :force => true do |t|\n    t.integer  \"rater_id\"\n    t.integer  \"ratee_id\"\n    t.float    \"score\"\n    t.integer  \"retro_id\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.integer  \"confidence\", :default => 100\n  end\n\n  add_index \"retro_ratings\", [\"ratee_id\"], :name => \"index_retro_ratings_on_ratee_id\"\n  add_index \"retro_ratings\", [\"rater_id\"], :name => \"index_retro_ratings_on_rater_id\"\n\n  create_table \"retros\", :force => true do |t|\n    t.integer  \"status_id\"\n    t.integer  \"project_id\"\n    t.datetime \"from_date\"\n    t.datetime \"to_date\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.integer  \"total_points\"\n  end\n\n  add_index \"retros\", [\"project_id\"], :name => \"index_retros_on_project_id\"\n\n  create_table \"roles\", :force => true do |t|\n    t.string  \"name\",        :limit => 30, :default => \"\",   :null => false\n    t.integer \"position\",                  :default => 1\n    t.boolean \"assignable\",                :default => true\n    t.integer \"builtin\",                   :default => 0,    :null => false\n    t.text    \"permissions\"\n    t.integer \"level\",                     :default => 3\n  end\n\n  create_table \"settings\", :force => true do |t|\n    t.string   \"name\",       :default => \"\", :null => false\n    t.text     \"value\"\n    t.datetime \"updated_at\"\n  end\n\n  add_index \"settings\", [\"name\"], :name => \"index_settings_on_name\"\n\n  create_table \"shares\", :force => true do |t|\n    t.float    \"amount\",                    :null => false\n    t.datetime \"expires\"\n    t.integer  \"variation\",  :default => 2, :null => false\n    t.datetime \"issued_on\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.integer  \"project_id\"\n    t.integer  \"owner_id\"\n  end\n\n  add_index \"shares\", [\"owner_id\"], :name => \"index_shares_on_owner_id\"\n  add_index \"shares\", [\"project_id\"], :name => \"index_shares_on_project_id\"\n\n  create_table \"taggings\", :force => true do |t|\n    t.integer  \"tag_id\"\n    t.integer  \"taggable_id\"\n    t.integer  \"tagger_id\"\n    t.string   \"tagger_type\"\n    t.string   \"taggable_type\"\n    t.string   \"context\"\n    t.datetime \"created_at\"\n    t.integer  \"project_id\"\n  end\n\n  add_index \"taggings\", [\"tag_id\"], :name => \"index_taggings_on_tag_id\"\n  add_index \"taggings\", [\"taggable_id\", \"taggable_type\", \"context\"], :name => \"index_taggings_on_taggable_id_and_taggable_type_and_context\"\n\n  create_table \"tags\", :force => true do |t|\n    t.string \"name\"\n  end\n\n  create_table \"todos\", :force => true do |t|\n    t.string   \"subject\"\n    t.integer  \"author_id\"\n    t.integer  \"owner_id\"\n    t.integer  \"issue_id\"\n    t.datetime \"completed_on\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.string   \"owner_login\"\n  end\n\n  add_index \"todos\", [\"author_id\"], :name => \"index_todos_on_author_id\"\n  add_index \"todos\", [\"owner_id\"], :name => \"index_todos_on_owner_id\"\n\n  create_table \"tokens\", :force => true do |t|\n    t.integer  \"user_id\",                  :default => 0,  :null => false\n    t.string   \"action\",     :limit => 30, :default => \"\", :null => false\n    t.string   \"value\",      :limit => 40, :default => \"\", :null => false\n    t.datetime \"created_at\",                               :null => false\n  end\n\n  add_index \"tokens\", [\"user_id\"], :name => \"index_tokens_on_user_id\"\n\n  create_table \"trackers\", :force => true do |t|\n    t.string  \"name\",               :limit => 30, :default => \"\",    :null => false\n    t.boolean \"is_in_chlog\",                      :default => false, :null => false\n    t.integer \"position\",                         :default => 1\n    t.boolean \"is_in_roadmap\",                    :default => true,  :null => false\n    t.boolean \"for_credits_module\",               :default => false\n  end\n\n  create_table \"tracks\", :force => true do |t|\n    t.integer  \"user_id\"\n    t.integer  \"code\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.string   \"ip\"\n  end\n\n  create_table \"user_preferences\", :force => true do |t|\n    t.integer \"user_id\",           :default => 0,    :null => false\n    t.text    \"others\"\n    t.boolean \"hide_mail\",         :default => true\n    t.string  \"time_zone\"\n    t.boolean \"active_only_jumps\", :default => true\n  end\n\n  add_index \"user_preferences\", [\"user_id\"], :name => \"index_user_preferences_on_user_id\"\n\n  create_table \"users\", :force => true do |t|\n    t.string   \"login\",                 :limit => 30, :default => \"\",    :null => false\n    t.string   \"hashed_password\",       :limit => 40, :default => \"\",    :null => false\n    t.string   \"firstname\",             :limit => 30, :default => \"\",    :null => false\n    t.string   \"lastname\",              :limit => 30, :default => \"\",    :null => false\n    t.string   \"mail\",                  :limit => 60, :default => \"\",    :null => false\n    t.boolean  \"mail_notification\",                   :default => true,  :null => false\n    t.boolean  \"admin\",                               :default => false, :null => false\n    t.integer  \"status\",                              :default => 1,     :null => false\n    t.datetime \"last_login_on\"\n    t.string   \"language\",              :limit => 5,  :default => \"\"\n    t.integer  \"auth_source_id\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.string   \"type\"\n    t.string   \"identity_url\"\n    t.string   \"activity_stream_token\"\n    t.string   \"identifier\"\n    t.integer  \"plan_id\",                             :default => 1\n    t.string   \"b_first_name\"\n    t.string   \"b_last_name\"\n    t.string   \"b_address1\"\n    t.string   \"b_zip\"\n    t.string   \"b_country\"\n    t.string   \"b_phone\"\n    t.string   \"b_ip_address\"\n    t.string   \"b_cc_last_four\"\n    t.string   \"b_cc_type\"\n    t.integer  \"b_cc_month\"\n    t.integer  \"b_cc_year\"\n    t.string   \"mail_hash\"\n    t.datetime \"trial_expires_on\"\n    t.boolean  \"active_subscription\",                 :default => false\n    t.datetime \"usage_over_at\"\n    t.datetime \"trial_expired_at\"\n  end\n\n  add_index \"users\", [\"auth_source_id\"], :name => \"index_users_on_auth_source_id\"\n  add_index \"users\", [\"id\", \"type\"], :name => \"index_users_on_id_and_type\"\n\n  create_table \"votes\", :force => true do |t|\n    t.boolean  \"vote\",          :default => false\n    t.integer  \"voteable_id\",                      :null => false\n    t.string   \"voteable_type\",                    :null => false\n    t.integer  \"voter_id\"\n    t.string   \"voter_type\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  add_index \"votes\", [\"voteable_id\", \"voteable_type\", \"voter_id\", \"voter_type\"], :name => \"uniq_one_vote_only\", :unique => true\n  add_index \"votes\", [\"voteable_id\", \"voteable_type\"], :name => \"fk_voteables\"\n  add_index \"votes\", [\"voter_id\", \"voter_type\"], :name => \"fk_voters\"\n\n  create_table \"watchers\", :force => true do |t|\n    t.string  \"watchable_type\", :default => \"\", :null => false\n    t.integer \"watchable_id\",   :default => 0,  :null => false\n    t.integer \"user_id\"\n  end\n\n  add_index \"watchers\", [\"user_id\", \"watchable_type\"], :name => \"watchers_user_id_type\"\n  add_index \"watchers\", [\"user_id\"], :name => \"index_watchers_on_user_id\"\n  add_index \"watchers\", [\"watchable_id\", \"watchable_type\"], :name => \"index_watchers_on_watchable_id_and_watchable_type\"\n\n  create_table \"wiki_content_versions\", :force => true do |t|\n    t.integer  \"wiki_content_id\",                              :null => false\n    t.integer  \"page_id\",                                      :null => false\n    t.integer  \"author_id\"\n    t.binary   \"data\"\n    t.string   \"compression\",     :limit => 6, :default => \"\"\n    t.string   \"comments\",                     :default => \"\"\n    t.datetime \"updated_at\",                                   :null => false\n    t.integer  \"version\",                                      :null => false\n  end\n\n  add_index \"wiki_content_versions\", [\"updated_at\"], :name => \"index_wiki_content_versions_on_updated_at\"\n  add_index \"wiki_content_versions\", [\"wiki_content_id\"], :name => \"wiki_content_versions_wcid\"\n\n  create_table \"wiki_contents\", :force => true do |t|\n    t.integer  \"page_id\",                    :null => false\n    t.integer  \"author_id\"\n    t.text     \"text\"\n    t.string   \"comments\",   :default => \"\"\n    t.datetime \"updated_at\",                 :null => false\n    t.integer  \"version\",                    :null => false\n  end\n\n  add_index \"wiki_contents\", [\"author_id\"], :name => \"index_wiki_contents_on_author_id\"\n  add_index \"wiki_contents\", [\"page_id\"], :name => \"wiki_contents_page_id\"\n\n  create_table \"wiki_pages\", :force => true do |t|\n    t.integer  \"wiki_id\",                       :null => false\n    t.string   \"title\",                         :null => false\n    t.datetime \"created_at\",                    :null => false\n    t.boolean  \"protected\",  :default => false, :null => false\n    t.integer  \"parent_id\"\n  end\n\n  add_index \"wiki_pages\", [\"parent_id\"], :name => \"index_wiki_pages_on_parent_id\"\n  add_index \"wiki_pages\", [\"title\", \"wiki_id\"], :name => \"wiki_pages_wiki_id_title\"\n  add_index \"wiki_pages\", [\"wiki_id\"], :name => \"index_wiki_pages_on_wiki_id\"\n\n  create_table \"wiki_redirects\", :force => true do |t|\n    t.integer  \"wiki_id\",      :null => false\n    t.string   \"title\"\n    t.string   \"redirects_to\"\n    t.datetime \"created_at\",   :null => false\n  end\n\n  add_index \"wiki_redirects\", [\"title\", \"wiki_id\"], :name => \"wiki_redirects_wiki_id_title\"\n  add_index \"wiki_redirects\", [\"wiki_id\"], :name => \"index_wiki_redirects_on_wiki_id\"\n\n  create_table \"wikis\", :force => true do |t|\n    t.integer \"project_id\",                :null => false\n    t.string  \"start_page\",                :null => false\n    t.integer \"status\",     :default => 1, :null => false\n  end\n\n  add_index \"wikis\", [\"project_id\"], :name => \"wikis_project_id\"\n\n  create_table \"workflows\", :force => true do |t|\n    t.integer \"tracker_id\",    :default => 0, :null => false\n    t.integer \"old_status_id\", :default => 0, :null => false\n    t.integer \"new_status_id\", :default => 0, :null => false\n    t.integer \"role_id\",       :default => 0, :null => false\n  end\n\n  add_index \"workflows\", [\"new_status_id\"], :name => \"index_workflows_on_new_status_id\"\n  add_index \"workflows\", [\"old_status_id\", \"role_id\", \"tracker_id\"], :name => \"wkfs_role_tracker_old_status\"\n  add_index \"workflows\", [\"old_status_id\"], :name => \"index_workflows_on_old_status_id\"\n  add_index \"workflows\", [\"role_id\"], :name => \"index_workflows_on_role_id\"\n\nend\n"
  },
  {
    "path": "db/seeds.rb",
    "content": "# Autogenerated by the db:seed:dump task\n# Do not hesitate to tweak this to your needs\n\n# TODO: remove 'is_' from columns and variables\n\nu = User.new(:firstname => \"admin\", :mail => \"admin@bettermeans.com\")\nu.password = 'adminadmin'\nu.password_confirmation = 'adminadmin'\nu.login = 'admin'\nu.save\n\n# create anonymous user\nUser.anonymous\n\nTracker.delete_all\ntrackers = Tracker.create([\n  {\n    :position => 1,\n    :name => \"Feature\",\n    :is_in_roadmap => true,\n    :is_in_chlog => false,\n    :for_credits_module => false\n  }, {\n    :position => 2,\n    :name => \"Chore\",\n    :is_in_roadmap => true,\n    :is_in_chlog => false,\n    :for_credits_module => false\n  }, {\n    :position => 3,\n    :name => \"Bug\",\n    :is_in_roadmap => true,\n    :is_in_chlog => false,\n    :for_credits_module => false\n  }, {\n    :position => 4,\n    :name => \"Gift\",\n    :is_in_roadmap => true,\n    :is_in_chlog => false,\n    :for_credits_module => true\n  }, {\n    :position => 5,\n    :name => \"Expense\",\n    :is_in_roadmap => true,\n    :is_in_chlog => false,\n    :for_credits_module => true\n  }, {\n    :position => 6,\n    :name => \"Recurring\",\n    :is_in_roadmap => true,\n    :is_in_chlog => false,\n    :for_credits_module => false\n  }, {\n    :position => 7,\n    :name => \"Hourly\",\n    :is_in_roadmap => true,\n    :is_in_chlog => false,\n    :for_credits_module => true\n  }\n])\n\nIssueStatus.delete_all\nissue_statuses = IssueStatus.create([\n  {\n    :position => 3,\n    :name => \"Open\",\n    :is_default => false,\n    :default_done_ratio => nil,\n    :is_closed => false\n  }, {\n    :position => 4,\n    :name => \"Committed\",\n    :is_default => false,\n    :default_done_ratio => nil,\n    :is_closed => false\n  }, {\n    :position => 7,\n    :name => \"Blocked\",\n    :is_default => false,\n    :default_done_ratio => nil,\n    :is_closed => false\n  }, {\n    :position => 5,\n    :name => \"Done\",\n    :is_default => false,\n    :default_done_ratio => nil,\n    :is_closed => true\n  }, {\n    :position => 6,\n    :name => \"Canceled\",\n    :is_default => false,\n    :default_done_ratio => nil,\n    :is_closed => true\n  }, {\n    :position => 1,\n    :name => \"New\",\n    :is_default => true,\n    :default_done_ratio => nil,\n    :is_closed => false\n  }, {\n    :position => 2,\n    :name => \"Estimate\",\n    :is_default => false,\n    :default_done_ratio => nil,\n    :is_closed => false\n  }, {\n    :position => 8,\n    :name => \"Archived\",\n    :is_default => false,\n    :default_done_ratio => nil,\n    :is_closed => true\n  }, {\n    :position => 9,\n    :name => \"Accepted\",\n    :is_default => false,\n    :default_done_ratio => nil,\n    :is_closed => true\n  }, {\n    :position => 10,\n    :name => \"Rejected\",\n    :is_default => false,\n    :default_done_ratio => nil,\n    :is_closed => false\n  }\n])\n\nEnumeration.delete_all\nenumerations = Enumeration.create([\n  {\n    :position => 1,\n    :name => \"\",\n    :project_id => nil,\n    :is_default => false,\n    :type => nil,\n    :parent_id => nil,\n    :opt => \"\",\n    :active => true\n  }\n])\n\nRole.delete_all\nroles = Role.create([\n  {\n    :position => 5,\n    :name => \"Non member\",\n    :level => 0,\n    :builtin => 1,\n    :permissions => [\n      :add_project,\n      :credits,\n      :join_from_generic_invitation,\n      :add_messages,\n      :view_credits,\n      :view_issues,\n      :add_issues,\n      :edit_issues,\n      :add_issue_notes,\n      :edit_own_issue_notes,\n      :pull_commitment,\n      :estimate_issues,\n      :accept_issues,\n      :start_issues,\n      :view_gantt,\n      :view_issue_watchers,\n      :browse_motion,\n      :vote_motion,\n      :comment_news,\n      :view_wiki_pages,\n      :view_wiki_edits\n    ],\n    :assignable => true\n  }, {\n    :position => 99,\n    :name => \"Anonymous\",\n    :level => 0,\n    :builtin => 2,\n    :permissions => [\n      :view_documents,\n      :view_files,\n      :view_issues,\n      :view_member_roles,\n      :view_wiki_pages,\n      :view_wiki_edits\n    ],\n    :assignable => true\n  }, {\n    :position => 0,\n    :name => \"Administrator\",\n    :level => 1,\n    :builtin => 3,\n    :permissions => [\n      :add_project,\n      :add_subprojects,\n      :edit_project,\n      :select_project_modules,\n      :manage_members,\n      :credits,\n      :send_invitations,\n      :manage_invitations,\n      :manage_boards,\n      :add_messages,\n      :edit_messages,\n      :edit_own_messages,\n      :delete_messages,\n      :delete_own_messages,\n      :view_credits,\n      :manage_documents,\n      :view_documents,\n      :manage_files,\n      :view_files,\n      :view_issues,\n      :add_issues,\n      :edit_issues,\n      :manage_issue_relations,\n      :add_issue_notes,\n      :edit_issue_notes,\n      :edit_own_issue_notes,\n      :move_issues,\n      :delete_issues,\n      :push_commitment,\n      :pull_commitment,\n      :view_commit_requests,\n      :view_member_roles,\n      :estimate_issues,\n      :accept_issues,\n      :start_issues,\n      :manage_public_queries,\n      :save_queries,\n      :view_gantt,\n      :view_calendar,\n      :view_issue_watchers,\n      :add_issue_watchers,\n      :manage_motion,\n      :browse_motion,\n      :create_motion,\n      :vote_motion,\n      :manage_news,\n      :comment_news,\n      :manage_wiki,\n      :rename_wiki_pages,\n      :delete_wiki_pages,\n      :view_wiki_pages,\n      :view_wiki_edits,\n      :edit_wiki_pages,\n      :delete_wiki_pages_attachments,\n      :protect_wiki_pages\n    ],\n    :assignable => true\n  }, {\n    :position => 2,\n    :name => \"Core Team\",\n    :level => 1,\n    :builtin => 4,\n    :permissions => [\n      :add_project,\n      :add_subprojects,\n      :send_invitations,\n      :manage_invitations,\n      :transfer_credits,\n      :join_from_generic_invitation,\n      :manage_boards,\n      :add_messages,\n      :edit_own_messages,\n      :view_credits,\n      :enable_disable_credits,\n      :manage_documents,\n      :view_documents,\n      :manage_files,\n      :view_files,\n      :view_issues,\n      :add_issues,\n      :edit_issues,\n      :manage_issue_relations,\n      :add_issue_notes,\n      :edit_issue_notes,\n      :edit_own_issue_notes,\n      :move_issues,\n      :push_commitment,\n      :pull_commitment,\n      :view_commit_requests,\n      :view_member_roles,\n      :estimate_issues,\n      :accept_issues,\n      :start_issues,\n      :save_queries,\n      :view_gantt,\n      :view_calendar,\n      :view_issue_watchers,\n      :add_issue_watchers,\n      :manage_motion,\n      :browse_motion,\n      :create_motion,\n      :vote_motion,\n      :manage_news,\n      :comment_news,\n      :manage_wiki,\n      :rename_wiki_pages,\n      :delete_wiki_pages,\n      :view_wiki_pages,\n      :view_wiki_edits,\n      :edit_wiki_pages,\n      :delete_wiki_pages_attachments,\n      :protect_wiki_pages\n    ],\n    :assignable => true\n  }, {\n    :position => 10,\n    :name => \"Active\",\n    :level => 2,\n    :builtin => 7,\n    :permissions => nil,\n    :assignable => true\n  },\n  {\n    :position => 3,\n    :name => \"Member\",\n    :level => 1,\n    :builtin => 8,\n    :permissions => [\n      :add_project,\n      :add_subprojects,\n      :send_invitations,\n      :manage_invitations,\n      :transfer_credits,\n      :join_from_generic_invitation,\n      :add_messages,\n      :edit_own_messages,\n      :view_credits,\n      :enable_disable_credits,\n      :view_documents,\n      :view_files,\n      :view_issues,\n      :add_issues,\n      :edit_issues,\n      :manage_issue_relations,\n      :add_issue_notes,\n      :edit_issue_notes,\n      :edit_own_issue_notes,\n      :push_commitment,\n      :pull_commitment,\n      :view_commit_requests,\n      :view_member_roles,\n      :estimate_issues,\n      :accept_issues,\n      :start_issues,\n      :manage_public_queries,\n      :save_queries,\n      :view_gantt,\n      :view_calendar,\n      :view_issue_watchers,\n      :browse_motion,\n      :create_motion,\n      :vote_motion,\n      :comment_news,\n      :rename_wiki_pages,\n      :view_wiki_pages,\n      :view_wiki_edits,\n      :edit_wiki_pages\n    ],\n    :assignable => true\n  }, {\n    :position => 1,\n    :name => \"Board\",\n    :level => 1,\n    :builtin => 9,\n    :permissions => [\n      :add_project,\n      :add_subprojects,\n      :manage_members,\n      :transfer_credits,\n      :join_from_generic_invitation,\n      :add_messages,\n      :view_credits,\n      :enable_disable_credits,\n      :view_issues,\n      :add_issues,\n      :add_issue_notes,\n      :edit_own_issue_notes,\n      :pull_commitment,\n      :start_issues,\n      :view_gantt,\n      :view_issue_watchers,\n      :manage_motion,\n      :browse_motion,\n      :create_motion,\n      :vote_motion,\n      :comment_news,\n      :view_wiki_pages,\n      :view_wiki_edits,\n      :edit_wiki_pages\n    ],\n    :assignable => true\n  }, {\n    :position => 11,\n    :name => \"Clearance\",\n    :level => 2,\n    :builtin => 10,\n    :permissions => nil,\n    :assignable => true\n  }, {\n    :position => 4,\n    :name => \"Contributor\",\n    :level => 1,\n    :builtin => 5,\n    :permissions => [\n      :add_project,\n      :transfer_credits,\n      :join_from_generic_invitation,\n      :add_messages,\n      :view_credits,\n      :enable_disable_credits,\n      :view_documents,\n      :view_files,\n      :view_issues,\n      :add_issues,\n      :edit_issues,\n      :add_issue_notes,\n      :edit_own_issue_notes,\n      :pull_commitment,\n      :view_commit_requests,\n      :estimate_issues,\n      :accept_issues,\n      :start_issues,\n      :save_queries,\n      :view_gantt,\n      :view_issue_watchers,\n      :browse_motion,\n      :vote_motion,\n      :comment_news,\n      :view_wiki_pages,\n      :view_wiki_edits,\n      :edit_wiki_pages\n    ],\n    :assignable => true\n  }\n])\n\nPlan.delete_all\nplans = Plan.create([\n  {\n    :name => \"Free\",\n    :created_at => nil,\n    :code => 0,\n    :updated_at => nil,\n    :storage_max => 1,\n    :contributor_max => 0,\n    :amount => 0.0,\n    :public_workstream_max => -1,\n    :private_workstream_max => 0,\n    :description => \"Free plan\"\n  }, {\n    :name => \"Basic\",\n    :created_at => nil,\n    :code => 1,\n    :updated_at => nil,\n    :storage_max => 1,\n    :contributor_max => 5,\n    :amount => 25.0,\n    :public_workstream_max => -1,\n    :private_workstream_max => 10,\n    :description => \"Best for small projects\"\n  }, {\n    :name => \"Better\",\n    :created_at => nil,\n    :code => 2,\n    :updated_at => nil,\n    :storage_max => 5,\n    :contributor_max => 20,\n    :amount => 50.0,\n    :public_workstream_max => -1,\n    :private_workstream_max => 25,\n    :description => \"For medium-sized projects\"\n  }, {\n    :name => \"Super\",\n    :created_at => nil,\n    :code => 3,\n    :updated_at => nil,\n    :storage_max => 50,\n    :contributor_max => 100,\n    :amount => 100.0,\n    :public_workstream_max => -1,\n    :private_workstream_max => 60,\n    :description => \"Our most popular plan\"\n  }, {\n    :name => \"Go Nuts!\",\n    :created_at => nil,\n    :code => 4,\n    :updated_at => nil,\n    :storage_max => 100,\n    :contributor_max => -1,\n    :amount => 200.0,\n    :public_workstream_max => -1,\n    :private_workstream_max => -1,\n    :description => \"Why limit yourself?\"\n  }\n])\n\nSetting.delete_all\nsettings = Setting.create([\n  {\n    :name => \"host_name\",\n    :updated_at => \"Mon Aug 24 22:30:20 -0700 2009\",\n    :value => \"rm.bettermeans.com\"\n  }, {\n    :name => \"date_format\",\n    :updated_at => \"Mon Aug 24 20:28:44 -0700 2009\",\n    :value => \"\"\n  }, {\n    :name => \"feeds_limit\",\n    :updated_at => \"Mon Aug 24 20:28:44 -0700 2009\",\n    :value => \"15\"\n  }, {\n    :name => \"default_language\",\n    :updated_at => \"Mon Aug 24 20:28:44 -0700 2009\",\n    :value => \"en\"\n  }, {\n    :name => \"welcome_text\",\n    :updated_at => \"Thu May 20 12:33:28 -0700 2010\",\n    :value => \"Welcome to BetterMeans! \\r\\n\\r\\nWe're currently running a \" <<\n              \"pre-beta release of our web platform.\\r\\nPlease report all \" <<\n              \"bugs in the web platform workstream of the bettermeans \" <<\n              \"enterprise\"\n  }, {\n    :name => \"diff_max_lines_displayed\",\n    :updated_at => \"Mon Aug 24 20:28:44 -0700 2009\",\n    :value => \"1500\"\n  }, {\n    :name => \"app_title\",\n    :updated_at => \"Thu May 20 12:33:28 -0700 2010\",\n    :value => \"BetterMeans\"\n  }, {\n    :name => \"activity_days_default\",\n    :updated_at => \"Wed Jun 02 13:43:47 -0700 2010\",\n    :value => \"5\"\n  }, {\n    :name => \"per_page_options\",\n    :updated_at => \"Mon Aug 24 20:28:44 -0700 2009\",\n    :value => \"25, 50, 100\"\n  }, {\n    :name => \"wiki_compression\",\n    :updated_at => \"Thu Feb 11 20:49:21 -0800 2010\",\n    :value => \"\"\n  }, {\n    :name => \"attachment_max_size\",\n    :updated_at => \"Wed Oct 14 14:50:55 -0700 2009\",\n    :value => \"51200\"\n  }, {\n    :name => \"time_format\",\n    :updated_at => \"Mon Aug 24 20:28:45 -0700 2009\",\n    :value => \"\"\n  }, {\n    :name => \"ui_theme\",\n    :updated_at => \"Wed Feb 24 03:14:19 -0800 2010\",\n    :value => \"bettermeans\"\n  }, {\n    :name => \"text_formatting\",\n    :updated_at => \"Mon Aug 24 20:28:45 -0700 2009\",\n    :value => \"textile\"\n  }, {\n    :name => \"user_format\",\n    :updated_at => \"Mon Aug 24 20:28:45 -0700 2009\",\n    :value => \"firstname_lastname\"\n  }, {\n    :name => \"gravatar_enabled\",\n    :updated_at => \"Mon Aug 24 20:28:45 -0700 2009\",\n    :value => \"1\"\n  }, {\n    :name => \"protocol\",\n    :updated_at => \"Mon Aug 24 20:28:45 -0700 2009\",\n    :value => \"http\"\n  }, {\n    :name => \"login_required\",\n    :updated_at => \"Thu Jun 03 17:01:27 -0700 2010\",\n    :value => \"0\"\n  }, {\n    :name => \"autologin\",\n    :updated_at => \"Mon Aug 24 20:31:26 -0700 2009\",\n    :value => \"30\"\n  }, {\n    :name => \"lost_password\",\n    :updated_at => \"Mon Aug 24 20:31:26 -0700 2009\",\n    :value => \"1\"\n  }, {\n    :name => \"self_registration\",\n    :updated_at => \"Wed Jun 30 14:21:01 -0700 2010\",\n    :value => \"3\"\n  }, {\n    :name => \"bcc_recipients\",\n    :updated_at => \"Sun Jun 06 01:10:02 -0700 2010\",\n    :value => \"1\"\n  }, {\n    :name => \"plain_text_mail\",\n    :updated_at => \"Mon Aug 24 21:01:35 -0700 2009\",\n    :value => \"0\"\n  }, {\n    :name => \"emails_footer\",\n    :updated_at => \"Mon Aug 24 22:44:05 -0700 2009\",\n    :value => \"You have received this notification because you have either \" <<\n              \"subscribed to it, or are involved in it.\\r\\nTo change your \" <<\n              \"notification preferences, please click here: \" <<\n              \"http://rm.bettermeans.com/my/account\"\n  }, {\n    :name => \"mail_from\",\n    :updated_at => \"Sun Jun 06 01:14:45 -0700 2010\",\n    :value => \"BetterMeans Admin<administrator@bettermeans.com>\"\n  }, {\n    :name => \"notified_events\",\n    :updated_at => \"Thu May 27 22:52:27 -0700 2010\",\n    :value => %w[ issue_added issue_updated news_added message_posted ].to_yaml\n  }, {\n    :name => \"default_projects_public\",\n    :updated_at => \"Tue Aug 25 00:27:38 -0700 2009\",\n    :value => \"1\"\n  }, {\n    :name => \"sequential_project_identifiers\",\n    :updated_at => \"Mon Aug 24 22:43:15 -0700 2009\",\n    :value => \"1\"\n  }, {\n    :name => \"mail_handler_api_key\",\n    :updated_at => \"Mon Aug 24 22:44:29 -0700 2009\",\n    :value => \"gX7EBfIyc9orWdXzQ9vM\"\n  }, {\n    :name => \"mail_handler_api_enabled\",\n    :updated_at => \"Mon Aug 24 22:44:29 -0700 2009\",\n    :value => \"1\"\n  }, {\n    :name => \"display_subprojects_issues\",\n    :updated_at => \"Tue Aug 25 00:17:45 -0700 2009\",\n    :value => \"1\"\n  }, {\n    :name => \"issues_export_limit\",\n    :updated_at => \"Tue Aug 25 00:17:45 -0700 2009\",\n    :value => \"500\"\n  }, {\n    :name => \"cross_project_issue_relations\",\n    :updated_at => \"Wed Oct 14 14:49:39 -0700 2009\",\n    :value => \"1\"\n  }, {\n    :name => \"issue_list_default_columns\",\n    :updated_at => \"Mon Dec 14 16:37:33 -0800 2009\",\n    :value => %w[ status subject assigned_to fixed_version ].to_yaml\n  }, {\n    :name => \"new_project_user_role_id\",\n    :updated_at => \"Tue Jun 08 15:20:43 -0700 2010\",\n    :value => \"7\"\n  }, {\n    :name => \"file_max_size_displayed\",\n    :updated_at => \"Wed Oct 14 14:50:55 -0700 2009\",\n    :value => \"512\"\n  }, {\n    :name => \"openid\",\n    :updated_at => \"Thu Feb 11 20:51:10 -0800 2010\",\n    :value => \"0\"\n  }, {\n    :name => \"password_min_length\",\n    :updated_at => \"Thu Jun 03 17:01:41 -0700 2010\",\n    :value => \"6\"\n  }, {\n    :name => \"default_projects_modules\",\n    :updated_at => \"Mon Dec 14 16:36:57 -0800 2009\",\n    :value => %w{ issue_tracking news documents files wiki boards }.to_yaml\n  }, {\n    :name => \"rest_api_enabled\",\n    :updated_at => \"Thu Feb 11 20:51:10 -0800 2010\",\n    :value => \"0\"\n  }, {\n    :name => \"gravatar_default\",\n    :updated_at => \"Thu Feb 11 20:52:56 -0800 2010\",\n    :value => \"identicon\"\n  }, {\n    :name => \"start_of_week\",\n    :updated_at => \"Thu Feb 11 20:52:56 -0800 2010\",\n    :value => \"\"\n  }, {\n    :name => \"commit_fix_keywords\",\n    :updated_at => \"Thu Feb 11 20:53:31 -0800 2010\",\n    :value => \"fixes,closes\"\n  }, {\n    :name => \"enabled_scm\",\n    :updated_at => \"Thu Feb 11 20:53:31 -0800 2010\",\n    :value => %w[ Subversion Darcs Mercurial Cvs Bazaar Git ].to_yaml\n  }, {\n    :name => \"commit_fix_status_id\",\n    :updated_at => \"Thu Feb 11 20:53:31 -0800 2010\",\n    :value => \"0\"\n  }, {\n    :name => \"sys_api_enabled\",\n    :updated_at => \"Thu Feb 11 20:53:31 -0800 2010\",\n    :value => \"0\"\n  }, {\n    :name => \"repositories_encodings\",\n    :updated_at => \"Thu Feb 11 20:53:31 -0800 2010\",\n    :value => \"\"\n  }, {\n    :name => \"commit_fix_done_ratio\",\n    :updated_at => \"Thu Feb 11 20:53:31 -0800 2010\",\n    :value => \"100\"\n  }, {\n    :name => \"commit_ref_keywords\",\n    :updated_at => \"Thu Feb 11 20:53:31 -0800 2010\",\n    :value => \"refs,references,IssueID\"\n  }, {\n    :name => \"repository_log_display_limit\",\n    :updated_at => \"Thu Feb 11 20:53:32 -0800 2010\",\n    :value => \"100\"\n  }, {\n    :name => \"commit_logs_encoding\",\n    :updated_at => \"Thu Feb 11 20:53:32 -0800 2010\",\n    :value => \"UTF-8\"\n  }, {\n    :name => \"autofetch_changesets\",\n    :updated_at => \"Thu Feb 11 20:53:32 -0800 2010\",\n    :value => \"1\"\n  }, {\n    :name => \"mail_handler_body_delimiters\",\n    :updated_at => \"Fri May 28 02:09:56 -0700 2010\",\n    :value => \"\"\n  }\n])\n"
  },
  {
    "path": "deploy",
    "content": "echo pushing to heroku...\ngit push heroku\n\necho pushing to github...\ngit push origin master\n\necho migrating db...\nheroku rake db:migrate\n\necho backing up db after new code...\nheroku pgbackups\nheroku rake backup\n\n"
  },
  {
    "path": "doc/COPYING",
    "content": "Copyright (C) 2006-2009  \nShereef Bishay\nBetterMeans\nAll Rights Reserved"
  },
  {
    "path": "doc/INSTALL",
    "content": "== Redmine installation\n\nRedmine - project management software\nCopyright (C) 2006-2011  See readme for details and license\nhttp://www.redmine.org/\n\n\n== Requirements\n\n* Ruby on Rails 2.2.2\n* A database:\n  * MySQL (tested with MySQL 5)\n  * PostgreSQL (tested with PostgreSQL 8.1)\n  * SQLite (tested with SQLite 3)\n\nOptional:\n* SVN binaries >= 1.3 (needed for repository browsing, must be available in PATH)\n* RMagick (gantt export to png)\n\n== Installation\n\n1. Uncompress the program archive\n   \n2. Create an empty database: \"redmine\" for example\n\n3. Configure database parameters in config/database.yml\n   for \"production\" environment (default database is MySQL)\n\n4. Create the database structure. Under the application main directory:\n   rake db:migrate RAILS_ENV=\"production\"\n   It will create tables and an administrator account.\n   \n5. Generate a session store secret\n   Redmine stores session data in cookies by default, which requires\n   a secret to be generated. Run:\n   rake config/initializers/session_store.rb\n\n6. Setting up permissions\n   The user who runs Redmine must have write permission on the following\n   subdirectories: files, log, tmp (create the last one if not present).\n\n   Assuming you run Redmine with a user named redmine:\n     mkdir tmp\n     sudo chown -R redmine:redmine files log tmp\n     sudo chmod -R 755 files log tmp\n\n7. Test the installation by running WEBrick web server:\n   ruby script/server -e production   \n  \n   Once WEBrick has started, point your browser to http://localhost:3000/\n   You should now see the application welcome page\n\n8. Use default administrator account to log in:\n   login: admin\n   password: admin\n   \n   Go to \"Administration\" to load the default configuration data (roles, \n   trackers, statuses, workflow) and adjust application settings\n\n\n== Email delivery Configuration\n\nCopy config/email.yml.example to config/email.yml and edit this file\nto adjust your SMTP settings.\nDon't forget to restart the application after any change to this file.\n\nPlease do not enter your SMTP settings in environment.rb.\n"
  },
  {
    "path": "doc/README_FOR_APP",
    "content": "= BetterMeans\n\nBetterMeans is software that allows enterprises to run in a new decentralized way.\n\nMore information at: http://bettermeans.com"
  },
  {
    "path": "doc/RUNNING_TESTS",
    "content": "Installing gems for testing\n===========================\n\nRun `rake gems RAILS_ENV=test` to list the required gems.  Run \n`rake gems:install RAILS_ENV=test` to install any missing gems.\n\nRunning Tests\n=============\n\nRun `rake --tasks test` to see available tests.\n`rake test` will run the entire testsuite.\n\nBefore running `rake test` you need to configure both development\nand test databases.\n\nCreating test repositories\n===================\n\nRedmine supports a wide array of different version control systems.\nTo test the support, a test repository needs to be created for each of those.\n\nRun `rake --tasks test:scm:setup` for a list of available test-repositories or\nrun `rake test:scm:setup:all` to set up all of them\n\n"
  },
  {
    "path": "extra/mail_handler/rdm-mailhandler.rb",
    "content": "#!/usr/bin/env ruby\n\n# == Synopsis\n#\n# Reads an email from standard input and forward it to a Redmine server\n# through a HTTP request.\n#\n# == Usage\n#\n#    rdm-mailhandler [options] --url=<Redmine URL> --key=<API key>\n#\n# == Arguments\n#\n#   -u, --url                      URL of the Redmine server\n#   -k, --key                      Redmine API key\n#\n# General options:\n#       --unknown-user=ACTION      how to handle emails from an unknown user\n#                                  ACTION can be one of the following values:\n#                                  ignore: email is ignored (default)\n#                                  accept: accept as anonymous user\n#                                  create: create a user account\n#       --no-permission-check      disable permission checking when receiving\n#                                  the email\n#   -h, --help                     show this help\n#   -v, --verbose                  show extra information\n#   -V, --version                  show version information and exit\n#\n# Issue attributes control options:\n#   -p, --project=PROJECT          identifier of the target project\n#   -s, --status=STATUS            name of the target status\n#   -t, --tracker=TRACKER          name of the target tracker\n#       --category=CATEGORY        name of the target category\n#       --priority=PRIORITY        name of the target priority\n#   -o, --allow-override=ATTRS     allow email content to override attributes\n#                                  specified by previous options\n#                                  ATTRS is a comma separated list of attributes\n#\n# == Examples\n# No project specified. Emails MUST contain the 'Project' keyword:\n#\n#   rdm-mailhandler --url http://redmine.domain.foo --key secret\n#\n# Fixed project and default tracker specified, but emails can override\n# both tracker and priority attributes using keywords:\n#\n#   rdm-mailhandler --url https://domain.foo/redmine --key secret \\\\\n#                   --project foo \\\\\n#                   --tracker bug \\\\\n#                   --allow-override tracker,priority\n\nrequire 'net/http'\nrequire 'net/https'\nrequire 'uri'\nrequire 'getoptlong'\nrequire 'rdoc/usage'\n\nmodule Net\n  class HTTPS < HTTP\n    def self.post_form(url, params)\n      request = Post.new(url.path)\n      request.form_data = params\n      request.basic_auth url.user, url.password if url.user\n      http = new(url.host, url.port)\n      http.use_ssl = (url.scheme == 'https')\n      http.start {|h| h.request(request) }\n    end\n  end\nend\n\nclass RedmineMailHandler\n  VERSION = '0.1'\n\n  attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :no_permission_check, :url, :key\n\n  def initialize\n    self.issue_attributes = {}\n\n    opts = GetoptLong.new(\n      [ '--help',           '-h', GetoptLong::NO_ARGUMENT ],\n      [ '--version',        '-V', GetoptLong::NO_ARGUMENT ],\n      [ '--verbose',        '-v', GetoptLong::NO_ARGUMENT ],\n      [ '--url',            '-u', GetoptLong::REQUIRED_ARGUMENT ],\n      [ '--key',            '-k', GetoptLong::REQUIRED_ARGUMENT],\n      [ '--project',        '-p', GetoptLong::REQUIRED_ARGUMENT ],\n      [ '--status',         '-s', GetoptLong::REQUIRED_ARGUMENT ],\n      [ '--tracker',        '-t', GetoptLong::REQUIRED_ARGUMENT],\n      [ '--category',             GetoptLong::REQUIRED_ARGUMENT],\n      [ '--priority',             GetoptLong::REQUIRED_ARGUMENT],\n      [ '--allow-override', '-o', GetoptLong::REQUIRED_ARGUMENT],\n      [ '--unknown-user',         GetoptLong::REQUIRED_ARGUMENT],\n      [ '--no-permission-check',  GetoptLong::NO_ARGUMENT]\n    )\n\n    opts.each do |opt, arg|\n      case opt\n      when '--url'\n        self.url = arg.dup\n      when '--key'\n        self.key = arg.dup\n      when '--help'\n        usage\n      when '--verbose'\n        self.verbose = true\n      when '--version'\n        puts VERSION; exit\n      when '--project', '--status', '--tracker'\n        self.issue_attributes[opt.gsub(%r{^\\-\\-}, '')] = arg.dup\n      when '--allow-override'\n        self.allow_override = arg.dup\n      when '--unknown-user'\n        self.unknown_user = arg.dup\n      when '--no-permission-check'\n        self.no_permission_check = '1'\n      end\n    end\n\n    RDoc.usage if url.nil?\n  end\n\n  def submit(email)\n    uri = url.gsub(%r{/*$}, '') + '/mail_handler'\n\n    data = { 'key' => key, 'email' => email,\n                           'allow_override' => allow_override,\n                           'unknown_user' => unknown_user,\n                           'no_permission_check' => no_permission_check}\n    issue_attributes.each { |attr, value| data[\"issue[#{attr}]\"] = value }\n\n    debug \"Posting to #{uri}...\"\n    response = Net::HTTPS.post_form(URI.parse(uri), data)\n    debug \"Response received: #{response.code}\"\n\n    case response.code.to_i\n      when 403\n        warn \"Request was denied by your Redmine server. \" +\n             \"Make sure that 'WS for incoming emails' is enabled in application settings and that you provided the correct API key.\"\n        return 77\n      when 422\n        warn \"Request was denied by your Redmine server. \" +\n             \"Possible reasons: email is sent from an invalid email address or is missing some information.\"\n        return 77\n      when 400..499\n        warn \"Request was denied by your Redmine server (#{response.code}).\"\n        return 77\n      when 500..599\n        warn \"Failed to contact your Redmine server (#{response.code}).\"\n        return 75\n      when 201\n        debug \"Proccessed successfully\"\n        return 0\n      else\n        return 1\n    end\n  end\n\n  private\n\n  def debug(msg)\n    puts msg if verbose\n  end\nend\n\nhandler = RedmineMailHandler.new\nexit(handler.submit(STDIN.read))\n"
  },
  {
    "path": "extra/sample_plugin/README",
    "content": "== Sample plugin\n\nThis is a sample plugin for Redmine\n\n== Installation\n\n1. Copy the plugin directory into the vendor/plugins directory\n\n2. Migrate plugin:\n   rake db:migrate_plugins\n\n3. Start Redmine\n\nInstalled plugins are listed and can be configured from 'Admin -> Plugins' screen.\n"
  },
  {
    "path": "extra/sample_plugin/app/controllers/example_controller.rb",
    "content": "# Sample plugin controller\nclass ExampleController < ApplicationController\n  unloadable\n\n  layout 'base'\n  before_filter :find_project, :authorize\n  menu_item :sample_plugin\n\n  def say_hello\n    @value = Setting.plugin_sample_plugin['sample_setting']\n  end\n\n  def say_goodbye\n  end\n\nprivate\n  def find_project\n    @project=Project.find(params[:id])\n  end\nend\n"
  },
  {
    "path": "extra/sample_plugin/app/models/meeting.rb",
    "content": "class Meeting < ActiveRecord::Base\n  belongs_to :project\n\n  acts_as_event :title => Proc.new {|o| \"#{o.scheduled_on} Meeting\"},\n                :datetime => :scheduled_on,\n                :author => nil,\n                :url => Proc.new {|o| {:controller => 'meetings', :action => 'show', :id => o.id}}\n\n  acts_as_activity_provider :timestamp => 'scheduled_on',\n                            :find_options => { :include => :project }\nend\n"
  },
  {
    "path": "extra/sample_plugin/app/views/example/say_goodbye.html.erb",
    "content": "<p class=\"icon icon-example-works\"><%= l(:text_say_goodbye) %></p>\n\n<% content_for :header_tags do %>\n  <%= stylesheet_link_tag \"example.css\", :plugin => \"sample_plugin\", :media => \"screen\" %>\n<% end %>\n"
  },
  {
    "path": "extra/sample_plugin/app/views/example/say_hello.html.erb",
    "content": "<p class=\"icon icon-example-works\"><%= l(:text_say_hello) %></p>\n\n<p><label>Example setting</label>: <%= @value %></p>\n\n<%= link_to_if_authorized 'Good bye', :action => 'say_goodbye', :id => @project %>\n\n<% content_for :header_tags do %>\n  <%= stylesheet_link_tag \"example.css\", :plugin => \"sample_plugin\", :media => \"screen\" %>\n<% end %>\n"
  },
  {
    "path": "extra/sample_plugin/app/views/my/blocks/_sample_block.html.erb",
    "content": "<h3>Sample block</h3>\n\nYou are <strong><%= h(User.current) %></strong> and this is a sample block for My Page added from a plugin.\n"
  },
  {
    "path": "extra/sample_plugin/app/views/settings/_sample_plugin_settings.html.erb",
    "content": "<p><label>Example setting</label><%= text_field_tag 'settings[sample_setting]', @settings['sample_setting'] %></p>\n\n<p><label>Foo</label><%= text_field_tag 'settings[foo]', @settings['foo'] %></p>\n"
  },
  {
    "path": "extra/sample_plugin/assets/stylesheets/example.css",
    "content": ".icon-example-works { background-image: url(../images/it_works.png); }\n"
  },
  {
    "path": "extra/sample_plugin/config/locales/en.yml",
    "content": "# Sample plugin\nen:\n  label_plugin_example: Sample Plugin\n  label_meeting_plural: Meetings\n  text_say_hello: Plugin say 'Hello'\n  text_say_goodbye: Plugin say 'Good bye'\n"
  },
  {
    "path": "extra/sample_plugin/config/locales/fr.yml",
    "content": "# Sample plugin\nfr:\n  label_plugin_example: Plugin exemple\n  label_meeting_plural: Meetings\n  text_say_hello: Plugin dit 'Bonjour'\n  text_say_goodbye: Plugin dit 'Au revoir'\n"
  },
  {
    "path": "extra/sample_plugin/db/migrate/001_create_meetings.rb",
    "content": "# Sample plugin migration\n# Use rake db:migrate_plugins to migrate installed plugins\nclass CreateMeetings < ActiveRecord::Migration\n  def self.up\n    create_table :meetings do |t|\n      t.column :project_id, :integer, :null => false\n      t.column :description, :string\n      t.column :scheduled_on, :datetime\n    end\n  end\n\n  def self.down\n    drop_table :meetings\n  end\nend\n"
  },
  {
    "path": "extra/sample_plugin/init.rb",
    "content": "# Redmine sample plugin\nrequire 'redmine'\n\nRAILS_DEFAULT_LOGGER.info 'Starting Example plugin for RedMine'\n\nRedmine::Plugin.register :sample_plugin do\n  name 'Example plugin'\n  author 'Author name'\n  description 'This is a sample plugin for Redmine'\n  version '0.0.1'\n  settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'settings/sample_plugin_settings'\n\n  # This plugin adds a project module\n  # It can be enabled/disabled at project level (Project settings -> Modules)\n  project_module :example_module do\n    # A public action\n    permission :example_say_hello, {:example => [:say_hello]}, :public => true\n    # This permission has to be explicitly given\n    # It will be listed on the permissions screen\n    permission :example_say_goodbye, {:example => [:say_goodbye]}\n    # This permission can be given to project members only\n    permission :view_meetings, {:meetings => [:index, :show]}, :require => :member\n  end\n\n  # A new item is added to the project menu\n  menu :project_menu, :sample_plugin, { :controller => 'example', :action => 'say_hello' }, :caption => 'Sample'\n\n  # Meetings are added to the activity view\n  activity_provider :meetings\nend\n"
  },
  {
    "path": "lib/activity_streams/log_activity_streams.rb",
    "content": "#--\n# Copyright (c) 2008 Matson Systems, Inc.\n# Released under the BSD license found in the file\n# LICENSE included with this ActivityStreams plug-in.\n#++\n# The LogActivityStreams module adds a controller class method and\n# helper for automatically logging activity streams.\n#\n# README provides examples\nmodule LogActivityStreams\n\n  def self.write_single_activity_stream(actor,actor_name,object,object_name,verb,activity, status, indirect_object, options)\n  # If there are identical activities within 8 hours, up count\n  as = find_identical(actor, object, verb, activity);\n  if as && !(as.object_type.downcase == 'issue' && as.indirect_object_description != nil) #if action was found, and action is NOT a comment on an issue)\n    as.count += 1\n  else\n    as = ActivityStream.new\n    as.verb = verb.to_s\n    as.activity = activity.to_s\n    as.actor = actor\n    as.actor_name_method = actor_name.to_s\n    as.actor_email = \"<#{actor.mail}>\"\n    as.object = object\n    as.object_name_method = object_name.to_s\n    as.status = status\n    as.project_id = options[:project_id] || object.send('project_id')\n    as.project_name = Project.find(as.project_id).name\n\n\n    #Pre-generating text\n    as.actor_name = actor.send(actor_name)\n    as.object_name = object.send(object_name)\n    as.object_description = object.send(options[:object_description_method]) if options[:object_description_method]\n\n    if as.object_type == \"Issue\"\n      as.tracker_name = as.object.tracker.name\n\n      #hiding gifts\n      if as.object.tracker.gift?\n        as.hidden_from_user_id = as.object.assigned_to_id\n        as.is_public = false\n      end\n    end\n\n\n    if indirect_object\n      as.indirect_object = indirect_object\n      as.indirect_object_name_method = options[:indirect_object_name_method].to_s\n      as.indirect_object_phrase = options[:indirect_object_phrase]\n      if options[:indirect_object_name_method]\n          as.indirect_object_name = indirect_object.send(options[:indirect_object_name_method])\n      end\n\n      if options[:indirect_object_description_method]\n          as.indirect_object_description = indirect_object.send(options[:indirect_object_description_method])\n      end\n    end\n  end\n\n  as.save!\n\n  end\n\n  def self.find_identical(actor, object, verb, activity) # :nodoc:\n    return nil unless object.respond_to?(:project_id)\n    ActivityStream.find(:first, :conditions => [\n      'actor_id = ? AND actor_type = ? AND object_id = ? AND object_type = ? AND verb = ? AND activity = ? AND updated_at >= ? AND project_id = ? AND status = 0',\n      actor.id, actor.class.name, object.id, object.class.name, verb.to_s,\n      activity.to_s, Time.now - 8.hours, object.project_id])\n  end\n\n\n  def self.included(controller) #:nodoc:\n    controller.extend(ClassMethods)\n    controller.helper_method :activity_stream_location\n  end\n\n  module ClassMethods #:nodoc:\n\n    # log_activity_streams writes the activity stream from a controller.\n    #\n    # README provides examples of how to call log_activity_streams\n    def log_activity_streams(actor_method, actor_name, verb, object_method,\n      object_name, action, activity, options={})\n\n      self.after_filter do |c|\n        c.send(:write_activity_stream_log, actor_method, actor_name, verb, object_method, object_name, action, activity, options)\n      end\n\n    end\n  end\n\n  protected\n\n  # activity_stream_location is a helper method for determing the current 'location' (public, logged in users).\n  #\n  #  Example:\n  #        <%= render :partial => 'activity_streams/activity_stream', :collection => ActivityStream.recent_actors(@user, activity_stream_location)  %>\n  #\n  def activity_stream_location\n    if not logged_in?\n      :public_location\n    else\n      :logged_in_location\n    end\n  end\n\n  def write_activity_stream_log(actor_method, actor_name, verb, object_method,\n    object_name, action, activity, options={}) #:nodoc:\n\n    return unless action == self.action_name.to_sym\n\n    return if !flash.now[:error].blank? || @suppress_activity_stream\n\n    status = options[:status] || 0\n\n    if actor_method.to_s.start_with?('@')\n      actors = self.instance_variable_get(actor_method) || []\n    else\n      actors = self.send(actor_method) || []\n    end\n    actors = [ actors ] unless actors.is_a? Array\n    return if actors.empty? || actors.first == :false\n\n    if object_method.to_s.start_with?('@')\n      objects = self.instance_variable_get(object_method) || []\n    else\n      objects = self.send(object_method) || []\n    end\n    objects = [ objects ] unless objects.is_a? Array\n\n\n    if indirect_object_method = options[:indirect_object]\n\n      if indirect_object_method.to_s.start_with?('@')\n        indirect_object = self.instance_variable_get(indirect_object_method)\n      else\n        indirect_object = self.send(indirect_object_method)\n      end\n    end\n\n    actors.each do |actor|\n      objects.each do |object|\n\n        # ensure no errors on object, as a validation error would mean no\n        # activity should fire\n        next unless object.errors.empty?\n\n        LogActivityStreams.write_single_activity_stream(actor,actor_name,object,object_name,verb,activity,status,indirect_object, options)\n\n        total = options[:total]\n        if total\n          total_for = options[:total_for] || :actor\n          if total_for == :actor\n            target = actor\n          else\n            target = object\n          end\n\n          if total.is_a? Symbol\n            if total.to_s.start_with?('@')\n              total = self.instance_variable_get(total)\n            else\n              total = self.send(total) || []\n            end\n          end\n          activity_stream_total = ActivityStreamTotal.find(:first,\n              :conditions => { :activity => activity,\n              :object_id => target.id,\n              :object_type => target.class.name}\n             ) || ActivityStreamTotal.new(:object => target,\n              :activity => activity)\n          activity_stream_total.total += total\n          activity_stream_total.save!\n        end\n      end\n    end\n  end\n\nend\n"
  },
  {
    "path": "lib/activity_streams/routes.rb",
    "content": "#--\n# Copyright (c) 2008 Matson Systems, Inc.\n# Released under the BSD license found in the file\n# LICENSE included with this ActivityStreams plug-in.\n#++\n# routes.rb adds additional routes for ActivityStreamsModule\n#\n# class ActionController::Routing::RouteSet # :nodoc:\n#   def draw # :nodoc:\n#     clear!\n#     mapper = Mapper.new(self)\n#\n#     activity_stream_maps(mapper)\n#\n#     yield mapper\n#\n#     install_helpers\n#   end\n#\n#   def activity_stream_maps(map) # :nodoc:\n#     map.your_activities '/feeds/your_activities/:activity_stream_token', :controller => 'activity_streams', :action => 'feed', :format => 'atom'\n#     map.resources :activity_stream_preferences\n#     map.resources :activity_streams\n#   end\n#\n# end\n"
  },
  {
    "path": "lib/activity_streams.rb",
    "content": "#--\n# Copyright (c) 2008 Matson Systems, Inc.\n# Released under the BSD license found in the file\n# LICENSE included with this ActivityStreams plug-in.\n#++\n# ActivityStreams\n#\nrequire 'activity_streams/log_activity_streams.rb'\n\nrequire 'controllers/activity_stream_preferences_module.rb'\nrequire 'controllers/activity_streams_module.rb'\n"
  },
  {
    "path": "lib/ar_condition.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nclass ARCondition\n  attr_reader :conditions\n\n  def initialize(condition=nil)\n    @conditions = ['1=1']\n    add(condition) if condition\n  end\n\n  def add(condition)\n    if condition.is_a?(Array)\n      @conditions.first << \" AND (#{condition.first})\"\n      @conditions += condition[1..-1]\n    elsif condition.is_a?(String)\n      @conditions.first << \" AND (#{condition})\"\n    else\n      raise \"Unsupported #{condition.class} condition: #{condition}\"\n    end\n    self\n  end\n\n  def <<(condition)\n    add(condition)\n  end\nend\n"
  },
  {
    "path": "lib/diff.rb",
    "content": "module RedmineDiff\n  class Diff\n\n    VERSION = 0.3\n\n    def Diff.lcs(a, b)\n      astart = 0\n      bstart = 0\n      afinish = a.length-1\n      bfinish = b.length-1\n      mvector = []\n\n      # First we prune off any common elements at the beginning\n      while (astart <= afinish && bstart <= afinish && a[astart] == b[bstart])\n        mvector[astart] = bstart\n        astart += 1\n        bstart += 1\n      end\n\n      # now the end\n      while (astart <= afinish && bstart <= bfinish && a[afinish] == b[bfinish])\n        mvector[afinish] = bfinish\n        afinish -= 1\n        bfinish -= 1\n      end\n\n      bmatches = b.reverse_hash(bstart..bfinish)\n      thresh = []\n      links = []\n\n      (astart..afinish).each { |aindex|\n        aelem = a[aindex]\n        next unless bmatches.has_key? aelem\n        k = nil\n        bmatches[aelem].reverse.each { |bindex|\n    if k && (thresh[k] > bindex) && (thresh[k-1] < bindex)\n      thresh[k] = bindex\n    else\n      k = thresh.replacenextlarger(bindex, k)\n    end\n    links[k] = [ (k==0) ? nil : links[k-1], aindex, bindex ] if k\n        }\n      }\n\n      if !thresh.empty?\n        link = links[thresh.length-1]\n        while link\n    mvector[link[1]] = link[2]\n    link = link[0]\n        end\n      end\n\n      return mvector\n    end\n\n    def makediff(a, b)\n      mvector = Diff.lcs(a, b)\n      ai = bi = 0\n      while ai < mvector.length\n        bline = mvector[ai]\n        if bline\n    while bi < bline\n      discardb(bi, b[bi])\n      bi += 1\n    end\n    match(ai, bi)\n    bi += 1\n        else\n    discarda(ai, a[ai])\n        end\n        ai += 1\n      end\n      while ai < a.length\n        discarda(ai, a[ai])\n        ai += 1\n      end\n      while bi < b.length\n        discardb(bi, b[bi])\n        bi += 1\n      end\n      match(ai, bi)\n      1\n    end\n\n    def compactdiffs\n      diffs = []\n      @diffs.each { |df|\n        i = 0\n        curdiff = []\n        while i < df.length\n    whot = df[i][0]\n    s = @isstring ? df[i][2].chr : [df[i][2]]\n    p = df[i][1]\n    last = df[i][1]\n    i += 1\n    while df[i] && df[i][0] == whot && df[i][1] == last+1\n      s << df[i][2]\n      last  = df[i][1]\n      i += 1\n    end\n    curdiff.push [whot, p, s]\n        end\n        diffs.push curdiff\n      }\n      return diffs\n    end\n\n    attr_reader :diffs, :difftype\n\n    def initialize(diffs_or_a, b = nil, isstring = nil)\n      if b.nil?\n        @diffs = diffs_or_a\n        @isstring = isstring\n      else\n        @diffs = []\n        @curdiffs = []\n        makediff(diffs_or_a, b)\n        @difftype = diffs_or_a.class\n      end\n    end\n\n    def match(ai, bi)\n      @diffs.push @curdiffs unless @curdiffs.empty?\n      @curdiffs = []\n    end\n\n    def discarda(i, elem)\n      @curdiffs.push ['-', i, elem]\n    end\n\n    def discardb(i, elem)\n      @curdiffs.push ['+', i, elem]\n    end\n\n    def compact\n      return Diff.new(compactdiffs)\n    end\n\n    def compact!\n      @diffs = compactdiffs\n    end\n\n    def inspect\n      @diffs.inspect\n    end\n\n  end\nend\n\nmodule Diffable\n  def diff(b)\n    RedmineDiff::Diff.new(self, b)\n  end\n\n  # Create a hash that maps elements of the array to arrays of indices\n  # where the elements are found.\n\n  def reverse_hash(range = (0...self.length))\n    revmap = {}\n    range.each { |i|\n      elem = self[i]\n      if revmap.has_key? elem\n  revmap[elem].push i\n      else\n  revmap[elem] = [i]\n      end\n    }\n    return revmap\n  end\n\n  def replacenextlarger(value, high = nil)\n    high ||= self.length\n    if self.empty? || value > self[-1]\n      push value\n      return high\n    end\n    # binary search for replacement point\n    low = 0\n    while low < high\n      index = (high+low)/2\n      found = self[index]\n      return nil if value == found\n      if value > found\n  low = index + 1\n      else\n  high = index\n      end\n    end\n\n    self[low] = value\n    return low\n  end\n\n  def patch(diff)\n    newary = nil\n    if diff.difftype == String\n      newary = diff.difftype.new('')\n    else\n      newary = diff.difftype.new\n    end\n    ai = 0\n    bi = 0\n    diff.diffs.each { |d|\n      d.each { |mod|\n  case mod[0]\n  when '-'\n    while ai < mod[1]\n      newary << self[ai]\n      ai += 1\n      bi += 1\n    end\n    ai += 1\n  when '+'\n    while bi < mod[1]\n      newary << self[ai]\n      ai += 1\n      bi += 1\n    end\n    newary << mod[2]\n    bi += 1\n  else\n    raise \"Unknown diff action\"\n  end\n      }\n    }\n    while ai < self.length\n      newary << self[ai]\n      ai += 1\n      bi += 1\n    end\n    return newary\n  end\nend\n\nclass Array\n  include Diffable\nend\n\nclass String\n  include Diffable\nend\n\n=begin\n  = Diff\n  (({diff.rb})) - computes the differences between two arrays or\n  strings. Copyright (C) 2001 Lars Christensen\n\n  == Synopsis\n\n      diff = Diff.new(a, b)\n      b = a.patch(diff)\n\n  == Class Diff\n  === Class Methods\n  --- Diff.new(a, b)\n  --- a.diff(b)\n        Creates a Diff object which represent the differences between\n        ((|a|)) and ((|b|)). ((|a|)) and ((|b|)) can be either be arrays\n        of any objects, strings, or object of any class that include\n        module ((|Diffable|))\n\n  == Module Diffable\n  The module ((|Diffable|)) is intended to be included in any class for\n  which differences are to be computed. Diffable is included into String\n  and Array when (({diff.rb})) is (({require}))'d.\n\n  Classes including Diffable should implement (({[]})) to get element at\n  integer indices, (({<<})) to append elements to the object and\n  (({ClassName#new})) should accept 0 arguments to create a new empty\n  object.\n\n  === Instance Methods\n  --- Diffable#patch(diff)\n        Applies the differences from ((|diff|)) to the object ((|obj|))\n        and return the result. ((|obj|)) is not changed. ((|obj|)) and\n        can be either an array or a string, but must match the object\n        from which the ((|diff|)) was created.\n=end\n"
  },
  {
    "path": "lib/faster_csv.rb",
    "content": "#!/usr/local/bin/ruby -w\n\n# = faster_csv.rb -- Faster CSV Reading and Writing\n#\n#  Created by James Edward Gray II on 2005-10-31.\n#  Copyright 2005 Gray Productions. All rights reserved.\n#\n# See FasterCSV for documentation.\n\nif RUBY_VERSION >= \"1.9\"\n  abort <<-VERSION_WARNING.gsub(/^\\s+/, \"\")\n  Please switch to Ruby 1.9's standard CSV library.  It's FasterCSV plus\n  support for Ruby 1.9's m17n encoding engine.\n  VERSION_WARNING\nend\n\nrequire \"forwardable\"\nrequire \"English\"\nrequire \"enumerator\"\nrequire \"date\"\nrequire \"stringio\"\n\n#\n# This class provides a complete interface to CSV files and data.  It offers\n# tools to enable you to read and write to and from Strings or IO objects, as\n# needed.\n#\n# == Reading\n#\n# === From a File\n#\n# ==== A Line at a Time\n#\n#   FasterCSV.foreach(\"path/to/file.csv\") do |row|\n#     # use row here...\n#   end\n#\n# ==== All at Once\n#\n#   arr_of_arrs = FasterCSV.read(\"path/to/file.csv\")\n#\n# === From a String\n#\n# ==== A Line at a Time\n#\n#   FasterCSV.parse(\"CSV,data,String\") do |row|\n#     # use row here...\n#   end\n#\n# ==== All at Once\n#\n#   arr_of_arrs = FasterCSV.parse(\"CSV,data,String\")\n#\n# == Writing\n#\n# === To a File\n#\n#   FasterCSV.open(\"path/to/file.csv\", \"w\") do |csv|\n#     csv << [\"row\", \"of\", \"CSV\", \"data\"]\n#     csv << [\"another\", \"row\"]\n#     # ...\n#   end\n#\n# === To a String\n#\n#   csv_string = FasterCSV.generate do |csv|\n#     csv << [\"row\", \"of\", \"CSV\", \"data\"]\n#     csv << [\"another\", \"row\"]\n#     # ...\n#   end\n#\n# == Convert a Single Line\n#\n#   csv_string = [\"CSV\", \"data\"].to_csv   # to CSV\n#   csv_array  = \"CSV,String\".parse_csv   # from CSV\n#\n# == Shortcut Interface\n#\n#   FCSV             { |csv_out| csv_out << %w{my data here} }  # to $stdout\n#   FCSV(csv = \"\")   { |csv_str| csv_str << %w{my data here} }  # to a String\n#   FCSV($stderr)    { |csv_err| csv_err << %w{my data here} }  # to $stderr\n#\nclass FasterCSV\n  # The version of the installed library.\n  VERSION = \"1.5.0\".freeze\n\n  #\n  # A FasterCSV::Row is part Array and part Hash.  It retains an order for the\n  # fields and allows duplicates just as an Array would, but also allows you to\n  # access fields by name just as you could if they were in a Hash.\n  #\n  # All rows returned by FasterCSV will be constructed from this class, if\n  # header row processing is activated.\n  #\n  class Row\n    #\n    # Construct a new FasterCSV::Row from +headers+ and +fields+, which are\n    # expected to be Arrays.  If one Array is shorter than the other, it will be\n    # padded with +nil+ objects.\n    #\n    # The optional +header_row+ parameter can be set to +true+ to indicate, via\n    # FasterCSV::Row.header_row?() and FasterCSV::Row.field_row?(), that this is\n    # a header row.  Otherwise, the row is assumes to be a field row.\n    #\n    # A FasterCSV::Row object supports the following Array methods through\n    # delegation:\n    #\n    # * empty?()\n    # * length()\n    # * size()\n    #\n    def initialize(headers, fields, header_row = false)\n      @header_row = header_row\n\n      # handle extra headers or fields\n      @row = if headers.size > fields.size\n        headers.zip(fields)\n      else\n        fields.zip(headers).map { |pair| pair.reverse }\n      end\n    end\n\n    # Internal data format used to compare equality.\n    attr_reader :row\n    protected   :row\n\n    ### Array Delegation ###\n\n    extend Forwardable\n    def_delegators :@row, :empty?, :length, :size\n\n    # Returns +true+ if this is a header row.\n    def header_row?\n      @header_row\n    end\n\n    # Returns +true+ if this is a field row.\n    def field_row?\n      not header_row?\n    end\n\n    # Returns the headers of this row.\n    def headers\n      @row.map { |pair| pair.first }\n    end\n\n    #\n    # :call-seq:\n    #   field( header )\n    #   field( header, offset )\n    #   field( index )\n    #\n    # This method will fetch the field value by +header+ or +index+.  If a field\n    # is not found, +nil+ is returned.\n    #\n    # When provided, +offset+ ensures that a header match occurrs on or later\n    # than the +offset+ index.  You can use this to find duplicate headers,\n    # without resorting to hard-coding exact indices.\n    #\n    def field(header_or_index, minimum_index = 0)\n      # locate the pair\n      finder = header_or_index.is_a?(Integer) ? :[] : :assoc\n      pair   = @row[minimum_index..-1].send(finder, header_or_index)\n\n      # return the field if we have a pair\n      pair.nil? ? nil : pair.last\n    end\n    alias_method :[], :field\n\n    #\n    # :call-seq:\n    #   []=( header, value )\n    #   []=( header, offset, value )\n    #   []=( index, value )\n    #\n    # Looks up the field by the semantics described in FasterCSV::Row.field()\n    # and assigns the +value+.\n    #\n    # Assigning past the end of the row with an index will set all pairs between\n    # to <tt>[nil, nil]</tt>.  Assigning to an unused header appends the new\n    # pair.\n    #\n    def []=(*args)\n      value = args.pop\n\n      if args.first.is_a? Integer\n        if @row[args.first].nil?  # extending past the end with index\n          @row[args.first] = [nil, value]\n          @row.map! { |pair| pair.nil? ? [nil, nil] : pair }\n        else                      # normal index assignment\n          @row[args.first][1] = value\n        end\n      else\n        index = index(*args)\n        if index.nil?             # appending a field\n          self << [args.first, value]\n        else                      # normal header assignment\n          @row[index][1] = value\n        end\n      end\n    end\n\n    #\n    # :call-seq:\n    #   <<( field )\n    #   <<( header_and_field_array )\n    #   <<( header_and_field_hash )\n    #\n    # If a two-element Array is provided, it is assumed to be a header and field\n    # and the pair is appended.  A Hash works the same way with the key being\n    # the header and the value being the field.  Anything else is assumed to be\n    # a lone field which is appended with a +nil+ header.\n    #\n    # This method returns the row for chaining.\n    #\n    def <<(arg)\n      if arg.is_a?(Array) and arg.size == 2  # appending a header and name\n        @row << arg\n      elsif arg.is_a?(Hash)                  # append header and name pairs\n        arg.each { |pair| @row << pair }\n      else                                   # append field value\n        @row << [nil, arg]\n      end\n\n      self  # for chaining\n    end\n\n    #\n    # A shortcut for appending multiple fields.  Equivalent to:\n    #\n    #   args.each { |arg| faster_csv_row << arg }\n    #\n    # This method returns the row for chaining.\n    #\n    def push(*args)\n      args.each { |arg| self << arg }\n\n      self  # for chaining\n    end\n\n    #\n    # :call-seq:\n    #   delete( header )\n    #   delete( header, offset )\n    #   delete( index )\n    #\n    # Used to remove a pair from the row by +header+ or +index+.  The pair is\n    # located as described in FasterCSV::Row.field().  The deleted pair is\n    # returned, or +nil+ if a pair could not be found.\n    #\n    def delete(header_or_index, minimum_index = 0)\n      if header_or_index.is_a? Integer  # by index\n        @row.delete_at(header_or_index)\n      else                              # by header\n        @row.delete_at(index(header_or_index, minimum_index))\n      end\n    end\n\n    #\n    # The provided +block+ is passed a header and field for each pair in the row\n    # and expected to return +true+ or +false+, depending on whether the pair\n    # should be deleted.\n    #\n    # This method returns the row for chaining.\n    #\n    def delete_if(&block)\n      @row.delete_if(&block)\n\n      self  # for chaining\n    end\n\n    #\n    # This method accepts any number of arguments which can be headers, indices,\n    # Ranges of either, or two-element Arrays containing a header and offset.\n    # Each argument will be replaced with a field lookup as described in\n    # FasterCSV::Row.field().\n    #\n    # If called with no arguments, all fields are returned.\n    #\n    def fields(*headers_and_or_indices)\n      if headers_and_or_indices.empty?  # return all fields--no arguments\n        @row.map { |pair| pair.last }\n      else                              # or work like values_at()\n        headers_and_or_indices.inject(Array.new) do |all, h_or_i|\n          all + if h_or_i.is_a? Range\n            index_begin = h_or_i.begin.is_a?(Integer) ? h_or_i.begin :\n                                                        index(h_or_i.begin)\n            index_end   = h_or_i.end.is_a?(Integer)   ? h_or_i.end :\n                                                        index(h_or_i.end)\n            new_range   = h_or_i.exclude_end? ? (index_begin...index_end) :\n                                                (index_begin..index_end)\n            fields.values_at(new_range)\n          else\n            [field(*Array(h_or_i))]\n          end\n        end\n      end\n    end\n    alias_method :values_at, :fields\n\n    #\n    # :call-seq:\n    #   index( header )\n    #   index( header, offset )\n    #\n    # This method will return the index of a field with the provided +header+.\n    # The +offset+ can be used to locate duplicate header names, as described in\n    # FasterCSV::Row.field().\n    #\n    def index(header, minimum_index = 0)\n      # find the pair\n      index = headers[minimum_index..-1].index(header)\n      # return the index at the right offset, if we found one\n      index.nil? ? nil : index + minimum_index\n    end\n\n    # Returns +true+ if +name+ is a header for this row, and +false+ otherwise.\n    def header?(name)\n      headers.include? name\n    end\n    alias_method :include?, :header?\n\n    #\n    # Returns +true+ if +data+ matches a field in this row, and +false+\n    # otherwise.\n    #\n    def field?(data)\n      fields.include? data\n    end\n\n    include Enumerable\n\n    #\n    # Yields each pair of the row as header and field tuples (much like\n    # iterating over a Hash).\n    #\n    # Support for Enumerable.\n    #\n    # This method returns the row for chaining.\n    #\n    def each(&block)\n      @row.each(&block)\n\n      self  # for chaining\n    end\n\n    #\n    # Returns +true+ if this row contains the same headers and fields in the\n    # same order as +other+.\n    #\n    def ==(other)\n      @row == other.row\n    end\n\n    #\n    # Collapses the row into a simple Hash.  Be warning that this discards field\n    # order and clobbers duplicate fields.\n    #\n    def to_hash\n      # flatten just one level of the internal Array\n      Hash[*@row.inject(Array.new) { |ary, pair| ary.push(*pair) }]\n    end\n\n    #\n    # Returns the row as a CSV String.  Headers are not used.  Equivalent to:\n    #\n    #   faster_csv_row.fields.to_csv( options )\n    #\n    def to_csv(options = Hash.new)\n      fields.to_csv(options)\n    end\n    alias_method :to_s, :to_csv\n\n    # A summary of fields, by header.\n    def inspect\n      str = \"#<#{self.class}\"\n      each do |header, field|\n        str << \" #{header.is_a?(Symbol) ? header.to_s : header.inspect}:\" <<\n               field.inspect\n      end\n      str << \">\"\n    end\n  end\n\n  #\n  # A FasterCSV::Table is a two-dimensional data structure for representing CSV\n  # documents.  Tables allow you to work with the data by row or column,\n  # manipulate the data, and even convert the results back to CSV, if needed.\n  #\n  # All tables returned by FasterCSV will be constructed from this class, if\n  # header row processing is activated.\n  #\n  class Table\n    #\n    # Construct a new FasterCSV::Table from +array_of_rows+, which are expected\n    # to be FasterCSV::Row objects.  All rows are assumed to have the same\n    # headers.\n    #\n    # A FasterCSV::Table object supports the following Array methods through\n    # delegation:\n    #\n    # * empty?()\n    # * length()\n    # * size()\n    #\n    def initialize(array_of_rows)\n      @table = array_of_rows\n      @mode  = :col_or_row\n    end\n\n    # The current access mode for indexing and iteration.\n    attr_reader :mode\n\n    # Internal data format used to compare equality.\n    attr_reader :table\n    protected   :table\n\n    ### Array Delegation ###\n\n    extend Forwardable\n    def_delegators :@table, :empty?, :length, :size\n\n    #\n    # Returns a duplicate table object, in column mode.  This is handy for\n    # chaining in a single call without changing the table mode, but be aware\n    # that this method can consume a fair amount of memory for bigger data sets.\n    #\n    # This method returns the duplicate table for chaining.  Don't chain\n    # destructive methods (like []=()) this way though, since you are working\n    # with a duplicate.\n    #\n    def by_col\n      self.class.new(@table.dup).by_col!\n    end\n\n    #\n    # Switches the mode of this table to column mode.  All calls to indexing and\n    # iteration methods will work with columns until the mode is changed again.\n    #\n    # This method returns the table and is safe to chain.\n    #\n    def by_col!\n      @mode = :col\n\n      self\n    end\n\n    #\n    # Returns a duplicate table object, in mixed mode.  This is handy for\n    # chaining in a single call without changing the table mode, but be aware\n    # that this method can consume a fair amount of memory for bigger data sets.\n    #\n    # This method returns the duplicate table for chaining.  Don't chain\n    # destructive methods (like []=()) this way though, since you are working\n    # with a duplicate.\n    #\n    def by_col_or_row\n      self.class.new(@table.dup).by_col_or_row!\n    end\n\n    #\n    # Switches the mode of this table to mixed mode.  All calls to indexing and\n    # iteration methods will use the default intelligent indexing system until\n    # the mode is changed again.  In mixed mode an index is assumed to be a row\n    # reference while anything else is assumed to be column access by headers.\n    #\n    # This method returns the table and is safe to chain.\n    #\n    def by_col_or_row!\n      @mode = :col_or_row\n\n      self\n    end\n\n    #\n    # Returns a duplicate table object, in row mode.  This is handy for chaining\n    # in a single call without changing the table mode, but be aware that this\n    # method can consume a fair amount of memory for bigger data sets.\n    #\n    # This method returns the duplicate table for chaining.  Don't chain\n    # destructive methods (like []=()) this way though, since you are working\n    # with a duplicate.\n    #\n    def by_row\n      self.class.new(@table.dup).by_row!\n    end\n\n    #\n    # Switches the mode of this table to row mode.  All calls to indexing and\n    # iteration methods will work with rows until the mode is changed again.\n    #\n    # This method returns the table and is safe to chain.\n    #\n    def by_row!\n      @mode = :row\n\n      self\n    end\n\n    #\n    # Returns the headers for the first row of this table (assumed to match all\n    # other rows).  An empty Array is returned for empty tables.\n    #\n    def headers\n      if @table.empty?\n        Array.new\n      else\n        @table.first.headers\n      end\n    end\n\n    #\n    # In the default mixed mode, this method returns rows for index access and\n    # columns for header access.  You can force the index association by first\n    # calling by_col!() or by_row!().\n    #\n    # Columns are returned as an Array of values.  Altering that Array has no\n    # effect on the table.\n    #\n    def [](index_or_header)\n      if @mode == :row or  # by index\n         (@mode == :col_or_row and index_or_header.is_a? Integer)\n        @table[index_or_header]\n      else                 # by header\n        @table.map { |row| row[index_or_header] }\n      end\n    end\n\n    #\n    # In the default mixed mode, this method assigns rows for index access and\n    # columns for header access.  You can force the index association by first\n    # calling by_col!() or by_row!().\n    #\n    # Rows may be set to an Array of values (which will inherit the table's\n    # headers()) or a FasterCSV::Row.\n    #\n    # Columns may be set to a single value, which is copied to each row of the\n    # column, or an Array of values.  Arrays of values are assigned to rows top\n    # to bottom in row major order.  Excess values are ignored and if the Array\n    # does not have a value for each row the extra rows will receive a +nil+.\n    #\n    # Assigning to an existing column or row clobbers the data.  Assigning to\n    # new columns creates them at the right end of the table.\n    #\n    def []=(index_or_header, value)\n      if @mode == :row or  # by index\n         (@mode == :col_or_row and index_or_header.is_a? Integer)\n        if value.is_a? Array\n          @table[index_or_header] = Row.new(headers, value)\n        else\n          @table[index_or_header] = value\n        end\n      else                 # set column\n        if value.is_a? Array  # multiple values\n          @table.each_with_index do |row, i|\n            if row.header_row?\n              row[index_or_header] = index_or_header\n            else\n              row[index_or_header] = value[i]\n            end\n          end\n        else                  # repeated value\n          @table.each do |row|\n            if row.header_row?\n              row[index_or_header] = index_or_header\n            else\n              row[index_or_header] = value\n            end\n          end\n        end\n      end\n    end\n\n    #\n    # The mixed mode default is to treat a list of indices as row access,\n    # returning the rows indicated.  Anything else is considered columnar\n    # access.  For columnar access, the return set has an Array for each row\n    # with the values indicated by the headers in each Array.  You can force\n    # column or row mode using by_col!() or by_row!().\n    #\n    # You cannot mix column and row access.\n    #\n    def values_at(*indices_or_headers)\n      if @mode == :row or  # by indices\n         ( @mode == :col_or_row and indices_or_headers.all? do |index|\n                                      index.is_a?(Integer)         or\n                                      ( index.is_a?(Range)         and\n                                        index.first.is_a?(Integer) and\n                                        index.last.is_a?(Integer) )\n                                    end )\n        @table.values_at(*indices_or_headers)\n      else                 # by headers\n        @table.map { |row| row.values_at(*indices_or_headers) }\n      end\n    end\n\n    #\n    # Adds a new row to the bottom end of this table.  You can provide an Array,\n    # which will be converted to a FasterCSV::Row (inheriting the table's\n    # headers()), or a FasterCSV::Row.\n    #\n    # This method returns the table for chaining.\n    #\n    def <<(row_or_array)\n      if row_or_array.is_a? Array  # append Array\n        @table << Row.new(headers, row_or_array)\n      else                         # append Row\n        @table << row_or_array\n      end\n\n      self  # for chaining\n    end\n\n    #\n    # A shortcut for appending multiple rows.  Equivalent to:\n    #\n    #   rows.each { |row| self << row }\n    #\n    # This method returns the table for chaining.\n    #\n    def push(*rows)\n      rows.each { |row| self << row }\n\n      self  # for chaining\n    end\n\n    #\n    # Removes and returns the indicated column or row.  In the default mixed\n    # mode indices refer to rows and everything else is assumed to be a column\n    # header.  Use by_col!() or by_row!() to force the lookup.\n    #\n    def delete(index_or_header)\n      if @mode == :row or  # by index\n         (@mode == :col_or_row and index_or_header.is_a? Integer)\n        @table.delete_at(index_or_header)\n      else                 # by header\n        @table.map { |row| row.delete(index_or_header).last }\n      end\n    end\n\n    #\n    # Removes any column or row for which the block returns +true+.  In the\n    # default mixed mode or row mode, iteration is the standard row major\n    # walking of rows.  In column mode, interation will +yield+ two element\n    # tuples containing the column name and an Array of values for that column.\n    #\n    # This method returns the table for chaining.\n    #\n    def delete_if(&block)\n      if @mode == :row or @mode == :col_or_row  # by index\n        @table.delete_if(&block)\n      else                                      # by header\n        to_delete = Array.new\n        headers.each_with_index do |header, i|\n          to_delete << header if block[[header, self[header]]]\n        end\n        to_delete.map { |header| delete(header) }\n      end\n\n      self  # for chaining\n    end\n\n    include Enumerable\n\n    #\n    # In the default mixed mode or row mode, iteration is the standard row major\n    # walking of rows.  In column mode, interation will +yield+ two element\n    # tuples containing the column name and an Array of values for that column.\n    #\n    # This method returns the table for chaining.\n    #\n    def each(&block)\n      if @mode == :col\n        headers.each { |header| block[[header, self[header]]] }\n      else\n        @table.each(&block)\n      end\n\n      self  # for chaining\n    end\n\n    # Returns +true+ if all rows of this table ==() +other+'s rows.\n    def ==(other)\n      @table == other.table\n    end\n\n    #\n    # Returns the table as an Array of Arrays.  Headers will be the first row,\n    # then all of the field rows will follow.\n    #\n    def to_a\n      @table.inject([headers]) do |array, row|\n        if row.header_row?\n          array\n        else\n          array + [row.fields]\n        end\n      end\n    end\n\n    #\n    # Returns the table as a complete CSV String.  Headers will be listed first,\n    # then all of the field rows.\n    #\n    def to_csv(options = Hash.new)\n      @table.inject([headers.to_csv(options)]) do |rows, row|\n        if row.header_row?\n          rows\n        else\n          rows + [row.fields.to_csv(options)]\n        end\n      end.join\n    end\n    alias_method :to_s, :to_csv\n\n    def inspect\n      \"#<#{self.class} mode:#{@mode} row_count:#{to_a.size}>\"\n    end\n  end\n\n  # The error thrown when the parser encounters illegal CSV formatting.\n  class MalformedCSVError < RuntimeError; end\n\n  #\n  # A FieldInfo Struct contains details about a field's position in the data\n  # source it was read from.  FasterCSV will pass this Struct to some blocks\n  # that make decisions based on field structure.  See\n  # FasterCSV.convert_fields() for an example.\n  #\n  # <b><tt>index</tt></b>::  The zero-based index of the field in its row.\n  # <b><tt>line</tt></b>::   The line of the data source this row is from.\n  # <b><tt>header</tt></b>:: The header for the column, when available.\n  #\n  FieldInfo = Struct.new(:index, :line, :header)\n\n  # A Regexp used to find and convert some common Date formats.\n  DateMatcher     = / \\A(?: (\\w+,?\\s+)?\\w+\\s+\\d{1,2},?\\s+\\d{2,4} |\n                            \\d{4}-\\d{2}-\\d{2} )\\z /x\n  # A Regexp used to find and convert some common DateTime formats.\n  DateTimeMatcher =\n    / \\A(?: (\\w+,?\\s+)?\\w+\\s+\\d{1,2}\\s+\\d{1,2}:\\d{1,2}:\\d{1,2},?\\s+\\d{2,4} |\n            \\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2} )\\z /x\n  #\n  # This Hash holds the built-in converters of FasterCSV that can be accessed by\n  # name.  You can select Converters with FasterCSV.convert() or through the\n  # +options+ Hash passed to FasterCSV::new().\n  #\n  # <b><tt>:integer</tt></b>::    Converts any field Integer() accepts.\n  # <b><tt>:float</tt></b>::      Converts any field Float() accepts.\n  # <b><tt>:numeric</tt></b>::    A combination of <tt>:integer</tt>\n  #                               and <tt>:float</tt>.\n  # <b><tt>:date</tt></b>::       Converts any field Date::parse() accepts.\n  # <b><tt>:date_time</tt></b>::  Converts any field DateTime::parse() accepts.\n  # <b><tt>:all</tt></b>::        All built-in converters.  A combination of\n  #                               <tt>:date_time</tt> and <tt>:numeric</tt>.\n  #\n  # This Hash is intetionally left unfrozen and users should feel free to add\n  # values to it that can be accessed by all FasterCSV objects.\n  #\n  # To add a combo field, the value should be an Array of names.  Combo fields\n  # can be nested with other combo fields.\n  #\n  Converters  = { :integer   => lambda { |f| Integer(f)        rescue f },\n                  :float     => lambda { |f| Float(f)          rescue f },\n                  :numeric   => [:integer, :float],\n                  :date      => lambda { |f|\n                    f =~ DateMatcher ? (Date.parse(f) rescue f) : f\n                  },\n                  :date_time => lambda { |f|\n                    f =~ DateTimeMatcher ? (DateTime.parse(f) rescue f) : f\n                  },\n                  :all       => [:date_time, :numeric] }\n\n  #\n  # This Hash holds the built-in header converters of FasterCSV that can be\n  # accessed by name.  You can select HeaderConverters with\n  # FasterCSV.header_convert() or through the +options+ Hash passed to\n  # FasterCSV::new().\n  #\n  # <b><tt>:downcase</tt></b>::  Calls downcase() on the header String.\n  # <b><tt>:symbol</tt></b>::    The header String is downcased, spaces are\n  #                              replaced with underscores, non-word characters\n  #                              are dropped, and finally to_sym() is called.\n  #\n  # This Hash is intetionally left unfrozen and users should feel free to add\n  # values to it that can be accessed by all FasterCSV objects.\n  #\n  # To add a combo field, the value should be an Array of names.  Combo fields\n  # can be nested with other combo fields.\n  #\n  HeaderConverters = {\n    :downcase => lambda { |h| h.downcase },\n    :symbol   => lambda { |h|\n      h.downcase.tr(\" \", \"_\").delete(\"^a-z0-9_\").to_sym\n    }\n  }\n\n  #\n  # The options used when no overrides are given by calling code.  They are:\n  #\n  # <b><tt>:col_sep</tt></b>::            <tt>\",\"</tt>\n  # <b><tt>:row_sep</tt></b>::            <tt>:auto</tt>\n  # <b><tt>:quote_char</tt></b>::         <tt>'\"'</tt>\n  # <b><tt>:converters</tt></b>::         +nil+\n  # <b><tt>:unconverted_fields</tt></b>:: +nil+\n  # <b><tt>:headers</tt></b>::            +false+\n  # <b><tt>:return_headers</tt></b>::     +false+\n  # <b><tt>:header_converters</tt></b>::  +nil+\n  # <b><tt>:skip_blanks</tt></b>::        +false+\n  # <b><tt>:force_quotes</tt></b>::       +false+\n  #\n  DEFAULT_OPTIONS = { :col_sep            => \",\",\n                      :row_sep            => :auto,\n                      :quote_char         => '\"',\n                      :converters         => nil,\n                      :unconverted_fields => nil,\n                      :headers            => false,\n                      :return_headers     => false,\n                      :header_converters  => nil,\n                      :skip_blanks        => false,\n                      :force_quotes       => false }.freeze\n\n  #\n  # This method will build a drop-in replacement for many of the standard CSV\n  # methods.  It allows you to write code like:\n  #\n  #   begin\n  #     require \"faster_csv\"\n  #     FasterCSV.build_csv_interface\n  #   rescue LoadError\n  #     require \"csv\"\n  #   end\n  #   # ... use CSV here ...\n  #\n  # This is not a complete interface with completely identical behavior.\n  # However, it is intended to be close enough that you won't notice the\n  # difference in most cases.  CSV methods supported are:\n  #\n  # * foreach()\n  # * generate_line()\n  # * open()\n  # * parse()\n  # * parse_line()\n  # * readlines()\n  #\n  # Be warned that this interface is slower than vanilla FasterCSV due to the\n  # extra layer of method calls.  Depending on usage, this can slow it down to\n  # near CSV speeds.\n  #\n  def self.build_csv_interface\n    Object.const_set(:CSV, Class.new).class_eval do\n      def self.foreach(path, rs = :auto, &block)  # :nodoc:\n        FasterCSV.foreach(path, :row_sep => rs, &block)\n      end\n\n      def self.generate_line(row, fs = \",\", rs = \"\")  # :nodoc:\n        FasterCSV.generate_line(row, :col_sep => fs, :row_sep => rs)\n      end\n\n      def self.open(path, mode, fs = \",\", rs = :auto, &block)  # :nodoc:\n        if block and mode.include? \"r\"\n          FasterCSV.open(path, mode, :col_sep => fs, :row_sep => rs) do |csv|\n            csv.each(&block)\n          end\n        else\n          FasterCSV.open(path, mode, :col_sep => fs, :row_sep => rs, &block)\n        end\n      end\n\n      def self.parse(str_or_readable, fs = \",\", rs = :auto, &block)  # :nodoc:\n        FasterCSV.parse(str_or_readable, :col_sep => fs, :row_sep => rs, &block)\n      end\n\n      def self.parse_line(src, fs = \",\", rs = :auto)  # :nodoc:\n        FasterCSV.parse_line(src, :col_sep => fs, :row_sep => rs)\n      end\n\n      def self.readlines(path, rs = :auto)  # :nodoc:\n        FasterCSV.readlines(path, :row_sep => rs)\n      end\n    end\n  end\n\n  #\n  # This method allows you to serialize an Array of Ruby objects to a String or\n  # File of CSV data.  This is not as powerful as Marshal or YAML, but perhaps\n  # useful for spreadsheet and database interaction.\n  #\n  # Out of the box, this method is intended to work with simple data objects or\n  # Structs.  It will serialize a list of instance variables and/or\n  # Struct.members().\n  #\n  # If you need need more complicated serialization, you can control the process\n  # by adding methods to the class to be serialized.\n  #\n  # A class method csv_meta() is responsible for returning the first row of the\n  # document (as an Array).  This row is considered to be a Hash of the form\n  # key_1,value_1,key_2,value_2,...  FasterCSV::load() expects to find a class\n  # key with a value of the stringified class name and FasterCSV::dump() will\n  # create this, if you do not define this method.  This method is only called\n  # on the first object of the Array.\n  #\n  # The next method you can provide is an instance method called csv_headers().\n  # This method is expected to return the second line of the document (again as\n  # an Array), which is to be used to give each column a header.  By default,\n  # FasterCSV::load() will set an instance variable if the field header starts\n  # with an @ character or call send() passing the header as the method name and\n  # the field value as an argument.  This method is only called on the first\n  # object of the Array.\n  #\n  # Finally, you can provide an instance method called csv_dump(), which will\n  # be passed the headers.  This should return an Array of fields that can be\n  # serialized for this object.  This method is called once for every object in\n  # the Array.\n  #\n  # The +io+ parameter can be used to serialize to a File, and +options+ can be\n  # anything FasterCSV::new() accepts.\n  #\n  def self.dump(ary_of_objs, io = \"\", options = Hash.new)\n    obj_template = ary_of_objs.first\n\n    csv = FasterCSV.new(io, options)\n\n    # write meta information\n    begin\n      csv << obj_template.class.csv_meta\n    rescue NoMethodError\n      csv << [:class, obj_template.class]\n    end\n\n    # write headers\n    begin\n      headers = obj_template.csv_headers\n    rescue NoMethodError\n      headers = obj_template.instance_variables.sort\n      if obj_template.class.ancestors.find { |cls| cls.to_s =~ /\\AStruct\\b/ }\n        headers += obj_template.members.map { |mem| \"#{mem}=\" }.sort\n      end\n    end\n    csv << headers\n\n    # serialize each object\n    ary_of_objs.each do |obj|\n      begin\n        csv << obj.csv_dump(headers)\n      rescue NoMethodError\n        csv << headers.map do |var|\n          if var[0] == ?@\n            obj.instance_variable_get(var)\n          else\n            obj[var[0..-2]]\n          end\n        end\n      end\n    end\n\n    if io.is_a? String\n      csv.string\n    else\n      csv.close\n    end\n  end\n\n  #\n  # :call-seq:\n  #   filter( options = Hash.new ) { |row| ... }\n  #   filter( input, options = Hash.new ) { |row| ... }\n  #   filter( input, output, options = Hash.new ) { |row| ... }\n  #\n  # This method is a convenience for building Unix-like filters for CSV data.\n  # Each row is yielded to the provided block which can alter it as needed.\n  # After the block returns, the row is appended to +output+ altered or not.\n  #\n  # The +input+ and +output+ arguments can be anything FasterCSV::new() accepts\n  # (generally String or IO objects).  If not given, they default to\n  # <tt>ARGF</tt> and <tt>$stdout</tt>.\n  #\n  # The +options+ parameter is also filtered down to FasterCSV::new() after some\n  # clever key parsing.  Any key beginning with <tt>:in_</tt> or\n  # <tt>:input_</tt> will have that leading identifier stripped and will only\n  # be used in the +options+ Hash for the +input+ object.  Keys starting with\n  # <tt>:out_</tt> or <tt>:output_</tt> affect only +output+.  All other keys\n  # are assigned to both objects.\n  #\n  # The <tt>:output_row_sep</tt> +option+ defaults to\n  # <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>).\n  #\n  def self.filter(*args)\n    # parse options for input, output, or both\n    in_options, out_options = Hash.new, {:row_sep => $INPUT_RECORD_SEPARATOR}\n    if args.last.is_a? Hash\n      args.pop.each do |key, value|\n        case key.to_s\n        when /\\Ain(?:put)?_(.+)\\Z/\n          in_options[$1.to_sym] = value\n        when /\\Aout(?:put)?_(.+)\\Z/\n          out_options[$1.to_sym] = value\n        else\n          in_options[key]  = value\n          out_options[key] = value\n        end\n      end\n    end\n    # build input and output wrappers\n    input   = FasterCSV.new(args.shift || ARGF,    in_options)\n    output  = FasterCSV.new(args.shift || $stdout, out_options)\n\n    # read, yield, write\n    input.each do |row|\n      yield row\n      output << row\n    end\n  end\n\n  #\n  # This method is intended as the primary interface for reading CSV files.  You\n  # pass a +path+ and any +options+ you wish to set for the read.  Each row of\n  # file will be passed to the provided +block+ in turn.\n  #\n  # The +options+ parameter can be anything FasterCSV::new() understands.\n  #\n  def self.foreach(path, options = Hash.new, &block)\n    open(path, \"rb\", options) do |csv|\n      csv.each(&block)\n    end\n  end\n\n  #\n  # :call-seq:\n  #   generate( str, options = Hash.new ) { |faster_csv| ... }\n  #   generate( options = Hash.new ) { |faster_csv| ... }\n  #\n  # This method wraps a String you provide, or an empty default String, in a\n  # FasterCSV object which is passed to the provided block.  You can use the\n  # block to append CSV rows to the String and when the block exits, the\n  # final String will be returned.\n  #\n  # Note that a passed String *is* modfied by this method.  Call dup() before\n  # passing if you need a new String.\n  #\n  # The +options+ parameter can be anthing FasterCSV::new() understands.\n  #\n  def self.generate(*args)\n    # add a default empty String, if none was given\n    if args.first.is_a? String\n      io = StringIO.new(args.shift)\n      io.seek(0, IO::SEEK_END)\n      args.unshift(io)\n    else\n      args.unshift(\"\")\n    end\n    faster_csv = new(*args)  # wrap\n    yield faster_csv         # yield for appending\n    faster_csv.string        # return final String\n  end\n\n  #\n  # This method is a shortcut for converting a single row (Array) into a CSV\n  # String.\n  #\n  # The +options+ parameter can be anthing FasterCSV::new() understands.\n  #\n  # The <tt>:row_sep</tt> +option+ defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>\n  # (<tt>$/</tt>) when calling this method.\n  #\n  def self.generate_line(row, options = Hash.new)\n    options = {:row_sep => $INPUT_RECORD_SEPARATOR}.merge(options)\n    (new(\"\", options) << row).string\n  end\n\n  #\n  # This method will return a FasterCSV instance, just like FasterCSV::new(),\n  # but the instance will be cached and returned for all future calls to this\n  # method for the same +data+ object (tested by Object#object_id()) with the\n  # same +options+.\n  #\n  # If a block is given, the instance is passed to the block and the return\n  # value becomes the return value of the block.\n  #\n  def self.instance(data = $stdout, options = Hash.new)\n    # create a _signature_ for this method call, data object and options\n    sig = [data.object_id] +\n          options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s })\n\n    # fetch or create the instance for this signature\n    @@instances ||= Hash.new\n    instance    =   (@@instances[sig] ||= new(data, options))\n\n    if block_given?\n      yield instance  # run block, if given, returning result\n    else\n      instance        # or return the instance\n    end\n  end\n\n  #\n  # This method is the reading counterpart to FasterCSV::dump().  See that\n  # method for a detailed description of the process.\n  #\n  # You can customize loading by adding a class method called csv_load() which\n  # will be passed a Hash of meta information, an Array of headers, and an Array\n  # of fields for the object the method is expected to return.\n  #\n  # Remember that all fields will be Strings after this load.  If you need\n  # something else, use +options+ to setup converters or provide a custom\n  # csv_load() implementation.\n  #\n  def self.load(io_or_str, options = Hash.new)\n    csv = FasterCSV.new(io_or_str, options)\n\n    # load meta information\n    meta = Hash[*csv.shift]\n    cls  = meta[\"class\"].split(\"::\").inject(Object) do |c, const|\n      c.const_get(const)\n    end\n\n    # load headers\n    headers = csv.shift\n\n    # unserialize each object stored in the file\n    results = csv.inject(Array.new) do |all, row|\n      begin\n        obj = cls.csv_load(meta, headers, row)\n      rescue NoMethodError\n        obj = cls.allocate\n        headers.zip(row) do |name, value|\n          if name[0] == ?@\n            obj.instance_variable_set(name, value)\n          else\n            obj.send(name, value)\n          end\n        end\n      end\n      all << obj\n    end\n\n    csv.close unless io_or_str.is_a? String\n\n    results\n  end\n\n  #\n  # :call-seq:\n  #   open( filename, mode=\"rb\", options = Hash.new ) { |faster_csv| ... }\n  #   open( filename, mode=\"rb\", options = Hash.new )\n  #\n  # This method opens an IO object, and wraps that with FasterCSV.  This is\n  # intended as the primary interface for writing a CSV file.\n  #\n  # You may pass any +args+ Ruby's open() understands followed by an optional\n  # Hash containing any +options+ FasterCSV::new() understands.\n  #\n  # This method works like Ruby's open() call, in that it will pass a FasterCSV\n  # object to a provided block and close it when the block termminates, or it\n  # will return the FasterCSV object when no block is provided.  (*Note*: This\n  # is different from the standard CSV library which passes rows to the block.\n  # Use FasterCSV::foreach() for that behavior.)\n  #\n  # An opened FasterCSV object will delegate to many IO methods, for\n  # convenience.  You may call:\n  #\n  # * binmode()\n  # * close()\n  # * close_read()\n  # * close_write()\n  # * closed?()\n  # * eof()\n  # * eof?()\n  # * fcntl()\n  # * fileno()\n  # * flush()\n  # * fsync()\n  # * ioctl()\n  # * isatty()\n  # * pid()\n  # * pos()\n  # * reopen()\n  # * seek()\n  # * stat()\n  # * sync()\n  # * sync=()\n  # * tell()\n  # * to_i()\n  # * to_io()\n  # * tty?()\n  #\n  def self.open(*args)\n    # find the +options+ Hash\n    options = if args.last.is_a? Hash then args.pop else Hash.new end\n    # default to a binary open mode\n    args << \"rb\" if args.size == 1\n    # wrap a File opened with the remaining +args+\n    csv     = new(File.open(*args), options)\n\n    # handle blocks like Ruby's open(), not like the CSV library\n    if block_given?\n      begin\n        yield csv\n      ensure\n        csv.close\n      end\n    else\n      csv\n    end\n  end\n\n  #\n  # :call-seq:\n  #   parse( str, options = Hash.new ) { |row| ... }\n  #   parse( str, options = Hash.new )\n  #\n  # This method can be used to easily parse CSV out of a String.  You may either\n  # provide a +block+ which will be called with each row of the String in turn,\n  # or just use the returned Array of Arrays (when no +block+ is given).\n  #\n  # You pass your +str+ to read from, and an optional +options+ Hash containing\n  # anything FasterCSV::new() understands.\n  #\n  def self.parse(*args, &block)\n    csv = new(*args)\n    if block.nil?  # slurp contents, if no block is given\n      begin\n        csv.read\n      ensure\n        csv.close\n      end\n    else           # or pass each row to a provided block\n      csv.each(&block)\n    end\n  end\n\n  #\n  # This method is a shortcut for converting a single line of a CSV String into\n  # a into an Array.  Note that if +line+ contains multiple rows, anything\n  # beyond the first row is ignored.\n  #\n  # The +options+ parameter can be anthing FasterCSV::new() understands.\n  #\n  def self.parse_line(line, options = Hash.new)\n    new(line, options).shift\n  end\n\n  #\n  # Use to slurp a CSV file into an Array of Arrays.  Pass the +path+ to the\n  # file and any +options+ FasterCSV::new() understands.\n  #\n  def self.read(path, options = Hash.new)\n    open(path, \"rb\", options) { |csv| csv.read }\n  end\n\n  # Alias for FasterCSV::read().\n  def self.readlines(*args)\n    read(*args)\n  end\n\n  #\n  # A shortcut for:\n  #\n  #   FasterCSV.read( path, { :headers           => true,\n  #                           :converters        => :numeric,\n  #                           :header_converters => :symbol }.merge(options) )\n  #\n  def self.table(path, options = Hash.new)\n    read( path, { :headers           => true,\n                  :converters        => :numeric,\n                  :header_converters => :symbol }.merge(options) )\n  end\n\n  #\n  # This constructor will wrap either a String or IO object passed in +data+ for\n  # reading and/or writing.  In addition to the FasterCSV instance methods,\n  # several IO methods are delegated.  (See FasterCSV::open() for a complete\n  # list.)  If you pass a String for +data+, you can later retrieve it (after\n  # writing to it, for example) with FasterCSV.string().\n  #\n  # Note that a wrapped String will be positioned at at the beginning (for\n  # reading).  If you want it at the end (for writing), use\n  # FasterCSV::generate().  If you want any other positioning, pass a preset\n  # StringIO object instead.\n  #\n  # You may set any reading and/or writing preferences in the +options+ Hash.\n  # Available options are:\n  #\n  # <b><tt>:col_sep</tt></b>::            The String placed between each field.\n  # <b><tt>:row_sep</tt></b>::            The String appended to the end of each\n  #                                       row.  This can be set to the special\n  #                                       <tt>:auto</tt> setting, which requests\n  #                                       that FasterCSV automatically discover\n  #                                       this from the data.  Auto-discovery\n  #                                       reads ahead in the data looking for\n  #                                       the next <tt>\"\\r\\n\"</tt>,\n  #                                       <tt>\"\\n\"</tt>, or <tt>\"\\r\"</tt>\n  #                                       sequence.  A sequence will be selected\n  #                                       even if it occurs in a quoted field,\n  #                                       assuming that you would have the same\n  #                                       line endings there.  If none of those\n  #                                       sequences is found, +data+ is\n  #                                       <tt>ARGF</tt>, <tt>STDIN</tt>,\n  #                                       <tt>STDOUT</tt>, or <tt>STDERR</tt>,\n  #                                       or the stream is only available for\n  #                                       output, the default\n  #                                       <tt>$INPUT_RECORD_SEPARATOR</tt>\n  #                                       (<tt>$/</tt>) is used.  Obviously,\n  #                                       discovery takes a little time.  Set\n  #                                       manually if speed is important.  Also\n  #                                       note that IO objects should be opened\n  #                                       in binary mode on Windows if this\n  #                                       feature will be used as the\n  #                                       line-ending translation can cause\n  #                                       problems with resetting the document\n  #                                       position to where it was before the\n  #                                       read ahead.\n  # <b><tt>:quote_char</tt></b>::         The character used to quote fields.\n  #                                       This has to be a single character\n  #                                       String.  This is useful for\n  #                                       application that incorrectly use\n  #                                       <tt>'</tt> as the quote character\n  #                                       instead of the correct <tt>\"</tt>.\n  #                                       FasterCSV will always consider a\n  #                                       double sequence this character to be\n  #                                       an escaped quote.\n  # <b><tt>:encoding</tt></b>::           The encoding to use when parsing the\n  #                                       file. Defaults to your <tt>$KDOCE</tt>\n  #                                       setting. Valid values: <tt>`n’</tt> or\n  #                                       <tt>`N’</tt> for none, <tt>`e’</tt> or\n  #                                       <tt>`E’</tt> for EUC, <tt>`s’</tt> or\n  #                                       <tt>`S’</tt> for SJIS, and\n  #                                       <tt>`u’</tt> or <tt>`U’</tt> for UTF-8\n  #                                       (see Regexp.new()).\n  # <b><tt>:field_size_limit</tt></b>::   This is a maximum size FasterCSV will\n  #                                       read ahead looking for the closing\n  #                                       quote for a field.  (In truth, it\n  #                                       reads to the first line ending beyond\n  #                                       this size.)  If a quote cannot be\n  #                                       found within the limit FasterCSV will\n  #                                       raise a MalformedCSVError, assuming\n  #                                       the data is faulty.  You can use this\n  #                                       limit to prevent what are effectively\n  #                                       DoS attacks on the parser.  However,\n  #                                       this limit can cause a legitimate\n  #                                       parse to fail and thus is set to\n  #                                       +nil+, or off, by default.\n  # <b><tt>:converters</tt></b>::         An Array of names from the Converters\n  #                                       Hash and/or lambdas that handle custom\n  #                                       conversion.  A single converter\n  #                                       doesn't have to be in an Array.\n  # <b><tt>:unconverted_fields</tt></b>:: If set to +true+, an\n  #                                       unconverted_fields() method will be\n  #                                       added to all returned rows (Array or\n  #                                       FasterCSV::Row) that will return the\n  #                                       fields as they were before convertion.\n  #                                       Note that <tt>:headers</tt> supplied\n  #                                       by Array or String were not fields of\n  #                                       the document and thus will have an\n  #                                       empty Array attached.\n  # <b><tt>:headers</tt></b>::            If set to <tt>:first_row</tt> or\n  #                                       +true+, the initial row of the CSV\n  #                                       file will be treated as a row of\n  #                                       headers.  If set to an Array, the\n  #                                       contents will be used as the headers.\n  #                                       If set to a String, the String is run\n  #                                       through a call of\n  #                                       FasterCSV::parse_line() with the same\n  #                                       <tt>:col_sep</tt>, <tt>:row_sep</tt>,\n  #                                       and <tt>:quote_char</tt> as this\n  #                                       instance to produce an Array of\n  #                                       headers.  This setting causes\n  #                                       FasterCSV.shift() to return rows as\n  #                                       FasterCSV::Row objects instead of\n  #                                       Arrays and FasterCSV.read() to return\n  #                                       FasterCSV::Table objects instead of\n  #                                       an Array of Arrays.\n  # <b><tt>:return_headers</tt></b>::     When +false+, header rows are silently\n  #                                       swallowed.  If set to +true+, header\n  #                                       rows are returned in a FasterCSV::Row\n  #                                       object with identical headers and\n  #                                       fields (save that the fields do not go\n  #                                       through the converters).\n  # <b><tt>:write_headers</tt></b>::      When +true+ and <tt>:headers</tt> is\n  #                                       set, a header row will be added to the\n  #                                       output.\n  # <b><tt>:header_converters</tt></b>::  Identical in functionality to\n  #                                       <tt>:converters</tt> save that the\n  #                                       conversions are only made to header\n  #                                       rows.\n  # <b><tt>:skip_blanks</tt></b>::        When set to a +true+ value, FasterCSV\n  #                                       will skip over any rows with no\n  #                                       content.\n  # <b><tt>:force_quotes</tt></b>::       When set to a +true+ value, FasterCSV\n  #                                       will quote all CSV fields it creates.\n  #\n  # See FasterCSV::DEFAULT_OPTIONS for the default settings.\n  #\n  # Options cannot be overriden in the instance methods for performance reasons,\n  # so be sure to set what you want here.\n  #\n  def initialize(data, options = Hash.new)\n    # build the options for this read/write\n    options = DEFAULT_OPTIONS.merge(options)\n\n    # create the IO object we will read from\n    @io = if data.is_a? String then StringIO.new(data) else data end\n\n    init_separators(options)\n    init_parsers(options)\n    init_converters(options)\n    init_headers(options)\n\n    unless options.empty?\n      raise ArgumentError, \"Unknown options:  #{options.keys.join(', ')}.\"\n    end\n\n    # track our own lineno since IO gets confused about line-ends is CSV fields\n    @lineno = 0\n  end\n\n  #\n  # The line number of the last row read from this file.  Fields with nested\n  # line-end characters will not affect this count.\n  #\n  attr_reader :lineno\n\n  ### IO and StringIO Delegation ###\n\n  extend Forwardable\n  def_delegators :@io, :binmode, :close, :close_read, :close_write, :closed?,\n                       :eof, :eof?, :fcntl, :fileno, :flush, :fsync, :ioctl,\n                       :isatty, :pid, :pos, :reopen, :seek, :stat, :string,\n                       :sync, :sync=, :tell, :to_i, :to_io, :tty?\n\n  # Rewinds the underlying IO object and resets FasterCSV's lineno() counter.\n  def rewind\n    @headers = nil\n    @lineno  = 0\n\n    @io.rewind\n  end\n\n  ### End Delegation ###\n\n  #\n  # The primary write method for wrapped Strings and IOs, +row+ (an Array or\n  # FasterCSV::Row) is converted to CSV and appended to the data source.  When a\n  # FasterCSV::Row is passed, only the row's fields() are appended to the\n  # output.\n  #\n  # The data source must be open for writing.\n  #\n  def <<(row)\n    # make sure headers have been assigned\n    if header_row? and [Array, String].include? @use_headers.class\n      parse_headers  # won't read data for Array or String\n      self << @headers if @write_headers\n    end\n\n    # Handle FasterCSV::Row objects and Hashes\n    row = case row\n          when self.class::Row then row.fields\n          when Hash            then @headers.map { |header| row[header] }\n          else                      row\n          end\n\n    @headers =  row if header_row?\n    @lineno  += 1\n\n    @io << row.map(&@quote).join(@col_sep) + @row_sep  # quote and separate\n\n    self  # for chaining\n  end\n  alias_method :add_row, :<<\n  alias_method :puts,    :<<\n\n  #\n  # :call-seq:\n  #   convert( name )\n  #   convert { |field| ... }\n  #   convert { |field, field_info| ... }\n  #\n  # You can use this method to install a FasterCSV::Converters built-in, or\n  # provide a block that handles a custom conversion.\n  #\n  # If you provide a block that takes one argument, it will be passed the field\n  # and is expected to return the converted value or the field itself.  If your\n  # block takes two arguments, it will also be passed a FieldInfo Struct,\n  # containing details about the field.  Again, the block should return a\n  # converted field or the field itself.\n  #\n  def convert(name = nil, &converter)\n    add_converter(:converters, self.class::Converters, name, &converter)\n  end\n\n  #\n  # :call-seq:\n  #   header_convert( name )\n  #   header_convert { |field| ... }\n  #   header_convert { |field, field_info| ... }\n  #\n  # Identical to FasterCSV.convert(), but for header rows.\n  #\n  # Note that this method must be called before header rows are read to have any\n  # effect.\n  #\n  def header_convert(name = nil, &converter)\n    add_converter( :header_converters,\n                   self.class::HeaderConverters,\n                   name,\n                   &converter )\n  end\n\n  include Enumerable\n\n  #\n  # Yields each row of the data source in turn.\n  #\n  # Support for Enumerable.\n  #\n  # The data source must be open for reading.\n  #\n  def each\n    while row = shift\n      yield row\n    end\n  end\n\n  #\n  # Slurps the remaining rows and returns an Array of Arrays.\n  #\n  # The data source must be open for reading.\n  #\n  def read\n    rows = to_a\n    if @use_headers\n      Table.new(rows)\n    else\n      rows\n    end\n  end\n  alias_method :readlines, :read\n\n  # Returns +true+ if the next row read will be a header row.\n  def header_row?\n    @use_headers and @headers.nil?\n  end\n\n  #\n  # The primary read method for wrapped Strings and IOs, a single row is pulled\n  # from the data source, parsed and returned as an Array of fields (if header\n  # rows are not used) or a FasterCSV::Row (when header rows are used).\n  #\n  # The data source must be open for reading.\n  #\n  def shift\n    #########################################################################\n    ### This method is purposefully kept a bit long as simple conditional ###\n    ### checks are faster than numerous (expensive) method calls.         ###\n    #########################################################################\n\n    # handle headers not based on document content\n    if header_row? and @return_headers and\n       [Array, String].include? @use_headers.class\n      if @unconverted_fields\n        return add_unconverted_fields(parse_headers, Array.new)\n      else\n        return parse_headers\n      end\n    end\n\n    # begin with a blank line, so we can always add to it\n    line = String.new\n\n    #\n    # it can take multiple calls to <tt>@io.gets()</tt> to get a full line,\n    # because of \\r and/or \\n characters embedded in quoted fields\n    #\n    loop do\n      # add another read to the line\n      begin\n        line  += @io.gets(@row_sep)\n      rescue\n        return nil\n      end\n      # copy the line so we can chop it up in parsing\n      parse =  line.dup\n      parse.sub!(@parsers[:line_end], \"\")\n\n      #\n      # I believe a blank line should be an <tt>Array.new</tt>, not\n      # CSV's <tt>[nil]</tt>\n      #\n      if parse.empty?\n        @lineno += 1\n        if @skip_blanks\n          line = \"\"\n          next\n        elsif @unconverted_fields\n          return add_unconverted_fields(Array.new, Array.new)\n        elsif @use_headers\n          return FasterCSV::Row.new(Array.new, Array.new)\n        else\n          return Array.new\n        end\n      end\n\n      # parse the fields with a mix of String#split and regular expressions\n      csv           = Array.new\n      current_field = String.new\n      field_quotes  = 0\n      parse.split(@col_sep, -1).each do |match|\n        if current_field.empty? && match.count(@quote_and_newlines).zero?\n          csv           << (match.empty? ? nil : match)\n        elsif(current_field.empty? ? match[0] : current_field[0]) == @quote_char[0]\n          current_field << match\n          field_quotes += match.count(@quote_char)\n          if field_quotes % 2 == 0\n            in_quotes = current_field[@parsers[:quoted_field], 1]\n            raise MalformedCSVError unless in_quotes\n            current_field = in_quotes\n            current_field.gsub!(@quote_char * 2, @quote_char) # unescape contents\n            csv           << current_field\n            current_field =  String.new\n            field_quotes  =  0\n          else # we found a quoted field that spans multiple lines\n            current_field << @col_sep\n          end\n        elsif match.count(\"\\r\\n\").zero?\n          raise MalformedCSVError, \"Illegal quoting on line #{lineno + 1}.\"\n        else\n          raise MalformedCSVError, \"Unquoted fields do not allow \" +\n                                   \"\\\\r or \\\\n (line #{lineno + 1}).\"\n        end\n      end\n\n      # if parse is empty?(), we found all the fields on the line...\n      if field_quotes % 2 == 0\n        @lineno += 1\n\n        # save fields unconverted fields, if needed...\n        unconverted = csv.dup if @unconverted_fields\n\n        # convert fields, if needed...\n        csv = convert_fields(csv) unless @use_headers or @converters.empty?\n        # parse out header rows and handle FasterCSV::Row conversions...\n        csv = parse_headers(csv)  if     @use_headers\n\n        # inject unconverted fields and accessor, if requested...\n        if @unconverted_fields and not csv.respond_to? :unconverted_fields\n          add_unconverted_fields(csv, unconverted)\n        end\n\n        # return the results\n        break csv\n      end\n      # if we're not empty?() but at eof?(), a quoted field wasn't closed...\n      if @io.eof?\n        raise MalformedCSVError, \"Unclosed quoted field on line #{lineno + 1}.\"\n      elsif @field_size_limit and current_field.size >= @field_size_limit\n        raise MalformedCSVError, \"Field size exceeded on line #{lineno + 1}.\"\n      end\n      # otherwise, we need to loop and pull some more data to complete the row\n    end\n  end\n  alias_method :gets,     :shift\n  alias_method :readline, :shift\n\n  # Returns a simplified description of the key FasterCSV attributes.\n  def inspect\n    str = \"<##{self.class} io_type:\"\n    # show type of wrapped IO\n    if    @io == $stdout then str << \"$stdout\"\n    elsif @io == $stdin  then str << \"$stdin\"\n    elsif @io == $stderr then str << \"$stderr\"\n    else                      str << @io.class.to_s\n    end\n    # show IO.path(), if available\n    if @io.respond_to?(:path) and (p = @io.path)\n      str << \" io_path:#{p.inspect}\"\n    end\n    # show other attributes\n    %w[ lineno     col_sep     row_sep\n        quote_char skip_blanks encoding ].each do |attr_name|\n      if a = instance_variable_get(\"@#{attr_name}\")\n        str << \" #{attr_name}:#{a.inspect}\"\n      end\n    end\n    if @use_headers\n      str << \" headers:#{(@headers || true).inspect}\"\n    end\n    str << \">\"\n  end\n\n  private\n\n  #\n  # Stores the indicated separators for later use.\n  #\n  # If auto-discovery was requested for <tt>@row_sep</tt>, this method will read\n  # ahead in the <tt>@io</tt> and try to find one.  +ARGF+, +STDIN+, +STDOUT+,\n  # +STDERR+ and any stream open for output only with a default\n  # <tt>@row_sep</tt> of <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>).\n  #\n  # This method also establishes the quoting rules used for CSV output.\n  #\n  def init_separators(options)\n    # store the selected separators\n    @col_sep            = options.delete(:col_sep)\n    @row_sep            = options.delete(:row_sep)\n    @quote_char         = options.delete(:quote_char)\n    @quote_and_newlines = \"#{@quote_char}\\r\\n\"\n\n    if @quote_char.length != 1\n      raise ArgumentError, \":quote_char has to be a single character String\"\n    end\n\n    # automatically discover row separator when requested\n    if @row_sep == :auto\n      if [ARGF, STDIN, STDOUT, STDERR].include?(@io) or\n        (defined?(Zlib) and @io.class == Zlib::GzipWriter)\n        @row_sep = $INPUT_RECORD_SEPARATOR\n      else\n        begin\n          saved_pos = @io.pos  # remember where we were\n          while @row_sep == :auto\n            #\n            # if we run out of data, it's probably a single line\n            # (use a sensible default)\n            #\n            if @io.eof?\n              @row_sep = $INPUT_RECORD_SEPARATOR\n              break\n            end\n\n            # read ahead a bit\n            sample =  @io.read(1024)\n            sample += @io.read(1) if sample[-1..-1] == \"\\r\" and not @io.eof?\n\n            # try to find a standard separator\n            if sample =~ /\\r\\n?|\\n/\n              @row_sep = $&\n              break\n            end\n          end\n          # tricky seek() clone to work around GzipReader's lack of seek()\n          @io.rewind\n          # reset back to the remembered position\n          while saved_pos > 1024  # avoid loading a lot of data into memory\n            @io.read(1024)\n            saved_pos -= 1024\n          end\n          @io.read(saved_pos) if saved_pos.nonzero?\n        rescue IOError  # stream not opened for reading\n          @row_sep = $INPUT_RECORD_SEPARATOR\n        end\n      end\n    end\n\n    # establish quoting rules\n    do_quote = lambda do |field|\n      @quote_char                                      +\n      String(field).gsub(@quote_char, @quote_char * 2) +\n      @quote_char\n    end\n    @quote = if options.delete(:force_quotes)\n      do_quote\n    else\n      lambda do |field|\n        if field.nil?  # represent +nil+ fields as empty unquoted fields\n          \"\"\n        else\n          field = String(field)  # Stringify fields\n          # represent empty fields as empty quoted fields\n          if field.empty? or\n             field.count(\"\\r\\n#{@col_sep}#{@quote_char}\").nonzero?\n            do_quote.call(field)\n          else\n            field  # unquoted field\n          end\n        end\n      end\n    end\n  end\n\n  # Pre-compiles parsers and stores them by name for access during reads.\n  def init_parsers(options)\n    # store the parser behaviors\n    @skip_blanks      = options.delete(:skip_blanks)\n    @encoding         = options.delete(:encoding)  # nil will use $KCODE\n    @field_size_limit = options.delete(:field_size_limit)\n\n    # prebuild Regexps for faster parsing\n    esc_col_sep = Regexp.escape(@col_sep)\n    esc_row_sep = Regexp.escape(@row_sep)\n    esc_quote   = Regexp.escape(@quote_char)\n    @parsers = {\n      :any_field      => Regexp.new( \"[^#{esc_col_sep}]+\",\n                                     Regexp::MULTILINE,\n                                     @encoding ),\n      :quoted_field   => Regexp.new( \"^#{esc_quote}(.*)#{esc_quote}$\",\n                                     Regexp::MULTILINE,\n                                     @encoding ),\n      # safer than chomp!()\n      :line_end       => Regexp.new(\"#{esc_row_sep}\\\\z\", nil, @encoding)\n    }\n  end\n\n  #\n  # Loads any converters requested during construction.\n  #\n  # If +field_name+ is set <tt>:converters</tt> (the default) field converters\n  # are set.  When +field_name+ is <tt>:header_converters</tt> header converters\n  # are added instead.\n  #\n  # The <tt>:unconverted_fields</tt> option is also actived for\n  # <tt>:converters</tt> calls, if requested.\n  #\n  def init_converters(options, field_name = :converters)\n    if field_name == :converters\n      @unconverted_fields = options.delete(:unconverted_fields)\n    end\n\n    instance_variable_set(\"@#{field_name}\", Array.new)\n\n    # find the correct method to add the coverters\n    convert = method(field_name.to_s.sub(/ers\\Z/, \"\"))\n\n    # load converters\n    unless options[field_name].nil?\n      # allow a single converter not wrapped in an Array\n      unless options[field_name].is_a? Array\n        options[field_name] = [options[field_name]]\n      end\n      # load each converter...\n      options[field_name].each do |converter|\n        if converter.is_a? Proc  # custom code block\n          convert.call(&converter)\n        else                     # by name\n          convert.call(converter)\n        end\n      end\n    end\n\n    options.delete(field_name)\n  end\n\n  # Stores header row settings and loads header converters, if needed.\n  def init_headers(options)\n    @use_headers    = options.delete(:headers)\n    @return_headers = options.delete(:return_headers)\n    @write_headers  = options.delete(:write_headers)\n\n    # headers must be delayed until shift(), in case they need a row of content\n    @headers = nil\n\n    init_converters(options, :header_converters)\n  end\n\n  #\n  # The actual work method for adding converters, used by both\n  # FasterCSV.convert() and FasterCSV.header_convert().\n  #\n  # This method requires the +var_name+ of the instance variable to place the\n  # converters in, the +const+ Hash to lookup named converters in, and the\n  # normal parameters of the FasterCSV.convert() and FasterCSV.header_convert()\n  # methods.\n  #\n  def add_converter(var_name, const, name = nil, &converter)\n    if name.nil?  # custom converter\n      instance_variable_get(\"@#{var_name}\") << converter\n    else          # named converter\n      combo = const[name]\n      case combo\n      when Array  # combo converter\n        combo.each do |converter_name|\n          add_converter(var_name, const, converter_name)\n        end\n      else        # individual named converter\n        instance_variable_get(\"@#{var_name}\") << combo\n      end\n    end\n  end\n\n  #\n  # Processes +fields+ with <tt>@converters</tt>, or <tt>@header_converters</tt>\n  # if +headers+ is passed as +true+, returning the converted field set.  Any\n  # converter that changes the field into something other than a String halts\n  # the pipeline of conversion for that field.  This is primarily an efficiency\n  # shortcut.\n  #\n  def convert_fields(fields, headers = false)\n    # see if we are converting headers or fields\n    converters = headers ? @header_converters : @converters\n\n    fields.enum_for(:each_with_index).map do |field, index|  # map_with_index\n      converters.each do |converter|\n        field = if converter.arity == 1  # straight field converter\n          converter[field]\n        else                             # FieldInfo converter\n          header = @use_headers && !headers ? @headers[index] : nil\n          converter[field, FieldInfo.new(index, lineno, header)]\n        end\n        break unless field.is_a? String  # short-curcuit pipeline for speed\n      end\n      field  # return final state of each field, converted or original\n    end\n  end\n\n  #\n  # This methods is used to turn a finished +row+ into a FasterCSV::Row.  Header\n  # rows are also dealt with here, either by returning a FasterCSV::Row with\n  # identical headers and fields (save that the fields do not go through the\n  # converters) or by reading past them to return a field row. Headers are also\n  # saved in <tt>@headers</tt> for use in future rows.\n  #\n  # When +nil+, +row+ is assumed to be a header row not based on an actual row\n  # of the stream.\n  #\n  def parse_headers(row = nil)\n    if @headers.nil?                # header row\n      @headers = case @use_headers  # save headers\n                 # Array of headers\n                 when Array  then @use_headers\n                 # CSV header String\n                 when String\n                   self.class.parse_line( @use_headers,\n                                          :col_sep    => @col_sep,\n                                          :row_sep    => @row_sep,\n                                          :quote_char => @quote_char )\n                 # first row is headers\n                 else             row\n                 end\n\n      # prepare converted and unconverted copies\n      row      = @headers                       if row.nil?\n      @headers = convert_fields(@headers, true)\n\n      if @return_headers                                     # return headers\n        return FasterCSV::Row.new(@headers, row, true)\n      elsif not [Array, String].include? @use_headers.class  # skip to field row\n        return shift\n      end\n    end\n\n    FasterCSV::Row.new(@headers, convert_fields(row))  # field row\n  end\n\n  #\n  # Thiw methods injects an instance variable <tt>unconverted_fields</tt> into\n  # +row+ and an accessor method for it called unconverted_fields().  The\n  # variable is set to the contents of +fields+.\n  #\n  def add_unconverted_fields(row, fields)\n    class << row\n      attr_reader :unconverted_fields\n    end\n    row.instance_eval { @unconverted_fields = fields }\n    row\n  end\nend\n\n# Another name for FasterCSV.\nFCSV = FasterCSV\n\n# Another name for FasterCSV::instance().\ndef FasterCSV(*args, &block)\n  FasterCSV.instance(*args, &block)\nend\n\n# Another name for FCSV::instance().\ndef FCSV(*args, &block)\n  FCSV.instance(*args, &block)\nend\n\nclass Array\n  # Equivalent to <tt>FasterCSV::generate_line(self, options)</tt>.\n  def to_csv(options = Hash.new)\n    FasterCSV.generate_line(self, options)\n  end\nend\n\nclass String\n  # Equivalent to <tt>FasterCSV::parse_line(self, options)</tt>.\n  def parse_csv(options = Hash.new)\n    FasterCSV.parse_line(self, options)\n  end\nend\n"
  },
  {
    "path": "lib/float.rb",
    "content": "class Float\n  def round_to(x)\n    (self * 10**x).round.to_f / 10**x\n  end\n\n  def ceil_to(x)\n    (self * 10**x).ceil.to_f / 10**x\n  end\n\n  def floor_to(x)\n    (self * 10**x).floor.to_f / 10**x\n  end\nend\n"
  },
  {
    "path": "lib/generators/redmine_plugin/USAGE",
    "content": "Description:\n    The plugin generator creates stubs for a new Redmine plugin.\n\t\nExample:\n    ./script/generate redmine_plugin meetings\n      create  vendor/plugins/redmine_meetings/app/controllers\n      create  vendor/plugins/redmine_meetings/app/helpers\n      create  vendor/plugins/redmine_meetings/app/models\n      create  vendor/plugins/redmine_meetings/app/views\n      create  vendor/plugins/redmine_meetings/db/migrate\n      create  vendor/plugins/redmine_meetings/lib/tasks\n      create  vendor/plugins/redmine_meetings/assets/images\n      create  vendor/plugins/redmine_meetings/assets/javascripts\n      create  vendor/plugins/redmine_meetings/assets/stylesheets\n      create  vendor/plugins/redmine_meetings/lang\n      create  vendor/plugins/redmine_meetings/README\n      create  vendor/plugins/redmine_meetings/init.rb\n      create  vendor/plugins/redmine_meetings/lang/en.yml\n      create  vendor/plugins/redmine_meetings/config/locales/en.yml\n      create  vendor/plugins/redmine_meetings/test/test_helper.rb\n"
  },
  {
    "path": "lib/generators/redmine_plugin/redmine_plugin_generator.rb",
    "content": "class RedminePluginGenerator < Rails::Generator::NamedBase\n  attr_reader :plugin_path, :plugin_name, :plugin_pretty_name\n\n  def initialize(runtime_args, runtime_options = {})\n    super\n    @plugin_name = \"redmine_#{file_name.underscore}\"\n    @plugin_pretty_name = plugin_name.titleize\n    @plugin_path = \"vendor/plugins/#{plugin_name}\"\n  end\n\n  def manifest\n    record do |m|\n      m.directory \"#{plugin_path}/app/controllers\"\n      m.directory \"#{plugin_path}/app/helpers\"\n      m.directory \"#{plugin_path}/app/models\"\n      m.directory \"#{plugin_path}/app/views\"\n      m.directory \"#{plugin_path}/db/migrate\"\n      m.directory \"#{plugin_path}/lib/tasks\"\n      m.directory \"#{plugin_path}/assets/images\"\n      m.directory \"#{plugin_path}/assets/javascripts\"\n      m.directory \"#{plugin_path}/assets/stylesheets\"\n      m.directory \"#{plugin_path}/lang\"\n      m.directory \"#{plugin_path}/config/locales\"\n      m.directory \"#{plugin_path}/test\"\n\n      m.template 'README.rdoc',    \"#{plugin_path}/README.rdoc\"\n      m.template 'init.rb.erb',   \"#{plugin_path}/init.rb\"\n      m.template 'en.yml',    \"#{plugin_path}/lang/en.yml\"\n      m.template 'en_rails_i18n.yml',    \"#{plugin_path}/config/locales/en.yml\"\n      m.template 'test_helper.rb.erb',    \"#{plugin_path}/test/test_helper.rb\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/generators/redmine_plugin/templates/README.rdoc",
    "content": "= <%= file_name %>\n\nDescription goes here\n"
  },
  {
    "path": "lib/generators/redmine_plugin/templates/en.yml",
    "content": "# English strings go here\nmy_label: \"My label\"\n"
  },
  {
    "path": "lib/generators/redmine_plugin/templates/en_rails_i18n.yml",
    "content": "# English strings go here for Rails i18n\nen:\n  my_label: \"My label\"\n"
  },
  {
    "path": "lib/generators/redmine_plugin/templates/init.rb.erb",
    "content": "require 'redmine'\n\nRedmine::Plugin.register :<%= plugin_name %> do\n  name '<%= plugin_pretty_name %> plugin'\n  author 'Author name'\n  description 'This is a plugin for Redmine'\n  version '0.0.1'\nend\n"
  },
  {
    "path": "lib/generators/redmine_plugin/templates/test_helper.rb.erb",
    "content": "# Load the normal Rails helper\nrequire File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')\n\n# Ensure that we are using the temporary fixture path\nEngines::Testing.set_fixture_path\n"
  },
  {
    "path": "lib/generators/redmine_plugin_controller/USAGE",
    "content": "Description:\n    Generates a plugin controller.\n\nExample:\n    ./script/generate redmine_plugin_controller MyPlugin Pools index show vote\n"
  },
  {
    "path": "lib/generators/redmine_plugin_controller/redmine_plugin_controller_generator.rb",
    "content": "require 'rails_generator/base'\nrequire 'rails_generator/generators/components/controller/controller_generator'\n\nclass RedminePluginControllerGenerator < ControllerGenerator\n  attr_reader :plugin_path, :plugin_name, :plugin_pretty_name\n\n  def initialize(runtime_args, runtime_options = {})\n    runtime_args = runtime_args.dup\n    @plugin_name = \"redmine_\" + runtime_args.shift.underscore\n    @plugin_pretty_name = plugin_name.titleize\n    @plugin_path = \"vendor/plugins/#{plugin_name}\"\n    super(runtime_args, runtime_options)\n  end\n\n  def destination_root\n    File.join(RAILS_ROOT, plugin_path)\n  end\n\n  def manifest\n    record do |m|\n      # Check for class naming collisions.\n      m.class_collisions class_path, \"#{class_name}Controller\", \"#{class_name}ControllerTest\", \"#{class_name}Helper\"\n\n      # Controller, helper, views, and test directories.\n      m.directory File.join('app/controllers', class_path)\n      m.directory File.join('app/helpers', class_path)\n      m.directory File.join('app/views', class_path, file_name)\n      m.directory File.join('test/functional', class_path)\n\n      # Controller class, functional test, and helper class.\n      m.template 'controller.rb.erb',\n                  File.join('app/controllers',\n                            class_path,\n                            \"#{file_name}_controller.rb\")\n\n      m.template 'functional_test.rb.erb',\n                  File.join('test/functional',\n                            class_path,\n                            \"#{file_name}_controller_test.rb\")\n\n      m.template 'helper.rb.erb',\n                  File.join('app/helpers',\n                            class_path,\n                            \"#{file_name}_helper.rb\")\n\n      # View template for each action.\n      actions.each do |action|\n        path = File.join('app/views', class_path, file_name, \"#{action}.html.erb\")\n        m.template 'view.html.erb', path,\n          :assigns => { :action => action, :path => path }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/generators/redmine_plugin_controller/templates/controller.rb.erb",
    "content": "class <%= class_name %>Controller < ApplicationController\n<% actions.each do |action| -%>\n\n  def <%= action %>\n  end\n<% end -%>\nend\n"
  },
  {
    "path": "lib/generators/redmine_plugin_controller/templates/functional_test.rb.erb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass <%= class_name %>ControllerTest < ActionController::TestCase\n  # Replace this with your real tests.\n  def test_truth\n    assert true\n  end\nend\n"
  },
  {
    "path": "lib/generators/redmine_plugin_controller/templates/helper.rb.erb",
    "content": "module <%= class_name %>Helper\nend\n"
  },
  {
    "path": "lib/generators/redmine_plugin_controller/templates/view.html.erb",
    "content": "<h2><%= class_name %>#<%= action %></h2>\n"
  },
  {
    "path": "lib/generators/redmine_plugin_model/USAGE",
    "content": "Description:\n    Generates a plugin model.\n\nExamples:\n    ./script/generate redmine_plugin_model MyPlugin pool title:string question:text\n"
  },
  {
    "path": "lib/generators/redmine_plugin_model/redmine_plugin_model_generator.rb",
    "content": "require 'rails_generator/base'\nrequire 'rails_generator/generators/components/model/model_generator'\n\nclass RedminePluginModelGenerator < ModelGenerator\n  attr_accessor :plugin_path, :plugin_name, :plugin_pretty_name\n\n  def initialize(runtime_args, runtime_options = {})\n    runtime_args = runtime_args.dup\n    @plugin_name = \"redmine_\" + runtime_args.shift.underscore\n    @plugin_pretty_name = plugin_name.titleize\n    @plugin_path = \"vendor/plugins/#{plugin_name}\"\n    super(runtime_args, runtime_options)\n  end\n\n  def destination_root\n    File.join(RAILS_ROOT, plugin_path)\n  end\n\n  def manifest\n    record do |m|\n      # Check for class naming collisions.\n      m.class_collisions class_path, class_name, \"#{class_name}Test\"\n\n      # Model, test, and fixture directories.\n      m.directory File.join('app/models', class_path)\n      m.directory File.join('test/unit', class_path)\n      m.directory File.join('test/fixtures', class_path)\n\n      # Model class, unit test, and fixtures.\n      m.template 'model.rb.erb',      File.join('app/models', class_path, \"#{file_name}.rb\")\n      m.template 'unit_test.rb.erb',  File.join('test/unit', class_path, \"#{file_name}_test.rb\")\n\n      unless options[:skip_fixture]\n         m.template 'fixtures.yml',  File.join('test/fixtures', \"#{table_name}.yml\")\n      end\n\n      unless options[:skip_migration]\n        m.migration_template 'migration.rb.erb', 'db/migrate', :assigns => {\n          :migration_name => \"Create#{class_name.pluralize.gsub(/::/, '')}\"\n        }, :migration_file_name => \"create_#{file_path.gsub(/\\//, '_').pluralize}\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/generators/redmine_plugin_model/templates/fixtures.yml",
    "content": "# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html\none:\n  id: 1\n<% for attribute in attributes -%>\n  <%= attribute.name %>: <%= attribute.default %>\n<% end -%>\ntwo:\n  id: 2\n<% for attribute in attributes -%>\n  <%= attribute.name %>: <%= attribute.default %>\n<% end -%>\n"
  },
  {
    "path": "lib/generators/redmine_plugin_model/templates/migration.rb.erb",
    "content": "class <%= migration_name %> < ActiveRecord::Migration\n  def self.up\n    create_table :<%= table_name %> do |t|\n<% for attribute in attributes -%>\n      t.column :<%= attribute.name %>, :<%= attribute.type %>\n<% end -%>\n    end\n  end\n\n  def self.down\n    drop_table :<%= table_name %>\n  end\nend\n"
  },
  {
    "path": "lib/generators/redmine_plugin_model/templates/model.rb.erb",
    "content": "class <%= class_name %> < ActiveRecord::Base\nend\n"
  },
  {
    "path": "lib/generators/redmine_plugin_model/templates/unit_test.rb.erb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass <%= class_name %>Test < ActiveSupport::TestCase\n  fixtures :<%= table_name %>\n\n  # Replace this with your real tests.\n  def test_truth\n    assert true\n  end\nend\n"
  },
  {
    "path": "lib/mention.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nclass Mention\n  def self.parse(object, mentioner_id)\n    #loop through properties and only search for mentions in text fields\n    object.attributes.each_value do |text|\n      next if text.class.to_s != 'String'\n      text = text.gsub(%r{([\\s\\(,\\-\\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\\d+)|(@)([a-zA-Z0-9._@]+)|(:)([^\"\\s<>][^\\s<>]*?|\"[^\"]+?\"))(?=(?=[[:punct:]]\\W)|,|\\s|<|$)}) do |m|\n        leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8\n        if esc.nil?\n          if sep == '@'\n            send_mention(object,mentioner_id,oid,text)\n          end\n        end\n      end\n    end\n  end\n\n  def self.send_mention(object,mentioner_id, mentioned_login, mention_text)\n    #Find user or abort\n    user = User.find_by_login(mentioned_login)\n\n    return if user.nil?\n\n    #Find better sub-section of text that includes user login\n    mention_text_subsection = mention_text\n\n    #Send mention to issue\n    object.send(:mention,mentioner_id,user.id,mention_text_subsection)\n  end\n\nend\n"
  },
  {
    "path": "lib/redcloth3.rb",
    "content": "#                                vim:ts=4:sw=4:\n# = RedCloth - Textile and Markdown Hybrid for Ruby\n#\n# Homepage::  http://whytheluckystiff.net/ruby/redcloth/\n# Author::    why the lucky stiff (http://whytheluckystiff.net/)\n# Copyright:: (cc) 2004 why the lucky stiff (and his puppet organizations.)\n# License::   BSD\n#\n# (see http://hobix.com/textile/ for a Textile Reference.)\n#\n# Based on (and also inspired by) both:\n#\n# PyTextile: http://diveintomark.org/projects/textile/textile.py.txt\n# Textism for PHP: http://www.textism.com/tools/textile/\n#\n#\n\n# = RedCloth\n#\n# RedCloth is a Ruby library for converting Textile and/or Markdown\n# into HTML.  You can use either format, intermingled or separately.\n# You can also extend RedCloth to honor your own custom text stylings.\n#\n# RedCloth users are encouraged to use Textile if they are generating\n# HTML and to use Markdown if others will be viewing the plain text.\n#\n# == What is Textile?\n#\n# Textile is a simple formatting style for text\n# documents, loosely based on some HTML conventions.\n#\n# == Sample Textile Text\n#\n#  h2. This is a title\n#\n#  h3. This is a subhead\n#\n#  This is a bit of paragraph.\n#\n#  bq. This is a blockquote.\n#\n# = Writing Textile\n#\n# A Textile document consists of paragraphs.  Paragraphs\n# can be specially formatted by adding a small instruction\n# to the beginning of the paragraph.\n#\n#  h[n].   Header of size [n].\n#  bq.     Blockquote.\n#  #       Numeric list.\n#  *       Bulleted list.\n#\n# == Quick Phrase Modifiers\n#\n# Quick phrase modifiers are also included, to allow formatting\n# of small portions of text within a paragraph.\n#\n#  \\_emphasis\\_\n#  \\_\\_italicized\\_\\_\n#  \\*strong\\*\n#  \\*\\*bold\\*\\*\n#  ??citation??\n#  -deleted text-\n#  +inserted text+\n#  ^superscript^\n#  ~subscript~\n#  @code@\n#  %(classname)span%\n#\n#  ==notextile== (leave text alone)\n#\n# == Links\n#\n# To make a hypertext link, put the link text in \"quotation\n# marks\" followed immediately by a colon and the URL of the link.\n#\n# Optional: text in (parentheses) following the link text,\n# but before the closing quotation mark, will become a Title\n# attribute for the link, visible as a tool tip when a cursor is above it.\n#\n# Example:\n#\n#  \"This is a link (This is a title) \":http://www.textism.com\n#\n# Will become:\n#\n#  <a href=\"http://www.textism.com\" title=\"This is a title\">This is a link</a>\n#\n# == Images\n#\n# To insert an image, put the URL for the image inside exclamation marks.\n#\n# Optional: text that immediately follows the URL in (parentheses) will\n# be used as the Alt text for the image. Images on the web should always\n# have descriptive Alt text for the benefit of readers using non-graphical\n# browsers.\n#\n# Optional: place a colon followed by a URL immediately after the\n# closing ! to make the image into a link.\n#\n# Example:\n#\n#  !http://www.textism.com/common/textist.gif(Textist)!\n#\n# Will become:\n#\n#  <img src=\"http://www.textism.com/common/textist.gif\" alt=\"Textist\" />\n#\n# With a link:\n#\n#  !/common/textist.gif(Textist)!:http://textism.com\n#\n# Will become:\n#\n#  <a href=\"http://textism.com\"><img src=\"/common/textist.gif\" alt=\"Textist\" /></a>\n#\n# == Defining Acronyms\n#\n# HTML allows authors to define acronyms via the tag. The definition appears as a\n# tool tip when a cursor hovers over the acronym. A crucial aid to clear writing,\n# this should be used at least once for each acronym in documents where they appear.\n#\n# To quickly define an acronym in Textile, place the full text in (parentheses)\n# immediately following the acronym.\n#\n# Example:\n#\n#  ACLU(American Civil Liberties Union)\n#\n# Will become:\n#\n#  <acronym title=\"American Civil Liberties Union\">ACLU</acronym>\n#\n# == Adding Tables\n#\n# In Textile, simple tables can be added by seperating each column by\n# a pipe.\n#\n#     |a|simple|table|row|\n#     |And|Another|table|row|\n#\n# Attributes are defined by style definitions in parentheses.\n#\n#     table(border:1px solid black).\n#     (background:#ddd;color:red). |{}| | | |\n#\n# == Using RedCloth\n#\n# RedCloth is simply an extension of the String class, which can handle\n# Textile formatting.  Use it like a String and output HTML with its\n# RedCloth#to_html method.\n#\n#  doc = RedCloth.new \"\n#\n#  h2. Test document\n#\n#  Just a simple test.\"\n#\n#  puts doc.to_html\n#\n# By default, RedCloth uses both Textile and Markdown formatting, with\n# Textile formatting taking precedence.  If you want to turn off Markdown\n# formatting, to boost speed and limit the processor:\n#\n#  class RedCloth::Textile.new( str )\n\nclass RedCloth3 < String\n\n    VERSION = '3.0.4'\n    DEFAULT_RULES = [:textile, :markdown]\n\n    #\n    # Two accessor for setting security restrictions.\n    #\n    # This is a nice thing if you're using RedCloth for\n    # formatting in public places (e.g. Wikis) where you\n    # don't want users to abuse HTML for bad things.\n    #\n    # If +:filter_html+ is set, HTML which wasn't\n    # created by the Textile processor will be escaped.\n    #\n    # If +:filter_styles+ is set, it will also disable\n    # the style markup specifier. ('{color: red}')\n    #\n    attr_accessor :filter_html, :filter_styles\n\n    #\n    # Accessor for toggling hard breaks.\n    #\n    # If +:hard_breaks+ is set, single newlines will\n    # be converted to HTML break tags.  This is the\n    # default behavior for traditional RedCloth.\n    #\n    attr_accessor :hard_breaks\n\n    # Accessor for toggling lite mode.\n    #\n    # In lite mode, block-level rules are ignored.  This means\n    # that tables, paragraphs, lists, and such aren't available.\n    # Only the inline markup for bold, italics, entities and so on.\n    #\n    #   r = RedCloth.new( \"And then? She *fell*!\", [:lite_mode] )\n    #   r.to_html\n    #   #=> \"And then? She <strong>fell</strong>!\"\n    #\n    attr_accessor :lite_mode\n\n    #\n    # Accessor for toggling span caps.\n    #\n    # Textile places `span' tags around capitalized\n    # words by default, but this wreaks havoc on Wikis.\n    # If +:no_span_caps+ is set, this will be\n    # suppressed.\n    #\n    attr_accessor :no_span_caps\n\n    #\n    # Establishes the markup predence.  Available rules include:\n    #\n    # == Textile Rules\n    #\n    # The following textile rules can be set individually.  Or add the complete\n    # set of rules with the single :textile rule, which supplies the rule set in\n    # the following precedence:\n    #\n    # refs_textile::          Textile references (i.e. [hobix]http://hobix.com/)\n    # block_textile_table::   Textile table block structures\n    # block_textile_lists::   Textile list structures\n    # block_textile_prefix::  Textile blocks with prefixes (i.e. bq., h2., etc.)\n    # inline_textile_image::  Textile inline images\n    # inline_textile_link::   Textile inline links\n    # inline_textile_span::   Textile inline spans\n    # glyphs_textile:: Textile entities (such as em-dashes and smart quotes)\n    #\n    # == Markdown\n    #\n    # refs_markdown::         Markdown references (for example: [hobix]: http://hobix.com/)\n    # block_markdown_setext:: Markdown setext headers\n    # block_markdown_atx::    Markdown atx headers\n    # block_markdown_rule::   Markdown horizontal rules\n    # block_markdown_bq::     Markdown blockquotes\n    # block_markdown_lists::  Markdown lists\n    # inline_markdown_link::  Markdown links\n    attr_accessor :rules\n\n    # Returns a new RedCloth object, based on _string_ and\n    # enforcing all the included _restrictions_.\n    #\n    #   r = RedCloth.new( \"h1. A <b>bold</b> man\", [:filter_html] )\n    #   r.to_html\n    #     #=>\"<h1>A &lt;b&gt;bold&lt;/b&gt; man</h1>\"\n    #\n    def initialize( string, restrictions = [] )\n        restrictions.each { |r| method( \"#{ r }=\" ).call( true ) }\n        super( string )\n    end\n\n    #\n    # Generates HTML from the Textile contents.\n    #\n    #   r = RedCloth.new( \"And then? She *fell*!\" )\n    #   r.to_html( true )\n    #     #=>\"And then? She <strong>fell</strong>!\"\n    #\n    def to_html( *rules )\n        rules = DEFAULT_RULES if rules.empty?\n        # make our working copy\n        text = self.dup\n\n        @urlrefs = {}\n        @shelf = []\n        textile_rules = [:block_textile_table, :block_textile_lists,\n                         :block_textile_prefix, :inline_textile_image, :inline_textile_link,\n                         :inline_textile_code, :inline_textile_span, :glyphs_textile]\n        markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule,\n                          :block_markdown_bq, :block_markdown_lists,\n                          :inline_markdown_reflink, :inline_markdown_link]\n        @rules = rules.collect do |rule|\n            case rule\n            when :markdown\n                markdown_rules\n            when :textile\n                textile_rules\n            else\n                rule\n            end\n        end.flatten\n\n        # standard clean up\n        incoming_entities text\n        clean_white_space text\n\n        # start processor\n        @pre_list = []\n        rip_offtags text\n        no_textile text\n        escape_html_tags text\n        hard_break text\n        unless @lite_mode\n            refs text\n            # need to do this before text is split by #blocks\n            block_textile_quotes text\n            blocks text\n        end\n        inline text\n        smooth_offtags text\n\n        retrieve text\n\n        text.gsub!( /<\\/?notextile>/, '' )\n        text.gsub!( /x%x%/, '&#38;' )\n        clean_html text if filter_html\n        text.strip!\n        text\n\n    end\n\n    #######\n    private\n    #######\n    #\n    # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents.\n    # (from PyTextile)\n    #\n    TEXTILE_TAGS =\n\n        [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230],\n         [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249],\n         [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217],\n         [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732],\n         [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]].\n\n        collect! do |a, b|\n            [a.chr, ( b.zero? and \"\" or \"&#{ b };\" )]\n        end\n\n    #\n    # Regular expressions to convert to HTML.\n    #\n    A_HLGN = /(?:(?:<>|<|>|\\=|[()]+)+)/\n    A_VLGN = /[\\-^~]/\n    C_CLAS = '(?:\\([^)]+\\))'\n    C_LNGE = '(?:\\[[^\\[\\]]+\\])'\n    C_STYL = '(?:\\{[^}]+\\})'\n    S_CSPN = '(?:\\\\\\\\\\d+)'\n    S_RSPN = '(?:/\\d+)'\n    A = \"(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)\"\n    S = \"(?:#{S_CSPN}?#{S_RSPN}|#{S_RSPN}?#{S_CSPN}?)\"\n    C = \"(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)\"\n    # PUNCT = Regexp::quote( '!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`{|}~' )\n    PUNCT = Regexp::quote( '!\"#$%&\\'*+,-./:;=?@\\\\^_`|~' )\n    PUNCT_NOQ = Regexp::quote( '!\"#$&\\',./:;=?@\\\\`|' )\n    PUNCT_Q = Regexp::quote( '*-_+^~%' )\n    HYPERLINK = '(\\S+?)([^\\w\\s/;=\\?]*?)(?=\\s|<|$)'\n\n    # Text markup tags, don't conflict with block tags\n    SIMPLE_HTML_TAGS = [\n        'tt', 'b', 'i', 'big', 'small', 'em', 'strong', 'dfn', 'code',\n        'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'a', 'img', 'br',\n        'br', 'map', 'q', 'sub', 'sup', 'span', 'bdo'\n    ]\n\n    QTAGS = [\n        ['**', 'b', :limit],\n        ['*', 'strong', :limit],\n        ['??', 'cite', :limit],\n        ['-', 'del', :limit],\n        ['__', 'i', :limit],\n        ['_', 'em', :limit],\n        ['%', 'span', :limit],\n        ['+', 'ins', :limit],\n        ['^', 'sup', :limit],\n        ['~', 'sub', :limit]\n    ]\n    QTAGS.collect! do |rc, ht, rtype|\n        rcq = Regexp::quote rc\n        re =\n            case rtype\n            when :limit\n                /(^|[>\\s\\(])\n                (#{rcq})\n                (#{C})\n                (?::(\\S+?))?\n                (\\w|[^\\s\\-].*?[^\\s\\-])\n                #{rcq}\n                (?=[[:punct:]]|\\s|\\)|$)/x\n            else\n                /(#{rcq})\n                (#{C})\n                (?::(\\S+))?\n                (\\w|[^\\s\\-].*?[^\\s\\-])\n                #{rcq}/xm\n            end\n        [rc, ht, re, rtype]\n    end\n\n    # Elements to handle\n    GLYPHS = [\n    #   [ /([^\\s\\[{(>])?\\'([dmst]\\b|ll\\b|ve\\b|\\s|:|$)/, '\\1&#8217;\\2' ], # single closing\n    #   [ /([^\\s\\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\\'/, '\\1&#8217;' ], # single closing\n    #   [ /\\'(?=[#{PUNCT_Q}]*(s\\b|[\\s#{PUNCT_NOQ}]))/, '&#8217;' ], # single closing\n    #   [ /\\'/, '&#8216;' ], # single opening\n    #   [ /</, '&lt;' ], # less-than\n    #   [ />/, '&gt;' ], # greater-than\n    #   [ /([^\\s\\[{(])?\"(\\s|:|$)/, '\\1&#8221;\\2' ], # double closing\n    #   [ /([^\\s\\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\"/, '\\1&#8221;' ], # double closing\n    #   [ /\"(?=[#{PUNCT_Q}]*[\\s#{PUNCT_NOQ}])/, '&#8221;' ], # double closing\n    #   [ /\"/, '&#8220;' ], # double opening\n    #   [ /\\b( )?\\.{3}/, '\\1&#8230;' ], # ellipsis\n    #   [ /\\b([A-Z][A-Z0-9]{2,})\\b(?:[(]([^)]*)[)])/, '<acronym title=\"\\2\">\\1</acronym>' ], # 3+ uppercase acronym\n    #   [ /(^|[^\"][>\\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^<A-Za-z0-9]|$)/, '\\1<span class=\"caps\">\\2</span>\\3', :no_span_caps ], # 3+ uppercase caps\n    #   [ /(\\.\\s)?\\s?--\\s?/, '\\1&#8212;' ], # em dash\n    #   [ /\\s->\\s/, ' &rarr; ' ], # right arrow\n    #   [ /\\s-\\s/, ' &#8211; ' ], # en dash\n    #   [ /(\\d+) ?x ?(\\d+)/, '\\1&#215;\\2' ], # dimension sign\n    #   [ /\\b ?[(\\[]TM[\\])]/i, '&#8482;' ], # trademark\n    #   [ /\\b ?[(\\[]R[\\])]/i, '&#174;' ], # registered\n    #   [ /\\b ?[(\\[]C[\\])]/i, '&#169;' ] # copyright\n    ]\n\n    H_ALGN_VALS = {\n        '<' => 'left',\n        '=' => 'center',\n        '>' => 'right',\n        '<>' => 'justify'\n    }\n\n    V_ALGN_VALS = {\n        '^' => 'top',\n        '-' => 'middle',\n        '~' => 'bottom'\n    }\n\n    #\n    # Flexible HTML escaping\n    #\n    def htmlesc( str, mode=:Quotes )\n      if str\n        str.gsub!( '&', '&amp;' )\n        str.gsub!( '\"', '&quot;' ) if mode != :NoQuotes\n        str.gsub!( \"'\", '&#039;' ) if mode == :Quotes\n        str.gsub!( '<', '&lt;')\n        str.gsub!( '>', '&gt;')\n      end\n      str\n    end\n\n    # Search and replace for Textile glyphs (quotes, dashes, other symbols)\n    def pgl( text )\n        #GLYPHS.each do |re, resub, tog|\n        #    next if tog and method( tog ).call\n        #    text.gsub! re, resub\n        #end\n        text.gsub!(/\\b([A-Z][A-Z0-9]{2,})\\b(?:[(]([^)]*)[)])/) do |m|\n          \"<acronym title=\\\"#{htmlesc $2}\\\">#{$1}</acronym>\"\n        end\n    end\n\n    # Parses Textile attribute lists and builds an HTML attribute string\n    def pba( text_in, element = \"\" )\n\n        return '' unless text_in\n\n        style = []\n        text = text_in.dup\n        if element == 'td'\n            colspan = $1 if text =~ /\\\\(\\d+)/\n            rowspan = $1 if text =~ /\\/(\\d+)/\n            style << \"vertical-align:#{ v_align( $& ) };\" if text =~ A_VLGN\n        end\n\n        style << \"#{ htmlesc $1 };\" if text.sub!( /\\{([^}]*)\\}/, '' ) && !filter_styles\n\n        lang = $1 if\n            text.sub!( /\\[([^)]+?)\\]/, '' )\n\n        cls = $1 if\n            text.sub!( /\\(([^()]+?)\\)/, '' )\n\n        style << \"padding-left:#{ $1.length }em;\" if\n            text.sub!( /([(]+)/, '' )\n\n        style << \"padding-right:#{ $1.length }em;\" if text.sub!( /([)]+)/, '' )\n\n        style << \"text-align:#{ h_align( $& ) };\" if text =~ A_HLGN\n\n        cls, id = $1, $2 if cls =~ /^(.*?)#(.*)$/\n\n        atts = ''\n        atts << \" style=\\\"#{ style.join }\\\"\" unless style.empty?\n        atts << \" class=\\\"#{ cls }\\\"\" unless cls.to_s.empty?\n        atts << \" lang=\\\"#{ lang }\\\"\" if lang\n        atts << \" id=\\\"#{ id }\\\"\" if id\n        atts << \" colspan=\\\"#{ colspan }\\\"\" if colspan\n        atts << \" rowspan=\\\"#{ rowspan }\\\"\" if rowspan\n\n        atts\n    end\n\n    TABLE_RE = /^(?:table(_?#{S}#{A}#{C})\\. ?\\n)?^(#{A}#{C}\\.? ?\\|.*?\\|)(\\n\\n|\\Z)/m\n\n    # Parses a Textile table block, building HTML from the result.\n    def block_textile_table( text )\n        text.gsub!( TABLE_RE ) do |matches|\n\n            tatts, fullrow = $~[1..2]\n            tatts = pba( tatts, 'table' )\n            tatts = shelve( tatts ) if tatts\n            rows = []\n\n            fullrow.each_line do |row|\n                ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\\. )(.*)/m\n                cells = []\n                row.split( /(\\|)(?![^\\[\\|]*\\]\\])/ )[1..-2].each do |cell|\n                    next if cell == '|'\n                    ctyp = 'd'\n                    ctyp = 'h' if cell =~ /^_/\n\n                    catts = ''\n                    catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\\. ?)(.*)/\n\n                    catts = shelve( catts ) if catts\n                    cells << \"\\t\\t\\t<t#{ ctyp }#{ catts }>#{ cell }</t#{ ctyp }>\"\n                end\n                ratts = shelve( ratts ) if ratts\n                rows << \"\\t\\t<tr#{ ratts }>\\n#{ cells.join( \"\\n\" ) }\\n\\t\\t</tr>\"\n            end\n            \"\\t<table#{ tatts }>\\n#{ rows.join( \"\\n\" ) }\\n\\t</table>\\n\\n\"\n        end\n    end\n\n    LISTS_RE = /^([#*]+?#{C} .*?)$(?![^#*])/m\n    LISTS_CONTENT_RE = /^([#*]+)(#{A}#{C}) (.*)$/m\n\n    # Parses Textile lists and generates HTML\n    def block_textile_lists( text )\n        text.gsub!( LISTS_RE ) do |match|\n            lines = match.split( /\\n/ )\n            last_line = -1\n            depth = []\n            lines.each_with_index do |line, line_id|\n                if line =~ LISTS_CONTENT_RE\n                    tl,atts,content = $~[1..3]\n                    if depth.last\n                        if depth.last.length > tl.length\n                            (depth.length - 1).downto(0) do |i|\n                                break if depth[i].length == tl.length\n                                lines[line_id - 1] << \"</li>\\n\\t</#{ lT( depth[i] ) }l>\\n\\t\"\n                                depth.pop\n                            end\n                        end\n                        if depth.last and depth.last.length == tl.length\n                            lines[line_id - 1] << '</li>'\n                        end\n                    end\n                    unless depth.last == tl\n                        depth << tl\n                        atts = pba( atts )\n                        atts = shelve( atts ) if atts\n                        lines[line_id] = \"\\t<#{ lT(tl) }l#{ atts }>\\n\\t<li>#{ content }\"\n                    else\n                        lines[line_id] = \"\\t\\t<li>#{ content }\"\n                    end\n                    last_line = line_id\n\n                else\n                    last_line = line_id\n                end\n                if line_id - last_line > 1 or line_id == lines.length - 1\n                    depth.delete_if do |v|\n                        lines[last_line] << \"</li>\\n\\t</#{ lT( v ) }l>\"\n                    end\n                end\n            end\n            lines.join( \"\\n\" )\n        end\n    end\n\n    QUOTES_RE = /(^>+([^\\n]*?)(\\n|$))+/m\n    QUOTES_CONTENT_RE = /^([> ]+)(.*)$/m\n\n    def block_textile_quotes( text )\n      text.gsub!( QUOTES_RE ) do |match|\n        lines = match.split( /\\n/ )\n        quotes = ''\n        indent = 0\n        lines.each do |line|\n          line =~ QUOTES_CONTENT_RE\n          bq,content = $1, $2\n          l = bq.count('>')\n          if l != indent\n            quotes << (\"\\n\\n\" + (l>indent ? '<blockquote>' * (l-indent) : '</blockquote>' * (indent-l)) + \"\\n\\n\")\n            indent = l\n          end\n          quotes << (content + \"\\n\")\n        end\n        quotes << (\"\\n\" + '</blockquote>' * indent + \"\\n\\n\")\n        quotes\n      end\n    end\n\n    CODE_RE = /(\\W)\n        @\n        (?:\\|(\\w+?)\\|)?\n        (.+?)\n        @\n        (?=\\W)/x\n\n    def inline_textile_code( text )\n        text.gsub!( CODE_RE ) do |m|\n            before,lang,code,after = $~[1..4]\n            lang = \" lang=\\\"#{ lang }\\\"\" if lang\n            rip_offtags( \"#{ before }<code#{ lang }>#{ code }</code>#{ after }\" )\n        end\n    end\n\n    def lT( text )\n        text =~ /\\#$/ ? 'o' : 'u'\n    end\n\n    def hard_break( text )\n        text.gsub!( /(.)\\n(?!\\Z| *([#*=]+(\\s|$)|[{|]))/, \"\\\\1<br />\" ) if hard_breaks\n    end\n\n    BLOCKS_GROUP_RE = /\\n{2,}(?! )/m\n\n    def blocks( text, deep_code = false )\n        text.replace( text.split( BLOCKS_GROUP_RE ).collect do |blk|\n            plain = blk !~ /\\A[#*> ]/\n\n            # skip blocks that are complex HTML\n            if blk =~ /^<\\/?(\\w+).*>/ and not SIMPLE_HTML_TAGS.include? $1\n                blk\n            else\n                # search for indentation levels\n                blk.strip!\n                if blk.empty?\n                    blk\n                else\n                    code_blk = nil\n                    blk.gsub!( /((?:\\n(?:\\n^ +[^\\n]*)+)+)/m ) do |iblk|\n                        flush_left iblk\n                        blocks iblk, plain\n                        iblk.gsub( /^(\\S)/, \"\\t\\\\1\" )\n                        if plain\n                            code_blk = iblk; \"\"\n                        else\n                            iblk\n                        end\n                    end\n\n                    block_applied = 0\n                    @rules.each do |rule_name|\n                        block_applied += 1 if ( rule_name.to_s.match /^block_/ and method( rule_name ).call( blk ) )\n                    end\n                    if block_applied.zero?\n                        if deep_code\n                            blk = \"\\t<pre><code>#{ blk }</code></pre>\"\n                        else\n                            blk = \"\\t<p>#{ blk }</p>\"\n                        end\n                    end\n                    # hard_break blk\n                    blk + \"\\n#{ code_blk }\"\n                end\n            end\n\n        end.join( \"\\n\\n\" ) )\n    end\n\n    def textile_bq( tag, atts, cite, content )\n        cite, cite_title = check_refs( cite )\n        cite = \" cite=\\\"#{ cite }\\\"\" if cite\n        atts = shelve( atts ) if atts\n        \"\\t<blockquote#{ cite }>\\n\\t\\t<p#{ atts }>#{ content }</p>\\n\\t</blockquote>\"\n    end\n\n    def textile_p( tag, atts, cite, content )\n        atts = shelve( atts ) if atts\n        \"\\t<#{ tag }#{ atts }>#{ content }</#{ tag }>\"\n    end\n\n    alias textile_h1 textile_p\n    alias textile_h2 textile_p\n    alias textile_h3 textile_p\n    alias textile_h4 textile_p\n    alias textile_h5 textile_p\n    alias textile_h6 textile_p\n\n    def textile_fn_( tag, num, atts, cite, content )\n        atts << \" id=\\\"fn#{ num }\\\" class=\\\"footnote\\\"\"\n        content = \"<sup>#{ num }</sup> #{ content }\"\n        atts = shelve( atts ) if atts\n        \"\\t<p#{ atts }>#{ content }</p>\"\n    end\n\n    BLOCK_RE = /^(([a-z]+)(\\d*))(#{A}#{C})\\.(?::(\\S+))? (.*)$/m\n\n    def block_textile_prefix( text )\n        if text =~ BLOCK_RE\n            tag,tagpre,num,atts,cite,content = $~[1..6]\n            atts = pba( atts )\n\n            # pass to prefix handler\n            if respond_to? \"textile_#{ tag }\", true\n                text.gsub!( $&, method( \"textile_#{ tag }\" ).call( tag, atts, cite, content ) )\n            elsif respond_to? \"textile_#{ tagpre }_\", true\n                text.gsub!( $&, method( \"textile_#{ tagpre }_\" ).call( tagpre, num, atts, cite, content ) )\n            end\n        end\n    end\n\n    SETEXT_RE = /\\A(.+?)\\n([=-])[=-]* *$/m\n    def block_markdown_setext( text )\n        if text =~ SETEXT_RE\n            tag = if $2 == \"=\"; \"h1\"; else; \"h2\"; end\n            blk, cont = \"<#{ tag }>#{ $1 }</#{ tag }>\", $'\n            blocks cont\n            text.replace( blk + cont )\n        end\n    end\n\n    ATX_RE = /\\A(\\#{1,6})  # $1 = string of #'s\n              [ ]*\n              (.+?)       # $2 = Header text\n              [ ]*\n              \\#*         # optional closing #'s (not counted)\n              $/x\n    def block_markdown_atx( text )\n        if text =~ ATX_RE\n            tag = \"h#{ $1.length }\"\n            blk, cont = \"<#{ tag }>#{ $2 }</#{ tag }>\\n\\n\", $'\n            blocks cont\n            text.replace( blk + cont )\n        end\n    end\n\n    MARKDOWN_BQ_RE = /\\A(^ *> ?.+$(.+\\n)*\\n*)+/m\n\n    def block_markdown_bq( text )\n        text.gsub!( MARKDOWN_BQ_RE ) do |blk|\n            blk.gsub!( /^ *> ?/, '' )\n            flush_left blk\n            blocks blk\n            blk.gsub!( /^(\\S)/, \"\\t\\\\1\" )\n            \"<blockquote>\\n#{ blk }\\n</blockquote>\\n\\n\"\n        end\n    end\n\n    MARKDOWN_RULE_RE = /^(#{\n        ['*', '-', '_'].collect { |ch| ' ?(' + Regexp::quote( ch ) + ' ?){3,}' }.join( '|' )\n    })$/\n\n    def block_markdown_rule( text )\n        text.gsub!( MARKDOWN_RULE_RE ) do |blk|\n            \"<hr />\"\n        end\n    end\n\n    # XXX TODO XXX\n    def block_markdown_lists( text )\n    end\n\n    def inline_textile_span( text )\n        QTAGS.each do |qtag_rc, ht, qtag_re, rtype|\n            text.gsub!( qtag_re ) do |m|\n\n                case rtype\n                when :limit\n                    sta,qtag,atts,cite,content = $~[1..5]\n                else\n                    qtag,atts,cite,content = $~[1..4]\n                    sta = ''\n                end\n                atts = pba( atts )\n                atts << \" cite=\\\"#{ cite }\\\"\" if cite\n                atts = shelve( atts ) if atts\n\n                \"#{ sta }<#{ ht }#{ atts }>#{ content }</#{ ht }>\"\n\n            end\n        end\n    end\n\n    LINK_RE = /\n            (\n            ([\\s\\[{(]|[#{PUNCT}])?     # $pre\n            \"                          # start\n            (#{C})                     # $atts\n            ([^\"\\n]+?)                 # $text\n            \\s?\n            (?:\\(([^)]+?)\\)(?=\"))?     # $title\n            \":\n            (                          # $url\n            (\\/|[a-zA-Z]+:\\/\\/|www\\.|mailto:)  # $proto\n            [\\w\\/]\\S+?\n            )\n            (\\/)?                      # $slash\n            ([^\\w\\=\\/;\\(\\)]*?)         # $post\n            )\n            (?=<|\\s|$)\n        /x\n#\"\n    def inline_textile_link( text )\n        text.gsub!( LINK_RE ) do |m|\n          all,pre,atts,text,title,url,proto,slash,post = $~[1..9]\n          if text.include?('<br />')\n            all\n          else\n            url, url_title = check_refs( url )\n            title ||= url_title\n\n            # Idea below : an URL with unbalanced parethesis and\n            # ending by ')' is put into external parenthesis\n            if ( url[-1]==?) and ((url.count(\"(\") - url.count(\")\")) < 0 ) )\n              url=url[0..-2] # discard closing parenth from url\n              post = \")\"+post # add closing parenth to post\n            end\n            atts = pba( atts )\n            atts = \" href=\\\"#{ url }#{ slash }\\\"#{ atts }\"\n            atts << \" title=\\\"#{ htmlesc title }\\\"\" if title\n            atts = shelve( atts ) if atts\n\n            external = (url =~ /^https?:\\/\\//) ? ' class=\"external\"' : ''\n\n            \"#{ pre }<a#{ atts }#{ external }>#{ text }</a>#{ post }\"\n          end\n        end\n    end\n\n    MARKDOWN_REFLINK_RE = /\n            \\[([^\\[\\]]+)\\]      # $text\n            [ ]?                # opt. space\n            (?:\\n[ ]*)?         # one optional newline followed by spaces\n            \\[(.*?)\\]           # $id\n        /x\n\n    def inline_markdown_reflink( text )\n        text.gsub!( MARKDOWN_REFLINK_RE ) do |m|\n            text, id = $~[1..2]\n\n            if id.empty?\n                url, title = check_refs( text )\n            else\n                url, title = check_refs( id )\n            end\n\n            atts = \" href=\\\"#{ url }\\\"\"\n            atts << \" title=\\\"#{ title }\\\"\" if title\n            atts = shelve( atts )\n\n            \"<a#{ atts }>#{ text }</a>\"\n        end\n    end\n\n    MARKDOWN_LINK_RE = /\n            \\[([^\\[\\]]+)\\]      # $text\n            \\(                  # open paren\n            [ \\t]*              # opt space\n            <?(.+?)>?           # $href\n            [ \\t]*              # opt space\n            (?:                 # whole title\n            (['\"])              # $quote\n            (.*?)               # $title\n            \\3                  # matching quote\n            )?                  # title is optional\n            \\)\n        /x\n\n    def inline_markdown_link( text )\n        text.gsub!( MARKDOWN_LINK_RE ) do |m|\n            text, url, quote, title = $~[1..4]\n\n            atts = \" href=\\\"#{ url }\\\"\"\n            atts << \" title=\\\"#{ title }\\\"\" if title\n            atts = shelve( atts )\n\n            \"<a#{ atts }>#{ text }</a>\"\n        end\n    end\n\n    TEXTILE_REFS_RE =  /(^ *)\\[([^\\[\\n]+?)\\](#{HYPERLINK})(?=\\s|$)/\n    MARKDOWN_REFS_RE = /(^ *)\\[([^\\n]+?)\\]:\\s+<?(#{HYPERLINK})>?(?:\\s+\"((?:[^\"]|\\\\\")+)\")?(?=\\s|$)/m\n\n    def refs( text )\n        @rules.each do |rule_name|\n            method( rule_name ).call( text ) if rule_name.to_s.match /^refs_/\n        end\n    end\n\n    def refs_textile( text )\n        text.gsub!( TEXTILE_REFS_RE ) do |m|\n            flag, url = $~[2..3]\n            @urlrefs[flag.downcase] = [url, nil]\n            nil\n        end\n    end\n\n    def refs_markdown( text )\n        text.gsub!( MARKDOWN_REFS_RE ) do |m|\n            flag, url = $~[2..3]\n            title = $~[6]\n            @urlrefs[flag.downcase] = [url, title]\n            nil\n        end\n    end\n\n    def check_refs( text )\n        ret = @urlrefs[text.downcase] if text\n        ret || [text, nil]\n    end\n\n    IMAGE_RE = /\n            (>|\\s|^)           # start of line?\n            \\!                   # opening\n            (\\<|\\=|\\>)?          # optional alignment atts\n            (#{C})               # optional style,class atts\n            (?:\\. )?             # optional dot-space\n            ([^\\s(!]+?)          # presume this is the src\n            \\s?                  # optional space\n            (?:\\(((?:[^\\(\\)]|\\([^\\)]+\\))+?)\\))?   # optional title\n            \\!                   # closing\n            (?::#{ HYPERLINK })? # optional href\n        /x\n\n    def inline_textile_image( text )\n        text.gsub!( IMAGE_RE )  do |m|\n            stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8]\n            htmlesc title\n            atts = pba( atts )\n            atts = \" src=\\\"#{ url }\\\"#{ atts }\"\n            atts << \" title=\\\"#{ title }\\\"\" if title\n            atts << \" alt=\\\"#{ title }\\\"\"\n            # size = @getimagesize($url);\n            # if($size) $atts.= \" $size[3]\";\n\n            href, alt_title = check_refs( href ) if href\n            url, url_title = check_refs( url )\n\n            out = ''\n            out << \"<a#{ shelve( \" href=\\\"#{ href }\\\"\" ) }>\" if href\n            out << \"<img#{ shelve( atts ) } />\"\n            out << \"</a>#{ href_a1 }#{ href_a2 }\" if href\n\n            if algn\n                algn = h_align( algn )\n                if stln == \"<p>\"\n                    out = \"<p style=\\\"float:#{ algn }\\\">#{ out }\"\n                else\n                    out = \"#{ stln }<div style=\\\"float:#{ algn }\\\">#{ out }</div>\"\n                end\n            else\n                out = stln + out\n            end\n\n            out\n        end\n    end\n\n    def shelve( val )\n        @shelf << val\n        \" :redsh##{ @shelf.length }:\"\n    end\n\n    def retrieve( text )\n        @shelf.each_with_index do |r, i|\n            text.gsub!( \" :redsh##{ i + 1 }:\", r )\n        end\n    end\n\n    def incoming_entities( text )\n        ## turn any incoming ampersands into a dummy character for now.\n        ## This uses a negative lookahead for alphanumerics followed by a semicolon,\n        ## implying an incoming html entity, to be skipped\n\n        text.gsub!( /&(?![#a-z0-9]+;)/i, \"x%x%\" )\n    end\n\n    def no_textile( text )\n        text.gsub!( /(^|\\s)==([^=]+.*?)==(\\s|$)?/,\n            '\\1<notextile>\\2</notextile>\\3' )\n        text.gsub!( /^ *==([^=]+.*?)==/m,\n            '\\1<notextile>\\2</notextile>\\3' )\n    end\n\n    def clean_white_space( text )\n        # normalize line breaks\n        text.gsub!( /\\r\\n/, \"\\n\" )\n        text.gsub!( /\\r/, \"\\n\" )\n        text.gsub!( /\\t/, '    ' )\n        text.gsub!( /^ +$/, '' )\n        text.gsub!( /\\n{3,}/, \"\\n\\n\" )\n        text.gsub!( /\"$/, \"\\\" \" )\n\n        # if entire document is indented, flush\n        # to the left side\n        flush_left text\n    end\n\n    def flush_left( text )\n        indt = 0\n        if text =~ /^ /\n            while text !~ /^ {#{indt}}\\S/\n                indt += 1\n            end unless text.empty?\n            if indt.nonzero?\n                text.gsub!( /^ {#{indt}}/, '' )\n            end\n        end\n    end\n\n    def footnote_ref( text )\n        text.gsub!( /\\b\\[([0-9]+?)\\](\\s)?/,\n            '<sup><a href=\"#fn\\1\">\\1</a></sup>\\2' )\n    end\n\n    OFFTAGS = /(code|pre|kbd|notextile)/\n    OFFTAG_MATCH = /(?:(<\\/#{ OFFTAGS }>)|(<#{ OFFTAGS }[^>]*>))(.*?)(?=<\\/?#{ OFFTAGS }\\W|\\Z)/mi\n    OFFTAG_OPEN = /<#{ OFFTAGS }/\n    OFFTAG_CLOSE = /<\\/?#{ OFFTAGS }/\n    HASTAG_MATCH = /(<\\/?\\w[^\\n]*?>)/m\n    ALLTAG_MATCH = /(<\\/?\\w[^\\n]*?>)|.*?(?=<\\/?\\w[^\\n]*?>|$)/m\n\n    def glyphs_textile( text, level = 0 )\n        if text !~ HASTAG_MATCH\n            pgl text\n            footnote_ref text\n        else\n            codepre = 0\n            text.gsub!( ALLTAG_MATCH ) do |line|\n                ## matches are off if we're between <code>, <pre> etc.\n                if $1\n                    if line =~ OFFTAG_OPEN\n                        codepre += 1\n                    elsif line =~ OFFTAG_CLOSE\n                        codepre -= 1\n                        codepre = 0 if codepre < 0\n                    end\n                elsif codepre.zero?\n                    glyphs_textile( line, level + 1 )\n                else\n                    htmlesc( line, :NoQuotes )\n                end\n                # p [level, codepre, line]\n\n                line\n            end\n        end\n    end\n\n    def rip_offtags( text )\n        if text =~ /<.*>/\n            ## strip and encode <pre> content\n            codepre, used_offtags = 0, {}\n            text.gsub!( OFFTAG_MATCH ) do |line|\n                if $3\n                    offtag, aftertag = $4, $5\n                    codepre += 1\n                    used_offtags[offtag] = true\n                    if codepre - used_offtags.length > 0\n                        htmlesc( line, :NoQuotes )\n                        @pre_list.last << line\n                        line = \"\"\n                    else\n                        htmlesc( aftertag, :NoQuotes ) if aftertag\n                        line = \"<redpre##{ @pre_list.length }>\"\n                        $3.match(/<#{ OFFTAGS }([^>]*)>/)\n                        tag = $1\n                        $2.to_s.match(/(class\\=\\S+)/i)\n                        tag << \" #{$1}\" if $1\n                        @pre_list << \"<#{ tag }>#{ aftertag }\"\n                    end\n                elsif $1 and codepre > 0\n                    if codepre - used_offtags.length > 0\n                        htmlesc( line, :NoQuotes )\n                        @pre_list.last << line\n                        line = \"\"\n                    end\n                    codepre -= 1 unless codepre.zero?\n                    used_offtags = {} if codepre.zero?\n                end\n                line\n            end\n        end\n        text\n    end\n\n    def smooth_offtags( text )\n        unless @pre_list.empty?\n            ## replace <pre> content\n            text.gsub!( /<redpre#(\\d+)>/ ) { @pre_list[$1.to_i] }\n        end\n    end\n\n    def inline( text )\n        [/^inline_/, /^glyphs_/].each do |meth_re|\n            @rules.each do |rule_name|\n                method( rule_name ).call( text ) if rule_name.to_s.match( meth_re )\n            end\n        end\n    end\n\n    def h_align( text )\n        H_ALGN_VALS[text]\n    end\n\n    def v_align( text )\n        V_ALGN_VALS[text]\n    end\n\n    def textile_popup_help( name, windowW, windowH )\n        ' <a target=\"_blank\" href=\"http://hobix.com/textile/#' + helpvar + '\" onclick=\"window.open(this.href, \\'popupwindow\\', \\'width=' + windowW + ',height=' + windowH + ',scrollbars,resizable\\'); return false;\">' + name + '</a><br />'\n    end\n\n    # HTML cleansing stuff\n    BASIC_TAGS = {\n        'a' => ['href', 'title'],\n        'img' => ['src', 'alt', 'title'],\n        'br' => [],\n        'i' => nil,\n        'u' => nil,\n        'b' => nil,\n        'pre' => nil,\n        'kbd' => nil,\n        'code' => ['lang'],\n        'cite' => nil,\n        'strong' => nil,\n        'em' => nil,\n        'ins' => nil,\n        'sup' => nil,\n        'sub' => nil,\n        'del' => nil,\n        'table' => nil,\n        'tr' => nil,\n        'td' => ['colspan', 'rowspan'],\n        'th' => nil,\n        'ol' => nil,\n        'ul' => nil,\n        'li' => nil,\n        'p' => nil,\n        'h1' => nil,\n        'h2' => nil,\n        'h3' => nil,\n        'h4' => nil,\n        'h5' => nil,\n        'h6' => nil,\n        'blockquote' => ['cite']\n    }\n\n    def clean_html( text, tags = BASIC_TAGS )\n        text.gsub!( /<!\\[CDATA\\[/, '' )\n        text.gsub!( /<(\\/*)(\\w+)([^>]*)>/ ) do\n            raw = $~\n            tag = raw[2].downcase\n            if tags.has_key? tag\n                pcs = [tag]\n                tags[tag].each do |prop|\n                    ['\"', \"'\", ''].each do |q|\n                        q2 = ( q != '' ? q : '\\s' )\n                        if raw[3] =~ /#{prop}\\s*=\\s*#{q}([^#{q2}]+)#{q}/i\n                            attrv = $1\n                            next if prop == 'src' and attrv =~ %r{^(?!http)\\w+:}\n                            pcs << \"#{prop}=\\\"#{$1.gsub('\"', '\\\\\"')}\\\"\"\n                            break\n                        end\n                    end\n                end if tags[tag]\n                \"<#{raw[1]}#{pcs.join \" \"}>\"\n            else\n                \" \"\n            end\n        end\n    end\n\n    ALLOWED_TAGS = %w(redpre pre code notextile)\n\n    def escape_html_tags(text)\n      text.gsub!(%r{<(\\/?([!\\w]+)[^<>\\n]*)(>?)}) {|m| ALLOWED_TAGS.include?($2) ? \"<#{$1}#{$3}\" : \"&lt;#{$1}#{'&gt;' unless $3.blank?}\" }\n    end\nend\n\n"
  },
  {
    "path": "lib/redmine/about.rb",
    "content": "module Redmine\n  class About\n    def self.print_plugin_info\n      plugins = Redmine::Plugin.registered_plugins\n\n      if !plugins.empty?\n        column_with = plugins.map {|internal_name, plugin| plugin.name.length}.max\n        puts \"\\nAbout your Redmine plugins\"\n\n        plugins.each do |internal_name, plugin|\n          puts sprintf(\"%-#{column_with}s   %s\", plugin.name, plugin.version)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/access_control.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine\n  module AccessControl\n\n    class << self\n      def map\n        mapper = Mapper.new\n        yield mapper\n        @permissions ||= []\n        @permissions += mapper.mapped_permissions\n      end\n\n      def permissions\n        @permissions\n      end\n\n      # Returns the permission of given name or nil if it wasn't found\n      # Argument should be a symbol\n      def permission(name)\n        permissions.detect {|p| p.name == name}\n      end\n\n      # Returns the actions that are allowed by the permission of given name\n      def allowed_actions(permission_name)\n        perm = permission(permission_name)\n        perm ? perm.actions : []\n      end\n\n      def public_permissions\n        @public_permissions ||= @permissions.select {|p| p.public?}\n      end\n\n      def members_only_permissions\n        @members_only_permissions ||= @permissions.select {|p| p.require_member?}\n      end\n\n      def loggedin_only_permissions\n        @loggedin_only_permissions ||= @permissions.select {|p| p.require_loggedin?}\n      end\n\n      def available_project_modules\n        @available_project_modules ||= @permissions.collect(&:project_module).uniq.compact\n      end\n\n      def modules_permissions(modules)\n        @permissions.select {|p| p.project_module.nil? || modules.include?(p.project_module.to_s)}\n      end\n    end\n\n    class Mapper\n      def initialize\n        @project_module = nil\n      end\n\n      def permission(name, hash, options={})\n        @permissions ||= []\n        options.merge!(:project_module => @project_module)\n        @permissions << Permission.new(name, hash, options)\n      end\n\n      def project_module(name, options={})\n        @project_module = name\n        yield self\n        @project_module = nil\n      end\n\n      def mapped_permissions\n        @permissions\n      end\n    end\n\n    class Permission\n      attr_reader :name, :actions, :project_module\n\n      def initialize(name, hash, options)\n        @name = name\n        @actions = []\n        @public = options[:public] || false\n        @require = options[:require]\n        @project_module = options[:project_module]\n        hash.each do |controller, actions|\n          if actions.is_a? Array\n            @actions << actions.collect {|action| \"#{controller}/#{action}\"}\n          else\n            @actions << \"#{controller}/#{actions}\"\n          end\n        end\n        @actions.flatten!\n      end\n\n      def public?\n        @public\n      end\n\n      def require_member?\n        @require && @require == :member\n      end\n\n      def require_loggedin?\n        @require && (@require == :member || @require == :loggedin)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/access_keys.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nmodule Redmine\n  module AccessKeys\n    ACCESSKEYS = {:edit => 'e',\n                  :preview => 'r',\n                  :quick_search => 'f',\n                  :search => '4',\n                  :new_issue => '7'\n                 }.freeze unless const_defined?(:ACCESSKEYS)\n\n    def self.key_for(action)\n      ACCESSKEYS[action]\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/activity/fetcher.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nmodule Redmine\n  module Activity\n    # Class used to retrieve activity events\n    class Fetcher\n      attr_reader :user, :project, :scope\n\n      # Needs to be unloaded in development mode\n      @@constantized_providers = Hash.new {|h,k| h[k] = Redmine::Activity.providers[k].collect {|t| t.constantize } }\n\n      def initialize(user, options={})\n        options.assert_valid_keys(:project, :with_subprojects, :author)\n        @user = user\n        @project = options[:project]\n        @options = options\n\n        @scope = event_types\n      end\n\n      # Returns an array of available event types\n      def event_types\n        return @event_types unless @event_types.nil?\n\n        @event_types = Redmine::Activity.available_event_types\n        @event_types = @event_types.select {|o| @user.allowed_to?(\"view_#{o}\".to_sym, @project)} if @project\n        @event_types\n      end\n\n      # Yields to filter the activity scope\n      def scope_select(&block)\n        @scope = @scope.select {|t| yield t }\n      end\n\n      # Sets the scope\n      # Argument can be :all, :default or an array of event types\n      def scope=(s)\n        case s\n        when :all\n          @scope = event_types\n        when :default\n          default_scope!\n        else\n          @scope = s & event_types\n        end\n      end\n\n      # Resets the scope to the default scope\n      def default_scope!\n        @scope = Redmine::Activity.default_event_types\n      end\n\n      # Returns an array of events for the given date range\n      # sorted in reverse chronological order\n      def events(from = nil, to = nil, options={})\n        e = []\n        @options[:limit] = options[:limit]\n\n        @scope.each do |event_type|\n          constantized_providers(event_type).each do |provider|\n            e += provider.find_events(event_type, @user, from, to, @options)\n          end\n        end\n\n        e.sort! {|a,b| b.event_datetime <=> a.event_datetime}\n\n        if options[:limit]\n          e = e.slice(0, options[:limit])\n        end\n        e\n      end\n\n      private\n\n      def constantized_providers(event_type)\n        @@constantized_providers[event_type]\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/activity.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nmodule Redmine\n  module Activity\n\n    mattr_accessor :available_event_types, :default_event_types, :providers\n\n    @@available_event_types = []\n    @@default_event_types = []\n    @@providers = Hash.new {|h,k| h[k]=[] }\n\n    class << self\n      def map(&block)\n        yield self\n      end\n\n      # Registers an activity provider\n      def register(event_type, options={})\n        options.assert_valid_keys(:class_name, :default)\n        event_type = event_type.to_s\n        providers = options[:class_name] || event_type.classify\n        providers = ([] << providers) unless providers.is_a?(Array)\n\n        @@available_event_types << event_type unless @@available_event_types.include?(event_type)\n        @@default_event_types << event_type unless options[:default] == false\n        @@providers[event_type] += providers\n      end\n    end\n\n  end\nend\n"
  },
  {
    "path": "lib/redmine/core_ext/string/conversions.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2008  Shereef Bishay\n#\n\nmodule Redmine #:nodoc:\n  module CoreExtensions #:nodoc:\n    module String #:nodoc:\n      # Custom string conversions\n      module Conversions\n        # Parses hours format and returns a float\n        def to_hours\n          s = self.dup\n          s.strip!\n          if s =~ %r{^(\\d+([.,]\\d+)?)h?$}\n            s = $1\n          else\n            # 2:30 => 2.5\n            s.gsub!(%r{^(\\d+):(\\d+)$}) { $1.to_i + $2.to_i / 60.0 }\n            # 2h30, 2h, 30m => 2.5, 2, 0.5\n            s.gsub!(%r{^((\\d+)\\s*(h|hours?))?\\s*((\\d+)\\s*(m|min)?)?$}) { |m| ($1 || $4) ? ($2.to_i + $5.to_i / 60.0) : m[0] }\n          end\n          # 2,5 => 2.5\n          s.gsub!(',', '.')\n          begin; Kernel.Float(s); rescue; nil; end\n        end\n\n        # Object#to_a removed in ruby1.9\n        if RUBY_VERSION > '1.9'\n          def to_a\n            [self.dup]\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/core_ext/string/inflections.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine #:nodoc:\n  module CoreExtensions #:nodoc:\n    module String #:nodoc:\n      # Custom string inflections\n      module Inflections\n        def with_leading_slash\n          starts_with?('/') ? self : \"/#{ self }\"\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/core_ext/string.rb",
    "content": "require File.dirname(__FILE__) + '/string/conversions'\nrequire File.dirname(__FILE__) + '/string/inflections'\n\nclass String #:nodoc:\n  include Redmine::CoreExtensions::String::Conversions\n  include Redmine::CoreExtensions::String::Inflections\nend\n"
  },
  {
    "path": "lib/redmine/core_ext.rb",
    "content": "Dir[File.dirname(__FILE__) + \"/core_ext/*.rb\"].each { |file| require(file) }\n"
  },
  {
    "path": "lib/redmine/default_data/loader.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine\n  module DefaultData\n    class DataAlreadyLoaded < Exception; end\n\n    module Loader\n      include Redmine::I18n\n\n      class << self\n        # Returns true if no data is already loaded in the database\n        # otherwise false\n        def no_data?\n          !Role.find(:first, :conditions => {:builtin => 0}) &&\n            !Tracker.find(:first) &&\n            !IssueStatus.find(:first) &&\n            !Enumeration.find(:first)\n        end\n\n        # Loads the default data\n        # Raises a RecordNotSaved exception if something goes wrong\n        def load(lang=nil)\n          raise DataAlreadyLoaded.new(\"Some configuration data is already loaded.\") unless no_data?\n          set_language_if_valid(lang)\n\n          Role.transaction do\n            # Roles\n            administrator = Role.create! :name => l(:default_role_administrator), :position => 1, :builtin => Role::BUILTIN_ADMINISTRATOR, :scope => Role::LEVEL_PROJECT\n            administrator.permissions = administrator.setable_permissions.collect {|p| p.name}\n            administrator.permissions.delete(:edit_time_entries)\n            administrator.permissions.delete(:manage_members)\n\n            administrator.save!\n\n            citizen = Role.create! :name => l(:default_role_citizen), :position => 2, :builtin => Role::BUILTIN_CORE_MEMBER, :scope => Role::LEVEL_PROJECT\n            citizen.permissions = citizen.setable_permissions.collect {|p| p.name}\n            citizen.permissions.delete(:add_project)\n            citizen.permissions.delete(:edit_project)\n            citizen.permissions.delete(:select_projected_modules)\n            citizen.permissions.delete(:manage_members)\n            citizen.permissions.delete(:manage_versions)\n            citizen.permissions.delete(:edit_time_entries)\n            citizen.save!\n\n            contributor = Role.create! :name => l(:default_role_contributor), :position => 3, :builtin => Role::BUILTIN_CONTRIBUTOR, :scope => Role::LEVEL_PROJECT\n            contributor.permissions = contributor.setable_permissions.collect {|p| p.name}\n            contributor.permissions.delete(:add_project)\n            contributor.permissions.delete(:edit_project)\n            contributor.permissions.delete(:select_projected_modules)\n            contributor.permissions.delete(:manage_members)\n            contributor.permissions.delete(:manage_versions)\n            contributor.permissions.delete(:manage_boards)\n            contributor.permissions.delete(:edit_messages)\n            contributor.permissions.delete(:delete_messages)\n            contributor.permissions.delete(:delete_own_messages)\n            contributor.permissions.delete(:manage_documents)\n            contributor.permissions.delete(:manage_files)\n            contributor.permissions.delete(:manage_categories)\n            contributor.permissions.delete(:manage_issue_relations)\n            contributor.permissions.delete(:edit_issue_notes)\n            contributor.permissions.delete(:move_issues)\n            contributor.permissions.delete(:delete_issues)\n            contributor.permissions.delete(:push_commitment)\n            contributor.permissions.delete(:manage_public_queries)\n            contributor.permissions.delete(:add_issue_watchers)\n            contributor.permissions.delete(:manage_news)\n            contributor.permissions.delete(:edit_time_entries)\n            contributor.permissions.delete(:manage_wiki)\n            contributor.permissions.delete(:rename_wiki_pages)\n            contributor.permissions.delete(:delete_wiki_pages)\n            contributor.permissions.delete(:delete_wiki_pages_attachments)\n            contributor.permissions.delete(:protect_wiki_pages)\n            contributor.save!\n\n            #TODO: Check that built in role aren't in there before creating them\n            @nonmember = Role.new(:name => 'Non member', :position => 0)\n            @nonmember.builtin = Role::BUILTIN_NON_MEMBER\n            @nonmember.save\n\n            @anonymous = Role.new(:name => 'Anonymous', :position => 0)\n            @anonymous.builtin = Role::BUILTIN_ANONYMOUS\n            @anonymous.save\n\n            Role.non_member.update_attribute :permissions, contributor.permissions\n\n            Role.anonymous.update_attribute :permissions, [:view_issues,\n                                                           :view_gantt,\n                                                           :view_calendar,\n                                                           :view_time_entries,\n                                                           :view_documents,\n                                                           :view_wiki_pages,\n                                                           :view_wiki_edits,\n                                                           :view_files,\n                                                           :view_changesets]\n\n            # Trackers\n            Tracker.create!(:name => l(:default_tracker_task),     :is_in_chlog => true,  :is_in_roadmap => true, :position => 1)\n            Tracker.create!(:name => l(:default_tracker_subtask), :is_in_chlog => true,  :is_in_roadmap => true,  :position => 2)\n\n            # Issue statuses\n            new       = IssueStatus.create!(:name => l(:default_issue_status_new), :is_closed => false, :is_default => true, :position => 1)\n            assigned  = IssueStatus.create!(:name => l(:default_issue_status_assigned), :is_closed => false, :is_default => false, :position => 2)\n            closed    = IssueStatus.create!(:name => l(:default_issue_status_closed), :is_closed => true, :is_default => false, :position => 3)\n            blocked  = IssueStatus.create!(:name => l(:default_issue_status_blocked), :is_closed => false, :is_default => false, :position => 4)\n\n            # Workflow\n            Tracker.find(:all).each { |t|\n              IssueStatus.find(:all).each { |os|\n                IssueStatus.find(:all).each { |ns|\n                  Workflow.create!(:tracker_id => t.id, :role_id => administrator.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns\n                }\n              }\n            }\n\n            Tracker.find(:all).each { |t|\n              IssueStatus.find(:all).each { |os|\n                IssueStatus.find(:all).each { |ns|\n                  Workflow.create!(:tracker_id => t.id, :role_id => citizen.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns\n                }\n              }\n            }\n\n            Tracker.find(:all).each { |t|\n              IssueStatus.find(:all).each { |os|\n                IssueStatus.find(:all).each { |ns|\n                  Workflow.create!(:tracker_id => t.id, :role_id => contributor.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns\n                }\n              }\n            }\n\n            # Enumerations\n            IssuePriority.create!(:opt => \"IPRI\", :name => l(:default_priority_low), :position => 1)\n            IssuePriority.create!(:opt => \"IPRI\", :name => l(:default_priority_normal), :position => 2, :is_default => true)\n            IssuePriority.create!(:opt => \"IPRI\", :name => l(:default_priority_high), :position => 3)\n            IssuePriority.create!(:opt => \"IPRI\", :name => l(:default_priority_urgent), :position => 4)\n\n          end\n          true\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/export/pdf.rb",
    "content": "# encoding: utf-8\n#\n# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nrequire 'iconv'\nrequire 'rfpdf/fpdf'\nrequire 'rfpdf/chinese'\n\nmodule Redmine\n  module Export\n    module PDF\n      include ActionView::Helpers::TextHelper\n      include ActionView::Helpers::NumberHelper\n\n      class IFPDF < FPDF\n        include Redmine::I18n\n        attr_accessor :footer_date\n\n        def initialize(lang)\n          super()\n          set_language_if_valid lang\n          case current_language.to_s.downcase\n          when 'ja'\n            extend(PDF_Japanese)\n            AddSJISFont()\n            @font_for_content = 'SJIS'\n            @font_for_footer = 'SJIS'\n          when 'zh'\n            extend(PDF_Chinese)\n            AddGBFont()\n            @font_for_content = 'GB'\n            @font_for_footer = 'GB'\n          when 'zh-tw'\n            extend(PDF_Chinese)\n            AddBig5Font()\n            @font_for_content = 'Big5'\n            @font_for_footer = 'Big5'\n          else\n            @font_for_content = 'Arial'\n            @font_for_footer = 'Helvetica'\n          end\n          SetCreator(Redmine::Info.app_name)\n          SetFont(@font_for_content)\n        end\n\n        def SetFontStyle(style, size)\n          SetFont(@font_for_content, style, size)\n        end\n\n        def SetTitle(txt)\n          txt = begin\n            utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt)\n            hextxt = \"<FEFF\"  # FEFF is BOM\n            hextxt << utf16txt.unpack(\"C*\").map {|x| sprintf(\"%02X\",x) }.join\n            hextxt << \">\"\n          rescue\n            txt\n          end || ''\n          super(txt)\n        end\n\n        def textstring(s)\n          # Format a text string\n          if s =~ /^</  # This means the string is hex-dumped.\n            return s\n          else\n            return '('+escape(s)+')'\n          end\n        end\n\n        def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='')\n          @ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')\n          # these quotation marks are not correctly rendered in the pdf\n          txt = txt.gsub(/[â€œâ€�]/, '\"') if txt\n          txt = begin\n            # 0x5c char handling\n            txtar = txt.split('\\\\')\n            txtar << '' if txt[-1] == ?\\\\\n            txtar.collect {|x| @ic.iconv(x)}.join('\\\\').gsub(/\\\\/, \"\\\\\\\\\\\\\\\\\")\n          rescue\n            txt\n          end || ''\n          super w,h,txt,border,ln,align,fill,link\n        end\n\n        def Footer\n          SetFont(@font_for_footer, 'I', 8)\n          SetY(-15)\n          SetX(15)\n          Cell(0, 5, @footer_date, 0, 0, 'L')\n          SetY(-15)\n          SetX(-30)\n          Cell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')\n        end\n      end\n\n      # Returns a PDF string of a list of issues\n      def issues_to_pdf(issues, project, query)\n        pdf = IFPDF.new(current_language)\n        title = query.new_record? ? l(:label_issue_plural) : query.name\n        title = \"#{project} - #{title}\" if project\n        pdf.SetTitle(title)\n        pdf.AliasNbPages\n        pdf.footer_date = format_date(Date.today)\n        pdf.AddPage(\"L\")\n\n        row_height = 6\n        col_width = []\n        unless query.columns.empty?\n          col_width = query.columns.collect {|column| column.name == :subject ? 4.0 : 1.0 }\n          ratio = 262.0 / col_width.inject(0) {|s,w| s += w}\n          col_width = col_width.collect {|w| w * ratio}\n        end\n\n        # title\n        pdf.SetFontStyle('B',11)\n        pdf.Cell(190,10, title)\n        pdf.Ln\n\n        # headers\n        pdf.SetFontStyle('B',8)\n        pdf.SetFillColor(230, 230, 230)\n        pdf.Cell(15, row_height, \"#\", 1, 0, 'L', 1)\n        query.columns.each_with_index do |column, i|\n          pdf.Cell(col_width[i], row_height, column.caption, 1, 0, 'L', 1)\n        end\n        pdf.Ln\n\n        # rows\n        pdf.SetFontStyle('',8)\n        pdf.SetFillColor(255, 255, 255)\n        group = false\n        issues.each do |issue|\n          if query.grouped? && issue.send(query.group_by) != group\n            group = issue.send(query.group_by)\n            pdf.SetFontStyle('B',9)\n            pdf.Cell(277, row_height, \"#{group.blank? ? 'None' : group.to_s}\", 1, 1, 'L')\n            pdf.SetFontStyle('',8)\n          end\n          pdf.Cell(15, row_height, issue.id.to_s, 1, 0, 'L', 1)\n          query.columns.each_with_index do |column, i|\n            value = issue.send(column.name)\n            if value.is_a?(Date)\n              format_date(value)\n            elsif value.is_a?(Time)\n              format_time(value)\n            else\n              value\n            end\n            pdf.Cell(col_width[i], row_height, s.to_s, 1, 0, 'L', 1)\n          end\n          pdf.Ln\n        end\n        if issues.size == Setting.issues_export_limit.to_i\n          pdf.SetFontStyle('B',10)\n          pdf.Cell(0, row_height, '...')\n        end\n        pdf.Output\n      end\n\n      # Returns a PDF string of a single issue\n      def issue_to_pdf(issue)\n        pdf = IFPDF.new(current_language)\n        pdf.SetTitle(\"#{issue.project} - ##{issue.tracker} #{issue.id}\")\n        pdf.AliasNbPages\n        pdf.footer_date = format_date(Date.today)\n        pdf.AddPage\n\n        pdf.SetFontStyle('B',11)\n        pdf.Cell(190,10, \"#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}\")\n        pdf.Ln\n\n        y0 = pdf.GetY\n\n        pdf.SetFontStyle('B',9)\n        pdf.Cell(35,5, l(:field_status) + \":\",\"LT\")\n        pdf.SetFontStyle('',9)\n        pdf.Cell(60,5, issue.status.to_s,\"RT\")\n        pdf.SetFontStyle('B',9)\n        pdf.Cell(35,5, l(:field_priority) + \":\",\"LT\")\n        pdf.SetFontStyle('',9)\n        pdf.Cell(60,5, issue.priority.to_s,\"RT\")\n        pdf.Ln\n\n        pdf.SetFontStyle('B',9)\n        pdf.Cell(35,5, l(:field_author) + \":\",\"L\")\n        pdf.SetFontStyle('',9)\n        pdf.Cell(60,5, issue.author.to_s,\"R\")\n        pdf.SetFontStyle('B',9)\n        pdf.Ln\n\n        pdf.SetFontStyle('B',9)\n        pdf.Cell(35,5, l(:field_created_at) + \":\",\"L\")\n        pdf.SetFontStyle('',9)\n        pdf.Cell(60,5, format_date(issue.created_at),\"R\")\n        pdf.SetFontStyle('B',9)\n        pdf.Cell(35,5, l(:field_assigned_to) + \":\",\"L\")\n        pdf.SetFontStyle('',9)\n        pdf.Cell(60,5, issue.assigned_to.to_s,\"R\")\n        pdf.Ln\n\n        pdf.SetFontStyle('B',9)\n        pdf.Cell(35,5, l(:field_updated_at) + \":\",\"LB\")\n        pdf.SetFontStyle('',9)\n        pdf.Cell(60,5, format_date(issue.updated_at),\"RB\")\n        pdf.SetFontStyle('B',9)\n        pdf.Cell(35,5, l(:field_due_date) + \":\",\"LB\")\n        pdf.SetFontStyle('',9)\n        pdf.Cell(60,5, format_date(issue.due_date),\"RB\")\n        pdf.Ln\n\n        pdf.SetFontStyle('B',9)\n        pdf.Cell(35,5, l(:field_subject) + \":\",\"LTB\")\n        pdf.SetFontStyle('',9)\n        pdf.Cell(155,5, issue.subject,\"RTB\")\n        pdf.Ln\n\n        pdf.SetFontStyle('B',9)\n        pdf.Cell(35,5, l(:field_description) + \":\")\n        pdf.SetFontStyle('',9)\n        pdf.MultiCell(155,5, @issue.description,\"BR\")\n\n        pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)\n        pdf.Line(pdf.GetX, pdf.GetY, 170, pdf.GetY)\n        pdf.Ln\n\n        if issue.changesets.any? && User.current.allowed_to?(:view_changesets, issue.project)\n          pdf.SetFontStyle('B',9)\n          pdf.Cell(190,5, l(:label_associated_revisions), \"B\")\n          pdf.Ln\n          for changeset in issue.changesets\n            pdf.SetFontStyle('B',8)\n            pdf.Cell(190,5, format_time(changeset.committed_on) + \" - \" + changeset.author.to_s)\n            pdf.Ln\n            unless changeset.comments.blank?\n              pdf.SetFontStyle('',8)\n              pdf.MultiCell(190,5, changeset.comments)\n            end\n            pdf.Ln\n          end\n        end\n\n        pdf.SetFontStyle('B',9)\n        pdf.Cell(190,5, l(:label_history), \"B\")\n        pdf.Ln\n        for journal in issue.journals.find(:all, :include => [:user, :details], :order => \"#{Journal.table_name}.created_at ASC\")\n          pdf.SetFontStyle('B',8)\n          pdf.Cell(190,5, format_time(journal.created_at) + \" - \" + journal.user.name)\n          pdf.Ln\n          pdf.SetFontStyle('I',8)\n          for detail in journal.details\n            pdf.Cell(190,5, \"- \" + show_detail(detail, true))\n            pdf.Ln\n          end\n          if journal.notes?\n            pdf.SetFontStyle('',8)\n            pdf.MultiCell(190,5, journal.notes)\n          end\n          pdf.Ln\n        end\n\n        if issue.attachments.any?\n          pdf.SetFontStyle('B',9)\n          pdf.Cell(190,5, l(:label_attachment_plural), \"B\")\n          pdf.Ln\n          for attachment in issue.attachments\n            pdf.SetFontStyle('',8)\n            pdf.Cell(80,5, attachment.filename)\n            pdf.Cell(20,5, number_to_human_size(attachment.filesize),0,0,\"R\")\n            pdf.Cell(25,5, format_date(attachment.created_at),0,0,\"R\")\n            pdf.Cell(65,5, attachment.author.name,0,0,\"R\")\n            pdf.Ln\n          end\n        end\n        pdf.Output\n      end\n\n      # Returns a PDF string of a gantt chart\n      def gantt_to_pdf(gantt, project)\n        pdf = IFPDF.new(current_language)\n        pdf.SetTitle(\"#{l(:label_gantt)} #{project}\")\n        pdf.AliasNbPages\n        pdf.footer_date = format_date(Date.today)\n        pdf.AddPage(\"L\")\n        pdf.SetFontStyle('B',12)\n        pdf.SetX(15)\n        pdf.Cell(70, 20, project.to_s)\n        pdf.Ln\n        pdf.SetFontStyle('B',9)\n\n        subject_width = 70\n        header_heigth = 5\n\n        headers_heigth = header_heigth\n        show_weeks = false\n        show_days = false\n\n        if gantt.months < 7\n          show_weeks = true\n          headers_heigth = 2*header_heigth\n          if gantt.months < 3\n            show_days = true\n            headers_heigth = 3*header_heigth\n          end\n        end\n\n        g_width = 210\n        zoom = (g_width) / (gantt.date_to - gantt.date_from + 1)\n        g_height = 120\n        t_height = g_height + headers_heigth\n\n        y_start = pdf.GetY\n\n        # Months headers\n        month_f = gantt.date_from\n        left = subject_width\n        height = header_heigth\n        gantt.months.times do\n          width = ((month_f >> 1) - month_f) * zoom\n          pdf.SetY(y_start)\n          pdf.SetX(left)\n          pdf.Cell(width, height, \"#{month_f.year}-#{month_f.month}\", \"LTR\", 0, \"C\")\n          left = left + width\n          month_f = month_f >> 1\n        end\n\n        # Weeks headers\n        if show_weeks\n          left = subject_width\n          height = header_heigth\n          if gantt.date_from.cwday == 1\n            # gantt.date_from is monday\n            week_f = gantt.date_from\n          else\n            # find next monday after gantt.date_from\n            week_f = gantt.date_from + (7 - gantt.date_from.cwday + 1)\n            width = (7 - gantt.date_from.cwday + 1) * zoom-1\n            pdf.SetY(y_start + header_heigth)\n            pdf.SetX(left)\n            pdf.Cell(width + 1, height, \"\", \"LTR\")\n            left = left + width+1\n          end\n          while week_f <= gantt.date_to\n            width = (week_f + 6 <= gantt.date_to) ? 7 * zoom : (gantt.date_to - week_f + 1) * zoom\n            pdf.SetY(y_start + header_heigth)\n            pdf.SetX(left)\n            pdf.Cell(width, height, (width >= 5 ? week_f.cweek.to_s : \"\"), \"LTR\", 0, \"C\")\n            left = left + width\n            week_f = week_f+7\n          end\n        end\n\n        # Days headers\n        if show_days\n          left = subject_width\n          height = header_heigth\n          wday = gantt.date_from.cwday\n          pdf.SetFontStyle('B',7)\n          (gantt.date_to - gantt.date_from + 1).to_i.times do\n            width = zoom\n            pdf.SetY(y_start + 2 * header_heigth)\n            pdf.SetX(left)\n            pdf.Cell(width, height, day_name(wday).first, \"LTR\", 0, \"C\")\n            left = left + width\n            wday = wday + 1\n            wday = 1 if wday > 7\n          end\n        end\n\n        pdf.SetY(y_start)\n        pdf.SetX(15)\n        pdf.Cell(subject_width+g_width-15, headers_heigth, \"\", 1)\n\n        # Tasks\n        top = headers_heigth + y_start\n        pdf.SetFontStyle('B',7)\n        gantt.events.each do |i|\n          pdf.SetY(top)\n          pdf.SetX(15)\n\n          if i.is_a? Issue\n            pdf.Cell(subject_width-15, 5, \"#{i.tracker} #{i.id}: #{i.subject}\".sub(/^(.{30}[^\\s]*\\s).*$/, '\\1 (...)'), \"LR\")\n          else\n            pdf.Cell(subject_width-15, 5, \"#{l(:label_version)}: #{i.name}\", \"LR\")\n          end\n\n          pdf.SetY(top)\n          pdf.SetX(subject_width)\n          pdf.Cell(g_width, 5, \"\", \"LR\")\n\n          pdf.SetY(top+1.5)\n\n          if i.is_a? Issue\n            i_start_date = (i.start_date >= gantt.date_from ? i.start_date : gantt.date_from )\n            i_end_date = (i.due_before <= gantt.date_to ? i.due_before : gantt.date_to )\n\n            i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor\n            i_done_date = (i_done_date <= gantt.date_from ? gantt.date_from : i_done_date )\n            i_done_date = (i_done_date >= gantt.date_to ? gantt.date_to : i_done_date )\n\n            i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today\n\n            i_left = ((i_start_date - gantt.date_from)*zoom)\n            i_width = ((i_end_date - i_start_date + 1)*zoom)\n            d_width = ((i_done_date - i_start_date)*zoom)\n            l_width = ((i_late_date - i_start_date+1)*zoom) if i_late_date\n            l_width ||= 0\n\n            pdf.SetX(subject_width + i_left)\n            pdf.SetFillColor(200,200,200)\n            pdf.Cell(i_width, 2, \"\", 0, 0, \"\", 1)\n\n            if l_width > 0\n              pdf.SetY(top+1.5)\n              pdf.SetX(subject_width + i_left)\n              pdf.SetFillColor(255,100,100)\n              pdf.Cell(l_width, 2, \"\", 0, 0, \"\", 1)\n            end\n            if d_width > 0\n              pdf.SetY(top+1.5)\n              pdf.SetX(subject_width + i_left)\n              pdf.SetFillColor(100,100,255)\n              pdf.Cell(d_width, 2, \"\", 0, 0, \"\", 1)\n            end\n\n            pdf.SetY(top+1.5)\n            pdf.SetX(subject_width + i_left + i_width)\n            pdf.Cell(30, 2, \"#{i.status} #{i.done_ratio}%\")\n          else\n            i_left = ((i.start_date - gantt.date_from)*zoom)\n\n            pdf.SetX(subject_width + i_left)\n            pdf.SetFillColor(50,200,50)\n            pdf.Cell(2, 2, \"\", 0, 0, \"\", 1)\n\n            pdf.SetY(top+1.5)\n            pdf.SetX(subject_width + i_left + 3)\n            pdf.Cell(30, 2, \"#{i.name}\")\n          end\n\n          top = top + 5\n          pdf.SetDrawColor(200, 200, 200)\n          pdf.Line(15, top, subject_width+g_width, top)\n          if pdf.GetY() > 180\n            pdf.AddPage(\"L\")\n            top = 20\n            pdf.Line(15, top, subject_width+g_width, top)\n          end\n          pdf.SetDrawColor(0, 0, 0)\n        end\n\n        pdf.Line(15, top, subject_width+g_width, top)\n        pdf.Output\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/helpers/calendar.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine\n  module Helpers\n\n    # Simple class to compute the start and end dates of a calendar\n    class Calendar\n      include Redmine::I18n\n      attr_reader :startdt, :enddt\n\n      def initialize(date, lang = current_language, period = :month)\n        @date = date\n        @events = []\n        @ending_events_by_days = {}\n        @starting_events_by_days = {}\n        set_language_if_valid lang\n        case period\n        when :month\n          @startdt = Date.civil(date.year, date.month, 1)\n          @enddt = (@startdt >> 1)-1\n          # starts from the first day of the week\n          @startdt = @startdt - (@startdt.cwday - first_wday)%7\n          # ends on the last day of the week\n          @enddt = @enddt + (last_wday - @enddt.cwday)%7\n        when :week\n          @startdt = date - (date.cwday - first_wday)%7\n          @enddt = date + (last_wday - date.cwday)%7\n        else\n          raise 'Invalid period'\n        end\n      end\n\n      # Sets calendar events\n      def events=(events)\n        @events = events\n        @ending_events_by_days = @events.group_by {|event| event.due_date}\n        @starting_events_by_days = @events.group_by {|event| event.start_date}\n      end\n\n      # Returns events for the given day\n      def events_on(day)\n        ((@ending_events_by_days[day] || []) + (@starting_events_by_days[day] || [])).uniq\n      end\n\n      # Calendar current month\n      def month\n        @date.month\n      end\n\n      # Return the first day of week\n      # 1 = Monday ... 7 = Sunday\n      def first_wday\n        case Setting.start_of_week.to_i\n        when 1\n          @first_dow ||= (1 - 1)%7 + 1\n        when 7\n          @first_dow ||= (7 - 1)%7 + 1\n        else\n          @first_dow ||= (l(:general_first_day_of_week).to_i - 1)%7 + 1\n        end\n      end\n\n      def last_wday\n        @last_dow ||= (first_wday + 5)%7 + 1\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/helpers/gantt.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nmodule Redmine\n  module Helpers\n    # Simple class to handle gantt chart data\n    class Gantt\n      attr_reader :year_from, :month_from, :date_from, :date_to, :zoom, :months, :events\n\n      def initialize(options={})\n        options = options.dup\n        @events = []\n\n        if options[:year] && options[:year].to_i >0\n          @year_from = options[:year].to_i\n          if options[:month] && options[:month].to_i >=1 && options[:month].to_i <= 12\n            @month_from = options[:month].to_i\n          else\n            @month_from = 1\n          end\n        else\n          @month_from ||= Date.today.month\n          @year_from ||= Date.today.year\n        end\n\n        zoom = (options[:zoom] || User.current.pref[:gantt_zoom]).to_i\n        @zoom = (zoom > 0 && zoom < 5) ? zoom : 2\n        months = (options[:months] || User.current.pref[:gantt_months]).to_i\n        @months = (months > 0 && months < 25) ? months : 6\n\n        # Save gantt parameters as user preference (zoom and months count)\n        if (User.current.logged? && (@zoom != User.current.pref[:gantt_zoom] || @months != User.current.pref[:gantt_months]))\n          User.current.pref[:gantt_zoom], User.current.pref[:gantt_months] = @zoom, @months\n          User.current.preference.save\n        end\n\n        @date_from = Date.civil(@year_from, @month_from, 1)\n        @date_to = (@date_from >> @months) - 1\n      end\n\n      def events=(e)\n        @events = e.sort {|x,y| x.start_date <=> y.start_date }\n      end\n\n      def params\n        { :zoom => zoom, :year => year_from, :month => month_from, :months => months }\n      end\n\n      def params_previous\n        { :year => (date_from << months).year, :month => (date_from << months).month, :zoom => zoom, :months => months }\n      end\n\n      def params_next\n        { :year => (date_from >> months).year, :month => (date_from >> months).month, :zoom => zoom, :months => months }\n      end\n\n      # Generates a gantt image\n      # Only defined if RMagick is avalaible\n      def to_image(format='PNG')\n        date_to = (@date_from >> @months)-1\n        show_weeks = @zoom > 1\n        show_days = @zoom > 2\n\n        subject_width = 320\n        header_heigth = 18\n        # width of one day in pixels\n        zoom = @zoom*2\n        g_width = (@date_to - @date_from + 1)*zoom\n        g_height = 20 * events.length + 20\n        headers_heigth = (show_weeks ? 2*header_heigth : header_heigth)\n        height = g_height + headers_heigth\n\n        imgl = Magick::ImageList.new\n        imgl.new_image(subject_width+g_width+1, height)\n        gc = Magick::Draw.new\n\n        # Subjects\n        top = headers_heigth + 20\n        gc.fill('black')\n        gc.stroke('transparent')\n        gc.stroke_width(1)\n        events.each do |i|\n          gc.text(4, top + 2, (i.is_a?(Issue) ? i.subject : i.name))\n          top = top + 20\n        end\n\n        # Months headers\n        month_f = @date_from\n        left = subject_width\n        @months.times do\n          width = ((month_f >> 1) - month_f) * zoom\n          gc.fill('white')\n          gc.stroke('grey')\n          gc.stroke_width(1)\n          gc.rectangle(left, 0, left + width, height)\n          gc.fill('black')\n          gc.stroke('transparent')\n          gc.stroke_width(1)\n          gc.text(left.round + 8, 14, \"#{month_f.year}-#{month_f.month}\")\n          left = left + width\n          month_f = month_f >> 1\n        end\n\n        # Weeks headers\n        if show_weeks\n          left = subject_width\n          height = header_heigth\n          if @date_from.cwday == 1\n              # date_from is monday\n                week_f = date_from\n          else\n              # find next monday after date_from\n            week_f = @date_from + (7 - @date_from.cwday + 1)\n            width = (7 - @date_from.cwday + 1) * zoom\n                gc.fill('white')\n                gc.stroke('grey')\n                gc.stroke_width(1)\n                gc.rectangle(left, header_heigth, left + width, 2*header_heigth + g_height-1)\n            left = left + width\n          end\n          while week_f <= date_to\n            width = (week_f + 6 <= date_to) ? 7 * zoom : (date_to - week_f + 1) * zoom\n                gc.fill('white')\n                gc.stroke('grey')\n                gc.stroke_width(1)\n                gc.rectangle(left.round, header_heigth, left.round + width, 2*header_heigth + g_height-1)\n                gc.fill('black')\n                gc.stroke('transparent')\n                gc.stroke_width(1)\n                gc.text(left.round + 2, header_heigth + 14, week_f.cweek.to_s)\n            left = left + width\n            week_f = week_f+7\n          end\n        end\n\n        # Days details (week-end in grey)\n        if show_days\n          left = subject_width\n          height = g_height + header_heigth - 1\n          wday = @date_from.cwday\n          (date_to - @date_from + 1).to_i.times do\n              width =  zoom\n              gc.fill(wday == 6 || wday == 7 ? '#eee' : 'white')\n              gc.stroke('grey')\n              gc.stroke_width(1)\n              gc.rectangle(left, 2*header_heigth, left + width, 2*header_heigth + g_height-1)\n              left = left + width\n              wday = wday + 1\n              wday = 1 if wday > 7\n          end\n        end\n\n        # border\n        gc.fill('transparent')\n        gc.stroke('grey')\n        gc.stroke_width(1)\n        gc.rectangle(0, 0, subject_width+g_width, headers_heigth)\n        gc.stroke('black')\n        gc.rectangle(0, 0, subject_width+g_width, g_height+ headers_heigth-1)\n\n        # content\n        top = headers_heigth + 20\n        gc.stroke('transparent')\n        events.each do |i|\n          if i.is_a?(Issue)\n            i_start_date = (i.start_date >= @date_from ? i.start_date : @date_from )\n            i_end_date = (i.due_before <= date_to ? i.due_before : date_to )\n            i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor\n            i_done_date = (i_done_date <= @date_from ? @date_from : i_done_date )\n            i_done_date = (i_done_date >= date_to ? date_to : i_done_date )\n            i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today\n\n            i_left = subject_width + ((i_start_date - @date_from)*zoom).floor\n            i_width = ((i_end_date - i_start_date + 1)*zoom).floor                  # total width of the issue\n            d_width = ((i_done_date - i_start_date)*zoom).floor                     # done width\n            l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor : 0 # delay width\n\n            gc.fill('grey')\n            gc.rectangle(i_left, top, i_left + i_width, top - 6)\n            gc.fill('red')\n            gc.rectangle(i_left, top, i_left + l_width, top - 6) if l_width > 0\n            gc.fill('blue')\n            gc.rectangle(i_left, top, i_left + d_width, top - 6) if d_width > 0\n            gc.fill('black')\n            gc.text(i_left + i_width + 5,top + 1, \"#{i.status.name} #{i.done_ratio}%\")\n          else\n            i_left = subject_width + ((i.start_date - @date_from)*zoom).floor\n            gc.fill('green')\n            gc.rectangle(i_left, top, i_left + 6, top - 6)\n            gc.fill('black')\n            gc.text(i_left + 11, top + 1, i.name)\n          end\n          top = top + 20\n        end\n\n        # today red line\n        if Date.today >= @date_from and Date.today <= date_to\n          gc.stroke('red')\n          x = (Date.today-@date_from+1)*zoom + subject_width\n          gc.line(x, headers_heigth, x, headers_heigth + g_height-1)\n        end\n\n        gc.draw(imgl)\n        imgl.format = format\n        imgl.to_blob\n      end if Object.const_defined?(:Magick)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/i18n.rb",
    "content": "module Redmine\n  module I18n\n    def self.included(base)\n      base.extend Redmine::I18n\n    end\n\n    def l(*args)\n      case args.size\n      when 1\n        ::I18n.t(*args)\n      when 2\n        if args.last.is_a?(Hash)\n          ::I18n.t(*args)\n        elsif args.last.is_a?(String)\n          ::I18n.t(args.first, :value => args.last)\n        else\n          ::I18n.t(args.first, :count => args.last)\n        end\n      else\n        raise \"Translation string with multiple values: #{args.first}\"\n      end\n    end\n\n    def l_or_humanize(s, options={})\n      k = \"#{options[:prefix]}#{s}\".to_sym\n      ::I18n.t(k, :default => s.to_s.humanize)\n    end\n\n    def l_hours(hours)\n      hours = hours.to_f\n      l((hours < 2.0 ? :label_f_hour : :label_f_hour_plural), :value => (\"%.2f\" % hours.to_f))\n    end\n\n    def ll(lang, str, value=nil)\n      ::I18n.t(str.to_s, :value => value, :locale => lang.to_s.gsub(%r{(.+)\\-(.+)$}) { \"#{$1}-#{$2.upcase}\" })\n    end\n\n    def format_date(date)\n      return nil unless date\n      Setting.date_format.blank? ? l(date.to_date) : date.strftime(Setting.date_format)\n    end\n\n    def format_time(time, include_date = true)\n      return nil unless time\n      time = time.to_time if time.is_a?(String)\n      zone = User.current.time_zone\n      local = zone ? time.in_time_zone(zone) : (time.utc? ? time.localtime : time)\n      Setting.time_format.blank? ? l(local, :format => (include_date ? :default : :time)) :\n                                   ((include_date ? \"#{format_date(time)} \" : \"\") + \"#{local.strftime(Setting.time_format)}\")\n    end\n\n    def local_time(time)\n      return nil unless time\n      time = time.to_time if time.is_a?(String)\n      zone = User.current.time_zone\n      local = zone ? time.in_time_zone(zone) : (time.utc? ? time.localtime : time)\n      return local\n    end\n\n\n    def day_name(day)\n      ::I18n.t('date.day_names')[day % 7]\n    end\n\n    def month_name(month)\n      ::I18n.t('date.month_names')[month]\n    end\n\n    def valid_languages\n      @@valid_languages ||= Dir.glob(File.join(RAILS_ROOT, 'config', 'locales', '*.yml')).collect {|f| File.basename(f).split('.').first}.collect(&:to_sym)\n    end\n\n    def find_language(lang)\n      @@languages_lookup = valid_languages.inject({}) {|k, v| k[v.to_s.downcase] = v; k }\n      @@languages_lookup[lang.to_s.downcase]\n    end\n\n    def set_language_if_valid(lang)\n      if l = find_language(lang)\n        ::I18n.locale = l\n      end\n    end\n\n    def current_language\n      ::I18n.locale\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/imap.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nrequire 'net/imap'\n\nmodule Redmine\n  module IMAP\n    class << self\n      def check(imap_options={}, options={})\n        host = imap_options[:host] || '127.0.0.1'\n        port = imap_options[:port] || '143'\n        ssl = !imap_options[:ssl].nil?\n        folder = imap_options[:folder] || 'INBOX'\n\n        imap = Net::IMAP.new(host, port, ssl)\n        imap.login(imap_options[:username], imap_options[:password]) unless imap_options[:username].nil?\n        imap.select(folder)\n        imap.search(['NOT', 'SEEN']).each do |message_id|\n          msg = imap.fetch(message_id,'RFC822')[0].attr['RFC822']\n          logger.debug \"Receiving message #{message_id}\" if logger && logger.debug?\n          if MailHandler.receive(msg, options)\n            logger.debug \"Message #{message_id} successfully received\" if logger && logger.debug?\n            if imap_options[:move_on_success]\n              imap.copy(message_id, imap_options[:move_on_success])\n            end\n            imap.store(message_id, \"+FLAGS\", [:Seen, :Deleted])\n          else\n            logger.debug \"Message #{message_id} can not be processed\" if logger && logger.debug?\n            imap.store(message_id, \"+FLAGS\", [:Seen])\n            if imap_options[:move_on_failure]\n              imap.copy(message_id, imap_options[:move_on_failure])\n              imap.store(message_id, \"+FLAGS\", [:Deleted])\n            end\n          end\n        end\n        imap.expunge\n      end\n\n      private\n\n      def logger\n        RAILS_DEFAULT_LOGGER\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/info.rb",
    "content": "module Redmine\n  module Info\n    class << self\n      def app_name; 'Redmine' end\n      def url; 'http://www.redmine.org/' end\n      def help_url; 'http://www.redmine.org/guide' end\n      def versioned_name; \"#{app_name} #{Redmine::VERSION}\" end\n\n      # Creates the url string to a specific Redmine issue\n      def issue(issue_id)\n        url + 'issues/' + issue_id.to_s\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/menu_manager.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nrequire 'tree' # gem install rubytree\n\n# Monkey patch the TreeNode to add on a few more methods :nodoc:\nmodule TreeNodePatch\n  def self.included(base)\n    base.class_eval do\n      attr_reader :last_items_count\n\n      alias :old_initilize :initialize\n      def initialize(name, content = nil)\n        old_initilize(name, content)\n        @last_items_count = 0\n        @childrenHash ||= {}\n        extend(InstanceMethods)\n      end\n    end\n  end\n\n  module InstanceMethods\n    # Adds the specified child node to the receiver node.  The child node's\n    # parent is set to be the receiver.  The child is added as the first child in\n    # the current list of children for the receiver node.\n    def prepend(child)\n      raise \"Child already added\" if @childrenHash && @childrenHash.has_key?(child.name)\n\n      @childrenHash[child.name]  = child\n      @children = [child] + @children\n      child.parent = self\n      return child\n\n    end\n\n    # Adds the specified child node to the receiver node.  The child node's\n    # parent is set to be the receiver.  The child is added at the position\n    # into the current list of children for the receiver node.\n    def add_at(child, position)\n      raise \"Child already added\" if @childrenHash && @childrenHash.has_key?(child.name)\n\n      @childrenHash[child.name]  = child\n      @children = @children.insert(position, child)\n      child.parent = self\n      return child\n\n    end\n\n    def add_last(child)\n      raise \"Child already added\" if @childrenHash && @childrenHash.has_key?(child.name)\n\n      @childrenHash[child.name]  = child\n      @children <<  child\n      @last_items_count += 1\n      child.parent = self\n      return child\n\n    end\n\n    # Adds the specified child node to the receiver node.  The child node's\n    # parent is set to be the receiver.  The child is added as the last child in\n    # the current list of children for the receiver node.\n    def add(child)\n      raise \"Child already added\" if @childrenHash && @childrenHash.has_key?(child.name)\n\n      @childrenHash[child.name]  = child\n      position = @children.size - @last_items_count\n      @children.insert(position, child)\n      child.parent = self\n      return child\n\n    end\n\n    # Will return the position (zero-based) of the current child in\n    # it's parent\n    def position\n      self.parent.children.index(self)\n    end\n  end\nend\nTree::TreeNode.send(:include, TreeNodePatch)\n\nmodule Redmine\n  module MenuManager\n    class MenuError < StandardError #:nodoc:\n    end\n\n    module MenuController\n      def self.included(base)\n        base.extend(ClassMethods)\n      end\n\n      module ClassMethods\n        @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}}\n        mattr_accessor :menu_items\n\n        # Set the menu item name for a controller or specific actions\n        # Examples:\n        #   * menu_item :tickets # => sets the menu name to :tickets for the whole controller\n        #   * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only\n        #   * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only\n        #\n        # The default menu item name for a controller is controller_name by default\n        # Eg. the default menu item name for ProjectsController is :projects\n        def menu_item(id, options = {})\n          if actions = options[:only]\n            actions = [] << actions unless actions.is_a?(Array)\n            actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id}\n          else\n            menu_items[controller_name.to_sym][:default] = id\n          end\n        end\n      end\n\n      def menu_items\n        self.class.menu_items\n      end\n\n      # Returns the menu item name according to the current action\n      def current_menu_item\n        @current_menu_item ||= menu_items[controller_name.to_sym][:actions][action_name.to_sym] ||\n                                 menu_items[controller_name.to_sym][:default]\n      end\n\n      # Redirects user to the menu item of the given project\n      # Returns false if user is not authorized\n      def redirect_to_project_menu_item(project, name)\n        item = Redmine::MenuManager.items(:project_menu).detect {|i| i.name.to_s == name.to_s}\n        if item && User.current.allowed_to?(item.url, project) && (item.condition.nil? || item.condition.call(project))\n          redirect_to({item.param => project}.merge(item.url))\n          return true\n        end\n        false\n      end\n    end\n\n    module MenuHelper\n      # Returns the current menu item name\n      def current_menu_item\n        @controller.current_menu_item\n      end\n\n      # Renders the application main menu\n      def render_main_menu(project)\n        render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project)\n      end\n\n      def render_menu(menu, project=nil)\n        links = []\n        menu_items_for(menu, project) do |node|\n          links << render_menu_node(node, project)\n        end\n        links.empty? ? nil : content_tag('ul', links.join(\"\\n\"))\n      end\n\n      def render_menu_node(node, project=nil)\n        if node.hasChildren? || !node.child_menus.nil?\n          return render_menu_node_with_children(node, project)\n        else\n          caption, url, selected = extract_node_details(node, project)\n          return content_tag('li',\n                               render_single_menu_node(node, caption, url, selected))\n        end\n      end\n\n      def render_menu_node_with_children(node, project=nil)\n        caption, url, selected = extract_node_details(node, project)\n\n        html = returning [] do |html|\n          html << '<li>'\n          # Parent\n          html << render_single_menu_node(node, caption, url, selected)\n\n          # Standard children\n          standard_children_list = returning \"\" do |child_html|\n            node.children.each do |child|\n              child_html << render_menu_node(child, project)\n            end\n          end\n\n          html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty?\n\n          # Unattached children\n          unattached_children_list = render_unattached_children_menu(node, project)\n          html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank?\n\n          html << '</li>'\n        end\n        return html.join(\"\\n\")\n      end\n\n      # Returns a list of unattached children menu items\n      def render_unattached_children_menu(node, project)\n        return nil unless node.child_menus\n\n        returning \"\" do |child_html|\n          unattached_children = node.child_menus.call(project)\n          # Tree nodes support #each so we need to do object detection\n          if unattached_children.is_a? Array\n            unattached_children.each do |child|\n              child_html << content_tag(:li, render_unattached_menu_item(child, project))\n            end\n          else\n            raise MenuError, \":child_menus must be an array of MenuItems\"\n          end\n        end\n      end\n\n      def render_single_menu_node(item, caption, url, selected)\n        link_to(h(caption), url, item.html_options(:selected => selected))\n      end\n\n      def render_unattached_menu_item(menu_item, project)\n        raise MenuError, \":child_menus must be an array of MenuItems\" unless menu_item.is_a? MenuItem\n\n        if User.current.allowed_to?(menu_item.url, project)\n          link_to(h(menu_item.caption),\n                  menu_item.url,\n                  menu_item.html_options)\n        end\n      end\n\n      def menu_items_for(menu, project=nil)\n        items = []\n        Redmine::MenuManager.items(menu).root.children.each do |node|\n          if allowed_node?(node, User.current, project)\n            if block_given?\n              yield node\n            else\n              items << node  # TODO: not used?\n            end\n          end\n        end\n        return block_given? ? nil : items\n      end\n\n      def extract_node_details(node, project=nil)\n        item = node\n        url = case item.url\n        when Hash\n          project.nil? ? item.url : {item.param => project}.merge(item.url)\n        when Symbol\n          send(item.url)\n        else\n          item.url\n        end\n        caption = item.caption(project)\n        return [caption, url, (current_menu_item == item.name)]\n      end\n\n      # Checks if a user is allowed to access the menu item by:\n      #\n      # * Checking the conditions of the item\n      # * Checking the url target (project only)\n      def allowed_node?(node, user, project)\n        if node.condition && !node.condition.call(project)\n          # Condition that doesn't pass\n          return false\n        end\n\n        if project\n          return user && user.allowed_to?(node.url, project)\n        else\n          # outside a project, all menu items allowed\n          return true\n        end\n      end\n    end\n\n    class << self\n      def map(menu_name)\n        @items ||= {}\n        mapper = Mapper.new(menu_name.to_sym, @items)\n        if block_given?\n          yield mapper\n        else\n          mapper\n        end\n      end\n\n      def items(menu_name)\n        @items[menu_name.to_sym] || Tree::TreeNode.new(:root, {})\n      end\n    end\n\n    class Mapper\n      def initialize(menu, items)\n        items[menu] ||= Tree::TreeNode.new(:root, {})\n        @menu = menu\n        @menu_items = items[menu]\n      end\n\n      @@last_items_count = Hash.new {|h,k| h[k] = 0}\n\n      # Adds an item at the end of the menu. Available options:\n      # * param: the parameter name that is used for the project id (default is :id)\n      # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true\n      # * caption that can be:\n      #   * a localized string Symbol\n      #   * a String\n      #   * a Proc that can take the project as argument\n      # * before, after: specify where the menu item should be inserted (eg. :after => :activity)\n      # * parent: menu item will be added as a child of another named menu (eg. :parent => :issues)\n      # * children: a Proc that is called before rendering the item. The Proc should return an array of MenuItems, which will be added as children to this item.\n      #   eg. :children => Proc.new {|project| [Redmine::MenuManager::MenuItem.new(...)] }\n      # * last: menu item will stay at the end (eg. :last => true)\n      # * html_options: a hash of html options that are passed to link_to\n      def push(name, url, options={})\n        options = options.dup\n\n        if options[:parent]\n          subtree = self.find(options[:parent])\n          if subtree\n            target_root = subtree\n          else\n            target_root = @menu_items.root\n          end\n\n        else\n          target_root = @menu_items.root\n        end\n\n        # menu item position\n        if first = options.delete(:first)\n          target_root.prepend(MenuItem.new(name, url, options))\n        elsif before = options.delete(:before)\n\n          if exists?(before)\n            target_root.add_at(MenuItem.new(name, url, options), position_of(before))\n          else\n            target_root.add(MenuItem.new(name, url, options))\n          end\n\n        elsif after = options.delete(:after)\n\n          if exists?(after)\n            target_root.add_at(MenuItem.new(name, url, options), position_of(after) + 1)\n          else\n            target_root.add(MenuItem.new(name, url, options))\n          end\n\n        elsif options.delete(:last)\n          target_root.add_last(MenuItem.new(name, url, options))\n        else\n          target_root.add(MenuItem.new(name, url, options))\n        end\n      end\n\n      # Removes a menu item\n      def delete(name)\n        if found = self.find(name)\n          @menu_items.remove!(found)\n        end\n      end\n\n      # Checks if a menu item exists\n      def exists?(name)\n        @menu_items.any? {|node| node.name == name}\n      end\n\n      def find(name)\n        @menu_items.find {|node| node.name == name}\n      end\n\n      def position_of(name)\n        @menu_items.each do |node|\n          if node.name == name\n            return node.position\n          end\n        end\n      end\n    end\n\n    class MenuItem < Tree::TreeNode\n      include Redmine::I18n\n      attr_reader :name, :url, :param, :condition, :parent, :child_menus\n\n      def initialize(name, url, options)\n        raise ArgumentError, \"Invalid option :if for menu item '#{name}'\" if options[:if] && !options[:if].respond_to?(:call)\n        raise ArgumentError, \"Invalid option :html for menu item '#{name}'\" if options[:html] && !options[:html].is_a?(Hash)\n        raise ArgumentError, \"Cannot set the :parent to be the same as this item\" if options[:parent] == name.to_sym\n        raise ArgumentError, \"Invalid option :children for menu item '#{name}'\" if options[:children] && !options[:children].respond_to?(:call)\n        @name = name\n        @url = url\n        @condition = options[:if]\n        @param = options[:param] || :id\n        @caption = options[:caption]\n        @html_options = options[:html] || {}\n        # Adds a unique class to each menu item based on its name\n        @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')\n        @parent = options[:parent]\n        @child_menus = options[:children]\n        super @name.to_sym\n      end\n\n      def caption(project=nil)\n        if @caption.is_a?(Proc)\n          c = @caption.call(project).to_s\n          c = @name.to_s.humanize if c.blank?\n          c\n        else\n          if @caption.nil?\n            l_or_humanize(name, :prefix => 'label_')\n          else\n            @caption.is_a?(Symbol) ? l(@caption) : @caption\n          end\n        end\n      end\n\n      def html_options(options={})\n        if options[:selected]\n          o = @html_options.dup\n          o[:class] += ' gt-active'\n          o\n        else\n          @html_options\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/mime_type.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine\n  module MimeType\n\n    MIME_TYPES = {\n      'text/plain' => 'txt,tpl,properties,patch,diff,ini,readme,install,upgrade',\n      'text/css' => 'css',\n      'text/html' => 'html,htm,xhtml',\n      'text/jsp' => 'jsp',\n      'text/x-c' => 'c,cpp,cc,h,hh',\n      'text/x-csharp' => 'cs',\n      'text/x-java' => 'java',\n      'text/x-javascript' => 'js',\n      'text/x-html-template' => 'rhtml,html.erb',\n      'text/x-perl' => 'pl,pm',\n      'text/x-php' => 'php,php3,php4,php5',\n      'text/x-python' => 'py',\n      'text/x-ruby' => 'rb,rbw,ruby,rake,erb',\n      'text/x-csh' => 'csh',\n      'text/x-sh' => 'sh',\n      'text/xml' => 'xml,xsd,mxml',\n      'text/yaml' => 'yml,yaml',\n      'image/gif' => 'gif',\n      'image/jpeg' => 'jpg,jpeg,jpe',\n      'image/png' => 'png',\n      'image/tiff' => 'tiff,tif',\n      'image/x-ms-bmp' => 'bmp',\n      'image/x-xpixmap' => 'xpm',\n      'application/pdf' => 'pdf',\n      'application/zip' => 'zip',\n      'application/x-gzip' => 'gz',\n    }.freeze\n\n    EXTENSIONS = MIME_TYPES.inject({}) do |map, (type, exts)|\n      exts.split(',').each {|ext| map[ext.strip] = type}\n      map\n    end\n\n    # returns mime type for name or nil if unknown\n    def self.of(name)\n      return nil unless name\n      m = name.to_s.match(/(^|\\.)([^\\.]+)$/)\n      EXTENSIONS[m[2].downcase] if m\n    end\n\n    # Returns the css class associated to\n    # the mime type of name\n    def self.css_class_of(name)\n      mime = of(name)\n      mime && mime.gsub('/', '-')\n    end\n\n    def self.main_mimetype_of(name)\n      mimetype = of(name)\n      mimetype.split('/').first if mimetype\n    end\n\n    # return true if mime-type for name is type/*\n    # otherwise false\n    def self.is_type?(type, name)\n      main_mimetype = main_mimetype_of(name)\n      type.to_s == main_mimetype\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/platform.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nmodule Redmine\n  module Platform\n    class << self\n      def mswin?\n        (RUBY_PLATFORM =~ /(:?mswin|mingw)/) || (RUBY_PLATFORM == 'java' && (ENV['OS'] || ENV['os']) =~ /windows/i)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/plugin.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine #:nodoc:\n\n  class PluginNotFound < StandardError; end\n  class PluginRequirementError < StandardError; end\n\n  # Base class for Redmine plugins.\n  # Plugins are registered using the <tt>register</tt> class method that acts as the public constructor.\n  #\n  #   Redmine::Plugin.register :example do\n  #     name 'Example plugin'\n  #     author 'John Smith'\n  #     description 'This is an example plugin for Redmine'\n  #     version '0.0.1'\n  #     settings :default => {'foo'=>'bar'}, :partial => 'settings/settings'\n  #   end\n  #\n  # === Plugin attributes\n  #\n  # +settings+ is an optional attribute that let the plugin be configurable.\n  # It must be a hash with the following keys:\n  # * <tt>:default</tt>: default value for the plugin settings\n  # * <tt>:partial</tt>: path of the configuration partial view, relative to the plugin <tt>app/views</tt> directory\n  # Example:\n  #   settings :default => {'foo'=>'bar'}, :partial => 'settings/settings'\n  # In this example, the settings partial will be found here in the plugin directory: <tt>app/views/settings/_settings.rhtml</tt>.\n  #\n  # When rendered, the plugin settings value is available as the local variable +settings+\n  class Plugin\n    @registered_plugins = {}\n    class << self\n      attr_reader :registered_plugins\n      private :new\n\n      def def_field(*names)\n        class_eval do\n          names.each do |name|\n            define_method(name) do |*args|\n              args.empty? ? instance_variable_get(\"@#{name}\") : instance_variable_set(\"@#{name}\", *args)\n            end\n          end\n        end\n      end\n    end\n    def_field :name, :description, :url, :author, :author_url, :version, :settings\n    attr_reader :id\n\n    # Plugin constructor\n    def self.register(id, &block)\n      p = new(id)\n      p.instance_eval(&block)\n      # Set a default name if it was not provided during registration\n      p.name(id.to_s.humanize) if p.name.nil?\n      # Adds plugin locales if any\n      # YAML translation files should be found under <plugin>/config/locales/\n      ::I18n.load_path += Dir.glob(File.join(RAILS_ROOT, 'vendor', 'plugins', id.to_s, 'config', 'locales', '*.yml'))\n      registered_plugins[id] = p\n    end\n\n    # Returns an array off all registered plugins\n    def self.all\n      registered_plugins.values.sort\n    end\n\n    # Finds a plugin by its id\n    # Returns a PluginNotFound exception if the plugin doesn't exist\n    def self.find(id)\n      registered_plugins[id.to_sym] || raise(PluginNotFound)\n    end\n\n    # Clears the registered plugins hash\n    # It doesn't unload installed plugins\n    def self.clear\n      @registered_plugins = {}\n    end\n\n    def initialize(id)\n      @id = id.to_sym\n    end\n\n    def <=>(plugin)\n      self.id.to_s <=> plugin.id.to_s\n    end\n\n    # Sets a requirement on Redmine version\n    # Raises a PluginRequirementError exception if the requirement is not met\n    #\n    # Examples\n    #   # Requires Redmine 0.7.3 or higher\n    #   requires_redmine :version_or_higher => '0.7.3'\n    #   requires_redmine '0.7.3'\n    #\n    #   # Requires a specific Redmine version\n    #   requires_redmine :version => '0.7.3'              # 0.7.3 only\n    #   requires_redmine :version => ['0.7.3', '0.8.0']   # 0.7.3 or 0.8.0\n    def requires_redmine(arg)\n      arg = { :version_or_higher => arg } unless arg.is_a?(Hash)\n      arg.assert_valid_keys(:version, :version_or_higher)\n\n      current = Redmine::VERSION.to_a\n      arg.each do |k, v|\n        v = [] << v unless v.is_a?(Array)\n        versions = v.collect {|s| s.split('.').collect(&:to_i)}\n        case k\n        when :version_or_higher\n          raise ArgumentError.new(\"wrong number of versions (#{versions.size} for 1)\") unless versions.size == 1\n          unless (current <=> versions.first) >= 0\n            raise PluginRequirementError.new(\"#{id} plugin requires Redmine #{v} or higher but current is #{current.join('.')}\")\n          end\n        when :version\n          unless versions.include?(current.slice(0,3))\n            raise PluginRequirementError.new(\"#{id} plugin requires one the following Redmine versions: #{v.join(', ')} but current is #{current.join('.')}\")\n          end\n        end\n      end\n      true\n    end\n\n    # Sets a requirement on a Redmine plugin version\n    # Raises a PluginRequirementError exception if the requirement is not met\n    #\n    # Examples\n    #   # Requires a plugin named :foo version 0.7.3 or higher\n    #   requires_redmine_plugin :foo, :version_or_higher => '0.7.3'\n    #   requires_redmine_plugin :foo, '0.7.3'\n    #\n    #   # Requires a specific version of a Redmine plugin\n    #   requires_redmine_plugin :foo, :version => '0.7.3'              # 0.7.3 only\n    #   requires_redmine_plugin :foo, :version => ['0.7.3', '0.8.0']   # 0.7.3 or 0.8.0\n    def requires_redmine_plugin(plugin_name, arg)\n      arg = { :version_or_higher => arg } unless arg.is_a?(Hash)\n      arg.assert_valid_keys(:version, :version_or_higher)\n\n      plugin = Plugin.find(plugin_name)\n      current = plugin.version.split('.').collect(&:to_i)\n\n      arg.each do |k, v|\n        v = [] << v unless v.is_a?(Array)\n        versions = v.collect {|s| s.split('.').collect(&:to_i)}\n        case k\n        when :version_or_higher\n          raise ArgumentError.new(\"wrong number of versions (#{versions.size} for 1)\") unless versions.size == 1\n          unless (current <=> versions.first) >= 0\n            raise PluginRequirementError.new(\"#{id} plugin requires the #{plugin_name} plugin #{v} or higher but current is #{current.join('.')}\")\n          end\n        when :version\n          unless versions.include?(current.slice(0,3))\n            raise PluginRequirementError.new(\"#{id} plugin requires one the following versions of #{plugin_name}: #{v.join(', ')} but current is #{current.join('.')}\")\n          end\n        end\n      end\n      true\n    end\n\n    # Adds an item to the given +menu+.\n    # The +id+ parameter (equals to the project id) is automatically added to the url.\n    #   menu :project_menu, :plugin_example, { :controller => 'example', :action => 'say_hello' }, :caption => 'Sample'\n    #\n    # +name+ parameter can be: :top_menu, :account_menu, :application_menu or :project_menu\n    #\n    def menu(menu, item, url, options={})\n      Redmine::MenuManager.map(menu).push(item, url, options)\n    end\n    alias :add_menu_item :menu\n\n    # Removes +item+ from the given +menu+.\n    def delete_menu_item(menu, item)\n      Redmine::MenuManager.map(menu).delete(item)\n    end\n\n    # Defines a permission called +name+ for the given +actions+.\n    #\n    # The +actions+ argument is a hash with controllers as keys and actions as values (a single value or an array):\n    #   permission :destroy_contacts, { :contacts => :destroy }\n    #   permission :view_contacts, { :contacts => [:index, :show] }\n    #\n    # The +options+ argument can be used to make the permission public (implicitly given to any user)\n    # or to restrict users the permission can be given to.\n    #\n    # Examples\n    #   # A permission that is implicitly given to any user\n    #   # This permission won't appear on the Roles & Permissions setup screen\n    #   permission :say_hello, { :example => :say_hello }, :public => true\n    #\n    #   # A permission that can be given to any user\n    #   permission :say_hello, { :example => :say_hello }\n    #\n    #   # A permission that can be given to registered users only\n    #   permission :say_hello, { :example => :say_hello }, :require => loggedin\n    #\n    #   # A permission that can be given to project members only\n    #   permission :say_hello, { :example => :say_hello }, :require => member\n    def permission(name, actions, options = {})\n      if @project_module\n        Redmine::AccessControl.map {|map| map.project_module(@project_module) {|map|map.permission(name, actions, options)}}\n      else\n        Redmine::AccessControl.map {|map| map.permission(name, actions, options)}\n      end\n    end\n\n    # Defines a project module, that can be enabled/disabled for each project.\n    # Permissions defined inside +block+ will be bind to the module.\n    #\n    #   project_module :things do\n    #     permission :view_contacts, { :contacts => [:list, :show] }, :public => true\n    #     permission :destroy_contacts, { :contacts => :destroy }\n    #   end\n    def project_module(name, &block)\n      @project_module = name\n      self.instance_eval(&block)\n      @project_module = nil\n    end\n\n    # Registers an activity provider.\n    #\n    # Options:\n    # * <tt>:class_name</tt> - one or more model(s) that provide these events (inferred from event_type by default)\n    # * <tt>:default</tt> - setting this option to false will make the events not displayed by default\n    #\n    # A model can provide several activity event types.\n    #\n    # Examples:\n    #   register :news\n    #   register :scrums, :class_name => 'Meeting'\n    #   register :issues, :class_name => ['Issue', 'Journal']\n    #\n    # Retrieving events:\n    # Associated model(s) must implement the find_events class method.\n    # ActiveRecord models can use acts_as_activity_provider as a way to implement this class method.\n    #\n    # The following call should return all the scrum events visible by current user that occured in the 5 last days:\n    #   Meeting.find_events('scrums', User.current, 5.days.ago, Date.today)\n    #   Meeting.find_events('scrums', User.current, 5.days.ago, Date.today, :project => foo) # events for project foo only\n    #\n    # Note that :view_scrums permission is required to view these events in the activity view.\n    def activity_provider(*args)\n      Redmine::Activity.register(*args)\n    end\n\n    # Registers a wiki formatter.\n    #\n    # Parameters:\n    # * +name+ - human-readable name\n    # * +formatter+ - formatter class, which should have an instance method +to_html+\n    # * +helper+ - helper module, which will be included by wiki pages\n    def wiki_format_provider(name, formatter, helper)\n      Redmine::WikiFormatting.register(name, formatter, helper)\n    end\n\n    # Returns +true+ if the plugin can be configured.\n    def configurable?\n      settings && settings.is_a?(Hash) && !settings[:partial].blank?\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/search.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2009  Jean-Philippe Lang\n#\n# This program is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation; either version 2\n# of the License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n\nmodule Redmine\n  module Search\n    module Controller\n      def self.included(base)\n        base.extend(ClassMethods)\n      end\n\n      module ClassMethods\n        @@default_search_scopes = Hash.new {|hash, key| hash[key] = {:default => nil, :actions => {}}}\n        mattr_accessor :default_search_scopes\n\n        # Set the default search scope for a controller or specific actions\n        # Examples:\n        #   * search_scope :issues # => sets the search scope to :issues for the whole controller\n        #   * search_scope :issues, :only => :index\n        #   * search_scope :issues, :only => [:index, :show]\n        def default_search_scope(id, options = {})\n          if actions = options[:only]\n            actions = [] << actions unless actions.is_a?(Array)\n            actions.each {|a| default_search_scopes[controller_name.to_sym][:actions][a.to_sym] = id.to_s}\n          else\n            default_search_scopes[controller_name.to_sym][:default] = id.to_s\n          end\n        end\n      end\n\n      def default_search_scopes\n        self.class.default_search_scopes\n      end\n\n      # Returns the default search scope according to the current action\n      def default_search_scope\n        @default_search_scope ||= default_search_scopes[controller_name.to_sym][:actions][action_name.to_sym] ||\n                                  default_search_scopes[controller_name.to_sym][:default]\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/themes.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine\n  module Themes\n\n    # Return an array of installed themes\n    def self.themes\n      @@installed_themes ||= scan_themes\n    end\n\n    # Rescan themes directory\n    def self.rescan\n      @@installed_themes = scan_themes\n    end\n\n    # Return theme for given id, or nil if it's not found\n    def self.theme(id)\n      themes.find {|t| t.id == id}\n    end\n\n    # Class used to represent a theme\n    class Theme\n      attr_reader :name, :dir, :stylesheets\n\n      def initialize(path)\n        @dir = File.basename(path)\n        @name = @dir.humanize\n        @stylesheets = Dir.glob(\"#{path}/stylesheets/*.css\").collect {|f| File.basename(f).gsub(/\\.css$/, '')}\n      end\n\n      # Directory name used as the theme id\n      def id; dir end\n\n      def <=>(theme)\n        name <=> theme.name\n      end\n    end\n\n    private\n\n    def self.scan_themes\n      dirs = Dir.glob(\"#{RAILS_ROOT}/public/themes/*\").select do |f|\n        # A theme should at least override application.css\n        File.directory?(f) && File.exist?(\"#{f}/stylesheets/application.css\")\n      end\n      dirs.collect {|dir| Theme.new(dir)}.sort\n    end\n  end\nend\n\nmodule ApplicationHelper\n  def stylesheet_path(source)\n    @current_theme ||= Redmine::Themes.theme(Setting.ui_theme)\n    super((@current_theme && @current_theme.stylesheets.include?(source)) ?\n      \"/themes/#{@current_theme.dir}/stylesheets/#{source}\" : source)\n  end\n\n  def path_to_stylesheet(source)\n    stylesheet_path source\n  end\nend\n"
  },
  {
    "path": "lib/redmine/unified_diff.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nmodule Redmine\n  # Class used to parse unified diffs\n  class UnifiedDiff < Array\n    def initialize(diff, options={})\n      options.assert_valid_keys(:type, :max_lines)\n      diff = diff.split(\"\\n\") if diff.is_a?(String)\n      diff_type = options[:type] || 'inline'\n\n      lines = 0\n      @truncated = false\n      diff_table = DiffTable.new(diff_type)\n      diff.each do |line|\n        unless diff_table.add_line line\n          self << diff_table if diff_table.length > 1\n          diff_table = DiffTable.new(diff_type)\n        end\n        lines += 1\n        if options[:max_lines] && lines > options[:max_lines]\n          @truncated = true\n          break\n        end\n      end\n      self << diff_table unless diff_table.empty?\n      self\n    end\n\n    def truncated?; @truncated; end\n  end\n\n  # Class that represents a file diff\n  class DiffTable < Hash\n    attr_reader :file_name, :line_num_l, :line_num_r\n\n    # Initialize with a Diff file and the type of Diff View\n    # The type view must be inline or sbs (side_by_side)\n    def initialize(type=\"inline\")\n      @parsing = false\n      @nb_line = 1\n      @start = false\n      @before = 'same'\n      @second = true\n      @type = type\n    end\n\n    # Function for add a line of this Diff\n    # Returns false when the diff ends\n    def add_line(line)\n      unless @parsing\n        if line =~ /^(---|\\+\\+\\+) (.*)$/\n          @file_name = $2\n        elsif line =~ /^@@ (\\+|\\-)(\\d+)(,\\d+)? (\\+|\\-)(\\d+)(,\\d+)? @@/\n          @line_num_l = $2.to_i\n          @line_num_r = $5.to_i\n          @parsing = true\n        end\n      else\n        if line =~ /^[^\\+\\-\\s@\\\\]/\n          @parsing = false\n          return false\n        elsif line =~ /^@@ (\\+|\\-)(\\d+)(,\\d+)? (\\+|\\-)(\\d+)(,\\d+)? @@/\n          @line_num_l = $2.to_i\n          @line_num_r = $5.to_i\n        else\n          @nb_line += 1 if parse_line(line, @type)\n        end\n      end\n      return true\n    end\n\n    def inspect\n      puts '### DIFF TABLE ###'\n      puts \"file : #{file_name}\"\n      self.each do |d|\n        d.inspect\n      end\n    end\n\n  private\n    # Test if is a Side By Side type\n    def sbs?(type, func)\n      if @start and type == \"sbs\"\n        if @before == func and @second\n          tmp_nb_line = @nb_line\n          self[tmp_nb_line] = Diff.new\n        else\n            @second = false\n            tmp_nb_line = @start\n            @start += 1\n            @nb_line -= 1\n        end\n      else\n        tmp_nb_line = @nb_line\n        @start = @nb_line\n        self[tmp_nb_line] = Diff.new\n        @second = true\n      end\n      unless self[tmp_nb_line]\n        @nb_line += 1\n        self[tmp_nb_line] = Diff.new\n      else\n        self[tmp_nb_line]\n      end\n    end\n\n    # Escape the HTML for the diff\n    def escapeHTML(line)\n        CGI.escapeHTML(line)\n    end\n\n    def parse_line(line, type=\"inline\")\n      if line[0, 1] == \"+\"\n        diff = sbs? type, 'add'\n        @before = 'add'\n        diff.line_right = escapeHTML line[1..-1]\n        diff.nb_line_right = @line_num_r\n        diff.type_diff_right = 'diff_in'\n        @line_num_r += 1\n        true\n      elsif line[0, 1] == \"-\"\n        diff = sbs? type, 'remove'\n        @before = 'remove'\n        diff.line_left = escapeHTML line[1..-1]\n        diff.nb_line_left = @line_num_l\n        diff.type_diff_left = 'diff_out'\n        @line_num_l += 1\n        true\n      elsif line[0, 1] =~ /\\s/\n        @before = 'same'\n        @start = false\n        diff = Diff.new\n        diff.line_right = escapeHTML line[1..-1]\n        diff.nb_line_right = @line_num_r\n        diff.line_left = escapeHTML line[1..-1]\n        diff.nb_line_left = @line_num_l\n        self[@nb_line] = diff\n        @line_num_l += 1\n        @line_num_r += 1\n        true\n      elsif line[0, 1] = \"\\\\\"\n          true\n        else\n          false\n        end\n      end\n    end\n\n  # A line of diff\n  class Diff\n    attr_accessor :nb_line_left\n    attr_accessor :line_left\n    attr_accessor :nb_line_right\n    attr_accessor :line_right\n    attr_accessor :type_diff_right\n    attr_accessor :type_diff_left\n\n    def initialize()\n      self.nb_line_left = ''\n      self.nb_line_right = ''\n      self.line_left = ''\n      self.line_right = ''\n      self.type_diff_right = ''\n      self.type_diff_left = ''\n    end\n\n    def inspect\n      puts '### Start Line Diff ###'\n      puts self.nb_line_left\n      puts self.line_left\n      puts self.nb_line_right\n      puts self.line_right\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/utils.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n# This program is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation; either version 2\n# of the License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n\nmodule Redmine\n  module Utils\n    class << self\n      # Returns the relative root url of the application\n      def relative_url_root\n        ActionController::Base.respond_to?('relative_url_root') ?\n          ActionController::Base.relative_url_root.to_s :\n          ActionController::AbstractRequest.relative_url_root.to_s\n      end\n\n      # Sets the relative root url of the application\n      def relative_url_root=(arg)\n        if ActionController::Base.respond_to?('relative_url_root=')\n          ActionController::Base.relative_url_root=arg\n        else\n          ActionController::AbstractRequest.relative_url_root=arg\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/version.rb",
    "content": "require 'rexml/document'\n\nmodule Redmine\n  module VERSION #:nodoc:\n    MAJOR = 0\n    MINOR = 9\n    TINY  = 0\n\n    # Branch values:\n    # * official release: nil\n    # * stable branch:    stable\n    # * trunk:            devel\n    BRANCH = 'devel'\n\n    def self.revision\n      revision = nil\n      entries_path = \"#{RAILS_ROOT}/.svn/entries\"\n      if File.readable?(entries_path)\n        begin\n          f = File.open(entries_path, 'r')\n          entries = f.read\n          f.close\n         if entries.match(%r{^\\d+})\n           revision = $1.to_i if entries.match(%r{^\\d+\\s+dir\\s+(\\d+)\\s})\n         else\n             xml = REXML::Document.new(entries)\n             revision = xml.elements['wc-entries'].elements[1].attributes['revision'].to_i\n           end\n         rescue\n           # Could not find the current revision\n         end\n     end\n     revision\n    end\n\n    REVISION = self.revision\n    ARRAY = [MAJOR, MINOR, TINY, BRANCH, REVISION].compact\n    STRING = ARRAY.join('.')\n\n    def self.to_a; ARRAY end\n    def self.to_s; STRING end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/views/my_page/block.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine\n  module Views\n    module MyPage\n      module Block\n        def self.additional_blocks\n          @@additional_blocks ||= Dir.glob(\"#{RAILS_ROOT}/vendor/plugins/*/app/views/my/blocks/_*.{rhtml,erb}\").inject({}) do |h,file|\n            name = File.basename(file).split('.').first.gsub(/^_/, '')\n            h[name] = name.to_sym\n            h\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/views/other_formats_builder.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine\n  module Views\n    class OtherFormatsBuilder\n      def initialize(view)\n        @view = view\n      end\n\n      def link_to(name, options={})\n        url = { :format => name.to_s.downcase }.merge(options.delete(:url) || {})\n        caption = options.delete(:caption) || name\n        html_options = { :class => name.to_s.downcase, :rel => 'nofollow' }.merge(options)\n        @view.content_tag('span', @view.link_to(caption, url, html_options))\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/wiki_formatting/macros.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine\n  module WikiFormatting\n    module Macros\n      module Definitions\n        def exec_macro(name, obj, args)\n          method_name = \"macro_#{name}\"\n          send(method_name, obj, args) if respond_to?(method_name)\n        end\n\n        def extract_macro_options(args, *keys)\n          options = {}\n          while args.last.to_s.strip =~ %r{^(.+)\\=(.+)$} && keys.include?($1.downcase.to_sym)\n            options[$1.downcase.to_sym] = $2\n            args.pop\n          end\n          return [args, options]\n        end\n      end\n\n      @@available_macros = {}\n\n      class << self\n        # Called with a block to define additional macros.\n        # Macro blocks accept 2 arguments:\n        # * obj: the object that is rendered\n        # * args: macro arguments\n        #\n        # Plugins can use this method to define new macros:\n        #\n        #   Redmine::WikiFormatting::Macros.register do\n        #     desc \"This is my macro\"\n        #     macro :my_macro do |obj, args|\n        #       \"My macro output\"\n        #     end\n        #   end\n        def register(&block)\n          class_eval(&block) if block_given?\n        end\n\n      private\n        # Defines a new macro with the given name and block.\n        def macro(name, &block)\n          name = name.to_sym if name.is_a?(String)\n          @@available_macros[name] = @@desc || ''\n          @@desc = nil\n          raise \"Can not create a macro without a block!\" unless block_given?\n          Definitions.send :define_method, \"macro_#{name}\".downcase, &block\n        end\n\n        # Sets description for the next macro to be defined\n        def desc(txt)\n          @@desc = txt\n        end\n      end\n\n      # Builtin macros\n      desc \"Sample macro.\"\n      macro :hello_world do |obj, args|\n        \"Hello world! Object: #{obj.class.name}, \" + (args.empty? ? \"Called with no argument.\" : \"Arguments: #{args.join(', ')}\")\n      end\n\n      desc \"Displays a list of all available macros, including description if available.\"\n      macro :macro_list do\n        out = ''\n        @@available_macros.keys.collect(&:to_s).sort.each do |macro|\n          out << content_tag('dt', content_tag('code', macro))\n          out << content_tag('dd', textilizable(@@available_macros[macro.to_sym]))\n        end\n        content_tag('dl', out)\n      end\n\n      desc \"Displays a list of child pages. With no argument, it displays the child pages of the current wiki page. Examples:\\n\\n\" +\n             \"  !{{child_pages}} -- can be used from a wiki page only\\n\" +\n             \"  !{{child_pages(Foo)}} -- lists all children of page Foo\\n\" +\n             \"  !{{child_pages(Foo, parent=1)}} -- same as above with a link to page Foo\"\n      macro :child_pages do |obj, args|\n        args, options = extract_macro_options(args, :parent)\n        page = nil\n        if args.size > 0\n          page = Wiki.find_page(args.first.to_s, :project => @project)\n        elsif obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)\n          page = obj.page\n        else\n          raise 'With no argument, this macro can be called from wiki pages only.'\n        end\n        raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project)\n        pages = ([page] + page.descendants).group_by(&:parent_id)\n        render_page_hierarchy(pages, options[:parent] ? page.parent_id : page.id)\n      end\n\n      desc \"Include a wiki page. Example:\\n\\n  !{{include(Foo)}}\\n\\nor to include a page of a specific project wiki:\\n\\n  !{{include(projectname:Foo)}}\"\n      macro :include do |obj, args|\n        page = Wiki.find_page(args.first.to_s, :project => @project)\n        raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project)\n        @included_wiki_pages ||= []\n        raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title)\n        @included_wiki_pages << page.title\n        out = textilizable(page.content, :text, :attachments => page.attachments)\n        @included_wiki_pages.pop\n        out\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/wiki_formatting/textile/formatter.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nrequire 'redcloth3'\nrequire 'coderay'\n\nmodule Redmine\n  module WikiFormatting\n    module Textile\n      class Formatter < RedCloth3\n\n        # auto_link rule after textile rules so that it doesn't break !image_url! tags\n        RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto, :inline_toc, :inline_macros]\n\n        def initialize(*args)\n          super\n          self.hard_breaks=true\n          self.no_span_caps=true\n          self.filter_styles=true\n        end\n\n        def to_html(*rules, &block)\n          @toc = []\n          @macros_runner = block\n          super(*RULES).to_s\n        end\n\n      private\n\n        # Patch for RedCloth.  Fixed in RedCloth r128 but _why hasn't released it yet.\n        # <a href=\"http://code.whytheluckystiff.net/redcloth/changeset/128\">http://code.whytheluckystiff.net/redcloth/changeset/128</a>\n        def hard_break( text )\n          text.gsub!( /(.)\\n(?!\\n|\\Z|>| *([#*=]+(\\s|$)|[{|]))/, \"\\\\1<br />\" ) if hard_breaks\n        end\n\n        # Patch to add code highlighting support to RedCloth\n        def smooth_offtags( text )\n          unless @pre_list.empty?\n            ## replace <pre> content\n            text.gsub!(/<redpre#(\\d+)>/) do\n              content = @pre_list[$1.to_i]\n              if content.match(/<code\\s+class=\"(\\w+)\">\\s?(.+)/m)\n                content = \"<code class=\\\"#{$1} CodeRay\\\">\" +\n                  CodeRay.scan($2, $1.downcase).html(:escape => false, :line_numbers => :inline)\n              end\n              content\n            end\n          end\n        end\n\n        # Patch to add 'table of content' support to RedCloth\n        def textile_p_withtoc(tag, atts, cite, content)\n          # removes wiki links from the item\n          toc_item = content.gsub(/(\\[\\[([^\\]\\|]*)(\\|([^\\]]*))?\\]\\])/) { $4 || $2 }\n          # removes styles\n          # eg. %{color:red}Triggers% => Triggers\n          toc_item.gsub! %r[%\\{[^\\}]*\\}([^%]+)%], '\\\\1'\n\n          # replaces non word caracters by dashes\n          anchor = toc_item.gsub(%r{[^\\w\\s\\-]}, '').gsub(%r{\\s+(\\-+\\s*)?}, '-')\n\n          unless anchor.blank?\n            if tag =~ /^h(\\d)$/\n              @toc << [$1.to_i, anchor, toc_item]\n            end\n            atts << \" id=\\\"#{anchor}\\\"\"\n            content = content + \"<a href=\\\"##{anchor}\\\" class=\\\"wiki-anchor\\\">&para;</a>\"\n          end\n          textile_p(tag, atts, cite, content)\n        end\n\n        alias :textile_h1 :textile_p_withtoc\n        alias :textile_h2 :textile_p_withtoc\n        alias :textile_h3 :textile_p_withtoc\n\n        def inline_toc(text)\n          text.gsub!(/<p>\\{\\{([<>]?)toc\\}\\}<\\/p>/i) do\n            div_class = 'toc'\n            div_class << ' right' if $1 == '>'\n            div_class << ' left' if $1 == '<'\n            out = \"<ul class=\\\"#{div_class}\\\">\"\n            @toc.each do |heading|\n              level, anchor, toc_item = heading\n              out << \"<li class=\\\"heading#{level}\\\"><a href=\\\"##{anchor}\\\">#{toc_item}</a></li>\\n\"\n            end\n            out << '</ul>'\n            out\n          end\n        end\n\n        MACROS_RE = /\n                      (!)?                        # escaping\n                      (\n                      \\{\\{                        # opening tag\n                      ([\\w]+)                     # macro name\n                      (\\(([^\\}]*)\\))?             # optional arguments\n                      \\}\\}                        # closing tag\n                      )\n                    /x unless const_defined?(:MACROS_RE)\n\n        def inline_macros(text)\n          text.gsub!(MACROS_RE) do\n            esc, all, macro = $1, $2, $3.downcase\n            args = ($5 || '').split(',').each(&:strip)\n            if esc.nil?\n              begin\n                @macros_runner.call(macro, args)\n              rescue => e\n                \"<div class=\\\"flash error\\\">Error executing the <strong>#{macro}</strong> macro (#{e})</div>\"\n              end || all\n            else\n              all\n            end\n          end\n        end\n\n        AUTO_LINK_RE = %r{\n                        (                          # leading text\n                          <\\w+.*?>|                # leading HTML tag, or\n                          [^=<>!:'\"/]|             # leading punctuation, or\n                          ^                        # beginning of line\n                        )\n                        (\n                          (?:https?://)|           # protocol spec, or\n                          (?:s?ftps?://)|\n                          (?:www\\.)                # www.*\n                        )\n                        (\n                          (\\S+?)                   # url\n                          (\\/)?                    # slash\n                        )\n                        ([^\\w\\=\\/;\\(\\)]*?)               # post\n                        (?=<|\\s|$)\n                       }x unless const_defined?(:AUTO_LINK_RE)\n\n        # Turns all urls into clickable links (code from Rails).\n        def inline_auto_link(text)\n          text.gsub!(AUTO_LINK_RE) do\n            all, leading, proto, url, post = $&, $1, $2, $3, $6\n            if leading =~ /<a\\s/i || leading =~ /![<>=]?/\n              # don't replace URL's that are already linked\n              # and URL's prefixed with ! !> !< != (textile images)\n              all\n            else\n              # Idea below : an URL with unbalanced parethesis and\n              # ending by ')' is put into external parenthesis\n              if ( url[-1]==?) and ((url.count(\"(\") - url.count(\")\")) < 0 ) )\n                url=url[0..-2] # discard closing parenth from url\n                post = \")\"+post # add closing parenth to post\n              end\n              %(#{leading}<a class=\"external\" href=\"#{proto==\"www.\"?\"http://www.\":proto}#{url}\">#{proto + url}</a>#{post})\n            end\n          end\n        end\n\n        # Turns all email addresses into clickable links (code from Rails).\n        def inline_auto_mailto(text)\n          text.gsub!(/([\\w\\.!#\\$%\\-+.]+@[A-Za-z0-9\\-]+(\\.[A-Za-z0-9\\-]+)+)/) do\n            mail = $1\n            if text.match(/<a\\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\\/a>/)\n              mail\n            else\n              %{<a href=\"mailto:#{mail}\" class=\"email\">#{mail}</a>}\n            end\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/wiki_formatting/textile/helper.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nmodule Redmine\n  module WikiFormatting\n    module Textile\n      module Helper\n\n        def initial_page_content(page)\n          \"h1. #{@page.pretty_title}\"\n        end\n\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine/wiki_formatting.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nmodule Redmine\n  module WikiFormatting\n    @@formatters = {}\n\n    class << self\n      def map\n        yield self\n      end\n\n      def register(name, formatter, helper)\n        raise ArgumentError, \"format name '#{name}' is already taken\" if @@formatters[name.to_sym]\n        @@formatters[name.to_sym] = {:formatter => formatter, :helper => helper}\n      end\n\n      def formatter_for(name)\n        entry = @@formatters[name.to_sym]\n        (entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter\n      end\n\n      def helper_for(name)\n        entry = @@formatters[name.to_sym]\n        (entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper\n      end\n\n      def format_names\n        @@formatters.keys.map\n      end\n\n      def to_html(format, text, options = {}, &block)\n        formatter_for(format).new(text).to_html(&block)\n      end\n    end\n\n    # Default formatter module\n    module NullFormatter\n      class Formatter\n        include ActionView::Helpers::TagHelper\n        include ActionView::Helpers::TextHelper\n        include ActionView::Helpers::UrlHelper\n\n        def initialize(text)\n          @text = text\n        end\n\n        def to_html(*args)\n          simple_format(auto_link(CGI::escapeHTML(@text)))\n        end\n      end\n\n      module Helper\n        def initial_page_content(page)\n          page.pretty_title.to_s\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/redmine.rb",
    "content": "require 'redmine/access_control'\nrequire 'redmine/menu_manager'\nrequire 'redmine/activity'\nrequire 'redmine/mime_type'\nrequire 'redmine/core_ext'\nrequire 'redmine/themes'\nrequire 'redmine/plugin'\nrequire 'redmine/wiki_formatting'\nrequire 'float' #todo: there's a more appropriate place for this\nrequire 'string'\nrequire 'mention'\n\nbegin\n  require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick)\nrescue LoadError\n  # RMagick is not available\nend\n\nif RUBY_VERSION < '1.9'\n  require 'faster_csv'\nelse\n  require 'csv'\n  FCSV = CSV\nend\n\nREDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar Git Filesystem )\n\n\n\n# Permissions\nRedmine::AccessControl.map do |map|\n  map.permission :view_project, {:projects => [:overview, :activity, :team, :shares, :map, :activity, :mypris, :community_members, :hourly_types, :all_tags]}, :public => true\n  map.permission :search_project, {:search => :index}, :public => true\n  map.permission :add_project, {:projects => [:add, :new, :copy]}, :require => :loggedin\n  map.permission :add_subprojects, {:projects => [:add, :new]}, :require => :loggedin\n  map.permission :edit_project, {:projects => [:settings, :edit, :copy, :archive, :unarchive, :destroy, :update_scale]}, :require => :member\n  map.permission :move_project, {:projects => [:move]}, :require => :member\n  map.permission :select_project_modules, {:projects => :modules}, :require => :member\n  map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member]}, :require => :member\n  map.permission :credits, {:credits => [:add, :edit, :update]}, :require => :admin\n  map.permission :send_invitations, {:invitations => [:new, :create, :resend, :index], :projects => [:reset_invitation_token]}, :require => :loggedin\n  map.permission :manage_invitations, {:invitations => [:index, :destroy, :resend, :update]}, :require => :loggedin\n  map.permission :transfer_credits, {:credit_transfers => [:index, :create]}, :require => :loggedin\n  map.permission :join_from_generic_invitation, {:projects => :join}, :require => :loggedin\n  map.project_module :issue_tracking do |map|\n    # Issues\n    map.permission :view_issues, {:projects => :roadmap,\n                                  :issues => [:index, :changes, :show, :context_menu, :datadump],\n                                  :queries => :index,\n                                  :reports => :issue_report,\n                                  :comments => :index,\n                                  :todos => :index,\n                                  :retros => [:index, :index_json, :dashdata, :show],\n                                  :projects => [:dashboard,:community_members, :dashdata, :new_dashdata]\n                                  }\n\n    map.permission :add_issues, {:issues => [:new, :update_form]}\n    map.permission :edit_issues, {:issues => [:edit, :reply, :bulk_edit, :update_form, :cancel, :restart, :prioritize, :agree, :disagree, :estimate, :join, :leave, :add_team_member, :remove_team_member, :update_tags]}\n    map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}\n    map.permission :add_issue_notes, {:issues => [:reply], :comments => :create, :todos => [:create,:update,:destroy]}\n    map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin\n    map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin\n    map.permission :move_issues, {:issues => :move}, :require => :loggedin\n    map.permission :delete_issues, {:issues => :destroy}, :require => :member\n    map.permission :push_commitment, {:issues => [:assign]} #Can send request for someone to comitt to a task\n    map.permission :pull_commitment, {:issues => [:assign]} #Can pull request. i.e. ask to be the person that the task is commited to.\n    map.permission :view_commit_requests, {:commit_requests => [:edit, :show]} #Can view ownereship requests\n    map.permission :view_member_roles, {:member_roles => [:show]} #Can view member roles\n    map.permission :estimate_issues, {:issues => :estimate}, :public => true #Can estimate issue\n    map.permission :accept_issues, {:issues => [:accept, :reject]}, :public => true #can accept or reject issues\n    map.permission :start_issues, {:issues => [:start,:finish,:release], :retro_ratings => :create} #can start issues\n    # Queries\n    map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member\n    map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin\n    # Gantt & calendar\n    map.permission :view_gantt, :issues => :gantt\n    map.permission :view_calendar, :issues => :calendar\n    # Watchers\n    map.permission :view_issue_watchers, {}\n    map.permission :add_issue_watchers, {:watchers => :new}\n    map.permission :delete_issue_watchers, {:watchers => :destroy}\n  end\n\n  map.project_module :documents do |map|\n    map.permission :manage_documents, {:documents => [:new, :edit, :destroy, :add_attachment]}, :require => :loggedin\n    map.permission :view_documents, :documents => [:index, :show, :download]\n    map.permission :manage_files, {:projects => :add_file}, :require => :loggedin\n    map.permission :view_files, :projects => :list_files\n  end\n\n  map.project_module :wiki do |map|\n    map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member\n    map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member\n    map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member\n    map.permission :view_wiki_pages, :wiki => [:index, :special]\n    map.permission :view_wiki_edits, :wiki => [:history, :diff, :annotate]\n    map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment]\n    map.permission :delete_wiki_pages_attachments, {}\n    map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member\n  end\n\n  map.project_module :boards do |map|\n    map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member\n    map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true\n    map.permission :add_messages, {:messages => [:new, :reply, :quote]}\n    map.permission :edit_messages, {:messages => :edit}, :require => :member\n    map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin\n    map.permission :delete_messages, {:messages => :destroy}, :require => :member\n    map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin\n  end\n\n  map.project_module :motions do |map|\n    map.permission :manage_motion, {:motions => [:edit, :destroy]}, :require => :admin\n    map.permission :browse_motion, {:motions => [:index, :view, :show]}, :require => :loggedin\n    map.permission :create_motion, {:motions => [:create, :new, :eligible_users]}, :require => :loggedin\n    map.permission :vote_motion, {:motions => :reply, :motion_vote => :create}, :require => :loggedin\n  end\n\n  map.project_module :news do |map|\n    map.permission :manage_news, {:news => [:new, :edit, :destroy, :destroy_comment]}, :require => :member\n    map.permission :view_news, {:news => [:index, :show]}, :public => true\n    map.permission :comment_news, {:news => :add_comment}\n  end\n\n  map.project_module :credits do |map|\n    map.permission :view_credits, {:projects => :credits, :credits => [:index,:show]}, :require => :loggedin\n    map.permission :enable_disable_credits, {:credits => [:enable, :disable]}, :require => :loggedin\n    map.permission :add_credits, {:credits => [:new, :create]}, :require => :loggedin\n    map.permission :manage_credits, {:credits => [:destroy, :edit, :update]}, :require => :loggedin\n  end\n\nend\n\nRedmine::MenuManager.map :application_menu do |menu|\n  # Empty\nend\n\nRedmine::MenuManager.map :admin_menu do |menu|\n  # Empty\nend\n\nRedmine::MenuManager.map :project_menu do |menu|\n  menu.push :overview, { :controller => 'projects', :action => 'overview' }\n  menu.push :dashboard, { :controller => 'projects', :action => 'dashboard' }, :caption => :label_dashboard\n  menu.push :team, { :controller => 'projects', :action => 'team' },\n      :if => Proc.new { |p| p.root? }\n  menu.push :credits, { :controller => 'projects', :action => 'credits' },\n      :if => Proc.new { |p| p.credits_enabled? }\n  menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id, :caption => :label_boards\n  menu.push :wiki, { :controller => 'wiki', :action => 'index', :page => nil }\n  menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural\n  menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural\n  menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true\nend\n\nRedmine::Activity.map do |activity|\n  activity.register :issues, :class_name => %w(Issue Journal)\n  activity.register :news\n  activity.register :documents, :class_name => %w(Document Attachment)\n  activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => true\n  activity.register :messages, :default => true\nend\n\nRedmine::WikiFormatting.map do |format|\n  format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper\nend\n"
  },
  {
    "path": "lib/string.rb",
    "content": "require 'rexml/parsers/pullparser'\n\nclass String\n  def truncate_html(len = 30)\n    begin\n      p = REXML::Parsers::PullParser.new(self)\n      tags = []\n      new_len = len\n      results = ''\n      while p.has_next? && new_len > 0\n        p_e = p.pull\n        case p_e.event_type\n        when :start_element\n          tags.push p_e[0]\n          results << \"<#{tags.last} #{attrs_to_s(p_e[1])}>\"\n        when :end_element\n          results << \"</#{tags.pop}>\"\n        when :text\n          results << p_e[0].first(new_len)\n          new_len -= p_e[0].length\n        else\n          results << \"<!-- #{p_e.inspect} -->\"\n        end\n      end\n      tags.reverse.each do |tag|\n        results << \"</#{tag}>\"\n      end\n      results\n    rescue\n      self\n    end\n  end\n\n  private\n\n  def attrs_to_s(attrs)\n    if attrs.empty?\n      ''\n    else\n      attrs.to_a.map { |attr| %{#{attr[0]}=\"#{attr[1]}\"} }.join(' ')\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tabular_form_builder.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nrequire 'action_view/helpers/form_helper'\n\nclass TabularFormBuilder < ActionView::Helpers::FormBuilder\n  include Redmine::I18n\n\n  def initialize(object_name, object, template, options, proc)\n    set_language_if_valid options.delete(:lang)\n    super\n  end\n\n  (field_helpers - %w(radio_button hidden_field) + %w(date_select)).each do |selector|\n    src = <<-END_SRC\n    def #{selector}(field, options = {})\n      label_for_field(field, options) + super\n    end\n    END_SRC\n    class_eval src, __FILE__, __LINE__\n  end\n\n  def select(field, choices, options = {}, html_options = {})\n    label_for_field(field, options) + super\n  end\n\n  # Returns a label tag for the given field\n  def label_for_field(field, options = {})\n      return '' if options.delete(:no_label)\n      text = options[:label].is_a?(Symbol) ? l(options[:label]) : options[:label]\n      text ||= l((\"field_\" + field.to_s.gsub(/\\_id$/, \"\")).to_sym)\n      text += @template.content_tag(\"span\", \" *\", :class => \"required\") if options.delete(:required)\n      @template.content_tag(\"label\", text,\n                                     :class => (@object && @object.errors[field] ? \"error\" : nil),\n                                     :for => (@object_name.to_s + \"_\" + field.to_s))\n  end\nend\n"
  },
  {
    "path": "lib/tasks/autoaccept_commitrequests.rake",
    "content": "# Auto accepts commitment requests that haven't been responded to\n\nMINIMUM_INCREMENT = 2 #Minimum size of time increment (in days) that can go buy before the system auto-accepts a request\nSECONDS_PER_DAY = 86400\n\ndef helpers\n  ActionController::Base.helpers\nend\n\n\ndesc \"Auto accepts commitment requests that haven't been responded to\"\ntask :autoaccept_commitrequests => :environment do\n  admin = User.find(:first,:conditions => {:login => \"admin\"})\n\n  CommitRequest.find(:all, :conditions => 'response = 0 AND responder_id is null AND days > -1').each do |cr|\n    non_response_time = (Time.now - cr.created_at) / SECONDS_PER_DAY\n    next if non_response_time < MINIMUM_INCREMENT\n    if non_response_time > cr.days\n      puts \"Auto accepting: #{cr.id}  for issue #{cr.issue.subject}\"\n\n      cr.response = 2\n      cr.responder_id = admin.id\n      cr.save\n\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tasks/backup.rake",
    "content": "\n\n# Heroku S3 Database backup task\n# by Nick Merwin (Lemur Heavy Industries) 10.08.09\n# * dumps db to yaml, gzip's and sends to S3\n#\n# Setup:\n# 1) replace APP_NAME and BACKUP_BUCKET with your info\n# 2) add config/s3.yml like so (same as Paperclip's):\n# production:\n# access_key_id: ...\n# secret_access_key: ...\n# 2) install the yaml_db plugin:\n# script/plugin install git://github.com/adamwiggins/yaml_db.git\n# 3) add aws-s3 to your .gems\n#\n# Usage:\n# heroku rake backup\n# rake backup remote=true # this will pull the db locally first\n# * or add this to your cron.rake for hourly or nightly backups:\n# Rake::Task['backup'].invoke\nrequire 'aws/s3'\n\ndesc \"backup db from heroku and send to S3\"\ntask :backup => :environment do\n\n  APP_NAME = 'bettermeans' # put your app name here\n  BACKUP_BUCKET = 'heroku-db-bckps-bm' # put your backup bucket name here\n\n  puts \"Back up started @ #{Time.now}\"\n\n  puts \"Pulling DB...\"\n\n  backup_name = \"ew#{Time.now.to_i}.db\"\n  backup_path = \"tmp/#{backup_name}\"\n\n  if ENV['remote'] == 'true'\n    puts `heroku db:pull sqlite://#{backup_path} --app #{APP_NAME}`\n  else\n    YamlDb.dump backup_path\n  end\n\n  puts \"gzipping db...\"\n  `gzip #{backup_path}`\n\n  backup_name += \".gz\"\n  backup_path = \"tmp/#{backup_name}\"\n\n  puts \"Uploading #{backup_name} to S3...\"\n\n  yaml_string = ERB.new(File.read(\"#{RAILS_ROOT}/config/s3.yml\")).result\n  options = YAML.load(yaml_string)\n\n  puts \"yaml string #{yaml_string}\"\n  puts \"access key #{options[Rails.env]['access_key_id']}\"\n  puts \"secret key #{options[Rails.env]['secret_access_key']}\"\n\n  AWS::S3::Base.establish_connection!(\n      :access_key_id => options[Rails.env]['access_key_id'],\n      :secret_access_key => options[Rails.env]['secret_access_key']\n    )\n\n  begin\n    bucket = AWS::S3::Bucket.find BACKUP_BUCKET\n  rescue AWS::S3::NoSuchBucket\n    AWS::S3::Bucket.create BACKUP_BUCKET\n    bucket = AWS::S3::Bucket.find BACKUP_BUCKET\n  end\n\n  AWS::S3::S3Object.store backup_name, File.read(backup_path), bucket.name, :content_type => 'application/x-gzip'\n\n  puts \"Done @ #{Time.now}\"\nend\n\nnamespace :heroku do\n  desc \"PostgreSQL database backups from Heroku to Amazon S3\"\n  task :daily_backup => :environment do\n    begin\n      require 'right_aws'\n      puts \"[#{Time.now}] heroku:backup started\"\n      name = \"#{ENV['APP_NAME']}-#{Time.now.strftime('%Y-%m-%d-%H%M%S')}.dump\"\n      db = ENV['DATABASE_URL'].match(/postgres:\\/\\/([^:]+):([^@]+)@([^\\/]+)\\/(.+)/)\n      system \"PGPASSWORD=#{db[2]} pg_dump -Fc --username=#{db[1]} --host=#{db[3]} #{db[4]} > tmp/#{name}\"\n      s3 = RightAws::S3.new(ENV['s3_access_key_id'], ENV['s3_secret_access_key'])\n      bucket = s3.bucket(\"#{ENV['APP_NAME']}-heroku-backups\", true, 'private')\n      bucket.put(name, open(\"tmp/#{name}\"))\n      system \"rm tmp/#{name}\"\n      puts \"[#{Time.now}] heroku:backup complete\"\n    end\n  end\nend\n\n"
  },
  {
    "path": "lib/tasks/bootstrap.rake",
    "content": "task :bootstrap => :environment do\n\n  puts \"Creating db...\"\n  Rake::Task['db:create'].invoke\n\n  puts \"Loading schema...\"\n  Rake::Task['db:schema:load'].invoke\n\n  puts \"Seeding...\"\n  Rake::Task['db:seed'].invoke\n\n  puts \"Creating admin\"\n  user = User.new :firstname => \"Redmine\",:lastname => \"Admin\",:mail => \"admin@example.net\",:mail_notification => true,:language => \"en\",:status => 1\n  user.admin = true\n  user.hashed_password = \"5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8\" #admin password is 'password'\n  user.login = \"admin\"\n  user.save\nend\n"
  },
  {
    "path": "lib/tasks/cleanup.rake",
    "content": "desc 'Remove trailing whitespace and add newlines at end of files'\ntask :cleanup do\n\n  filetypes = %w(\n    builder\n    conf\n    css\n    erb\n    Gemfile\n    haml\n    html\n    json\n    rake\n    rb\n    rhtml\n    rjs\n    rxml\n    scss\n    js\n    txt\n    xml\n    yaml\n    yml\n  )\n\n  paths = %w(\n    app\n    config\n    curriculum/source\n    db/migrate\n    Gemfile\n    lib\n    modules\n    public\n    test\n    spec\n  )\n\n  filetype_regexp = /\\.(#{filetypes.join('|')})$/\n  paths_regexp = /^(\\.\\/)?(#{paths.join('|')})/\n\n  files = `find .`\n  files.lines.each do |f|\n\n    # Only examine specified file types and paths\n    if f =~ filetype_regexp && f =~ paths_regexp\n\n      # Add a linebreak to the end of the file if it doesn't have one\n      if `tail -c1 #{f}` != \"\\n\"\n        puts \"adding line break to #{f}\"\n        `echo >> #{f}`\n      end\n\n      # Remove trailing whitespace if it exists\n      if system(\"grep -q '[[:blank:]]$' #{f}\")\n        puts \"removing trailing spaces from #{f}\"\n        # sed command works differently on Mac and Linux\n        if `uname` =~ /Darwin/\n          `sed -i \"\" -e $'s/[ \\t]*$//g' #{f}`\n        elsif `uname` =~ /Linux/\n          `sed -i -e 's/[ \\t]*$//g' #{f}`\n        end\n      end\n\n      # sed command works differently on Mac and Linux\n      if `uname` =~ /Darwin/\n        `sed -i \"\" -e $'s/\\t/  /g' #{f}`\n      elsif `uname` =~ /Linux/\n        `sed -i -e 's/\\t/  /g' #{f}`\n      end\n    end\n  end\n\nend\n"
  },
  {
    "path": "lib/tasks/close_retros.rake",
    "content": "# Closes retrospectives that are open\n\ndef helpers\n  ActionController::Base.helpers\nend\n\ndesc \"Closes retrospectives that are open\"\ntask :close_retros => :environment do\n  puts \"Closing retros...\"\n  Retro.find(:all, :conditions => {:status_id => Retro::STATUS_INPROGRESS}).each do |retro|\n    if ((Time.now.advance(:days => Setting::DEFAULT_RETROSPECTIVE_LENGTH * -1)  > retro.created_at) || retro.all_in?)\n      retro.close\n      retro.distribute_credits\n    end\n  end\nend\n\ndesc \"Start retrospectives that are ready to be started\"\ntask :start_retros => :environment do\n  Project.all.each do |project|\n    project.start_retro_if_ready\n  end\nend\n\n"
  },
  {
    "path": "lib/tasks/cron.rake",
    "content": "task :cron => :environment do\n    puts \"Running cron...\"\n    Rake::Task['backup'].invoke\n    Rake::Task['close_retros'].invoke\n    Rake::Task['custom:refresh_active_members'].invoke\n    Rake::Task['custom:lazy_majority'].invoke\n    Rake::Task['custom:close_motions'].invoke\n    Rake::Task['custom:refresh_activity_timelines'].invoke\n\n    if Time.now.hour == 18\n      Rake::Task['custom:deliver_daily_digest'].invoke\n    end\n\n    if Time.now.hour == 0\n\n      Rake::Task['heroku:daily_backup'].invoke\n      Rake::Task['start_retros'].invoke\n      Rake::Task['custom:calculate_reputation'].invoke\n      Rake::Task['custom:calculate_project_storage'].invoke\n      Rake::Task['custom:detect_users_over_limit'].invoke\n      Rake::Task['custom:detect_trial_expiration'].invoke\n      Rake::Task['custom:refresh_project_issue_counts'].invoke\n\n    end\n    puts \"done.\"\nend\n"
  },
  {
    "path": "lib/tasks/cucumber.rake",
    "content": "# This file was generated by\n$LOAD_PATH.unshift(RAILS_ROOT + '/vendor/plugins/cucumber/lib') if File.directory?(RAILS_ROOT + '/vendor/plugins/cucumber/lib')\n\nunless ARGV.any? {|a| a =~ /^gems/}\n\nbegin\n  require 'cucumber/rake/task'\n\n\n  # Use vendored cucumber binary if possible. If it's not vendored,\n  # Cucumber::Rake::Task will automatically use installed gem's cucumber binary\n  vendored_cucumber_binary = Dir[\"#{RAILS_ROOT}/vendor/{gems,plugins}/cucumber*/bin/cucumber\"].first\n\n  namespace :cucumber do\n    Cucumber::Rake::Task.new({:ok => 'custom:load_test_data'}, 'Run features that should pass') do |t|\n      t.binary = vendored_cucumber_binary\n      t.fork = true # You may get faster startup if you set this to false\n      t.cucumber_opts = \"--color --tags ~@wip --strict --format #{ENV['CUCUMBER_FORMAT'] || 'pretty'}\"\n    end\n\n    Cucumber::Rake::Task.new({:wip => 'custom:load_test_data'}, 'Run features that are being worked on') do |t|\n      t.binary = vendored_cucumber_binary\n      t.fork = true # You may get faster startup if you set this to false\n      t.cucumber_opts = \"--color --tags @wip:2 --wip --format #{ENV['CUCUMBER_FORMAT'] || 'pretty'}\"\n    end\n\n    desc 'Run all features'\n    task :all => [:ok, :wip]\n  end\n  desc 'Alias for cucumber:ok'\n  task :cucumber => 'cucumber:ok'\n\n  task :default => :cucumber\n\n  task :features => :cucumber do\n    STDERR.puts \"*** The 'features' task is deprecated. See rake -T cucumber ***\"\n  end\nrescue LoadError\n  desc 'cucumber rake task not available (cucumber not installed)'\n  task :cucumber do\n    abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'\n  end\nend\n\nend\n"
  },
  {
    "path": "lib/tasks/custom.rake",
    "content": "namespace :custom do\n  task :load_test_data => :environment do\n    system 'rake db:test:prepare'\n    system 'rake environment RAILS_ENV=test redmine:load_default_data'\n  end\n\n  task :refresh_active_members => :environment do\n    Project.all.each do |project|\n      puts \"Refreshing #{project.id}: #{project.name}\"\n      project.refresh_active_members\n    end\n\n  end\n\n# Rejects/accepts lazy majority items that haven't had any activity for a certain number of days (LAZY_MAJORITY_NO_ACTIVITY_LENGTH)\n  task :lazy_majority => :environment do\n    Issue.all(:conditions => [ \"status_id = ? AND updated_at < ?\", IssueStatus.newstatus.id,DateTime.now - Setting::LAZY_MAJORITY_NO_ACTIVITY_LENGTH ]).each do |issue|\n      issue.update_status\n    end\n\n    Issue.all(:conditions => [ \"status_id = ? AND updated_at < ?\", IssueStatus.estimate.id,DateTime.now - Setting::LAZY_MAJORITY_NO_ACTIVITY_LENGTH ]).each do |issue|\n      issue.update_status\n    end\n\n    Issue.all(:conditions => [ \"status_id = ? AND updated_at < ?\", IssueStatus.done.id,DateTime.now - Setting::LAZY_MAJORITY_NO_ACTIVITY_LENGTH ]).each do |issue|\n      issue.update_status\n    end\n  end\n\n  #sanity checks all project issue counts\n  task :refresh_project_issue_counts => :environment do\n    Project.all.each do |p|\n      p.refresh_issue_count\n    end\n  end\n\n\n\n# loops through active motions and makes a decision on them\n  task :close_motions => :environment do\n    Motion.allactive.each do |motion|\n      motion.close\n    end\n  end\n\n  task :calculate_reputation => :environment do\n    Reputation.calculate_all\n  end\n\n  task :refresh_activity_timelines => :environment do\n    Project.all_roots.each {|p| p.refresh_activity_line}\n  end\n\n  #one time fix for credits tables, and makes sure all projects have credit module enabled\n  task :run_once_fix_credit_distros => :environment do\n    CreditDistribution.all.each do |cd|\n      credit = Credit.find(:first, :conditions => {:owner_id => cd.user_id, :amount => cd.amount})\n      credit.project_id = cd.project_id\n      credit.save\n    end\n\n    Project.all.each do |p|\n      p.enabled_modules << EnabledModule.create(:name => \"credits\")\n    end\n  end\n\n  #maps all users to recurly users\n  task :create_recurly_users => :environment do\n    User.all.each do |user|\n      User.create_recurly_account(user.id)\n    end\n  end\n\n  task :calculate_project_storage => :environment do\n    Project.all.each do |p| p.calculate_storage end\n  end\n\n  task :add_daily_digest_option_to_users => :environment do\n    User.all.each do |user|\n      user.pref.others.merge!({:daily_digest => true})\n      user.pref.save\n    end\n  end\n\n  task :deliver_daily_digest => :environment do\n    DailyDigest.deliver\n  end\n\n  task :deliver_personal_welcome => :environment do\n    PersonalWelcome.deliver\n  end\n\n  #temporary task to re-assign admins that have been lost\n  task :run_once_fix_owners => :environment do\n    Project.all.each do |p|\n      next unless p.administrators == [] && p.root?\n      p.owner.add_to_project(p, Role.administrator)\n      p.owner.add_to_project(p, Role.core_member)\n\n      p.all_members.each do |ms|\n        if ms.created_at > Time.now.advance(:minutes => -2)\n          ms.created_at = p.created_at\n          ms.save\n        end\n\n        ms.member_roles.each do |mr|\n          if mr.created_at > Time.now.advance(:minutes => -2)\n            mr.created_at = p.created_at\n            mr.save\n          end\n        end\n      end\n\n      puts \"fixed #{p.id} #{p.name}\"\n    end\n  end\n\n  #one time fix to add members again, after they've been lost\n  task :run_once_rerun_membership_motions => :environment do\n    Motion.find(:all, :conditions => [\"created_at > ?\", Time.parse('10/1/2010')], :order => \"created_at ASC\").each do |m|\n      m.execute_action\n    end\n  end\n\n\n  #fixing the dropped member roles by re-adding all accepted invitations\n  task :run_once_fix_invitations => :environment do\n    Invitation.all.each do |i|\n      next if i.status == 0\n      unless i.user.enterprise_member_of?(i.project)\n        puts \"Adding #{i.user.name} #{i.user.id} to project #{i.project.name} #{i.project.id} as #{i.role.name}\"\n        i.user.add_to_project(i.project,i.role)\n      end\n    end\n  end\n\n\n  #Used to trim a production database for development\n  task :trim_db => :environment do\n    if ENV['reset_safe'] == 'true'\n      puts \"Trimming database\"\n\n      @p = Project.find(20) #bettermeans\n      @p.name = \"LOCAL BETTERMEANS\" #changing title so there's not confusion when working with local db\n      @p.save\n\n      puts \"Deleting private projects\"\n      Project.all.each do |p|\n        next if p.is_public?\n        puts \"Deleting project #{p.id} #{p.name}\"\n        p.destroy\n        puts \"done.\"\n      end\n\n      puts \"Changing passwords to 'password' \"\n      User.update_all(:hashed_password => \"5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8\")\n\n      puts \"Changing emails\"\n      User.all.each do |user|\n        user.mail = \"#{(0...20).map{65.+(rand(25)).chr}.join}@bogus.com\"\n        user.save\n      end\n\n      puts \"done.\"\n    else\n      puts \"wont reset. we're not in development\"\n      puts \"to allow reset use: export reset_safe=true\"\n    end\n\n  end\n\n  #detecting users that are overusing their plans and need to upgrade\n  task :detect_users_over_limit => :environment do\n    User.active.each do |u|\n      u.update_usage_over\n    end\n  end\n\n  #detecting users whose trials have expired and need to pay\n  task :detect_trial_expiration => :environment do\n    User.active.each do |u|\n      u.update_trial_expiration\n    end\n  end\n\n  #moving from features to tags\n  task :run_once_features_to_task => :environment do\n    Issue.all.each do |i|\n      begin\n      tag = i.tracker.name.downcase\n      unless tag == \"feature\"\n        puts(\"Upgrading issue #{i.id}  #{tag}\")\n        i.update_attribute(:tag_list,i.tag_list.add(tag))\n      end\n      i.update_attribute(:tags_copy, i.tags.join(\",\"))\n      rescue\n        puts(\"FAILED TO UPGRADE issue #{i.id}\")\n      end\n    end\n  end\n\n  #moving from features to tags\n  task :run_once_fix_retros => :environment do\n    Retro.all.each do |r|\n      if r.status_id == 3 && r.total_points > 0\n        dist = CreditDistribution.find_by_retro_id(r.id)\n        unless dist\n          puts(\"retro #{r.id} for #{r.project.name}\")\n          r.update_attribute(:status_id, 2)\n          r.distribute_credits\n        end\n      end\n    end\n  end\n\nend\n"
  },
  {
    "path": "lib/tasks/deprecated.rake",
    "content": "def deprecated_task(name, new_name)\n  task name=>new_name do\n    $stderr.puts \"\\nNote: The rake task #{name} has been deprecated, please use the replacement version #{new_name}\"\n  end\nend\n\ndeprecated_task :load_default_data, \"redmine:load_default_data\"\ndeprecated_task :migrate_from_mantis, \"redmine:migrate_from_mantis\"\ndeprecated_task :migrate_from_trac, \"redmine:migrate_from_trac\"\n"
  },
  {
    "path": "lib/tasks/email.rake",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nnamespace :redmine do\n  namespace :email do\n\n    desc <<-END_DESC\nRead an email from standard input.\n\nGeneral options:\n  unknown_user=ACTION      how to handle emails from an unknown user\n                           ACTION can be one of the following values:\n                           ignore: email is ignored (default)\n                           accept: accept as anonymous user\n                           create: create a user account\n  no_permission_check=1    disable permission checking when receiving\n                           the email\n\nIssue attributes control options:\n  project=PROJECT          identifier of the target project\n  status=STATUS            name of the target status\n  tracker=TRACKER          name of the target tracker\n  category=CATEGORY        name of the target category\n  priority=PRIORITY        name of the target priority\n  allow_override=ATTRS     allow email content to override attributes\n                           specified by previous options\n                           ATTRS is a comma separated list of attributes\n\nExamples:\n  # No project specified. Emails MUST contain the 'Project' keyword:\n  rake redmine:email:read RAILS_ENV=\"production\" < raw_email\n\n  # Fixed project and default tracker specified, but emails can override\n  # both tracker and priority attributes:\n  rake redmine:email:read RAILS_ENV=\"production\" \\\\\n                  project=foo \\\\\n                  tracker=bug \\\\\n                  allow_override=tracker,priority < raw_email\nEND_DESC\n\n    task :read => :environment do\n      options = { :issue => {} }\n      %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] }\n      options[:allow_override] = ENV['allow_override'] if ENV['allow_override']\n      options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user']\n      options[:no_permission_check] = ENV['no_permission_check'] if ENV['no_permission_check']\n\n      MailHandler.receive(STDIN.read, options)\n    end\n\n    desc <<-END_DESC\nRead emails from an IMAP server.\n\nGeneral options:\n  unknown_user=ACTION      how to handle emails from an unknown user\n                           ACTION can be one of the following values:\n                           ignore: email is ignored (default)\n                           accept: accept as anonymous user\n                           create: create a user account\n  no_permission_check=1    disable permission checking when receiving\n                           the email\n\nAvailable IMAP options:\n  host=HOST                IMAP server host (default: 127.0.0.1)\n  port=PORT                IMAP server port (default: 143)\n  ssl=SSL                  Use SSL? (default: false)\n  username=USERNAME        IMAP account\n  password=PASSWORD        IMAP password\n  folder=FOLDER            IMAP folder to read (default: INBOX)\n\nIssue attributes control options:\n  project=PROJECT          identifier of the target project\n  status=STATUS            name of the target status\n  tracker=TRACKER          name of the target tracker\n  category=CATEGORY        name of the target category\n  priority=PRIORITY        name of the target priority\n  allow_override=ATTRS     allow email content to override attributes\n                           specified by previous options\n                           ATTRS is a comma separated list of attributes\n\nProcessed emails control options:\n  move_on_success=MAILBOX  move emails that were successfully received\n                           to MAILBOX instead of deleting them\n  move_on_failure=MAILBOX  move emails that were ignored to MAILBOX\n\nExamples:\n  # No project specified. Emails MUST contain the 'Project' keyword:\n\n  rake redmine:email:receive_iamp RAILS_ENV=\"production\" \\\\\n    host=imap.foo.bar username=redmine@example.net password=xxx\n\n\n  # Fixed project and default tracker specified, but emails can override\n  # both tracker and priority attributes:\n\n  rake redmine:email:receive_iamp RAILS_ENV=\"production\" \\\\\n    host=imap.foo.bar username=redmine@example.net password=xxx ssl=1 \\\\\n    project=foo \\\\\n    tracker=bug \\\\\n    allow_override=tracker,priority\nEND_DESC\n\n    task :receive_imap => :environment do\n      imap_options = {:host => ENV['host'],\n                      :port => ENV['port'],\n                      :ssl => ENV['ssl'],\n                      :username => ENV['username'],\n                      :password => ENV['password'],\n                      :folder => ENV['folder'],\n                      :move_on_success => ENV['move_on_success'],\n                      :move_on_failure => ENV['move_on_failure']}\n\n      options = { :issue => {} }\n      %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] }\n      options[:allow_override] = ENV['allow_override'] if ENV['allow_override']\n      options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user']\n      options[:no_permission_check] = ENV['no_permission_check'] if ENV['no_permission_check']\n\n      Redmine::IMAP.check(imap_options, options)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tasks/extract_fixtures.rake",
    "content": "desc 'Create YAML test fixtures from data in an existing database.\nDefaults to development database. Set RAILS_ENV to override.'\n\ntask :extract_fixtures => :environment do\n  sql = \"SELECT * FROM %s\"\n  skip_tables = [\"schema_info\"]\n  ActiveRecord::Base.establish_connection\n  (ActiveRecord::Base.connection.tables - skip_tables).each do |table_name|\n    i = \"000\"\n    File.open(\"#{RAILS_ROOT}/#{table_name}.yml\", 'w' ) do |file|\n      data = ActiveRecord::Base.connection.select_all(sql % table_name)\n      file.write data.inject({}) { |hash, record|\n\n      # cast extracted values\n      ActiveRecord::Base.connection.columns(table_name).each { |col|\n        record[col.name] = col.type_cast(record[col.name]) if record[col.name]\n      }\n\n      hash[\"#{table_name}_#{i.succ!}\"] = record\n      hash\n      }.to_yaml\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tasks/fetch_changesets.rake",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\ndesc 'Fetch changesets from the repositories'\n\nnamespace :redmine do\n  task :fetch_changesets => :environment do\n    Repository.fetch_changesets\n  end\nend\n"
  },
  {
    "path": "lib/tasks/initializers.rake",
    "content": "desc 'Generates a configuration file for cookie store sessions.'\n\nfile 'config/initializers/session_store.rb' do\n  path = File.join(RAILS_ROOT, 'config', 'initializers', 'session_store.rb')\n  secret = ActiveSupport::SecureRandom.hex(40)\n  File.open(path, 'w') do |f|\n    f.write <<\"EOF\"\n# This file was generated by 'rake config/initializers/session_store.rb',\n# and should not be made visible to public.\n# If you have a load-balancing Redmine cluster, you will need to use the\n# same version of this file on each machine. And be sure to restart your\n# server when you modify this file.\n\n# Your secret key for verifying cookie session data integrity. If you\n# change this key, all old sessions will become invalid! Make sure the\n# secret is at least 30 characters and all random, no regular words or\n# you'll be exposed to dictionary attacks.\nActionController::Base.session = {\n  :session_key => '_redmine_session',\n  :secret => '#{secret}'\n}\nEOF\n  end\nend\n"
  },
  {
    "path": "lib/tasks/load_default_data.rake",
    "content": "desc 'Load Redmine default configuration data. Language is chosen interactively or by setting REDMINE_LANG environment variable.'\n\nnamespace :redmine do\n  task :load_default_data => :environment do\n    include Redmine::I18n\n    envlang = 'en'\n\n    if !envlang || !set_language_if_valid(envlang)\n      puts\n      while true\n        print \"Select language: \"\n        print valid_languages.collect(&:to_s).sort.join(\", \")\n        print \" [#{current_language}] \"\n        STDOUT.flush\n        lang = STDIN.gets.chomp!\n        break if lang.empty?\n        break if set_language_if_valid(lang)\n        puts \"Unknown language!\"\n      end\n      STDOUT.flush\n      puts \"====================================\"\n    end\n\n    begin\n      Redmine::DefaultData::Loader.load(current_language)\n      puts \"Default configuration data loaded.\"\n    rescue Redmine::DefaultData::DataAlreadyLoaded => error\n      puts error\n    rescue => error\n      puts \"Error: \" + error\n      puts \"Default configuration data was not loaded.\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tasks/locales.rake",
    "content": "namespace :locales do\n  desc 'Updates language files based on en.yml content (only works for new top level keys).'\n  task :update do\n    dir = ENV['DIR'] || './config/locales'\n\n    en_strings = YAML.load(File.read(File.join(dir,'en.yml')))['en']\n\n    files = Dir.glob(File.join(dir,'*.{yaml,yml}'))\n    files.each do |file|\n      puts \"Updating file #{file}\"\n      file_strings = YAML.load(File.read(file))\n      file_strings = file_strings[file_strings.keys.first]\n\n      missing_keys = en_strings.keys - file_strings.keys\n      next if missing_keys.empty?\n\n      puts \"==> Missing #{missing_keys.size} keys (#{missing_keys.join(', ')})\"\n      lang = File.open(file, 'a')\n\n      missing_keys.each do |key|\n        {key => en_strings[key]}.to_yaml.each_line do |line|\n          next if line =~ /^---/ || line.empty?\n          puts \"  #{line}\"\n          lang << \"  #{line}\"\n        end\n      end\n\n      lang.close\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tasks/metrics.rake",
    "content": "begin\n  require 'metric_fu'\nrescue LoadError\n  # Metric-fu not installed\n  # http://metric-fu.rubyforge.org/\nend\n"
  },
  {
    "path": "lib/tasks/migrate_from_mantis.rake",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\ndesc 'Mantis migration script'\n\nrequire 'active_record'\nrequire 'iconv'\nrequire 'pp'\n\nnamespace :redmine do\ntask :migrate_from_mantis => :environment do\n\n  module MantisMigrate\n\n      DEFAULT_STATUS = IssueStatus.default\n      assigned_status = IssueStatus.find_by_position(2)\n      resolved_status = IssueStatus.find_by_position(3)\n      feedback_status = IssueStatus.find_by_position(4)\n      closed_status = IssueStatus.find :first, :conditions => { :is_closed => true }\n      STATUS_MAPPING = {10 => DEFAULT_STATUS,  # new\n                        20 => feedback_status, # feedback\n                        30 => DEFAULT_STATUS,  # acknowledged\n                        40 => DEFAULT_STATUS,  # confirmed\n                        50 => assigned_status, # assigned\n                        80 => resolved_status, # resolved\n                        90 => closed_status    # closed\n                        }\n\n      priorities = Enumeration.priorities\n      DEFAULT_PRIORITY = priorities[2]\n      PRIORITY_MAPPING = {10 => priorities[1], # none\n                          20 => priorities[1], # low\n                          30 => priorities[2], # normal\n                          40 => priorities[3], # high\n                          50 => priorities[4], # urgent\n                          60 => priorities[5]  # immediate\n                          }\n\n      TRACKER_BUG = Tracker.find_by_position(1)\n      TRACKER_FEATURE = Tracker.find_by_position(2)\n\n      roles = Role.find(:all, :conditions => {:builtin => 0}, :order => 'position ASC')\n      manager_role = roles[0]\n      developer_role = roles[1]\n      DEFAULT_ROLE = roles.last\n      ROLE_MAPPING = {10 => DEFAULT_ROLE,   # viewer\n                      25 => DEFAULT_ROLE,   # reporter\n                      40 => DEFAULT_ROLE,   # updater\n                      55 => developer_role, # developer\n                      70 => manager_role,   # manager\n                      90 => manager_role    # administrator\n                      }\n\n      CUSTOM_FIELD_TYPE_MAPPING = {0 => 'string', # String\n                                   1 => 'int',    # Numeric\n                                   2 => 'int',    # Float\n                                   3 => 'list',   # Enumeration\n                                   4 => 'string', # Email\n                                   5 => 'bool',   # Checkbox\n                                   6 => 'list',   # List\n                                   7 => 'list',   # Multiselection list\n                                   8 => 'date',   # Date\n                                   }\n\n      RELATION_TYPE_MAPPING = {1 => IssueRelation::TYPE_RELATES,    # related to\n                               2 => IssueRelation::TYPE_RELATES,    # parent of\n                               3 => IssueRelation::TYPE_RELATES,    # child of\n                               0 => IssueRelation::TYPE_DUPLICATES, # duplicate of\n                               4 => IssueRelation::TYPE_DUPLICATES  # has duplicate\n                               }\n\n    class MantisUser < ActiveRecord::Base\n      set_table_name :mantis_user_table\n\n      def firstname\n        @firstname = realname.blank? ? username : realname.split.first[0..29]\n        @firstname.gsub!(/[^\\w\\s\\'\\-]/i, '')\n        @firstname\n      end\n\n      def lastname\n        @lastname = realname.blank? ? '-' : realname.split[1..-1].join(' ')[0..29]\n        @lastname.gsub!(/[^\\w\\s\\'\\-]/i, '')\n        @lastname = '-' if @lastname.blank?\n        @lastname\n      end\n\n      def email\n        if read_attribute(:email).match(/^([^@\\s]+)@((?:[-a-z0-9]+\\.)+[a-z]{2,})$/i) &&\n             !User.find_by_mail(read_attribute(:email))\n          @email = read_attribute(:email)\n        else\n          @email = \"#{username}@foo.bar\"\n        end\n      end\n\n      def username\n        read_attribute(:username)[0..29].gsub(/[^a-zA-Z0-9_\\-@\\.]/, '-')\n      end\n    end\n\n    class MantisProject < ActiveRecord::Base\n      set_table_name :mantis_project_table\n      has_many :versions, :class_name => \"MantisVersion\", :foreign_key => :project_id\n      has_many :categories, :class_name => \"MantisCategory\", :foreign_key => :project_id\n      has_many :news, :class_name => \"MantisNews\", :foreign_key => :project_id\n      has_many :members, :class_name => \"MantisProjectUser\", :foreign_key => :project_id\n\n      def name\n        read_attribute(:name)[0..29]\n      end\n\n      def identifier\n        read_attribute(:name).underscore[0..19].gsub(/[^a-z0-9\\-]/, '-')\n      end\n    end\n\n    class MantisVersion < ActiveRecord::Base\n      set_table_name :mantis_project_version_table\n\n      def version\n        read_attribute(:version)[0..29]\n      end\n\n      def description\n        read_attribute(:description)[0..254]\n      end\n    end\n\n    class MantisCategory < ActiveRecord::Base\n      set_table_name :mantis_project_category_table\n    end\n\n    class MantisProjectUser < ActiveRecord::Base\n      set_table_name :mantis_project_user_list_table\n    end\n\n    class MantisBug < ActiveRecord::Base\n      set_table_name :mantis_bug_table\n      belongs_to :bug_text, :class_name => \"MantisBugText\", :foreign_key => :bug_text_id\n      has_many :bug_notes, :class_name => \"MantisBugNote\", :foreign_key => :bug_id\n      has_many :bug_files, :class_name => \"MantisBugFile\", :foreign_key => :bug_id\n      has_many :bug_monitors, :class_name => \"MantisBugMonitor\", :foreign_key => :bug_id\n    end\n\n    class MantisBugText < ActiveRecord::Base\n      set_table_name :mantis_bug_text_table\n\n      # Adds Mantis steps_to_reproduce and additional_information fields\n      # to description if any\n      def full_description\n        full_description = description\n        full_description += \"\\n\\n*Steps to reproduce:*\\n\\n#{steps_to_reproduce}\" unless steps_to_reproduce.blank?\n        full_description += \"\\n\\n*Additional information:*\\n\\n#{additional_information}\" unless additional_information.blank?\n        full_description\n      end\n    end\n\n    class MantisBugNote < ActiveRecord::Base\n      set_table_name :mantis_bugnote_table\n      belongs_to :bug, :class_name => \"MantisBug\", :foreign_key => :bug_id\n      belongs_to :bug_note_text, :class_name => \"MantisBugNoteText\", :foreign_key => :bugnote_text_id\n    end\n\n    class MantisBugNoteText < ActiveRecord::Base\n      set_table_name :mantis_bugnote_text_table\n    end\n\n    class MantisBugFile < ActiveRecord::Base\n      set_table_name :mantis_bug_file_table\n\n      def size\n        filesize\n      end\n\n      def original_filename\n        MantisMigrate.encode(filename)\n      end\n\n      def content_type\n        file_type\n      end\n\n      def read(*args)\n        if @read_finished\n          nil\n        else\n          @read_finished = true\n          content\n        end\n      end\n    end\n\n    class MantisBugRelationship < ActiveRecord::Base\n      set_table_name :mantis_bug_relationship_table\n    end\n\n    class MantisBugMonitor < ActiveRecord::Base\n      set_table_name :mantis_bug_monitor_table\n    end\n\n    class MantisNews < ActiveRecord::Base\n      set_table_name :mantis_news_table\n    end\n\n    class MantisCustomField < ActiveRecord::Base\n      set_table_name :mantis_custom_field_table\n      set_inheritance_column :none\n      has_many :values, :class_name => \"MantisCustomFieldString\", :foreign_key => :field_id\n      has_many :projects, :class_name => \"MantisCustomFieldProject\", :foreign_key => :field_id\n\n      def format\n        read_attribute :type\n      end\n\n      def name\n        read_attribute(:name)[0..29].gsub(/[^\\w\\s\\'\\-]/, '-')\n      end\n    end\n\n    class MantisCustomFieldProject < ActiveRecord::Base\n      set_table_name :mantis_custom_field_project_table\n    end\n\n    class MantisCustomFieldString < ActiveRecord::Base\n      set_table_name :mantis_custom_field_string_table\n    end\n\n\n    def self.migrate\n\n      # Users\n      print \"Migrating users\"\n      User.delete_all \"login <> 'admin'\"\n      users_map = {}\n      users_migrated = 0\n      MantisUser.find(:all).each do |user|\n      u = User.new :firstname => encode(user.firstname),\n             :lastname => encode(user.lastname),\n             :mail => user.email,\n             :last_login_on => user.last_visit\n      u.login = user.username\n      u.password = 'mantis'\n      u.status = User::STATUS_LOCKED if user.enabled != 1\n      u.admin = true if user.access_level == 90\n      next unless u.save!\n      users_migrated += 1\n      users_map[user.id] = u.id\n      print '.'\n      end\n      puts\n\n      # Projects\n      print \"Migrating projects\"\n      Project.destroy_all\n      projects_map = {}\n      versions_map = {}\n      categories_map = {}\n      MantisProject.find(:all).each do |project|\n      p = Project.new :name => encode(project.name),\n                        :description => encode(project.description)\n      p.identifier = project.identifier\n      next unless p.save\n      projects_map[project.id] = p.id\n      p.enabled_module_names = ['issue_tracking', 'news', 'wiki']\n        p.trackers << TRACKER_BUG\n        p.trackers << TRACKER_FEATURE\n      print '.'\n\n      # Project members\n      project.members.each do |member|\n          m = Member.new :user => User.find_by_id(users_map[member.user_id]),\n                         :roles => [ROLE_MAPPING[member.access_level] || DEFAULT_ROLE]\n        m.project = p\n        m.save\n      end\n\n      # Project versions\n      project.versions.each do |version|\n          v = Version.new :name => encode(version.version),\n                          :description => encode(version.description),\n                          :effective_date => version.date_order.to_date\n          v.project = p\n          v.save\n          versions_map[version.id] = v.id\n      end\n\n      # Project categories\n      project.categories.each do |category|\n          g = IssueCategory.new :name => category.category[0,30]\n          g.project = p\n          g.save\n          categories_map[category.category] = g.id\n      end\n      end\n      puts\n\n      # Bugs\n      print \"Migrating bugs\"\n      Issue.destroy_all\n      issues_map = {}\n      keep_bug_ids = (Issue.count == 0)\n      MantisBug.find_each(:batch_size => 200) do |bug|\n        next unless projects_map[bug.project_id] && users_map[bug.reporter_id]\n      i = Issue.new :project_id => projects_map[bug.project_id],\n                      :subject => encode(bug.summary),\n                      :description => encode(bug.bug_text.full_description),\n                      :priority => PRIORITY_MAPPING[bug.priority] || DEFAULT_PRIORITY,\n                      :created_at => bug.date_submitted,\n                      :updated_at => bug.last_updated\n      i.author = User.find_by_id(users_map[bug.reporter_id])\n      i.category = IssueCategory.find_by_project_id_and_name(i.project_id, bug.category[0,30]) unless bug.category.blank?\n      i.fixed_version = Version.find_by_project_id_and_name(i.project_id, bug.fixed_in_version) unless bug.fixed_in_version.blank?\n      i.status = STATUS_MAPPING[bug.status] || DEFAULT_STATUS\n      i.tracker = (bug.severity == 10 ? TRACKER_FEATURE : TRACKER_BUG)\n      i.id = bug.id if keep_bug_ids\n      next unless i.save\n      issues_map[bug.id] = i.id\n      print '.'\n\n        # Assignee\n        # Redmine checks that the assignee is a project member\n        if (bug.handler_id && users_map[bug.handler_id])\n          i.assigned_to = User.find_by_id(users_map[bug.handler_id])\n          i.save_with_validation(false)\n        end\n\n      # Bug notes\n      bug.bug_notes.each do |note|\n        next unless users_map[note.reporter_id]\n          n = Journal.new :notes => encode(note.bug_note_text.note),\n                          :created_at => note.date_submitted\n          n.user = User.find_by_id(users_map[note.reporter_id])\n          n.journalized = i\n          n.save\n      end\n\n        # Bug files\n        bug.bug_files.each do |file|\n          a = Attachment.new :created_at => file.date_added\n          a.file = file\n          a.author = User.find :first\n          a.container = i\n          a.save\n        end\n\n        # Bug monitors\n        bug.bug_monitors.each do |monitor|\n          next unless users_map[monitor.user_id]\n          i.add_watcher(User.find_by_id(users_map[monitor.user_id]))\n        end\n      end\n\n      # update issue id sequence if needed (postgresql)\n      Issue.connection.reset_pk_sequence!(Issue.table_name) if Issue.connection.respond_to?('reset_pk_sequence!')\n      puts\n\n      # Bug relationships\n      print \"Migrating bug relations\"\n      MantisBugRelationship.find(:all).each do |relation|\n        next unless issues_map[relation.source_bug_id] && issues_map[relation.destination_bug_id]\n        r = IssueRelation.new :relation_type => RELATION_TYPE_MAPPING[relation.relationship_type]\n        r.issue_from = Issue.find_by_id(issues_map[relation.source_bug_id])\n        r.issue_to = Issue.find_by_id(issues_map[relation.destination_bug_id])\n        pp r unless r.save\n        print '.'\n      end\n      puts\n\n      # News\n      print \"Migrating news\"\n      News.destroy_all\n      MantisNews.find(:all, :conditions => 'project_id > 0').each do |news|\n        next unless projects_map[news.project_id]\n        n = News.new :project_id => projects_map[news.project_id],\n                     :title => encode(news.headline[0..59]),\n                     :description => encode(news.body),\n                     :created_at => news.date_posted\n        n.author = User.find_by_id(users_map[news.poster_id])\n        n.save\n        print '.'\n      end\n      puts\n\n      # Custom fields\n      print \"Migrating custom fields\"\n      IssueCustomField.destroy_all\n      MantisCustomField.find(:all).each do |field|\n        f = IssueCustomField.new :name => field.name[0..29],\n                                 :field_format => CUSTOM_FIELD_TYPE_MAPPING[field.format],\n                                 :min_length => field.length_min,\n                                 :max_length => field.length_max,\n                                 :regexp => field.valid_regexp,\n                                 :possible_values => field.possible_values.split('|'),\n                                 :is_required => field.require_report?\n        next unless f.save\n        print '.'\n\n        # Trackers association\n        f.trackers = Tracker.find :all\n\n        # Projects association\n        field.projects.each do |project|\n          f.projects << Project.find_by_id(projects_map[project.project_id]) if projects_map[project.project_id]\n        end\n\n        # Values\n        field.values.each do |value|\n          v = CustomValue.new :custom_field_id => f.id,\n                              :value => value.value\n          v.customized = Issue.find_by_id(issues_map[value.bug_id]) if issues_map[value.bug_id]\n          v.save\n        end unless f.new_record?\n      end\n      puts\n\n      puts\n      puts \"Users:           #{users_migrated}/#{MantisUser.count}\"\n      puts \"Projects:        #{Project.count}/#{MantisProject.count}\"\n      puts \"Memberships:     #{Member.count}/#{MantisProjectUser.count}\"\n      puts \"Versions:        #{Version.count}/#{MantisVersion.count}\"\n      puts \"Categories:      #{IssueCategory.count}/#{MantisCategory.count}\"\n      puts \"Bugs:            #{Issue.count}/#{MantisBug.count}\"\n      puts \"Bug notes:       #{Journal.count}/#{MantisBugNote.count}\"\n      puts \"Bug files:       #{Attachment.count}/#{MantisBugFile.count}\"\n      puts \"Bug relations:   #{IssueRelation.count}/#{MantisBugRelationship.count}\"\n      puts \"Bug monitors:    #{Watcher.count}/#{MantisBugMonitor.count}\"\n      puts \"News:            #{News.count}/#{MantisNews.count}\"\n      puts \"Custom fields:   #{IssueCustomField.count}/#{MantisCustomField.count}\"\n    end\n\n    def self.encoding(charset)\n      @ic = Iconv.new('UTF-8', charset)\n    rescue Iconv::InvalidEncoding\n      return false\n    end\n\n    def self.establish_connection(params)\n      constants.each do |const|\n        klass = const_get(const)\n        next unless klass.respond_to? 'establish_connection'\n        klass.establish_connection params\n      end\n    end\n\n    def self.encode(text)\n      @ic.iconv text\n    rescue\n      text\n    end\n  end\n\n  puts\n  if Redmine::DefaultData::Loader.no_data?\n    puts \"Redmine configuration need to be loaded before importing data.\"\n    puts \"Please, run this first:\"\n    puts\n    puts \"  rake redmine:load_default_data RAILS_ENV=\\\"#{ENV['RAILS_ENV']}\\\"\"\n    exit\n  end\n\n  puts \"WARNING: Your Redmine data will be deleted during this process.\"\n  print \"Are you sure you want to continue ? [y/N] \"\n  break unless STDIN.gets.match(/^y$/i)\n\n  # Default Mantis database settings\n  db_params = {:adapter => 'mysql',\n               :database => 'bugtracker',\n               :host => 'localhost',\n               :username => 'root',\n               :password => '' }\n\n  puts\n  puts \"Please enter settings for your Mantis database\"\n  [:adapter, :host, :database, :username, :password].each do |param|\n    print \"#{param} [#{db_params[param]}]: \"\n    value = STDIN.gets.chomp!\n    db_params[param] = value unless value.blank?\n  end\n\n  while true\n    print \"encoding [UTF-8]: \"\n    encoding = STDIN.gets.chomp!\n    encoding = 'UTF-8' if encoding.blank?\n    break if MantisMigrate.encoding encoding\n    puts \"Invalid encoding!\"\n  end\n  puts\n\n  # Make sure bugs can refer bugs in other projects\n  Setting.cross_project_issue_relations = 1 if Setting.respond_to? 'cross_project_issue_relations'\n\n  # Turn off email notifications\n  Setting.notified_events = []\n\n  MantisMigrate.establish_connection db_params\n  MantisMigrate.migrate\nend\nend\n"
  },
  {
    "path": "lib/tasks/migrate_from_trac.rake",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n# This program is free software; you can redistribute it and/or\n# modify it under the terms of the GNU General Public License\n# as published by the Free Software Foundation; either version 2\n# of the License, or (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n\nrequire 'active_record'\nrequire 'iconv'\nrequire 'pp'\n\nnamespace :redmine do\n  desc 'Trac migration script'\n  task :migrate_from_trac => :environment do\n\n    module TracMigrate\n        TICKET_MAP = []\n\n        DEFAULT_STATUS = IssueStatus.default\n        assigned_status = IssueStatus.find_by_position(2)\n        resolved_status = IssueStatus.find_by_position(3)\n        feedback_status = IssueStatus.find_by_position(4)\n        closed_status = IssueStatus.find :first, :conditions => { :is_closed => true }\n        STATUS_MAPPING = {'new' => DEFAULT_STATUS,\n                          'reopened' => feedback_status,\n                          'assigned' => assigned_status,\n                          'closed' => closed_status\n                          }\n\n        priorities = Enumeration.priorities\n        DEFAULT_PRIORITY = priorities[0]\n        PRIORITY_MAPPING = {'lowest' => priorities[0],\n                            'low' => priorities[0],\n                            'normal' => priorities[1],\n                            'high' => priorities[2],\n                            'highest' => priorities[3],\n                            # ---\n                            'trivial' => priorities[0],\n                            'minor' => priorities[1],\n                            'major' => priorities[2],\n                            'critical' => priorities[3],\n                            'blocker' => priorities[4]\n                            }\n\n        TRACKER_BUG = Tracker.find_by_position(1)\n        TRACKER_FEATURE = Tracker.find_by_position(2)\n        DEFAULT_TRACKER = TRACKER_BUG\n        TRACKER_MAPPING = {'defect' => TRACKER_BUG,\n                           'enhancement' => TRACKER_FEATURE,\n                           'task' => TRACKER_FEATURE,\n                           'patch' =>TRACKER_FEATURE\n                           }\n\n        roles = Role.find(:all, :conditions => {:builtin => 0}, :order => 'position ASC')\n        manager_role = roles[0]\n        developer_role = roles[1]\n        DEFAULT_ROLE = roles.last\n        ROLE_MAPPING = {'admin' => manager_role,\n                        'developer' => developer_role\n                        }\n\n      class ::Time\n        class << self\n          alias :real_now :now\n          def now\n            real_now - @fake_diff.to_i\n          end\n          def fake(time)\n            @fake_diff = real_now - time\n            res = yield\n            @fake_diff = 0\n           res\n          end\n        end\n      end\n\n      class TracComponent < ActiveRecord::Base\n        set_table_name :component\n      end\n\n      class TracMilestone < ActiveRecord::Base\n        set_table_name :milestone\n        # If this attribute is set a milestone has a defined target timepoint\n        def due\n          if read_attribute(:due) && read_attribute(:due) > 0\n            Time.at(read_attribute(:due)).to_date\n          else\n            nil\n          end\n        end\n        # This is the real timepoint at which the milestone has finished.\n        def completed\n          if read_attribute(:completed) && read_attribute(:completed) > 0\n            Time.at(read_attribute(:completed)).to_date\n          else\n            nil\n          end\n        end\n\n        def description\n          # Attribute is named descr in Trac v0.8.x\n          has_attribute?(:descr) ? read_attribute(:descr) : read_attribute(:description)\n        end\n      end\n\n      class TracTicketCustom < ActiveRecord::Base\n        set_table_name :ticket_custom\n      end\n\n      class TracAttachment < ActiveRecord::Base\n        set_table_name :attachment\n        set_inheritance_column :none\n\n        def time; Time.at(read_attribute(:time)) end\n\n        def original_filename\n          filename\n        end\n\n        def content_type\n          Redmine::MimeType.of(filename) || ''\n        end\n\n        def exist?\n          File.file? trac_fullpath\n        end\n\n        def open\n          File.open(\"#{trac_fullpath}\", 'rb') {|f|\n            @file = f\n            yield self\n          }\n        end\n\n        def read(*args)\n          @file.read(*args)\n        end\n\n        def description\n          read_attribute(:description).to_s.slice(0,255)\n        end\n\n      private\n        def trac_fullpath\n          attachment_type = read_attribute(:type)\n          trac_file = filename.gsub( /[^a-zA-Z0-9\\-_\\.!~*']/n ) {|x| sprintf('%%%02x', x[0]) }\n          \"#{TracMigrate.trac_attachments_directory}/#{attachment_type}/#{id}/#{trac_file}\"\n        end\n      end\n\n      class TracTicket < ActiveRecord::Base\n        set_table_name :ticket\n        set_inheritance_column :none\n\n        # ticket changes: only migrate status changes and comments\n        has_many :changes, :class_name => \"TracTicketChange\", :foreign_key => :ticket\n        has_many :attachments, :class_name => \"TracAttachment\",\n                               :finder_sql => \"SELECT DISTINCT attachment.* FROM #{TracMigrate::TracAttachment.table_name}\" +\n                                              \" WHERE #{TracMigrate::TracAttachment.table_name}.type = 'ticket'\" +\n                                              ' AND #{TracMigrate::TracAttachment.table_name}.id = \\'#{id}\\''\n        has_many :customs, :class_name => \"TracTicketCustom\", :foreign_key => :ticket\n\n        def ticket_type\n          read_attribute(:type)\n        end\n\n        def summary\n          read_attribute(:summary).blank? ? \"(no subject)\" : read_attribute(:summary)\n        end\n\n        def description\n          read_attribute(:description).blank? ? summary : read_attribute(:description)\n        end\n\n        def time; Time.at(read_attribute(:time)) end\n        def changetime; Time.at(read_attribute(:changetime)) end\n      end\n\n      class TracTicketChange < ActiveRecord::Base\n        set_table_name :ticket_change\n\n        def time; Time.at(read_attribute(:time)) end\n      end\n\n      TRAC_WIKI_PAGES = %w(InterMapTxt InterTrac InterWiki RecentChanges SandBox TracAccessibility TracAdmin TracBackup TracBrowser TracCgi TracChangeset \\\n                           TracEnvironment TracFastCgi TracGuide TracImport TracIni TracInstall TracInterfaceCustomization \\\n                           TracLinks TracLogging TracModPython TracNotification TracPermissions TracPlugins TracQuery \\\n                           TracReports TracRevisionLog TracRoadmap TracRss TracSearch TracStandalone TracSupport TracSyntaxColoring TracTickets \\\n                           TracTicketsCustomFields TracTimeline TracUnicode TracUpgrade TracWiki WikiDeletePage WikiFormatting \\\n                           WikiHtml WikiMacros WikiNewPage WikiPageNames WikiProcessors WikiRestructuredText WikiRestructuredTextLinks \\\n                           CamelCase TitleIndex)\n\n      class TracWikiPage < ActiveRecord::Base\n        set_table_name :wiki\n        set_primary_key :name\n\n        has_many :attachments, :class_name => \"TracAttachment\",\n                               :finder_sql => \"SELECT DISTINCT attachment.* FROM #{TracMigrate::TracAttachment.table_name}\" +\n                                      \" WHERE #{TracMigrate::TracAttachment.table_name}.type = 'wiki'\" +\n                                      ' AND #{TracMigrate::TracAttachment.table_name}.id = \\'#{id}\\''\n\n        def self.columns\n          # Hides readonly Trac field to prevent clash with AR readonly? method (Rails 2.0)\n          super.select {|column| column.name.to_s != 'readonly'}\n        end\n\n        def time; Time.at(read_attribute(:time)) end\n      end\n\n      class TracPermission < ActiveRecord::Base\n        set_table_name :permission\n      end\n\n      class TracSessionAttribute < ActiveRecord::Base\n        set_table_name :session_attribute\n      end\n\n      def self.find_or_create_user(username, project_member = false)\n        return User.anonymous if username.blank?\n\n        u = User.find_by_login(username)\n        if !u\n          # Create a new user if not found\n          mail = username[0,limit_for(User, 'mail')]\n          if mail_attr = TracSessionAttribute.find_by_sid_and_name(username, 'email')\n            mail = mail_attr.value\n          end\n          mail = \"#{mail}@foo.bar\" unless mail.include?(\"@\")\n\n          name = username\n          if name_attr = TracSessionAttribute.find_by_sid_and_name(username, 'name')\n            name = name_attr.value\n          end\n          name =~ (/(.*)(\\s+\\w+)?/)\n          fn = $1.strip\n          ln = ($2 || '-').strip\n\n          u = User.new :mail => mail.gsub(/[^-@a-z0-9\\.]/i, '-'),\n                       :firstname => fn[0, limit_for(User, 'firstname')].gsub(/[^\\w\\s\\'\\-]/i, '-'),\n                       :lastname => ln[0, limit_for(User, 'lastname')].gsub(/[^\\w\\s\\'\\-]/i, '-')\n\n          u.login = username[0,limit_for(User, 'login')].gsub(/[^a-z0-9_\\-@\\.]/i, '-')\n          u.password = 'trac'\n          u.admin = true if TracPermission.find_by_username_and_action(username, 'admin')\n          # finally, a default user is used if the new user is not valid\n          u = User.find(:first) unless u.save\n        end\n        # Make sure he is a member of the project\n        if project_member && !u.member_of?(@target_project)\n          role = DEFAULT_ROLE\n          if u.admin\n            role = ROLE_MAPPING['admin']\n          elsif TracPermission.find_by_username_and_action(username, 'developer')\n            role = ROLE_MAPPING['developer']\n          end\n          Member.create(:user => u, :project => @target_project, :roles => [role])\n          u.reload\n        end\n        u\n      end\n\n      # Basic wiki syntax conversion\n      def self.convert_wiki_text(text)\n        # Titles\n        text = text.gsub(/^(\\=+)\\s(.+)\\s(\\=+)/) {|s| \"\\nh#{$1.length}. #{$2}\\n\"}\n        # External Links\n        text = text.gsub(/\\[(http[^\\s]+)\\s+([^\\]]+)\\]/) {|s| \"\\\"#{$2}\\\":#{$1}\"}\n        # Ticket links:\n        #      [ticket:234 Text],[ticket:234 This is a test]\n        text = text.gsub(/\\[ticket\\:([^\\ ]+)\\ (.+?)\\]/, '\"\\2\":/issues/show/\\1')\n        #      ticket:1234\n        #      #1 is working cause Redmine uses the same syntax.\n        text = text.gsub(/ticket\\:([^\\ ]+)/, '#\\1')\n        # Milestone links:\n        #      [milestone:\"0.1.0 Mercury\" Milestone 0.1.0 (Mercury)]\n        #      The text \"Milestone 0.1.0 (Mercury)\" is not converted,\n        #      cause Redmine's wiki does not support this.\n        text = text.gsub(/\\[milestone\\:\\\"([^\\\"]+)\\\"\\ (.+?)\\]/, 'version:\"\\1\"')\n        #      [milestone:\"0.1.0 Mercury\"]\n        text = text.gsub(/\\[milestone\\:\\\"([^\\\"]+)\\\"\\]/, 'version:\"\\1\"')\n        text = text.gsub(/milestone\\:\\\"([^\\\"]+)\\\"/, 'version:\"\\1\"')\n        #      milestone:0.1.0\n        text = text.gsub(/\\[milestone\\:([^\\ ]+)\\]/, 'version:\\1')\n        text = text.gsub(/milestone\\:([^\\ ]+)/, 'version:\\1')\n        # Internal Links\n        text = text.gsub(/\\[\\[BR\\]\\]/, \"\\n\") # This has to go before the rules below\n        text = text.gsub(/\\[\\\"(.+)\\\".*\\]/) {|s| \"[[#{$1.delete(',./?;|:')}]]\"}\n        text = text.gsub(/\\[wiki:\\\"(.+)\\\".*\\]/) {|s| \"[[#{$1.delete(',./?;|:')}]]\"}\n        text = text.gsub(/\\[wiki:\\\"(.+)\\\".*\\]/) {|s| \"[[#{$1.delete(',./?;|:')}]]\"}\n        text = text.gsub(/\\[wiki:([^\\s\\]]+)\\]/) {|s| \"[[#{$1.delete(',./?;|:')}]]\"}\n        text = text.gsub(/\\[wiki:([^\\s\\]]+)\\s(.*)\\]/) {|s| \"[[#{$1.delete(',./?;|:')}|#{$2.delete(',./?;|:')}]]\"}\n\n  # Links to pages UsingJustWikiCaps\n  text = text.gsub(/([^!]|^)(^| )([A-Z][a-z]+[A-Z][a-zA-Z]+)/, '\\\\1\\\\2[[\\3]]')\n  # Normalize things that were supposed to not be links\n  # like !NotALink\n  text = text.gsub(/(^| )!([A-Z][A-Za-z]+)/, '\\1\\2')\n        # Revisions links\n        text = text.gsub(/\\[(\\d+)\\]/, 'r\\1')\n        # Ticket number re-writing\n        text = text.gsub(/#(\\d+)/) do |s|\n          if $1.length < 10\n            TICKET_MAP[$1.to_i] ||= $1\n            \"\\##{TICKET_MAP[$1.to_i] || $1}\"\n          else\n            s\n          end\n        end\n        # We would like to convert the Code highlighting too\n        # This will go into the next line.\n        shebang_line = false\n        # Reguar expression for start of code\n        pre_re = /\\{\\{\\{/\n        # Code hightlighing...\n        shebang_re = /^\\#\\!([a-z]+)/\n        # Regular expression for end of code\n        pre_end_re = /\\}\\}\\}/\n\n        # Go through the whole text..extract it line by line\n        text = text.gsub(/^(.*)$/) do |line|\n          m_pre = pre_re.match(line)\n          if m_pre\n            line = '<pre>'\n          else\n            m_sl = shebang_re.match(line)\n            if m_sl\n              shebang_line = true\n              line = '<code class=\"' + m_sl[1] + '\">'\n            end\n            m_pre_end = pre_end_re.match(line)\n            if m_pre_end\n              line = '</pre>'\n              if shebang_line\n                line = '</code>' + line\n              end\n            end\n          end\n          line\n        end\n\n        # Highlighting\n        text = text.gsub(/'''''([^\\s])/, '_*\\1')\n        text = text.gsub(/([^\\s])'''''/, '\\1*_')\n        text = text.gsub(/'''/, '*')\n        text = text.gsub(/''/, '_')\n        text = text.gsub(/__/, '+')\n        text = text.gsub(/~~/, '-')\n        text = text.gsub(/`/, '@')\n        text = text.gsub(/,,/, '~')\n        # Lists\n        text = text.gsub(/^([ ]+)\\* /) {|s| '*' * $1.length + \" \"}\n\n        text\n      end\n\n      def self.migrate\n        establish_connection\n\n        # Quick database test\n        TracComponent.count\n\n        migrated_components = 0\n        migrated_milestones = 0\n        migrated_tickets = 0\n        migrated_custom_values = 0\n        migrated_ticket_attachments = 0\n        migrated_wiki_edits = 0\n        migrated_wiki_attachments = 0\n\n        #Wiki system initializing...\n        @target_project.wiki.destroy if @target_project.wiki\n        @target_project.reload\n        wiki = Wiki.new(:project => @target_project, :start_page => 'WikiStart')\n        wiki_edit_count = 0\n\n        # Components\n        print \"Migrating components\"\n        issues_category_map = {}\n        TracComponent.find(:all).each do |component|\n        print '.'\n        STDOUT.flush\n          c = IssueCategory.new :project => @target_project,\n                                :name => encode(component.name[0, limit_for(IssueCategory, 'name')])\n        next unless c.save\n        issues_category_map[component.name] = c\n        migrated_components += 1\n        end\n        puts\n\n        # Milestones\n        print \"Migrating milestones\"\n        version_map = {}\n        TracMilestone.find(:all).each do |milestone|\n          print '.'\n          STDOUT.flush\n          # First we try to find the wiki page...\n          p = wiki.find_or_new_page(milestone.name.to_s)\n          p.content = WikiContent.new(:page => p) if p.new_record?\n          p.content.text = milestone.description.to_s\n          p.content.author = find_or_create_user('trac')\n          p.content.comments = 'Milestone'\n          p.save\n\n          v = Version.new :project => @target_project,\n                          :name => encode(milestone.name[0, limit_for(Version, 'name')]),\n                          :description => nil,\n                          :wiki_page_title => milestone.name.to_s,\n                          :effective_date => milestone.completed\n\n          next unless v.save\n          version_map[milestone.name] = v\n          migrated_milestones += 1\n        end\n        puts\n\n        # Custom fields\n        # TODO: read trac.ini instead\n        print \"Migrating custom fields\"\n        custom_field_map = {}\n        TracTicketCustom.find_by_sql(\"SELECT DISTINCT name FROM #{TracTicketCustom.table_name}\").each do |field|\n          print '.'\n          STDOUT.flush\n          # Redmine custom field name\n          field_name = encode(field.name[0, limit_for(IssueCustomField, 'name')]).humanize\n          # Find if the custom already exists in Redmine\n          f = IssueCustomField.find_by_name(field_name)\n          # Or create a new one\n          f ||= IssueCustomField.create(:name => encode(field.name[0, limit_for(IssueCustomField, 'name')]).humanize,\n                                        :field_format => 'string')\n\n          next if f.new_record?\n          f.trackers = Tracker.find(:all)\n          f.projects << @target_project\n          custom_field_map[field.name] = f\n        end\n        puts\n\n        # Trac 'resolution' field as a Redmine custom field\n        r = IssueCustomField.find(:first, :conditions => { :name => \"Resolution\" })\n        r = IssueCustomField.new(:name => 'Resolution',\n                                 :field_format => 'list',\n                                 :is_filter => true) if r.nil?\n        r.trackers = Tracker.find(:all)\n        r.projects << @target_project\n        r.possible_values = (r.possible_values + %w(fixed invalid wontfix duplicate worksforme)).flatten.compact.uniq\n        r.save!\n        custom_field_map['resolution'] = r\n\n        # Tickets\n        print \"Migrating tickets\"\n          TracTicket.find_each(:batch_size => 200) do |ticket|\n          print '.'\n          STDOUT.flush\n          i = Issue.new :project => @target_project,\n                          :subject => encode(ticket.summary[0, limit_for(Issue, 'subject')]),\n                          :description => convert_wiki_text(encode(ticket.description)),\n                          :priority => PRIORITY_MAPPING[ticket.priority] || DEFAULT_PRIORITY,\n                          :created_at => ticket.time\n          i.author = find_or_create_user(ticket.reporter)\n          i.category = issues_category_map[ticket.component] unless ticket.component.blank?\n          i.fixed_version = version_map[ticket.milestone] unless ticket.milestone.blank?\n          i.status = STATUS_MAPPING[ticket.status] || DEFAULT_STATUS\n          i.tracker = TRACKER_MAPPING[ticket.ticket_type] || DEFAULT_TRACKER\n          i.id = ticket.id unless Issue.exists?(ticket.id)\n          next unless Time.fake(ticket.changetime) { i.save }\n          TICKET_MAP[ticket.id] = i.id\n          migrated_tickets += 1\n\n          # Owner\n            unless ticket.owner.blank?\n              i.assigned_to = find_or_create_user(ticket.owner, true)\n              Time.fake(ticket.changetime) { i.save }\n            end\n\n          # Comments and status/resolution changes\n          ticket.changes.group_by(&:time).each do |time, changeset|\n              status_change = changeset.select {|change| change.field == 'status'}.first\n              resolution_change = changeset.select {|change| change.field == 'resolution'}.first\n              comment_change = changeset.select {|change| change.field == 'comment'}.first\n\n              n = Journal.new :notes => (comment_change ? convert_wiki_text(encode(comment_change.newvalue)) : ''),\n                              :created_at => time\n              n.user = find_or_create_user(changeset.first.author)\n              n.journalized = i\n              if status_change &&\n                   STATUS_MAPPING[status_change.oldvalue] &&\n                   STATUS_MAPPING[status_change.newvalue] &&\n                   (STATUS_MAPPING[status_change.oldvalue] != STATUS_MAPPING[status_change.newvalue])\n                n.details << JournalDetail.new(:property => 'attr',\n                                               :prop_key => 'status_id',\n                                               :old_value => STATUS_MAPPING[status_change.oldvalue].id,\n                                               :value => STATUS_MAPPING[status_change.newvalue].id)\n              end\n              if resolution_change\n                n.details << JournalDetail.new(:property => 'cf',\n                                               :prop_key => custom_field_map['resolution'].id,\n                                               :old_value => resolution_change.oldvalue,\n                                               :value => resolution_change.newvalue)\n              end\n              n.save unless n.details.empty? && n.notes.blank?\n          end\n\n          # Attachments\n          ticket.attachments.each do |attachment|\n            next unless attachment.exist?\n              attachment.open {\n                a = Attachment.new :created_at => attachment.time\n                a.file = attachment\n                a.author = find_or_create_user(attachment.author)\n                a.container = i\n                a.description = attachment.description\n                migrated_ticket_attachments += 1 if a.save\n              }\n          end\n\n          # Custom fields\n          custom_values = ticket.customs.inject({}) do |h, custom|\n            if custom_field = custom_field_map[custom.name]\n              h[custom_field.id] = custom.value\n              migrated_custom_values += 1\n            end\n            h\n          end\n          if custom_field_map['resolution'] && !ticket.resolution.blank?\n            custom_values[custom_field_map['resolution'].id] = ticket.resolution\n          end\n          i.custom_field_values = custom_values\n          i.save_custom_field_values\n        end\n\n        # update issue id sequence if needed (postgresql)\n        Issue.connection.reset_pk_sequence!(Issue.table_name) if Issue.connection.respond_to?('reset_pk_sequence!')\n        puts\n\n        # Wiki\n        print \"Migrating wiki\"\n        if wiki.save\n          TracWikiPage.find(:all, :order => 'name, version').each do |page|\n            # Do not migrate Trac manual wiki pages\n            next if TRAC_WIKI_PAGES.include?(page.name)\n            wiki_edit_count += 1\n            print '.'\n            STDOUT.flush\n            p = wiki.find_or_new_page(page.name)\n            p.content = WikiContent.new(:page => p) if p.new_record?\n            p.content.text = page.text\n            p.content.author = find_or_create_user(page.author) unless page.author.blank? || page.author == 'trac'\n            p.content.comments = page.comment\n            Time.fake(page.time) { p.new_record? ? p.save : p.content.save }\n\n            next if p.content.new_record?\n            migrated_wiki_edits += 1\n\n            # Attachments\n            page.attachments.each do |attachment|\n              next unless attachment.exist?\n              next if p.attachments.find_by_filename(attachment.filename.gsub(/^.*(\\\\|\\/)/, '').gsub(/[^\\w\\.\\-]/,'_')) #add only once per page\n              attachment.open {\n                a = Attachment.new :created_at => attachment.time\n                a.file = attachment\n                a.author = find_or_create_user(attachment.author)\n                a.description = attachment.description\n                a.container = p\n                migrated_wiki_attachments += 1 if a.save\n              }\n            end\n          end\n\n          wiki.reload\n          wiki.pages.each do |page|\n            page.content.text = convert_wiki_text(page.content.text)\n            Time.fake(page.content.updated_at) { page.content.save }\n          end\n        end\n        puts\n\n        puts\n        puts \"Components:      #{migrated_components}/#{TracComponent.count}\"\n        puts \"Milestones:      #{migrated_milestones}/#{TracMilestone.count}\"\n        puts \"Tickets:         #{migrated_tickets}/#{TracTicket.count}\"\n        puts \"Ticket files:    #{migrated_ticket_attachments}/\" + TracAttachment.count(:conditions => {:type => 'ticket'}).to_s\n        puts \"Custom values:   #{migrated_custom_values}/#{TracTicketCustom.count}\"\n        puts \"Wiki edits:      #{migrated_wiki_edits}/#{wiki_edit_count}\"\n        puts \"Wiki files:      #{migrated_wiki_attachments}/\" + TracAttachment.count(:conditions => {:type => 'wiki'}).to_s\n      end\n\n      def self.limit_for(klass, attribute)\n        klass.columns_hash[attribute.to_s].limit\n      end\n\n      def self.encoding(charset)\n        @ic = Iconv.new('UTF-8', charset)\n      rescue Iconv::InvalidEncoding\n        puts \"Invalid encoding!\"\n        return false\n      end\n\n      def self.set_trac_directory(path)\n        @@trac_directory = path\n        raise \"This directory doesn't exist!\" unless File.directory?(path)\n        raise \"#{trac_attachments_directory} doesn't exist!\" unless File.directory?(trac_attachments_directory)\n        @@trac_directory\n      rescue Exception => e\n        puts e\n        return false\n      end\n\n      def self.trac_directory\n        @@trac_directory\n      end\n\n      def self.set_trac_adapter(adapter)\n        return false if adapter.blank?\n        raise \"Unknown adapter: #{adapter}!\" unless %w(sqlite sqlite3 mysql postgresql).include?(adapter)\n        # If adapter is sqlite or sqlite3, make sure that trac.db exists\n        raise \"#{trac_db_path} doesn't exist!\" if %w(sqlite sqlite3).include?(adapter) && !File.exist?(trac_db_path)\n        @@trac_adapter = adapter\n      rescue Exception => e\n        puts e\n        return false\n      end\n\n      def self.set_trac_db_host(host)\n        return nil if host.blank?\n        @@trac_db_host = host\n      end\n\n      def self.set_trac_db_port(port)\n        return nil if port.to_i == 0\n        @@trac_db_port = port.to_i\n      end\n\n      def self.set_trac_db_name(name)\n        return nil if name.blank?\n        @@trac_db_name = name\n      end\n\n      def self.set_trac_db_username(username)\n        @@trac_db_username = username\n      end\n\n      def self.set_trac_db_password(password)\n        @@trac_db_password = password\n      end\n\n      def self.set_trac_db_schema(schema)\n        @@trac_db_schema = schema\n      end\n\n      mattr_reader :trac_directory, :trac_adapter, :trac_db_host, :trac_db_port, :trac_db_name, :trac_db_schema, :trac_db_username, :trac_db_password\n\n      def self.trac_db_path; \"#{trac_directory}/db/trac.db\" end\n      def self.trac_attachments_directory; \"#{trac_directory}/attachments\" end\n\n      def self.target_project_identifier(identifier)\n        project = Project.find_by_identifier(identifier)\n        if !project\n          # create the target project\n          project = Project.new :name => identifier.humanize,\n                                :description => ''\n          project.identifier = identifier\n          puts \"Unable to create a project with identifier '#{identifier}'!\" unless project.save\n          # enable issues and wiki for the created project\n          project.enabled_module_names = ['issue_tracking', 'wiki']\n        else\n          puts\n          puts \"This project already exists in your Redmine database.\"\n          print \"Are you sure you want to append data to this project ? [Y/n] \"\n          exit if STDIN.gets.match(/^n$/i)\n        end\n        project.trackers << TRACKER_BUG unless project.trackers.include?(TRACKER_BUG)\n        project.trackers << TRACKER_FEATURE unless project.trackers.include?(TRACKER_FEATURE)\n        @target_project = project.new_record? ? nil : project\n      end\n\n      def self.connection_params\n        if %w(sqlite sqlite3).include?(trac_adapter)\n          {:adapter => trac_adapter,\n           :database => trac_db_path}\n        else\n          {:adapter => trac_adapter,\n           :database => trac_db_name,\n           :host => trac_db_host,\n           :port => trac_db_port,\n           :username => trac_db_username,\n           :password => trac_db_password,\n           :schema_search_path => trac_db_schema\n          }\n        end\n      end\n\n      def self.establish_connection\n        constants.each do |const|\n          klass = const_get(const)\n          next unless klass.respond_to? 'establish_connection'\n          klass.establish_connection connection_params\n        end\n      end\n\n    private\n      def self.encode(text)\n        @ic.iconv text\n      rescue\n        text\n      end\n    end\n\n    puts\n    if Redmine::DefaultData::Loader.no_data?\n      puts \"Redmine configuration need to be loaded before importing data.\"\n      puts \"Please, run this first:\"\n      puts\n      puts \"  rake redmine:load_default_data RAILS_ENV=\\\"#{ENV['RAILS_ENV']}\\\"\"\n      exit\n    end\n\n    puts \"WARNING: a new project will be added to Redmine during this process.\"\n    print \"Are you sure you want to continue ? [y/N] \"\n    break unless STDIN.gets.match(/^y$/i)\n    puts\n\n    def prompt(text, options = {}, &block)\n      default = options[:default] || ''\n      while true\n        print \"#{text} [#{default}]: \"\n        value = STDIN.gets.chomp!\n        value = default if value.blank?\n        break if yield value\n      end\n    end\n\n    DEFAULT_PORTS = {'mysql' => 3306, 'postgresql' => 5432}\n\n    prompt('Trac directory') {|directory| TracMigrate.set_trac_directory directory.strip}\n    prompt('Trac database adapter (sqlite, sqlite3, mysql, postgresql)', :default => 'sqlite') {|adapter| TracMigrate.set_trac_adapter adapter}\n    unless %w(sqlite sqlite3).include?(TracMigrate.trac_adapter)\n      prompt('Trac database host', :default => 'localhost') {|host| TracMigrate.set_trac_db_host host}\n      prompt('Trac database port', :default => DEFAULT_PORTS[TracMigrate.trac_adapter]) {|port| TracMigrate.set_trac_db_port port}\n      prompt('Trac database name') {|name| TracMigrate.set_trac_db_name name}\n      prompt('Trac database schema', :default => 'public') {|schema| TracMigrate.set_trac_db_schema schema}\n      prompt('Trac database username') {|username| TracMigrate.set_trac_db_username username}\n      prompt('Trac database password') {|password| TracMigrate.set_trac_db_password password}\n    end\n    prompt('Trac database encoding', :default => 'UTF-8') {|encoding| TracMigrate.encoding encoding}\n    prompt('Target project identifier') {|identifier| TracMigrate.target_project_identifier identifier}\n    puts\n\n    # Turn off email notifications\n    Setting.notified_events = []\n\n    TracMigrate.migrate\n  end\nend\n\n"
  },
  {
    "path": "lib/tasks/migrate_plugins.rake",
    "content": "namespace :db do\n  desc 'Migrates installed plugins.'\n  task :migrate_plugins => :environment do\n    if Rails.respond_to?('plugins')\n      Rails.plugins.each do |plugin|\n        next unless plugin.respond_to?('migrate')\n        puts \"Migrating #{plugin.name}...\"\n        plugin.migrate\n      end\n    else\n      puts \"Undefined method plugins for Rails!\"\n      puts \"Make sure engines plugin is installed.\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tasks/plugins.rake",
    "content": "require 'source_annotation_extractor'\n\n# Modified version of the SourceAnnotationExtractor in railties\n# Will search for runable code that uses <tt>call_hook</tt>\nclass PluginSourceAnnotationExtractor < SourceAnnotationExtractor\n  # Returns a hash that maps filenames under +dir+ (recursively) to arrays\n  # with their annotations. Only files with annotations are included, and only\n  # those with extension +.builder+, +.rb+, +.rxml+, +.rjs+, +.rhtml+, and +.erb+\n  # are taken into account.\n  def find_in(dir)\n    results = {}\n\n    Dir.glob(\"#{dir}/*\") do |item|\n      next if File.basename(item)[0] == ?.\n\n      if File.directory?(item)\n        results.update(find_in(item))\n      elsif item =~ /(hook|test)\\.rb/\n        # skip\n      elsif item =~ /\\.(builder|(r(?:b|xml|js)))$/\n        results.update(extract_annotations_from(item, /\\s*(#{tag})\\(?\\s*(.*)$/))\n      elsif item =~ /\\.(rhtml|erb)$/\n        results.update(extract_annotations_from(item, /<%=\\s*\\s*(#{tag})\\(?\\s*(.*?)\\s*%>/))\n      end\n    end\n\n    results\n  end\nend\n\nnamespace :redmine do\n  namespace :plugins do\n    desc \"Enumerate all Redmine plugin hooks and their context parameters\"\n    task :hook_list do\n      PluginSourceAnnotationExtractor.enumerate 'call_hook'\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tasks/reek.rake",
    "content": "namespace :reek do\n  task :statements do\n    dirs_to_reek = ['app/models', 'app/controllers', 'app/helpers']\n    files_to_reek = dirs_to_reek.map { |dir| Dir[File.join(dir, \"**/*.rb\")] }\n    output = `reek #{files_to_reek.join(' ')}`\n    long_methods = output.lines.select { |line| line =~ /TooManyStatements/ }\n    long_methods.sort! do |line_1, line_2|\n      line_1.split[3].to_i <=> line_2.split[3].to_i\n    end\n    puts long_methods\n  end\nend\n"
  },
  {
    "path": "lib/tasks/reminder.rake",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2008  Shereef Bishay\n#\n\ndesc <<-END_DESC\nSend reminders about issues due in the next days.\n\nAvailable options:\n  * days     => number of days to remind about (defaults to 7)\n  * tracker  => id of tracker (defaults to all trackers)\n  * project  => id or identifier of project (defaults to all projects)\n\nExample:\n  rake redmine:send_reminders days=7 RAILS_ENV=\"production\"\nEND_DESC\n\nnamespace :redmine do\n  task :send_reminders => :environment do\n    options = {}\n    options[:days] = ENV['days'].to_i if ENV['days']\n    options[:project] = ENV['project'] if ENV['project']\n    options[:tracker] = ENV['tracker'].to_i if ENV['tracker']\n\n    Mailer.reminders(options)\n  end\nend\n"
  },
  {
    "path": "lib/tasks/remove_problem_type.rake",
    "content": "# Used once\n\ndesc \"removes item of type : problem and changes them to type : taks\"\ntask :remove_problem_type => :environment do\n\n  problem = Tracker.first(:conditions => {:name => \"Problem\"})\n  task = Tracker.first(:conditions => {:name => \"Task\"})\n\n  Issue.find(:all, :conditions => {:tracker_id => problem.id }).each do |issue|\n    issue.tracker = task\n    issue.save\n    puts \"#{issue.subject}\"\n  end\nend\n"
  },
  {
    "path": "lib/tasks/reset_all_passwords.rake",
    "content": "task :reset_all_passwords => :environment do\n\n  if ENV['reset_safe'] == 'true'\n    puts \"Resetting all passwords to 'password'...\"\n    User.update_all(:hashed_password => \"5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8\")\n    puts \"done.\"\n  else\n    puts \"wont reset. we're not in development\"\n    puts \"to allow reset use: export reset_safe=true\"\n  end\nend\n"
  },
  {
    "path": "lib/tasks/rspec.rake",
    "content": "gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9\nrspec_gem_dir = nil\nDir[\"#{RAILS_ROOT}/vendor/gems/*\"].each do |subdir|\n  rspec_gem_dir = subdir if subdir.gsub(\"#{RAILS_ROOT}/vendor/gems/\",\"\") =~ /^(\\w+-)?rspec-(\\d+)/ && File.exist?(\"#{subdir}/lib/spec/rake/spectask.rb\")\nend\nrspec_plugin_dir = File.expand_path(File.dirname(__FILE__) + '/../../vendor/plugins/rspec')\n\nif rspec_gem_dir && (test ?d, rspec_plugin_dir)\n  raise \"\\n#{'*'*50}\\nYou have rspec installed in both vendor/gems and vendor/plugins\\nPlease pick one and dispose of the other.\\n#{'*'*50}\\n\\n\"\nend\n\nif rspec_gem_dir\n  $LOAD_PATH.unshift(\"#{rspec_gem_dir}/lib\")\nelsif File.exist?(rspec_plugin_dir)\n  $LOAD_PATH.unshift(\"#{rspec_plugin_dir}/lib\")\nend\n\n# Don't load rspec if running \"rake gems:*\"\nunless ARGV.any? {|a| a =~ /^gems/}\n\nbegin\n  require 'spec/rake/spectask'\nrescue MissingSourceFile\n  module Spec\n    module Rake\n      class SpecTask\n        def initialize(name)\n          task name do\n            # if rspec-rails is a configured gem, this will output helpful material and exit ...\n            require File.expand_path(File.join(File.dirname(__FILE__),\"..\",\"..\",\"config\",\"environment\"))\n\n            # ... otherwise, do this:\n            raise <<-MSG\n\n#{\"*\" * 80}\n*  You are trying to run an rspec rake task defined in\n*  #{__FILE__},\n*  but rspec can not be found in vendor/gems, vendor/plugins or system gems.\n#{\"*\" * 80}\nMSG\n          end\n        end\n      end\n    end\n  end\nend\n\nRake.application.instance_variable_get('@tasks').delete('default')\n\nspec_prereq = File.exist?(File.join(RAILS_ROOT, 'config', 'database.yml')) ? \"db:test:prepare\" : :noop\ntask :noop do\nend\n\ntask :default => :spec\ntask :stats => \"spec:statsetup\"\n\ndesc \"Run all specs in spec directory (excluding plugin specs)\"\nSpec::Rake::SpecTask.new(:spec => spec_prereq) do |t|\n  t.spec_opts = ['--options', \"\\\"#{RAILS_ROOT}/spec/spec.opts\\\"\"]\n  t.spec_files = FileList['spec/**/*_spec.rb']\nend\n\nnamespace :spec do\n  desc \"Run all specs in spec directory with RCov (excluding plugin specs)\"\n  Spec::Rake::SpecTask.new(:rcov) do |t|\n    t.spec_opts = ['--options', \"\\\"#{RAILS_ROOT}/spec/spec.opts\\\"\"]\n    t.spec_files = FileList['spec/**/*_spec.rb']\n    t.rcov = true\n    t.rcov_opts = lambda do\n      IO.readlines(\"#{RAILS_ROOT}/spec/rcov.opts\").map {|l| l.chomp.split \" \"}.flatten\n    end\n  end\n\n  desc \"Print Specdoc for all specs (excluding plugin specs)\"\n  Spec::Rake::SpecTask.new(:doc) do |t|\n    t.spec_opts = [\"--format\", \"specdoc\", \"--dry-run\"]\n    t.spec_files = FileList['spec/**/*_spec.rb']\n  end\n\n  desc \"Print Specdoc for all plugin examples\"\n  Spec::Rake::SpecTask.new(:plugin_doc) do |t|\n    t.spec_opts = [\"--format\", \"specdoc\", \"--dry-run\"]\n    t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*')\n  end\n\n  [:models, :controllers, :views, :helpers, :lib, :integration].each do |sub|\n    desc \"Run the code examples in spec/#{sub}\"\n    Spec::Rake::SpecTask.new(sub => spec_prereq) do |t|\n      t.spec_opts = ['--options', \"\\\"#{RAILS_ROOT}/spec/spec.opts\\\"\"]\n      t.spec_files = FileList[\"spec/#{sub}/**/*_spec.rb\"]\n    end\n  end\n\n  desc \"Run the code examples in vendor/plugins (except RSpec's own)\"\n  Spec::Rake::SpecTask.new(:plugins => spec_prereq) do |t|\n    t.spec_opts = ['--options', \"\\\"#{RAILS_ROOT}/spec/spec.opts\\\"\"]\n    t.spec_files = FileList['vendor/plugins/**/spec/**/*_spec.rb'].exclude('vendor/plugins/rspec/*').exclude(\"vendor/plugins/rspec-rails/*\")\n  end\n\n  namespace :plugins do\n    desc \"Runs the examples for rspec_on_rails\"\n    Spec::Rake::SpecTask.new(:rspec_on_rails) do |t|\n      t.spec_opts = ['--options', \"\\\"#{RAILS_ROOT}/spec/spec.opts\\\"\"]\n      t.spec_files = FileList['vendor/plugins/rspec-rails/spec/**/*_spec.rb']\n    end\n  end\n\n  # Setup specs for stats\n  task :statsetup do\n    require 'code_statistics'\n    ::STATS_DIRECTORIES << %w(Model\\ specs spec/models) if File.exist?('spec/models')\n    ::STATS_DIRECTORIES << %w(View\\ specs spec/views) if File.exist?('spec/views')\n    ::STATS_DIRECTORIES << %w(Controller\\ specs spec/controllers) if File.exist?('spec/controllers')\n    ::STATS_DIRECTORIES << %w(Helper\\ specs spec/helpers) if File.exist?('spec/helpers')\n    ::STATS_DIRECTORIES << %w(Library\\ specs spec/lib) if File.exist?('spec/lib')\n    ::STATS_DIRECTORIES << %w(Routing\\ specs spec/routing) if File.exist?('spec/routing')\n    ::STATS_DIRECTORIES << %w(Integration\\ specs spec/integration) if File.exist?('spec/integration')\n    ::CodeStatistics::TEST_TYPES << \"Model specs\" if File.exist?('spec/models')\n    ::CodeStatistics::TEST_TYPES << \"View specs\" if File.exist?('spec/views')\n    ::CodeStatistics::TEST_TYPES << \"Controller specs\" if File.exist?('spec/controllers')\n    ::CodeStatistics::TEST_TYPES << \"Helper specs\" if File.exist?('spec/helpers')\n    ::CodeStatistics::TEST_TYPES << \"Library specs\" if File.exist?('spec/lib')\n    ::CodeStatistics::TEST_TYPES << \"Routing specs\" if File.exist?('spec/routing')\n    ::CodeStatistics::TEST_TYPES << \"Integration specs\" if File.exist?('spec/integration')\n  end\n\n  namespace :db do\n    namespace :fixtures do\n      desc \"Load fixtures (from spec/fixtures) into the current environment's database.  Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z.\"\n      task :load => :environment do\n        ActiveRecord::Base.establish_connection(Rails.env)\n        base_dir = File.join(Rails.root, 'spec', 'fixtures')\n        fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir\n\n        require 'active_record/fixtures'\n        (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir.glob(File.join(fixtures_dir, '*.{yml,csv}'))).each do |fixture_file|\n          Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*'))\n        end\n      end\n    end\n  end\nend\n\nend\n"
  },
  {
    "path": "lib/tasks/steak.rake",
    "content": "unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks\n\nbegin\n  require 'spec/rake/spectask'\nrescue MissingSourceFile\n  module Spec\n    module Rake\n      class SpecTask\n        def initialize(name)\n          task name do\n            # if rspec-rails is a configured gem, this will output helpful material and exit ...\n            require File.expand_path(File.join(File.dirname(__FILE__),\"..\",\"..\",\"config\",\"environment\"))\n\n            # ... otherwise, do this:\n            raise <<-MSG\n\n#{\"*\" * 80}\n*  You are trying to run an rspec rake task defined in\n*  #{__FILE__},\n*  but rspec can not be found in vendor/gems, vendor/plugins or system gems.\n#{\"*\" * 80}\nMSG\n          end\n        end\n      end\n    end\n  end\nend\n\nnamespace :spec do\n  desc \"Run the code examples in spec/acceptance\"\n  Spec::Rake::SpecTask.new(:acceptance => \"db:test:prepare\") do |t|\n    t.spec_opts = ['--options', \"\\\"#{RAILS_ROOT}/spec/spec.opts\\\"\"]\n    t.spec_files = FileList[\"spec/acceptance/**/*_spec.rb\"]\n  end\n\n  # Setup stats to include acceptance specs\n  task :statsetup do\n    require 'code_statistics'\n    ::STATS_DIRECTORIES << %w(Acceptance\\ specs spec/acceptance) if File.exist?('spec/acceptance')\n    ::CodeStatistics::TEST_TYPES << \"Acceptance specs\" if File.exist?('spec/acceptance')\n  end\nend\nend\n"
  },
  {
    "path": "lib/tasks/testing.rake",
    "content": "### From http://svn.geekdaily.org/public/rails/plugins/generally_useful/tasks/coverage_via_rcov.rake\n\nnamespace :test do\n  desc 'Measures test coverage'\n  task :coverage do\n    rm_f \"coverage\"\n    rm_f \"coverage.data\"\n    rcov = \"rcov --rails --aggregate coverage.data --text-summary -Ilib --html\"\n    files = Dir.glob(\"test/**/*_test.rb\").join(\" \")\n    system(\"#{rcov} #{files}\")\n    system(\"open coverage/index.html\") if PLATFORM['darwin']\n  end\n\n  namespace :scm do\n    namespace :setup do\n      desc \"Creates directory for test repositories\"\n      task :create_dir do\n        FileUtils.mkdir_p Rails.root + '/tmp/test'\n      end\n\n      supported_scms = [:subversion, :cvs, :bazaar, :mercurial, :git, :darcs, :filesystem]\n\n      desc \"Creates a test subversion repository\"\n      task :subversion => :create_dir do\n        repo_path = \"tmp/test/subversion_repository\"\n        system \"svnadmin create #{repo_path}\"\n        system \"gunzip < test/fixtures/repositories/subversion_repository.dump.gz | svnadmin load #{repo_path}\"\n      end\n\n      (supported_scms - [:subversion]).each do |scm|\n        desc \"Creates a test #{scm} repository\"\n        task scm => :create_dir do\n          system \"gunzip < test/fixtures/repositories/#{scm}_repository.tar.gz | tar -xv -C tmp/test\"\n        end\n      end\n\n      desc \"Creates all test repositories\"\n      task :all => supported_scms\n    end\n  end\nend\n"
  },
  {
    "path": "lib/tasks/update_item_statuses.rake",
    "content": "# Updates item status to Done or Canceled depending on what their % complete is\n# Used once for migrating to new more defined item statuses\n\ndesc \"update item statuses to Done or Canceled depending on what their % complete is\"\ntask :update_item_statuses => :environment do\n\n  done = IssueStatus.first(:conditions => {:name => \"Done\"})\n  canceled = IssueStatus.first(:conditions => {:name => \"Canceled\"})\n  closed = IssueStatus.first(:conditions => {:name => \"Closed\"})\n  Issue.find(:all, :conditions => {:status_id => closed.id }).each do |issue|\n    issue.done_ratio < 100 ? issue.status = canceled : issue.status = done\n    issue.save\n  end\nend\n"
  },
  {
    "path": "lib/tasks/watchers.rake",
    "content": "desc 'Removes watchers from what they can no longer view.'\n\nnamespace :redmine do\n  namespace :watchers do\n    task :prune => :environment do\n      Watcher.prune\n    end\n  end\nend\n"
  },
  {
    "path": "public/.htaccess",
    "content": "# General Apache options\n<IfModule mod_fastcgi.c>\n\tAddHandler fastcgi-script .fcgi\n</IfModule>\n<IfModule mod_fcgid.c>\n\tAddHandler fcgid-script .fcgi\n</IfModule>\n<IfModule mod_cgi.c>\n\tAddHandler cgi-script .cgi\n</IfModule>\nOptions +FollowSymLinks +ExecCGI\n\n# If you don't want Rails to look in certain directories,\n# use the following rewrite rules so that Apache won't rewrite certain requests\n# \n# Example:\n#   RewriteCond %{REQUEST_URI} ^/notrails.*\n#   RewriteRule .* - [L]\n\n# Redirect all requests not available on the filesystem to Rails\n# By default the cgi dispatcher is used which is very slow\n# \n# For better performance replace the dispatcher with the fastcgi one\n#\n# Example:\n#   RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]\nRewriteEngine On\n\n# If your Rails application is accessed via an Alias directive,\n# then you MUST also set the RewriteBase in this htaccess file.\n#\n# Example:\n#   Alias /myrailsapp /path/to/myrailsapp/public\n#   RewriteBase /myrailsapp\n\nRewriteRule ^$ index.html [QSA]\nRewriteRule ^([^.]+)$ $1.html [QSA]\nRewriteCond %{REQUEST_FILENAME} !-f\n<IfModule mod_fastcgi.c>\n\tRewriteRule ^(.*)$ dispatch.fcgi [QSA,L]\n</IfModule>\n<IfModule mod_fcgid.c>\n\tRewriteRule ^(.*)$ dispatch.fcgi [QSA,L]\n</IfModule>\n<IfModule mod_cgi.c>\n\tRewriteRule ^(.*)$ dispatch.cgi [QSA,L]\n</IfModule>\n\n# In case Rails experiences terminal errors\n# Instead of displaying this message you can supply a file here which will be rendered instead\n# \n# Example:\n#   ErrorDocument 500 /500.html\n\nErrorDocument 500 \"<h2>Application error</h2>Rails application failed to start properly\""
  },
  {
    "path": "public/404.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n   \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<title>BetterMeans 404 error</title>\n<style>\nbody{\nfont-family: Trebuchet MS,Georgia,\"Times New Roman\",serif;\ncolor:#303030;\nmargin:10px;\n}\nh1{\nfont-size:1.5em;\n}\np{\nfont-size:0.8em;\n}\n</style>\n<body>\n  <script type=\"text/javascript\">\n\n    var _gaq = _gaq || [];\n    _gaq.push(['_setAccount', 'UA-1630609-6']);\n    _gaq.push(['_trackPageview']);\n\n    (function() {\n      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n    })();\n\n  </script>\n  <h1>Page not found</h1>\n  <p>The page you were trying to access doesn't exist or has been removed.</p>\n  <p><a href=\"javascript:history.back()\">Back</a></p>\n</body>\n</html>\n"
  },
  {
    "path": "public/500.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n   \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<title>BetterMeans 500 error</title>\n<style>\nbody{\nfont-family: Trebuchet MS,Georgia,\"Times New Roman\",serif;\ncolor:#303030;\nmargin:10px;\n}\nh1{\nfont-size:1.5em;\n}\np{\nfont-size:0.8em;\n}\n</style>\n<body>\n  <script type=\"text/javascript\">\n\n    var _gaq = _gaq || [];\n    _gaq.push(['_setAccount', 'UA-1630609-6']);\n    _gaq.push(['_trackPageview']);\n\n    (function() {\n      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n    })();\n\n  </script>\n  <h1>Oops. Something went wrong: Internal error</h1>\n  <p>We've dispatched our geeks, and they're on it. Really sorry about that!</p>\n  <p><a href=\"javascript:history.back()\">Back</a></p>\n</body>\n</html>\n"
  },
  {
    "path": "public/help/wiki_syntax.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />\n<title>Wiki formatting</title>\n<style type=\"text/css\">\nh1 { font-family: Verdana, sans-serif; font-size: 14px; text-align: center; color: #444; }\nbody { font-family: Verdana, sans-serif; font-size: 12px; color: #444; }\ntable th { padding-top: 1em; }\ntable td { vertical-align: top; background-color: #f5f5f5; height: 2em; vertical-align: middle;}\ntable td code { font-size: 1.2em; }\ntable td h1 { font-size: 1.8em; text-align: left; }\ntable td h2 { font-size: 1.4em; text-align: left; }\ntable td h3 { font-size: 1.2em; text-align: left; }\n\n</style>\n</head>\n<body>\n\n<h1>Wiki Syntax Quick Reference</h1>\n\n<table width=\"100%\">\n<tr><th colspan=\"3\">Font Styles</th></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_strong.png\" style=\"border: 1px solid #bbb;\" alt=\"Strong\" /></th><td width=\"50%\">*Strong*</td><td width=\"50%\"><strong>Strong</strong></td></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_em.png\" style=\"border: 1px solid #bbb;\" alt=\"Italic\" /></th><td>_Italic_</td><td><em>Italic</em></td></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_ins.png\" style=\"border: 1px solid #bbb;\" alt=\"Underline\" /></th><td>+Underline+</td><td><ins>Underline</ins></td></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_del.png\" style=\"border: 1px solid #bbb;\" alt=\"Deleted\" /></th><td>-Deleted-</td><td><del>Deleted</del></td></tr>\n<tr><th></th><td>??Quote??</td><td><cite>Quote</cite></td></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_code.png\" style=\"border: 1px solid #bbb;\" alt=\"Inline Code\" /></th><td>@Inline Code@</td><td><code>Inline Code</code></td></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_pre.png\" style=\"border: 1px solid #bbb;\" alt=\"Preformatted text\" /></th><td>&lt;pre><br />&nbsp;lines<br />&nbsp;of code<br />&lt;/pre></td><td>\n<pre>\n lines\n of code\n</pre>\n</td></tr>\n\n<tr><th colspan=\"3\">Lists</th></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_ul.png\" style=\"border: 1px solid #bbb;\" alt=\"Unordered list\" /></th><td>* Item 1<br />* Item 2</td><td><ul><li>Item 1</li><li>Item 2</li></ul></td></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_ol.png\" style=\"border: 1px solid #bbb;\" alt=\"Ordered list\" /></th><td># Item 1<br /># Item 2</td><td><ol><li>Item 1</li><li>Item 2</li></ol></td></tr>\n\n<tr><th colspan=\"3\">Headings</th></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_h1.png\" style=\"border: 1px solid #bbb;\" alt=\"Heading 1\" /></th><td>h1. Title 1</td><td><h1>Title 1</h1></td></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_h2.png\" style=\"border: 1px solid #bbb;\" alt=\"Heading 2\" /></th><td>h2. Title 2</td><td><h2>Title 2</h2></td></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_h3.png\" style=\"border: 1px solid #bbb;\" alt=\"Heading 3\" /></th><td>h3. Title 3</td><td><h3>Title 3</h3></td></tr>\n\n<tr><th colspan=\"3\">Links</th></tr>\n<tr><th></th><td>http://foo.bar</td><td><a href=\"#\">http://foo.bar</a></td></tr>\n<tr><th></th><td>\"Foo\":http://foo.bar</td><td><a href=\"#\">Foo</a></td></tr>\n\n<tr><th colspan=\"3\">BetterMeans links</th></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_link.png\" style=\"border: 1px solid #bbb;\" alt=\"Link to a Wiki page\" /></th><td>[[Wiki page]]</td><td><a href=\"#\">Wiki page</a></td></tr>\n<tr><th></th><td>Issue #12</td><td>Issue <a href=\"#\">#12</a></td></tr>\n<tr><th></th><td>Revision r43</td><td>Revision <a href=\"#\">r43</a></td></tr>\n<tr><th></th><td>commit:f30e13e43</td><td><a href=\"#\">f30e13e4</a></td></tr>\n<tr><th></th><td>source:some/file</td><td><a href=\"#\">source:some/file</a></td></tr>\n\n<tr><th colspan=\"3\">Inline images</th></tr>\n<tr><th><img src=\"../images/jstoolbar/bt_img.png\" style=\"border: 1px solid #bbb;\" alt=\"Image\" /></th><td>!<em>image_url</em>!</td><td></td></tr>\n<tr><th></th><td>!<em>attached_image</em>!</td><td></td></tr>\n</table>\n\n<p><a href=\"wiki_syntax_detailed.html\" onclick=\"window.open('wiki_syntax_detailed.html', '', ''); return false;\">More Information</a></p>\n\n</body>\n</html>\n"
  },
  {
    "path": "public/help/wiki_syntax_detailed.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<head>\n<title>BetterMeansWikiFormatting</title>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n<style type=\"text/css\">\n    body { font:80% Verdana,Tahoma,Arial,sans-serif; }\n    h1, h2, h3, h4 {  font-family: Trebuchet MS,Georgia,\"Times New Roman\",serif; }\n    pre, code { font-size:120%; }\n    pre code { font-size:100%; }\n    pre {\n        margin: 1em 1em 1em 1.6em;\n        padding: 2px;\n        background-color: #fafafa;\n        border: 1px solid #dadada;\n        width:95%;\n        overflow-x: auto;\n    }\n    a.new { color: #b73535; }\n\n    .CodeRay .c  { color:#666; }\n\n    .CodeRay .cl { color:#B06; font-weight:bold }\n    .CodeRay .dl { color:black }\n    .CodeRay .fu { color:#06B; font-weight:bold }\n\n    .CodeRay .il { background: #eee }\n    .CodeRay .il .idl { font-weight: bold; color: #888 }\n\n    .CodeRay .iv { color:#33B }\n    .CodeRay .r  { color:#080; font-weight:bold }\n\n    .CodeRay .s  { background-color:#fff0f0 }\n    .CodeRay .s  .dl { color:#710 }\n</style>\n</head>\n\n<body>\n<h1><a name=\"1\" class=\"wiki-page\"></a>Wiki formatting</h1>\n\n    <h2><a name=\"2\" class=\"wiki-page\"></a>Links</h2>\n\n        <h3><a name=\"3\" class=\"wiki-page\"></a>BetterMeans links</h3>\n\n        <p>BetterMeans allows hyperlinking between issues, changesets and wiki pages from anywhere wiki formatting is used.</p>\n        <ul>\n            <li>Link to an issue: <strong>#124</strong> (displays <del><a href=\"/issues/show/124\" class=\"issue\" title=\"bulk edit doesn't change the category or fixed version properties (Closed)\">#124</a></del>, link is striked-through if the issue is closed)</li>\n            <li>Link to a changeset: <strong>r758</strong> (displays <a href=\"/repositories/revision/1?rev=758\" class=\"changeset\" title=\"Search engine now only searches objects the user is allowed to view.\">r758</a>)</li>\n            <li>Link to a changeset with a non-numeric hash: <strong>commit:c6f4d0fd</strong> (displays c6f4d0fd).  Added in <a href=\"/repositories/revision/1?rev=1236\" class=\"changeset\" title=\"Merged Git support branch (r1200 to r1226).\">r1236</a>.</li>\n        </ul>\n\n        <p>Wiki links:</p>\n\n        <ul>\n            <li><strong>[[Guide]]</strong> displays a link to the page named 'Guide': <a href=\"Guide.html\" class=\"wiki-page\">Guide</a></li>\n            <li><strong>[[Guide#further-reading]]</strong> takes you to the anchor \"further-reading\". Headings get automatically assigned anchors so that you can refer to them: <a href=\"Guide.html#further-reading\" class=\"wiki-page\">Guide</a></li>\n            <li><strong>[[Guide|User manual]]</strong> displays a link to the same page but with a different text: <a href=\"Guide.html\" class=\"wiki-page\">User manual</a></li>\n        </ul>\n\n        <p>You can also link to pages of an other project wiki:</p>\n\n        <ul>\n            <li><strong>[[sandbox:some page]]</strong> displays a link to the page named 'Some page' of the Sandbox wiki</li>\n            <li><strong>[[sandbox:]]</strong> displays a link to the Sandbox wiki main page</li>\n        </ul>\n\n        <p>Wiki links are displayed in red if the page doesn't exist yet, eg: <a href=\"Nonexistent_page.html\" class=\"wiki-page new\">Nonexistent page</a>.</p>\n\n        <p>Links to others resources (0.7):</p>\n\n        <ul>\n            <li>Documents:\n                <ul>\n                    <li><strong>document#17</strong> (link to document with id 17)</li>\n                    <li><strong>document:Greetings</strong> (link to the document with title \"Greetings\")</li>\n                    <li><strong>document:\"Some document\"</strong> (double quotes can be used when document title contains spaces)</li>\n                </ul></li>\n        </ul>\n\n        <ul>\n            <li>Versions:\n                <ul>\n                    <li><strong>version#3</strong> (link to version with id 3)</li>\n                    <li><strong>version:1.0.0</strong> (link to version named \"1.0.0\")</li>\n                    <li><strong>version:\"1.0 beta 2\"</strong></li>\n                </ul></li>\n        </ul>\n\n        <ul>\n            <li>Attachments:\n                <ul>\n                    <li><strong>attachment:file.zip</strong> (link to the attachment of the current object named file.zip)</li>\n                    <li>For now, attachments of the current object can be referenced only (if you're on an issue, it's possible to reference attachments of this issue only)</li>\n                </ul></li>\n        </ul>\n\n        <ul>\n             <li>Repository files\n                <ul>\n                    <li><strong>source:some/file</strong>          -- Link to the file located at /some/file in the project's repository</li>\n                    <li><strong>source:some/file@52</strong>       -- Link to the file's revision 52</li>\n                    <li><strong>source:some/file#L120</strong>     -- Link to line 120 of the file</li>\n                    <li><strong>source:some/file@52#L120</strong>  -- Link to line 120 of the file's revision 52</li>\n                    <li><strong>export:some/file</strong>          -- Force the download of the file</li>\n            </ul></li>\n        </ul>\n\n        <p>Escaping (0.7):</p>\n\n        <ul>\n            <li>You can prevent BetterMeans links from being parsed by preceding them with an exclamation mark: !</li>\n        </ul>\n\n\n        <h3><a name=\"4\" class=\"wiki-page\"></a>External links</h3>\n\n        <p>HTTP URLs and email addresses are automatically turned into clickable links:</p>\n\n<pre>\nhttp://www.BetterMeans.org, someone@foo.bar\n</pre>\n\n        <p>displays: <a class=\"external\" href=\"http://www.BetterMeans.org\">http://www.BetterMeans.org</a>, <a href=\"mailto:someone@foo.bar\" class=\"email\">someone@foo.bar</a></p>\n\n        <p>If you want to display a specific text instead of the URL, you can use the standard textile syntax:</p>\n\n<pre>\n\"BetterMeans web site\":http://www.BetterMeans.org\n</pre>\n\n        <p>displays: <a href=\"http://www.BetterMeans.org\" class=\"external\">BetterMeans web site</a></p>\n\n\n    <h2><a name=\"5\" class=\"wiki-page\"></a>Text formatting</h2>\n\n\n    <p>For things such as headlines, bold, tables, lists, BetterMeans supports Textile syntax.  See <a class=\"external\" href=\"http://www.textism.com/tools/textile/\">http://www.textism.com/tools/textile/</a> for information on using any of these features.  A few samples are included below, but the engine is capable of much more of that.</p>\n\n        <h3><a name=\"6\" class=\"wiki-page\"></a>Font style</h3>\n\n<pre>\n* *bold*\n* _italic_\n* _*bold italic*_\n* +underline+\n* -strike-through-\n</pre>\n\n        <p>Display:</p>\n\n        <ul>\n            <li><strong>bold</strong></li>\n            <li><em>italic</em></li>\n            <li><em>*bold italic*</em></li>\n            <li><ins>underline</ins></li>\n            <li><del>strike-through</del></li>\n        </ul>\n\n        <h3><a name=\"7\" class=\"wiki-page\"></a>Inline images</h3>\n\n        <ul>\n            <li><strong>!image_url!</strong> displays an image located at image_url (textile syntax)</li>\n            <li><strong>!>image_url!</strong> right floating image</li>\n            <li>If you have an image attached to your wiki page, it can be displayed inline using its filename: <strong>!attached_image.png!</strong></li>\n        </ul>\n\n        <h3><a name=\"8\" class=\"wiki-page\"></a>Headings</h3>\n\n<pre>\nh1. Heading\nh2. Subheading\nh3. Subsubheading\n</pre>\n\n        <p>BetterMeans assigns an anchor to each of those headings thus you can link to them with \"#Heading\", \"#Subheading\" and so forth.</p>\n\n\n        <h3><a name=\"9\" class=\"wiki-page\"></a>Paragraphs</h3>\n\n<pre>\np>. right aligned\np=. centered\n</pre>\n\n        <p style=\"text-align:center;\">This is centered paragraph.</p>\n\n\n        <h3><a name=\"10\" class=\"wiki-page\"></a>Blockquotes</h3>\n\n        <p>Start the paragraph with <strong>bq.</strong></p>\n\n<pre>\nbq. Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.\nTo go live, all you need to add is a database and a web server.\n</pre>\n\n        <p>Display:</p>\n\n        <blockquote>\n                <p>Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.<br />To go live, all you need to add is a database and a web server.</p>\n        </blockquote>\n\n\n        <h3><a name=\"11\" class=\"wiki-page\"></a>Table of content</h3>\n\n<pre>\n{{toc}} => left aligned toc\n{{>toc}} => right aligned toc\n</pre>\n\n    <h2><a name=\"12\" class=\"wiki-page\"></a>Macros</h2>\n\n    <p>BetterMeans has the following builtin macros:</p>\n\n    <p><dl><dt><code>hello_world</code></dt><dd><p>Sample macro.</p></dd><dt><code>include</code></dt><dd><p>Include a wiki page. Example:</p>\n\n    <pre><code>{{include(Foo)}}</code></pre></dd><dt><code>macro_list</code></dt><dd><p>Displays a list of all available macros, including description if available.</p></dd></dl></p>\n\n\n    <h2><a name=\"13\" class=\"wiki-page\"></a>Code highlighting</h2>\n\n    <p>Code highlightment relies on <a href=\"http://coderay.rubychan.de/\" class=\"external\">CodeRay</a>, a fast syntax highlighting library written completely in Ruby. It currently supports c, html, javascript, rhtml, ruby, scheme, xml languages.</p>\n\n    <p>You can highlight code in your wiki page using this syntax:</p>\n\n<pre>\n&lt;pre&gt;&lt;code class=\"ruby\"&gt;\n  Place you code here.\n&lt;/code&gt;&lt;/pre&gt;\n</pre>\n\n    <p>Example:</p>\n\n<pre><code class=\"ruby CodeRay\"><span class=\"no\"> 1</span> <span class=\"c\"># The Greeter class</span>\n<span class=\"no\"> 2</span> <span class=\"r\">class</span> <span class=\"cl\">Greeter</span>\n<span class=\"no\"> 3</span>   <span class=\"r\">def</span> <span class=\"fu\">initialize</span>(name)\n<span class=\"no\"> 4</span>     <span class=\"iv\">@name</span> = name.capitalize\n<span class=\"no\"> 5</span>   <span class=\"r\">end</span>\n<span class=\"no\"> 6</span>\n<span class=\"no\"> 7</span>   <span class=\"r\">def</span> <span class=\"fu\">salute</span>\n<span class=\"no\"> 8</span>     puts <span class=\"s\"><span class=\"dl\">\"</span><span class=\"k\">Hello </span><span class=\"il\"><span class=\"idl\">#{</span><span class=\"iv\">@name</span><span class=\"idl\">}</span></span><span class=\"k\">!</span><span class=\"dl\">\"</span></span>\n<span class=\"no\"> 9</span>   <span class=\"r\">end</span>\n<span class=\"no\"><strong>10</strong></span> <span class=\"r\">end</span>\n</code>\n</pre>\n</body>\n</html>\n"
  },
  {
    "path": "public/javascripts/application.js",
    "content": "/* BetterMeans - Work 2.0\n   Copyright (C) 2006-2011  See readme for details and license */\n\nvar jumpbox_text = \"\";\nvar community_members = {}; //used by @mention autocomplete\n\nfunction initialize(){\n  arm_fancybox();\n  prep_jumpbox();\n  break_long_words();\n  bind_autocomplete_mentions();\n}\n\nfunction break_long_words(){\n  $('.long-words').breakWords();\n}\n\nfunction arm_fancybox(){\n  if((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))) {\n     return;\n  }\n  $(\"a.fancyframe\").fancybox({\n      'speedIn'    :  0,\n      'speedOut'    :  0,\n      'overlayShow'  :  true,\n      'width'        : '90%',\n      'height'      : '95%',\n          'autoScale'       : false,\n      'moddal'      : false,\n      'hideOnOverlayClick' : true,\n      'transitionIn'    : 'none',\n      'transitionOut'    : 'none',\n      'type'        : 'iframe'\n    }).click(function(){\n      $.fancybox.showActivity();\n      $('#fancybox-frame').load(function(){\n          $.fancybox.hideActivity();\n          $(\"#fancybox-frame\").contents().find(\"a[href*=/]\").not(\"a[target*=top]\").attr('target', '_blank');\n        });\n    });\n}\n\nfunction arm_checkboxes(){\n  $(\".cb-enable\").click(function(){\n        var parent = $(this).parents('.switch');\n        $('.cb-disable',parent).removeClass('selected');\n        $(this).addClass('selected');\n        $('.checkbox',parent).attr('checked', true);\n    });\n    $(\".cb-disable\").click(function(){\n        var parent = $(this).parents('.switch');\n        $('.cb-enable',parent).removeClass('selected');\n        $(this).addClass('selected');\n        $('.checkbox',parent).attr('checked', false);\n    });\n}\n\nfunction prep_jumpbox(){\n  jumpbox_text = $('#jumpbox :selected').text();\n  $('#jumpbox :selected').text($.trim($('#jumpbox :selected').text()));\n  adjust_jumpbox_width();\n\n  $('#jumpbox').focus(function(){\n    $('#jumpbox :selected').text(jumpbox_text);\n    //adjust_jumpbox_width();\n     $('#jumpbox').width('auto');\n  });\n  $('#jumpbox').focusout(function(){\n    $('#jumpbox :selected').text($.trim($('#jumpbox :selected').text()));\n    $('#jumpbox').css('background','#323232');\n    adjust_jumpbox_width();\n\n  });\n  $('#jumpbox').change(function(){\n    $('#jumpbox :selected').text($.trim($('#jumpbox :selected').text()));\n    $('#jumpbox').css('background','#323232');\n    adjust_jumpbox_width();\n  });\n}\n\nfunction adjust_jumpbox_width(){\n  jumpbox_width = $('#widthcalc').html($('#jumpbox :selected').text()).width();\n  if (jumpbox_width > 10){\n    $('#jumpbox').width(jumpbox_width + 35);\n  }\n}\n\nfunction show_fancybox(url,message){\n  $.fancybox({\n          'width'        : '90%',\n        'height'      : '95%',\n            'autoScale'       : false,\n            'transitionIn'    : 'none',\n        'transitionOut'    : 'none',\n            'speedIn'      : '0',\n        'speedOut'      : '0',\n        'type'        : 'iframe',\n        'href'        : url\n    });\n\n  $('#fancybox-frame').load(function(){\n       $('#fancy-loading').hide();\n      $(\"#fancybox-frame\").contents().find(\"a[href*=/]\").not(\"a[target*=top]\").attr('target', '_blank');\n    });\n  $('#fancybox-inner').prepend(\"<div id='fancy-loading' class='loading'>\" + message + \"</div>\");\n}\n\nfunction checkAll (id, checked) {\n     $(\"form#\" + id + \" INPUT[type='checkbox']\").attr('checked', checked);\n}\n\nfunction toggleCheckboxesBySelector(selector) {\n  boxes = $$(selector);\n  var all_checked = true;\n  for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } }\n  for (i = 0; i < boxes.length; i++) { boxes[i].checked = !all_checked; }\n}\n\nfunction showAndScrollTo(id, focus) {\n  $('#' + id).show();\n  if (focus!=null) { $('#' + focus).focus(); }\n  $('#' + focus).parent().scrollTo('#' + focus);\n}\n\nfunction toggleRowGroup(el) {\n  var tr = Element.up(el, 'tr');\n  var n = Element.next(tr);\n  tr.toggleClassName('open');\n  while (n != undefined && !n.hasClassName('group')) {\n    Element.toggle(n);\n    n = Element.next(n);\n  }\n}\n\nfunction toggleFieldset(el) {\n  var fieldset = Element.up(el, 'fieldset');\n  fieldset.toggleClassName('collapsed');\n  Effect.toggle(fieldset.down('div'), 'slide', {duration:0.2});\n}\n\nvar fileFieldCount = 1;\n\nfunction addFileField() {\n    if (fileFieldCount >= 10) return false;\n    fileFieldCount++;\n    var f = document.createElement(\"input\");\n    f.type = \"file\";\n    f.name = \"attachments[\" + fileFieldCount + \"][file]\";\n    f.size = 30;\n    var d = document.createElement(\"input\");\n    d.type = \"text\";\n    d.name = \"attachments[\" + fileFieldCount + \"][description]\";\n    d.size = 60;\n\n    p = document.getElementById(\"attachments_fields\");\n    p.appendChild(document.createElement(\"br\"));\n    p.appendChild(f);\n    p.appendChild(d);\n}\n\nfunction showTab(name) {\n  $('.tab-content').hide();\n  $('.tab-top').removeClass(\"selected\");\n  $('#tab-content-' + name).show();\n  $('#tab-' + name).addClass(\"selected\");\n  return false;\n}\n\nfunction moveTabRight(el) {\n  var lis = Element.up(el, 'div.tabs').down('ul').childElements();\n  var tabsWidth = 0;\n  var i;\n  for (i=0; i<lis.length; i++) {\n    if (lis[i].visible()) {\n      tabsWidth += lis[i].getWidth() + 6;\n    }\n  }\n  if (tabsWidth < Element.up(el, 'div.tabs').getWidth() - 60) {\n    return;\n  }\n  i=0;\n  while (i<lis.length && !lis[i].visible()) {\n    i++;\n  }\n  lis[i].hide();\n}\n\nfunction moveTabLeft(el) {\n  var lis = Element.up(el, 'div.tabs').down('ul').childElements();\n  var i = 0;\n  while (i<lis.length && !lis[i].visible()) {\n    i++;\n  }\n  if (i>0) {\n    lis[i-1].show();\n  }\n}\n\nfunction displayTabsButtons() {\n  var lis;\n  var tabsWidth = 0;\n  var i;\n  $$('div.tabs').each(function(el) {\n    lis = el.down('ul').childElements();\n    for (i=0; i<lis.length; i++) {\n      if (lis[i].visible()) {\n        tabsWidth += lis[i].getWidth() + 6;\n      }\n    }\n    if ((tabsWidth < el.getWidth() - 60) && (lis[0].visible())) {\n      el.down('div.tabs-buttons').hide();\n    } else {\n      el.down('div.tabs-buttons').show();\n    }\n  });\n}\n\nfunction setPredecessorFieldsVisibility() {\n    relationType = $('relation_relation_type');\n    if (relationType && (relationType.value == \"precedes\" || relationType.value == \"follows\")) {\n        Element.show('predecessor_fields');\n    } else {\n        Element.hide('predecessor_fields');\n    }\n}\n\nfunction collapseScmEntry(id) {\n    var els = document.getElementsByClassName(id, 'browser');\n  for (var i = 0; i < els.length; i++) {\n     if (els[i].hasClassName('open')) {\n         collapseScmEntry(els[i].id);\n     }\n       Element.hide(els[i]);\n    }\n    $(id).removeClassName('open');\n}\n\nfunction expandScmEntry(id) {\n    var els = document.getElementsByClassName(id, 'browser');\n  for (var i = 0; i < els.length; i++) {\n       Element.show(els[i]);\n       if (els[i].hasClassName('loaded') && !els[i].hasClassName('collapsed')) {\n            expandScmEntry(els[i].id);\n       }\n    }\n    $(id).addClassName('open');\n}\n\nfunction scmEntryClick(id) {\n    el = $(id);\n    if (el.hasClassName('open')) {\n        collapseScmEntry(id);\n        el.addClassName('collapsed');\n        return false;\n    } else if (el.hasClassName('loaded')) {\n        expandScmEntry(id);\n        el.removeClassName('collapsed');\n        return false;\n    }\n    if (el.hasClassName('loading')) {\n        return false;\n    }\n    el.addClassName('loading');\n    return true;\n}\n\nfunction scmEntryLoaded(id) {\n    Element.addClassName(id, 'open');\n    Element.addClassName(id, 'loaded');\n    Element.removeClassName(id, 'loading');\n}\n\nfunction randomKey(size) {\n  var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');\n  var key = '';\n  for (i = 0; i < size; i++) {\n    key += chars[Math.floor(Math.random() * chars.length)];\n  }\n  return key;\n}\n\n//TODO: replace this with jquery alternative\n// /* shows and hides ajax indicator */\n// Ajax.Responders.register({\n//     onCreate: function(){\n//         if ($('ajax-indicator') && Ajax.activeRequestCount > 0) {\n//             Element.show('ajax-indicator');\n//         }\n//     },\n//     onComplete: function(){\n//         if ($('ajax-indicator') && Ajax.activeRequestCount == 0) {\n//             Element.hide('ajax-indicator');\n//         }\n//     }\n// });\n\n$(document).ajaxStart(function() {\n              $('#ajax-indicator').show();\n });\n$(document).ajaxStop(function() {\n              $('#ajax-indicator').hide();\n});\n\n$(document).ajaxSend(function(event, request, settings) {\n  if (typeof(AUTH_TOKEN) == \"undefined\") return;\n  // settings.data is a serialized string like \"foo=bar&baz=boink\" (or null)\n  if (settings.type == 'GET') return; // Don't add anything to a get request let IE turn it into a POST.\n\n  settings.data = settings.data || \"\";\n  settings.data += (settings.data ? \"&\" : \"\") + \"authenticity_token=\" + encodeURIComponent(AUTH_TOKEN);\n});\n\n///HELPERS\nfunction url_for(options){\n  // THINKABOUTTHIS: Is it worth using Rails' routes for this instead?\n  var url = '/' + options['controller'] ;\n  if(options['id']!=null) url += \"/\" + options['id'];\n  if(options['action']!=null && options['action'].match(/index/)==null) url += '/' + options['action'];\n\n  // var keys = Object.keys(options).select(function(key){ return (key!=\"controller\" && key!=\"action\" && key!=\"id\"); });\n  // if(keys.length>0) url += \"?\";\n  //\n  // keys.each(function(key, index){\n  //   url += key + \"=\" + options[key];\n  //   if(index<keys.length-1) url += \"&\";\n  // });\n\n  return url;\n}\n\n//\n// Html encode the strings by escaping the &, <, > and \" characters\n// with their equivalent html counter parts\n//\nfunction h(s) {\n  var escaped = s;\n  escaped = escaped.replace(/\\r\\n/g, \"xxxxxx11\");\n  escaped = escaped.replace(/\\n/g, \"xxxxxx11\");\n  escaped = escaped.replace(/<br>/g, \"xxxxxx11\");\n  escaped = escaped.replace(/&/g, \"&amp;\");\n  escaped = escaped.replace(/</g, \"&lt;\");\n  escaped = escaped.replace(/>/g, \"&gt;\");\n  escaped = escaped.replace(/\\\"/g, \"&quot;\");\n  escaped = escaped.replace(/xxxxxx11/g, \"\\r\\n\");\n\n  return escaped;\n}\n\nfunction text_only(text){\n  text = \"<p>\" + text + \"</p>\";\n  text = $(text).text();\n  return text;\n}\n\n\nfunction display_sparks(){\n  $('.spark').each(function(){\n  $(this).show();\n\n  if(!$(this).attr('max')){\n    return;\n  }\n\n  var max = parseFloat($(this).attr('max'));\n  if (max > 15){\n    max = 15;\n  }\n  if (max == 0){\n    max = 1;\n  }\n\n  $(this).sparkline('html', {type: 'bar' , barColor: 'grey', chartRangeMax: max, height: 15});\n\n  if ($(this).is(\":visible\")){\n    $(this).removeAttr(\"max\"); //so we don't sparkline it again\n  }\n\n\n  // $(this).removeClass(\"spark\");\n\n  // if (isNaN(max)){\n  //     $(this).sparkline('html', {type: 'bar' , barColor: 'grey'});\n  //   }\n  //   else{\n  //     $(this).sparkline('html', {type: 'bar' , barColor: 'grey', height: max});\n  //   }\n  });\n}\n\n//hides right column, and expands left one if right column is empty\n// function hide_empty_right_column(){\n//   if ($('.gt-right-col').html().length < 100){\n//     $('.gt-right-col').hide();\n//     $('.gt-left-col').width('100%');\n//   }\n// }\n\nfunction humane_date(date_str){\n\n      var time_formats = [\n              [60, 'Just Now'],\n              [90, '1 Minute'], // 60*1.5\n              [3600, 'Minutes', 60], // 60*60, 60\n              [5400, '1 Hour'], // 60*60*1.5\n              [86400, 'Hours', 3600], // 60*60*24, 60*60\n              [129600, '1 Day'], // 60*60*24*1.5\n              [604800, 'Days', 86400], // 60*60*24*7, 60*60*24\n              [907200, '1 Week'], // 60*60*24*7*1.5\n              [2628000, 'Weeks', 604800], // 60*60*24*(365/12), 60*60*24*7\n              [3942000, '1 Month'], // 60*60*24*(365/12)*1.5\n              [31536000, 'Months', 2628000], // 60*60*24*365, 60*60*24*(365/12)\n              [47304000, '1 Year'], // 60*60*24*365*1.5\n              [3153600000, 'Years', 31536000], // 60*60*24*365*100, 60*60*24*365\n              [4730400000, '1 Century'] // 60*60*24*365*100*1.5\n      ];\n\n      var dt = new Date,\n          seconds = ((dt - new Date(date_str)) / 1000),\n          token = ' Ago',\n          prepend = '',\n          i = 0,\n          format;\n\n      if (seconds < 0) {\n              seconds = Math.abs(seconds);\n              token = '';\n          prepend = 'In ';\n      }\n\n      while (format = time_formats[i++]) {\n              if (seconds < format[0]) {\n                      if (format.length == 2) {\n                              return (i>1?prepend:'') + format[1] + (i > 1 ? token : ''); // Conditional so we don't return Just Now Ago\n                      } else {\n                              return prepend + Math.round(seconds / format[2]) + ' ' + format[1] + (i > 1 ? token : '');\n                      }\n              }\n      }\n\n      // overflow for centuries\n      if(seconds > 4730400000)\n              return Math.round(seconds / 4730400000) + ' Centuries' + token;\n\n      return date_str;\n  };\n\n\nfunction promptToRemote(text, param, url) {\n    value = prompt(text + ':');\n    if (value) {\n        new Ajax.Request(url + '?' + param + '=' + encodeURIComponent(value), {asynchronous:true, evalScripts:true});\n        return false;\n    }\n}\n\n//param must start with &\nfunction send_remote(url,param,note){\n  top.send_remote(url,param,note)\n  // top.$.ajax({\n  //    type: \"POST\",\n  //    dataType: \"json\",\n  //    url: url,\n  //    data: '&note=' + note + param,\n  //   timeout: 30000 //30 seconds\n  //  });\n}\n\nfunction comment_prompt_to_remote(dataId,title,message,param,url,required){\n\n  var content = '';\n  var note = \"$('#prompt_comment_\" + dataId + \"').val()\" ;\n  content = content + '<div id=\"comment_prompt\"><h2>' + title + '</h2><br>';\n  if (message){\n    content = content + message + '<br><br>';\n  }\n        content = content + '<p><textarea id=\"prompt_comment_' + dataId + '\" class=\"comment_prompt_text\" rows=\"10\" ></textarea></p><br>';\n    content = content + '<p>';\n        content = content + '<input type=\"submit\" onclick=\"$.fancybox.close();send_remote(\\'' + url + '\\',\\'' + param + '\\',' + note + ');\" value=\"Submit\"></input>';\n    if (!required){\n          content = content + '<input type=\"submit\" onclick=\"$.fancybox.close();send_remote(\\'' + url + '\\',\\'' + param + '\\',\\'\\');\" value=\"No Comment\"></input>';\n    }\n        content = content + '<input type=\"submit\" onclick=\"$.fancybox.close();return false;\" value=\"Cancel\"></input>';\n    content = content + '</p><br><br></div>';\n\n  $.fancybox(\n    {\n        'content'      : content,\n        'width'        : 'auto',\n        'height'      : 'auto',\n        'title'        : title,\n            'autoScale'       : false,\n            'transitionIn'    : 'none',\n        'transitionOut'    : 'none',\n        'scrolling'      : 'no',\n        'showCloseButton' : false,\n        'modal' : true,\n        'href'  : '#comment_prompt'\n    });\n\n  $('#prompt_comment_' + dataId).focus();\n}\n\n\n\n$.fn.mybubbletip = function(tip, options) {\n\n    var _this = $(this);\n\n    var _options = {\n      positionAt: 'element', // element | body | mouse\n      positionAtElement: _this,\n      offsetTop: 0,\n      offsetLeft: 0,\n      deltaPosition: 0,\n      deltaDirection: 'up', // direction: up | down | left | right\n      // animationDuration: 250,\n      // animationEasing: 'swing', // linear | swing\n      bindShow: 'mouseover', // mouseover | focus | click | etc.\n      bindHide: 'mouseout', // mouseout | blur | etc.\n      delayShow: 0,\n      delayHide: 500\n    };\n    if (options) {\n      _options = $.extend(_options, options);\n    }\n\n    $(this).bind(_options.bindShow,function() {\n      $(this).bubbletip(tip,_options);\n    });\n};\n\n(function($) {\n    $.fn.getGravatar = function(options) {\n      //debug(this);\n      // build main options before element iteration\n      var opts = $.extend({}, $.fn.getGravatar.defaults, options);\n      // iterate and reformat each matched element\n      return this.each(function() {\n        $this = $(this);\n        // build element specific options\n            var o = $.meta ? $.extend({}, opts, $this.data()) : opts;\n      var t = \"\";\n      //check to see if we're working with an text input first\n            if($this.is(\"input[type='text']\")){\n      //do an initial check of the value\n      $.fn.getGravatar.getUrl(o, $this.val());\n\n      //do our ajax call for the MD5 hash every time a key is released\n      $this.keyup(function(){\n      clearTimeout(t);\n      var email = $this.val();\n      t = setTimeout(function(){$.fn.getGravatar.getUrl(o, email);}, 500);\n    });\n    }\n    });\n  };\n  //\n  // define and expose our functions\n  //\n$.fn.getGravatar.getUrl = function(o, email){\n//call the start function if in use\nif(o.start) o.start($this);\n\n//call MD5 function\nid = email;\n// id = $.fn.getGravatar.md5(email);\nvar gravatar_url = \"https://secure.gravatar.com/avatar.php?gravatar_id=\"+id+\"&size=\"+o.avatarSize;\n//call our function to output the avatar to the container\n    $.fn.getGravatar.output(o.avatarContainer, gravatar_url, o.stop);\n}\n  $.fn.getGravatar.output = function(avatarContainer, gravatar_url, stop) {\n//replace the src of our avatar container with the gravatar url\n$(avatarContainer).attr(\"src\", gravatar_url);\n$(avatarContainer).show();\nif(stop) stop();\n  };\n  $.fn.getGravatar.md5 = function(str) {\n      // Calculate the md5 hash of a string\n      //\n      // version: 909.322\n      // discuss at: http://phpjs.org/functions/md5\n      // + original by: Webtoolkit.info (http://www.webtoolkit.info/)\n      // + namespaced by: Michael White (http://getsprink.com)\n      // + tweaked by: Jack\n      // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\n      // + input by: Brett Zamir (http://brett-zamir.me)\n      // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\n      // - depends on: utf8_encode\n      // * example 1: md5('Kevin van Zonneveld');\n      // * returns 1: '6e658d4bfcb59cc13f96c14450ac40b9'\n      var xl;\n\n      var rotateLeft = function (lValue, iShiftBits) {\n          return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));\n      };\n\n      var addUnsigned = function (lX,lY) {\n          var lX4,lY4,lX8,lY8,lResult;\n          lX8 = (lX & 0x80000000);\n          lY8 = (lY & 0x80000000);\n          lX4 = (lX & 0x40000000);\n          lY4 = (lY & 0x40000000);\n          lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);\n          if (lX4 & lY4) {\n              return (lResult ^ 0x80000000 ^ lX8 ^ lY8);\n          }\n          if (lX4 | lY4) {\n              if (lResult & 0x40000000) {\n                  return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);\n              } else {\n                  return (lResult ^ 0x40000000 ^ lX8 ^ lY8);\n              }\n          } else {\n              return (lResult ^ lX8 ^ lY8);\n          }\n      };\n\n      var _F = function (x,y,z) { return (x & y) | ((~x) & z); };\n      var _G = function (x,y,z) { return (x & z) | (y & (~z)); };\n      var _H = function (x,y,z) { return (x ^ y ^ z); };\n      var _I = function (x,y,z) { return (y ^ (x | (~z))); };\n\n      var _FF = function (a,b,c,d,x,s,ac) {\n          a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));\n          return addUnsigned(rotateLeft(a, s), b);\n      };\n\n      var _GG = function (a,b,c,d,x,s,ac) {\n          a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));\n          return addUnsigned(rotateLeft(a, s), b);\n      };\n\n      var _HH = function (a,b,c,d,x,s,ac) {\n          a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));\n          return addUnsigned(rotateLeft(a, s), b);\n      };\n\n      var _II = function (a,b,c,d,x,s,ac) {\n          a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));\n          return addUnsigned(rotateLeft(a, s), b);\n      };\n\n      var convertToWordArray = function (str) {\n          var lWordCount;\n          var lMessageLength = str.length;\n          var lNumberOfWords_temp1=lMessageLength + 8;\n          var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;\n          var lNumberOfWords = (lNumberOfWords_temp2+1)*16;\n          var lWordArray=new Array(lNumberOfWords-1);\n          var lBytePosition = 0;\n          var lByteCount = 0;\n          while ( lByteCount < lMessageLength ) {\n              lWordCount = (lByteCount-(lByteCount % 4))/4;\n              lBytePosition = (lByteCount % 4)*8;\n              lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount)<<lBytePosition));\n              lByteCount++;\n          }\n          lWordCount = (lByteCount-(lByteCount % 4))/4;\n          lBytePosition = (lByteCount % 4)*8;\n          lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);\n          lWordArray[lNumberOfWords-2] = lMessageLength<<3;\n          lWordArray[lNumberOfWords-1] = lMessageLength>>>29;\n          return lWordArray;\n      };\n\n      var wordToHex = function (lValue) {\n          var wordToHexValue=\"\",wordToHexValue_temp=\"\",lByte,lCount;\n          for (lCount = 0;lCount<=3;lCount++) {\n              lByte = (lValue>>>(lCount*8)) & 255;\n              wordToHexValue_temp = \"0\" + lByte.toString(16);\n              wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length-2,2);\n          }\n          return wordToHexValue;\n      };\n\n      var x=[],\n          k,AA,BB,CC,DD,a,b,c,d,\n          S11=7, S12=12, S13=17, S14=22,\n          S21=5, S22=9 , S23=14, S24=20,\n          S31=4, S32=11, S33=16, S34=23,\n          S41=6, S42=10, S43=15, S44=21;\n\n      str = $.fn.getGravatar.utf8_encode(str);\n      x = convertToWordArray(str);\n      a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;\n\n      xl = x.length;\n      for (k=0;k<xl;k+=16) {\n          AA=a; BB=b; CC=c; DD=d;\n          a=_FF(a,b,c,d,x[k+0], S11,0xD76AA478);\n          d=_FF(d,a,b,c,x[k+1], S12,0xE8C7B756);\n          c=_FF(c,d,a,b,x[k+2], S13,0x242070DB);\n          b=_FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);\n          a=_FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);\n          d=_FF(d,a,b,c,x[k+5], S12,0x4787C62A);\n          c=_FF(c,d,a,b,x[k+6], S13,0xA8304613);\n          b=_FF(b,c,d,a,x[k+7], S14,0xFD469501);\n          a=_FF(a,b,c,d,x[k+8], S11,0x698098D8);\n          d=_FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);\n          c=_FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);\n          b=_FF(b,c,d,a,x[k+11],S14,0x895CD7BE);\n          a=_FF(a,b,c,d,x[k+12],S11,0x6B901122);\n          d=_FF(d,a,b,c,x[k+13],S12,0xFD987193);\n          c=_FF(c,d,a,b,x[k+14],S13,0xA679438E);\n          b=_FF(b,c,d,a,x[k+15],S14,0x49B40821);\n          a=_GG(a,b,c,d,x[k+1], S21,0xF61E2562);\n          d=_GG(d,a,b,c,x[k+6], S22,0xC040B340);\n          c=_GG(c,d,a,b,x[k+11],S23,0x265E5A51);\n          b=_GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);\n          a=_GG(a,b,c,d,x[k+5], S21,0xD62F105D);\n          d=_GG(d,a,b,c,x[k+10],S22,0x2441453);\n          c=_GG(c,d,a,b,x[k+15],S23,0xD8A1E681);\n          b=_GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);\n          a=_GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);\n          d=_GG(d,a,b,c,x[k+14],S22,0xC33707D6);\n          c=_GG(c,d,a,b,x[k+3], S23,0xF4D50D87);\n          b=_GG(b,c,d,a,x[k+8], S24,0x455A14ED);\n          a=_GG(a,b,c,d,x[k+13],S21,0xA9E3E905);\n          d=_GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);\n          c=_GG(c,d,a,b,x[k+7], S23,0x676F02D9);\n          b=_GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);\n          a=_HH(a,b,c,d,x[k+5], S31,0xFFFA3942);\n          d=_HH(d,a,b,c,x[k+8], S32,0x8771F681);\n          c=_HH(c,d,a,b,x[k+11],S33,0x6D9D6122);\n          b=_HH(b,c,d,a,x[k+14],S34,0xFDE5380C);\n          a=_HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);\n          d=_HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);\n          c=_HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);\n          b=_HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);\n          a=_HH(a,b,c,d,x[k+13],S31,0x289B7EC6);\n          d=_HH(d,a,b,c,x[k+0], S32,0xEAA127FA);\n          c=_HH(c,d,a,b,x[k+3], S33,0xD4EF3085);\n          b=_HH(b,c,d,a,x[k+6], S34,0x4881D05);\n          a=_HH(a,b,c,d,x[k+9], S31,0xD9D4D039);\n          d=_HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);\n          c=_HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);\n          b=_HH(b,c,d,a,x[k+2], S34,0xC4AC5665);\n          a=_II(a,b,c,d,x[k+0], S41,0xF4292244);\n          d=_II(d,a,b,c,x[k+7], S42,0x432AFF97);\n          c=_II(c,d,a,b,x[k+14],S43,0xAB9423A7);\n          b=_II(b,c,d,a,x[k+5], S44,0xFC93A039);\n          a=_II(a,b,c,d,x[k+12],S41,0x655B59C3);\n          d=_II(d,a,b,c,x[k+3], S42,0x8F0CCC92);\n          c=_II(c,d,a,b,x[k+10],S43,0xFFEFF47D);\n          b=_II(b,c,d,a,x[k+1], S44,0x85845DD1);\n          a=_II(a,b,c,d,x[k+8], S41,0x6FA87E4F);\n          d=_II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);\n          c=_II(c,d,a,b,x[k+6], S43,0xA3014314);\n          b=_II(b,c,d,a,x[k+13],S44,0x4E0811A1);\n          a=_II(a,b,c,d,x[k+4], S41,0xF7537E82);\n          d=_II(d,a,b,c,x[k+11],S42,0xBD3AF235);\n          c=_II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);\n          b=_II(b,c,d,a,x[k+9], S44,0xEB86D391);\n          a=addUnsigned(a,AA);\n          b=addUnsigned(b,BB);\n          c=addUnsigned(c,CC);\n          d=addUnsigned(d,DD);\n      }\n\n      var temp = wordToHex(a)+wordToHex(b)+wordToHex(c)+wordToHex(d);\n\n      return temp.toLowerCase();\n  }\n  $.fn.getGravatar.utf8_encode = function ( argString ) {\n      // Encodes an ISO-8859-1 string to UTF-8\n      //\n      // version: 909.322\n      // discuss at: http://phpjs.org/functions/utf8_encode\n      // + original by: Webtoolkit.info (http://www.webtoolkit.info/)\n      // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\n      // + improved by: sowberry\n      // + tweaked by: Jack\n      // + bugfixed by: Onno Marsman\n      // + improved by: Yves Sucaet\n      // + bugfixed by: Onno Marsman\n      // + bugfixed by: Ulrich\n      // * example 1: utf8_encode('Kevin van Zonneveld');\n      // * returns 1: 'Kevin van Zonneveld'\n      var string = (argString+''); // .replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n\n      var utftext = \"\";\n      var start, end;\n      var stringl = 0;\n\n      start = end = 0;\n      stringl = string.length;\n      for (var n = 0; n < stringl; n++) {\n          var c1 = string.charCodeAt(n);\n          var enc = null;\n\n          if (c1 < 128) {\n              end++;\n          } else if (c1 > 127 && c1 < 2048) {\n              enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128);\n          } else {\n              enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128);\n          }\n          if (enc !== null) {\n              if (end > start) {\n                  utftext += string.substring(start, end);\n              }\n              utftext += enc;\n              start = end = n+1;\n          }\n      }\n\n      if (end > start) {\n          utftext += string.substring(start, string.length);\n      }\n\n      return utftext;\n  }\n  //\n  // plugin defaults\n  //\n  $.fn.getGravatar.defaults = {\n    fallback: '',\navatarSize: 50,\navatarContainer: '#gravatar',\nstart: null,\nstop: null\n  };\n})(jQuery);\n\n/*\n * bubbletip\n *\n * Copyright (c) 2009, UhLeeKa\n * Version:\n *      1.0.4\n * Licensed under the GPL license:\n *     http://www.gnu.org/licenses/gpl.html\n * Author Website:\n *     http://www.uhleeka.com\n * Description:\n *     A bubble-styled tooltip extension\n *      - multiple tips on a page\n *      - multiple tips per jQuery element\n *      - tips open outward in four directions:\n *         - up\n *         - down\n *         - left\n *         - right\n *      - tips can be:\n *         - anchored to the triggering jQuery element\n *         - absolutely positioned\n *         - opened at the current mouse coordinates\n *         - anchored to a specified jQuery element\n *      - IE png transparency is handled via filters\n */\n  var bindIndex = 0;\n  var mouse_over_bubble = false;\n  $.fn.extend({\n    bubbletip: function(tip, options) {\n      // check to see if the tip is a descendant of\n      // a table.bubbletip element and therefore\n      // has already been instantiated as a bubbletip\n      if ($('table.bubbletip #' + $(tip).id).length > 0) {\n        return this;\n      }\n\n      var _this, _tip, _calc, _timeoutAnimate, _timeoutRefresh, _isActive, _isHiding, _wrapper, _bindIndex;\n\n      _this = $(this);\n      _tip = $(tip);\n      _bindIndex = bindIndex++;  // for window.resize namespace binding\n\n      var _options = {\n        positionAt: 'element', // element | body | mouse\n        positionAtElement: _this,\n        offsetTop: 0,\n        offsetLeft: 0,\n        deltaPosition: 0,\n        deltaDirection: 'up', // direction: up | down | left | right\n        animationDuration: 0,\n        // animationEasing: 'swing', // linear | swing\n        bindShow: 'mouseover', // mouseover | focus | click | etc.\n        bindHide: 'mouseout', // mouseout | blur | etc.\n        delayShow: 0,\n        delayHide: 500\n      };\n      if (options) {\n        _options = $.extend(_options, options);\n      }\n\n\n      // calculated values\n      _calc = {\n        top: 0,\n        left: 0,\n        delta: 0,\n        mouseTop: 0,\n        mouseLeft: 0,\n        tipHeight: 0,\n        bindShow: (_options.bindShow + ' ').replace(/ +/g, '.bubbletip' + _bindIndex),\n        bindHide: (_options.bindHide + ' ').replace(/ +/g, '.bubbletip' + _bindIndex)\n      };\n      _timeoutAnimate = null;\n      _timeoutRefresh = null;\n      _isActive = false;\n      _isHiding = false;\n\n      // store the tip id for removeBubbletip\n      if (!_this.data('bubbletip_tips')) {\n        _this.data('bubbletip_tips', [[_tip.get(0).id, _calc.bindShow, _calc.bindHide, _bindIndex]]);\n      } else {\n        _this.data('bubbletip_tips', $.merge(_this.data('bubbletip_tips'), [[_tip.get(0).id, _calc.bindShow, _calc.bindHide, _bindIndex]]));\n      }\n\n\n      // validate _options\n      if (!_options.positionAt.match(/^element|body|mouse$/i)) {\n        _options.positionAt = 'element';\n      }\n      if (!_options.deltaDirection.match(/^up|down|left|right$/i)) {\n        _options.deltaDirection = 'up';\n      }\n\n      // create the wrapper table element\n      create_wrapper(false);\n\n      _Calculate(true);\n\n\n\n      show_tip();\n\n\n\n    //    return false;\n      $('.bubbletip').bind('mouseover',function(){\n        mouse_over_bubble = true;\n      });\n\n      $('.bubbletip').bind('mouseout', function() {\n              mouse_over_bubble = false; //BUGBUG: change to false\n      });\n\n      $([_wrapper.get(0), this.get(0)]).bind(_calc.bindHide, function() {\n              if (_timeoutAnimate) {\n                clearTimeout(_timeoutAnimate);\n              }\n              _timeoutAnimate = setTimeout(function() {\n                if (!mouse_over_bubble)\n                {\n                  _HideWrapper();\n                  // _tip.appendTo('body');\n                   // $('.bubbletip').remove();\n                  //removeBubbletip(tip);\n                }\n\n              }, _options.delayHide);\n\n              return false;\n            });\n\n      function show_tip(){\n        if (_timeoutAnimate) {\n          clearTimeout(_timeoutAnimate);\n        }\n        _timeoutAnimate = setTimeout(function() {\n          if (_isActive) {\n            return;\n          }\n          _isActive = true;\n          if (_isHiding) {\n            _wrapper.stop(true, false);\n          }\n\n          var animation;\n\n          if (_options.positionAt.match(/^element|body$/i)) {\n            if (_options.deltaDirection.match(/^up|down$/i)) {\n              if (!_isHiding) {\n                _wrapper.css('top', parseInt(_calc.top + _calc.delta,10) + 'px');\n              }\n              animation = { 'opacity': 1, 'top': _calc.top + 'px' };\n            } else {\n              if (!_isHiding) {\n                _wrapper.css('left', parseInt(_calc.left + _calc.delta,10) + 'px');\n              }\n              animation = { 'opacity': 1, 'left': _calc.left + 'px' };\n            }\n          } else {\n            if (_options.deltaDirection.match(/^up|down$/i)) {\n              if (!_isHiding) {\n                _calc.mouseTop = e.pageY + _calc.top;\n                _wrapper.css({ 'top': parseInt(_calc.mouseTop + _calc.delta,10) + 'px', 'left': parseInt(e.pageX - (_wrapper.width() / 2),10) + 'px' });\n              }\n              animation = { 'opacity': 1, 'top': _calc.mouseTop + 'px' };\n            } else {\n              if (!_isHiding) {\n                _calc.mouseLeft = e.pageX + _calc.left;\n                _wrapper.css({ 'left': parseInt(_calc.mouseLeft + _calc.delta,10) + 'px', 'top': parseInt(e.pageY - (_wrapper.height() / 2),10) + 'px' });\n              }\n              animation = { 'opacity': 1, 'left': _calc.left + 'px' };\n            }\n          }\n          _isHiding = false;\n          _wrapper.show();\n          _wrapper.animate(animation, _options.animationDuration, _options.animationEasing, function() {\n            _wrapper.css('opacity', '');\n            _isActive = true;\n            // $('.bubbletip').remove();\n\n          });\n        }, _options.delayShow);\n\n      }\n\n      function create_wrapper(noTip){\n        if (noTip)\n        {\n          _wrapper = $('<table class=\"bubbletip\" cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"bt-topleft\"></td><td class=\"bt-top\"></td><td class=\"bt-topright\"></td></tr><tr><td class=\"bt-left\"></td><td class=\"bt-content\"></td><td class=\"bt-right\"></td></tr><tr><td class=\"bt-bottomleft\"></td><td class=\"bt-bottom\"></td><td class=\"bt-bottomright\"></td></tr></tbody></table>');\n\n        }\n        else\n        {\n          if (_options.deltaDirection.match(/^up$/i)) {\n            _wrapper = $('<table class=\"bubbletip\" cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"bt-topleft\"></td><td class=\"bt-top\"></td><td class=\"bt-topright\"></td></tr><tr><td class=\"bt-left\"></td><td class=\"bt-content\"></td><td class=\"bt-right\"></td></tr><tr><td class=\"bt-bottomleft\"></td><td><table class=\"bt-bottom\" cellspacing=\"0\" cellpadding=\"0\"><tr><th></th><td><div></div></td><th></th></tr></table></td><td class=\"bt-bottomright\"></td></tr></tbody></table>');\n          } else if (_options.deltaDirection.match(/^down$/i)) {\n            _wrapper = $('<table class=\"bubbletip\" cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"bt-topleft\"></td><td><table class=\"bt-top\" cellspacing=\"0\" cellpadding=\"0\"><tr><th></th><td><div></div></td><th></th></tr></table></td><td class=\"bt-topright\"></td></tr><tr><td class=\"bt-left\"></td><td class=\"bt-content\"></td><td class=\"bt-right\"></td></tr><tr><td class=\"bt-bottomleft\"></td><td class=\"bt-bottom\"></td><td class=\"bt-bottomright\"></td></tr></tbody></table>');\n          } else if (_options.deltaDirection.match(/^left$/i)) {\n            _wrapper = $('<table class=\"bubbletip\" cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"bt-topleft\"></td><td class=\"bt-top\"></td><td class=\"bt-topright\"></td></tr><tr><td class=\"bt-left\"></td><td class=\"bt-content\"></td><td class=\"bt-right-tail\"><div class=\"bt-right\"></div><div class=\"bt-right-tail\"></div><div class=\"bt-right\"></div></td></tr><tr><td class=\"bt-bottomleft\"></td><td class=\"bt-bottom\"></td><td class=\"bt-bottomright\"></td></tr></tbody></table>');\n          } else if (_options.deltaDirection.match(/^right$/i)) {\n            _wrapper = $('<table class=\"bubbletip\" cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"bt-topleft\"></td><td class=\"bt-top\"></td><td class=\"bt-topright\"></td></tr><tr><td class=\"bt-left-tail\"><div class=\"bt-left\"></div><div class=\"bt-left-tail\"></div><div class=\"bt-left\"></div></td><td class=\"bt-content\"></td><td class=\"bt-right\"></td></tr><tr><td class=\"bt-bottomleft\"></td><td class=\"bt-bottom\"></td><td class=\"bt-bottomright\"></td></tr></tbody></table>');\n          }\n        }\n\n\n        // append the wrapper to the document body\n        _wrapper.appendTo('body');\n        _wrapper.width(_tip.width() + 66);\n\n        // apply IE filters to _wrapper elements\n        if ((/msie/.test(navigator.userAgent.toLowerCase())) && (!/opera/.test(navigator.userAgent.toLowerCase()))) {\n          $('*', _wrapper).each(function() {\n            var image = $(this).css('background-image');\n            if (image.match(/^url\\([\"']?(.*\\.png)[\"']?\\)$/i)) {\n              image = RegExp.$1;\n              $(this).css({\n                'backgroundImage': 'none',\n                'filter': 'progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=' + ($(this).css('backgroundRepeat') == 'no-repeat' ? 'crop' : 'scale') + ', src=\\'' + image + '\\')'\n              }).each(function() {\n                var position = $(this).css('position');\n                if (position != 'absolute' && position != 'relative')\n                  $(this).css('position', 'relative');\n              });\n            }\n          });\n        }\n\n        // move the tip element into the content section of the wrapper\n        $('.bt-content', _wrapper).append(_tip);\n        // show the tip (in case it is hidden) so that we can calculate its dimensions\n        _tip.show();\n        // handle left|right delta\n        if (_options.deltaDirection.match(/^left|right$/i)) {\n          // tail is 40px, so divide height by two and subtract 20px;\n          _calc.tipHeight = parseInt(_tip.height() / 2,10);\n          // handle odd integer height\n          if ((_tip.height() % 2) == 1) {\n            _calc.tipHeight++;\n          }\n          _calc.tipHeight = (_calc.tipHeight < 20) ? 1 : _calc.tipHeight - 20;\n          if (_options.deltaDirection.match(/^left$/i)) {\n            $('div.bt-right', _wrapper).css('height', _calc.tipHeight + 'px');\n          } else {\n            $('div.bt-left', _wrapper).css('height', _calc.tipHeight + 'px');\n          }\n        }\n        // set the opacity of the wrapper to 0\n        _wrapper.css('opacity', 0);\n        // execute initial calculations\n\n\n      }\n\n      function _HideWrapper() {\n        var animation;\n\n        _isActive = false;\n        _isHiding = true;\n        if (_options.positionAt.match(/^element|body$/i)) {\n          if (_options.deltaDirection.match(/^up|down$/i)) {\n            animation = { 'opacity': 0, 'top': parseInt(_calc.top - _calc.delta,10) + 'px' };\n          } else {\n            animation = { 'opacity': 0, 'left': parseInt(_calc.left - _calc.delta,10) + 'px' };\n          }\n        } else {\n          if (_options.deltaDirection.match(/^up|down$/i)) {\n            animation = { 'opacity': 0, 'top': parseInt(_calc.mouseTop - _calc.delta,10) + 'px' };\n          } else {\n            animation = { 'opacity': 0, 'left': parseInt(_calc.mouseLeft - _calc.delta,10) + 'px' };\n          }\n        }\n        _wrapper.animate(animation, _options.animationDuration, _options.animationEasing, function() {\n          _wrapper.hide();\n          _isHiding = false;\n          _tip.appendTo('body');\n          _tip.hide();\n          _wrapper.hide();\n          _wrapper.addClass('oldbubble');\n          $('.oldbubble').hide();\n        });\n      };\n\n      function _Calculate(firstTime) {\n\n        // calculate values\n        if (_options.positionAt.match(/^element$/i)) {\n          var offset = _options.positionAtElement.offset();\n          if (_options.deltaDirection.match(/^up$/i)) {\n            _calc.top = offset.top + _options.offsetTop - _wrapper.height();\n            _calc.left = offset.left + _options.offsetLeft + ((_options.positionAtElement.width() - _wrapper.width()) / 2);\n            _calc.delta = _options.deltaPosition;\n          } else if (_options.deltaDirection.match(/^down$/i)) {\n            _calc.top = offset.top + _options.positionAtElement.height() + _options.offsetTop;\n            _calc.left = offset.left + _options.offsetLeft + ((_options.positionAtElement.width() - _wrapper.width()) / 2);\n            _calc.delta = -_options.deltaPosition;\n          } else if (_options.deltaDirection.match(/^left$/i)) {\n            _calc.top = offset.top + _options.offsetTop + ((_options.positionAtElement.height() - _wrapper.height()) / 2);\n            _calc.left = offset.left + _options.offsetLeft - _wrapper.width();\n            _calc.delta = _options.deltaPosition;\n          } else if (_options.deltaDirection.match(/^right$/i)) {\n            _calc.top = offset.top + _options.offsetTop + ((_options.positionAtElement.height() - _wrapper.height()) / 2);\n            _calc.left = offset.left + _options.positionAtElement.width() + _options.offsetLeft;\n            _calc.delta = -_options.deltaPosition;\n          }\n        } else if (_options.positionAt.match(/^body$/i)) {\n          if (_options.deltaDirection.match(/^up|left$/i)) {\n            _calc.top = _options.offsetTop;\n            _calc.left = _options.offsetLeft;\n            // up or left\n            _calc.delta = _options.deltaPosition;\n          } else {\n            if (_options.deltaDirection.match(/^down$/i)) {\n              _calc.top = parseInt(_options.offsetTop + _wrapper.height(),10);\n              _calc.left = _options.offsetLeft;\n            } else {\n              _calc.top = _options.offsetTop;\n              _calc.left = parseInt(_options.offsetLeft + _wrapper.width(),10);\n            }\n            // down or right\n            _calc.delta = -_options.deltaPosition;\n          }\n        } else if (_options.positionAt.match(/^mouse$/i)) {\n          if (_options.deltaDirection.match(/^up|left$/i)) {\n            if (_options.deltaDirection.match(/^up$/i)) {\n              _calc.top = -(_options.offsetTop + _wrapper.height());\n              _calc.left = _options.offsetLeft;\n            } else if (_options.deltaDirection.match(/^left$/i)) {\n              _calc.top = _options.offsetTop;\n              _calc.left = -(_options.offsetLeft + _wrapper.width());\n            }\n            // up or left\n            _calc.delta = _options.deltaPosition;\n          } else {\n            _calc.top = _options.offsetTop;\n            _calc.left = _options.offsetLeft;\n            // down or right\n            _calc.delta = -_options.deltaPosition;\n          }\n        }\n\n        //Flip\n        //first handle corners\n\n        // //bottom right\n        // if (((_calc.left + _wrapper.width()) > $(window).width())&&((_calc.top + _wrapper.height()) > $(window).height())){\n        //   create_wrapper(true);\n        //    _calc.top = $(window).height() - _wrapper.height();\n        //   _calc.left = $(window).width() - _wrapper.width();\n        // }\n        //\n        // //bottom left\n        // if ((_calc.left < 0)&&((_calc.top + _wrapper.height()) > $(window).height())){\n        //   create_wrapper(true);\n        //    _calc.top = $(window).height() - _wrapper.height();\n        //   _calc.left = 0;\n        // }\n        //\n        // //top right\n        // if (((_calc.left + _wrapper.width()) > $(window).width())&&((_calc.top < 0))){\n        //   create_wrapper(true);\n        //    _calc.top = 0;\n        //   _calc.left = $(window).width() - _wrapper.width();\n        // }\n        //\n        // //top left\n        // if ((_calc.left < 0)&&(_calc.top < 0 )){\n        //   create_wrapper(true);\n        //    _calc.top = 0;\n        //   _calc.left = 0;\n        // }\n\n\n\n        if (_calc.top < 0){\n          _options.deltaDirection = \"down\";\n          if (firstTime)\n          {\n            create_wrapper(false);\n            _Calculate(false);\n            return false;\n          }\n        }\n\n        if (_calc.left < 0){\n          _options.deltaDirection = \"right\";\n          if (firstTime)\n          {\n            create_wrapper(false);\n            _Calculate(false);\n            return false;\n          }\n        }\n\n        if ((_calc.left + _wrapper.width()) > $(window).width()){\n          _options.deltaDirection = \"left\";\n          if (firstTime)\n          {\n            create_wrapper(false);\n            _Calculate(false);\n            return false;\n          }\n        }\n\n        if ((_calc.top + _wrapper.height()) > $(window).height()){\n          _options.deltaDirection = \"up\";\n          if (firstTime)\n          {\n            create_wrapper(false);\n            _Calculate(false);\n            return false;\n          }\n        }\n\n        //Nudge edges\n        if ((_calc.left + _wrapper.width()) > $(window).width()){\n           create_wrapper(true);\n           _calc.left = $(window).width() - _wrapper.width();\n        }\n\n        // if ((_calc.top + _wrapper.height()) > $(window).height()){\n        //    create_wrapper(true);\n        //     _calc.top = $(window).height() - _wrapper.height();\n        // }\n\n        if (_calc.left < 0){\n           create_wrapper(true);\n            _calc.left = 0;\n        }\n\n        if (_calc.top < 0){\n           create_wrapper(true);\n            _calc.top = 0;\n        }\n\n\n\n\n        // hide\n        _wrapper.hide();\n        _wrapper.addClass('oldbubble');\n        $('.oldbubble').hide();\n\n        // handle the wrapper (element|body) positioning\n        if (_options.positionAt.match(/^element|body$/i)) {\n          _wrapper.css({\n            'position': 'absolute',\n            'top': _calc.top + 'px',\n            'left': _calc.left + 'px'\n          });\n        }\n\n        return true;\n      };\n      return this;\n    }// ,\n    //     removeBubbletip: function(tips) {\n    //         $('.bubbletip').remove();\n    //         var tipsActive;\n    //         var tipsToRemove = new Array();\n    //         var arr, i, ix;\n    //         var elem;\n    //\n    //         tipsActive = $.makeArray($(this).data('bubbletip_tips'));\n    //\n    //         // convert the parameter array of tip id's or elements to id's\n    //         arr = $.makeArray(tips);\n    //         for (i = 0; i < arr.length; i++) {\n    //           tipsToRemove.push($(arr[i]).get(0).id);\n    //         }\n    //\n    //         for (i = 0; i < tipsActive.length; i++) {\n    //           ix = null;\n    //           if ((tipsToRemove.length == 0) || ((ix = $.inArray(tipsActive[i][0], tipsToRemove)) >= 0)) {\n    //             // remove all tips if there are none specified\n    //             // otherwise, remove only specified tips\n    //\n    //             // find the surrounding table.bubbletip\n    //             elem = $('#' + tipsActive[i][0]).get(0).parentNode;\n    //             while (elem.tagName.toLowerCase() != 'table') {\n    //               elem = elem.parentNode;\n    //             }\n    //             // attach the tip element to body and hide\n    //             $(tipsActive[i][0]).appendTo('body').hide();\n    //             // remove the surrounding table.bubbletip\n    //             $(elem).remove();\n    //\n    //             // unbind show/hide events\n    //             $(this).unbind(tipsActive[i][1]).unbind([i][2]);\n    //\n    //             // unbind window.resize event\n    //             $(window).unbind('resize.bubbletip' + tipsActive[i][3]);\n    //           }\n    //         }\n    //\n    //         return this;\n    //       }\n  });\n\n\n  /*\n   * Date Format 1.2.3\n   * (c) 2007-2009 Steven Levithan <stevenlevithan.com>\n   * MIT license\n   *\n   * Includes enhancements by Scott Trenda <scott.trenda.net>\n   * and Kris Kowal <cixar.com/~kris.kowal/>\n   *\n   * Accepts a date, a mask, or a date and a mask.\n   * Returns a formatted version of the given date.\n   * The date defaults to the current date/time.\n   * The mask defaults to dateFormat.masks.default.\n   */\n\n  var dateFormat = function () {\n    var  token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\\1?|[LloSZ]|\"[^\"]*\"|'[^']*'/g,\n      timezone = /\\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\\d{4})?)\\b/g,\n      timezoneClip = /[^-+\\dA-Z]/g,\n      pad = function (val, len) {\n        val = String(val);\n        len = len || 2;\n        while (val.length < len) val = \"0\" + val;\n        return val;\n      };\n\n    // Regexes and supporting functions are cached through closure\n    return function (date, mask, utc) {\n      var dF = dateFormat;\n\n      // You can't provide utc if you skip other args (use the \"UTC:\" mask prefix)\n      if (arguments.length == 1 && Object.prototype.toString.call(date) == \"[object String]\" && !/\\d/.test(date)) {\n        mask = date;\n        date = undefined;\n      }\n\n      // Passing date through Date applies Date.parse, if necessary\n      date = date ? new Date(date) : new Date;\n      if (isNaN(date)) throw SyntaxError(\"invalid date\");\n\n      mask = String(dF.masks[mask] || mask || dF.masks[\"default\"]);\n\n      // Allow setting the utc argument via the mask\n      if (mask.slice(0, 4) == \"UTC:\") {\n        mask = mask.slice(4);\n        utc = true;\n      }\n\n      var  _ = utc ? \"getUTC\" : \"get\",\n        d = date[_ + \"Date\"](),\n        D = date[_ + \"Day\"](),\n        m = date[_ + \"Month\"](),\n        y = date[_ + \"FullYear\"](),\n        H = date[_ + \"Hours\"](),\n        M = date[_ + \"Minutes\"](),\n        s = date[_ + \"Seconds\"](),\n        L = date[_ + \"Milliseconds\"](),\n        o = utc ? 0 : date.getTimezoneOffset(),\n        flags = {\n          d:    d,\n          dd:   pad(d),\n          ddd:  dF.i18n.dayNames[D],\n          dddd: dF.i18n.dayNames[D + 7],\n          m:    m + 1,\n          mm:   pad(m + 1),\n          mmm:  dF.i18n.monthNames[m],\n          mmmm: dF.i18n.monthNames[m + 12],\n          yy:   String(y).slice(2),\n          yyyy: y,\n          h:    H % 12 || 12,\n          hh:   pad(H % 12 || 12),\n          H:    H,\n          HH:   pad(H),\n          M:    M,\n          MM:   pad(M),\n          s:    s,\n          ss:   pad(s),\n          l:    pad(L, 3),\n          L:    pad(L > 99 ? Math.round(L / 10) : L),\n          t:    H < 12 ? \"a\"  : \"p\",\n          tt:   H < 12 ? \"am\" : \"pm\",\n          T:    H < 12 ? \"A\"  : \"P\",\n          TT:   H < 12 ? \"AM\" : \"PM\",\n          Z:    utc ? \"UTC\" : (String(date).match(timezone) || [\"\"]).pop().replace(timezoneClip, \"\"),\n          o:    (o > 0 ? \"-\" : \"+\") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),\n          S:    [\"th\", \"st\", \"nd\", \"rd\"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]\n        };\n\n      return mask.replace(token, function ($0) {\n        return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);\n      });\n    };\n  }();\n\n  // Some common format strings\n  dateFormat.masks = {\n    \"default\":      \"ddd mmm dd yyyy HH:MM:ss\",\n    shortDate:      \"m/d/yy\",\n    mediumDate:     \"mmm d, yyyy\",\n    longDate:       \"mmmm d, yyyy\",\n    fullDate:       \"dddd, mmmm d, yyyy\",\n    shortTime:      \"h:MM TT\",\n    mediumTime:     \"h:MM:ss TT\",\n    longTime:       \"h:MM:ss TT Z\",\n    isoDate:        \"yyyy-mm-dd\",\n    isoTime:        \"HH:MM:ss\",\n    isoDateTime:    \"yyyy-mm-dd'T'HH:MM:ss\",\n    isoUtcDateTime: \"UTC:yyyy-mm-dd'T'HH:MM:ss'Z'\"\n  };\n\n  // Internationalization strings\n  dateFormat.i18n = {\n    dayNames: [\n      \"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\",\n      \"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"\n    ],\n    monthNames: [\n      \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n      \"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"\n    ]\n  };\n\n  jQuery.fn.texthighlight = function(pat) {\n   function innerHighlight(node, pat) {\n    var skip = 0;\n    if (node.nodeType == 3) {\n     var pos = node.data.toUpperCase().indexOf(pat);\n     if (pos >= 0) {\n      var spannode = document.createElement('span');\n      spannode.className = 'search-highlight';\n      var middlebit = node.splitText(pos);\n      var endbit = middlebit.splitText(pat.length);\n      var middleclone = middlebit.cloneNode(true);\n      spannode.appendChild(middleclone);\n      middlebit.parentNode.replaceChild(spannode, middlebit);\n      skip = 1;\n     }\n    }\n    else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {\n     for (var i = 0; i < node.childNodes.length; ++i) {\n      i += innerHighlight(node.childNodes[i], pat);\n     }\n    }\n    return skip;\n   }\n   return this.each(function() {\n    innerHighlight(this, pat.toUpperCase());\n   });\n  };\n\n  jQuery.fn.removeHighlight = function() {\n   return this.find(\"span.search-highlight\").each(function() {\n    this.parentNode.firstChild.nodeName;\n    with (this.parentNode) {\n     replaceChild(this.firstChild, this);\n     normalize();\n    }\n   }).end();\n  };\n\n\n  jQuery.timer = function (interval, callback)\n   {\n   /**\n    *\n    * timer() provides a cleaner way to handle intervals\n    *\n    *  @usage\n    * $.timer(interval, callback);\n    *\n    *\n    * @example\n    * $.timer(1000, function (timer) {\n    *   alert(\"hello\");\n    *   timer.stop();\n    * });\n    * @desc Show an alert box after 1 second and stop\n    *\n    * @example\n    * var second = false;\n    *  $.timer(1000, function (timer) {\n    *    if (!second) {\n    *      alert('First time!');\n    *      second = true;\n    *      timer.reset(3000);\n    *    }\n    *    else {\n    *      alert('Second time');\n    *      timer.stop();\n    *    }\n    *  });\n    * @desc Show an alert box after 1 second and show another after 3 seconds\n    *\n    *\n    */\n\n    var interval = interval || 100;\n\n    if (!callback)\n      return false;\n\n    _timer = function (interval, callback) {\n      this.stop = function () {\n        clearInterval(self.id);\n      };\n\n      this.internalCallback = function () {\n        callback(self);\n      };\n\n      this.reset = function (val) {\n        if (self.id)\n          clearInterval(self.id);\n\n        var val = val || 100;\n        this.id = setInterval(this.internalCallback, val);\n      };\n\n      this.interval = interval;\n      this.id = setInterval(this.internalCallback, this.interval);\n\n      var self = this;\n    };\n\n    return new _timer(interval, callback);\n   };\n\n\n  /*\n  *\n  * Copyright (c) 2006-2008 Sam Collett (http://www.texotela.co.uk)\n  * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)\n  * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.\n  *\n  * Version 2.2.4\n  * Demo: http://www.texotela.co.uk/code/jquery/select/\n  *\n  * $LastChangedDate: 2008-06-17 17:27:25 +0100 (Tue, 17 Jun 2008) $\n  * $Rev: 5727 $\n  *\n  */\n  ;(function(h){h.fn.addOption=function(){var j=function(a,f,c,g){var d=document.createElement(\"option\");d.value=f,d.text=c;var b=a.options;var e=b.length;if(!a.cache){a.cache={};for(var i=0;i<e;i++){a.cache[b[i].value]=i}}if(typeof a.cache[f]==\"undefined\")a.cache[f]=e;a.options[a.cache[f]]=d;if(g){d.selected=true}};var k=arguments;if(k.length==0)return this;var l=true;var m=false;var n,o,p;if(typeof(k[0])==\"object\"){m=true;n=k[0]}if(k.length>=2){if(typeof(k[1])==\"boolean\")l=k[1];else if(typeof(k[2])==\"boolean\")l=k[2];if(!m){o=k[0];p=k[1]}}this.each(function(){if(this.nodeName.toLowerCase()!=\"select\")return;if(m){for(var a in n){j(this,a,n[a],l)}}else{j(this,o,p,l)}});return this};h.fn.ajaxAddOption=function(c,g,d,b,e){if(typeof(c)!=\"string\")return this;if(typeof(g)!=\"object\")g={};if(typeof(d)!=\"boolean\")d=true;this.each(function(){var f=this;h.getJSON(c,g,function(a){h(f).addOption(a,d);if(typeof b==\"function\"){if(typeof e==\"object\"){b.apply(f,e)}else{b.call(f)}}})});return this};h.fn.removeOption=function(){var d=arguments;if(d.length==0)return this;var b=typeof(d[0]);var e,i;if(b==\"string\"||b==\"object\"||b==\"function\"){e=d[0];if(e.constructor==Array){var j=e.length;for(var k=0;k<j;k++){this.removeOption(e[k],d[1])}return this}}else if(b==\"number\")i=d[0];else return this;this.each(function(){if(this.nodeName.toLowerCase()!=\"select\")return;if(this.cache)this.cache=null;var a=false;var f=this.options;if(!!e){var c=f.length;for(var g=c-1;g>=0;g--){if(e.constructor==RegExp){if(f[g].value.match(e)){a=true}}else if(f[g].value==e){a=true}if(a&&d[1]===true)a=f[g].selected;if(a){f[g]=null}a=false}}else{if(d[1]===true){a=f[i].selected}else{a=true}if(a){this.remove(i)}}});return this};h.fn.sortOptions=function(e){var i=h(this).selectedValues();var j=typeof(e)==\"undefined\"?true:!!e;this.each(function(){if(this.nodeName.toLowerCase()!=\"select\")return;var c=this.options;var g=c.length;var d=[];for(var b=0;b<g;b++){d[b]={v:c[b].value,t:c[b].text}}d.sort(function(a,f){o1t=a.t.toLowerCase(),o2t=f.t.toLowerCase();if(o1t==o2t)return 0;if(j){return o1t<o2t?-1:1}else{return o1t>o2t?-1:1}});for(var b=0;b<g;b++){c[b].text=d[b].t;c[b].value=d[b].v}}).selectOptions(i,true);return this};h.fn.selectOptions=function(g,d){var b=g;var e=typeof(g);if(e==\"object\"&&b.constructor==Array){var i=this;h.each(b,function(){i.selectOptions(this,d)})};var j=d||false;if(e!=\"string\"&&e!=\"function\"&&e!=\"object\")return this;this.each(function(){if(this.nodeName.toLowerCase()!=\"select\")return this;var a=this.options;var f=a.length;for(var c=0;c<f;c++){if(b.constructor==RegExp){if(a[c].value.match(b)){a[c].selected=true}else if(j){a[c].selected=false}}else{if(a[c].value==b){a[c].selected=true}else if(j){a[c].selected=false}}}});return this};h.fn.copyOptions=function(g,d){var b=d||\"selected\";if(h(g).size()==0)return this;this.each(function(){if(this.nodeName.toLowerCase()!=\"select\")return this;var a=this.options;var f=a.length;for(var c=0;c<f;c++){if(b==\"all\"||(b==\"selected\"&&a[c].selected)){h(g).addOption(a[c].value,a[c].text)}}});return this};h.fn.containsOption=function(g,d){var b=false;var e=g;var i=typeof(e);var j=typeof(d);if(i!=\"string\"&&i!=\"function\"&&i!=\"object\")return j==\"function\"?this:b;this.each(function(){if(this.nodeName.toLowerCase()!=\"select\")return this;if(b&&j!=\"function\")return false;var a=this.options;var f=a.length;for(var c=0;c<f;c++){if(e.constructor==RegExp){if(a[c].value.match(e)){b=true;if(j==\"function\")d.call(a[c],c)}}else{if(a[c].value==e){b=true;if(j==\"function\")d.call(a[c],c)}}}});return j==\"function\"?this:b};h.fn.selectedValues=function(){var a=[];this.selectedOptions().each(function(){a[a.length]=this.value});return a};h.fn.selectedTexts=function(){var a=[];this.selectedOptions().each(function(){a[a.length]=this.text});return a};h.fn.selectedOptions=function(){return this.find(\"option:selected\")}})(jQuery);\n\n\n  (function($) {\n    $.fn.breakWords = function() {\n      this.each(function() {\n        if(this.nodeType !== 1) { return; }\n\n        if(this.currentStyle && typeof this.currentStyle.wordBreak === 'string') {\n          //Lazy Function Definition Pattern, Peter's Blog\n          //From http://peter.michaux.ca/article/3556\n          this.runtimeStyle.wordBreak = 'break-all';\n        }\n        else if(document.createTreeWalker) {\n\n          //Faster Trim in Javascript, Flagrant Badassery\n          //http://blog.stevenlevithan.com/archives/faster-trim-javascript\n\n          var trim = function(str) {\n            str = str.replace(/^\\s\\s*/, '');\n            var ws = /\\s/,\n            i = str.length;\n            while (ws.test(str.charAt(--i)));\n            return str.slice(0, i + 1);\n          };\n\n          //Lazy Function Definition Pattern, Peter's Blog\n          //From http://peter.michaux.ca/article/3556\n\n          //For Opera, Safari, and Firefox\n          var dWalker = document.createTreeWalker(this, NodeFilter.SHOW_TEXT, null, false);\n          var node,s,c = String.fromCharCode('8203');\n          while (dWalker.nextNode()) {\n            node = dWalker.currentNode;\n            //we need to trim String otherwise Firefox will display\n            //incorect text-indent with space characters\n        words = node.nodeValue.split(' ');\n        for (var i = 0; i < words.length; i++){\n        if (words[i].length > 15){\n          words[i] = trim(words[i].split('').join(c));\n        }\n        }\n            node.nodeValue = words.join(' ');\n          }\n        }\n      });\n\n      return this;\n    };\n  })(jQuery);\n\n  function wbr(string,length){\n    string =  string.replace(/(?:<[^>]+>)|(.{20})/g,'$&<wbr/>');\n    return string.replace(/><wbr\\/>/,'>');\n  }\n\n\n  /*\n  * Auto-growing textareas; technique ripped from Facebook\n  */\n      $.fn.autogrow = function(options) {\n\n          this.filter('textarea').each(function() {\n\n              var $this = $(this),\n                  minHeight = $this.height(),\n                  lineHeight = $this.css('lineHeight');\n\n              var shadow = $('<div></div>').css({\n                  position: 'absolute',\n                  top: -10000,\n                  left: -10000,\n                  width: $(this).width() - parseInt($this.css('paddingLeft'),10) - parseInt($this.css('paddingRight'),10),\n                  fontSize: $this.css('fontSize'),\n                  fontFamily: $this.css('fontFamily'),\n                  lineHeight: $this.css('lineHeight'),\n                  resize: 'none'\n              }).appendTo(document.body);\n\n              var update = function() {\n\n                  var times = function(string, number) {\n                      for (var i = 0, r = ''; i < number; i ++) r += string;\n                      return r;\n                  };\n\n                  var val = this.value.replace(/</g, '&lt;')\n                                      .replace(/>/g, '&gt;')\n                                      .replace(/&/g, '&amp;')\n                                      .replace(/\\n$/, '<br/>&nbsp;')\n                                      .replace(/\\n/g, '<br/>')\n                                      .replace(/ {2,}/g, function(space) { return times('&nbsp;', space.length -1) + ' ' ;});\n\n                  shadow.html(val);\n                  $(this).css('height', Math.max(shadow.height() + 20, minHeight));\n\n              };\n\n              $(this).change(update).keyup(update).keydown(update);\n\n              update.apply(this);\n\n          });\n\n          return this;\n\n      };\n\n\n(function( $ ){\n\n  //Auto complete code for @mentions\n  //To attach to a textarea add this class: autocomplete-mentions and the script below\n  // <script type=\"text/javascript\">\n  // projectId = <%= @project.id %>;\n  // </script>\n  //or just directly run $('#widget').mentions(projectId);\n  //or add a property to the text area autocomplete-mentions-projectid=\"<%= as.project_id %>\"\n  // \"autocomplete-mentions-projectid\" => @project.id\n\n   function getCaretPosition(e) {\n       if (typeof e.selectionStart == 'number') {\n           return e.selectionStart;\n       } else if (document.selection) {\n           var range = document.selection.createRange();\n           var rangeLength = range.text.length;\n           range.moveStart('character', -e.value.length);\n           return range.text.length - rangeLength;\n       }\n   };\n\n   function setCaretPosition(e, start, end) {\n       if (e.createTextRange) {\n           var r = e.createTextRange();\n           r.moveStart('character', start);\n           r.moveEnd('character', (end || start));\n           r.select();\n       } else if (e.selectionStart) {\n           e.focus();\n           e.setSelectionRange(start, (end || start));\n       }\n   };\n\n   function getWordBeforeCaretPosition(e) {\n       var s = e.value;\n       var i = getCaretPosition(e) - 1;\n       while (i >= 0 && s[i] != ' ') {\n           i = i - 1;\n       }\n       return i + 1;\n   };\n\n   function getWordBeforeCaret(e) {\n     var p = getWordBeforeCaretPosition(e);\n     var c = getCaretPosition(e);\n     return e.value.substring(p, c);\n   };\n\n   function replaceWordBeforeCaret(e, word) {\n       var p = getWordBeforeCaretPosition(e);\n       var c = getCaretPosition(e);\n       e.value = e.value.substring(0, p) + word + e.value.substring(c);\n       setCaretPosition(e, p + word.length);\n   };\n\n  var methods = {\n     init : function( options ) {\n\n       return this.each(function(){\n\n         var $this = $(this),\n            data = $this.data('mentions');\n\n    if (options < 0){\n      var projectId = $this.attr(\"autocomplete-mentions-projectid\");\n    }\n    else{\n      var projectId = options;\n    }\n      $this.bind(\"keydown\", function(event) {\n               if (event.keyCode === $.ui.keyCode.TAB && $(this).data(\"autocomplete\").menu.active ) {\n                 event.preventDefault();\n               }\n               })\n             .autocomplete({\n               minLength: 0,\n             open: function(){\n                $(\".ui-menu\").width('auto');\n              },\n               source: function(request, response) {\n                 var w = getWordBeforeCaret(this.element[0]);\n                 if (w[0] != '@') {\n                   this.close();\n                   return false;\n                 }\n\n                 if (typeof community_members[projectId] != \"undefined\") {\n                   //map the data into a response that will be understood by the autocomplete widget\n                   response($.ui.autocomplete.filter(community_members[projectId], w.substring(1, w.length)));\n                 }\n                 //get the data from the server\n                 else {\n                   $.ajax({\n                     url: \"/projects/\" + projectId + \"/community_members_array\",\n                     dataType: \"json\",\n                     success: function(data) {\n                       //cache the data for later\n                       community_members[projectId] = data;\n                       //map the data into a response that will be understood by the autocomplete widget\n                         response($.ui.autocomplete.filter(community_members[projectId], w.substring(1, w.length)));\n                     }\n                   });\n                 }\n               },\n      delay: 0,\n               position: {\n                   my: \"left top\",\n                   at: \"right top\"\n               },\n               focus: function() {\n                 return false;\n               },\n               search: function(event, ui) {\n                 return true;\n               },\n               select: function(event, ui) {\n                 replaceWordBeforeCaret(this, '@' + ui.item.value + ' ');\n                 return false;\n               }\n             })\n      .data( \"autocomplete\" )._renderItem = function( ul, item ) {\n        return $( \"<li></li>\" )\n          .data( \"item.autocomplete\", item )\n          .append( \"<img src='http://gravatar.com/avatar.php?gravatar_id=\" + item.mail_hash + \"&size=17/>\")\n          .append( \"<a>\" + item.label + \"</a>\" )\n          // .append( \"<img src='https://secure.gravatar.com/avatar.php?gravatar_id=\" + item.mail_hash + \"&size=17/>\")\n          // .append( \"<a><img src='http://secure.gravatar.com/avatar.php?gravatar_id=\" + item.mail_hash + \"&size=17/>\" + item.label + \"</a>\" )\n          .appendTo( ul );\n      };\n\n    //Replace with code below to show gravatars in dropdown. Works only in firefox\n    // .data(\"autocomplete\")._renderItem = function( ul, item ) {\n    //     return $( \"<li><a><img src='https://secure.gravatar.com/avatar.php?gravatar_id=\" + item.mail_hash + \"&size=17/>\" + item.label + \"</a></li>\" )\n    //       .data( \"item.autocomplete\", item )\n    //       .appendTo( ul );\n    //   };\n       });\n     },\n     destroy : function( ) {\n\n       return this.each(function(){\n\n         var $this = $(this),\n             data = $this.data('mentions');\n\n         // Namespacing FTW\n         $(window).unbind('.mentions');\n         data.mentions.remove();\n         $this.removeData('mentions');\n\n       })\n\n     }\n  };\n\n  $.fn.mentions = function( projectId ) {\n     return methods['init'].apply( this, Array.prototype.slice.call( arguments, 0 ));\n  };\n\n})( jQuery );\n\n\nfunction bind_autocomplete_mentions(){\n  $(\"input[autocomplete-mentions-projectid]\").mentions(-1);\n  $(\"textarea[autocomplete-mentions-projectid]\").mentions(-1);\n\n  if (typeof projectId != \"undefined\"){\n    $( \".autocomplete-mentions\" ).mentions(projectId);\n  }\n};\n\nfunction bind_relations_autocomplete(projectId){\n  $(\".issue-relation\").autocomplete({\n         minLength: 2,\n         // source: // \"/projects/\" + projectId + \"/community_members_array\",\n      // source: function( request, response ) {\n      //   $.ajax({\n      //     url: \"http://ws.geonames.org/searchJSON\",\n      //     dataType: \"jsonp\",\n      //     data: {\n      //       featureClass: \"P\",\n      //       style: \"full\",\n      //       maxRows: 12,\n      //       name_startsWith: request.term\n      //     },\n      //     success: function( data ) {\n      //       console.log(data);\n      //       response( $.map( data.geonames, function( item ) {\n      //         return {\n      //           label: item.name + (item.adminName1 ? \", \" + item.adminName1 : \"\") + \", \" + item.countryName,\n      //           value: item.name\n      //         }\n      //       }));\n      //     }\n      //   });\n      // },\n      source: function( request, response ) {\n        $.ajax({\n          url: \"/projects/\" + projectId + \"/issue_search\",\n          dataType: \"json\",\n          data: {\n            // maxRows: 12,\n            searchTerm: request.term\n          },\n          success: function( data ) {\n            response( $.map( data, function( item ) {\n              return {\n                label: item.id + ' - ' + item.subject,\n                value: item.id\n              }\n            }));\n          }\n        });\n      },\n      delay: 0\n         })\n}\n\nfunction help_popup(){\n  $.fancybox({\n  'content'      : $('#help_section_container').html(),\n  'padding'    : 0,\n  'margin'  : 0,\n  'title'      : 'Help Tip'\n  // 'transitionIn'  : 'elastic',\n  // 'transitionOut'  : 'elastic',\n  // 'scrolling' : 'no'\n  });\n};\n\n\n\n/**\n * Cookie plugin\n *\n * Copyright (c) 2006 Klaus Hartl (stilbuero.de)\n * Dual licensed under the MIT and GPL licenses:\n * http://www.opensource.org/licenses/mit-license.php\n * http://www.gnu.org/licenses/gpl.html\n *\n */\n\n/**\n * Create a cookie with the given name and value and other optional parameters.\n *\n * @example $.cookie('the_cookie', 'the_value');\n * @desc Set the value of a cookie.\n * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });\n * @desc Create a cookie with all available options.\n * @example $.cookie('the_cookie', 'the_value');\n * @desc Create a session cookie.\n * @example $.cookie('the_cookie', null);\n * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain\n *       used when the cookie was set.\n *\n * @param String name The name of the cookie.\n * @param String value The value of the cookie.\n * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.\n * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.\n *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.\n *                             If set to null or omitted, the cookie will be a session cookie and will not be retained\n *                             when the the browser exits.\n * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).\n * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).\n * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will\n *                        require a secure protocol (like HTTPS).\n * @type undefined\n *\n * @name $.cookie\n * @cat Plugins/Cookie\n * @author Klaus Hartl/klaus.hartl@stilbuero.de\n */\n\n/**\n * Get the value of a cookie with the given name.\n *\n * @example $.cookie('the_cookie');\n * @desc Get the value of a cookie.\n *\n * @param String name The name of the cookie.\n * @return The value of the cookie.\n * @type String\n *\n * @name $.cookie\n * @cat Plugins/Cookie\n * @author Klaus Hartl/klaus.hartl@stilbuero.de\n */\njQuery.cookie = function(name, value, options) {\n    if (typeof value != 'undefined') { // name and value given, set cookie\n        options = options || {};\n        if (value === null) {\n            value = '';\n            options.expires = -1;\n        }\n        var expires = '';\n        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {\n            var date;\n            if (typeof options.expires == 'number') {\n                date = new Date();\n                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));\n            } else {\n                date = options.expires;\n            }\n            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE\n        }\n        // CAUTION: Needed to parenthesize options.path and options.domain\n        // in the following expressions, otherwise they evaluate to undefined\n        // in the packed version for some reason...\n        var path = options.path ? '; path=' + (options.path) : '';\n        var domain = options.domain ? '; domain=' + (options.domain) : '';\n        var secure = options.secure ? '; secure' : '';\n        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');\n    } else { // only name given, get cookie\n        var cookieValue = null;\n        if (document.cookie && document.cookie != '') {\n            var cookies = document.cookie.split(';');\n            for (var i = 0; i < cookies.length; i++) {\n                var cookie = jQuery.trim(cookies[i]);\n                // Does this cookie string begin with the name we want?\n                if (cookie.substring(0, name.length + 1) == (name + '=')) {\n                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n                    break;\n                }\n            }\n        }\n        return cookieValue;\n    }\n};\n"
  },
  {
    "path": "public/javascripts/calendar/calendar-setup.js",
    "content": "/*  Copyright Mihai Bazon, 2002, 2003  |  http://dynarch.com/mishoo/\n * ---------------------------------------------------------------------------\n *\n * The DHTML Calendar\n *\n * Details and latest version at:\n * http://dynarch.com/mishoo/calendar.epl\n *\n * This script is distributed under the GNU Lesser General Public License.\n * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html\n *\n * This file defines helper functions for setting up the calendar.  They are\n * intended to help non-programmers get a working calendar on their site\n * quickly.  This script should not be seen as part of the calendar.  It just\n * shows you what one can do with the calendar, while in the same time\n * providing a quick and simple method for setting it up.  If you need\n * exhaustive customization of the calendar creation process feel free to\n * modify this code to suit your needs (this is recommended and much better\n * than modifying calendar.js itself).\n */\n\n// $Id: calendar-setup.js,v 1.25 2005/03/07 09:51:33 mishoo Exp $\n\n/**\n *  This function \"patches\" an input field (or other element) to use a calendar\n *  widget for date selection.\n *\n *  The \"params\" is a single object that can have the following properties:\n *\n *    prop. name   | description\n *  -------------------------------------------------------------------------------------------------\n *   inputField    | the ID of an input field to store the date\n *   displayArea   | the ID of a DIV or other element to show the date\n *   button        | ID of a button or other element that will trigger the calendar\n *   eventName     | event that will trigger the calendar, without the \"on\" prefix (default: \"click\")\n *   ifFormat      | date format that will be stored in the input field\n *   daFormat      | the date format that will be used to display the date in displayArea\n *   singleClick   | (true/false) wether the calendar is in single click mode or not (default: true)\n *   firstDay      | numeric: 0 to 6.  \"0\" means display Sunday first, \"1\" means display Monday first, etc.\n *   align         | alignment (default: \"Br\"); if you don't know what's this see the calendar documentation\n *   range         | array with 2 elements.  Default: [1900, 2999] -- the range of years available\n *   weekNumbers   | (true/false) if it's true (default) the calendar will display week numbers\n *   flat          | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID\n *   flatCallback  | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar)\n *   disableFunc   | function that receives a JS Date object and should return true if that date has to be disabled in the calendar\n *   onSelect      | function that gets called when a date is selected.  You don't _have_ to supply this (the default is generally okay)\n *   onClose       | function that gets called when the calendar is closed.  [default]\n *   onUpdate      | function that gets called after the date is updated in the input field.  Receives a reference to the calendar.\n *   date          | the date that the calendar will be initially displayed to\n *   showsTime     | default: false; if true the calendar will include a time selector\n *   timeFormat    | the time format; can be \"12\" or \"24\", default is \"12\"\n *   electric      | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close\n *   step          | configures the step of the years in drop-down boxes; default: 2\n *   position      | configures the calendar absolute position; default: null\n *   cache         | if \"true\" (but default: \"false\") it will reuse the same calendar object, where possible\n *   showOthers    | if \"true\" (but default: \"false\") it will show days from other months too\n *\n *  None of them is required, they all have default values.  However, if you\n *  pass none of \"inputField\", \"displayArea\" or \"button\" you'll get a warning\n *  saying \"nothing to setup\".\n */\nCalendar.setup = function (params) {\n  function param_default(pname, def) { if (typeof params[pname] == \"undefined\") { params[pname] = def; } };\n\n  param_default(\"inputField\",     null);\n  param_default(\"displayArea\",    null);\n  param_default(\"button\",         null);\n  param_default(\"eventName\",      \"click\");\n  param_default(\"ifFormat\",       \"%Y/%m/%d\");\n  param_default(\"daFormat\",       \"%Y/%m/%d\");\n  param_default(\"singleClick\",    true);\n  param_default(\"disableFunc\",    null);\n  param_default(\"dateStatusFunc\", params[\"disableFunc\"]);  // takes precedence if both are defined\n  param_default(\"dateText\",       null);\n  param_default(\"firstDay\",       null);\n  param_default(\"align\",          \"Br\");\n  param_default(\"range\",          [1900, 2999]);\n  param_default(\"weekNumbers\",    true);\n  param_default(\"flat\",           null);\n  param_default(\"flatCallback\",   null);\n  param_default(\"onSelect\",       null);\n  param_default(\"onClose\",        null);\n  param_default(\"onUpdate\",       null);\n  param_default(\"date\",           null);\n  param_default(\"showsTime\",      false);\n  param_default(\"timeFormat\",     \"24\");\n  param_default(\"electric\",       true);\n  param_default(\"step\",           2);\n  param_default(\"position\",       null);\n  param_default(\"cache\",          false);\n  param_default(\"showOthers\",     false);\n  param_default(\"multiple\",       null);\n\n  var tmp = [\"inputField\", \"displayArea\", \"button\"];\n  for (var i in tmp) {\n    if (typeof params[tmp[i]] == \"string\") {\n      params[tmp[i]] = document.getElementById(params[tmp[i]]);\n    }\n  }\n  if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) {\n    alert(\"Calendar.setup:\\n  Nothing to setup (no fields found).  Please check your code\");\n    return false;\n  }\n\n  function onSelect(cal) {\n    var p = cal.params;\n    var update = (cal.dateClicked || p.electric);\n    if (update && p.inputField) {\n      p.inputField.value = cal.date.print(p.ifFormat);\n      if (typeof p.inputField.onchange == \"function\")\n        p.inputField.onchange();\n    }\n    if (update && p.displayArea)\n      p.displayArea.innerHTML = cal.date.print(p.daFormat);\n    if (update && typeof p.onUpdate == \"function\")\n      p.onUpdate(cal);\n    if (update && p.flat) {\n      if (typeof p.flatCallback == \"function\")\n        p.flatCallback(cal);\n    }\n    if (update && p.singleClick && cal.dateClicked)\n      cal.callCloseHandler();\n  };\n\n  if (params.flat != null) {\n    if (typeof params.flat == \"string\")\n      params.flat = document.getElementById(params.flat);\n    if (!params.flat) {\n      alert(\"Calendar.setup:\\n  Flat specified but can't find parent.\");\n      return false;\n    }\n    var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect);\n    cal.showsOtherMonths = params.showOthers;\n    cal.showsTime = params.showsTime;\n    cal.time24 = (params.timeFormat == \"24\");\n    cal.params = params;\n    cal.weekNumbers = params.weekNumbers;\n    cal.setRange(params.range[0], params.range[1]);\n    cal.setDateStatusHandler(params.dateStatusFunc);\n    cal.getDateText = params.dateText;\n    if (params.ifFormat) {\n      cal.setDateFormat(params.ifFormat);\n    }\n    if (params.inputField && typeof params.inputField.value == \"string\") {\n      cal.parseDate(params.inputField.value);\n    }\n    cal.create(params.flat);\n    cal.show();\n    return false;\n  }\n\n  var triggerEl = params.button || params.displayArea || params.inputField;\n  triggerEl[\"on\" + params.eventName] = function() {\n    var dateEl = params.inputField || params.displayArea;\n    var dateFmt = params.inputField ? params.ifFormat : params.daFormat;\n    var mustCreate = false;\n    var cal = window.calendar;\n    if (dateEl)\n      params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt);\n    if (!(cal && params.cache)) {\n      window.calendar = cal = new Calendar(params.firstDay,\n                   params.date,\n                   params.onSelect || onSelect,\n                   params.onClose || function(cal) { cal.hide(); });\n      cal.showsTime = params.showsTime;\n      cal.time24 = (params.timeFormat == \"24\");\n      cal.weekNumbers = params.weekNumbers;\n      mustCreate = true;\n    } else {\n      if (params.date)\n        cal.setDate(params.date);\n      cal.hide();\n    }\n    if (params.multiple) {\n      cal.multiple = {};\n      for (var i = params.multiple.length; --i >= 0;) {\n        var d = params.multiple[i];\n        var ds = d.print(\"%Y%m%d\");\n        cal.multiple[ds] = d;\n      }\n    }\n    cal.showsOtherMonths = params.showOthers;\n    cal.yearStep = params.step;\n    cal.setRange(params.range[0], params.range[1]);\n    cal.params = params;\n    cal.setDateStatusHandler(params.dateStatusFunc);\n    cal.getDateText = params.dateText;\n    cal.setDateFormat(dateFmt);\n    if (mustCreate)\n      cal.create();\n    cal.refresh();\n    if (!params.position)\n      cal.showAtElement(params.button || params.displayArea || params.inputField, params.align);\n    else\n      cal.showAt(params.position[0], params.position[1]);\n    return false;\n  };\n\n  return cal;\n};\n"
  },
  {
    "path": "public/javascripts/calendar/calendar.js",
    "content": "/*  Copyright Mihai Bazon, 2002-2005  |  www.bazon.net/mishoo\n * -----------------------------------------------------------\n *\n * The DHTML Calendar, version 1.0 \"It is happening again\"\n *\n * Details and latest version at:\n * www.dynarch.com/projects/calendar\n *\n * This script is developed by Dynarch.com.  Visit us at www.dynarch.com.\n *\n * This script is distributed under the GNU Lesser General Public License.\n * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html\n */\n\n// $Id: calendar.js,v 1.51 2005/03/07 16:44:31 mishoo Exp $\n\n/** The Calendar object constructor. */\nCalendar = function (firstDayOfWeek, dateStr, onSelected, onClose) {\n  // member variables\n  this.activeDiv = null;\n  this.currentDateEl = null;\n  this.getDateStatus = null;\n  this.getDateToolTip = null;\n  this.getDateText = null;\n  this.timeout = null;\n  this.onSelected = onSelected || null;\n  this.onClose = onClose || null;\n  this.dragging = false;\n  this.hidden = false;\n  this.minYear = 1970;\n  this.maxYear = 2050;\n  this.dateFormat = Calendar._TT[\"DEF_DATE_FORMAT\"];\n  this.ttDateFormat = Calendar._TT[\"TT_DATE_FORMAT\"];\n  this.isPopup = true;\n  this.weekNumbers = true;\n  this.firstDayOfWeek = typeof firstDayOfWeek == \"number\" ? firstDayOfWeek : Calendar._FD; // 0 for Sunday, 1 for Monday, etc.\n  this.showsOtherMonths = false;\n  this.dateStr = dateStr;\n  this.ar_days = null;\n  this.showsTime = false;\n  this.time24 = true;\n  this.yearStep = 2;\n  this.hiliteToday = true;\n  this.multiple = null;\n  // HTML elements\n  this.table = null;\n  this.element = null;\n  this.tbody = null;\n  this.firstdayname = null;\n  // Combo boxes\n  this.monthsCombo = null;\n  this.yearsCombo = null;\n  this.hilitedMonth = null;\n  this.activeMonth = null;\n  this.hilitedYear = null;\n  this.activeYear = null;\n  // Information\n  this.dateClicked = false;\n\n  // one-time initializations\n  if (typeof Calendar._SDN == \"undefined\") {\n    // table of short day names\n    if (typeof Calendar._SDN_len == \"undefined\")\n      Calendar._SDN_len = 3;\n    var ar = new Array();\n    for (var i = 8; i > 0;) {\n      ar[--i] = Calendar._DN[i].substr(0, Calendar._SDN_len);\n    }\n    Calendar._SDN = ar;\n    // table of short month names\n    if (typeof Calendar._SMN_len == \"undefined\")\n      Calendar._SMN_len = 3;\n    ar = new Array();\n    for (var i = 12; i > 0;) {\n      ar[--i] = Calendar._MN[i].substr(0, Calendar._SMN_len);\n    }\n    Calendar._SMN = ar;\n  }\n};\n\n// ** constants\n\n/// \"static\", needed for event handlers.\nCalendar._C = null;\n\n/// detect a special case of \"web browser\"\nCalendar.is_ie = ( /msie/i.test(navigator.userAgent) &&\n       !/opera/i.test(navigator.userAgent) );\n\nCalendar.is_ie5 = ( Calendar.is_ie && /msie 5\\.0/i.test(navigator.userAgent) );\n\n/// detect Opera browser\nCalendar.is_opera = /opera/i.test(navigator.userAgent);\n\n/// detect KHTML-based browsers\nCalendar.is_khtml = /Konqueror|Safari|KHTML/i.test(navigator.userAgent);\n\n// BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate\n//        library, at some point.\n\nCalendar.getAbsolutePos = function(el) {\n  var SL = 0, ST = 0;\n  var is_div = /^div$/i.test(el.tagName);\n  if (is_div && el.scrollLeft)\n    SL = el.scrollLeft;\n  if (is_div && el.scrollTop)\n    ST = el.scrollTop;\n  var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };\n  if (el.offsetParent) {\n    var tmp = this.getAbsolutePos(el.offsetParent);\n    r.x += tmp.x;\n    r.y += tmp.y;\n  }\n  return r;\n};\n\nCalendar.isRelated = function (el, evt) {\n  var related = evt.relatedTarget;\n  if (!related) {\n    var type = evt.type;\n    if (type == \"mouseover\") {\n      related = evt.fromElement;\n    } else if (type == \"mouseout\") {\n      related = evt.toElement;\n    }\n  }\n  while (related) {\n    if (related == el) {\n      return true;\n    }\n    related = related.parentNode;\n  }\n  return false;\n};\n\nCalendar.removeClass = function(el, className) {\n  if (!(el && el.className)) {\n    return;\n  }\n  var cls = el.className.split(\" \");\n  var ar = new Array();\n  for (var i = cls.length; i > 0;) {\n    if (cls[--i] != className) {\n      ar[ar.length] = cls[i];\n    }\n  }\n  el.className = ar.join(\" \");\n};\n\nCalendar.addClass = function(el, className) {\n  Calendar.removeClass(el, className);\n  el.className += \" \" + className;\n};\n\n// FIXME: the following 2 functions totally suck, are useless and should be replaced immediately.\nCalendar.getElement = function(ev) {\n  var f = Calendar.is_ie ? window.event.srcElement : ev.currentTarget;\n  while (f.nodeType != 1 || /^div$/i.test(f.tagName))\n    f = f.parentNode;\n  return f;\n};\n\nCalendar.getTargetElement = function(ev) {\n  var f = Calendar.is_ie ? window.event.srcElement : ev.target;\n  while (f.nodeType != 1)\n    f = f.parentNode;\n  return f;\n};\n\nCalendar.stopEvent = function(ev) {\n  ev || (ev = window.event);\n  if (Calendar.is_ie) {\n    ev.cancelBubble = true;\n    ev.returnValue = false;\n  } else {\n    ev.preventDefault();\n    ev.stopPropagation();\n  }\n  return false;\n};\n\nCalendar.addEvent = function(el, evname, func) {\n  if (el.attachEvent) { // IE\n    el.attachEvent(\"on\" + evname, func);\n  } else if (el.addEventListener) { // Gecko / W3C\n    el.addEventListener(evname, func, true);\n  } else {\n    el[\"on\" + evname] = func;\n  }\n};\n\nCalendar.removeEvent = function(el, evname, func) {\n  if (el.detachEvent) { // IE\n    el.detachEvent(\"on\" + evname, func);\n  } else if (el.removeEventListener) { // Gecko / W3C\n    el.removeEventListener(evname, func, true);\n  } else {\n    el[\"on\" + evname] = null;\n  }\n};\n\nCalendar.createElement = function(type, parent) {\n  var el = null;\n  if (document.createElementNS) {\n    // use the XHTML namespace; IE won't normally get here unless\n    // _they_ \"fix\" the DOM2 implementation.\n    el = document.createElementNS(\"http://www.w3.org/1999/xhtml\", type);\n  } else {\n    el = document.createElement(type);\n  }\n  if (typeof parent != \"undefined\") {\n    parent.appendChild(el);\n  }\n  return el;\n};\n\n// END: UTILITY FUNCTIONS\n\n// BEGIN: CALENDAR STATIC FUNCTIONS\n\n/** Internal -- adds a set of events to make some element behave like a button. */\nCalendar._add_evs = function(el) {\n  with (Calendar) {\n    addEvent(el, \"mouseover\", dayMouseOver);\n    addEvent(el, \"mousedown\", dayMouseDown);\n    addEvent(el, \"mouseout\", dayMouseOut);\n    if (is_ie) {\n      addEvent(el, \"dblclick\", dayMouseDblClick);\n      el.setAttribute(\"unselectable\", true);\n    }\n  }\n};\n\nCalendar.findMonth = function(el) {\n  if (typeof el.month != \"undefined\") {\n    return el;\n  } else if (typeof el.parentNode.month != \"undefined\") {\n    return el.parentNode;\n  }\n  return null;\n};\n\nCalendar.findYear = function(el) {\n  if (typeof el.year != \"undefined\") {\n    return el;\n  } else if (typeof el.parentNode.year != \"undefined\") {\n    return el.parentNode;\n  }\n  return null;\n};\n\nCalendar.showMonthsCombo = function () {\n  var cal = Calendar._C;\n  if (!cal) {\n    return false;\n  }\n  var cal = cal;\n  var cd = cal.activeDiv;\n  var mc = cal.monthsCombo;\n  if (cal.hilitedMonth) {\n    Calendar.removeClass(cal.hilitedMonth, \"hilite\");\n  }\n  if (cal.activeMonth) {\n    Calendar.removeClass(cal.activeMonth, \"active\");\n  }\n  var mon = cal.monthsCombo.getElementsByTagName(\"div\")[cal.date.getMonth()];\n  Calendar.addClass(mon, \"active\");\n  cal.activeMonth = mon;\n  var s = mc.style;\n  s.display = \"block\";\n  if (cd.navtype < 0)\n    s.left = cd.offsetLeft + \"px\";\n  else {\n    var mcw = mc.offsetWidth;\n    if (typeof mcw == \"undefined\")\n      // Konqueror brain-dead techniques\n      mcw = 50;\n    s.left = (cd.offsetLeft + cd.offsetWidth - mcw) + \"px\";\n  }\n  s.top = (cd.offsetTop + cd.offsetHeight) + \"px\";\n};\n\nCalendar.showYearsCombo = function (fwd) {\n  var cal = Calendar._C;\n  if (!cal) {\n    return false;\n  }\n  var cal = cal;\n  var cd = cal.activeDiv;\n  var yc = cal.yearsCombo;\n  if (cal.hilitedYear) {\n    Calendar.removeClass(cal.hilitedYear, \"hilite\");\n  }\n  if (cal.activeYear) {\n    Calendar.removeClass(cal.activeYear, \"active\");\n  }\n  cal.activeYear = null;\n  var Y = cal.date.getFullYear() + (fwd ? 1 : -1);\n  var yr = yc.firstChild;\n  var show = false;\n  for (var i = 12; i > 0; --i) {\n    if (Y >= cal.minYear && Y <= cal.maxYear) {\n      yr.innerHTML = Y;\n      yr.year = Y;\n      yr.style.display = \"block\";\n      show = true;\n    } else {\n      yr.style.display = \"none\";\n    }\n    yr = yr.nextSibling;\n    Y += fwd ? cal.yearStep : -cal.yearStep;\n  }\n  if (show) {\n    var s = yc.style;\n    s.display = \"block\";\n    if (cd.navtype < 0)\n      s.left = cd.offsetLeft + \"px\";\n    else {\n      var ycw = yc.offsetWidth;\n      if (typeof ycw == \"undefined\")\n        // Konqueror brain-dead techniques\n        ycw = 50;\n      s.left = (cd.offsetLeft + cd.offsetWidth - ycw) + \"px\";\n    }\n    s.top = (cd.offsetTop + cd.offsetHeight) + \"px\";\n  }\n};\n\n// event handlers\n\nCalendar.tableMouseUp = function(ev) {\n  var cal = Calendar._C;\n  if (!cal) {\n    return false;\n  }\n  if (cal.timeout) {\n    clearTimeout(cal.timeout);\n  }\n  var el = cal.activeDiv;\n  if (!el) {\n    return false;\n  }\n  var target = Calendar.getTargetElement(ev);\n  ev || (ev = window.event);\n  Calendar.removeClass(el, \"active\");\n  if (target == el || target.parentNode == el) {\n    Calendar.cellClick(el, ev);\n  }\n  var mon = Calendar.findMonth(target);\n  var date = null;\n  if (mon) {\n    date = new Date(cal.date);\n    if (mon.month != date.getMonth()) {\n      date.setMonth(mon.month);\n      cal.setDate(date);\n      cal.dateClicked = false;\n      cal.callHandler();\n    }\n  } else {\n    var year = Calendar.findYear(target);\n    if (year) {\n      date = new Date(cal.date);\n      if (year.year != date.getFullYear()) {\n        date.setFullYear(year.year);\n        cal.setDate(date);\n        cal.dateClicked = false;\n        cal.callHandler();\n      }\n    }\n  }\n  with (Calendar) {\n    removeEvent(document, \"mouseup\", tableMouseUp);\n    removeEvent(document, \"mouseover\", tableMouseOver);\n    removeEvent(document, \"mousemove\", tableMouseOver);\n    cal._hideCombos();\n    _C = null;\n    return stopEvent(ev);\n  }\n};\n\nCalendar.tableMouseOver = function (ev) {\n  var cal = Calendar._C;\n  if (!cal) {\n    return;\n  }\n  var el = cal.activeDiv;\n  var target = Calendar.getTargetElement(ev);\n  if (target == el || target.parentNode == el) {\n    Calendar.addClass(el, \"hilite active\");\n    Calendar.addClass(el.parentNode, \"rowhilite\");\n  } else {\n    if (typeof el.navtype == \"undefined\" || (el.navtype != 50 && (el.navtype == 0 || Math.abs(el.navtype) > 2)))\n      Calendar.removeClass(el, \"active\");\n    Calendar.removeClass(el, \"hilite\");\n    Calendar.removeClass(el.parentNode, \"rowhilite\");\n  }\n  ev || (ev = window.event);\n  if (el.navtype == 50 && target != el) {\n    var pos = Calendar.getAbsolutePos(el);\n    var w = el.offsetWidth;\n    var x = ev.clientX;\n    var dx;\n    var decrease = true;\n    if (x > pos.x + w) {\n      dx = x - pos.x - w;\n      decrease = false;\n    } else\n      dx = pos.x - x;\n\n    if (dx < 0) dx = 0;\n    var range = el._range;\n    var current = el._current;\n    var count = Math.floor(dx / 10) % range.length;\n    for (var i = range.length; --i >= 0;)\n      if (range[i] == current)\n        break;\n    while (count-- > 0)\n      if (decrease) {\n        if (--i < 0)\n          i = range.length - 1;\n      } else if ( ++i >= range.length )\n        i = 0;\n    var newval = range[i];\n    el.innerHTML = newval;\n\n    cal.onUpdateTime();\n  }\n  var mon = Calendar.findMonth(target);\n  if (mon) {\n    if (mon.month != cal.date.getMonth()) {\n      if (cal.hilitedMonth) {\n        Calendar.removeClass(cal.hilitedMonth, \"hilite\");\n      }\n      Calendar.addClass(mon, \"hilite\");\n      cal.hilitedMonth = mon;\n    } else if (cal.hilitedMonth) {\n      Calendar.removeClass(cal.hilitedMonth, \"hilite\");\n    }\n  } else {\n    if (cal.hilitedMonth) {\n      Calendar.removeClass(cal.hilitedMonth, \"hilite\");\n    }\n    var year = Calendar.findYear(target);\n    if (year) {\n      if (year.year != cal.date.getFullYear()) {\n        if (cal.hilitedYear) {\n          Calendar.removeClass(cal.hilitedYear, \"hilite\");\n        }\n        Calendar.addClass(year, \"hilite\");\n        cal.hilitedYear = year;\n      } else if (cal.hilitedYear) {\n        Calendar.removeClass(cal.hilitedYear, \"hilite\");\n      }\n    } else if (cal.hilitedYear) {\n      Calendar.removeClass(cal.hilitedYear, \"hilite\");\n    }\n  }\n  return Calendar.stopEvent(ev);\n};\n\nCalendar.tableMouseDown = function (ev) {\n  if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) {\n    return Calendar.stopEvent(ev);\n  }\n};\n\nCalendar.calDragIt = function (ev) {\n  var cal = Calendar._C;\n  if (!(cal && cal.dragging)) {\n    return false;\n  }\n  var posX;\n  var posY;\n  if (Calendar.is_ie) {\n    posY = window.event.clientY + document.body.scrollTop;\n    posX = window.event.clientX + document.body.scrollLeft;\n  } else {\n    posX = ev.pageX;\n    posY = ev.pageY;\n  }\n  cal.hideShowCovered();\n  var st = cal.element.style;\n  st.left = (posX - cal.xOffs) + \"px\";\n  st.top = (posY - cal.yOffs) + \"px\";\n  return Calendar.stopEvent(ev);\n};\n\nCalendar.calDragEnd = function (ev) {\n  var cal = Calendar._C;\n  if (!cal) {\n    return false;\n  }\n  cal.dragging = false;\n  with (Calendar) {\n    removeEvent(document, \"mousemove\", calDragIt);\n    removeEvent(document, \"mouseup\", calDragEnd);\n    tableMouseUp(ev);\n  }\n  cal.hideShowCovered();\n};\n\nCalendar.dayMouseDown = function(ev) {\n  var el = Calendar.getElement(ev);\n  if (el.disabled) {\n    return false;\n  }\n  var cal = el.calendar;\n  cal.activeDiv = el;\n  Calendar._C = cal;\n  if (el.navtype != 300) with (Calendar) {\n    if (el.navtype == 50) {\n      el._current = el.innerHTML;\n      addEvent(document, \"mousemove\", tableMouseOver);\n    } else\n      addEvent(document, Calendar.is_ie5 ? \"mousemove\" : \"mouseover\", tableMouseOver);\n    addClass(el, \"hilite active\");\n    addEvent(document, \"mouseup\", tableMouseUp);\n  } else if (cal.isPopup) {\n    cal._dragStart(ev);\n  }\n  if (el.navtype == -1 || el.navtype == 1) {\n    if (cal.timeout) clearTimeout(cal.timeout);\n    cal.timeout = setTimeout(\"Calendar.showMonthsCombo()\", 250);\n  } else if (el.navtype == -2 || el.navtype == 2) {\n    if (cal.timeout) clearTimeout(cal.timeout);\n    cal.timeout = setTimeout((el.navtype > 0) ? \"Calendar.showYearsCombo(true)\" : \"Calendar.showYearsCombo(false)\", 250);\n  } else {\n    cal.timeout = null;\n  }\n  return Calendar.stopEvent(ev);\n};\n\nCalendar.dayMouseDblClick = function(ev) {\n  Calendar.cellClick(Calendar.getElement(ev), ev || window.event);\n  if (Calendar.is_ie) {\n    document.selection.empty();\n  }\n};\n\nCalendar.dayMouseOver = function(ev) {\n  var el = Calendar.getElement(ev);\n  if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) {\n    return false;\n  }\n  if (el.ttip) {\n    if (el.ttip.substr(0, 1) == \"_\") {\n      el.ttip = el.caldate.print(el.calendar.ttDateFormat) + el.ttip.substr(1);\n    }\n    el.calendar.tooltips.innerHTML = el.ttip;\n  }\n  if (el.navtype != 300) {\n    Calendar.addClass(el, \"hilite\");\n    if (el.caldate) {\n      Calendar.addClass(el.parentNode, \"rowhilite\");\n    }\n  }\n  return Calendar.stopEvent(ev);\n};\n\nCalendar.dayMouseOut = function(ev) {\n  with (Calendar) {\n    var el = getElement(ev);\n    if (isRelated(el, ev) || _C || el.disabled)\n      return false;\n    removeClass(el, \"hilite\");\n    if (el.caldate)\n      removeClass(el.parentNode, \"rowhilite\");\n    if (el.calendar)\n      el.calendar.tooltips.innerHTML = _TT[\"SEL_DATE\"];\n    return stopEvent(ev);\n  }\n};\n\n/**\n *  A generic \"click\" handler :) handles all types of buttons defined in this\n *  calendar.\n */\nCalendar.cellClick = function(el, ev) {\n  var cal = el.calendar;\n  var closing = false;\n  var newdate = false;\n  var date = null;\n  if (typeof el.navtype == \"undefined\") {\n    if (cal.currentDateEl) {\n      Calendar.removeClass(cal.currentDateEl, \"selected\");\n      Calendar.addClass(el, \"selected\");\n      closing = (cal.currentDateEl == el);\n      if (!closing) {\n        cal.currentDateEl = el;\n      }\n    }\n    cal.date.setDateOnly(el.caldate);\n    date = cal.date;\n    var other_month = !(cal.dateClicked = !el.otherMonth);\n    if (!other_month && !cal.currentDateEl)\n      cal._toggleMultipleDate(new Date(date));\n    else\n      newdate = !el.disabled;\n    // a date was clicked\n    if (other_month)\n      cal._init(cal.firstDayOfWeek, date);\n  } else {\n    if (el.navtype == 200) {\n      Calendar.removeClass(el, \"hilite\");\n      cal.callCloseHandler();\n      return;\n    }\n    date = new Date(cal.date);\n    if (el.navtype == 0)\n      date.setDateOnly(new Date()); // TODAY\n    // unless \"today\" was clicked, we assume no date was clicked so\n    // the selected handler will know not to close the calenar when\n    // in single-click mode.\n    // cal.dateClicked = (el.navtype == 0);\n    cal.dateClicked = false;\n    var year = date.getFullYear();\n    var mon = date.getMonth();\n    function setMonth(m) {\n      var day = date.getDate();\n      var max = date.getMonthDays(m);\n      if (day > max) {\n        date.setDate(max);\n      }\n      date.setMonth(m);\n    };\n    switch (el.navtype) {\n        case 400:\n      Calendar.removeClass(el, \"hilite\");\n      var text = Calendar._TT[\"ABOUT\"];\n      if (typeof text != \"undefined\") {\n        text += cal.showsTime ? Calendar._TT[\"ABOUT_TIME\"] : \"\";\n      } else {\n        // FIXME: this should be removed as soon as lang files get updated!\n        text = \"Help and about box text is not translated into this language.\\n\" +\n          \"If you know this language and you feel generous please update\\n\" +\n          \"the corresponding file in \\\"lang\\\" subdir to match calendar-en.js\\n\" +\n          \"and send it back to <mihai_bazon@yahoo.com> to get it into the distribution  ;-)\\n\\n\" +\n          \"Thank you!\\n\" +\n          \"http://dynarch.com/mishoo/calendar.epl\\n\";\n      }\n      alert(text);\n      return;\n        case -2:\n      if (year > cal.minYear) {\n        date.setFullYear(year - 1);\n      }\n      break;\n        case -1:\n      if (mon > 0) {\n        setMonth(mon - 1);\n      } else if (year-- > cal.minYear) {\n        date.setFullYear(year);\n        setMonth(11);\n      }\n      break;\n        case 1:\n      if (mon < 11) {\n        setMonth(mon + 1);\n      } else if (year < cal.maxYear) {\n        date.setFullYear(year + 1);\n        setMonth(0);\n      }\n      break;\n        case 2:\n      if (year < cal.maxYear) {\n        date.setFullYear(year + 1);\n      }\n      break;\n        case 100:\n      cal.setFirstDayOfWeek(el.fdow);\n      return;\n        case 50:\n      var range = el._range;\n      var current = el.innerHTML;\n      for (var i = range.length; --i >= 0;)\n        if (range[i] == current)\n          break;\n      if (ev && ev.shiftKey) {\n        if (--i < 0)\n          i = range.length - 1;\n      } else if ( ++i >= range.length )\n        i = 0;\n      var newval = range[i];\n      el.innerHTML = newval;\n      cal.onUpdateTime();\n      return;\n        case 0:\n      // TODAY will bring us here\n      if ((typeof cal.getDateStatus == \"function\") &&\n          cal.getDateStatus(date, date.getFullYear(), date.getMonth(), date.getDate())) {\n        return false;\n      }\n      break;\n    }\n    if (!date.equalsTo(cal.date)) {\n      cal.setDate(date);\n      newdate = true;\n    } else if (el.navtype == 0)\n      newdate = closing = true;\n  }\n  if (newdate) {\n    ev && cal.callHandler();\n  }\n  if (closing) {\n    Calendar.removeClass(el, \"hilite\");\n    ev && cal.callCloseHandler();\n  }\n};\n\n// END: CALENDAR STATIC FUNCTIONS\n\n// BEGIN: CALENDAR OBJECT FUNCTIONS\n\n/**\n *  This function creates the calendar inside the given parent.  If _par is\n *  null than it creates a popup calendar inside the BODY element.  If _par is\n *  an element, be it BODY, then it creates a non-popup calendar (still\n *  hidden).  Some properties need to be set before calling this function.\n */\nCalendar.prototype.create = function (_par) {\n  var parent = null;\n  if (! _par) {\n    // default parent is the document body, in which case we create\n    // a popup calendar.\n    parent = document.getElementsByTagName(\"body\")[0];\n    this.isPopup = true;\n  } else {\n    parent = _par;\n    this.isPopup = false;\n  }\n  this.date = this.dateStr ? new Date(this.dateStr) : new Date();\n\n  var table = Calendar.createElement(\"table\");\n  this.table = table;\n  table.cellSpacing = 0;\n  table.cellPadding = 0;\n  table.calendar = this;\n  Calendar.addEvent(table, \"mousedown\", Calendar.tableMouseDown);\n\n  var div = Calendar.createElement(\"div\");\n  this.element = div;\n  div.className = \"calendar\";\n  if (this.isPopup) {\n    div.style.position = \"absolute\";\n    div.style.display = \"none\";\n  }\n  div.appendChild(table);\n\n  var thead = Calendar.createElement(\"thead\", table);\n  var cell = null;\n  var row = null;\n\n  var cal = this;\n  var hh = function (text, cs, navtype) {\n    cell = Calendar.createElement(\"td\", row);\n    cell.colSpan = cs;\n    cell.className = \"button\";\n    if (navtype != 0 && Math.abs(navtype) <= 2)\n      cell.className += \" nav\";\n    Calendar._add_evs(cell);\n    cell.calendar = cal;\n    cell.navtype = navtype;\n    cell.innerHTML = \"<div unselectable='on'>\" + text + \"</div>\";\n    return cell;\n  };\n\n  row = Calendar.createElement(\"tr\", thead);\n  var title_length = 6;\n  (this.isPopup) && --title_length;\n  (this.weekNumbers) && ++title_length;\n\n  hh(\"?\", 1, 400).ttip = Calendar._TT[\"INFO\"];\n  this.title = hh(\"\", title_length, 300);\n  this.title.className = \"title\";\n  if (this.isPopup) {\n    this.title.ttip = Calendar._TT[\"DRAG_TO_MOVE\"];\n    this.title.style.cursor = \"move\";\n    hh(\"&#x00d7;\", 1, 200).ttip = Calendar._TT[\"CLOSE\"];\n  }\n\n  row = Calendar.createElement(\"tr\", thead);\n  row.className = \"headrow\";\n\n  this._nav_py = hh(\"&#x00ab;\", 1, -2);\n  this._nav_py.ttip = Calendar._TT[\"PREV_YEAR\"];\n\n  this._nav_pm = hh(\"&#x2039;\", 1, -1);\n  this._nav_pm.ttip = Calendar._TT[\"PREV_MONTH\"];\n\n  this._nav_now = hh(Calendar._TT[\"TODAY\"], this.weekNumbers ? 4 : 3, 0);\n  this._nav_now.ttip = Calendar._TT[\"GO_TODAY\"];\n\n  this._nav_nm = hh(\"&#x203a;\", 1, 1);\n  this._nav_nm.ttip = Calendar._TT[\"NEXT_MONTH\"];\n\n  this._nav_ny = hh(\"&#x00bb;\", 1, 2);\n  this._nav_ny.ttip = Calendar._TT[\"NEXT_YEAR\"];\n\n  // day names\n  row = Calendar.createElement(\"tr\", thead);\n  row.className = \"daynames\";\n  if (this.weekNumbers) {\n    cell = Calendar.createElement(\"td\", row);\n    cell.className = \"name wn\";\n    cell.innerHTML = Calendar._TT[\"WK\"];\n  }\n  for (var i = 7; i > 0; --i) {\n    cell = Calendar.createElement(\"td\", row);\n    if (!i) {\n      cell.navtype = 100;\n      cell.calendar = this;\n      Calendar._add_evs(cell);\n    }\n  }\n  this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild;\n  this._displayWeekdays();\n\n  var tbody = Calendar.createElement(\"tbody\", table);\n  this.tbody = tbody;\n\n  for (i = 6; i > 0; --i) {\n    row = Calendar.createElement(\"tr\", tbody);\n    if (this.weekNumbers) {\n      cell = Calendar.createElement(\"td\", row);\n    }\n    for (var j = 7; j > 0; --j) {\n      cell = Calendar.createElement(\"td\", row);\n      cell.calendar = this;\n      Calendar._add_evs(cell);\n    }\n  }\n\n  if (this.showsTime) {\n    row = Calendar.createElement(\"tr\", tbody);\n    row.className = \"time\";\n\n    cell = Calendar.createElement(\"td\", row);\n    cell.className = \"time\";\n    cell.colSpan = 2;\n    cell.innerHTML = Calendar._TT[\"TIME\"] || \"&nbsp;\";\n\n    cell = Calendar.createElement(\"td\", row);\n    cell.className = \"time\";\n    cell.colSpan = this.weekNumbers ? 4 : 3;\n\n    (function(){\n      function makeTimePart(className, init, range_start, range_end) {\n        var part = Calendar.createElement(\"span\", cell);\n        part.className = className;\n        part.innerHTML = init;\n        part.calendar = cal;\n        part.ttip = Calendar._TT[\"TIME_PART\"];\n        part.navtype = 50;\n        part._range = [];\n        if (typeof range_start != \"number\")\n          part._range = range_start;\n        else {\n          for (var i = range_start; i <= range_end; ++i) {\n            var txt;\n            if (i < 10 && range_end >= 10) txt = '0' + i;\n            else txt = '' + i;\n            part._range[part._range.length] = txt;\n          }\n        }\n        Calendar._add_evs(part);\n        return part;\n      };\n      var hrs = cal.date.getHours();\n      var mins = cal.date.getMinutes();\n      var t12 = !cal.time24;\n      var pm = (hrs > 12);\n      if (t12 && pm) hrs -= 12;\n      var H = makeTimePart(\"hour\", hrs, t12 ? 1 : 0, t12 ? 12 : 23);\n      var span = Calendar.createElement(\"span\", cell);\n      span.innerHTML = \":\";\n      span.className = \"colon\";\n      var M = makeTimePart(\"minute\", mins, 0, 59);\n      var AP = null;\n      cell = Calendar.createElement(\"td\", row);\n      cell.className = \"time\";\n      cell.colSpan = 2;\n      if (t12)\n        AP = makeTimePart(\"ampm\", pm ? \"pm\" : \"am\", [\"am\", \"pm\"]);\n      else\n        cell.innerHTML = \"&nbsp;\";\n\n      cal.onSetTime = function() {\n        var pm, hrs = this.date.getHours(),\n          mins = this.date.getMinutes();\n        if (t12) {\n          pm = (hrs >= 12);\n          if (pm) hrs -= 12;\n          if (hrs == 0) hrs = 12;\n          AP.innerHTML = pm ? \"pm\" : \"am\";\n        }\n        H.innerHTML = (hrs < 10) ? (\"0\" + hrs) : hrs;\n        M.innerHTML = (mins < 10) ? (\"0\" + mins) : mins;\n      };\n\n      cal.onUpdateTime = function() {\n        var date = this.date;\n        var h = parseInt(H.innerHTML, 10);\n        if (t12) {\n          if (/pm/i.test(AP.innerHTML) && h < 12)\n            h += 12;\n          else if (/am/i.test(AP.innerHTML) && h == 12)\n            h = 0;\n        }\n        var d = date.getDate();\n        var m = date.getMonth();\n        var y = date.getFullYear();\n        date.setHours(h);\n        date.setMinutes(parseInt(M.innerHTML, 10));\n        date.setFullYear(y);\n        date.setMonth(m);\n        date.setDate(d);\n        this.dateClicked = false;\n        this.callHandler();\n      };\n    })();\n  } else {\n    this.onSetTime = this.onUpdateTime = function() {};\n  }\n\n  var tfoot = Calendar.createElement(\"tfoot\", table);\n\n  row = Calendar.createElement(\"tr\", tfoot);\n  row.className = \"footrow\";\n\n  cell = hh(Calendar._TT[\"SEL_DATE\"], this.weekNumbers ? 8 : 7, 300);\n  cell.className = \"ttip\";\n  if (this.isPopup) {\n    cell.ttip = Calendar._TT[\"DRAG_TO_MOVE\"];\n    cell.style.cursor = \"move\";\n  }\n  this.tooltips = cell;\n\n  div = Calendar.createElement(\"div\", this.element);\n  this.monthsCombo = div;\n  div.className = \"combo\";\n  for (i = 0; i < Calendar._MN.length; ++i) {\n    var mn = Calendar.createElement(\"div\");\n    mn.className = Calendar.is_ie ? \"label-IEfix\" : \"label\";\n    mn.month = i;\n    mn.innerHTML = Calendar._SMN[i];\n    div.appendChild(mn);\n  }\n\n  div = Calendar.createElement(\"div\", this.element);\n  this.yearsCombo = div;\n  div.className = \"combo\";\n  for (i = 12; i > 0; --i) {\n    var yr = Calendar.createElement(\"div\");\n    yr.className = Calendar.is_ie ? \"label-IEfix\" : \"label\";\n    div.appendChild(yr);\n  }\n\n  this._init(this.firstDayOfWeek, this.date);\n  parent.appendChild(this.element);\n};\n\n/** keyboard navigation, only for popup calendars */\nCalendar._keyEvent = function(ev) {\n  var cal = window._dynarch_popupCalendar;\n  if (!cal || cal.multiple)\n    return false;\n  (Calendar.is_ie) && (ev = window.event);\n  var act = (Calendar.is_ie || ev.type == \"keypress\"),\n    K = ev.keyCode;\n  if (ev.ctrlKey) {\n    switch (K) {\n        case 37: // KEY left\n      act && Calendar.cellClick(cal._nav_pm);\n      break;\n        case 38: // KEY up\n      act && Calendar.cellClick(cal._nav_py);\n      break;\n        case 39: // KEY right\n      act && Calendar.cellClick(cal._nav_nm);\n      break;\n        case 40: // KEY down\n      act && Calendar.cellClick(cal._nav_ny);\n      break;\n        default:\n      return false;\n    }\n  } else switch (K) {\n      case 32: // KEY space (now)\n    Calendar.cellClick(cal._nav_now);\n    break;\n      case 27: // KEY esc\n    act && cal.callCloseHandler();\n    break;\n      case 37: // KEY left\n      case 38: // KEY up\n      case 39: // KEY right\n      case 40: // KEY down\n    if (act) {\n      var prev, x, y, ne, el, step;\n      prev = K == 37 || K == 38;\n      step = (K == 37 || K == 39) ? 1 : 7;\n      function setVars() {\n        el = cal.currentDateEl;\n        var p = el.pos;\n        x = p & 15;\n        y = p >> 4;\n        ne = cal.ar_days[y][x];\n      };setVars();\n      function prevMonth() {\n        var date = new Date(cal.date);\n        date.setDate(date.getDate() - step);\n        cal.setDate(date);\n      };\n      function nextMonth() {\n        var date = new Date(cal.date);\n        date.setDate(date.getDate() + step);\n        cal.setDate(date);\n      };\n      while (1) {\n        switch (K) {\n            case 37: // KEY left\n          if (--x >= 0)\n            ne = cal.ar_days[y][x];\n          else {\n            x = 6;\n            K = 38;\n            continue;\n          }\n          break;\n            case 38: // KEY up\n          if (--y >= 0)\n            ne = cal.ar_days[y][x];\n          else {\n            prevMonth();\n            setVars();\n          }\n          break;\n            case 39: // KEY right\n          if (++x < 7)\n            ne = cal.ar_days[y][x];\n          else {\n            x = 0;\n            K = 40;\n            continue;\n          }\n          break;\n            case 40: // KEY down\n          if (++y < cal.ar_days.length)\n            ne = cal.ar_days[y][x];\n          else {\n            nextMonth();\n            setVars();\n          }\n          break;\n        }\n        break;\n      }\n      if (ne) {\n        if (!ne.disabled)\n          Calendar.cellClick(ne);\n        else if (prev)\n          prevMonth();\n        else\n          nextMonth();\n      }\n    }\n    break;\n      case 13: // KEY enter\n    if (act)\n      Calendar.cellClick(cal.currentDateEl, ev);\n    break;\n      default:\n    return false;\n  }\n  return Calendar.stopEvent(ev);\n};\n\n/**\n *  (RE)Initializes the calendar to the given date and firstDayOfWeek\n */\nCalendar.prototype._init = function (firstDayOfWeek, date) {\n  var today = new Date(),\n    TY = today.getFullYear(),\n    TM = today.getMonth(),\n    TD = today.getDate();\n  this.table.style.visibility = \"hidden\";\n  var year = date.getFullYear();\n  if (year < this.minYear) {\n    year = this.minYear;\n    date.setFullYear(year);\n  } else if (year > this.maxYear) {\n    year = this.maxYear;\n    date.setFullYear(year);\n  }\n  this.firstDayOfWeek = firstDayOfWeek;\n  this.date = new Date(date);\n  var month = date.getMonth();\n  var mday = date.getDate();\n  var no_days = date.getMonthDays();\n\n  // calendar voodoo for computing the first day that would actually be\n  // displayed in the calendar, even if it's from the previous month.\n  // WARNING: this is magic. ;-)\n  date.setDate(1);\n  var day1 = (date.getDay() - this.firstDayOfWeek) % 7;\n  if (day1 < 0)\n    day1 += 7;\n  date.setDate(-day1);\n  date.setDate(date.getDate() + 1);\n\n  var row = this.tbody.firstChild;\n  var MN = Calendar._SMN[month];\n  var ar_days = this.ar_days = new Array();\n  var weekend = Calendar._TT[\"WEEKEND\"];\n  var dates = this.multiple ? (this.datesCells = {}) : null;\n  for (var i = 0; i < 6; ++i, row = row.nextSibling) {\n    var cell = row.firstChild;\n    if (this.weekNumbers) {\n      cell.className = \"day wn\";\n      cell.innerHTML = date.getWeekNumber();\n      cell = cell.nextSibling;\n    }\n    row.className = \"daysrow\";\n    var hasdays = false, iday, dpos = ar_days[i] = [];\n    for (var j = 0; j < 7; ++j, cell = cell.nextSibling, date.setDate(iday + 1)) {\n      iday = date.getDate();\n      var wday = date.getDay();\n      cell.className = \"day\";\n      cell.pos = i << 4 | j;\n      dpos[j] = cell;\n      var current_month = (date.getMonth() == month);\n      if (!current_month) {\n        if (this.showsOtherMonths) {\n          cell.className += \" othermonth\";\n          cell.otherMonth = true;\n        } else {\n          cell.className = \"emptycell\";\n          cell.innerHTML = \"&nbsp;\";\n          cell.disabled = true;\n          continue;\n        }\n      } else {\n        cell.otherMonth = false;\n        hasdays = true;\n      }\n      cell.disabled = false;\n      cell.innerHTML = this.getDateText ? this.getDateText(date, iday) : iday;\n      if (dates)\n        dates[date.print(\"%Y%m%d\")] = cell;\n      if (this.getDateStatus) {\n        var status = this.getDateStatus(date, year, month, iday);\n        if (this.getDateToolTip) {\n          var toolTip = this.getDateToolTip(date, year, month, iday);\n          if (toolTip)\n            cell.title = toolTip;\n        }\n        if (status === true) {\n          cell.className += \" disabled\";\n          cell.disabled = true;\n        } else {\n          if (/disabled/i.test(status))\n            cell.disabled = true;\n          cell.className += \" \" + status;\n        }\n      }\n      if (!cell.disabled) {\n        cell.caldate = new Date(date);\n        cell.ttip = \"_\";\n        if (!this.multiple && current_month\n            && iday == mday && this.hiliteToday) {\n          cell.className += \" selected\";\n          this.currentDateEl = cell;\n        }\n        if (date.getFullYear() == TY &&\n            date.getMonth() == TM &&\n            iday == TD) {\n          cell.className += \" today\";\n          cell.ttip += Calendar._TT[\"PART_TODAY\"];\n        }\n        if (weekend.indexOf(wday.toString()) != -1)\n          cell.className += cell.otherMonth ? \" oweekend\" : \" weekend\";\n      }\n    }\n    if (!(hasdays || this.showsOtherMonths))\n      row.className = \"emptyrow\";\n  }\n  this.title.innerHTML = Calendar._MN[month] + \", \" + year;\n  this.onSetTime();\n  this.table.style.visibility = \"visible\";\n  this._initMultipleDates();\n  // PROFILE\n  // this.tooltips.innerHTML = \"Generated in \" + ((new Date()) - today) + \" ms\";\n};\n\nCalendar.prototype._initMultipleDates = function() {\n  if (this.multiple) {\n    for (var i in this.multiple) {\n      var cell = this.datesCells[i];\n      var d = this.multiple[i];\n      if (!d)\n        continue;\n      if (cell)\n        cell.className += \" selected\";\n    }\n  }\n};\n\nCalendar.prototype._toggleMultipleDate = function(date) {\n  if (this.multiple) {\n    var ds = date.print(\"%Y%m%d\");\n    var cell = this.datesCells[ds];\n    if (cell) {\n      var d = this.multiple[ds];\n      if (!d) {\n        Calendar.addClass(cell, \"selected\");\n        this.multiple[ds] = date;\n      } else {\n        Calendar.removeClass(cell, \"selected\");\n        delete this.multiple[ds];\n      }\n    }\n  }\n};\n\nCalendar.prototype.setDateToolTipHandler = function (unaryFunction) {\n  this.getDateToolTip = unaryFunction;\n};\n\n/**\n *  Calls _init function above for going to a certain date (but only if the\n *  date is different than the currently selected one).\n */\nCalendar.prototype.setDate = function (date) {\n  if (!date.equalsTo(this.date)) {\n    this._init(this.firstDayOfWeek, date);\n  }\n};\n\n/**\n *  Refreshes the calendar.  Useful if the \"disabledHandler\" function is\n *  dynamic, meaning that the list of disabled date can change at runtime.\n *  Just * call this function if you think that the list of disabled dates\n *  should * change.\n */\nCalendar.prototype.refresh = function () {\n  this._init(this.firstDayOfWeek, this.date);\n};\n\n/** Modifies the \"firstDayOfWeek\" parameter (pass 0 for Synday, 1 for Monday, etc.). */\nCalendar.prototype.setFirstDayOfWeek = function (firstDayOfWeek) {\n  this._init(firstDayOfWeek, this.date);\n  this._displayWeekdays();\n};\n\n/**\n *  Allows customization of what dates are enabled.  The \"unaryFunction\"\n *  parameter must be a function object that receives the date (as a JS Date\n *  object) and returns a boolean value.  If the returned value is true then\n *  the passed date will be marked as disabled.\n */\nCalendar.prototype.setDateStatusHandler = Calendar.prototype.setDisabledHandler = function (unaryFunction) {\n  this.getDateStatus = unaryFunction;\n};\n\n/** Customization of allowed year range for the calendar. */\nCalendar.prototype.setRange = function (a, z) {\n  this.minYear = a;\n  this.maxYear = z;\n};\n\n/** Calls the first user handler (selectedHandler). */\nCalendar.prototype.callHandler = function () {\n  if (this.onSelected) {\n    this.onSelected(this, this.date.print(this.dateFormat));\n  }\n};\n\n/** Calls the second user handler (closeHandler). */\nCalendar.prototype.callCloseHandler = function () {\n  if (this.onClose) {\n    this.onClose(this);\n  }\n  this.hideShowCovered();\n};\n\n/** Removes the calendar object from the DOM tree and destroys it. */\nCalendar.prototype.destroy = function () {\n  var el = this.element.parentNode;\n  el.removeChild(this.element);\n  Calendar._C = null;\n  window._dynarch_popupCalendar = null;\n};\n\n/**\n *  Moves the calendar element to a different section in the DOM tree (changes\n *  its parent).\n */\nCalendar.prototype.reparent = function (new_parent) {\n  var el = this.element;\n  el.parentNode.removeChild(el);\n  new_parent.appendChild(el);\n};\n\n// This gets called when the user presses a mouse button anywhere in the\n// document, if the calendar is shown.  If the click was outside the open\n// calendar this function closes it.\nCalendar._checkCalendar = function(ev) {\n  var calendar = window._dynarch_popupCalendar;\n  if (!calendar) {\n    return false;\n  }\n  var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev);\n  for (; el != null && el != calendar.element; el = el.parentNode);\n  if (el == null) {\n    // calls closeHandler which should hide the calendar.\n    window._dynarch_popupCalendar.callCloseHandler();\n    return Calendar.stopEvent(ev);\n  }\n};\n\n/** Shows the calendar. */\nCalendar.prototype.show = function () {\n  var rows = this.table.getElementsByTagName(\"tr\");\n  for (var i = rows.length; i > 0;) {\n    var row = rows[--i];\n    Calendar.removeClass(row, \"rowhilite\");\n    var cells = row.getElementsByTagName(\"td\");\n    for (var j = cells.length; j > 0;) {\n      var cell = cells[--j];\n      Calendar.removeClass(cell, \"hilite\");\n      Calendar.removeClass(cell, \"active\");\n    }\n  }\n  this.element.style.display = \"block\";\n  this.hidden = false;\n  if (this.isPopup) {\n    window._dynarch_popupCalendar = this;\n    Calendar.addEvent(document, \"keydown\", Calendar._keyEvent);\n    Calendar.addEvent(document, \"keypress\", Calendar._keyEvent);\n    Calendar.addEvent(document, \"mousedown\", Calendar._checkCalendar);\n  }\n  this.hideShowCovered();\n};\n\n/**\n *  Hides the calendar.  Also removes any \"hilite\" from the class of any TD\n *  element.\n */\nCalendar.prototype.hide = function () {\n  if (this.isPopup) {\n    Calendar.removeEvent(document, \"keydown\", Calendar._keyEvent);\n    Calendar.removeEvent(document, \"keypress\", Calendar._keyEvent);\n    Calendar.removeEvent(document, \"mousedown\", Calendar._checkCalendar);\n  }\n  this.element.style.display = \"none\";\n  this.hidden = true;\n  this.hideShowCovered();\n};\n\n/**\n *  Shows the calendar at a given absolute position (beware that, depending on\n *  the calendar element style -- position property -- this might be relative\n *  to the parent's containing rectangle).\n */\nCalendar.prototype.showAt = function (x, y) {\n  var s = this.element.style;\n  s.left = x + \"px\";\n  s.top = y + \"px\";\n  this.show();\n};\n\n/** Shows the calendar near a given element. */\nCalendar.prototype.showAtElement = function (el, opts) {\n  var self = this;\n  var p = Calendar.getAbsolutePos(el);\n  if (!opts || typeof opts != \"string\") {\n    this.showAt(p.x, p.y + el.offsetHeight);\n    return true;\n  }\n  function fixPosition(box) {\n    if (box.x < 0)\n      box.x = 0;\n    if (box.y < 0)\n      box.y = 0;\n    var cp = document.createElement(\"div\");\n    var s = cp.style;\n    s.position = \"absolute\";\n    s.right = s.bottom = s.width = s.height = \"0px\";\n    document.body.appendChild(cp);\n    var br = Calendar.getAbsolutePos(cp);\n    document.body.removeChild(cp);\n    if (Calendar.is_ie) {\n      br.y += document.body.scrollTop;\n      br.x += document.body.scrollLeft;\n    } else {\n      br.y += window.scrollY;\n      br.x += window.scrollX;\n    }\n    var tmp = box.x + box.width - br.x;\n    if (tmp > 0) box.x -= tmp;\n    tmp = box.y + box.height - br.y;\n    if (tmp > 0) box.y -= tmp;\n  };\n  this.element.style.display = \"block\";\n  Calendar.continuation_for_the_fucking_khtml_browser = function() {\n    var w = self.element.offsetWidth;\n    var h = self.element.offsetHeight;\n    self.element.style.display = \"none\";\n    var valign = opts.substr(0, 1);\n    var halign = \"l\";\n    if (opts.length > 1) {\n      halign = opts.substr(1, 1);\n    }\n    // vertical alignment\n    switch (valign) {\n        case \"T\": p.y -= h; break;\n        case \"B\": p.y += el.offsetHeight; break;\n        case \"C\": p.y += (el.offsetHeight - h) / 2; break;\n        case \"t\": p.y += el.offsetHeight - h; break;\n        case \"b\": break; // already there\n    }\n    // horizontal alignment\n    switch (halign) {\n        case \"L\": p.x -= w; break;\n        case \"R\": p.x += el.offsetWidth; break;\n        case \"C\": p.x += (el.offsetWidth - w) / 2; break;\n        case \"l\": p.x += el.offsetWidth - w; break;\n        case \"r\": break; // already there\n    }\n    p.width = w;\n    p.height = h + 40;\n    self.monthsCombo.style.display = \"none\";\n    fixPosition(p);\n    self.showAt(p.x, p.y);\n  };\n  if (Calendar.is_khtml)\n    setTimeout(\"Calendar.continuation_for_the_fucking_khtml_browser()\", 10);\n  else\n    Calendar.continuation_for_the_fucking_khtml_browser();\n};\n\n/** Customizes the date format. */\nCalendar.prototype.setDateFormat = function (str) {\n  this.dateFormat = str;\n};\n\n/** Customizes the tooltip date format. */\nCalendar.prototype.setTtDateFormat = function (str) {\n  this.ttDateFormat = str;\n};\n\n/**\n *  Tries to identify the date represented in a string.  If successful it also\n *  calls this.setDate which moves the calendar to the given date.\n */\nCalendar.prototype.parseDate = function(str, fmt) {\n  if (!fmt)\n    fmt = this.dateFormat;\n  this.setDate(Date.parseDate(str, fmt));\n};\n\nCalendar.prototype.hideShowCovered = function () {\n  if (!Calendar.is_ie && !Calendar.is_opera)\n    return;\n  function getVisib(obj){\n    var value = obj.style.visibility;\n    if (!value) {\n      if (document.defaultView && typeof (document.defaultView.getComputedStyle) == \"function\") { // Gecko, W3C\n        if (!Calendar.is_khtml)\n          value = document.defaultView.\n            getComputedStyle(obj, \"\").getPropertyValue(\"visibility\");\n        else\n          value = '';\n      } else if (obj.currentStyle) { // IE\n        value = obj.currentStyle.visibility;\n      } else\n        value = '';\n    }\n    return value;\n  };\n\n  var tags = new Array(\"applet\", \"iframe\", \"select\");\n  var el = this.element;\n\n  var p = Calendar.getAbsolutePos(el);\n  var EX1 = p.x;\n  var EX2 = el.offsetWidth + EX1;\n  var EY1 = p.y;\n  var EY2 = el.offsetHeight + EY1;\n\n  for (var k = tags.length; k > 0; ) {\n    var ar = document.getElementsByTagName(tags[--k]);\n    var cc = null;\n\n    for (var i = ar.length; i > 0;) {\n      cc = ar[--i];\n\n      p = Calendar.getAbsolutePos(cc);\n      var CX1 = p.x;\n      var CX2 = cc.offsetWidth + CX1;\n      var CY1 = p.y;\n      var CY2 = cc.offsetHeight + CY1;\n\n      if (this.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) {\n        if (!cc.__msh_save_visibility) {\n          cc.__msh_save_visibility = getVisib(cc);\n        }\n        cc.style.visibility = cc.__msh_save_visibility;\n      } else {\n        if (!cc.__msh_save_visibility) {\n          cc.__msh_save_visibility = getVisib(cc);\n        }\n        cc.style.visibility = \"hidden\";\n      }\n    }\n  }\n};\n\n/** Internal function; it displays the bar with the names of the weekday. */\nCalendar.prototype._displayWeekdays = function () {\n  var fdow = this.firstDayOfWeek;\n  var cell = this.firstdayname;\n  var weekend = Calendar._TT[\"WEEKEND\"];\n  for (var i = 0; i < 7; ++i) {\n    cell.className = \"day name\";\n    var realday = (i + fdow) % 7;\n    if (i) {\n      cell.ttip = Calendar._TT[\"DAY_FIRST\"].replace(\"%s\", Calendar._DN[realday]);\n      cell.navtype = 100;\n      cell.calendar = this;\n      cell.fdow = realday;\n      Calendar._add_evs(cell);\n    }\n    if (weekend.indexOf(realday.toString()) != -1) {\n      Calendar.addClass(cell, \"weekend\");\n    }\n    cell.innerHTML = Calendar._SDN[(i + fdow) % 7];\n    cell = cell.nextSibling;\n  }\n};\n\n/** Internal function.  Hides all combo boxes that might be displayed. */\nCalendar.prototype._hideCombos = function () {\n  this.monthsCombo.style.display = \"none\";\n  this.yearsCombo.style.display = \"none\";\n};\n\n/** Internal function.  Starts dragging the element. */\nCalendar.prototype._dragStart = function (ev) {\n  if (this.dragging) {\n    return;\n  }\n  this.dragging = true;\n  var posX;\n  var posY;\n  if (Calendar.is_ie) {\n    posY = window.event.clientY + document.body.scrollTop;\n    posX = window.event.clientX + document.body.scrollLeft;\n  } else {\n    posY = ev.clientY + window.scrollY;\n    posX = ev.clientX + window.scrollX;\n  }\n  var st = this.element.style;\n  this.xOffs = posX - parseInt(st.left);\n  this.yOffs = posY - parseInt(st.top);\n  with (Calendar) {\n    addEvent(document, \"mousemove\", calDragIt);\n    addEvent(document, \"mouseup\", calDragEnd);\n  }\n};\n\n// BEGIN: DATE OBJECT PATCHES\n\n/** Adds the number of days array to the Date object. */\nDate._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31);\n\n/** Constants used for time computations */\nDate.SECOND = 1000 /* milliseconds */;\nDate.MINUTE = 60 * Date.SECOND;\nDate.HOUR   = 60 * Date.MINUTE;\nDate.DAY    = 24 * Date.HOUR;\nDate.WEEK   =  7 * Date.DAY;\n\nDate.parseDate = function(str, fmt) {\n  var today = new Date();\n  var y = 0;\n  var m = -1;\n  var d = 0;\n  var a = str.split(/\\W+/);\n  var b = fmt.match(/%./g);\n  var i = 0, j = 0;\n  var hr = 0;\n  var min = 0;\n  for (i = 0; i < a.length; ++i) {\n    if (!a[i])\n      continue;\n    switch (b[i]) {\n        case \"%d\":\n        case \"%e\":\n      d = parseInt(a[i], 10);\n      break;\n\n        case \"%m\":\n      m = parseInt(a[i], 10) - 1;\n      break;\n\n        case \"%Y\":\n        case \"%y\":\n      y = parseInt(a[i], 10);\n      (y < 100) && (y += (y > 29) ? 1900 : 2000);\n      break;\n\n        case \"%b\":\n        case \"%B\":\n      for (j = 0; j < 12; ++j) {\n        if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; }\n      }\n      break;\n\n        case \"%H\":\n        case \"%I\":\n        case \"%k\":\n        case \"%l\":\n      hr = parseInt(a[i], 10);\n      break;\n\n        case \"%P\":\n        case \"%p\":\n      if (/pm/i.test(a[i]) && hr < 12)\n        hr += 12;\n      else if (/am/i.test(a[i]) && hr >= 12)\n        hr -= 12;\n      break;\n\n        case \"%M\":\n      min = parseInt(a[i], 10);\n      break;\n    }\n  }\n  if (isNaN(y)) y = today.getFullYear();\n  if (isNaN(m)) m = today.getMonth();\n  if (isNaN(d)) d = today.getDate();\n  if (isNaN(hr)) hr = today.getHours();\n  if (isNaN(min)) min = today.getMinutes();\n  if (y != 0 && m != -1 && d != 0)\n    return new Date(y, m, d, hr, min, 0);\n  y = 0; m = -1; d = 0;\n  for (i = 0; i < a.length; ++i) {\n    if (a[i].search(/[a-zA-Z]+/) != -1) {\n      var t = -1;\n      for (j = 0; j < 12; ++j) {\n        if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }\n      }\n      if (t != -1) {\n        if (m != -1) {\n          d = m+1;\n        }\n        m = t;\n      }\n    } else if (parseInt(a[i], 10) <= 12 && m == -1) {\n      m = a[i]-1;\n    } else if (parseInt(a[i], 10) > 31 && y == 0) {\n      y = parseInt(a[i], 10);\n      (y < 100) && (y += (y > 29) ? 1900 : 2000);\n    } else if (d == 0) {\n      d = a[i];\n    }\n  }\n  if (y == 0)\n    y = today.getFullYear();\n  if (m != -1 && d != 0)\n    return new Date(y, m, d, hr, min, 0);\n  return today;\n};\n\n/** Returns the number of days in the current month */\nDate.prototype.getMonthDays = function(month) {\n  var year = this.getFullYear();\n  if (typeof month == \"undefined\") {\n    month = this.getMonth();\n  }\n  if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) {\n    return 29;\n  } else {\n    return Date._MD[month];\n  }\n};\n\n/** Returns the number of day in the year. */\nDate.prototype.getDayOfYear = function() {\n  var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);\n  var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);\n  var time = now - then;\n  return Math.floor(time / Date.DAY);\n};\n\n/** Returns the number of the week in year, as defined in ISO 8601. */\nDate.prototype.getWeekNumber = function() {\n  var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);\n  var DoW = d.getDay();\n  d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu\n  var ms = d.valueOf(); // GMT\n  d.setMonth(0);\n  d.setDate(4); // Thu in Week 1\n  return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;\n};\n\n/** Checks date and time equality */\nDate.prototype.equalsTo = function(date) {\n  return ((this.getFullYear() == date.getFullYear()) &&\n    (this.getMonth() == date.getMonth()) &&\n    (this.getDate() == date.getDate()) &&\n    (this.getHours() == date.getHours()) &&\n    (this.getMinutes() == date.getMinutes()));\n};\n\n/** Set only the year, month, date parts (keep existing time) */\nDate.prototype.setDateOnly = function(date) {\n  var tmp = new Date(date);\n  this.setDate(1);\n  this.setFullYear(tmp.getFullYear());\n  this.setMonth(tmp.getMonth());\n  this.setDate(tmp.getDate());\n};\n\n/** Prints the date in a string according to the given format. */\nDate.prototype.print = function (str) {\n  var m = this.getMonth();\n  var d = this.getDate();\n  var y = this.getFullYear();\n  var wn = this.getWeekNumber();\n  var w = this.getDay();\n  var s = {};\n  var hr = this.getHours();\n  var pm = (hr >= 12);\n  var ir = (pm) ? (hr - 12) : hr;\n  var dy = this.getDayOfYear();\n  if (ir == 0)\n    ir = 12;\n  var min = this.getMinutes();\n  var sec = this.getSeconds();\n  s[\"%a\"] = Calendar._SDN[w]; // abbreviated weekday name [FIXME: I18N]\n  s[\"%A\"] = Calendar._DN[w]; // full weekday name\n  s[\"%b\"] = Calendar._SMN[m]; // abbreviated month name [FIXME: I18N]\n  s[\"%B\"] = Calendar._MN[m]; // full month name\n  // FIXME: %c : preferred date and time representation for the current locale\n  s[\"%C\"] = 1 + Math.floor(y / 100); // the century number\n  s[\"%d\"] = (d < 10) ? (\"0\" + d) : d; // the day of the month (range 01 to 31)\n  s[\"%e\"] = d; // the day of the month (range 1 to 31)\n  // FIXME: %D : american date style: %m/%d/%y\n  // FIXME: %E, %F, %G, %g, %h (man strftime)\n  s[\"%H\"] = (hr < 10) ? (\"0\" + hr) : hr; // hour, range 00 to 23 (24h format)\n  s[\"%I\"] = (ir < 10) ? (\"0\" + ir) : ir; // hour, range 01 to 12 (12h format)\n  s[\"%j\"] = (dy < 100) ? ((dy < 10) ? (\"00\" + dy) : (\"0\" + dy)) : dy; // day of the year (range 001 to 366)\n  s[\"%k\"] = hr;    // hour, range 0 to 23 (24h format)\n  s[\"%l\"] = ir;    // hour, range 1 to 12 (12h format)\n  s[\"%m\"] = (m < 9) ? (\"0\" + (1+m)) : (1+m); // month, range 01 to 12\n  s[\"%M\"] = (min < 10) ? (\"0\" + min) : min; // minute, range 00 to 59\n  s[\"%n\"] = \"\\n\";    // a newline character\n  s[\"%p\"] = pm ? \"PM\" : \"AM\";\n  s[\"%P\"] = pm ? \"pm\" : \"am\";\n  // FIXME: %r : the time in am/pm notation %I:%M:%S %p\n  // FIXME: %R : the time in 24-hour notation %H:%M\n  s[\"%s\"] = Math.floor(this.getTime() / 1000);\n  s[\"%S\"] = (sec < 10) ? (\"0\" + sec) : sec; // seconds, range 00 to 59\n  s[\"%t\"] = \"\\t\";    // a tab character\n  // FIXME: %T : the time in 24-hour notation (%H:%M:%S)\n  s[\"%U\"] = s[\"%W\"] = s[\"%V\"] = (wn < 10) ? (\"0\" + wn) : wn;\n  s[\"%u\"] = w + 1;  // the day of the week (range 1 to 7, 1 = MON)\n  s[\"%w\"] = w;    // the day of the week (range 0 to 6, 0 = SUN)\n  // FIXME: %x : preferred date representation for the current locale without the time\n  // FIXME: %X : preferred time representation for the current locale without the date\n  s[\"%y\"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)\n  s[\"%Y\"] = y;    // year with the century\n  s[\"%%\"] = \"%\";    // a literal '%' character\n\n  var re = /%./g;\n  if (!Calendar.is_ie5 && !Calendar.is_khtml)\n    return str.replace(re, function (par) { return s[par] || par; });\n\n  var a = str.match(re);\n  for (var i = 0; i < a.length; i++) {\n    var tmp = s[a[i]];\n    if (tmp) {\n      re = new RegExp(a[i], 'g');\n      str = str.replace(re, tmp);\n    }\n  }\n\n  return str;\n};\n\nDate.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;\nDate.prototype.setFullYear = function(y) {\n  var d = new Date(this);\n  d.__msh_oldSetFullYear(y);\n  if (d.getMonth() != this.getMonth())\n    this.setDate(28);\n  this.__msh_oldSetFullYear(y);\n};\n\n// END: DATE OBJECT PATCHES\n\n\n// global object that remembers the calendar\nwindow._dynarch_popupCalendar = null;\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-bg.js",
    "content": "// ** I18N\n\n// Calendar BG language\n// Author: Nikolay Solakov, <thoranga@gmail.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Неделя\",\n \"Понеделник\",\n \"Вторник\",\n \"Сряда\",\n \"Четвъртък\",\n \"Петък\",\n \"Събота\",\n \"Неделя\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Нед\",\n \"Пон\",\n \"Вто\",\n \"Сря\",\n \"Чет\",\n \"Пет\",\n \"Съб\",\n \"Нед\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Януари\",\n \"Февруари\",\n \"Март\",\n \"Април\",\n \"Май\",\n \"Юни\",\n \"Юли\",\n \"Август\",\n \"Септември\",\n \"Октомври\",\n \"Ноември\",\n \"Декември\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Яну\",\n \"Фев\",\n \"Мар\",\n \"Апр\",\n \"Май\",\n \"Юни\",\n \"Юли\",\n \"Авг\",\n \"Сеп\",\n \"Окт\",\n \"Ное\",\n \"Дек\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"За календара\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Избор на дата:\\n\" +\n\"- Използвайте \\xab, \\xbb за избор на година\\n\" +\n\"- Използвайте \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" за избор на месец\\n\" +\n\"- Задръжте натиснат бутона за списък с години/месеци.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Избор на час:\\n\" +\n\"- Кликнете на числата от часа за да ги увеличите\\n\" +\n\"- или Shift-click за намаляването им\\n\" +\n\"- или кликнете и влачете за по-бърза промяна.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Предишна година (задръжте за списък)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Предишен месец (задръжте за списък)\";\nCalendar._TT[\"GO_TODAY\"] = \"Днешна дата\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Следващ месец (задръжте за списък)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Следваща година (задръжте за списък)\";\nCalendar._TT[\"SEL_DATE\"] = \"Избор на дата\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Дръпнете за преместване\";\nCalendar._TT[\"PART_TODAY\"] = \" (днес)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Седмицата започва с %s\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Затвори\";\nCalendar._TT[\"TODAY\"] = \"Днес\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Click или влачене за промяна на стойност\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"седм\";\nCalendar._TT[\"TIME\"] = \"Час:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-bs.js",
    "content": "// ** I18N\n\n// Calendar BS language\n// Autor: Ernad Husremović <hernad@bring.out.ba>\n//\n// Preuzeto od Dragan Matic, <kkid@panforma.co.yu>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Nedjelja\",\n \"Ponedeljak\",\n \"Utorak\",\n \"Srijeda\",\n \"Četvrtak\",\n \"Petak\",\n \"Subota\",\n \"Nedelja\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Ned\",\n \"Pon\",\n \"Uto\",\n \"Sri\",\n \"Čet\",\n \"Pet\",\n \"Sub\",\n \"Ned\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"Januar\",\n \"Februar\",\n \"Mart\",\n \"April\",\n \"Maj\",\n \"Jun\",\n \"Jul\",\n \"Avgust\",\n \"Septembar\",\n \"Oktobar\",\n \"Novembar\",\n \"Decembar\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"Maj\",\n \"Jun\",\n \"Jul\",\n \"Avg\",\n \"Sep\",\n \"Okt\",\n \"Nov\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"O kalendaru\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Date selection:\\n\" +\n\"- Use the \\xab, \\xbb buttons to select year\\n\" +\n\"- Use the \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" buttons to select month\\n\" +\n\"- Hold mouse button on any of the above buttons for faster selection.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Time selection:\\n\" +\n\"- Click on any of the time parts to increase it\\n\" +\n\"- or Shift-click to decrease it\\n\" +\n\"- or click and drag for faster selection.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Preth. godina (drži pritisnuto za meni)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Preth. mjesec (drži pritisnuto za meni)\";\nCalendar._TT[\"GO_TODAY\"] = \"Na današnji dan\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Naredni mjesec (drži pritisnuto za meni)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Naredna godina (drži prisnuto za meni)\";\nCalendar._TT[\"SEL_DATE\"] = \"Izbor datuma\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Prevucite za izmjenu\";\nCalendar._TT[\"PART_TODAY\"] = \" (danas)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Prikaži %s prvo\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Zatvori\";\nCalendar._TT[\"TODAY\"] = \"Danas\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Klik ili prevlačenje za izmjenu vrijednosti\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d.%m.%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"Vrijeme:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-ca.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Diumenge\",\n \"Dilluns\",\n \"Dimarts\",\n \"Dimecres\",\n \"Dijous\",\n \"Divendres\",\n \"Dissabte\",\n \"Diumenge\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"dg\",\n \"dl\",\n \"dt\",\n \"dc\",\n \"dj\",\n \"dv\",\n \"ds\",\n \"dg\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"Gener\",\n \"Febrer\",\n \"Març\",\n \"Abril\",\n \"Maig\",\n \"Juny\",\n \"Juliol\",\n \"Agost\",\n \"Setembre\",\n \"Octubre\",\n \"Novembre\",\n \"Desembre\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Gen\",\n \"Feb\",\n \"Mar\",\n \"Abr\",\n \"Mai\",\n \"Jun\",\n \"Jul\",\n \"Ago\",\n \"Set\",\n \"Oct\",\n \"Nov\",\n \"Des\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Quant al calendari\";\n\nCalendar._TT[\"ABOUT\"] =\n\"Selector DHTML de data/hora\\n\" +\n\"(c) dynarch.com 2002-2005 / Autor: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"Per a aconseguir l'última versió visiteu: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distribuït sota la llicència GNU LGPL.  Vegeu http://gnu.org/licenses/lgpl.html per a més detalls.\" +\n\"\\n\\n\" +\n\"Selecció de la data:\\n\" +\n\"- Utilitzeu els botons \\xab, \\xbb per a seleccionar l'any\\n\" +\n\"- Utilitzeu els botons \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" per a selecciona el mes\\n\" +\n\"- Mantingueu premut el botó del ratolí sobre qualsevol d'aquests botons per a uns selecció més ràpida.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Selecció de l'hora:\\n\" +\n\"- Feu clic en qualsevol part de l'hora per a incrementar-la\\n\" +\n\"- o premeu majúscules per a disminuir-la\\n\" +\n\"- o feu clic i arrossegueu per a una selecció més ràpida.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Any anterior (mantenir per menú)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Mes anterior (mantenir per menú)\";\nCalendar._TT[\"GO_TODAY\"] = \"Anar a avui\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Mes següent (mantenir per menú)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Any següent (mantenir per menú)\";\nCalendar._TT[\"SEL_DATE\"] = \"Sel·lecciona data\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Arrossega per a moure\";\nCalendar._TT[\"PART_TODAY\"] = \" (avui)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Primer mostra el %s\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Tanca\";\nCalendar._TT[\"TODAY\"] = \"Avui\";\nCalendar._TT[\"TIME_PART\"] = \"(Majúscules-)Feu clic o arrossegueu per a canviar el valor\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d-%m-%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%A, %e de %B de %Y\";\n\nCalendar._TT[\"WK\"] = \"set\";\nCalendar._TT[\"TIME\"] = \"Hora:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-cs.js",
    "content": "/*\n  calendar-cs-win.js\n  language: Czech\n  encoding: windows-1250\n  author: Lubos Jerabek (xnet@seznam.cz)\n          Jan Uhlir (espinosa@centrum.cz)\n*/\n\n// ** I18N\nCalendar._DN  = new Array('Neděle','Pondělí','Úterý','Středa','Čtvrtek','Pátek','Sobota','Neděle');\nCalendar._SDN = new Array('Ne','Po','Út','St','Čt','Pá','So','Ne');\nCalendar._MN  = new Array('Leden','Únor','Březen','Duben','Květen','Červen','Červenec','Srpen','Září','Říjen','Listopad','Prosinec');\nCalendar._SMN = new Array('Led','Úno','Bře','Dub','Kvě','Črv','Čvc','Srp','Zář','Říj','Lis','Pro');\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"O komponentě kalendář\";\nCalendar._TT[\"TOGGLE\"] = \"Změna prvního dne v týdnu\";\nCalendar._TT[\"PREV_YEAR\"] = \"Předchozí rok (přidrž pro menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Předchozí měsíc (přidrž pro menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Dnešní datum\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Další měsíc (přidrž pro menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Další rok (přidrž pro menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Vyber datum\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Chyť a táhni, pro přesun\";\nCalendar._TT[\"PART_TODAY\"] = \" (dnes)\";\nCalendar._TT[\"MON_FIRST\"] = \"Ukaž jako první Pondělí\";\n//Calendar._TT[\"SUN_FIRST\"] = \"Ukaž jako první Neděli\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Výběr datumu:\\n\" +\n\"- Use the \\xab, \\xbb buttons to select year\\n\" +\n\"- Použijte tlačítka \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" k výběru měsíce\\n\" +\n\"- Podržte tlačítko myši na jakémkoliv z těch tlačítek pro rychlejší výběr.\";\n\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Výběr času:\\n\" +\n\"- Klikněte na jakoukoliv z částí výběru času pro zvýšení.\\n\" +\n\"- nebo Shift-click pro snížení\\n\" +\n\"- nebo klikněte a táhněte pro rychlejší výběr.\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Zobraz %s první\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Zavřít\";\nCalendar._TT[\"TODAY\"] = \"Dnes\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Klikni nebo táhni pro změnu hodnoty\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"d.m.yy\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"Čas:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-da.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Translater: Mads N. Vestergaard <mnv@coolsms.dk>\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Søndag\",\n \"Mandag\",\n \"Tirsdag\",\n \"Onsdag\",\n \"Torsdag\",\n \"Fredag\",\n \"Lørdag\",\n \"Søndag\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Søn\",\n \"Man\",\n \"Tir\",\n \"Ons\",\n \"Tor\",\n \"Fre\",\n \"Lør\",\n \"Søn\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Januar\",\n \"Februar\",\n \"Marts\",\n \"April\",\n \"Maj\",\n \"Juni\",\n \"Juli\",\n \"August\",\n \"September\",\n \"Oktober\",\n \"November\",\n \"December\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"Maj\",\n \"Jun\",\n \"Jul\",\n \"Aug\",\n \"Sep\",\n \"Okt\",\n \"Nov\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Om denne kalender\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For seneste version, besøg: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distribueret under GNU LGPL.  Se http://gnu.org/licenses/lgpl.html for detaljer.\" +\n\"\\n\\n\" +\n\"Dato valg:\\n\" +\n\"- Benyt \\xab, \\xbb tasterne til at vælge år\\n\" +\n\"- Benyt \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" tasterne til at vælge måned\\n\" +\n\"- Hold musetasten inde på punkterne for at vælge hurtigere.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Tids valg:\\n\" +\n\"- Klik på en af tidsrammerne for at forhøje det\\n\" +\n\"- eller Shift-klik for at mindske det\\n\" +\n\"- eller klik og træk for hurtigere valg.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Forrige år (hold for menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Forrige måned (hold for menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Gå til dags dato\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Næste måned (hold for menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Næste år (hold for menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Vælg dato\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Træk for at flytte\";\nCalendar._TT[\"PART_TODAY\"] = \" (dags dato)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Vis %s først\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"6,7\";\n\nCalendar._TT[\"CLOSE\"] = \"Luk\";\nCalendar._TT[\"TODAY\"] = \"I dag\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Klik eller træk for at ændre værdi\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"uge\";\nCalendar._TT[\"TIME\"] = \"Tid:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-de.js",
    "content": "// ** I18N\n\n// Calendar DE language\n// Author: Jack (tR), <jack@jtr.de>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Sonntag\",\n \"Montag\",\n \"Dienstag\",\n \"Mittwoch\",\n \"Donnerstag\",\n \"Freitag\",\n \"Samstag\",\n \"Sonntag\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// short day names\nCalendar._SDN = new Array\n(\"So\",\n \"Mo\",\n \"Di\",\n \"Mi\",\n \"Do\",\n \"Fr\",\n \"Sa\",\n \"So\");\n\n// full month names\nCalendar._MN = new Array\n(\"Januar\",\n \"Februar\",\n \"M\\u00e4rz\",\n \"April\",\n \"Mai\",\n \"Juni\",\n \"Juli\",\n \"August\",\n \"September\",\n \"Oktober\",\n \"November\",\n \"Dezember\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Feb\",\n \"M\\u00e4r\",\n \"Apr\",\n \"May\",\n \"Jun\",\n \"Jul\",\n \"Aug\",\n \"Sep\",\n \"Okt\",\n \"Nov\",\n \"Dez\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"\\u00DCber dieses Kalendarmodul\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Datum ausw\\u00e4hlen:\\n\" +\n\"- Benutzen Sie die \\xab, \\xbb Buttons um das Jahr zu w\\u00e4hlen\\n\" +\n\"- Benutzen Sie die \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" Buttons um den Monat zu w\\u00e4hlen\\n\" +\n\"- F\\u00fcr eine Schnellauswahl halten Sie die Maustaste \\u00fcber diesen Buttons fest.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Zeit ausw\\u00e4hlen:\\n\" +\n\"- Klicken Sie auf die Teile der Uhrzeit, um diese zu erh\\u00F6hen\\n\" +\n\"- oder klicken Sie mit festgehaltener Shift-Taste um diese zu verringern\\n\" +\n\"- oder klicken und festhalten f\\u00fcr Schnellauswahl.\";\n\nCalendar._TT[\"TOGGLE\"] = \"Ersten Tag der Woche w\\u00e4hlen\";\nCalendar._TT[\"PREV_YEAR\"] = \"Voriges Jahr (Festhalten f\\u00fcr Schnellauswahl)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Voriger Monat (Festhalten f\\u00fcr Schnellauswahl)\";\nCalendar._TT[\"GO_TODAY\"] = \"Heute ausw\\u00e4hlen\";\nCalendar._TT[\"NEXT_MONTH\"] = \"N\\u00e4chst. Monat (Festhalten f\\u00fcr Schnellauswahl)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"N\\u00e4chst. Jahr (Festhalten f\\u00fcr Schnellauswahl)\";\nCalendar._TT[\"SEL_DATE\"] = \"Datum ausw\\u00e4hlen\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Zum Bewegen festhalten\";\nCalendar._TT[\"PART_TODAY\"] = \" (Heute)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Woche beginnt mit %s \";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Schlie\\u00dfen\";\nCalendar._TT[\"TODAY\"] = \"Heute\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Klick oder Festhalten und Ziehen um den Wert zu \\u00e4ndern\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d.%m.%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"Zeit:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-en.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Sunday\",\n \"Monday\",\n \"Tuesday\",\n \"Wednesday\",\n \"Thursday\",\n \"Friday\",\n \"Saturday\",\n \"Sunday\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Sun\",\n \"Mon\",\n \"Tue\",\n \"Wed\",\n \"Thu\",\n \"Fri\",\n \"Sat\",\n \"Sun\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"May\",\n \"Jun\",\n \"Jul\",\n \"Aug\",\n \"Sep\",\n \"Oct\",\n \"Nov\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"About the calendar\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Date selection:\\n\" +\n\"- Use the \\xab, \\xbb buttons to select year\\n\" +\n\"- Use the \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" buttons to select month\\n\" +\n\"- Hold mouse button on any of the above buttons for faster selection.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Time selection:\\n\" +\n\"- Click on any of the time parts to increase it\\n\" +\n\"- or Shift-click to decrease it\\n\" +\n\"- or click and drag for faster selection.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Prev. year (hold for menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Prev. month (hold for menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Go Today\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Next month (hold for menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Next year (hold for menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Select date\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Drag to move\";\nCalendar._TT[\"PART_TODAY\"] = \" (today)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Display %s first\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Close\";\nCalendar._TT[\"TODAY\"] = \"Today\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Click or drag to change value\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"Time:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-es.js",
    "content": "// ** I18N\n\n// Calendar ES (spanish) language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Updater: Servilio Afre Puentes <servilios@yahoo.com>\n// Updated: 2004-06-03\n// Encoding: utf-8\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Domingo\",\n \"Lunes\",\n \"Martes\",\n \"Miércoles\",\n \"Jueves\",\n \"Viernes\",\n \"Sábado\",\n \"Domingo\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Dom\",\n \"Lun\",\n \"Mar\",\n \"Mié\",\n \"Jue\",\n \"Vie\",\n \"Sáb\",\n \"Dom\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Enero\",\n \"Febrero\",\n \"Marzo\",\n \"Abril\",\n \"Mayo\",\n \"Junio\",\n \"Julio\",\n \"Agosto\",\n \"Septiembre\",\n \"Octubre\",\n \"Noviembre\",\n \"Diciembre\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Ene\",\n \"Feb\",\n \"Mar\",\n \"Abr\",\n \"May\",\n \"Jun\",\n \"Jul\",\n \"Ago\",\n \"Sep\",\n \"Oct\",\n \"Nov\",\n \"Dic\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Acerca del calendario\";\n\nCalendar._TT[\"ABOUT\"] =\n\"Selector DHTML de Fecha/Hora\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"Para conseguir la última versión visite: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distribuido bajo licencia GNU LGPL. Visite http://gnu.org/licenses/lgpl.html para más detalles.\" +\n\"\\n\\n\" +\n\"Selección de fecha:\\n\" +\n\"- Use los botones \\xab, \\xbb para seleccionar el año\\n\" +\n\"- Use los botones \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" para seleccionar el mes\\n\" +\n\"- Mantenga pulsado el ratón en cualquiera de estos botones para una selección rápida.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Selección de hora:\\n\" +\n\"- Pulse en cualquiera de las partes de la hora para incrementarla\\n\" +\n\"- o pulse las mayúsculas mientras hace clic para decrementarla\\n\" +\n\"- o haga clic y arrastre el ratón para una selección más rápida.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Año anterior (mantener para menú)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Mes anterior (mantener para menú)\";\nCalendar._TT[\"GO_TODAY\"] = \"Ir a hoy\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Mes siguiente (mantener para menú)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Año siguiente (mantener para menú)\";\nCalendar._TT[\"SEL_DATE\"] = \"Seleccionar fecha\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Arrastrar para mover\";\nCalendar._TT[\"PART_TODAY\"] = \" (hoy)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Hacer %s primer día de la semana\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Cerrar\";\nCalendar._TT[\"TODAY\"] = \"Hoy\";\nCalendar._TT[\"TIME_PART\"] = \"(Mayúscula-)Clic o arrastre para cambiar valor\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d/%m/%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%A, %e de %B de %Y\";\n\nCalendar._TT[\"WK\"] = \"sem\";\nCalendar._TT[\"TIME\"] = \"Hora:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-fi.js",
    "content": "// ** I18N\n\n// Calendar FI language\n// Author: Antti Perkiömäki <antti.perkiomaki@gmail.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Sunnuntai\",\n \"Maanantai\",\n \"Tiistai\",\n \"Keskiviikko\",\n \"Torstai\",\n \"Perjantai\",\n \"Lauantai\",\n \"Sunnuntai\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Su\",\n \"Ma\",\n \"Ti\",\n \"Ke\",\n \"To\",\n \"Pe\",\n \"La\",\n \"Su\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Tammikuu\",\n \"Helmikuu\",\n \"Maaliskuu\",\n \"Huhtikuu\",\n \"Toukokuu\",\n \"Kesäkuu\",\n \"Heinäkuu\",\n \"Elokuu\",\n \"Syyskuu\",\n \"Lokakuu\",\n \"Marraskuu\",\n \"Joulukuu\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Tammi\",\n \"Helmi\",\n \"Maalis\",\n \"Huhti\",\n \"Touko\",\n \"Kesä\",\n \"Heinä\",\n \"Elo\",\n \"Syys\",\n \"Loka\",\n \"Marras\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Tietoa kalenterista\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Tekijä: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"Viimeisin versio: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Jaettu GNU LGPL alaisena. Katso lisätiedot http://gnu.org/licenses/lgpl.html\" +\n\"\\n\\n\" +\n\"Päivä valitsin:\\n\" +\n\"- Käytä \\xab, \\xbb painikkeita valitaksesi vuoden\\n\" +\n\"- Käytä \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" painikkeita valitaksesi kuukauden\\n\" +\n\"- Pidä alhaalla hiiren painiketta missä tahansa yllämainituissa painikkeissa valitaksesi nopeammin.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Ajan valinta:\\n\" +\n\"- Paina mitä tahansa ajan osaa kasvattaaksesi sitä\\n\" +\n\"- tai Vaihtonäppäin-paina laskeaksesi sitä\\n\" +\n\"- tai paina ja raahaa valitaksesi nopeammin.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Edellinen vuosi (valikko tulee painaessa)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Edellinen kuukausi (valikko tulee painaessa)\";\nCalendar._TT[\"GO_TODAY\"] = \"Siirry Tänään\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Seuraava kuukausi (valikko tulee painaessa)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Seuraava vuosi (valikko tulee painaessa)\";\nCalendar._TT[\"SEL_DATE\"] = \"Valitse päivä\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Rahaa siirtääksesi\";\nCalendar._TT[\"PART_TODAY\"] = \" (tänään)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Näytä %s ensin\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"6,0\";\n\nCalendar._TT[\"CLOSE\"] = \"Sulje\";\nCalendar._TT[\"TODAY\"] = \"Tänään\";\nCalendar._TT[\"TIME_PART\"] = \"(Vaihtonäppäin-)Paina tai raahaa vaihtaaksesi arvoa\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d.%m.%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"vko\";\nCalendar._TT[\"TIME\"] = \"Aika:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-fr.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// Translator: David Duret, <pilgrim@mala-template.net> from previous french version\n\n// full day names\nCalendar._DN = new Array\n(\"Dimanche\",\n \"Lundi\",\n \"Mardi\",\n \"Mercredi\",\n \"Jeudi\",\n \"Vendredi\",\n \"Samedi\",\n \"Dimanche\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Dim\",\n \"Lun\",\n \"Mar\",\n \"Mer\",\n \"Jeu\",\n \"Ven\",\n \"Sam\",\n \"Dim\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Janvier\",\n \"Février\",\n \"Mars\",\n \"Avril\",\n \"Mai\",\n \"Juin\",\n \"Juillet\",\n \"Août\",\n \"Septembre\",\n \"Octobre\",\n \"Novembre\",\n \"Décembre\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Fev\",\n \"Mar\",\n \"Avr\",\n \"Mai\",\n \"Juin\",\n \"Juil\",\n \"Aout\",\n \"Sep\",\n \"Oct\",\n \"Nov\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"A propos du calendrier\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Heure Selecteur\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"Pour la derniere version visitez : http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distribué par GNU LGPL.  Voir http://gnu.org/licenses/lgpl.html pour les details.\" +\n\"\\n\\n\" +\n\"Selection de la date :\\n\" +\n\"- Utiliser les bouttons \\xab, \\xbb  pour selectionner l\\'annee\\n\" +\n\"- Utiliser les bouttons \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" pour selectionner les mois\\n\" +\n\"- Garder la souris sur n'importe quels boutons pour une selection plus rapide\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Selection de l\\'heure :\\n\" +\n\"- Cliquer sur heures ou minutes pour incrementer\\n\" +\n\"- ou Maj-clic pour decrementer\\n\" +\n\"- ou clic et glisser-deplacer pour une selection plus rapide\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Année préc. (maintenir pour menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Mois préc. (maintenir pour menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Atteindre la date du jour\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Mois suiv. (maintenir pour menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Année suiv. (maintenir pour menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Sélectionner une date\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Déplacer\";\nCalendar._TT[\"PART_TODAY\"] = \" (Aujourd'hui)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Afficher %s en premier\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Fermer\";\nCalendar._TT[\"TODAY\"] = \"Aujourd'hui\";\nCalendar._TT[\"TIME_PART\"] = \"(Maj-)Clic ou glisser pour modifier la valeur\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d/%m/%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"Sem.\";\nCalendar._TT[\"TIME\"] = \"Heure :\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-gl.js",
    "content": "// ** I18N\n\n// Calendar GL (galician) language\n// Author: Martín Vázquez Cabanas, <eu@martinvazquez.net>\n// Updated: 2009-01-23\n// Encoding: utf-8\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Domingo\",\n \"Luns\",\n \"Martes\",\n \"Mércores\",\n \"Xoves\",\n \"Venres\",\n \"Sábado\",\n \"Domingo\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Dom\",\n \"Lun\",\n \"Mar\",\n \"Mér\",\n \"Xov\",\n \"Ven\",\n \"Sáb\",\n \"Dom\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Xaneiro\",\n \"Febreiro\",\n \"Marzo\",\n \"Abril\",\n \"Maio\",\n \"Xuño\",\n \"Xullo\",\n \"Agosto\",\n \"Setembro\",\n \"Outubro\",\n \"Novembro\",\n \"Decembro\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Xan\",\n \"Feb\",\n \"Mar\",\n \"Abr\",\n \"Mai\",\n \"Xun\",\n \"Xull\",\n \"Ago\",\n \"Set\",\n \"Out\",\n \"Nov\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Acerca do calendario\";\n\nCalendar._TT[\"ABOUT\"] =\n\"Selector DHTML de Data/Hora\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"Para conseguila última versión visite: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distribuído baixo licenza GNU LGPL. Visite http://gnu.org/licenses/lgpl.html para máis detalles.\" +\n\"\\n\\n\" +\n\"Selección de data:\\n\" +\n\"- Use os botóns \\xab, \\xbb para seleccionalo ano\\n\" +\n\"- Use os botóns \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" para seleccionalo mes\\n\" +\n\"- Manteña pulsado o rato en calquera destes botóns para unha selección rápida.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Selección de hora:\\n\" +\n\"- Pulse en calquera das partes da hora para incrementala\\n\" +\n\"- ou pulse maiúsculas mentres fai clic para decrementala\\n\" +\n\"- ou faga clic e arrastre o rato para unha selección máis rápida.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Ano anterior (manter para menú)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Mes anterior (manter para menú)\";\nCalendar._TT[\"GO_TODAY\"] = \"Ir a hoxe\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Mes seguinte (manter para menú)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Ano seguinte (manter para menú)\";\nCalendar._TT[\"SEL_DATE\"] = \"Seleccionar data\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Arrastrar para mover\";\nCalendar._TT[\"PART_TODAY\"] = \" (hoxe)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Facer %s primeiro día da semana\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Pechar\";\nCalendar._TT[\"TODAY\"] = \"Hoxe\";\nCalendar._TT[\"TIME_PART\"] = \"(Maiúscula-)Clic ou arrastre para cambiar valor\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d/%m/%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%A, %e de %B de %Y\";\n\nCalendar._TT[\"WK\"] = \"sem\";\nCalendar._TT[\"TIME\"] = \"Hora:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-he.js",
    "content": "// ** I18N\n\n// Calendar HE language\n// Author: Saggi Mizrahi\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"ראשון\",\n \"שני\",\n \"שלישי\",\n \"רביעי\",\n \"חמישי\",\n \"שישי\",\n \"שבת\",\n \"ראשון\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"א\",\n \"ב\",\n \"ג\",\n \"ד\",\n \"ה\",\n \"ו\",\n \"ש\",\n \"א\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"ינואר\",\n \"פברואר\",\n \"מרץ\",\n \"אפריל\",\n \"מאי\",\n \"יוני\",\n \"יולי\",\n \"אוגוסט\",\n \"ספטמבר\",\n \"אוקטובר\",\n \"נובמבר\",\n \"דצמבר\");\n\n// short month names\nCalendar._SMN = new Array\n(\"ינו'\",\n \"פבו'\",\n \"מרץ\",\n \"אפר'\",\n \"מאי\",\n \"יונ'\",\n \"יול'\",\n \"אוג'\",\n \"ספט'\",\n \"אוקט'\",\n \"נוב'\",\n \"דצמ'\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"אודות לוח השנה\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Date selection:\\n\" +\n\"- Use the \\xab, \\xbb buttons to select year\\n\" +\n\"- Use the \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" buttons to select month\\n\" +\n\"- Hold mouse button on any of the above buttons for faster selection.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Time selection:\\n\" +\n\"- Click on any of the time parts to increase it\\n\" +\n\"- or Shift-click to decrease it\\n\" +\n\"- or click and drag for faster selection.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"שנה קודמת (החזק לתפריט)\";\nCalendar._TT[\"PREV_MONTH\"] = \"חודש קודם (החזק לתפריט)\";\nCalendar._TT[\"GO_TODAY\"] = \"לך להיום\";\nCalendar._TT[\"NEXT_MONTH\"] = \"חודש הבא (החזק לתפריט)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"שנה הבאה (החזק לתפריט)\";\nCalendar._TT[\"SEL_DATE\"] = \"בחר תאריך\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"משוך כדי להזיז\";\nCalendar._TT[\"PART_TODAY\"] = \" (היום)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"הצג %s קודם\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"5,6\";\n\nCalendar._TT[\"CLOSE\"] = \"סגור\";\nCalendar._TT[\"TODAY\"] = \"היום\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)לחץ או משוך כדי לשנות את הערך\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d-%m-%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"זמן:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-hu.js",
    "content": "﻿// ** I18N\n\n// Calendar HU language\n// Author: Takács Gábor\n// Encoding: UTF-8\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Vasárnap\",\n \"Hétfő\",\n \"Kedd\",\n \"Szerda\",\n \"Csütörtök\",\n \"Péntek\",\n \"Szombat\",\n \"Vasárnap\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Vas\",\n \"Hét\",\n \"Ked\",\n \"Sze\",\n \"Csü\",\n \"Pén\",\n \"Szo\",\n \"Vas\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Január\",\n \"Február\",\n \"Március\",\n \"Április\",\n \"Május\",\n \"Június\",\n \"Július\",\n \"Augusztus\",\n \"Szeptember\",\n \"Október\",\n \"November\",\n \"December\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Feb\",\n \"Már\",\n \"Ápr\",\n \"Máj\",\n \"Jún\",\n \"Júl\",\n \"Aug\",\n \"Szep\",\n \"Okt\",\n \"Nov\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"A naptár leírása\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Date selection:\\n\" +\n\"- Use the \\xab, \\xbb buttons to select year\\n\" +\n\"- Use the \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" buttons to select month\\n\" +\n\"- Hold mouse button on any of the above buttons for faster selection.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Time selection:\\n\" +\n\"- Click on any of the time parts to increase it\\n\" +\n\"- or Shift-click to decrease it\\n\" +\n\"- or click and drag for faster selection.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Előző év (nyomvatart = menü)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Előző hónap (nyomvatart = menü)\";\nCalendar._TT[\"GO_TODAY\"] = \"Irány a Ma\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Következő hónap (nyomvatart = menü)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Következő év (nyomvatart = menü)\";\nCalendar._TT[\"SEL_DATE\"] = \"Válasszon dátumot\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Fogd és vidd\";\nCalendar._TT[\"PART_TODAY\"] = \" (ma)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"%s megjelenítése elsőként\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Bezár\";\nCalendar._TT[\"TODAY\"] = \"Ma\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Click vagy húzd az érték változtatásához\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y.%m.%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%B %e, %A\";\n\nCalendar._TT[\"WK\"] = \"hét\";\nCalendar._TT[\"TIME\"] = \"Idő:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-id.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// Translator: Raden Prabowo, <cakbowo@gmail.com>\n\n// full day names\nCalendar._DN = new Array\n(\"Minggu\",\n \"Senin\",\n \"Selasa\",\n \"Rabu\",\n \"Kamis\",\n \"Jumat\",\n \"Sabtu\",\n \"Minggu\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Ming\",\n \"Sen\",\n \"Sel\",\n \"Rab\",\n \"Kam\",\n \"Jum\",\n \"Sab\",\n \"Ming\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"Januari\",\n \"Februari\",\n \"Maret\",\n \"April\",\n \"Mei\",\n \"Juni\",\n \"Juli\",\n \"Agustus\",\n \"September\",\n \"Oktober\",\n \"November\",\n \"Desember\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"Mei\",\n \"Jun\",\n \"Jul\",\n \"Agu\",\n \"Sep\",\n \"Okt\",\n \"Nov\",\n \"Des\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Mengenai kalender\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"Versi terbaru terdapat di: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Disebarkan dibawah lisensi GNU LGPL.  Lihat http://gnu.org/licenses/lgpl.html untuk detil.\" +\n\"\\n\\n\" +\n\"Pemilihan tanggal:\\n\" +\n\"- Gunakan tombol \\xab, \\xbb untuk memilih tahun\\n\" +\n\"- Gunakan tombol \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" untuk memilih bulan\\n\" +\n\"- Tekan terus tombol kanan pada mouse atau salah satu tombol diatas untuk memilih lebih cepat.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Pemilihan waktu:\\n\" +\n\"- Klik bagian waktu untuk menaikkan\\n\" +\n\"- atau Shift-klick untuk menurunkan\\n\" +\n\"- atau klik dan geser untuk pemilihan yang lebih cepat.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Tahun sebelumnya. (tekan terus untuk menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Bulan sebelumnya. (tekan terus untuk menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Ke Hari ini\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Bulan berikutnya. (tekan terus untuk menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Tahun berikutnya. (tekan terus untuk menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Pilih tanggal\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Geser untuk menggerakkan\";\nCalendar._TT[\"PART_TODAY\"] = \" (hari ini)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Tampilkan %s lebih dulu\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Tutup\";\nCalendar._TT[\"TODAY\"] = \"Hari ini\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Click atau geser untuk mengubah nilai\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d-%m-%Y\";\n//Calendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %e %b\";\n\nCalendar._TT[\"WK\"] = \"mg\";\nCalendar._TT[\"TIME\"] = \"Waktu:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-it.js",
    "content": "﻿// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Domenica\",\n \"Lunedì\",\n \"Martedì\",\n \"Mercoledì\",\n \"Giovedì\",\n \"Venerdì\",\n \"Sabato\",\n \"Domenica\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Dom\",\n \"Lun\",\n \"Mar\",\n \"Mer\",\n \"Gio\",\n \"Ven\",\n \"Sab\",\n \"Dom\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Gennaio\",\n \"Febbraio\",\n \"Marzo\",\n \"Aprile\",\n \"Maggio\",\n \"Giugno\",\n \"Luglio\",\n \"Agosto\",\n \"Settembre\",\n \"Ottobre\",\n \"Novembre\",\n \"Dicembre\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Gen\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"Mag\",\n \"Giu\",\n \"Lug\",\n \"Ago\",\n \"Set\",\n \"Ott\",\n \"Nov\",\n \"Dic\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Informazioni sul calendario\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Date selection:\\n\" +\n\"- Use the \\xab, \\xbb buttons to select year\\n\" +\n\"- Use the \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" buttons to select month\\n\" +\n\"- Hold mouse button on any of the above buttons for faster selection.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Time selection:\\n\" +\n\"- Click on any of the time parts to increase it\\n\" +\n\"- or Shift-click to decrease it\\n\" +\n\"- or click and drag for faster selection.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Anno prec. (tieni premuto per menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Mese prec. (tieni premuto per menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Oggi\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Mese succ. (tieni premuto per menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Anno succ. (tieni premuto per menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Seleziona data\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Trascina per spostare\";\nCalendar._TT[\"PART_TODAY\"] = \" (oggi)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Mostra %s per primo\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Chiudi\";\nCalendar._TT[\"TODAY\"] = \"Oggi\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Click o trascina per modificare\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"sett\";\nCalendar._TT[\"TIME\"] = \"Ora:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-ja.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array (\"日曜日\", \"月曜日\", \"火曜日\", \"水曜日\", \"木曜日\", \"金曜日\", \"土曜日\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array (\"日\", \"月\", \"火\", \"水\", \"木\", \"金\", \"土\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array (\"1月\", \"2月\", \"3月\", \"4月\", \"5月\", \"6月\", \"7月\", \"8月\", \"9月\", \"10月\", \"11月\", \"12月\");\n\n// short month names\nCalendar._SMN = new Array (\"1月\", \"2月\", \"3月\", \"4月\", \"5月\", \"6月\", \"7月\", \"8月\", \"9月\", \"10月\", \"11月\", \"12月\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"このカレンダーについて\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"日付の選択方法:\\n\" +\n\"- \\xab, \\xbb ボタンで年を選択。\\n\" +\n\"- \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" ボタンで年を選択。\\n\" +\n\"- 上記ボタンの長押しでメニューから選択。\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Time selection:\\n\" +\n\"- Click on any of the time parts to increase it\\n\" +\n\"- or Shift-click to decrease it\\n\" +\n\"- or click and drag for faster selection.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"前年 (長押しでメニュー表示)\";\nCalendar._TT[\"PREV_MONTH\"] = \"前月 (長押しでメニュー表示)\";\nCalendar._TT[\"GO_TODAY\"] = \"今日の日付を選択\";\nCalendar._TT[\"NEXT_MONTH\"] = \"翌月 (長押しでメニュー表示)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"翌年 (長押しでメニュー表示)\";\nCalendar._TT[\"SEL_DATE\"] = \"日付を選択してください\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"ドラッグで移動\";\nCalendar._TT[\"PART_TODAY\"] = \" (今日)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"%s始まりで表示\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"閉じる\";\nCalendar._TT[\"TODAY\"] = \"今日\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Click or drag to change value\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%b%e日(%a)\";\n\nCalendar._TT[\"WK\"] = \"週\";\nCalendar._TT[\"TIME\"] = \"Time:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-ko.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"일요일\",\n \"월요일\",\n \"화요일\",\n \"수요일\",\n \"목요일\",\n \"금요일\",\n \"토요일\",\n \"일요일\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"일\",\n \"월\",\n \"화\",\n \"수\",\n \"목\",\n \"금\",\n \"토\",\n \"일\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"1월\",\n \"2월\",\n \"3월\",\n \"4월\",\n \"5월\",\n \"6월\",\n \"7월\",\n \"8월\",\n \"9월\",\n \"10월\",\n \"11월\",\n \"12월\");\n\n// short month names\nCalendar._SMN = new Array\n(\"1월\",\n \"2월\",\n \"3월\",\n \"4월\",\n \"5월\",\n \"6월\",\n \"7월\",\n \"8월\",\n \"9월\",\n \"10월\",\n \"11월\",\n \"12월\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"이 달력은 ... & 도움말\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML 날짜/시간 선택기\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"최신 버전을 구하려면 여기로: http://www.dynarch.com/projects/calendar/\\n\" +\n\"배포라이센스:GNU LGPL.  참조:http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"날짜 선택:\\n\" +\n\"- 해를 선택하려면 \\xab, \\xbb 버튼을 사용하세요.\\n\" +\n\"- 달을 선택하려면 \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" 버튼을 사용하세요.\\n\" +\n\"- 좀 더 빠르게 선택하려면 위의 버튼을 꾹 눌러주세요.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"시간 선택:\\n\" +\n\"- 시, 분을 더하려면 클릭하세요.\\n\" +\n\"- 시, 분을 빼려면  쉬프트 누르고 클릭하세요.\\n\" +\n\"- 좀 더 빠르게 선택하려면 클릭하고 드래그하세요.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"이전 해\";\nCalendar._TT[\"PREV_MONTH\"] = \"이전 달\";\nCalendar._TT[\"GO_TODAY\"] = \"오늘로 이동\";\nCalendar._TT[\"NEXT_MONTH\"] = \"다음 달\";\nCalendar._TT[\"NEXT_YEAR\"] = \"다음 해\";\nCalendar._TT[\"SEL_DATE\"] = \"날짜 선택\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"이동(드래그)\";\nCalendar._TT[\"PART_TODAY\"] = \" (오늘)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"[%s]을 처음으로\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"닫기\";\nCalendar._TT[\"TODAY\"] = \"오늘\";\nCalendar._TT[\"TIME_PART\"] = \"클릭(+),쉬프트+클릭(-),드래그\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"주\";\nCalendar._TT[\"TIME\"] = \"시간:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-lt.js",
    "content": "// ** I18N\n\n// Calendar LT language\n// Author: Gediminas Muižis, <gediminas.muizis@elgama.eu>\n// Encoding: UTF-8\n// Distributed under the same terms as the calendar itself.\n// Ver: 0.2\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Sekmadienis\",\n \"Pirmadienis\",\n \"Antradienis\",\n \"Trečiadienis\",\n \"Ketvirtadienis\",\n \"Penktadienis\",\n \"Šeštadienis\",\n \"Sekmadienis\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Sek\",\n \"Pir\",\n \"Ant\",\n \"Tre\",\n \"Ket\",\n \"Pen\",\n \"Šeš\",\n \"Sek\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Sausis\",\n \"Vasaris\",\n \"Kovas\",\n \"Balandis\",\n \"Gegužė\",\n \"Birželis\",\n \"Liepa\",\n \"Rudpjūtis\",\n \"Rugsėjis\",\n \"Spalis\",\n \"Lapkritis\",\n \"Gruodis\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Sau\",\n \"Vas\",\n \"Kov\",\n \"Bal\",\n \"Geg\",\n \"Brž\",\n \"Lie\",\n \"Rgp\",\n \"Rgs\",\n \"Spl\",\n \"Lap\",\n \"Grd\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Apie kalendorių\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Datos pasirinkimas:\\n\" +\n\"- Naudoti \\xab, \\xbb mygtukus norint pasirinkti metus\\n\" +\n\"- Naudoti \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" mygtukus norint pasirinkti mėnesį\\n\" +\n\"- PAlaikykite nuspaudę bet kurį nygtuką norėdami iškviesti greitąjį meniu.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Datos pasirinkimas:\\n\" +\n\"- Paspaudus ant valandos ar minutės, jų reikšmės padidėja\\n\" +\n\"- arba Shift-paspaudimas norint sumažinti reikšmę\\n\" +\n\"- arba paspauskite ir tempkite norint greičiau keisti reikšmę.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Ankst. metai (laikyti, norint iškviesti meniu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Ankst. mėnuo (laikyti, norint iškviesti meniu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Šiandien\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Kitas mėnuo (laikyti, norint iškviesti meniu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Kiti metai (laikyti, norint iškviesti meniu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Pasirinkti datą\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Perkelkite pėlyte\";\nCalendar._TT[\"PART_TODAY\"] = \" (šiandien)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Rodyti %s pirmiau\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Uždaryti\";\nCalendar._TT[\"TODAY\"] = \"Šiandien\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Spausti ar tempti, norint pakeisti reikšmę\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"sav\";\nCalendar._TT[\"TIME\"] = \"Laikas:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-mk.js",
    "content": "// ** I18N\n\n// Calendar МК language\n// Author: Илин Татабитовски, <ilin@slobodensoftver.org.mk>\n// Encoding: UTF-8\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"недела\",\n \"понеделник\",\n \"вторник\",\n \"среда\",\n \"четврток\",\n \"петок\",\n \"сабота\",\n \"недела\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"нед\",\n \"пон\",\n \"вто\",\n \"сре\",\n \"чет\",\n \"пет\",\n \"саб\",\n \"нед\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"јануари\",\n \"февруари\",\n \"март\",\n \"април\",\n \"мај\",\n \"јуни\",\n \"јули\",\n \"август\",\n \"септември\",\n \"октомври\",\n \"ноември\",\n \"декември\");\n\n// short month names\nCalendar._SMN = new Array\n(\"јан\",\n \"фев\",\n \"мар\",\n \"апр\",\n \"мај\",\n \"јун\",\n \"јул\",\n \"авг\",\n \"сеп\",\n \"окт\",\n \"ное\",\n \"дек\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"За календарот\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Date selection:\\n\" +\n\"- Use the \\xab, \\xbb buttons to select year\\n\" +\n\"- Use the \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" buttons to select month\\n\" +\n\"- Hold mouse button on any of the above buttons for faster selection.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Time selection:\\n\" +\n\"- Click on any of the time parts to increase it\\n\" +\n\"- or Shift-click to decrease it\\n\" +\n\"- or click and drag for faster selection.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Претходна година (hold for menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Претходен месец (hold for menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Go Today\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Следен месец (hold for menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Следна година (hold for menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Изберете дата\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Drag to move\";\nCalendar._TT[\"PART_TODAY\"] = \" (денес)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Прикажи %s прво\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Затвори\";\nCalendar._TT[\"TODAY\"] = \"Денес\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Click or drag to change value\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d-%m-%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %e %b\";\n\nCalendar._TT[\"WK\"] = \"нед\";\nCalendar._TT[\"TIME\"] = \"Време:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-nl.js",
    "content": "// ** I18N\n\n// Calendar NL language\n// Author: Linda van den Brink, <linda@dynasol.nl>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Zondag\",\n \"Maandag\",\n \"Dinsdag\",\n \"Woensdag\",\n \"Donderdag\",\n \"Vrijdag\",\n \"Zaterdag\",\n \"Zondag\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Zo\",\n \"Ma\",\n \"Di\",\n \"Wo\",\n \"Do\",\n \"Vr\",\n \"Za\",\n \"Zo\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"Januari\",\n \"Februari\",\n \"Maart\",\n \"April\",\n \"Mei\",\n \"Juni\",\n \"Juli\",\n \"Augustus\",\n \"September\",\n \"Oktober\",\n \"November\",\n \"December\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Feb\",\n \"Maa\",\n \"Apr\",\n \"Mei\",\n \"Jun\",\n \"Jul\",\n \"Aug\",\n \"Sep\",\n \"Okt\",\n \"Nov\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Over de kalender\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Datum selectie:\\n\" +\n\"- Gebruik de \\xab, \\xbb knoppen om het jaar te selecteren\\n\" +\n\"- Gebruik de \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" knoppen om de maand te selecteren\\n\" +\n\"- Houd de muisknop ingedrukt op een van de knoppen voor snellere selectie.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Tijd selectie:\\n\" +\n\"- Klik op een deel van de tijd om het te verhogen\\n\" +\n\"- of Shift-click om het te verlagen\\n\" +\n\"- of klik en sleep voor snellere selectie.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Vorig jaar (vasthouden voor menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Vorige maand (vasthouden voor menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Ga naar vandaag\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Volgende maand (vasthouden voor menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Volgend jaar(vasthouden voor menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Selecteer datum\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Sleep om te verplaatsen\";\nCalendar._TT[\"PART_TODAY\"] = \" (vandaag)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Toon %s eerst\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Sluiten\";\nCalendar._TT[\"TODAY\"] = \"Vandaag\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)klik of sleep om waarde te wijzigen\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"Tijd:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-no.js",
    "content": "// ** I18N\n\n// Calendar NO language (Norwegian/Norsk bokmål)\n// Author: Kai Olav Fredriksen <k@i.fredriksen.net>\n\n// full day names\nCalendar._DN = new Array\n(\"Søndag\",\n \"Mandag\",\n \"Tirsdag\",\n \"Onsdag\",\n \"Torsdag\",\n \"Fredag\",\n \"Lørdag\",\n \"Søndag\");\n\nCalendar._SDN_len = 3; // short day name length\nCalendar._SMN_len = 3; // short month name length\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Januar\",\n \"Februar\",\n \"Mars\",\n \"April\",\n \"Mai\",\n \"Juni\",\n \"Juli\",\n \"August\",\n \"September\",\n \"Oktober\",\n \"November\",\n \"Desember\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Om kalenderen\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Date selection:\\n\" +\n\"- Use the \\xab, \\xbb buttons to select year\\n\" +\n\"- Use the \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" buttons to select month\\n\" +\n\"- Hold mouse button on any of the above buttons for faster selection.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Time selection:\\n\" +\n\"- Click on any of the time parts to increase it\\n\" +\n\"- or Shift-click to decrease it\\n\" +\n\"- or click and drag for faster selection.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Forrige år (hold for meny)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Forrige måned (hold for meny)\";\nCalendar._TT[\"GO_TODAY\"] = \"Gå til idag\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Neste måned (hold for meny)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Neste år (hold for meny)\";\nCalendar._TT[\"SEL_DATE\"] = \"Velg dato\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Dra for å flytte\";\nCalendar._TT[\"PART_TODAY\"] = \" (idag)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Vis %s først\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Lukk\";\nCalendar._TT[\"TODAY\"] = \"Idag\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Klikk eller dra for å endre verdi\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%%d.%m.%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"uke\";\nCalendar._TT[\"TIME\"] = \"Tid:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-pl.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Niedziela\",\n \"Poniedziałek\",\n \"Wtorek\",\n \"Środa\",\n \"Czwartek\",\n \"Piątek\",\n \"Sobota\",\n \"Niedziela\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Nie\",\n \"Pon\",\n \"Wto\",\n \"Śro\",\n \"Czw\",\n \"Pią\",\n \"Sob\",\n \"Nie\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Styczeń\",\n \"Luty\",\n \"Marzec\",\n \"Kwiecień\",\n \"Maj\",\n \"Czerwiec\",\n \"Lipiec\",\n \"Sierpień\",\n \"Wrzesień\",\n \"Październik\",\n \"Listopad\",\n \"Grudzień\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Sty\",\n \"Lut\",\n \"Mar\",\n \"Kwi\",\n \"Maj\",\n \"Cze\",\n \"Lip\",\n \"Sie\",\n \"Wrz\",\n \"Paź\",\n \"Lis\",\n \"Gru\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"O kalendarzu\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"Po ostatnią wersję odwiedź: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Rozpowszechniany pod licencją GNU LGPL.  Zobacz: http://gnu.org/licenses/lgpl.html z celu zapoznania się ze szczegółami.\" +\n\"\\n\\n\" +\n\"Wybór daty:\\n\" +\n\"- Użyj \\xab, \\xbb przycisków by zaznaczyć rok\\n\" +\n\"- Użyj \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" przycisków by zaznaczyć miesiąc\\n\" +\n\"- Trzymaj wciśnięty przycisk myszy na każdym z powyższych przycisków by przyśpieszyć zaznaczanie.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Wybór czasu:\\n\" +\n\"- Kliknij na każdym przedziale czasu aby go powiększyć\\n\" +\n\"- lub kliknij z przyciskiem Shift by go zmniejszyć\\n\" +\n\"- lub kliknij i przeciągnij dla szybszego zaznaczenia.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Poprz. rok (przytrzymaj dla menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Poprz. miesiąc (przytrzymaj dla menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Idź do Dzisiaj\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Następny miesiąc(przytrzymaj dla menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Następny rok (przytrzymaj dla menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Zaznacz datę\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Przeciągnij by przenieść\";\nCalendar._TT[\"PART_TODAY\"] = \" (dzisiaj)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Pokaż %s pierwszy\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Zamknij\";\nCalendar._TT[\"TODAY\"] = \"Dzisiaj\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Kliknij lub upuść by zmienić wartość\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%R-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"Czas:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-pt-br.js",
    "content": "// ** I18N\n\n// Calendar pt_BR language\n// Author: Adalberto Machado, <betosm@terra.com.br>\n// Review: Alexandre da Silva, <simpsomboy@gmail.com>\n// Encoding: UTF-8\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Domingo\",\n \"Segunda\",\n \"Terça\",\n \"Quarta\",\n \"Quinta\",\n \"Sexta\",\n \"Sabado\",\n \"Domingo\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Dom\",\n \"Seg\",\n \"Ter\",\n \"Qua\",\n \"Qui\",\n \"Sex\",\n \"Sab\",\n \"Dom\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"Janeiro\",\n \"Fevereiro\",\n \"Março\",\n \"Abril\",\n \"Maio\",\n \"Junho\",\n \"Julho\",\n \"Agosto\",\n \"Setembro\",\n \"Outubro\",\n \"Novembro\",\n \"Dezembro\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Fev\",\n \"Mar\",\n \"Abr\",\n \"Mai\",\n \"Jun\",\n \"Jul\",\n \"Ago\",\n \"Set\",\n \"Out\",\n \"Nov\",\n \"Dez\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Sobre o calendário\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"Última versão visite: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distribuído sobre GNU LGPL.  Veja http://gnu.org/licenses/lgpl.html para detalhes.\" +\n\"\\n\\n\" +\n\"Seleção de data:\\n\" +\n\"- Use os botões \\xab, \\xbb para selecionar o ano\\n\" +\n\"- Use os botões \" + String.fromCharCode(0x2039) + \", \" +\nString.fromCharCode(0x203a) + \" para selecionar o mês\\n\" +\n\"- Segure o botão do mouse em qualquer um desses botões para seleção rápida.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Seleção de hora:\\n\" +\n\"- Clique em qualquer parte da hora para incrementar\\n\" +\n\"- ou Shift-click para decrementar\\n\" +\n\"- ou clique e segure para seleção rápida.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Ant. ano (segure para menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Ant. mês (segure para menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Hoje\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Próx. mes (segure para menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Próx. ano (segure para menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Selecione a data\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Arraste para mover\";\nCalendar._TT[\"PART_TODAY\"] = \" (hoje)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Mostre %s primeiro\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Fechar\";\nCalendar._TT[\"TODAY\"] = \"Hoje\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Click ou arraste para mudar valor\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d/%m/%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %e %b\";\n\nCalendar._TT[\"WK\"] = \"sm\";\nCalendar._TT[\"TIME\"] = \"Hora:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-pt.js",
    "content": "// ** I18N\n\n// Calendar pt language\n// Author: Adalberto Machado, <betosm@terra.com.br>\n// Corrected by: Pedro Araújo <phcrva19@hotmail.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Domingo\",\n \"Segunda\",\n \"Terça\",\n \"Quarta\",\n \"Quinta\",\n \"Sexta\",\n \"Sábado\",\n \"Domingo\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Dom\",\n \"Seg\",\n \"Ter\",\n \"Qua\",\n \"Qui\",\n \"Sex\",\n \"Sáb\",\n \"Dom\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Janeiro\",\n \"Fevereiro\",\n \"Março\",\n \"Abril\",\n \"Maio\",\n \"Junho\",\n \"Julho\",\n \"Agosto\",\n \"Setembro\",\n \"Outubro\",\n \"Novembro\",\n \"Dezembro\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Fev\",\n \"Mar\",\n \"Abr\",\n \"Mai\",\n \"Jun\",\n \"Jul\",\n \"Ago\",\n \"Set\",\n \"Out\",\n \"Nov\",\n \"Dez\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Sobre o calendário\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"Última versão visite: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distribuído sobre a licença GNU LGPL.  Veja http://gnu.org/licenses/lgpl.html para detalhes.\" +\n\"\\n\\n\" +\n\"Selecção de data:\\n\" +\n\"- Use os botões \\xab, \\xbb para seleccionar o ano\\n\" +\n\"- Use os botões \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" para seleccionar o mês\\n\" +\n\"- Segure o botão do rato em qualquer um desses botões para selecção rápida.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Selecção de hora:\\n\" +\n\"- Clique em qualquer parte da hora para incrementar\\n\" +\n\"- ou Shift-click para decrementar\\n\" +\n\"- ou clique e segure para selecção rápida.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Ano ant. (segure para menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Mês ant. (segure para menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Hoje\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Prox. mês (segure para menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Prox. ano (segure para menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Seleccione a data\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Arraste para mover\";\nCalendar._TT[\"PART_TODAY\"] = \" (hoje)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Mostre %s primeiro\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Fechar\";\nCalendar._TT[\"TODAY\"] = \"Hoje\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Click ou arraste para mudar valor\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d/%m/%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %e %b\";\n\nCalendar._TT[\"WK\"] = \"sm\";\nCalendar._TT[\"TIME\"] = \"Hora:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-ro.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Duminică\",\n \"Luni\",\n \"Marți\",\n \"Miercuri\",\n \"Joi\",\n \"Vineri\",\n \"Sâmbătă\",\n \"Duminică\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Dum\",\n \"Lun\",\n \"Mar\",\n \"Mie\",\n \"Joi\",\n \"Vin\",\n \"Sâm\",\n \"Dum\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Ianuarie\",\n \"Februarie\",\n \"Martie\",\n \"Aprilie\",\n \"Mai\",\n \"Iunie\",\n \"Iulie\",\n \"August\",\n \"Septembrie\",\n \"Octombrie\",\n \"Noiembrie\",\n \"Decembrie\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Ian\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"Mai\",\n \"Iun\",\n \"Iul\",\n \"Aug\",\n \"Sep\",\n \"Oct\",\n \"Noi\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Despre calendar\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Selectare data:\\n\" +\n\"- Folositi butoanele \\xab, \\xbb pentru a selecta anul\\n\" +\n\"- Folositi butoanele \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" pentru a selecta luna\\n\" +\n\"- Lasati apasat butonul pentru o selectie mai rapida.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Selectare timp:\\n\" +\n\"- Click pe campul de timp pentru a majora timpul\\n\" +\n\"- sau Shift-Click pentru a micsora\\n\" +\n\"- sau click si drag pentru manipulare rapida.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Anul precedent (apasati pentru meniu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Luna precedenta (apasati pentru meniu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Astazi\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Luna viitoare (apasati pentru meniu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Anul viitor (apasati pentru meniu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Selecteaza data\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Drag pentru a muta\";\nCalendar._TT[\"PART_TODAY\"] = \" (azi)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Vizualizează %s prima\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Închide\";\nCalendar._TT[\"TODAY\"] = \"Azi\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Click sau drag pentru a schimba valoarea\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%A-%l-%z\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"săpt\";\nCalendar._TT[\"TIME\"] = \"Ora:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-ru.js",
    "content": "// ** I18N\n\n// Calendar RU language\n// Translation: Sly Golovanov, http://golovanov.net, <sly@golovanov.net>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"воскресенье\",\n \"понедельник\",\n \"вторник\",\n \"среда\",\n \"четверг\",\n \"пятница\",\n \"суббота\",\n \"воскресенье\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"вск\",\n \"пон\",\n \"втр\",\n \"срд\",\n \"чет\",\n \"пят\",\n \"суб\",\n \"вск\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"январь\",\n \"февраль\",\n \"март\",\n \"апрель\",\n \"май\",\n \"июнь\",\n \"июль\",\n \"август\",\n \"сентябрь\",\n \"октябрь\",\n \"ноябрь\",\n \"декабрь\");\n\n// short month names\nCalendar._SMN = new Array\n(\"янв\",\n \"фев\",\n \"мар\",\n \"апр\",\n \"май\",\n \"июн\",\n \"июл\",\n \"авг\",\n \"сен\",\n \"окт\",\n \"ноя\",\n \"дек\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"О календаре...\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Как выбрать дату:\\n\" +\n\"- При помощи кнопок \\xab, \\xbb можно выбрать год\\n\" +\n\"- При помощи кнопок \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" можно выбрать месяц\\n\" +\n\"- Подержите эти кнопки нажатыми, чтобы появилось меню быстрого выбора.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Как выбрать время:\\n\" +\n\"- При клике на часах или минутах они увеличиваются\\n\" +\n\"- при клике с нажатой клавишей Shift они уменьшаются\\n\" +\n\"- если нажать и двигать мышкой влево/вправо, они будут меняться быстрее.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"На год назад (удерживать для меню)\";\nCalendar._TT[\"PREV_MONTH\"] = \"На месяц назад (удерживать для меню)\";\nCalendar._TT[\"GO_TODAY\"] = \"Сегодня\";\nCalendar._TT[\"NEXT_MONTH\"] = \"На месяц вперед (удерживать для меню)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"На год вперед (удерживать для меню)\";\nCalendar._TT[\"SEL_DATE\"] = \"Выберите дату\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Перетаскивайте мышкой\";\nCalendar._TT[\"PART_TODAY\"] = \" (сегодня)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Первый день недели будет %s\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Закрыть\";\nCalendar._TT[\"TODAY\"] = \"Сегодня\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)клик или нажать и двигать\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%e %b, %a\";\n\nCalendar._TT[\"WK\"] = \"нед\";\nCalendar._TT[\"TIME\"] = \"Время:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-sk.js",
    "content": "/*\n  calendar-sk.js\n  language: Slovak\n  encoding: UTF-8\n  author: Stanislav Pach (stano.pach@seznam.cz)\n*/\n\n// ** I18N\nCalendar._DN  = new Array('Nedeľa','Pondelok','Utorok','Streda','Štvrtok','Piatok','Sobota','Nedeľa');\nCalendar._SDN = new Array('Ne','Po','Ut','St','Št','Pi','So','Ne');\nCalendar._MN  = new Array('Január','Február','Marec','Apríl','Máj','Jún','Júl','August','September','Október','November','December');\nCalendar._SMN = new Array('Jan','Feb','Mar','Apr','Máj','Jún','Júl','Aug','Sep','Okt','Nov','Dec');\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"O komponente kalendár\";\nCalendar._TT[\"TOGGLE\"] = \"Zmena prvého dňa v týždni\";\nCalendar._TT[\"PREV_YEAR\"] = \"Predchádzajúci rok (pridrž pre menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Predchádzajúci mesiac (pridrž pre menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Dnešný dátum\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Ďalší mesiac (pridrž pre menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Ďalší rok (pridrž pre menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Zvoľ dátum\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Chyť a ťahaj pre presun\";\nCalendar._TT[\"PART_TODAY\"] = \" (dnes)\";\nCalendar._TT[\"MON_FIRST\"] = \"Ukáž ako prvný Pondelok\";\n//Calendar._TT[\"SUN_FIRST\"] = \"Ukaž jako první Neděli\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Výber dátumu:\\n\" +\n\"- Použijte tlačítka \\xab, \\xbb pre voľbu roku\\n\" +\n\"- Použijte tlačítka \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" pre výber mesiaca\\n\" +\n\"- Podržte tlačítko myši na akomkoľvek z týchto tlačítok pre rýchlejší výber.\";\n\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Výber času:\\n\" +\n\"- Kliknite na akúkoľvek časť z výberu času pre zvýšenie.\\n\" +\n\"- alebo Shift-klick pre zníženie\\n\" +\n\"- alebo kliknite a ťahajte pre rýchlejší výber.\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Zobraz %s ako prvý\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Zavrieť\";\nCalendar._TT[\"TODAY\"] = \"Dnes\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Klikni alebo ťahaj pre zmenu hodnoty\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"d.m.yy\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"týž\";\nCalendar._TT[\"TIME\"] = \"Čas:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-sl.js",
    "content": "// ** I18N\n\n// Calendar SL language\n// Author: Jernej Vidmar, <jernej.vidmar@vidmarboehm.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Nedelja\",\n \"Ponedeljek\",\n \"Torek\",\n \"Sreda\",\n \"Četrtek\",\n \"Petek\",\n \"Sobota\",\n \"Nedelja\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Ned\",\n \"Pon\",\n \"Tor\",\n \"Sre\",\n \"Čet\",\n \"Pet\",\n \"Sob\",\n \"Ned\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"Januar\",\n \"Februar\",\n \"Marec\",\n \"April\",\n \"Maj\",\n \"Junij\",\n \"Julij\",\n \"Avgust\",\n \"September\",\n \"Oktober\",\n \"November\",\n \"December\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"Maj\",\n \"Jun\",\n \"Jul\",\n \"Avg\",\n \"Sep\",\n \"Okt\",\n \"Nov\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"O koledarju\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Izbira datuma:\\n\" +\n\"- Uporabite \\xab, \\xbb gumbe za izbiro leta\\n\" +\n\"- Uporabite \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" gumbe za izbiro meseca\\n\" +\n\"- Za hitrejšo izbiro držite miškin gumb nad enim od zgornjih gumbov.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Izbira časa:\\n\" +\n\"- Kliknite na katerikoli del časa da ga povečate\\n\" +\n\"- oziroma kliknite s Shiftom za znižanje\\n\" +\n\"- ali kliknite in vlecite za hitrejšo izbiro.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Prejšnje leto (držite za meni)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Prejšnji mesec (držite za meni)\";\nCalendar._TT[\"GO_TODAY\"] = \"Pojdi na danes\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Naslednji mesec (držite za meni)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Naslednje leto (držite za meni)\";\nCalendar._TT[\"SEL_DATE\"] = \"Izberite datum\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Povlecite za premik\";\nCalendar._TT[\"PART_TODAY\"] = \" (danes)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Najprej prikaži %s\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Zapri\";\nCalendar._TT[\"TODAY\"] = \"Danes\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)klik ali povleči, da spremeniš vrednost\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"Time:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-sr.js",
    "content": "// ** I18N\n\n// Calendar SR language\n// Author: Dragan Matic, <kkid@panforma.co.yu>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Nedelja\",\n \"Ponedeljak\",\n \"Utorak\",\n \"Sreda\",\n \"Četvrtak\",\n \"Petak\",\n \"Subota\",\n \"Nedelja\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Ned\",\n \"Pon\",\n \"Uto\",\n \"Sre\",\n \"Čet\",\n \"Pet\",\n \"Sub\",\n \"Ned\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"Januar\",\n \"Februar\",\n \"Mart\",\n \"April\",\n \"Maj\",\n \"Jun\",\n \"Jul\",\n \"Avgust\",\n \"Septembar\",\n \"Oktobar\",\n \"Novembar\",\n \"Decembar\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"Maj\",\n \"Jun\",\n \"Jul\",\n \"Avg\",\n \"Sep\",\n \"Okt\",\n \"Nov\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"O kalendaru\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Date selection:\\n\" +\n\"- Use the \\xab, \\xbb buttons to select year\\n\" +\n\"- Use the \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" buttons to select month\\n\" +\n\"- Hold mouse button on any of the above buttons for faster selection.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Time selection:\\n\" +\n\"- Click on any of the time parts to increase it\\n\" +\n\"- or Shift-click to decrease it\\n\" +\n\"- or click and drag for faster selection.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Preth. godina (hold for menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Preth. mesec (hold for menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Na današnji dan\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Naredni mesec (hold for menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Naredna godina (hold for menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Izbor datuma\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Prevucite za izmenu\";\nCalendar._TT[\"PART_TODAY\"] = \" (danas)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Prikazi %s prvo\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Close\";\nCalendar._TT[\"TODAY\"] = \"Danas\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Klik ili prevlačenje za izmenu vrednosti\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d-%m-%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"Vreme:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-sv.js",
    "content": "// ** I18N\n\n// full day names\nCalendar._DN = new Array\n(\"Söndag\",\n \"Måndag\",\n \"Tisdag\",\n \"Onsdag\",\n \"Torsdag\",\n \"Fredag\",\n \"Lördag\",\n \"Söndag\");\n\nCalendar._SDN_len = 3; // short day name length\nCalendar._SMN_len = 3; // short month name length\n\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Januari\",\n \"Februari\",\n \"Mars\",\n \"April\",\n \"Maj\",\n \"Juni\",\n \"Juli\",\n \"Augusti\",\n \"September\",\n \"Oktober\",\n \"November\",\n \"December\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Om kalendern\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Datum/Tid-väljare\\n\" +\n\"(c) dynarch.com 2002-2005 / Upphovsman: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"För senaste version besök: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distribueras under GNU LGPL.  Se http://gnu.org/licenses/lgpl.html för detaljer.\" +\n\"\\n\\n\" +\n\"Välja datum:\\n\" +\n\"- Använd \\xab, \\xbb knapparna för att välja år\\n\" +\n\"- Använd \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" knapparna för att välja månad\\n\" +\n\"- Håll nere musknappen på någon av ovanstående knappar för att se snabbval.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Välja tid:\\n\" +\n\"- Klicka på något av tidsfälten för att öka\\n\" +\n\"- eller Skift-klicka för att minska\\n\" +\n\"- eller klicka och dra för att välja snabbare.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Föreg. år (håll nere för lista)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Föreg. månad (håll nere för lista)\";\nCalendar._TT[\"GO_TODAY\"] = \"Gå till Idag\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Nästa månad (håll nere för lista)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Nästa år (håll nere för lista)\";\nCalendar._TT[\"SEL_DATE\"] = \"Välj datum\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Dra för att flytta\";\nCalendar._TT[\"PART_TODAY\"] = \" (idag)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Visa %s först\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Stäng\";\nCalendar._TT[\"TODAY\"] = \"Idag\";\nCalendar._TT[\"TIME_PART\"] = \"(Skift-)klicka eller dra för att ändra värde\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"v.\";\nCalendar._TT[\"TIME\"] = \"Tid:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-th.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Gampol Thitinilnithi, <gampolt@gmail.com>\n// Encoding: UTF-8\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"อาทิตย์\",\n \"จันทร์\",\n \"อังคาร\",\n \"พุธ\",\n \"พฤหัสบดี\",\n \"ศุกร์\",\n \"เสาร์\",\n \"อาทิตย์\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"อา.\",\n \"จ.\",\n \"อ.\",\n \"พ.\",\n \"พฤ.\",\n \"ศ.\",\n \"ส.\",\n \"อา.\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"มกราคม\",\n \"กุมภาพันธ์\",\n \"มีนาคม\",\n \"เมษายน\",\n \"พฤษภาคม\",\n \"มิถุนายน\",\n \"กรกฎาคม\",\n \"สิงหาคม\",\n \"กันยายน\",\n \"ตุลาคม\",\n \"พฤศจิกายน\",\n \"ธันวาคม\");\n\n// short month names\nCalendar._SMN = new Array\n(\"ม.ค.\",\n \"ก.พ.\",\n \"มี.ค.\",\n \"เม.ย.\",\n \"พ.ค.\",\n \"มิ.ย.\",\n \"ก.ค.\",\n \"ส.ค.\",\n \"ก.ย.\",\n \"ต.ค.\",\n \"พ.ย.\",\n \"ธ.ค.\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"เกี่ยวกับปฏิทิน\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Date selection:\\n\" +\n\"- Use the \\xab, \\xbb buttons to select year\\n\" +\n\"- Use the \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" buttons to select month\\n\" +\n\"- Hold mouse button on any of the above buttons for faster selection.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Time selection:\\n\" +\n\"- Click on any of the time parts to increase it\\n\" +\n\"- or Shift-click to decrease it\\n\" +\n\"- or click and drag for faster selection.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"ปีที่แล้ว (ถ้ากดค้างจะมีเมนู)\";\nCalendar._TT[\"PREV_MONTH\"] = \"เดือนที่แล้ว (ถ้ากดค้างจะมีเมนู)\";\nCalendar._TT[\"GO_TODAY\"] = \"ไปที่วันนี้\";\nCalendar._TT[\"NEXT_MONTH\"] = \"เดือนหน้า (ถ้ากดค้างจะมีเมนู)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"ปีหน้า (ถ้ากดค้างจะมีเมนู)\";\nCalendar._TT[\"SEL_DATE\"] = \"เลือกวัน\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"กดแล้วลากเพื่อย้าย\";\nCalendar._TT[\"PART_TODAY\"] = \" (วันนี้)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"แสดง %s เป็นวันแรก\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"ปิด\";\nCalendar._TT[\"TODAY\"] = \"วันนี้\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)กดหรือกดแล้วลากเพื่อเปลี่ยนค่า\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a %e %b\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"เวลา:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-tr.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Pazar\",\n \"Pazartesi\",\n \"Salı\",\n \"Çarşamba\",\n \"Perşembe\",\n \"Cuma\",\n \"Cumartesi\",\n \"Pazar\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Paz\",\n \"Pzt\",\n \"Sal\",\n \"Çar\",\n \"Per\",\n \"Cum\",\n \"Cmt\",\n \"Paz\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Ocak\",\n \"Şubat\",\n \"Mart\",\n \"Nisan\",\n \"Mayıs\",\n \"Haziran\",\n \"Temmuz\",\n \"Ağustos\",\n \"Eylül\",\n \"Ekim\",\n \"Kasım\",\n \"Aralık\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Oca\",\n \"Şub\",\n \"Mar\",\n \"Nis\",\n \"May\",\n \"Haz\",\n \"Tem\",\n \"Ağu\",\n \"Eyl\",\n \"Eki\",\n \"Kas\",\n \"Ara\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Takvim hakkında\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Tarih/Zaman Seçici\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Tarih Seçimi:\\n\" +\n\"- Yıl seçmek için \\xab, \\xbb tuşlarını kullanın\\n\" +\n\"- Ayı seçmek için \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" tuşlarını kullanın\\n\" +\n\"- Hızlı seçim için yukardaki butonların üzerinde farenin tuşuna basılı tutun.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Zaman Seçimi:\\n\" +\n\"- Arttırmak için herhangi bir zaman bölümüne tıklayın\\n\" +\n\"- ya da azaltmak için Shift+tıkla yapın\\n\" +\n\"- ya da daha hızlı bir seçim için tıklayın ve sürükleyin.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Öncki yıl (Menu için basılı tutun)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Önceki ay (Menu için basılı tutun)\";\nCalendar._TT[\"GO_TODAY\"] = \"Bugüne Git\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Sonraki Ay (Menu için basılı tutun)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Next year (Menu için basılı tutun)\";\nCalendar._TT[\"SEL_DATE\"] = \"Tarih seçin\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Taşımak için sürükleyin\";\nCalendar._TT[\"PART_TODAY\"] = \" (bugün)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"%s : önce göster\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"1,0\";\n\nCalendar._TT[\"CLOSE\"] = \"Kapat\";\nCalendar._TT[\"TODAY\"] = \"Bugün\";\nCalendar._TT[\"TIME_PART\"] = \"Değeri değiştirmek için (Shift-)tıkla veya sürükle\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%d-%m-%Y\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"Hafta\";\nCalendar._TT[\"TIME\"] = \"Saat:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-uk.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Sunday\",\n \"Monday\",\n \"Tuesday\",\n \"Wednesday\",\n \"Thursday\",\n \"Friday\",\n \"Saturday\",\n \"Sunday\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"Sun\",\n \"Mon\",\n \"Tue\",\n \"Wed\",\n \"Thu\",\n \"Fri\",\n \"Sat\",\n \"Sun\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"May\",\n \"Jun\",\n \"Jul\",\n \"Aug\",\n \"Sep\",\n \"Oct\",\n \"Nov\",\n \"Dec\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"About the calendar\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"For latest version visit: http://www.dynarch.com/projects/calendar/\\n\" +\n\"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details.\" +\n\"\\n\\n\" +\n\"Date selection:\\n\" +\n\"- Use the \\xab, \\xbb buttons to select year\\n\" +\n\"- Use the \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" buttons to select month\\n\" +\n\"- Hold mouse button on any of the above buttons for faster selection.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Time selection:\\n\" +\n\"- Click on any of the time parts to increase it\\n\" +\n\"- or Shift-click to decrease it\\n\" +\n\"- or click and drag for faster selection.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Prev. year (hold for menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Prev. month (hold for menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"Go Today\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Next month (hold for menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Next year (hold for menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Select date\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Drag to move\";\nCalendar._TT[\"PART_TODAY\"] = \" (today)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Display %s first\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Close\";\nCalendar._TT[\"TODAY\"] = \"Today\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)Click or drag to change value\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"Time:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-vi.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"Chủ nhật\",\n \"Thứ Hai\",\n \"Thứ Ba\",\n \"Thứ Tư\",\n \"Thứ Năm\",\n \"Thứ Sáu\",\n \"Thứ Bảy\",\n \"Chủ Nhật\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"C.Nhật\",\n \"Hai\",\n \"Ba\",\n \"Tư\",\n \"Năm\",\n \"Sáu\",\n \"Bảy\",\n \"C.Nhật\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 1;\n\n// full month names\nCalendar._MN = new Array\n(\"Tháng Giêng\",\n \"Tháng Hai\",\n \"Tháng Ba\",\n \"Tháng Tư\",\n \"Tháng Năm\",\n \"Tháng Sáu\",\n \"Tháng Bảy\",\n \"Tháng Tám\",\n \"Tháng Chín\",\n \"Tháng Mười\",\n \"Tháng M.Một\",\n \"Tháng Chạp\");\n\n// short month names\nCalendar._SMN = new Array\n(\"Mmột\",\n \"Hai\",\n \"Ba\",\n \"Tư\",\n \"Năm\",\n \"Sáu\",\n \"Bảy\",\n \"Tám\",\n \"Chín\",\n \"Mười\",\n \"MMột\",\n \"Chạp\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"Giới thiệu\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML Date/Time Selector (c) dynarch.com 2002-2005 / Tác giả: Mihai Bazon. \" + // don't translate this this ;-)\n\"Phiên bản mới nhất có tại: http://www.dynarch.com/projects/calendar/. \" +\n\"Sản phẩm được phân phối theo giấy phép GNU LGPL. Xem chi tiết tại http://gnu.org/licenses/lgpl.html.\" +\n\"\\n\\n\" +\n\"Chọn ngày:\\n\" +\n\"- Dùng nút \\xab, \\xbb để chọn năm\\n\" +\n\"- Dùng nút \" + String.fromCharCode(0x2039) + \", \" + String.fromCharCode(0x203a) + \" để chọn tháng\\n\" +\n\"- Giữ chuột vào các nút trên để có danh sách năm và tháng.\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"Chọn thời gian:\\n\" +\n\"- Click chuột trên từng phần của thời gian để chỉnh sửa\\n\" +\n\"- hoặc nhấn Shift + click chuột để tăng giá trị\\n\" +\n\"- hoặc click chuột và kéo (drag) để chọn nhanh.\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"Năm trước (giữ chuột để có menu)\";\nCalendar._TT[\"PREV_MONTH\"] = \"Tháng trước (giữ chuột để có menu)\";\nCalendar._TT[\"GO_TODAY\"] = \"đến Hôm nay\";\nCalendar._TT[\"NEXT_MONTH\"] = \"Tháng tới (giữ chuột để có menu)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"Ngày tới (giữ chuột để có menu)\";\nCalendar._TT[\"SEL_DATE\"] = \"Chọn ngày\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"Kéo (drag) để di chuyển\";\nCalendar._TT[\"PART_TODAY\"] = \" (hôm nay)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"Hiển thị %s trước\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"Đóng\";\nCalendar._TT[\"TODAY\"] = \"Hôm nay\";\nCalendar._TT[\"TIME_PART\"] = \"Click, shift-click hoặc kéo (drag) để đổi giá trị\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"%a, %b %e\";\n\nCalendar._TT[\"WK\"] = \"wk\";\nCalendar._TT[\"TIME\"] = \"Time:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-zh-tw.js",
    "content": "// ** I18N\n\n// Calendar EN language\n// Author: Mihai Bazon, <mihai_bazon@yahoo.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"星期日\",\n \"星期一\",\n \"星期二\",\n \"星期三\",\n \"星期四\",\n \"星期五\",\n \"星期六\",\n \"星期日\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"日\",\n \"一\",\n \"二\",\n \"三\",\n \"四\",\n \"五\",\n \"六\",\n \"日\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"一月\",\n \"二月\",\n \"三月\",\n \"四月\",\n \"五月\",\n \"六月\",\n \"七月\",\n \"八月\",\n \"九月\",\n \"十月\",\n \"十一月\",\n \"十二月\");\n\n// short month names\nCalendar._SMN = new Array\n(\"一月\",\n \"二月\",\n \"三月\",\n \"四月\",\n \"五月\",\n \"六月\",\n \"七月\",\n \"八月\",\n \"九月\",\n \"十月\",\n \"十一月\",\n \"十二月\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"關於 calendar\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML 日期/時間 選擇器\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"最新版本取得位址: http://www.dynarch.com/projects/calendar/\\n\" +\n\"使用 GNU LGPL 發行.  參考 http://gnu.org/licenses/lgpl.html 以取得更多關於 LGPL 之細節。\" +\n\"\\n\\n\" +\n\"日期選擇方式:\\n\" +\n\"- 使用滑鼠點擊 \\xab 、 \\xbb 按鈕選擇年份\\n\" +\n\"- 使用滑鼠點擊 \" + String.fromCharCode(0x2039) + \" 、 \" + String.fromCharCode(0x203a) + \" 按鈕選擇月份\\n\" +\n\"- 使用滑鼠點擊上述按鈕並按住不放，可開啟快速選單。\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"時間選擇方式：\\n\" +\n\"- 「單擊」時分秒為遞增\\n\" +\n\"- 或 「Shift-單擊」為遞減\\n\" +\n\"- 或 「單擊且拖拉」為快速選擇\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"前一年 (按住不放可顯示選單)\";\nCalendar._TT[\"PREV_MONTH\"] = \"前一個月 (按住不放可顯示選單)\";\nCalendar._TT[\"GO_TODAY\"] = \"選擇今天\";\nCalendar._TT[\"NEXT_MONTH\"] = \"後一個月 (按住不放可顯示選單)\";\nCalendar._TT[\"NEXT_YEAR\"] = \"下一年 (按住不放可顯式選單)\";\nCalendar._TT[\"SEL_DATE\"] = \"請點選日期\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"按住不放可拖拉視窗\";\nCalendar._TT[\"PART_TODAY\"] = \" (今天)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"以 %s 做為一週的首日\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"關閉視窗\";\nCalendar._TT[\"TODAY\"] = \"今天\";\nCalendar._TT[\"TIME_PART\"] = \"(Shift-)加「單擊」或「拖拉」可變更值\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"星期 %a, %b %e 日\";\n\nCalendar._TT[\"WK\"] = \"週\";\nCalendar._TT[\"TIME\"] = \"時間:\";\n"
  },
  {
    "path": "public/javascripts/calendar/lang/calendar-zh.js",
    "content": "// ** I18N\n\n// Calendar Chinese language\n// Author: Andy Wu, <andywu.zh@gmail.com>\n// Encoding: any\n// Distributed under the same terms as the calendar itself.\n\n// For translators: please use UTF-8 if possible.  We strongly believe that\n// Unicode is the answer to a real internationalized world.  Also please\n// include your contact information in the header, as can be seen above.\n\n// full day names\nCalendar._DN = new Array\n(\"星期日\",\n \"星期一\",\n \"星期二\",\n \"星期三\",\n \"星期四\",\n \"星期五\",\n \"星期六\",\n \"星期日\");\n\n// Please note that the following array of short day names (and the same goes\n// for short month names, _SMN) isn't absolutely necessary.  We give it here\n// for exemplification on how one can customize the short day names, but if\n// they are simply the first N letters of the full name you can simply say:\n//\n//   Calendar._SDN_len = N; // short day name length\n//   Calendar._SMN_len = N; // short month name length\n//\n// If N = 3 then this is not needed either since we assume a value of 3 if not\n// present, to be compatible with translation files that were written before\n// this feature.\n\n// short day names\nCalendar._SDN = new Array\n(\"日\",\n \"一\",\n \"二\",\n \"三\",\n \"四\",\n \"五\",\n \"六\",\n \"日\");\n\n// First day of the week. \"0\" means display Sunday first, \"1\" means display\n// Monday first, etc.\nCalendar._FD = 0;\n\n// full month names\nCalendar._MN = new Array\n(\"1月\",\n \"2月\",\n \"3月\",\n \"4月\",\n \"5月\",\n \"6月\",\n \"7月\",\n \"8月\",\n \"9月\",\n \"10月\",\n \"11月\",\n \"12月\");\n\n// short month names\nCalendar._SMN = new Array\n(\"1月\",\n \"2月\",\n \"3月\",\n \"4月\",\n \"5月\",\n \"6月\",\n \"7月\",\n \"8月\",\n \"9月\",\n \"10月\",\n \"11月\",\n \"12月\");\n\n// tooltips\nCalendar._TT = {};\nCalendar._TT[\"INFO\"] = \"关于日历\";\n\nCalendar._TT[\"ABOUT\"] =\n\"DHTML 日期/时间 选择器\\n\" +\n\"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\\n\" + // don't translate this this ;-)\n\"最新版本请访问： http://www.dynarch.com/projects/calendar/\\n\" +\n\"遵循 GNU LGPL 发布。详情请查阅 http://gnu.org/licenses/lgpl.html \" +\n\"\\n\\n\" +\n\"日期选择：\\n\" +\n\"- 使用 \\xab，\\xbb 按钮选择年\\n\" +\n\"- 使用 \" + String.fromCharCode(0x2039) + \"，\" + String.fromCharCode(0x203a) + \" 按钮选择月\\n\" +\n\"- 在上述按钮上按住不放可以快速选择\";\nCalendar._TT[\"ABOUT_TIME\"] = \"\\n\\n\" +\n\"时间选择：\\n\" +\n\"- 点击时间的任意部分来增加\\n\" +\n\"- Shift加点击来减少\\n\" +\n\"- 点击后拖动进行快速选择\";\n\nCalendar._TT[\"PREV_YEAR\"] = \"上年（按住不放显示菜单）\";\nCalendar._TT[\"PREV_MONTH\"] = \"上月（按住不放显示菜单）\";\nCalendar._TT[\"GO_TODAY\"] = \"回到今天\";\nCalendar._TT[\"NEXT_MONTH\"] = \"下月（按住不放显示菜单）\";\nCalendar._TT[\"NEXT_YEAR\"] = \"下年（按住不放显示菜单）\";\nCalendar._TT[\"SEL_DATE\"] = \"选择日期\";\nCalendar._TT[\"DRAG_TO_MOVE\"] = \"拖动\";\nCalendar._TT[\"PART_TODAY\"] = \" (今日)\";\n\n// the following is to inform that \"%s\" is to be the first day of week\n// %s will be replaced with the day name.\nCalendar._TT[\"DAY_FIRST\"] = \"一周开始于 %s\";\n\n// This may be locale-dependent.  It specifies the week-end days, as an array\n// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1\n// means Monday, etc.\nCalendar._TT[\"WEEKEND\"] = \"0,6\";\n\nCalendar._TT[\"CLOSE\"] = \"关闭\";\nCalendar._TT[\"TODAY\"] = \"今天\";\nCalendar._TT[\"TIME_PART\"] = \"Shift加点击或者拖动来变更\";\n\n// date formats\nCalendar._TT[\"DEF_DATE_FORMAT\"] = \"%Y-%m-%d\";\nCalendar._TT[\"TT_DATE_FORMAT\"] = \"星期%a %b%e日\";\n\nCalendar._TT[\"WK\"] = \"周\";\nCalendar._TT[\"TIME\"] = \"时间：\";\n"
  },
  {
    "path": "public/javascripts/context_menu.js",
    "content": "/* BetterMeans - Work 2.0\n   Copyright (C) 2006-2011  See readme for details and license */\n\nvar observingContextMenuClick;\n\nContextMenu = Class.create();\nContextMenu.prototype = {\n  initialize: function (url) {\n  this.url = url;\n\n  // prevent text selection in the issue list\n  var tables = $$('table.issues');\n  for (i=0; i<tables.length; i++) {\n    tables[i].onselectstart = function () { return false; } // ie\n    tables[i].onmousedown = function () { return false; } // mozilla\n  }\n\n  if (!observingContextMenuClick) {\n    Event.observe(document, 'click', this.Click.bindAsEventListener(this));\n    Event.observe(document, (window.opera ? 'click' : 'contextmenu'), this.RightClick.bindAsEventListener(this));\n    observingContextMenuClick = true;\n  }\n\n  this.unselectAll();\n  this.lastSelected = null;\n  },\n\n  RightClick: function(e) {\n    this.hideMenu();\n    // do not show the context menu on links\n    if (Event.element(e).tagName == 'A') { return; }\n    // right-click simulated by Alt+Click with Opera\n    if (window.opera && !e.altKey) { return; }\n    var tr = Event.findElement(e, 'tr');\n    if (tr == document || tr == undefined  || !tr.hasClassName('hascontextmenu')) { return; }\n    Event.stop(e);\n    if (!this.isSelected(tr)) {\n      this.unselectAll();\n      this.addSelection(tr);\n      this.lastSelected = tr;\n    }\n    this.showMenu(e);\n  },\n\n  Click: function(e) {\n    this.hideMenu();\n    if (Event.element(e).tagName == 'A') { return; }\n    if (window.opera && e.altKey) {  return; }\n    if (Event.isLeftClick(e) || (navigator.appVersion.match(/\\bMSIE\\b/))) {\n      var tr = Event.findElement(e, 'tr');\n      if (tr!=null && tr!=document && tr.hasClassName('hascontextmenu')) {\n        // a row was clicked, check if the click was on checkbox\n        var box = Event.findElement(e, 'input');\n        if (box!=document && box!=undefined) {\n          // a checkbox may be clicked\n          if (box.checked) {\n            tr.addClassName('context-menu-selection');\n          } else {\n            tr.removeClassName('context-menu-selection');\n          }\n        } else {\n          if (e.ctrlKey) {\n            this.toggleSelection(tr);\n          } else if (e.shiftKey) {\n            if (this.lastSelected != null) {\n              var toggling = false;\n              var rows = $$('.hascontextmenu');\n              for (i=0; i<rows.length; i++) {\n                if (toggling || rows[i]==tr) {\n                  this.addSelection(rows[i]);\n                }\n                if (rows[i]==tr || rows[i]==this.lastSelected) {\n                  toggling = !toggling;\n                }\n              }\n            } else {\n              this.addSelection(tr);\n            }\n          } else {\n            this.unselectAll();\n            this.addSelection(tr);\n          }\n          this.lastSelected = tr;\n        }\n      } else {\n        // click is outside the rows\n        var t = Event.findElement(e, 'a');\n        if ((t != document) && (Element.hasClassName(t, 'disabled') || Element.hasClassName(t, 'submenu'))) {\n          Event.stop(e);\n        }\n      }\n    }\n    else{\n      this.RightClick(e);\n    }\n  },\n\n  showMenu: function(e) {\n    var mouse_x = Event.pointerX(e);\n    var mouse_y = Event.pointerY(e);\n    var render_x = mouse_x;\n    var render_y = mouse_y;\n    var dims;\n    var menu_width;\n    var menu_height;\n    var window_width;\n    var window_height;\n    var max_width;\n    var max_height;\n\n    $('context-menu').style['left'] = (render_x + 'px');\n    $('context-menu').style['top'] = (render_y + 'px');\n    Element.update('context-menu', '');\n\n    new Ajax.Updater({success:'context-menu'}, this.url,\n      {asynchronous:true,\n       evalScripts:true,\n       parameters:Form.serialize(Event.findElement(e, 'form')),\n       onComplete:function(request){\n         dims = $('context-menu').getDimensions();\n         menu_width = dims.width;\n         menu_height = dims.height;\n         max_width = mouse_x + 2*menu_width;\n         max_height = mouse_y + menu_height;\n\n         var ws = window_size();\n         window_width = ws.width;\n         window_height = ws.height;\n\n         /* display the menu above and/or to the left of the click if needed */\n         if (max_width > window_width) {\n           render_x -= menu_width;\n           $('context-menu').addClassName('reverse-x');\n         } else {\n           $('context-menu').removeClassName('reverse-x');\n         }\n         if (max_height > window_height) {\n           render_y -= menu_height;\n           $('context-menu').addClassName('reverse-y');\n         } else {\n           $('context-menu').removeClassName('reverse-y');\n         }\n         if (render_x <= 0) render_x = 1;\n         if (render_y <= 0) render_y = 1;\n         $('context-menu').style['left'] = (render_x + 'px');\n         $('context-menu').style['top'] = (render_y + 'px');\n\n         Effect.Appear('context-menu', {duration: 0.20});\n         if (window.parseStylesheets) { window.parseStylesheets(); } // IE\n      }})\n  },\n\n  hideMenu: function() {\n    Element.hide('context-menu');\n  },\n\n  addSelection: function(tr) {\n    tr.addClassName('context-menu-selection');\n    this.checkSelectionBox(tr, true);\n  },\n\n  toggleSelection: function(tr) {\n    if (this.isSelected(tr)) {\n      this.removeSelection(tr);\n    } else {\n      this.addSelection(tr);\n    }\n  },\n\n  removeSelection: function(tr) {\n    tr.removeClassName('context-menu-selection');\n    this.checkSelectionBox(tr, false);\n  },\n\n  unselectAll: function() {\n    var rows = $$('.hascontextmenu');\n    for (i=0; i<rows.length; i++) {\n      this.removeSelection(rows[i]);\n    }\n  },\n\n  checkSelectionBox: function(tr, checked) {\n    var inputs = Element.getElementsBySelector(tr, 'input');\n    if (inputs.length > 0) { inputs[0].checked = checked; }\n  },\n\n  isSelected: function(tr) {\n    return Element.hasClassName(tr, 'context-menu-selection');\n  }\n}\n\nfunction toggleIssuesSelection(el) {\n  var boxes = el.getElementsBySelector('input[type=checkbox]');\n  var all_checked = true;\n  for (i = 0; i < boxes.length; i++) { if (boxes[i].checked == false) { all_checked = false; } }\n  for (i = 0; i < boxes.length; i++) {\n    if (all_checked) {\n      boxes[i].checked = false;\n      boxes[i].up('tr').removeClassName('context-menu-selection');\n    } else if (boxes[i].checked == false) {\n      boxes[i].checked = true;\n      boxes[i].up('tr').addClassName('context-menu-selection');\n    }\n  }\n}\n\nfunction window_size() {\n    var w;\n    var h;\n    if (window.innerWidth) {\n  w = window.innerWidth;\n  h = window.innerHeight;\n    } else if (document.documentElement) {\n  w = document.documentElement.clientWidth;\n  h = document.documentElement.clientHeight;\n    } else {\n  w = document.body.clientWidth;\n  h = document.body.clientHeight;\n    }\n    return {width: w, height: h};\n}\n"
  },
  {
    "path": "public/javascripts/controls.js",
    "content": "// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)\n//           (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan)\n//           (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)\n// Contributors:\n//  Richard Livsey\n//  Rahul Bhargava\n//  Rob Wills\n//\n// script.aculo.us is freely distributable under the terms of an MIT-style license.\n// For details, see the script.aculo.us web site: http://script.aculo.us/\n\n// Autocompleter.Base handles all the autocompletion functionality\n// that's independent of the data source for autocompletion. This\n// includes drawing the autocompletion menu, observing keyboard\n// and mouse events, and similar.\n//\n// Specific autocompleters need to provide, at the very least,\n// a getUpdatedChoices function that will be invoked every time\n// the text inside the monitored textbox changes. This method\n// should get the text for which to provide autocompletion by\n// invoking this.getToken(), NOT by directly accessing\n// this.element.value. This is to allow incremental tokenized\n// autocompletion. Specific auto-completion logic (AJAX, etc)\n// belongs in getUpdatedChoices.\n//\n// Tokenized incremental autocompletion is enabled automatically\n// when an autocompleter is instantiated with the 'tokens' option\n// in the options parameter, e.g.:\n// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });\n// will incrementally autocomplete with a comma as the token.\n// Additionally, ',' in the above example can be replaced with\n// a token array, e.g. { tokens: [',', '\\n'] } which\n// enables autocompletion on multiple tokens. This is most\n// useful when one of the tokens is \\n (a newline), as it\n// allows smart autocompletion after linebreaks.\n\nif(typeof Effect == 'undefined')\n  throw(\"controls.js requires including script.aculo.us' effects.js library\");\n\nvar Autocompleter = { };\nAutocompleter.Base = Class.create({\n  baseInitialize: function(element, update, options) {\n    element          = $(element);\n    this.element     = element;\n    this.update      = $(update);\n    this.hasFocus    = false;\n    this.changed     = false;\n    this.active      = false;\n    this.index       = 0;\n    this.entryCount  = 0;\n    this.oldElementValue = this.element.value;\n\n    if(this.setOptions)\n      this.setOptions(options);\n    else\n      this.options = options || { };\n\n    this.options.paramName    = this.options.paramName || this.element.name;\n    this.options.tokens       = this.options.tokens || [];\n    this.options.frequency    = this.options.frequency || 0.4;\n    this.options.minChars     = this.options.minChars || 1;\n    this.options.onShow       = this.options.onShow ||\n      function(element, update){\n        if(!update.style.position || update.style.position=='absolute') {\n          update.style.position = 'absolute';\n          Position.clone(element, update, {\n            setHeight: false,\n            offsetTop: element.offsetHeight\n          });\n        }\n        Effect.Appear(update,{duration:0.15});\n      };\n    this.options.onHide = this.options.onHide ||\n      function(element, update){ new Effect.Fade(update,{duration:0.15}) };\n\n    if(typeof(this.options.tokens) == 'string')\n      this.options.tokens = new Array(this.options.tokens);\n    // Force carriage returns as token delimiters anyway\n    if (!this.options.tokens.include('\\n'))\n      this.options.tokens.push('\\n');\n\n    this.observer = null;\n\n    this.element.setAttribute('autocomplete','off');\n\n    Element.hide(this.update);\n\n    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));\n    Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));\n  },\n\n  show: function() {\n    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);\n    if(!this.iefix &&\n      (Prototype.Browser.IE) &&\n      (Element.getStyle(this.update, 'position')=='absolute')) {\n      new Insertion.After(this.update,\n       '<iframe id=\"' + this.update.id + '_iefix\" '+\n       'style=\"display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);\" ' +\n       'src=\"javascript:false;\" frameborder=\"0\" scrolling=\"no\"></iframe>');\n      this.iefix = $(this.update.id+'_iefix');\n    }\n    if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);\n  },\n\n  fixIEOverlapping: function() {\n    Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});\n    this.iefix.style.zIndex = 1;\n    this.update.style.zIndex = 2;\n    Element.show(this.iefix);\n  },\n\n  hide: function() {\n    this.stopIndicator();\n    if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);\n    if(this.iefix) Element.hide(this.iefix);\n  },\n\n  startIndicator: function() {\n    if(this.options.indicator) Element.show(this.options.indicator);\n  },\n\n  stopIndicator: function() {\n    if(this.options.indicator) Element.hide(this.options.indicator);\n  },\n\n  onKeyPress: function(event) {\n    if(this.active)\n      switch(event.keyCode) {\n       case Event.KEY_TAB:\n       case Event.KEY_RETURN:\n         this.selectEntry();\n         Event.stop(event);\n       case Event.KEY_ESC:\n         this.hide();\n         this.active = false;\n         Event.stop(event);\n         return;\n       case Event.KEY_LEFT:\n       case Event.KEY_RIGHT:\n         return;\n       case Event.KEY_UP:\n         this.markPrevious();\n         this.render();\n         Event.stop(event);\n         return;\n       case Event.KEY_DOWN:\n         this.markNext();\n         this.render();\n         Event.stop(event);\n         return;\n      }\n     else\n       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||\n         (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;\n\n    this.changed = true;\n    this.hasFocus = true;\n\n    if(this.observer) clearTimeout(this.observer);\n      this.observer =\n        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);\n  },\n\n  activate: function() {\n    this.changed = false;\n    this.hasFocus = true;\n    this.getUpdatedChoices();\n  },\n\n  onHover: function(event) {\n    var element = Event.findElement(event, 'LI');\n    if(this.index != element.autocompleteIndex)\n    {\n        this.index = element.autocompleteIndex;\n        this.render();\n    }\n    Event.stop(event);\n  },\n\n  onClick: function(event) {\n    var element = Event.findElement(event, 'LI');\n    this.index = element.autocompleteIndex;\n    this.selectEntry();\n    this.hide();\n  },\n\n  onBlur: function(event) {\n    // needed to make click events working\n    setTimeout(this.hide.bind(this), 250);\n    this.hasFocus = false;\n    this.active = false;\n  },\n\n  render: function() {\n    if(this.entryCount > 0) {\n      for (var i = 0; i < this.entryCount; i++)\n        this.index==i ?\n          Element.addClassName(this.getEntry(i),\"selected\") :\n          Element.removeClassName(this.getEntry(i),\"selected\");\n      if(this.hasFocus) {\n        this.show();\n        this.active = true;\n      }\n    } else {\n      this.active = false;\n      this.hide();\n    }\n  },\n\n  markPrevious: function() {\n    if(this.index > 0) this.index--;\n      else this.index = this.entryCount-1;\n    this.getEntry(this.index).scrollIntoView(true);\n  },\n\n  markNext: function() {\n    if(this.index < this.entryCount-1) this.index++;\n      else this.index = 0;\n    this.getEntry(this.index).scrollIntoView(false);\n  },\n\n  getEntry: function(index) {\n    return this.update.firstChild.childNodes[index];\n  },\n\n  getCurrentEntry: function() {\n    return this.getEntry(this.index);\n  },\n\n  selectEntry: function() {\n    this.active = false;\n    this.updateElement(this.getCurrentEntry());\n  },\n\n  updateElement: function(selectedElement) {\n    if (this.options.updateElement) {\n      this.options.updateElement(selectedElement);\n      return;\n    }\n    var value = '';\n    if (this.options.select) {\n      var nodes = $(selectedElement).select('.' + this.options.select) || [];\n      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);\n    } else\n      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');\n\n    var bounds = this.getTokenBounds();\n    if (bounds[0] != -1) {\n      var newValue = this.element.value.substr(0, bounds[0]);\n      var whitespace = this.element.value.substr(bounds[0]).match(/^\\s+/);\n      if (whitespace)\n        newValue += whitespace[0];\n      this.element.value = newValue + value + this.element.value.substr(bounds[1]);\n    } else {\n      this.element.value = value;\n    }\n    this.oldElementValue = this.element.value;\n    this.element.focus();\n\n    if (this.options.afterUpdateElement)\n      this.options.afterUpdateElement(this.element, selectedElement);\n  },\n\n  updateChoices: function(choices) {\n    if(!this.changed && this.hasFocus) {\n      this.update.innerHTML = choices;\n      Element.cleanWhitespace(this.update);\n      Element.cleanWhitespace(this.update.down());\n\n      if(this.update.firstChild && this.update.down().childNodes) {\n        this.entryCount =\n          this.update.down().childNodes.length;\n        for (var i = 0; i < this.entryCount; i++) {\n          var entry = this.getEntry(i);\n          entry.autocompleteIndex = i;\n          this.addObservers(entry);\n        }\n      } else {\n        this.entryCount = 0;\n      }\n\n      this.stopIndicator();\n      this.index = 0;\n\n      if(this.entryCount==1 && this.options.autoSelect) {\n        this.selectEntry();\n        this.hide();\n      } else {\n        this.render();\n      }\n    }\n  },\n\n  addObservers: function(element) {\n    Event.observe(element, \"mouseover\", this.onHover.bindAsEventListener(this));\n    Event.observe(element, \"click\", this.onClick.bindAsEventListener(this));\n  },\n\n  onObserverEvent: function() {\n    this.changed = false;\n    this.tokenBounds = null;\n    if(this.getToken().length>=this.options.minChars) {\n      this.getUpdatedChoices();\n    } else {\n      this.active = false;\n      this.hide();\n    }\n    this.oldElementValue = this.element.value;\n  },\n\n  getToken: function() {\n    var bounds = this.getTokenBounds();\n    return this.element.value.substring(bounds[0], bounds[1]).strip();\n  },\n\n  getTokenBounds: function() {\n    if (null != this.tokenBounds) return this.tokenBounds;\n    var value = this.element.value;\n    if (value.strip().empty()) return [-1, 0];\n    var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);\n    var offset = (diff == this.oldElementValue.length ? 1 : 0);\n    var prevTokenPos = -1, nextTokenPos = value.length;\n    var tp;\n    for (var index = 0, l = this.options.tokens.length; index < l; ++index) {\n      tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);\n      if (tp > prevTokenPos) prevTokenPos = tp;\n      tp = value.indexOf(this.options.tokens[index], diff + offset);\n      if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;\n    }\n    return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);\n  }\n});\n\nAutocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {\n  var boundary = Math.min(newS.length, oldS.length);\n  for (var index = 0; index < boundary; ++index)\n    if (newS[index] != oldS[index])\n      return index;\n  return boundary;\n};\n\nAjax.Autocompleter = Class.create(Autocompleter.Base, {\n  initialize: function(element, update, url, options) {\n    this.baseInitialize(element, update, options);\n    this.options.asynchronous  = true;\n    this.options.onComplete    = this.onComplete.bind(this);\n    this.options.defaultParams = this.options.parameters || null;\n    this.url                   = url;\n  },\n\n  getUpdatedChoices: function() {\n    this.startIndicator();\n\n    var entry = encodeURIComponent(this.options.paramName) + '=' +\n      encodeURIComponent(this.getToken());\n\n    this.options.parameters = this.options.callback ?\n      this.options.callback(this.element, entry) : entry;\n\n    if(this.options.defaultParams)\n      this.options.parameters += '&' + this.options.defaultParams;\n\n    new Ajax.Request(this.url, this.options);\n  },\n\n  onComplete: function(request) {\n    this.updateChoices(request.responseText);\n  }\n});\n\n// The local array autocompleter. Used when you'd prefer to\n// inject an array of autocompletion options into the page, rather\n// than sending out Ajax queries, which can be quite slow sometimes.\n//\n// The constructor takes four parameters. The first two are, as usual,\n// the id of the monitored textbox, and id of the autocompletion menu.\n// The third is the array you want to autocomplete from, and the fourth\n// is the options block.\n//\n// Extra local autocompletion options:\n// - choices - How many autocompletion choices to offer\n//\n// - partialSearch - If false, the autocompleter will match entered\n//                    text only at the beginning of strings in the\n//                    autocomplete array. Defaults to true, which will\n//                    match text at the beginning of any *word* in the\n//                    strings in the autocomplete array. If you want to\n//                    search anywhere in the string, additionally set\n//                    the option fullSearch to true (default: off).\n//\n// - fullSsearch - Search anywhere in autocomplete array strings.\n//\n// - partialChars - How many characters to enter before triggering\n//                   a partial match (unlike minChars, which defines\n//                   how many characters are required to do any match\n//                   at all). Defaults to 2.\n//\n// - ignoreCase - Whether to ignore case when autocompleting.\n//                 Defaults to true.\n//\n// It's possible to pass in a custom function as the 'selector'\n// option, if you prefer to write your own autocompletion logic.\n// In that case, the other options above will not apply unless\n// you support them.\n\nAutocompleter.Local = Class.create(Autocompleter.Base, {\n  initialize: function(element, update, array, options) {\n    this.baseInitialize(element, update, options);\n    this.options.array = array;\n  },\n\n  getUpdatedChoices: function() {\n    this.updateChoices(this.options.selector(this));\n  },\n\n  setOptions: function(options) {\n    this.options = Object.extend({\n      choices: 10,\n      partialSearch: true,\n      partialChars: 2,\n      ignoreCase: true,\n      fullSearch: false,\n      selector: function(instance) {\n        var ret       = []; // Beginning matches\n        var partial   = []; // Inside matches\n        var entry     = instance.getToken();\n        var count     = 0;\n\n        for (var i = 0; i < instance.options.array.length &&\n          ret.length < instance.options.choices ; i++) {\n\n          var elem = instance.options.array[i];\n          var foundPos = instance.options.ignoreCase ?\n            elem.toLowerCase().indexOf(entry.toLowerCase()) :\n            elem.indexOf(entry);\n\n          while (foundPos != -1) {\n            if (foundPos == 0 && elem.length != entry.length) {\n              ret.push(\"<li><strong>\" + elem.substr(0, entry.length) + \"</strong>\" +\n                elem.substr(entry.length) + \"</li>\");\n              break;\n            } else if (entry.length >= instance.options.partialChars &&\n              instance.options.partialSearch && foundPos != -1) {\n              if (instance.options.fullSearch || /\\s/.test(elem.substr(foundPos-1,1))) {\n                partial.push(\"<li>\" + elem.substr(0, foundPos) + \"<strong>\" +\n                  elem.substr(foundPos, entry.length) + \"</strong>\" + elem.substr(\n                  foundPos + entry.length) + \"</li>\");\n                break;\n              }\n            }\n\n            foundPos = instance.options.ignoreCase ?\n              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :\n              elem.indexOf(entry, foundPos + 1);\n\n          }\n        }\n        if (partial.length)\n          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));\n        return \"<ul>\" + ret.join('') + \"</ul>\";\n      }\n    }, options || { });\n  }\n});\n\n// AJAX in-place editor and collection editor\n// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).\n\n// Use this if you notice weird scrolling problems on some browsers,\n// the DOM might be a bit confused when this gets called so do this\n// waits 1 ms (with setTimeout) until it does the activation\nField.scrollFreeActivate = function(field) {\n  setTimeout(function() {\n    Field.activate(field);\n  }, 1);\n};\n\nAjax.InPlaceEditor = Class.create({\n  initialize: function(element, url, options) {\n    this.url = url;\n    this.element = element = $(element);\n    this.prepareOptions();\n    this._controls = { };\n    arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!\n    Object.extend(this.options, options || { });\n    if (!this.options.formId && this.element.id) {\n      this.options.formId = this.element.id + '-inplaceeditor';\n      if ($(this.options.formId))\n        this.options.formId = '';\n    }\n    if (this.options.externalControl)\n      this.options.externalControl = $(this.options.externalControl);\n    if (!this.options.externalControl)\n      this.options.externalControlOnly = false;\n    this._originalBackground = this.element.getStyle('background-color') || 'transparent';\n    this.element.title = this.options.clickToEditText;\n    this._boundCancelHandler = this.handleFormCancellation.bind(this);\n    this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);\n    this._boundFailureHandler = this.handleAJAXFailure.bind(this);\n    this._boundSubmitHandler = this.handleFormSubmission.bind(this);\n    this._boundWrapperHandler = this.wrapUp.bind(this);\n    this.registerListeners();\n  },\n  checkForEscapeOrReturn: function(e) {\n    if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;\n    if (Event.KEY_ESC == e.keyCode)\n      this.handleFormCancellation(e);\n    else if (Event.KEY_RETURN == e.keyCode)\n      this.handleFormSubmission(e);\n  },\n  createControl: function(mode, handler, extraClasses) {\n    var control = this.options[mode + 'Control'];\n    var text = this.options[mode + 'Text'];\n    if ('button' == control) {\n      var btn = document.createElement('input');\n      btn.type = 'submit';\n      btn.value = text;\n      btn.className = 'editor_' + mode + '_button';\n      if ('cancel' == mode)\n        btn.onclick = this._boundCancelHandler;\n      this._form.appendChild(btn);\n      this._controls[mode] = btn;\n    } else if ('link' == control) {\n      var link = document.createElement('a');\n      link.href = '#';\n      link.appendChild(document.createTextNode(text));\n      link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;\n      link.className = 'editor_' + mode + '_link';\n      if (extraClasses)\n        link.className += ' ' + extraClasses;\n      this._form.appendChild(link);\n      this._controls[mode] = link;\n    }\n  },\n  createEditField: function() {\n    var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());\n    var fld;\n    if (1 >= this.options.rows && !/\\r|\\n/.test(this.getText())) {\n      fld = document.createElement('input');\n      fld.type = 'text';\n      var size = this.options.size || this.options.cols || 0;\n      if (0 < size) fld.size = size;\n    } else {\n      fld = document.createElement('textarea');\n      fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);\n      fld.cols = this.options.cols || 40;\n    }\n    fld.name = this.options.paramName;\n    fld.value = text; // No HTML breaks conversion anymore\n    fld.className = 'editor_field';\n    if (this.options.submitOnBlur)\n      fld.onblur = this._boundSubmitHandler;\n    this._controls.editor = fld;\n    if (this.options.loadTextURL)\n      this.loadExternalText();\n    this._form.appendChild(this._controls.editor);\n  },\n  createForm: function() {\n    var ipe = this;\n    function addText(mode, condition) {\n      var text = ipe.options['text' + mode + 'Controls'];\n      if (!text || condition === false) return;\n      ipe._form.appendChild(document.createTextNode(text));\n    };\n    this._form = $(document.createElement('form'));\n    this._form.id = this.options.formId;\n    this._form.addClassName(this.options.formClassName);\n    this._form.onsubmit = this._boundSubmitHandler;\n    this.createEditField();\n    if ('textarea' == this._controls.editor.tagName.toLowerCase())\n      this._form.appendChild(document.createElement('br'));\n    if (this.options.onFormCustomization)\n      this.options.onFormCustomization(this, this._form);\n    addText('Before', this.options.okControl || this.options.cancelControl);\n    this.createControl('ok', this._boundSubmitHandler);\n    addText('Between', this.options.okControl && this.options.cancelControl);\n    this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');\n    addText('After', this.options.okControl || this.options.cancelControl);\n  },\n  destroy: function() {\n    if (this._oldInnerHTML)\n      this.element.innerHTML = this._oldInnerHTML;\n    this.leaveEditMode();\n    this.unregisterListeners();\n  },\n  enterEditMode: function(e) {\n    if (this._saving || this._editing) return;\n    this._editing = true;\n    this.triggerCallback('onEnterEditMode');\n    if (this.options.externalControl)\n      this.options.externalControl.hide();\n    this.element.hide();\n    this.createForm();\n    this.element.parentNode.insertBefore(this._form, this.element);\n    if (!this.options.loadTextURL)\n      this.postProcessEditField();\n    if (e) Event.stop(e);\n  },\n  enterHover: function(e) {\n    if (this.options.hoverClassName)\n      this.element.addClassName(this.options.hoverClassName);\n    if (this._saving) return;\n    this.triggerCallback('onEnterHover');\n  },\n  getText: function() {\n    return this.element.innerHTML.unescapeHTML();\n  },\n  handleAJAXFailure: function(transport) {\n    this.triggerCallback('onFailure', transport);\n    if (this._oldInnerHTML) {\n      this.element.innerHTML = this._oldInnerHTML;\n      this._oldInnerHTML = null;\n    }\n  },\n  handleFormCancellation: function(e) {\n    this.wrapUp();\n    if (e) Event.stop(e);\n  },\n  handleFormSubmission: function(e) {\n    var form = this._form;\n    var value = $F(this._controls.editor);\n    this.prepareSubmission();\n    var params = this.options.callback(form, value) || '';\n    if (Object.isString(params))\n      params = params.toQueryParams();\n    params.editorId = this.element.id;\n    if (this.options.htmlResponse) {\n      var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);\n      Object.extend(options, {\n        parameters: params,\n        onComplete: this._boundWrapperHandler,\n        onFailure: this._boundFailureHandler\n      });\n      new Ajax.Updater({ success: this.element }, this.url, options);\n    } else {\n      var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);\n      Object.extend(options, {\n        parameters: params,\n        onComplete: this._boundWrapperHandler,\n        onFailure: this._boundFailureHandler\n      });\n      new Ajax.Request(this.url, options);\n    }\n    if (e) Event.stop(e);\n  },\n  leaveEditMode: function() {\n    this.element.removeClassName(this.options.savingClassName);\n    this.removeForm();\n    this.leaveHover();\n    this.element.style.backgroundColor = this._originalBackground;\n    this.element.show();\n    if (this.options.externalControl)\n      this.options.externalControl.show();\n    this._saving = false;\n    this._editing = false;\n    this._oldInnerHTML = null;\n    this.triggerCallback('onLeaveEditMode');\n  },\n  leaveHover: function(e) {\n    if (this.options.hoverClassName)\n      this.element.removeClassName(this.options.hoverClassName);\n    if (this._saving) return;\n    this.triggerCallback('onLeaveHover');\n  },\n  loadExternalText: function() {\n    this._form.addClassName(this.options.loadingClassName);\n    this._controls.editor.disabled = true;\n    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);\n    Object.extend(options, {\n      parameters: 'editorId=' + encodeURIComponent(this.element.id),\n      onComplete: Prototype.emptyFunction,\n      onSuccess: function(transport) {\n        this._form.removeClassName(this.options.loadingClassName);\n        var text = transport.responseText;\n        if (this.options.stripLoadedTextTags)\n          text = text.stripTags();\n        this._controls.editor.value = text;\n        this._controls.editor.disabled = false;\n        this.postProcessEditField();\n      }.bind(this),\n      onFailure: this._boundFailureHandler\n    });\n    new Ajax.Request(this.options.loadTextURL, options);\n  },\n  postProcessEditField: function() {\n    var fpc = this.options.fieldPostCreation;\n    if (fpc)\n      $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();\n  },\n  prepareOptions: function() {\n    this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);\n    Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);\n    [this._extraDefaultOptions].flatten().compact().each(function(defs) {\n      Object.extend(this.options, defs);\n    }.bind(this));\n  },\n  prepareSubmission: function() {\n    this._saving = true;\n    this.removeForm();\n    this.leaveHover();\n    this.showSaving();\n  },\n  registerListeners: function() {\n    this._listeners = { };\n    var listener;\n    $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {\n      listener = this[pair.value].bind(this);\n      this._listeners[pair.key] = listener;\n      if (!this.options.externalControlOnly)\n        this.element.observe(pair.key, listener);\n      if (this.options.externalControl)\n        this.options.externalControl.observe(pair.key, listener);\n    }.bind(this));\n  },\n  removeForm: function() {\n    if (!this._form) return;\n    this._form.remove();\n    this._form = null;\n    this._controls = { };\n  },\n  showSaving: function() {\n    this._oldInnerHTML = this.element.innerHTML;\n    this.element.innerHTML = this.options.savingText;\n    this.element.addClassName(this.options.savingClassName);\n    this.element.style.backgroundColor = this._originalBackground;\n    this.element.show();\n  },\n  triggerCallback: function(cbName, arg) {\n    if ('function' == typeof this.options[cbName]) {\n      this.options[cbName](this, arg);\n    }\n  },\n  unregisterListeners: function() {\n    $H(this._listeners).each(function(pair) {\n      if (!this.options.externalControlOnly)\n        this.element.stopObserving(pair.key, pair.value);\n      if (this.options.externalControl)\n        this.options.externalControl.stopObserving(pair.key, pair.value);\n    }.bind(this));\n  },\n  wrapUp: function(transport) {\n    this.leaveEditMode();\n    // Can't use triggerCallback due to backward compatibility: requires\n    // binding + direct element\n    this._boundComplete(transport, this.element);\n  }\n});\n\nObject.extend(Ajax.InPlaceEditor.prototype, {\n  dispose: Ajax.InPlaceEditor.prototype.destroy\n});\n\nAjax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {\n  initialize: function($super, element, url, options) {\n    this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;\n    $super(element, url, options);\n  },\n\n  createEditField: function() {\n    var list = document.createElement('select');\n    list.name = this.options.paramName;\n    list.size = 1;\n    this._controls.editor = list;\n    this._collection = this.options.collection || [];\n    if (this.options.loadCollectionURL)\n      this.loadCollection();\n    else\n      this.checkForExternalText();\n    this._form.appendChild(this._controls.editor);\n  },\n\n  loadCollection: function() {\n    this._form.addClassName(this.options.loadingClassName);\n    this.showLoadingText(this.options.loadingCollectionText);\n    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);\n    Object.extend(options, {\n      parameters: 'editorId=' + encodeURIComponent(this.element.id),\n      onComplete: Prototype.emptyFunction,\n      onSuccess: function(transport) {\n        var js = transport.responseText.strip();\n        if (!/^\\[.*\\]$/.test(js)) // TODO: improve sanity check\n          throw('Server returned an invalid collection representation.');\n        this._collection = eval(js);\n        this.checkForExternalText();\n      }.bind(this),\n      onFailure: this.onFailure\n    });\n    new Ajax.Request(this.options.loadCollectionURL, options);\n  },\n\n  showLoadingText: function(text) {\n    this._controls.editor.disabled = true;\n    var tempOption = this._controls.editor.firstChild;\n    if (!tempOption) {\n      tempOption = document.createElement('option');\n      tempOption.value = '';\n      this._controls.editor.appendChild(tempOption);\n      tempOption.selected = true;\n    }\n    tempOption.update((text || '').stripScripts().stripTags());\n  },\n\n  checkForExternalText: function() {\n    this._text = this.getText();\n    if (this.options.loadTextURL)\n      this.loadExternalText();\n    else\n      this.buildOptionList();\n  },\n\n  loadExternalText: function() {\n    this.showLoadingText(this.options.loadingText);\n    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);\n    Object.extend(options, {\n      parameters: 'editorId=' + encodeURIComponent(this.element.id),\n      onComplete: Prototype.emptyFunction,\n      onSuccess: function(transport) {\n        this._text = transport.responseText.strip();\n        this.buildOptionList();\n      }.bind(this),\n      onFailure: this.onFailure\n    });\n    new Ajax.Request(this.options.loadTextURL, options);\n  },\n\n  buildOptionList: function() {\n    this._form.removeClassName(this.options.loadingClassName);\n    this._collection = this._collection.map(function(entry) {\n      return 2 === entry.length ? entry : [entry, entry].flatten();\n    });\n    var marker = ('value' in this.options) ? this.options.value : this._text;\n    var textFound = this._collection.any(function(entry) {\n      return entry[0] == marker;\n    }.bind(this));\n    this._controls.editor.update('');\n    var option;\n    this._collection.each(function(entry, index) {\n      option = document.createElement('option');\n      option.value = entry[0];\n      option.selected = textFound ? entry[0] == marker : 0 == index;\n      option.appendChild(document.createTextNode(entry[1]));\n      this._controls.editor.appendChild(option);\n    }.bind(this));\n    this._controls.editor.disabled = false;\n    Field.scrollFreeActivate(this._controls.editor);\n  }\n});\n\n//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****\n//**** This only  exists for a while,  in order to  let ****\n//**** users adapt to  the new API.  Read up on the new ****\n//**** API and convert your code to it ASAP!            ****\n\nAjax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {\n  if (!options) return;\n  function fallback(name, expr) {\n    if (name in options || expr === undefined) return;\n    options[name] = expr;\n  };\n  fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :\n    options.cancelLink == options.cancelButton == false ? false : undefined)));\n  fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :\n    options.okLink == options.okButton == false ? false : undefined)));\n  fallback('highlightColor', options.highlightcolor);\n  fallback('highlightEndColor', options.highlightendcolor);\n};\n\nObject.extend(Ajax.InPlaceEditor, {\n  DefaultOptions: {\n    ajaxOptions: { },\n    autoRows: 3,                                // Use when multi-line w/ rows == 1\n    cancelControl: 'link',                      // 'link'|'button'|false\n    cancelText: 'cancel',\n    clickToEditText: 'Click to edit',\n    externalControl: null,                      // id|elt\n    externalControlOnly: false,\n    fieldPostCreation: 'activate',              // 'activate'|'focus'|false\n    formClassName: 'inplaceeditor-form',\n    formId: null,                               // id|elt\n    highlightColor: '#ffff99',\n    highlightEndColor: '#ffffff',\n    hoverClassName: '',\n    htmlResponse: true,\n    loadingClassName: 'inplaceeditor-loading',\n    loadingText: 'Loading...',\n    okControl: 'button',                        // 'link'|'button'|false\n    okText: 'ok',\n    paramName: 'value',\n    rows: 1,                                    // If 1 and multi-line, uses autoRows\n    savingClassName: 'inplaceeditor-saving',\n    savingText: 'Saving...',\n    size: 0,\n    stripLoadedTextTags: false,\n    submitOnBlur: false,\n    textAfterControls: '',\n    textBeforeControls: '',\n    textBetweenControls: ''\n  },\n  DefaultCallbacks: {\n    callback: function(form) {\n      return Form.serialize(form);\n    },\n    onComplete: function(transport, element) {\n      // For backward compatibility, this one is bound to the IPE, and passes\n      // the element directly.  It was too often customized, so we don't break it.\n      new Effect.Highlight(element, {\n        startcolor: this.options.highlightColor, keepBackgroundImage: true });\n    },\n    onEnterEditMode: null,\n    onEnterHover: function(ipe) {\n      ipe.element.style.backgroundColor = ipe.options.highlightColor;\n      if (ipe._effect)\n        ipe._effect.cancel();\n    },\n    onFailure: function(transport, ipe) {\n      alert('Error communication with the server: ' + transport.responseText.stripTags());\n    },\n    onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.\n    onLeaveEditMode: null,\n    onLeaveHover: function(ipe) {\n      ipe._effect = new Effect.Highlight(ipe.element, {\n        startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,\n        restorecolor: ipe._originalBackground, keepBackgroundImage: true\n      });\n    }\n  },\n  Listeners: {\n    click: 'enterEditMode',\n    keydown: 'checkForEscapeOrReturn',\n    mouseover: 'enterHover',\n    mouseout: 'leaveHover'\n  }\n});\n\nAjax.InPlaceCollectionEditor.DefaultOptions = {\n  loadingCollectionText: 'Loading options...'\n};\n\n// Delayed observer, like Form.Element.Observer,\n// but waits for delay after last key input\n// Ideal for live-search fields\n\nForm.Element.DelayedObserver = Class.create({\n  initialize: function(element, delay, callback) {\n    this.delay     = delay || 0.5;\n    this.element   = $(element);\n    this.callback  = callback;\n    this.timer     = null;\n    this.lastValue = $F(this.element);\n    Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));\n  },\n  delayedListener: function(event) {\n    if(this.lastValue == $F(this.element)) return;\n    if(this.timer) clearTimeout(this.timer);\n    this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);\n    this.lastValue = $F(this.element);\n  },\n  onTimerEvent: function() {\n    this.timer = null;\n    this.callback(this.element, $F(this.element));\n  }\n});\n"
  },
  {
    "path": "public/javascripts/dashboard.js",
    "content": "var D = []; //all data\nvar R = []; //all retrospectives\nvar local_D = null;\n// var local_R = null;\nvar MAX_REQUESTS_PER_PERSON = 4;\nvar TIMER_INTERVAL = 15000; //15 seconds\nvar INACTIVITY_THRESHOLD = 300000; //5 minutes\nvar timer_active = false;\nvar ITEMHASH = new Array(); //mapping between item IDs and their id in the D array\nvar keyboard_shortcuts = false;\nvar searching = false; //true when user is entering text in search box\nvar default_new_title = 'Enter Title Here';\nvar new_comment_text = 'Add new comment';\nvar new_todo_text = 'Add todo';\n// var panel_height = $(window).height() - $('.gt-hd').height() - $('#help_section').height() + 28;// + $('.gt-footer').height() ;\nvar panel_height = $(window).height() - $('.gt-hd').height() + 28;// + $('.gt-footer').height() ;\nvar last_activity = new Date(); //tracks last activity of mouse or keyboard click. Used to turn off server polling\nvar last_data_pull = new Date(); //tracks last data recieved from server\nvar highest_pri = -9999;\nvar loaded_panels = 0; //keeps track of how many panels have had their data loaded\nvar local_store = null; //local persistant storage\nvar ok_to_save_local_data = false;\nvar complexity_description = ['Real Easy','.','.','Average','.','.','Super Hard'];\nvar new_attachments = []; //stores ids of attachments to a new item\nvar timer_started = false;\n\n$(window).bind('resize', function() {\n  resize();\n});\n\n\n$.fn.makeAbsolute = function(rebase) {\n\n    return this.each(function() {\n\n        var el = $(this);\n\n        var pos = el.position();\n\n        el.css({ position: \"absolute\",\n\n            marginLeft: 0, marginTop: 0,\n\n            top: pos.top, left: pos.left });\n\n        if (rebase)\n\n            el.remove().appendTo(\"body\");\n\n    });\n\n};\n\n$.fn.watermark = function(css, text) {\n    $(this).focus(function() {\n      $(this).filter(function() {\n        return $(this).val() == \"\" || $(this).val() == text;\n      }).removeClass(css).val(\"\");\n    });\n\n    $(this).blur(function() {\n      $(this).filter(function() {\n        return $(this).val() == \"\";\n      }).addClass(css).val(text);\n    });\n\n    var input = $(this);\n    $(this).closest(\"form\").submit(function() {\n      input.filter(function() {\n        return $(this).val() == text;\n      }).val(\"\");\n    });\n\n    $(this).addClass(css).val(text);\n};\n\n\n$.fn.keyboard_sensitive = function() {\n    $(this).focus(function() {\n      keyboard_shortcuts = false;\n    });\n\n    $(this).blur(function() {\n      keyboard_shortcuts = true;\n    });\n};\n\nfunction start(){\n  disable_refresh_button();\n  arm_checkboxes();\n  set_sub_toggle();\n\n  timer_active = false; //stop timer from starting until data loads\n  $('.help-section-link').bind('click',function() {\n    resize();\n  });\n\n  $(\"#dash_key\").mybubbletip('#help_key', {deltaDirection: 'right', bindShow: 'click'});\n\n  $('#fast_search').watermark('watermark','Quick Filter');\n  //Checking for single issue display\n  if (show_issue_id){\n    show_issue_full(show_issue_id);\n    $(\"#load_dashboard\").show();\n    $(\"#loading\").hide();\n  }\n  else if (show_retro_id){\n    show_retro_full(show_retro_id);\n    $(\"#load_dashboard\").show();\n    $(\"#loading\").hide();\n  }\n  else{\n    load_dashboard();\n  }\n}\n\n//Chooses setting of sub workstream toggle button and adds events to it\nfunction set_sub_toggle(){\n  var include = $.cookie('include_sub' + currentUserId);\n  if (include == null){\n    include = 'true';\n  }\n\n  if (include == 'true'){\n    $(\"#toggle_sub_on\").click();\n  }\n  else{\n    $(\"#toggle_sub_off\").click();\n  }\n\n  $(\"#toggle_sub_on\").click(function(){\n    $.cookie('include_sub' + currentUserId, 'true', { expires: 365 });\n    refresh_local_data();\n  });\n  $(\"#toggle_sub_off\").click(function(){\n    $.cookie('include_sub' + currentUserId, 'false', { expires: 365 });\n    refresh_local_data();\n  });\n}\n\nfunction load_dashboard(){\n  //prepares ui for page\n  prepare_page();\n  load_dashboard_data();\n  start_timer();\n\n  $(document).keyup(function(e){\n    last_activity = new Date();\n    start_timer();\n    if (searching){\n      var text = $('#fast_search').val();\n      search_for(text);\n    }\n  });\n\n  $(document).click(function(e)\n  {\n    start_timer();\n    last_activity = new Date();\n  });\n\n  $(document).focus(function(e)\n  {\n    start_timer();\n    last_activity = new Date();\n  });\n\n}\n\n//For IE explorer handling of xml\nfunction parse_xml(xml){\n  if (jQuery.browser.msie) {\n      var xmlDoc = new ActiveXObject(\"Microsoft.XMLDOM\");\n      xmlDoc.loadXML(xml);\n      xml = xmlDoc;\n    }\n    return xml;\n}\n\n\nfunction load_dashboard_data(){\n  $(\"#load_dashboard\").hide();\n  $(\"#loading\").hide();\n\n  get_local_data();\n  // if (local_R == null){\n  //   local_R = [];\n  // }\n\n  if (local_D != null){\n    data_ready(local_D,'all');\n    // if (credits_enabled){\n    //   retros_ready(local_R);\n    //   load_retros();\n    // }\n    ISSUE_COUNT = -1; //we are loading from local data, so we set the counter past 10 to refresh moved items\n    timer_active = true;\n    new_dash_data();\n    local_D = null;\n    // local_R = null;\n  }\n  else{\n    D = [];\n    R = [];\n    keyboard_shortcuts = false;\n\n    ISSUE_COUNT = 0;\n\n    load_dashboard_data_for_statuses('10,11','new');\n    load_dashboard_data_for_statuses('1,6','open');\n    load_dashboard_data_for_statuses('4','inprogress');\n    load_dashboard_data_for_statuses('8,14,13','done');\n    load_dashboard_data_for_statuses('9','canceled');\n    // load_dashboard_data_for_statuses('12','archived');\n  }\n\n  ok_to_save_local_data = true;\n\n}\n\nfunction refresh_local_data(){\n  $(\"#loading_error\").hide();\n  timer_active = false;\n  disable_refresh_button();\n  clear_filters();\n  try{\n  store.set('D_' + projectId, null);\n  store.set('R_' + projectId, null);\n  store.set('lata_data_pull_' + projectId, null);\n  }\n  catch(err){\n    return;\n  }\n  wipe_panels();\n  display_panels();\n  recalculate_widths();\n  load_dashboard_data();\n  // enable_refresh_button();\n\n}\n\nfunction save_local_data(){\n  if (ok_to_save_local_data == false) {return false;}\n\n  try{\n\n    store.set('D_' + projectId,JSON.stringify(D));\n    store.set('R_' + projectId,JSON.stringify(R));\n    store.set('last_data_pull_' + projectId,last_data_pull);\n    store.set('includes_sub_workstreams' + projectId, ($('#include_subworkstreams_checkbox').attr(\"checked\") == true));\n    return true;\n  }\n  catch(err){\n    return false;\n  }\n}\n\nfunction get_local_data(){\n  try{\n\n    includes_subs = store.get('includes_sub_workstreams' + projectId);\n\n    //don't use local data if stored includes subs but requested data doesn't, or vise versa\n    if (includes_subs != String($('#include_subworkstreams_checkbox').attr(\"checked\") == true)){\n      return false;\n    }\n\n    local_D = JSON.parse(store.get('D_' + projectId));\n\n    if (local_D == null) {return false;}\n\n    // local_R = JSON.parse(store.get('R_' + projectId));\n    // if (local_R == null) {local_R = [];}\n\n    last_data_pull = new Date(store.get('last_data_pull_' + projectId));\n\n    //refresh local data since latest code update that require data structure to be updated\n    if (Date.parse(LAST_LOCAL_DB_CHANGE) > last_data_pull){\n      return false;\n    }\n    else{\n      return true;\n    }\n  }\n  catch(err){\n    return false;\n  }\n}\n\nfunction load_dashboard_data_for_statuses(status_ids,name){\n  var url = url_for({ controller: 'projects',\n                             action    : 'dashdata',\n                id    : projectId\n                            });\n\n\n  // var url = url + '?status_ids=1,4,6,8,10,11,13,14';\n  url = url + '?status_ids=' + status_ids;\n\n  if ($('#include_subworkstreams_checkbox').attr(\"checked\") == true){\n    url = url + \"&include_subworkstreams=true\";\n  }\n\n\n  $.ajax({\n     type: \"GET\",\n     dataType: \"json\",\n     contentType: \"application/json\",\n     cache:false,\n    data:{},\n     // dataType: ($.browser.msie) ? \"text\" : \"json\",\n     url: url,\n     success:    function(html){\n      last_data_pull = new Date();\n      ISSUE_COUNT = ISSUE_COUNT + html.length;\n      data_ready(html,name);\n    },\n     error:   function (xhr, textStatus, errorThrown) {\n    // alert(xhr.status);\n    // typically only one of textStatus or errorThrown will have info\n    // possible valuees for textstatus \"timeout\", \"error\", \"notmodified\" and \"parsererror\n    $(\"#loading\").hide();\n    $(\"#loading_error\").show();\n    },\n    timeout: 30000 //30 seconds\n   });\n}\n\n\n\n// listens for any navigation keypress activity\n// $(document).keypress(function(e)\n// {\n//   if (!keyboard_shortcuts){return;};\n//\n//   switch(e.which)\n//   {\n//     // user presses the \"a\"\n//     case 110:  new_item();\n//           break;\n//\n//   }\n// });\n\nfunction data_ready(html,name){\n  last_item = D.length;\n  D = D.concat(html);\n  add_items_to_panels(last_item);\n  sort_panels();\n  if (name == 'all'){\n    $('#new_close').addClass('closePanel').removeClass('closePanelLoading');\n    $('#open_close').addClass('closePanel').removeClass('closePanelLoading');\n    $('#inprogress_close').addClass('closePanel').removeClass('closePanelLoading');\n    $('#done_close').addClass('closePanel').removeClass('closePanelLoading');\n    loaded_panels = 6;\n    enable_refresh_button();\n    timer_active = true;\n  }\n  else{\n    $('#' + name + '_close').addClass('closePanel').removeClass('closePanelLoading');\n    loaded_panels = loaded_panels + 1;\n  }\n  update_panel_counts();\n  prepare_item_lookup_array(); //TODO: move this somewhere else for efficiency. it should only run once\n  // if (loaded_panels == 4 && credits_enabled){\n  //   load_retros();\n  //   timer_active = true;\n  // }\n  if (loaded_panels == 4){\n    enable_refresh_button();\n    timer_active = true;\n  }\n}\n\nfunction replace_reloading_images_for_panels(){\n  $('.closePanelLoading').addClass('closePanel').removeClass('closePanelLoading');\n}\n\n\n// function load_retros(){\n//\n//     if (!credits_enabled){\n//       return false;\n//     }\n//     var url = url_for({ controller: 'projects',\n//                 id    : projectId\n//                                 });\n//     url = url + '/retros/index_json';\n//\n//     $.ajax({\n//        type: \"GET\",\n//        dataType: \"json\",\n//        contentType: \"application/json\",\n//        url: url,\n//        success:    function(html){\n//         retros_ready(html);\n//         enable_refresh_button();\n//       },\n//        error:   function (XMLHttpRequest, textStatus, errorThrown) {\n//       // typically only one of textStatus or errorThrown will have info\n//       // possible valuees for textstatus \"timeout\", \"error\", \"notmodified\" and \"parsererror\n//       $(\"#loading\").hide();\n//       $(\"#loading_error\").show();\n//       enable_refresh_button();\n//       },\n//       timeout: 30000 //30 seconds\n//      });\n//     return true;\n// }\n//\nfunction enable_refresh_button(){\n  $('#refresh_data').show();\n}\n\nfunction disable_refresh_button(){\n  $('#refresh_data').hide();\n}\n\nfunction retros_ready(html,load_remaining_panels){\n  R = html;\n  insert_retros();\n}\n\nfunction insert_retros(){\n  $('.retrospective').remove();\n  for(var i = 0; i < R.length; i++ ){\n    add_retro(i,\"top\",false);\n  }\n}\n\nfunction add_retro(rdataId,position,scroll){\n  var html = generate_retro(rdataId);\n  var panelid = 'done';\n  if (position==\"bottom\")\n  {\n    $(\"#\" + panelid + '_end_of_list').append(html);\n  }\n  else if (position==\"top\")\n  {\n    $(\"#\" + panelid+ '_end_of_list').prepend(html);\n  }\n\n  if (scroll)\n  {\n    $(\"#\" + panelid + \"_items\").scrollTo('#item_' + dataId, 100);\n  }\n}\n\n//makes all text boxes sensitive to keyboard shortcuts\nfunction make_text_boxes_toggle_keyboard_shortcuts(){\n  $(\"input\").keyboard_sensitive();\n  $(\"textarea\").keyboard_sensitive();\n}\n\n\n// function load_search(){\n//   html = '';\n//\n//   html = html + '  <table class=\"searchField\">';\n//   html = html + '  <tbody>';\n//   html = html + '  <tr>';\n//   html = html + '  <td>';\n//   html = html + '  <a onclick=\"$(\\'searchString\\').focus(); return false;\" href=\"#\">';\n//   html = html + '  <img src=\"/images/search_left.png\" alt=\"Search\" title=\"\"/>';\n//   html = html + '  </a>';\n//   html = html + '  </td>';\n//   html = html + '  <td class=\"field\">';\n//   html = html + '  <input id=\"searchString\" type=\"text\" autocomplete=\"off\" size=\"20\" name=\"searchString\" value=\"\"/>';\n//   html = html + '  </td>';\n//   html = html + '  <td style=\"vertical-align:top;\">';\n//   html = html + '  <img src=\"/images/search_right.png\"/>';\n//   html = html + '  </td>';\n//   html = html + '  </tr>';\n//   html = html + '  </tbody>';\n//   html = html + '  </table>';\n//\n//   $('#header').append(html);\n// }\n\n\nfunction prepare_page(){\n  display_panels();\n  resize();\n  recalculate_widths();\n  keyboard_shortcuts = true;\n  make_text_boxes_toggle_keyboard_shortcuts();\n}\n\nfunction start_timer(){\n  if (timer_started == true){\n    return;\n  }\n  else{\n    timer_started = true;\n  }\n\n  $.timer(TIMER_INTERVAL, function (timer) {\n    timer_beat(timer);\n  });\n}\n\nfunction stop_timer(timer){\n  timer_started = false;\n  timer.stop();\n}\n\nfunction prepare_item_lookup_array(){\n  for (var i=0; i<D.length;i++){\n    ITEMHASH[\"item\" + String(D[i].id)] = i;\n  }\n}\n\n\n// Loads all items in their perspective panels, and sets up panels\nfunction display_panels(){\n  loaded_panels = 0;\n  insert_panel(0,'new','Open',true);\n  add_new_link();\n  // insert_panel(0,'estimate','In Estimation',true);\n  // insert_panel(0,'open','Open',true);\n  insert_panel(0,'inprogress','In Progress',true);\n  insert_panel(0,'done','Done',false);\n  insert_panel(0,'canceled','Canceled',false);\n  // insert_panel(0,'archived','Archived',false);\n}\n\nfunction wipe_panels(){\n  $('.panel').remove();\n  $('.dashboard-button-panel').remove();\n}\n\nfunction sort_panels(){\n  // sort_panel('open');\n  sort_panel('new');\n  sort_panel('inprogress');\n}\n\nfunction add_items_to_panels(last_item){\n  for(var i = last_item; i < D.length; i++ ){\n      add_item(i,\"bottom\",false);\n  }\n\n  adjust_button_container_widths();\n\n}\n\nfunction adjust_button_container_widths(){\n\n  if (jQuery.browser.msie) {\n\n    $.each($('.itemCollapsedButtons'), function(){\n\n    var $sum = 0;\n\n    $(this).children().each(function()\n    {\n      if ($(this).is(\":visible\")){\n         $sum += $(this).outerWidth();\n      }\n    });\n\n    $(this).width($sum);\n\n    });\n  }\n}\n\n//Called after data is ready for a retrospective\nfunction rdata_ready(html,rdataId){\n  var retro = R[rdataId];\n  var panelid = 'retro_' + retro.id;\n  var i = D.length;\n\n  $('#' + panelid + '_close').addClass('closePanel').removeClass('closePanelLoading');\n\n  D = D.concat(html);\n  if (retro.status_id == 1){\n    var notice = generate_notice('<a class=\"date_label\" title=\"Retrospective is now open\" href=\"#\" onclick=\"click_retro(' + i +',this.id);return false;\">Retrospective is open &rArr;</a>', rdataId);\n    $('#retro_' + retro.id + '_items').prepend(notice);\n  }\n  for(; i < D.length; i++ ){\n    add_item(i,\"bottom\",false,panelid);\n  }\n  update_panel_count(panelid,true);\n}\n\n\nfunction show_item_fancybox(dataId){\n  var itemId = D[dataId].id;\n  var url = url_for({ controller: 'issues',\n                             action    : 'show',\n                id    : itemId\n                            });\n\n    url = url + '?dataId=' + dataId;\n\n\n  show_fancybox(url,'loading data...');\n}\n\nfunction show_details_flyover(dataId,callingElement,delayshow){\n\n  $('#flyover_' + dataId).remove();\n  generate_details_flyover(dataId);\n\n  $('#' + callingElement).bubbletip($('#flyover_' + dataId), {\n    deltaDirection: 'right',\n    delayShow: delayshow,\n    delayHide: 100,\n    offsetLeft: 0\n  });\n}\n\nfunction show_estimate_flyover(dataId,callingElement){\n  $('#flyover_estimate_' + dataId).remove();\n  generate_estimate_flyover(dataId);\n\n  $('#' + callingElement).bubbletip($('#flyover_estimate_' + dataId), {\n    deltaDirection: 'right',\n    delayShow: 0,\n    delayHide: 100,\n    offsetLeft: 0\n  });\n}\n\nfunction show_points_flyover(dataId,callingElement){\n  $('#flyover_points_' + dataId).remove();\n  generate_points_flyover(dataId);\n\n  $('#' + callingElement).bubbletip($('#flyover_points_' + dataId), {\n    deltaDirection: 'right',\n    delayShow: 0,\n    delayHide: 100,\n    offsetLeft: 0\n  });\n}\n\nfunction hide_bubbletips(){\n  $('.bubbletip').hide();\n}\n\n\nfunction show_pri_flyover(dataId,callingElement){\n\n  $('#flyover_pri_' + dataId).remove();\n  generate_pri_flyover(dataId);\n\n  $('#' + callingElement).bubbletip($('#flyover_pri_' + dataId), {\n    deltaDirection: 'right',\n    delayShow: 0,\n    delayHide: 100,\n    offsetLeft: 0\n  });\n}\n\nfunction show_agree_flyover(dataId,callingElement){\n\n  $('#flyover_agree_' + dataId).remove();\n  generate_agree_flyover(dataId);\n\n  $('#' + callingElement).bubbletip($('#flyover_agree_' + dataId), {\n    deltaDirection: 'right',\n    delayShow: 0,\n    delayHide: 100,\n    offsetLeft: 0\n  });\n}\n\nfunction show_accept_flyover(dataId,callingElement){\n\n  $('#flyover_accept_' + dataId).remove();\n  generate_accept_flyover(dataId);\n\n  //If flyover hasn't already been generated, then generate it!\n  // if ($('#flyover_accept_' + dataId).length == 0){\n  //   generate_accept_flyover(dataId);\n  // }\n\n  $('#' + callingElement).bubbletip($('#flyover_accept_' + dataId), {\n    deltaDirection: 'right',\n    delayShow: 0,\n    delayHide: 100,\n    offsetLeft: 0\n  });\n}\n\nfunction is_visible(item){\n  if (item == null) {return false;}\n\n  return true;\n}\n\nfunction is_startable(item){\n  if (item.status.name == \"Open\"){\n    return true;\n    // return ((item.pri > (highest_pri - startable_priority_tiers))||(item.pri == 0));\n  }\n  else{\n    return false;\n  }\n}\n\nfunction add_item(dataId,position,scroll,panelid){\n\n  if (!is_visible(D[dataId])) {return;}\n\n  if (!panelid){\n    //Deciding on wich panel for this item?\n    switch (D[dataId].status.name){\n    case 'New':\n    panelid= 'new';\n    break;\n    case 'Estimate':\n    panelid= 'new';\n    break;\n    case 'Open':\n    panelid= 'new';\n    break;\n    case 'Committed':\n    panelid = 'inprogress';\n    break;\n    case 'Done':\n    panelid = 'done';\n    break;\n    case 'Accepted':\n    panelid = 'done';\n    break;\n    case 'Rejected':\n    panelid = 'done';\n    break;\n    case 'Canceled':\n    panelid = 'canceled';\n    break;\n    case 'Archived':\n    panelid = 'canceled';\n    break;\n    default : panelid = 'canceled';\n    }\n  }\n\n\n  var html = generate_item(dataId);\n  if (position==\"bottom\")\n  {\n    $(\"#\" + panelid + '_start_of_list').append(html);\n  }\n  else if (position==\"top\")\n  {\n    $(\"#\" + panelid+ '_start_of_list').prepend(html);\n  }\n  // else if (position==\"pri\"){\n  //   $(\"#\" + panelid + \"_items\").children.each()\n  // }\n\n  if (scroll)\n  {\n    $(\"#\" + panelid + \"_items\").scrollTo('#item_' + dataId, 100);\n  }\n\n}\n\nfunction generate_estimate_flyover(dataId){\n  var item = D[dataId];\n  var i = 0; //counter\n  var credits = item.points;\n\n  var you_voted = \"You haven't estimated yet\";\n  var title = '';\n  var user_estimate = -100;\n  var total_people_estimating = 0;\n\n  for(i=0; i < item.issue_votes.length; i++){\n    if (item.issue_votes[i].vote_type != 4) continue;\n    total_people_estimating++ ;\n\n    if (currentUserLogin == item.issue_votes[i].user.login){\n\n      var user_estimate_text = \"\";\n      if (item.issue_votes[i].points == -1){\n        user_estimate = item.issue_votes[i].points;\n        user_estimate_text = \"Don't know\";\n      }\n      else if (credits_enabled){\n        user_estimate = item.issue_votes[i].points;\n        user_estimate_text = user_estimate + \" credits\";\n      }\n      else{\n        user_estimate = convert_points_to_complexity(item.issue_votes[i].points);\n        user_estimate_text = user_estimate;\n      }\n\n      you_voted = \"Your estimate \" + user_estimate_text + \" - \" + humane_date(item.issue_votes[i].updated_at);\n    }\n  }\n\n  //If user estimated, or item is in progress, we can see the average\n  if (((item.status.name != 'New')&&(item.status.name != 'Estimate')&&(item.status.name != 'Open')) || (user_estimate != -100)){\n    if (credits == null){\n      title = 'No binding estimates yet';\n    }\n    else if (credits_enabled){\n      title = 'Avg ' + Math.round(credits) + ' credits (' + total_people_estimating + ' people)';\n    }\n    else{\n      title = 'Avg ' + credits_to_points(Math.round(credits),credit_base) + ' points (' + total_people_estimating + ' people)';\n    }\n  }\n  else{\n    title = \"Vote to see Estimates\";\n  }\n\n  var history = '';\n  //Show history if user estimated, or if item is no longer available for estimation\n  if ((user_estimate != -100)||((item.status.name != 'New')&&(item.status.name != 'Estimate')&&(item.status.name != 'Open'))){\n    for(i = 0; i < item.issue_votes.length; i++ ){\n      if (item.issue_votes[i].vote_type != 4) continue;\n\n      if (item.issue_votes[i].points == -1){\n        history = history + 'Don\\'t know - ' + item.issue_votes[i].user.firstname + ' ' + item.issue_votes[i].user.lastname;\n      }\n      else if (credits_enabled){\n        history = history + item.issue_votes[i].points + ' cr - ' + item.issue_votes[i].user.firstname + ' ' + item.issue_votes[i].user.lastname;\n      }\n      else{\n        history = history + credits_to_points(Math.round(item.issue_votes[i].points),credit_base) + ' points - ' + item.issue_votes[i].user.firstname + ' ' + item.issue_votes[i].user.lastname;\n      }\n\n      if (item.issue_votes[i].isbinding == false){\n        history = history + ' (non-binding)';\n      }\n      history = history + '<br>';\n    }\n\n  }\n\n  var action_header = '';\n  var buttons = '';\n\n  // if (((item.status.name != 'New')&&(item.status.name != 'Estimate')&&(item.status.name != 'Open'))) {\n    user_estimate == -100 ? action_header = 'Make an estimate' : action_header = 'Change your estimate';\n\n    buttons = buttons + generate_estimate_button(-1,-1, item.id, dataId, (user_estimate != -100));\n\n    for(i = 0; i < point_factor.length; i++ ){\n      buttons = buttons + generate_estimate_button(i,point_factor[i] * credit_base, item.id, dataId, (user_estimate != -100));\n    }\n    buttons = buttons + generate_custom_estimate_button(dataId,user_estimate);\n  // }\n\n  return generate_flyover(dataId,'estimate',title,you_voted,action_header,buttons,history);\n\n}\n\nfunction generate_points_flyover(dataId){\n  var item = D[dataId];\n  var i = 0; //counter\n  var credits = item.points;\n\n  var you_voted = \"This is a read only value, and cannot be voted on.\";\n\n  var  title = item.points + ' credits';\n\n  var history = '';\n\n  var action_header = '';\n  var buttons = '';\n\n  return generate_flyover(dataId,'points',title,you_voted,action_header,buttons,history);\n\n}\n\n\nfunction prompt_for_number(message,default_data){\n  var amount=prompt(message,default_data);\n  if (amount == null || amount == '' || (!isNumeric(amount))) {\n    return prompt_for_number(message,default_data);\n  }\n\n  else\n  {\n    return amount;\n  }\n}\n\n\nfunction prompt_for_custom_estimate(dataId,points){\n  var amount = prompt_for_number(\"Please enter expense amount in dollars:\",points);\n  send_item_action(dataId,'estimate','&points=' + amount);\n}\n\n\n\nfunction generate_custom_estimate_button(dataId,user_estimate){\n  if (!credits_enabled){\n    return '';\n  }\n\n  var points = 0;\n  if (user_estimate > -1){\n    points = user_estimate;\n  }\n\n  var html = '<div>';\n  html = html + '<img src=\"/images/dice_No.png\" width=\"18\" height=\"18\" alt=\"Custom Credits\" class=\"dice\" onclick=\"prompt_for_custom_estimate(' + dataId + ',' + points + ')\">';\n  html = html + ' custom amount';\n  html = html + '</div>';\n  return html;\n}\n\nfunction convert_points_to_complexity(points){\n  if (points == -1){\n    return \"Don't know\";\n  }\n\n  if (points > complexity_description.length - 1){\n    points = complexity_description.length - 1;\n  }\n  return complexity_description[points];\n}\n\n\nfunction generate_estimate_button(points,credits, itemId, dataId, comment){\n  var label = '';\n  if (credits == -1){\n    label = \"Don't know\";\n  }\n  else if (credits_enabled){\n    label = credits + ' Credits';\n  }\n  else{\n    label = convert_points_to_complexity(points);\n  }\n  var html = '<div>';\n  var onclick = 'click_estimate_from_flyover(' + dataId + ',this,\\'' + '&points=' + credits + '\\',' + comment + ');return false;';\n\n  html = html + '<img src=\"/images/dice_' + Math.round(points) + '.png\" width=\"18\" height=\"18\" alt=\"' + label + '\" class=\"dice\" onclick=\"' + onclick + '\">';\n\n\n  html = html + ' ' + label;\n  html = html + '</div>';\n  return html;\n}\n\nfunction generate_pri_action(points, itemId, dataId){\n  var html = '<div id=\"item_flyover_pri_button_' + dataId + '\" class=\"clickable pri_button pri_button_action pri_button_' + pri_text(points).toLowerCase() + '\" onclick=\"click_pri(' + dataId + ',this,' + points + ');return false;\">' + pri_text(points) + '</div>';\n  return html;\n}\n\nfunction pri_text(points){\n  switch (points){\n  case 0:\n    return \"NEUTRAL\";\n    break;\n  case 1:\n    return \"UP\";\n    break;\n  case -1:\n    return \"DOWN\";\n    break;\n  }\n  return \"ERROR: OUT OF RANGE\";\n}\n\nfunction agree_text(points){\n  switch (points){\n  case 0:\n    return \"NEUTRAL\";\n    break;\n  case 1:\n    return \"AGREE\";\n    break;\n  case -1:\n    return \"DISAGREE\";\n    break;\n  case -9999:\n    return \"BLOCK\";\n    break;\n  }\n  return \"ERROR: OUT OF RANGE\";\n}\n\nfunction accept_text(points){\n  switch (points){\n  case 0:\n    return \"NEUTRAL\";\n    break;\n  case 1:\n    return \"ACCEPT\";\n    break;\n  case -1:\n    return \"REJECT\";\n    break;\n  case -9999:\n    return \"BLOCK\";\n    break;\n  }\n  return \"ERROR: OUT OF RANGE\";\n}\n\nfunction generate_pri_flyover(dataId){\n  var item = D[dataId];\n\n  var points;\n  item.pri == null ? points = 0 : points = item.pri;\n\n  var you_voted = '';\n  var user_pri_id = 0;\n  var total_people_prioritizing = 0;\n  var i = 0; //counter variable\n\n  for(i=0; i < item.issue_votes.length; i++){\n    if (currentUserLogin == item.issue_votes[i].user.login){\n      if (item.issue_votes[i].vote_type != 3) continue;\n      total_people_prioritizing++ ;\n      you_voted = \"You prioritized \" + pri_text(item.issue_votes[i].points) + \" - \" + humane_date(item.issue_votes[i].updated_at);\n      user_pri_id = item.issue_votes[i].id;\n    }\n  }\n\n  if (user_pri_id == 0){\n    you_voted = \"You haven't prioritized this item\";\n  }\n\n  var title = 'Total ' + points + ' points (' + total_people_prioritizing + ' people)';\n  var action_header = '';\n  user_pri_id == 0 ? action_header = 'Prioritize' : action_header = 'Change your prioritization:';\n\n  var buttons = '';\n  buttons = buttons + generate_pri_action(1, item.id, dataId) + '<br>';\n  buttons = buttons + generate_pri_action(0, item.id, dataId) + '<br>';\n  buttons = buttons + generate_pri_action(-1, item.id, dataId);\n\n\n  var history = '';\n  if (!(item.issue_votes == null || item.issue_votes.length < 1)){\n    for(i = 0; i < item.issue_votes.length; i++ ){\n      if (item.issue_votes[i].vote_type != 3) continue;\n      history = history + pri_text(item.issue_votes[i].points) + ' - ' + item.issue_votes[i].user.firstname + ' ' + item.issue_votes[i].user.lastname;\n      if (item.issue_votes[i].isbinding == false){\n        history = history + ' (non-binding)';\n      }\n      history = history + '<br>';\n    }\n  }\n\n\n\n  return generate_flyover(dataId,'pri',title,you_voted,action_header,buttons,history);\n}\n\n\nfunction generate_flyover(dataId,type,title,you_voted,action_header,buttons,history){\n  var html = '';\n\n  html = html + '<div id=\"flyover_' + type + '_' + dataId + '\" class=\"overlay\" style=\"display:none;\">';\n  html = html + '    <div style=\"border: 0pt none ; margin: 0pt;\">';\n  html = html + '      <div class=\"overlayContentWrapper gt-Sfo flyover\" style=\"width: 200px;\">';\n  html = html + '        <div class=\"storyTitle\">';\n  html = html + title;\n  html = html + '        </div>';\n  html = html + '        <div class=\"sectionDivider\">';\n  html = html + '        <div style=\"height: auto;\">';\n  html = html + '          <div class=\"metaInfo\">';\n  html = html + '            <div class=\"left\">';\n  html = html + you_voted;\n  html = html + '            </div>';\n  html = html + '            <div class=\"clear\"></div>';\n  html = html + '          </div>';\n  html = html + '          <div class=\"gt-Ifc gt-Sd\">';\n  html = html + '              <div class=\"section\">';\n  html = html + '                  <div class=\"header\">';\n  html = html + action_header;\n  html = html + '                  </div>';\n  html = html + '                  <table class=\"buttonsTable\">';\n  html = html + '                    <tbody>';\n  html = html + '                      <tr class=\"buttonsTextRow\">';\n  html = html + '                        <td class=\"buttonsText\">';\n  html = html + buttons;\n  html = html + '                        </td>';\n  html = html + '                      </tr>';\n  html = html + '                    </tbody>';\n  html = html + '                  </table>';\n\n  if (history != ''){\n    html = html + '    <div class=\"header\">';\n    html = html + '      History';\n    html = html + '    </div>';\n    html = html + '    <table class=\"notesTable\">';\n    html = html + '      <tbody>';\n    html = html + '<tr class=\"noteInfoRow\">';\n    html = html + '<td class=\"noteInfo\">';\n    html = html + history;\n     html = html + '</td>';\n      html = html + '</tr>';\n    html = html + '      </tbody>';\n    html = html + '    </table>';\n    html = html + '  <div class=\"clear\"></div>';\n    html = html + '                </div>';\n  }\n\n  html = html + '          </div>';\n  html = html + '        </div>';\n  html = html + '      </div>';\n  html = html + '    </div>';\n  html = html + '  </div>';\n\n  $('#flyovers').append(html);\n\n  return html;\n}\n\nfunction generate_agree_flyover(dataId){\n  var item = D[dataId];\n\n  var agree_total;\n  item.agree_total == null ? agree_total = 0 : agree_total = item.agree_total;\n\n  var you_voted = '';\n  var user_agree_id = -1;\n  var total_people_agreeing = 0;\n  var i = 0; //counter variable\n\n  for(i=0; i < item.issue_votes.length; i++){\n    if (currentUserLogin == item.issue_votes[i].user.login){\n      if (item.issue_votes[i].vote_type != 1) continue;\n      total_people_agreeing++ ;\n      title = \"You voted: \" + agree_text(item.issue_votes[i].points);// + \" - \" + humane_date(item.issue_votes[i].updated_at);\n      user_agree_id = i;\n    }\n  }\n\n  if (user_agree_id == -1){\n    title = \"You haven't voted yet\";\n    you_voted = \"Details are hidden until you vote to avoid group think\";\n  }\n  else {\n    you_voted = item.agree + ' agree / ' + item.disagree + ' disagree (binding)<br>';\n    you_voted = you_voted + item.agree_nonbind + ' agree / ' + item.disagree_nonbind + ' disagree (non-binding)<br>';\n  }\n\n  var history = '';\n  var action_header = '';\n  var buttons = '';\n  var points = 999;\n\n  http://bettermeans.com/front/?page_id=318\n  if (user_agree_id > -1){\n    points = item.issue_votes[user_agree_id].points;\n\n    for(i = 0; i < item.issue_votes.length; i++ ){\n      if (item.issue_votes[i].vote_type != 1) continue;\n      history = history + agree_text(item.issue_votes[i].points) + ' - ' + item.issue_votes[i].user.firstname + ' ' + item.issue_votes[i].user.lastname;\n      if (item.issue_votes[i].isbinding == false){\n        history = history + ' (non-binding)';\n      }\n      history = history + '<br>';\n    }\n  }\n\n\n  if (!((item.status.name != 'New')&&(item.status.name != 'Estimate')&&(item.status.name != 'Open'))) {\n    user_agree_id < 0 ? action_header = 'Vote' : action_header = 'Change your vote:';\n    if (points != 1) {buttons = buttons + dash_button('agree',dataId,points == 1,{action:'agree',data:'&points=1'}) + '<br>';}\n    if (points != 0) {buttons = buttons + dash_button('neutral',dataId,points == 0,{action:'agree',data:'&points=0'}) + '<br>';}\n    if (points != -1) {buttons = buttons + dash_button('disagree',dataId,points == -1,{action:'agree',data:'&points=-1'}) + '<br>';}\n    if (points != -9999) {buttons = buttons + dash_button('block',dataId,false,{action:'agree',data:'&points=-9999'}) + '<br>';}\n  }\n\n  return generate_flyover(dataId,'agree',title,you_voted,action_header,buttons,history);\n}\n\nfunction generate_accept_flyover(dataId){\n  var item = D[dataId];\n\n  var accept_total;\n  item.accept_total == null ? accept_total = 0 : accept_total = item.accept_total;\n\n  var you_voted = '';\n  var user_accept_id = -1;\n  var total_people_accepting = 0;\n  var i = 0;\n\n  for(i=0; i < item.issue_votes.length; i++){\n    if (currentUserLogin == item.issue_votes[i].user.login){\n      if (item.issue_votes[i].vote_type != 2) continue;\n      total_people_accepting++ ;\n      title = \"You voted: \" + accept_text(item.issue_votes[i].points);// + \" - \" + humane_date(item.issue_votes[i].updated_at);\n      user_accept_id = i;\n    }\n  }\n\n  if (user_accept_id == -1){\n    title = \"You haven't voted yet\";\n    you_voted = \"Totals are hidden until you vote\";\n  }\n  else {\n    you_voted = item.accept + ' accept / ' + item.reject + ' reject (binding)<br>';\n    you_voted = you_voted + item.accept_nonbind + ' accept / ' + item.reject_nonbind + ' reject (non-binding)<br>';\n  }\n\n  var history = '';\n  var action_header = '';\n  var buttons = '';\n  var points = 999;\n\n\n  if (user_accept_id > -1){\n    points = item.issue_votes[user_accept_id].points;\n\n    for(i = 0; i < item.issue_votes.length; i++ ){\n      if (item.issue_votes[i].vote_type != 2) continue;\n      history = history + accept_text(item.issue_votes[i].points) + ' - ' + item.issue_votes[i].user.firstname + ' ' + item.issue_votes[i].user.lastname;\n      if (item.issue_votes[i].isbinding == false){\n        history = history + ' (non-binding)';\n      }\n      history = history + '<br>';\n    }\n  }\n\n  if (item.status.name == 'Done') {\n    user_accept_id < 0 ? action_header = 'Vote' : action_header = 'Change your vote:';\n    if (points != 1) {buttons = buttons + dash_button('accept',dataId,points == 1,{action:'accept',data:'&points=1'}) + '<br>';}\n    if (points != 0) {buttons = buttons + dash_button('neutral',dataId,points == 0,{action:'accept',data:'&points=0'}) + '<br>';}\n    if (points != -1) {buttons = buttons + dash_button('reject',dataId,points == -1,{action:'accept',data:'&points=-1'}) + '<br>';}\n    if (points != -9999) {buttons = buttons + dash_button('block',dataId,false,{action:'accept',data:'&points=-9999'}) + '<br>';}\n  }\n\n  return generate_flyover(dataId,'accept',title,you_voted,action_header,buttons,history);\n}\n\n\nfunction generate_details_flyover_description(item){\n\n  if (item.description == null || item.description.length < 3){return '';};\n\n  var html = '';\n  html = html + '    <div class=\"header\">';\n  html = html + '      Description';\n  html = html + '    </div>';\n  html = html + '    <table class=\"notesTable\">';\n  html = html + '      <tbody>';\n  html = html + '<tr class=\"noteInfoRow\">';\n  html = html + '<td class=\"noteInfo\">';\n  html = html + '<span class=\"specialhighlight\">' + h(item.description).replace(/\\n/g,\"<br>\") + '</span>';\n   html = html + '</td>';\n    html = html + '</tr>';\n  html = html + '      </tbody>';\n  html = html + '    </table>';\n  html = html + '  <div class=\"clear\"></div>';\n  return html;\n\n}\n\nfunction generate_comments_section(dataId){\n  var html = '            <div class=\"section\" id=\"comments_container_' + dataId + '\">';\n  html = html + '              <table class=\"storyDescriptionTable\">';\n  html = html + '                <tbody>';\n  html = html + '                  <tr>';\n  html = html + generate_comments(dataId,false);\n  html = html + '                  </tr>';\n  html = html + '                  <tr>';\n  html = html + '                    <td colspan=\"5\">';\n  html = html + '                      <div>';\n  html = html + '                        <textarea class = \"textAreaFocus\" id=\"new_comment_' + dataId + '\" rows=\"1\" cols=\"20\" name=\"story[comment]\"></textarea>     ';\n  html = html + '                      <div>';\n  html = html + '                      <input value=\"Post Comment\" type=\"submit\" id=\"post_comment_button_' + dataId + '\" onclick=\"post_comment(' + dataId + '); return false;\">';\n  html = html + '                          (Format using *<b>bold</b>* and _<i>italic</i>_ text.)';\n  html = html + '                        </div>';\n  html = html + '                      </div>';\n  html = html + '                    </td>';\n  html = html + '                  </tr>';\n  html = html + '                </tbody>';\n  html = html + '              </table>';\n  html = html + '            </div>';\n  return html;\n}\n\n//blank_if_no_comments: when true, nothing is returned if there aren't any comments, when false the header is returned\nfunction generate_comments(dataId,blank_if_no_comments){\n  var item = D[dataId];\n  var count = 0;\n  for(var k = 0; k < item.journals.length; k++ ){\n      if (item.journals[k].notes != '' && item.journals[k].notes != null){\n        count++;\n      }\n  }\n\n  if (count==0 && blank_if_no_comments){return '';};\n\n  var html = '';\n  html = html + '    <div class=\"header\">';\n  html = html + '      Comments <span id=\"comment_' + item.id  + '_count\" class=\"commentCount\">(' + count + ')</span>';\n  html = html + '    </div>';\n  html = html + '    <table class=\"notesTable\" id=\"notesTable_' + item.id + '\">';\n  html = html + '      <tbody>';\n\n  for(var i = 0; i < item.journals.length; i++ ){\n      if (item.journals[i].notes != '' && item.journals[i].notes != null){\n        var author = item.journals[i].user.firstname + ' ' + item.journals[i].user.lastname;\n        var note = '';\n        if (item.journals[i].notes.indexOf('wrote:') > -1)\n        {\n          var note_array = item.journals[i].notes.split('\\n');\n          for(var j = 1; j < note_array.length; j++ ){\n            if (note_array[j][0]!='>'){note = note + note_array[j].replace(/\\n/g,\"<br>\") + '\\n';};\n          }\n        }\n        else\n        {\n          note = item.journals[i].notes;\n        }\n        var last_comment = (i == (item.journals.length - 1));\n        html = html + generate_comment(author,note,item.journals[i].created_at,item.id, (last_comment &&(currentUserId == item.journals[i].user_id)), item.journals[i].id,dataId);\n      }\n  }\n  html = html + '      </tbody>';\n  html = html + '    </table>';\n  html = html + '  <div class=\"clear\"></div>';\n  return html;\n\n}\n\nfunction generate_comment(author,note,created_at,itemId,last_comment,journalId,dataId){\n  var html = '';\n  html = html + '<tr class=\"noteInfoRow\">';\n  html = html + '<td class=\"noteInfo\" id=\"noteInfo_' + journalId + '\">';\n  html = html + '<span class=\"specialhighlight\">' + author + '</span> <span class=\"italic\">' + humane_date(created_at) + '</span>';\n  if (last_comment){\n    html = html + '&nbsp;&nbsp;<a href=\"\" onclick=\"edit_comment(' + journalId + ',' + dataId + ');return false;\">edit</a>';\n  }\n  html = html + '</td>';\n  html = html + '</tr>';\n    html = html + '<tr class=\"noteTextRow\">';\n  html = html + '<td class=\"noteText\" id=\"noteText_' + journalId + '\">';\n  html = html + '  <span id=\"comment_' + journalId + '_text_container\">' + h(note).replace(/\\r\\n/g,\"<br>\").replace(/\\n/g,\"<br>\") + '</span>';\n  html = html + '  <span id=\"comment_' + journalId + '_subject_submit_container\"></span>';\n  html = html + '</td>';\n  html = html + '</tr>';\n  return html;\n\n}\n\n//blank_if_no_todos: when true, nothing is returned if there aren't any todos, when false the header is returned\nfunction generate_todos(dataId,blank_if_no_todos, item_editable){\n  var item = D[dataId];\n\n\n  var count = item.todos.length;\n\n  if (count==0 && blank_if_no_todos){return '';};\n\n  var html = '';\n  html = html + '<div  id=\"todo_container_' + item.id + '\">';\n  html = html + '    <div class=\"header\">';\n  html = html + '      Todos <span id=\"task_' + dataId  + '_count\" class=\"todoCount\">(' + count + ')</span>';\n  html = html + '    </div>';\n  html = html + '    <table class=\"tasksTable\" id=\"notesTable_todos_' + item.id + '\">';\n  // html = html + '      <tbody>';\n\n  var sorted = item.todos.sort(function(a, b) {\n     return (a.id < b.id) ? -1 : (a.id > b.id) ? 1 : 0;\n  });\n\n  for(var i = 0; i < sorted.length; i++ ){\n    html = html + generate_todo(sorted[i].subject,sorted[i].completed_on, sorted[i].id,sorted[i].owner_login,dataId, item_editable);\n  }\n  // html = html + '      </tbody>';\n  html = html + '    </table>';\n  html = html + '  <div class=\"clear\"></div>';\n  html = html + '    </div>';\n  return html;\n\n}\n\nfunction generate_todo(subject,completed_on,todoId,owner_login,dataId, item_editable){\n  var completed = '';\n  var checked = '';\n  var disabled = '';\n  if (completed_on != null){\n    completed = 'completed';\n    checked = ' checked=\"true\" ';\n    }\n  if (!item_editable){\n    disabled = ' disabled=\"true\" ';\n  }\n\n  var html = '';\n  html = html + '<tr class=\"task_row\" id=\"task_' + todoId  + '\"  onmouseover=\"update_todo_buttons(' + todoId + ',true)\"  onmouseout=\"update_todo_buttons(' + todoId + ',false)\">';\n  html = html + '  <td>';\n  html = html + '  <input type=\"checkbox\" value=\"\" id=\"task_' + todoId  + '_complete\" onclick=\"update_todo(' + todoId + ',' + dataId + ')\" ' + checked + disabled + '/>';\n  html = html + '  </td>';\n  html = html + '<td  id=\"task_' + todoId  + '_subject\" class=\"taskDescription ' + completed + '\">';\n  html = html + '  <span id=\"task_' + todoId + '_subject_text\">';\n  html = html + h(subject);\n  if ((owner_login != '') && (owner_login!= null)){\n    html = html + ' (' + owner_login + ')';\n  }\n  html = html + '  </span>';\n  html = html + '  <input id=\"task_' + todoId + '_subject_input\" style=\"display:none;\" value=\"' + h(subject) + '\" onblur=\"edit_todo_post('+ todoId +',' + dataId + ')\">';\n  html = html + '  <span id=\"task_' + todoId + '_subject_submit_container\"></span>';\n  html = html + '</td>';\n\n  if (item_editable){\n    html = html + '  <td>';\n    html = html + '  <a id=\"task_' + todoId  + '_edit\" href=\"javascript:void(0);\" style=\"opacity: 0;\" onclick=\"edit_todo('+ todoId +',' + dataId + ')\">';\n    html = html + '  <img src=\"/images/task_edit.png\"/>';\n    html = html + '  </a>';\n    html = html + '  </td>';\n    html = html + '  <td>';\n    html = html + '  <a id=\"task_' + todoId  + '_delete\" href=\"javascript:void(0);\" style=\"opacity: 0;\" onclick=\"delete_todo('+ todoId +',' + dataId + ')\">';\n    html = html + '  <img src=\"/images/task_delete.png\"/>';\n    html = html + '  </a>';\n    html = html + '  </td>';\n  }\n\n  html = html + '</tr>';\n  return html;\n\n}\n\nfunction edit_todo(todoId, dataId){\ntry{\n\n    var button = ' <input id=\"task_' + todoId + '_subject_submit\" style=\"display:none;\" type=\"submit\" onclick=\"edit_todo_post(' + todoId + ',' + dataId + ');return false;\">  </input>';\n    $('#task_' + todoId + '_edit').attr(\"style\",\"opacity: 0\");\n    $('#task_' + todoId + '_subject_text').hide();\n    $('#task_' + todoId + '_subject_submit_container').html(button);\n    $('#task_' + todoId + '_subject_input').show().focus();\n\n    keyboard_shortcuts = false;\n\n    return false;\n  }\ncatch(err){\n  return false;\n}\n}\n\nfunction edit_comment(journalId,dataId){\ntry{\n    var button = ' <input id=\"comment_' + journalId + '_subject_submit\" type=\"submit\" onclick=\"edit_comment_post(' + journalId + ',' + dataId + ');return false;\" value=\"done\" class=\"right\"/>';\n    var cancel_button = ' <input id=\"comment_' + journalId + '_subject_submit\" type=\"submit\" onclick=\"edit_comment_cancel(' + journalId + ',' + dataId + ');return false;\" value=\"cancel\" class=\"right\"/>';\n    var input = '<textarea id=\"comment_' + journalId + '_subject_input\" cols=\"20\" rows=\"5\"/>';\n    $('#comment_' + journalId + '_text_container').hide();\n    $('#comment_' + journalId + '_subject_submit_container').html(input + button + cancel_button);\n    $('#comment_' + journalId + '_subject_input').show().focus();\n    $('#comment_' + journalId + '_subject_input').html($('#comment_' + journalId + '_text_container').html().replace(/<br>/g, \"\\n\"));\n    keyboard_shortcuts = false;\n\n    return false;\n  }\ncatch(err){\n  return false;\n}\n}\n\nfunction edit_comment_cancel(journalId,dataId){\n  keyboard_shortcuts = true;\n  $('#comment_' + journalId + '_text_container').show();\n  $('#comment_' + journalId + '_subject_submit_container').html('');\n}\n\nfunction edit_comment_post(journalId,dataId){\ntry{\n  keyboard_shortcuts = true;\n  var new_text = $('#comment_' + journalId + '_subject_input').val(); //.replace(/<br>/g, \"\\n\");\n\n  $('#comment_' + journalId + '_text_container').html(h(new_text).replace(/\\r\\n/g,\"<br>\").replace(/\\n/g,\"<br>\")).show();\n  $('#comment_' + journalId + '_subject_submit_container').html('');\n\n  var data = \"commit=Update&id=\" + journalId + \"&issue_id=\" + D[dataId].id + \"&journal[notes]=\" + encodeURIComponent(new_text);\n\n  var url = url_for({ controller: 'journals',\n                             action    : 'edit_from_dashboard'\n                            });\n\n  $.ajax({\n     type: \"POST\",\n     dataType: \"json\",\n     url: url,\n     data: data,\n     success:   function(html){\n      comment_added(html,dataId);\n    },\n     error:   function (XMLHttpRequest, textStatus, errorThrown) {\n    handle_error(XMLHttpRequest, textStatus, errorThrown, dataId, \"post\");\n    },\n    timeout: 30000 //30 seconds\n   });\n\n  return false;\n  }\ncatch(err){\n  return false;\n}\n}\n\n\nfunction edit_todo_post(todoId, dataId){\ntry{\n\n  keyboard_shortcuts = true;\n\n\n  $('#task_' + todoId + '_subject_text').html(h($('#task_' + todoId + '_subject_input').val())).show();\n  $('#task_' + todoId + '_subject_input').hide();\n  $('#task_' + todoId + '_subject_submit_container').html('');\n\n  var item = D[dataId];\n  var data = \"commit=Update&id=\" + todoId + \"&issue_id=\" + item.id + \"&todo[subject]=\" + encodeURIComponent($('#task_' + todoId + '_subject_input').val());\n\n  if ($('#task_' + todoId + '_complete').attr(\"checked\") == true){\n    $('#task_' + todoId  + '_subject').addClass('completed');\n    data = data + '&todo[owner_login]=' + currentUserLogin;\n    data = data + '&todo[owner_id]=' + currentUserId;\n    data = data + '&todo[completed_on]=' + Date();\n  }\n  else\n  {\n    $('#task_' + todoId  + '_subject').removeClass('completed');\n    data = data + '&todo[completed_on]=';\n  }\n\n  var url = url_for({ controller: 'todos',\n                           action    : 'update'\n                          });\n\n  $.ajax({\n     type: \"POST\",\n     dataType: \"json\",\n     url: url,\n     data: data,\n     success:   function(html){\n      todo_updated(html,dataId);\n    },\n     error:   function (XMLHttpRequest, textStatus, errorThrown) {\n    handle_error(XMLHttpRequest, textStatus, errorThrown, dataId, \"post\");\n    },\n    timeout: 30000 //30 seconds\n   });\n\n  return false;\n  }\ncatch(err){\n  return false;\n}\n}\n\n\n\nfunction update_todo_buttons(todoId,show){\n  if (show){\n    $('#task_' + todoId + '_edit').attr(\"style\",\"opacity: 100\");\n    $('#task_' + todoId + '_delete').attr(\"style\",\"opacity: 100\");\n  }\n  else{\n    $('#task_' + todoId + '_edit').attr(\"style\",\"opacity: 0\");\n    $('#task_' + todoId + '_delete').attr(\"style\",\"opacity: 0\");\n  }\n}\n\n//Takes credits, and base, and turns them to points for display\nfunction credits_to_points(credits,base){\n  normalized = Math.round(credits/base);\n  if (normalized > credits_to_points_array.length - 1 ){\n    return credits_to_points_array[credits_to_points_array.length - 1];\n  }\n  return credits_to_points_array[normalized]; //TODO: fix this formula credits larger than 12\n}\n\nfunction has_current_user_estimated(item){\n\n  //Checking wether or not current user estimated this item voted\n  for(i=0; i < item.issue_votes.length; i++){\n    if (item.issue_votes[i].vote_type != 4) continue;\n\n    if (currentUserLogin == item.issue_votes[i].user.login){\n      return true;\n    }\n  }\n  return false;\n}\n\nfunction generate_item_estimate_button(dataId,points){\n  var item = D[dataId];\n  var html = '';\n  var onclick = \"\";\n\n  if (is_item_estimatable(item)){\n    onclick = \"show_estimate_flyover(\"+ dataId +\",this.id);return false;\";\n  }\n  else{\n    onclick = \"show_points_flyover(\"+ dataId +\",this.id);return false;\";\n  }\n\n  var current_user_voted = has_current_user_estimated(item);\n\n  if (((item.status.name != 'New')&&(item.status.name != 'Estimate')&&(item.status.name != 'Open')) || (current_user_voted) || (!is_item_estimatable(item))){\n\n    //If no binding points, then current user is non-binding and has voted so we show them a different symbol so they can track what they estimated, and what they didn't estimate\n    if (points == \"No\" && current_user_voted){\n      points = \"wait\";\n    }\n    html = html + '<img id=\"diceicon_' + dataId + '\"  class=\"storyPoints hoverDiceIcon clickable\" src=\"/images/dice_' + points + '.png\" alt=\"' + points + ' credits\" onclick=' + onclick + '>';\n  }\n  else{\n    html = html + '<img id=\"diceicon_' + dataId + '\"  class=\"storyPoints hoverDiceIcon clickable\" src=\"/images/dice_No.png\" alt=\"Credits hidden until you estimate\" onclick=' + onclick + '>';\n  }\n\n  return html;\n\n}\n\nfunction add_new_link(){\n  $(\"#new_list\").prepend(generate_new_link());\n}\n\nfunction remove_new_link(){\n  $(\"#item_new_link\").remove();\n}\n\n\nfunction generate_new_link(){\n  var html = '';\n\n  html = html + '<div id=\"item_new_link\" class=\"item\">';\n  html = html + '<div id=\"item_content_new_link\" class=\"newlink hoverable\" style=\"\">';\n  html = html + '<div class=\"itemCollapsedHeader\">';\n\n  html = html + '<div id=\"item_content_details_new_link\" class=\"itemCollapsedTextNewLink\" onDblclick=\"new_item();return false;\" style=\"cursor: default;\">';\n\n  html = html + '<a href=\"#\" onclick=\"new_item();return false;\">Add New Item</a>';\n  html = html + '</div>';\n  html = html + '</div>';\n  html = html + '</div>';\n  html = html + '</div>';\n  return html;\n}\n\n\n//Generates html for collapsed item\nfunction generate_item(dataId){\n  var item = D[dataId];\n  var html = '';\n  var points;\n  item.points == null ? points = 'No' : points = credits_to_points(item.points,credit_base);\n\n  html = html + '<div id=\"item_' + dataId + '\" class=\"item points_' + points + ' pri_' + item.pri + '\">';\n  html = html + '<div id=\"item_content_' + dataId + '\" class=\"' + item.status.name.replace(\" \",\"-\").toLowerCase() + ' hoverable\" style=\"\">';\n  html = html + '<div class=\"itemCollapsedHeader\">';\n  html = html + '<div id=\"item_content_buttons_' + dataId + '\" class=\"itemCollapsedButtons\">';\n  if (currentUserId != ANONYMOUS_USER_ID){\n    html = html + buttons_for(dataId);\n  }\n\n  html = html + '</div>';\n\n  html = html + '<div id=\"icons_' + dataId + '\" class=\"icons\">'; //The id of this div is used to lookup the item to generate the flyover\n  html = html + '<img id=\"item_content_icons_editButton_' + dataId + '\" class=\"toggleExpandedButton\" src=\"/images/story_collapsed.png\" title=\"Expand\" alt=\"Expand\" onclick=\"expand_item(' + dataId + ');return false;\">';\n  html = html + '<div id=\"icon_set_' + dataId + '\" class=\"left\">';\n  if (is_cancelable(dataId)){\n    html = html + dash_button('cancel',dataId,false,{label:'&nbsp;'});\n  }\n\n  // html = html + '<img id=\"featureicon_' + dataId + '\" itemid=\"' + item.id + '\" class=\"storyTypeIcon hoverDetailsIcon clickable\" src=\"/images/' + item.tracker.name.toLowerCase() + '_icon.png\" alt=\"' + item.tracker.name + '\"  onclick=\" show_item_fancybox('+ dataId +');return false;\">';\n\n  if (currentUserId != ANONYMOUS_USER_ID){\n    html = html + generate_item_estimate_button(dataId,points);\n  }\n\n  // if (show_comment(item)){\n  // html = html + '<img id=\"flyovericon_' + dataId + '\"  class=\"flyoverIcon hoverCommentsIcon clickable\" src=\"/images/story_flyover_icon.png\" onclick=\"show_details_flyover('+ dataId +',this.id);return false;\">';\n  // }\n\n  html = html + '</div>';\n\n  html = html + '</div>';\n\n\n  html = html + '<div id=\"item_content_details_' + dataId + '\" class=\"itemCollapsedText\" onDblclick=\"expand_item(' + dataId + ');return false;\" style=\"cursor: default;\">';\n  html = html + '<span>'\n  html = html + '<a href=\"#\" class=\"dash-item-title\" onclick=\"show_item_fancybox(' + dataId + ');return false;\">' + h(item.subject) + '</a>';\n  html = html + generate_tags(item.tags_copy);\n  html = html + '</span><div class=\"clear\"></div>';\n  html = html + '</div>';\n  html = html + '</div>';\n  html = html + '</div>';\n  html = html + '</div>';\n  return html;\n}\n\nfunction generate_tags(tag_list){\n  if (!tag_list){return '';}\n  html = '';\n  html = html + '<div class=\"tagsoutput tagsdash\">';\n\n  var tag_array = tag_list.split(',');\n  for(var j = 0; j < tag_array.length; j++ ){\n    html = html + '<span class=\"tag\">';\n    html = html + tag_array[j];\n    html = html + '</span>';\n  }\n\n  // $.each(, function() {\n  //     $('#' + name + '_start_of_list').append(this);\n  //     });\n\n  html = html + '</div>';\n  return html;\n\n  // issue.tag_list.each {|t| html = html + content_tag('span', t, :class => \"tag\")}\n  //     content_tag('div', html, :class => \"tagsoutput\")\n\n}\n\n//Generates html for item header in lightbox\nfunction generate_item_lightbox(dataId){\n  var item = D[dataId];\n  var html = '';\n  var points;\n  item.points == null ? points = 'No' : points = credits_to_points(item.points,credit_base);\n\n  html = html + '<div id=\"item_lightbox_' + dataId + '\" class=\"item_lightbox points_' + points + ' pri_' + item.pri + '\">';\n  html = html + '<div id=\"item_content_' + dataId + '\" class=\"' + item.status.name.replace(\" \",\"-\").toLowerCase() + ' hoverable\" style=\"\">';\n  html = html + '<div id=\"item_content_buttons_' + dataId + '\" class=\"itemCollapsedButtons\">';\n  html = html + buttons_for(dataId);\n  html = html + '</div>';\n\n  html = html + '<div id=\"icons_' + dataId + '\" class=\"icons\">'; //The id of this div is used to lookup the item to generate the flyover\n  html = html + '<h3 style=\"border:none;padding-left:11px\">';\n\n  html = html + generate_item_estimate_button(dataId,points);\n\n  html = html + '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' + h(item.subject);\n  html = html + '&nbsp;<span id=\"icon_set_' + dataId + '\">&nbsp;';\n  html = html + '</span>';\n  html = html + '</h3>';\n\n\n\n  html = html + '</div>';\n\n  // html = html + '<div class=\"left\">';\n  // html = html + '</div>';\n\n\n  html = html + '</div>';\n  html = html + '</div>';\n  return html;\n}\n\nfunction update_lightbox_lock_version(dataId){\n  $(\"#issue_lock_version\").attr('value', D[dataId].lock_version);\n}\n\nfunction generate_retro(rdataId){\n  var retro = R[rdataId];\n  var html = '';\n  html = html + '  <div id=\"retro_' + rdataId + '\" class=\"item retrospective\">';\n  html = html + '  <div id=\"retro_' + rdataId + '_content\" class=\"gt-Iih\">';\n  html = html + '  <table>';\n  html = html + '  <tbody>';\n  html = html + '  <tr>';\n  html = html + '  <td style=\"white-space: nowrap; width: 1%; padding: 1px 0pt 1px 4px; color: rgb(255, 255, 255); background-color: rgb(69, 71, 72);\">';\n  html = html + '    <img id=\"done_itemList_' + retro.id + '_toggle_expanded_button\" class=\"gt-IihToggleExpandedButton\" src=\"/images/iteration_expander_closed.png\" title=\"Expand\" alt=\"Expand\" style=\"height: 12px; width: 12px;\" onclick=\"display_retro(' + rdataId + ');return false;\"/>';\n  html = html + '  </td>';\n  html = html + '  <td style=\"white-space: nowrap; width: 1%; padding: 1px 0.5em 1px 0pt; color: white; background-color: rgb(69, 71, 72);\">';\n  html = html + '    <div id=\"done_itemList_' + rdataId + '_iteration_label\" title=\"Retrospective ' + retro.id + '\" style=\"width: 2em; text-align: right;\">' + retro.id + '</div>';\n  html = html + '  </td>';\n  html = html + '  <td id=\"done_' + rdataId + '_date_label\" style=\"white-space: nowrap; width: 99%; padding: 1px 0.5em; color: rgb(255, 255, 255);\">';\n  html = html + '  <span>';\n  html = html + '  <a class=\"date_label\" title=\"Retro: ' + dateFormat(retro.to_date,'dd mm yy') + ' (' + retro_status(retro) + ')\" onclick=\"display_retro(' + rdataId + ');return false;\">Retro: ' + dateFormat(retro.to_date,'dd mmm') + ' (' + retro_status(retro) + ')</a>';\n  html = html + '  </span>';\n  html = html + '  </td>';\n  html = html + '  <td id=\"done_' + rdataId + '_details_points\" style=\"white-space: nowrap; width: 1%; padding: 1px 0.5em; color: rgb(255, 255, 255);\">';\n  html = html + '    <span title=\"Credits completed: ' + retro.total_points + '\">' + retro.total_points + ' credits</span>';\n  html = html + '  </td>';\n  html = html + '  </tr>';\n  html = html + '  </tbody>';\n  html = html + '  </table>';\n  html = html + '  </div>';\n  html = html + '  </div>';\n  return html;\n}\n\n// function retro_status(retro){\n//   if (retro.status_id == 1){\n//     return \"open\";\n//   }\n//   else{\n//     return \"done\";\n//   }\n// }\n\nfunction display_retro(rdataId){\n\n\n  var retro = R[rdataId];\n\n  $('#done_itemList_' + retro.id + '_toggle_expanded_button').attr('src','/images/iteration_expander_open.png');\n\n  var url = 'retros/' + retro.id + '/dashdata';\n\n  if ($('#include_subworkstreams_checkbox').attr(\"checked\") == true){\n    url = url + \"&include_subworkstreams=true\";\n  }\n\n\n  $.ajax({\n     type: \"GET\",\n     dataType: \"json\",\n     contentType: \"application/json\",\n     url: url,\n     success:    function(html){\n      $('#new_retro_wrapper_' + rdataId).hide();\n      rdata_ready(html,rdataId);\n    },\n     error:   function (XMLHttpRequest, textStatus, errorThrown) {\n      handle_error(XMLHttpRequest, textStatus, errorThrown, null,'load data');\n    },\n    timeout: 30000 //30 seconds\n   });\n\n\n  $('#retro_' + retro.id + '_panel').remove();\n  generate_and_append_panel(0,'retro_' + retro.id,'Retro ' + retro.id + ': ' + dateFormat(retro.from_date,'dd mmm yyyy') + ' to ' + dateFormat(retro.to_date,'dd mmm yyyy'),true);\n  recalculate_widths();\n  var html = '  <div class=\"item\" id=\"new_retro_wrapper_' + rdataId + '\"><div id=\"loading\" class=\"loading\"> Loading...</div></div>';\n  $('#retro_' + retro.id + '_items').prepend(html);\n\n\n}\n\n\nfunction generate_notice(noticeHtml, noticeId){\n  $('#notice_' + noticeId).remove();\n  var html =  '';\n  html = html + '  <div id=\"notice_' + noticeId + '\" class=\"item panel_notice\">';\n  html = html + '  <div id=\"notice_' + noticeId + '_content\" class=\"gt-Iih\">';\n  html = html + '  <table>';\n  html = html + '  <tbody>';\n  html = html + '  <tr>';\n  html = html + '  <td id=\"done_' + noticeId + '_date_label\" style=\"white-space: nowrap; width: 99%; padding: 1px 0.5em; color: rgb(255, 255, 255);\">';\n  html = html + '  <span>';\n  html = html + noticeHtml;\n  html = html + '  </span>';\n  html = html + '  </td>';\n  html = html + '  </tr>';\n  html = html + '  </tbody>';\n  html = html + '  </table>';\n  html = html + '  </div>';\n  html = html + '  </div>';\n  return html;\n}\n\nfunction is_cancelable(dataId){\n  item = D[dataId];\n\n  if (currentUserIsCore == 'true'){\n    var today = new Date();\n    var one_day=1000*60*60*24;\n    var updated = new Date(item.updated_at).getTime();\n    var days = (today.getTime() - updated)/one_day;\n    if (days > 30){\n      return true;\n    }\n  }\n\n  if (currentUserId != item.author_id){\n    return false;\n  }\n  else{\n    for (var i = 0; i < item.issue_votes.length; i ++){\n      if(item.issue_votes[i].user_id != currentUserId){\n        return false;\n      }\n    }\n    for (var j = 0; j < item.journals.length; j ++){\n      if((item.journals[j].user_id != currentUserId)&&(item.journals[j].user_id != adminUserId)){\n        return false;\n      }\n    }\n  }\n  return true;\n}\n\n\nfunction buttons_for(dataId,expanded){\n  if (currentUserId == ANONYMOUS_USER_ID){ return \"\";}\n  var item = D[dataId];\n  var html = '';\n\n  switch (item.status.name){\n  case 'New':\n    html = html + pri_button(dataId);\n    html = html + agree_buttons_root(dataId, true, expanded);\n  break;\n  case 'Estimate':\n    html = html + pri_button(dataId);\n    html = html + agree_buttons_root(dataId,true,expanded);\n  break;\n  case 'Open':\n    html = html + pri_button(dataId);\n    html = html + agree_buttons_root(dataId,true,expanded);\n  break;\n  case 'Committed':\n    if (item.assigned_to_id == currentUserId){\n      html = html + dash_button('finish',dataId);\n      html = html + dash_button('release',dataId,false,{label:'giveup'});\n    }\n    else if (item.assigned_to != null){\n      if (is_part_of_team(item)){\n        html = html + dash_button('finish',dataId);\n        html = html + dash_button('leave',dataId);\n      }\n      else if (is_item_joinable(item)){\n        html = html + '<div id=\"committed_tally_' + dataId + '\" class=\"action_button_tally\">' + item.assigned_to.firstname + '</div>';\n        html = html + dash_button('join',dataId);\n      }\n    }\n  break;\n  case 'Done':\n    html = html + accept_buttons_root(dataId,expanded);\n  break;\n  case 'Accepted':\n    html = html + '<div id=\"accepted_' + dataId + '\" class=\"action_button action_button_accepted\" onclick=\"click_accept_root(' + dataId + ',this,\\'false\\');return false;\">Accepted</div>';\n\n    if (item.retro_id && (item.retro_id > 0)){\n      html = html + dash_button('retro',dataId,false,item.retro_id);\n    }\n  break;\n  case 'Rejected':\n    html = html + '<div id=\"rejected_' + dataId + '\" class=\"action_button action_button_rejected\" onclick=\"click_accept_root(' + dataId + ',this,\\'false\\');return false;\">Rejected</div>';\n    html = html + dash_button('start',dataId);\n  break;\n  case 'Archived':\n    html = html + '<div id=\"accepted_' + dataId + '\" class=\"action_button action_button_accepted\" onclick=\"click_accept_root(' + dataId + ',this,\\'false\\');return false;\">Accepted</div>';\n    if (item.retro_id > 0){\n      html = html + dash_button('retro',dataId,false,item.retro_id);\n    }\n  break;\n  case 'Canceled':\n    html = html + dash_button('restart',dataId);\n  break;\n  }\n\n  return html;\n\n}\n\n//returns true if current user is on the team for this item\nfunction is_part_of_team(item){\n  //Determining wether or not user is already part of the team for this task\n  var part_of_team = false;\n  for(var i=0; i < item.issue_votes.length; i++){\n    if ((currentUserLogin == item.issue_votes[i].user.login)&&(item.issue_votes[i].vote_type == 5)){\n      part_of_team = true;\n      break;\n    }\n  }\n  return part_of_team;\n}\n\nfunction agree_buttons_root(dataId,include_start_button,expanded){\n  var html = '';\n  var item = D[dataId];\n\n  var tally = 'agree?';\n  var cssclass = 'root';\n  var user_voted = 'false';\n  var user_estimated = false;\n\n\n  for(var i=0; i < item.issue_votes.length; i++){\n    //bugbug: hardcoded issue vote (4)\n    if ((currentUserLogin == item.issue_votes[i].user.login)&&(item.issue_votes[i].vote_type == 4)){\n      user_estimated = true;\n    }\n\n    //bugbug: hardcoded issue vote (1)\n    if ((currentUserLogin == item.issue_votes[i].user.login)&&(item.issue_votes[i].vote_type == 1)){\n      user_voted = item.issue_votes[i].points;\n      tally = '';\n\n      if (item.disagree > 5000){\n        include_start_button = false;\n        tally = 'Blocked';\n      }\n      else{\n        tally = (item.agree + item.agree_nonbind) + ' - ' + (item.disagree + item.disagree_nonbind);\n      }\n      switch(String(item.issue_votes[i].points))\n      {\n        case \"1\":  cssclass = 'agree';\n              break;\n        case \"0\":  cssclass = 'neutral';\n              break;\n        case \"-1\":  cssclass = 'disagree';\n              break;\n        case \"-9999\": cssclass = 'block';\n              break;\n      }\n    }\n  }\n\n  if (include_start_button){\n    html = html + dash_button('start',dataId,false); //add start button\n  }\n\n  // if ((!user_estimated) && user_voted){\n  //   html = html + dash_button('estimate',dataId,false,{'label':'estimate?'}); //no room to show tally if estimate button is included\n  // }\n  var total_votes = item.agree + item.agree_nonbind - item.disagree - item.disagree_nonbind\n  html = html + votes_button(dataId,total_votes, user_voted);\n\n  return html;\n}\n\n\n\n// function agree_buttons_root(dataId,include_start_button,expanded){\n//   var html = '';\n//   var item = D[dataId];\n//\n//   var tally = 'agree?';\n//   var cssclass = 'root';\n//   var user_voted = false;\n//   var user_estimated = false;\n//\n//\n//   for(var i=0; i < item.issue_votes.length; i++){\n//     //bugbug: hardcoded issue vote (4)\n//     if ((currentUserLogin == item.issue_votes[i].user.login)&&(item.issue_votes[i].vote_type == 4)){\n//       user_estimated = true;\n//     }\n//\n//     //bugbug: hardcoded issue vote (1)\n//     if ((currentUserLogin == item.issue_votes[i].user.login)&&(item.issue_votes[i].vote_type == 1)){\n//       user_voted = true;\n//       tally = '';\n//\n//       if (item.disagree > 5000){\n//         include_start_button = false;\n//         tally = 'Blocked';\n//       }\n//       else{\n//         tally = (item.agree + item.agree_nonbind) + ' - ' + (item.disagree + item.disagree_nonbind);\n//       }\n//       switch(String(item.issue_votes[i].points))\n//       {\n//         case \"1\":  cssclass = 'agree';\n//               break;\n//         case \"0\":  cssclass = 'neutral';\n//               break;\n//         case \"-1\":  cssclass = 'disagree';\n//               break;\n//         case \"-9999\": cssclass = 'block';\n//               break;\n//       }\n//     }\n//   }\n//\n//   if (include_start_button && user_estimated && user_voted){\n//     html = html + dash_button('start',dataId,false); //add start button if user estimated and voted\n//   }\n//\n//   if ((!user_estimated) && user_voted){\n//     html = html + dash_button('estimate',dataId,false,{'label':'estimate?'}); //no room to show tally if estimate button is included\n//   }\n//\n//   html = html + dash_button('agree_root',dataId,false,{label:tally,cssclass:cssclass});\n//\n//   return html;\n// }\n\nfunction accept_buttons_root(dataId,include_start_button,expanded){\n\n  var html = '';\n  var item = D[dataId];\n\n  var tally = 'accept?';\n\n  if (item.reject > 5000){\n    tally = 'Blocked';\n  }\n  else{\n    tally = (item.accept + item.accept_nonbind) + ' - ' + (item.reject + item.reject_nonbind);\n  }\n\n  var cssclass = 'root';\n  var user_voted = false;\n\n\n  for(var i=0; i < item.issue_votes.length; i++){\n    if ((currentUserLogin == item.issue_votes[i].user.login)&&(item.issue_votes[i].vote_type == 2)){\n      user_voted = true;\n      switch(String(item.issue_votes[i].points))\n      {\n        case \"1\":  cssclass = 'accept';\n              break;\n        case \"0\":  cssclass = 'neutral';\n              break;\n        case \"-1\":  cssclass = 'reject';\n              break;\n        case \"-9999\": cssclass = 'block';\n              break;\n      }\n\n      break;\n    }\n  }\n\n  if (!user_voted){\n    tally = \"accept?\";\n  }\n\n  html = dash_button('accept_root',dataId,false,{label:tally,cssclass:cssclass});\n\n  if (item.assigned_to_id == currentUserId){\n    html = html + dash_button('start',dataId,false,{label:'takeback', cssclass:'takeback'});\n  }\n\n\n  return html;\n}\n\n\nfunction pri_button(dataId){\n  var item = D[dataId];\n  for(var i=0; i < item.issue_votes.length; i++){\n    if ((currentUserLogin == item.issue_votes[i].user.login)&&(item.issue_votes[i].vote_type == 3)){\n      if (item.issue_votes[i].points == 1){\n        return generate_pri_button(dataId,'up',(item.pri + item.pri_nonbind));\n      }\n      else if (item.issue_votes[i].points == -1){\n        return generate_pri_button(dataId,'down',(item.pri + item.pri_nonbind));\n      }\n      else if (item.issue_votes[i].points == 0){\n        return generate_pri_button(dataId,'neutral',(item.pri + item.pri_nonbind));\n      }\n    }\n  }\n  return generate_pri_button(dataId,'none',(item.pri + item.pri_nonbind));\n}\n\nfunction generate_pri_button(dataId,direction,pri){\n  // var html = '<div id=\"pri_container_' + D[dataId].id + '\" class=\"pri_container\">';\n  var ondblclick =  'hide_bubbletips();click_pri(' + dataId + ',this,1);hide_bubbletips();return false;';\n  var html = '<div id=\"item_content_buttons_pri_button_' + dataId + '\" class=\"clickable pri_button pri_button_' + direction + '\" onclick=\"show_pri_flyover(' + dataId + ',this.id);return false;\" onDblclick = ' + ondblclick + '>' + pri + '</div>';\n  // html = html + '</div>';\n  return html;\n}\n\nfunction votes_button(dataId,votes_total,user_voted){\n  var type = 'agree_root';\n  var label = votes_total + ' vote';\n  if (votes_total != 1){ label = label + 's'}else{ label = label + ' '};\n  if (votes_total < -9000){ label = 'blocked'};\n  var cssclass = '';\n  var onclick = 'click_agree_root(' + dataId + ',this,\\'\\');return false;';\n\n  if (user_voted == 'false'){\n      var  onarrowclick =  'click_agree(' + dataId + ',this,\\'&points=1\\')\";return false;';\n  }\n  else{\n      var onarrowclick = 'click_agree_root(' + dataId + ',this,\\'\\');return false;';\n  }\n\n\n  html = '';\n  html = html + '<div id=\"item_content_buttons_' + type + '_button_' + dataId + '\" class=\"action_button action_button_votes\" total_votes=\"' + votes_total + '\">';\n  html = html + '<a id=\"item_action_link_vote' + dataId + '\" onclick=\"' + onarrowclick + '\" class=\"vote_arrow\"><img src=\"/images/upvote_' + user_voted + '.png\"/></a>';\n\n  html = html + '<a id=\"item_action_link_' + type + dataId + '\" class=\"action_link_votes clickable\" onclick=\"' + onclick + '\">';\n  html = html + label + '</a>';\n  html = html + '</div>';\n  return html;\n}\n\n\n\n//Generates a button type for item id\nfunction dash_button(type,dataId,hide,options_param){\n    var options = options_param || {};\n    var label = typeof(options['label']) == 'undefined' ?\n                                    type :\n                                    options['label'];\n    var cssclass = typeof(options['cssclass']) == 'undefined' ?\n                                    type :\n                                    options['cssclass'];\n    var action = typeof(options['action']) == 'undefined' ?\n                                    type :\n                                    options['action'];\n    var data = typeof(options['data']) == 'undefined' ?\n                                    '' :\n                                    options['data'];\n  var hide_style = '';\n  var onclick = 'click_' + action + '(' + dataId + ',this,\\'' + data + '\\');return false;';\n  var ondblclick = '';\n\n  if (type == \"agree_root\"){\n    ondblclick =  'click_agree(' + dataId + ',this,\\'&points=1\\')\";return false;';\n  }\n\n  if (type == \"accept_root\"){\n    ondblclick =  'click_accept(' + dataId + ',this,\\'&points=1\\')\";return false;';\n  }\n\n\n  if (hide){ hide_style = \"style=display:none;\"; }\n  html = '';\n  html = html + '<div id=\"item_content_buttons_' + type + '_button_' + dataId + '\" onclick=\"' + onclick + '\" class=\"action_button action_button_' + cssclass + '\" ' + hide_style + '>';\n  html = html + '<a id=\"item_action_link_' + type + dataId + '\" class=\"action_link clickable\" onDblclick=\"' + ondblclick + '\"  onclick=\"return false;\">';\n  html = html + label + '</a></div>';\n  return html;\n}\n\nfunction click_start(dataId,source,data){\n  //Login required\n  if (!is_user_logged_in()){return false;}\n\n  if (($(\".action_button_finish\").get().length - 1) >= MAX_REQUESTS_PER_PERSON){\n    $.jGrowl(\"Sorry, you're only allowed to own \" + MAX_REQUESTS_PER_PERSON + \" items at a time\");\n    return false;\n  }\n\n  if (credits_enabled && !has_current_user_estimated(D[dataId])){\n    $.jGrowl(\"Sorry, you can't start an item before estimating it first. <br><br>Click on the dice with the question mark on it, to estimate the complexity/size of this item.\");\n    return false;\n  }\n\n\n  $('#' + source.id).parent().hide();\n  send_item_action(dataId,'start');\n  return false;\n}\n\nfunction click_reject(dataId,source,data){\n  //Login required\n  if (!is_user_logged_in()){return;}\n\n  $('#' + source.id).parent().hide();\n  comment_prompt(dataId,source,data,'reject',true,\"Please explain your rejection\");\n}\n\n\n//This is the estimate button clicked from the dashboard\nfunction click_estimate(dataId,source,data,comment){\n  show_estimate_flyover(dataId,source.id);\n}\n\n//This is the actual die clicked from the estimate flyover\nfunction click_estimate_from_flyover(dataId,source,data,comment){\n  //Login required\n  if (!is_user_logged_in()){return;}\n\n  // $('#' + source.id).parent().hide();\n  if (comment == true){\n    comment_prompt(dataId,source,data,'estimate',false,\"Please explain why you're changing your estimate (optional)\");\n  }\n  else{\n    send_item_action(dataId,'estimate',data);\n  }\n\n}\n\n\nfunction click_finish(dataId,source,data){\n  //Login required\n  if (!is_user_logged_in()){return;}\n\n  $('#' + source.id).parent().hide();\n  comment_prompt(dataId,source,data,'finish',false,\"Tell your team what was accomplished. Include links to help them see the work, and accept it.\");\n}\n\nfunction click_restart(dataId,source,data){\n  //Login required\n  if (!is_user_logged_in()){return;}\n\n  $('#' + source.id).parent().hide();\n  send_item_action(dataId,'restart');\n}\n\n// function click_estimate(dataId,source,data){\n//   $('#' + source.id).parent().hide();\n// }\n\nfunction click_agree(dataId,source,data){\n  //Login required\n  if (!is_user_logged_in()){return;}\n\n  // $('#item_content_buttons_' + dataId).hide();\n\n  var item = D[dataId];\n  var user_voted = 0;\n  for(var i=0; i < item.issue_votes.length; i++){\n    if ((currentUserLogin == item.issue_votes[i].user.login)&&(item.issue_votes[i].vote_type == 1)){\n      user_voted = item.issue_votes[i].points;\n    }\n  }\n\n  var user_new_voted = parseInt(data.split('=')[1])\n  var votes_total = item.agree + item.agree_nonbind - item.disagree - item.disagree_nonbind - user_voted + user_new_voted\n  $('#item_content_buttons_agree_root_button_' + dataId).html(votes_button(dataId, votes_total, user_new_voted));\n\n\n  switch(data)\n  {\n    case \"&points=1\":  send_item_action(dataId,'agree',data);\n          break;\n    case \"&points=0\":  send_item_action(dataId,'agree',data);\n          break;\n    case \"&points=-1\":  comment_prompt(dataId,source,data,'agree',false, \"Please explain why you disagree (optional)\");\n          break;\n    case \"&points=-9999\":  comment_prompt(dataId,source,data,'agree',true, \"Please explain why you're blocking\");\n          break;\n  }\n}\n\nfunction click_agree_root(dataId,source,data){\n  show_agree_flyover(dataId,source.id);\n  return false;\n}\n\nfunction click_accept_root(dataId,source,data){\n  show_accept_flyover(dataId,source.id);\n  return false;\n}\n\nfunction click_accept(dataId,source,data){\n  //Login required\n  if (!is_user_logged_in()){return;}\n\n  $('#' + source.id).parent().hide();\n  switch(data)\n  {\n    case \"&points=1\":  send_item_action(dataId,'accept',data);\n          break;\n    case \"&points=0\":  send_item_action(dataId,'accept',data);\n          break;\n    case \"&points=-1\":  comment_prompt(dataId,source,data,'accept',false,\"Please explain your rejection (optional)\");\n          break;\n    case \"&points=-9999\":  comment_prompt(dataId,source,data,'accept',true,\"Please explaing your blocking\");\n          break;\n  }\n}\n\nfunction click_release(dataId,source,data){\n  //Login required\n  if (!is_user_logged_in()){return;}\n\n  $('#' + source.id).parent().hide();\n  send_item_action(dataId,'release');\n}\n\nfunction click_cancel(dataId,source,data){\n  //Login required\n  if (!is_user_logged_in()){return;}\n\n  $('#' + source.id).parent().hide();\n  comment_prompt(dataId,source,data,'cancel',false,\"Please explain why you're canceling\");\n}\n\nfunction click_leave(dataId,source,data){\n  //Login required\n  if (!is_user_logged_in()){return;}\n\n  $('#' + source.id).parent().hide();\n  send_item_action(dataId,'leave');\n}\n\nfunction click_join(dataId,source,data){\n  //Login required\n  if (!is_user_logged_in()){return;}\n\n  if(confirm(\"By joining an item, you are declaring that you want to help get it done.\\n\\n Are you sure you want to do this?\")){\n    $('#' + source.id).parent().hide();\n    send_item_action(dataId,'join');\n  }\n}\n\nfunction click_pri(dataId,source,points){\n  //Login required\n  if (!is_user_logged_in()){return;}\n  $(\".bubbletip\").hide();\n  $('#pri_container_' + D[dataId].id).hide();\n  send_item_action(dataId,'prioritize','&points=' + points);\n}\n\nfunction click_retro(dataId,source,data){\n  //Login required\n  if (!is_user_logged_in()){return false;}\n\n  var url = '/projects/' + projectId + '/retros/' + D[dataId].retro_id + '/show';\n\n  show_fancybox(url,'generating retrospective data...');\n  return false;\n}\n\nfunction submit_comment_prompt(dataId,data,action){\n  var text = $(\"#prompt_comment_\" + dataId).val();\n  if ((text == null) || (text.length < 2)){\n    alert('Comment is too short!');\n  }\n  else{\n    // post_comment(dataId,true,action);\n    data = data + '&notes=' + encodeURIComponent(text);\n    send_item_action(dataId,action,data);\n    $.fancybox.close();\n  }\n  return false;\n}\n\nfunction cancel_comment_prompt(dataId,source,data,action){\n  $('#item_content_buttons_' + dataId).show();\n  $('#' + source.id).parent().show();\n  $.fancybox.close();\n  return false;\n}\n\n\nfunction comment_prompt(dataId,source,data,action,required,message){\n\n  var title = required ? 'required' : 'optional';\n\n  var content = '';\n  content = content + '<div id=\"comment_prompt\"><h2>Comment</h2><br>';\n  if (message){\n    content = content + message + '<br><br>';\n  }\n        content = content + '<p><textarea id=\"prompt_comment_' + dataId + '\" class=\"comment_prompt_text\" rows=\"10\" ></textarea></p><br>';\n    content = content + '<p>';\n        content = content + '<input type=\"submit\" onclick=\"submit_comment_prompt(' + dataId + ',\\'' + data + '\\',\\'' + action + '\\')\" value=\"Submit\"></input>';\n    if (!required){\n          content = content + '<input type=\"submit\" onclick=\"send_item_action(' + dataId + ',\\'' + action + '\\',\\'' + data + '\\'); $.fancybox.close();return false;\" value=\"No Comment\"></input>';\n    }\n        content = content + '<input type=\"submit\" onclick=\"cancel_comment_prompt(' + dataId + ',\\'' + source + '\\',\\'' + data + '\\',\\'' + action + '\\')\" value=\"Cancel\"></input>';\n    content = content + '</p><br><br></div>';\n\n  $.fancybox(\n    {\n        'content'      : content,\n        'width'        : 'auto',\n        'height'      : 'auto',\n        'title'        : title,\n                    'autoScale'       : false,\n                    'transitionIn'    : 'none',\n        'transitionOut'    : 'none',\n        'scrolling'      : 'no',\n        'showCloseButton' : false,\n        'modal' : true,\n        'href'  : '#comment_prompt'\n    });\n\n  $('#new_comment_' + dataId).focus();\n  $( \"#prompt_comment_\" + dataId ).mentions(projectId);\n}\n\n\n\nfunction filter_select(){\n  var selection = $(\"#filter_select\").val();\n  $('#fast_search').val(''); //clearing fast search\n\n  switch(selection)\n  {\n    case \"1\":  hide_inactive(1);\n          break;\n    case \"2\":  hide_inactive(2);\n          break;\n    case \"3\":  hide_inactive(3);\n          break;\n    case \"7\":  hide_inactive(7);\n          break;\n    case \"14\":  hide_inactive(14);\n          break;\n    case \"21\":  hide_inactive(21);\n          break;\n    case \"30\":  hide_inactive(30);\n          break;\n    case \"60\":  hide_inactive(60);\n          break;\n    case \"90\":  hide_inactive(90);\n          break;\n    case \"120\":  hide_inactive(120);\n          break;\n    case \"150\":  hide_inactive(150);\n          break;\n    case \"all\":  hide_inactive(99999);\n          break;\n    case \"all_top\":  hide_inactive(99999);\n          break;\n    case \"unagreed\":  show_unvoted({'New':1,'Open':1,'Estimate':1}, 1);\n          break;\n    case \"unaccepted\":  show_unvoted({'Done':1},2);\n          break;\n    case \"unprioritized\":  show_unvoted({'New':1,'Open':1,'Estimate':1},3);\n          break;\n    case \"unestimated\":  show_unvoted({'New':1,'Open':1,'Estimate':1},4);\n          break;\n    case \"prioritized\":  show_voted({'New':1,'Open':1,'Estimate':1,'Done':1},3,1);\n          break;\n    case \"added_by_me\":  show_added_by_me();\n          break;\n    case \"touched_by_me\": show_hide_touched(true);\n          break;\n    case \"untouched_by_me\":  show_hide_touched(false);\n          break;\n    default: show_tag(selection);\n      break;\n  }\n\n  if (selection != \"all\" && selection != \"all_top\"){\n    $('#filtered_message').show();\n    $('#filter_detail').html($(\"#filter_select :selected\").text());\n  }\n  else\n  {\n    $('#filtered_message').hide();\n  }\n  update_panel_counts();\n}\n\n//Shows all items added by current user\nfunction show_added_by_me(){\n\n  for(var i = 0; i < D.length; i++ ){\n    if (D[i].author_id == currentUserId){\n      $(\"#item_\" + i).show();\n    }\n    else{\n      $(\"#item_\" + i).hide();\n    }\n  }\n}\n\n//Shows (or hides) all items touched by current user, if show is true it shows them, else it hides them\nfunction show_hide_touched(show){\n  for(var i = 0; i < D.length; i++ ){\n    if (is_item_touched_by_user(D[i])){\n      show ? $(\"#item_\" + i).show() : $(\"#item_\" + i).hide();\n    }\n    else{\n      show ? $(\"#item_\" + i).hide() : $(\"#item_\" + i).show();\n    }\n  }\n}\n\n//Hides all items except those with the tag\nfunction show_tag(tag){\n\n  for(var i = 0; i < D.length; i++ ){\n    if (D[i].tags_copy == null){\n      $(\"#item_\" + i).hide();\n    }\n    else if (D[i].tags_copy.indexOf(tag) != -1){\n      $(\"#item_\" + i).show();\n    }\n    else{\n      $(\"#item_\" + i).hide();\n    }\n  }\n}\n\n\n//Hides all items not active in the last *days*\nfunction hide_inactive(days){\n  var today = new Date();\n\n  for(var i = 0; i < D.length; i++ ){\n    if (new Date(D[i].updated_at) < new Date().setDate(today.getDate()-days)){\n      $(\"#item_\" + i).hide();\n    }\n    else{\n      $(\"#item_\" + i).show();\n    }\n  }\n}\n\n//Shows only items that don't have vote_type by current user for statuses defined in statuses option array\nfunction show_unvoted(statuses,vote_type){\n  for(var i = 0; i < D.length; i++ ){\n    if (statuses[D[i].status.name] == undefined){\n      $(\"#item_\" + i).hide();\n    }\n    else if (has_vote_type(D[i],vote_type)){\n      $(\"#item_\" + i).hide();\n    }\n    else{\n      $(\"#item_\" + i).show();\n    }\n  }\n}\n\n//Shows only items that have vote_type by current user for statuses defined in statuses option array\nfunction show_voted(statuses,vote_type,vote_value){\n  for(var i = 0; i < D.length; i++ ){\n    if (statuses[D[i].status.name] == undefined){\n      $(\"#item_\" + i).hide();\n    }\n    else if (has_vote_type(D[i],vote_type,vote_value)){\n      $(\"#item_\" + i).show();\n    }\n    else{\n      $(\"#item_\" + i).hide();\n    }\n  }\n}\n\n//If vote_value is defined, function checks that item has been voted on by curent user with vote_value, otherwise, it just checks that it was voted on by current user\nfunction has_vote_type(item,vote_type,vote_value){\n  for(var i = 0; i < item.issue_votes.length ; i++ ){\n    if (item.issue_votes[i].user_id != currentUserId){continue;}\n\n    if (vote_value == undefined){\n      if (item.issue_votes[i].vote_type == vote_type){return true;}\n    }\n    else{\n      if (item.issue_votes[i].vote_type == vote_type && item.issue_votes[i].points == vote_value){return true;}\n    }\n  }\n  return false;\n}\n\n//returns true if user has voted in any way on item\nfunction is_item_touched_by_user(item){\n  if (item.author_id == currentUserId){\n    return true;\n  }\n\n  for(var i = 0; i < item.issue_votes.length ; i++ ){\n    if (item.issue_votes[i].user_id == currentUserId){return true;}\n  }\n\n  for(var j = 0; j < item.journals.length ; j++ ){\n    if (item.journals[j].user_id == currentUserId){return true;}\n  }\n\n  return false;\n}\n\nfunction search_for(text){\n  text = text.toLowerCase();\n  if (text.length > 1){\n    for(var i = 0; i < D.length; i++ )\n    {\n      if ((text.length == 0) || (D[i].subject.toLowerCase().indexOf(text) > -1))\n      {\n        $(\"#item_\" + i).show().removeHighlight();\n        if (text.length > 0){\n          $(\"#item_content_details_\" + i).texthighlight(text);\n        }\n      }\n      else if (D[i].description.toLowerCase().indexOf(text) > -1)\n      {\n        $(\"#item_\" + i).show().removeHighlight();\n      }\n      else if (D[i].tags_copy != null && D[i].tags_copy.toLowerCase().indexOf(text) > -1)\n      {\n        $(\"#item_\" + i).show().removeHighlight();\n      }\n      else\n      {\n        $(\"#item_\" + i).hide().removeHighlight();\n      }\n      if (String(D[i].id) == text){\n        $(\"#item_\" + i).show();\n      }\n    }\n  }\n\n  if ((text.length == 1)&&($('#filtered_message').is(\":visible\"))){\n    for(var x = 0; x < D.length; x++ )\n    {\n      $(\"#item_\" + x).show().removeHighlight();\n    }\n  }\n\n  if (text.length > 0){\n    $('#filtered_message').show();\n    $('#filter_detail').html('  \"' + text + '\"');\n    update_panel_counts();\n  }\n  else{\n    clear_filters();\n  }\n\n}\n\nfunction search_for_old(text){\n  text = text.toLowerCase();\n  for(var i = 0; i < D.length; i++ )\n  {\n    var subject = D[i].subject.toLowerCase();\n    if ((text.length == 0) || (subject.indexOf(text) > -1))\n    {\n      $(\"#item_\" + i).show().removeHighlight();\n      if (text.length > 0){\n        $(\"#item_content_details_\" + i).texthighlight(text);\n      }\n    }\n    else\n    {\n      $(\"#item_\" + i).hide().removeHighlight();\n    }\n  }\n\n  if (text.length > 0){\n    $('#filtered_message').show();\n    $('#filter_detail').html('  \"' + text + '\"');\n    update_panel_counts();\n  }\n  else{\n    clear_filters();\n  }\n\n}\n\nfunction clear_filters(){\n  $('#filtered_message').hide();\n  $('#fast_search').val('');\n  $('#fast_search').val(''); //clearing fast search\n  $(\"#filter_select option[value='all_top']\").attr('selected', 'selected');  //clearing select\n  hide_inactive(99999);\n  update_panel_counts();\n\n  for(var i = 0; i < D.length; i++ )\n  {\n    $(\"#item_\" + i).show().removeHighlight();\n  }\n\n}\n\nfunction send_item_action(dataId,action,extradata){\n  //Login required\n  if (!is_user_logged_in()){return;}\n\n  var data = \"commit=Create&lock_version=\" + D[dataId].lock_version + extradata;\n\n    var url = url_for({ controller: 'issues',\n                           action    : action,\n              id    : D[dataId].id\n                          });\n\n  $(\"#item_content_icons_editButton_\" + dataId).remove();\n  $(\"#icon_set_\" + dataId).addClass('updating');\n\n\n  $.ajax({\n     type: \"POST\",\n     dataType: \"json\",\n     url: url,\n     data: data,\n     success:    function(html){\n      item_actioned(html,dataId,action);\n    },\n     error:   function (XMLHttpRequest, textStatus, errorThrown) {\n    // typically only one of textStatus or errorThrown will have info\n    // possible valuees for textstatus \"timeout\", \"error\", \"notmodified\" and \"parsererror\n    handle_error(XMLHttpRequest, textStatus, errorThrown, dataId,action);\n    },\n    timeout: 30000 //30 seconds\n   });\n\n  $('.bubbletip').hide();\n}\n\n\n//returns true if item has a description or any journals that have notes\nfunction show_comment(item){\n  for(var i = 0; i < item.journals.length; i++ ){\n      if (item.journals[i].notes != '' && item.journals[i].notes != null){\n        return true;\n      }\n    }\n  return false;\n}\n\n//resize heights of container and panels\nfunction resize(){\n  panel_height = $(window).height() - $('.gt-hd').height() - $('#help_section:visible').height() + 28;// + $('.gt-footer').height() ;\n  // panel_height = $(window).height() - $('.gt-hd').height() + 28;// + $('.gt-footer').height() ;\n  // $(\"#content\").height(panel_height - 35);\n  $(\".list\").height(panel_height - 75);\n  $(\"#panels\").show();\n  recalculate_widths();\n}\n\nfunction insert_panel(position, name, title, visible){\n  var button_style = \"\";\n  if (visible){button_style = 'style=\"display:none;\"';}\n  generate_and_append_panel(position,name,title, visible);\n\n  // $('#panel_buttons').prepend('<input id=\"' + name + '_panel_toggle\" value=\"' + title + ' (0)\" type=\"submit\" onclick=\"show_panel(\\'' + name + '\\');return false;\" class=\"dashboard-button-panel\" ' + button_style + '/>');\n  var button = \"\";\n  button = button + '<a id=\"' + name + '_panel_toggle\" onclick=\"show_panel(\\'' + name + '\\');return false;\" class=\"dashboard-button-panel\" ' + button_style + '>';\n  button = button + '<div id=\"' + name + '_panel_toggle_count\" class=\"panel_button_top\">' + title + ' (0)</div>';\n  button = button + '</a>';\n  $('#panel_buttons').prepend(button);\n\n  $(\"#help_image_panel_\" + name).mybubbletip('#help_panel_' + name, {deltaDirection: 'right', bindShow: 'click'});\n}\n\nfunction generate_and_append_panel(position,name,title, visible){\n  var panel_style = null;\n  if (!visible){panel_style = 'style=\"display:none;\"';}\n\n  var panelHtml = '';\n  panelHtml = panelHtml + \"  <td id='\" + name + \"_panel' class='panel' \" + panel_style + \"'>\";\n  panelHtml = panelHtml + \"<div class='panelHeaderRight'></div>\";\n  panelHtml = panelHtml + \"<div class='panelHeaderLeft'></div>\";\n  panelHtml = panelHtml + \"<div id='panel_header_\" + name +\"'class='panelHeader'>\";\n  panelHtml = panelHtml + \"  <a href='javascript:void(0)' class='closePanelLoading panelLink' id='\" + name + \"_close' title='Close panel' onclick='close_panel(\\\"\" + name + \"\\\");return false;'></a>\";\n  panelHtml = panelHtml + \"  <span id='\" + name +\"_panel_title' class='panelTitle'>\" + title + \" (0)</span>\";\n  panelHtml = panelHtml + '    <img id=\"help_image_panel_' + name + '\" src=\"/images/help.png\" class=\"help_question_mark\">';\n  panelHtml = panelHtml + \"</div>\";\n  panelHtml = panelHtml + \"<div id='\" + name + \"_list' class='list'>\";\n  panelHtml = panelHtml + \"  <div id='\" + name + \"_items' class='items'>\";\n  panelHtml = panelHtml + \"  <div id='\" + name + \"_start_of_list' class='startOfList'></div>\";\n  panelHtml = panelHtml + \"  <div id='\" + name + \"_end_of_list' class='endOfList'></div>\";\n  panelHtml = panelHtml + \"  </div>\";\n  panelHtml = panelHtml + \"</div>\";\n  panelHtml = panelHtml + \"</td>\";\n  $(\"#main_row\").append(panelHtml);\n  $(\"#content\").height(panel_height - 35);\n  $(\".list\").height(panel_height - 75);\n}\n\nfunction update_panel_counts(){\n  update_panel_count('new');\n  update_panel_count('open');\n  update_panel_count('inprogress');\n  update_panel_count('done');\n  update_panel_count('canceled');\n  // update_panel_count('archived');\n\n  adjust_button_container_widths();\n\n}\n\nfunction update_panel_count(name, skip_button){\n  try{\n    if ($(\"#\" + name + '_panel').is(\":visible\")){\n      count = $(\"#\" + name + \"_start_of_list > *:visible\").length;\n    }\n    else{\n      count = $(\"#\" + name + \"_start_of_list > *\").length;\n    }\n\n    $(\"#\" + name + '_panel_title').html($(\"#\" + name + '_panel_title').html().replace(/\\([0-9]*\\)/,\"(\" + count + \")\"));\n    if (!skip_button){\n      $(\"#\" + name + '_panel_toggle_count').html($(\"#\" + name + '_panel_toggle_count').html().replace(/\\([0-9]*\\)/,\"(\" + count + \")\"));\n    }\n    return true;\n  }\n  catch(err){\n    return false;\n  }\n}\n\nfunction close_panel(name){\n  $('#' + name + '_panel').hide();\n  $('#' + name + '_panel_toggle').show();\n  recalculate_widths();\n  if (name == \"new\"){keyboard_shortcuts = true;} //If we're closing the new panel, then we want keyboard shortcuts to be on again, in case they were off\n  if (name.indexOf(\"retro\") == 0){ //If we're closing a retrospective panel, we untoggle the expander button\n    retroId = name.split('_')[1];\n    $('#done_itemList_' + retroId + '_toggle_expanded_button').attr('src','/images/iteration_expander_closed.png');\n  }\n}\n\nfunction show_panel(name){\n  $('#' + name + '_panel').show();\n  $('#' + name + '_panel_toggle').hide();\n  recalculate_widths();\n  $('#' + name + '_close').addClass('closePanel').removeClass('closePanelLoading');\n}\n\n// Sorts items in a plane by priority (highest first) followed by created date (oldest first)\nfunction sort_panel(name){\n    var listitems = $('#' + name + '_start_of_list').children().get();\n\n     //Setting highest_pri to priority of first item in open panel\n    // if ((name == \"open\") && (listitems.length > 0)){\n    //   var first_item_id = listitems[0].id.replace(/item_/g,'');\n    //   // var first_item_data_id = ITEMHASH[\"item\" + first_item_id];\n    //   //BUGBUG: listitems.length could be greater than 0 if it has only one item that's being edited\n    //   highest_pri = D[first_item_id].pri;\n    //   }\n\n    listitems.sort(function(a, b) {\n       var compA = a.id.replace(/item_/g,'');\n       var compB = b.id.replace(/item_/g,'');\n\n      //        if (name == \"open\"){\n      // if (D[compA].pri > highest_pri) { highest_pri = D[compA].pri;}\n      //            if (D[compB].pri > highest_pri) { highest_pri = D[compB].pri;}\n      //        }\n\n       if (compA == 'new_link') {\n        return -1;\n      }\n      else if (compB == 'new_link') {\n          return 1;\n      }\n        else if (D[compA].agree_total + D[compA].agree_total_nonbind > D[compB].agree_total + D[compB].agree_total_nonbind) {\n      return -1;\n      } else if (D[compA].agree_total + D[compA].agree_total_nonbind < D[compB].agree_total + D[compB].agree_total_nonbind) {\n        return 1;\n      } else if (new Date(D[compA].created_at) > new Date(D[compB].created_at)) {\n        return 1;\n      } else {\n        return -1;\n      }\n    });\n\n\n    $('#' + name + '_start_of_list').children().remove();\n\n    $.each(listitems, function() {\n        $('#' + name + '_start_of_list').append(this);\n        });\n\n    // if (name == \"open\"){\n    //   show_start_buttons();\n    // }\n}\n\n// function show_start_buttons(){\n//   $(\".action_button_start\").hide();\n//   for (var i=0; i < startable_priority_tiers; i++){\n//     $(\".pri_\" + (highest_pri - i)).find(\".action_button_start\").show();\n//   }\n//   $(\".points_0\").find(\".action_button_start\").show();\n// }\n\n\nfunction recalculate_widths(){\n  var new_width = $('#main').width() / $('.panel:visible').length;\n  $('.panel:visible').width(new_width);\n  adjust_button_container_widths();\n\n}\n\nfunction expand_item(dataId){\n  $('#item_' + dataId).replaceWith(generate_item_edit(dataId));\n\n  //arming file upload\n  $('#file_upload_' + dataId).fileUploadUI({\n        uploadTable: $('#files_' + dataId),\n        downloadTable: $('#files_' + dataId),\n        buildUploadRow: function (files, index) {\n            return $('<tr><td>' + files[index].name + '<\\/td>' +\n                    '<td class=\"file_upload_progress\"><div><\\/div><\\/td>' +\n                    '<td class=\"file_upload_cancel\">' +\n                    '<button class=\"ui-state-default ui-corner-all\" title=\"Cancel\">' +\n                    '<span class=\"ui-icon ui-icon-cancel\">Cancel<\\/span>' +\n                    '<\\/button><\\/td><\\/tr>');\n        },\n        buildDownloadRow: function (attachment) {\n            return $('<tr><td><a class=\"icon icon-attachment\" href=\"/attachments/' + attachment.id + '/' + attachment.filename + '\">' + attachment.filename + '</a> (' + attachment.filesize + ' Bytes)<\\/td><\\/tr>');\n        }\n    });\n\n  $.fn.getGravatar.getUrl({\n          avatarContainer: '#gravatar_' + dataId,\n          avatarSize:27\n      },\n      D[dataId].author.mail_hash\n  );\n\n  $('#new_comment_' + dataId).watermark('watermark',new_comment_text);\n  $('#new_comment_' + dataId).autogrow().mentions(projectId);\n  $('#new_todo_' + dataId).watermark('watermark',new_todo_text);\n  $('#edit_description_' + dataId).autogrow().mentions(projectId);\n  $('#help_image_description_' + dataId).mybubbletip($('#help_description'), {\n    deltaDirection: 'right',\n    delayShow: 300,\n    delayHide: 100,\n    offsetLeft: 0,\n    bindShow: 'click'\n  });\n  $('#help_image_requestid_' + dataId).mybubbletip($('#help_requestid'), {\n    deltaDirection: 'right',\n    delayShow: 300,\n    delayHide: 100,\n    offsetLeft: 0,\n    bindShow: 'click'\n  });\n  $('#issue_tags_edit_' + dataId).tagsInput({\n     'autocomplete_url': 'http://localhost:3000/projects/' + projectId + '/all_tags',\n     'autocomplete':{selectFirst:true,width:'100px',autoFill:true},\n     'issue_id':D[dataId].id,\n     'height':'20px',\n     'width':$('#edit_title_input_' + dataId).width() - 30,\n     'defaultText':'add a tag'\n  });\n\n  make_text_boxes_toggle_keyboard_shortcuts();\n  $('#item_' + dataId).parent().parent().scrollTo('#item_' + dataId, 500);\n\n}\n\nfunction collapse_item(dataId,check_for_save){\n  //save subject and title if they changed\n  // if(check_for_save){\n  //   if (($('#edit_title_input_' + dataId).val() != D[dataId].subject) || ($('#edit_description_' + dataId).val() != D[dataId].description)){\n  //     save_edit_item(dataId);\n  //     return false;\n  //   }\n  // }\n\n  $(\"#edit_item_\" + dataId).replaceWith(generate_item(dataId));\n  $(\"#item_content_\" + dataId).effect(\"highlight\", {mode: 'show'}, 5000);\n  keyboard_shortcuts = true;\n  // show_start_buttons();\n  adjust_button_container_widths();\n  return false;\n}\n\nfunction save_new_item(prioritize){\n    if (($('#new_title_input').val() == default_new_title) || ($('#new_title_input').val() == ''))\n    {\n  alert('Please enter a title');\n  return false;\n    }\n\n\n    var data = \"commit=Create&project_id=\" + projectId +\n        // \"&issue[tracker_id]=\" + $('#new_story_type').val() +\n        \"&issue[subject]=\" + encodeURIComponent($('#new_title_input').val()) +\n        \"&issue[description]=\" + encodeURIComponent($('#new_description').val()) +\n        \"&issue[tags_copy]=\" + encodeURIComponent($('#new_tags').val()) +\n        \"&estimate=\" + $('#new_story_complexity').val() +\n        \"&prioritize=\" + prioritize;\n\n  if (new_attachments.length > 0){\n    data = data + \"&attachments=\" + new_attachments.join(\",\");\n    new_attachments = [];\n  }\n\n    var url = url_for({ controller: 'issues',\n                           action    : 'new'\n                          });\n\n  $(\"#new_item_wrapper\").html('<div id=\"loading\" class=\"loading\"> Adding...</div>');\n\n  $.ajax({\n     type: \"POST\",\n     dataType: \"json\",\n     url: url,\n     data: data,\n     success:    function(html){\n          item_added(html);\n    },\n     error:   function (XMLHttpRequest, textStatus, errorThrown) {\n    // typically only one of textStatus or errorThrown will have info\n    // possible valuees for textstatus \"timeout\", \"error\", \"notmodified\" and \"parsererror\n    remove_new_link();\n    add_new_link();\n    handle_error(XMLHttpRequest, textStatus, errorThrown, false, \"add\");\n    },\n    timeout: 30000 //30 seconds\n   });\n\n\n  return false;\n}\n\nfunction save_edit_item(dataId){\n\n    if (($('#edit_title_input_' + dataId).val() == default_new_title) || ($('#edit_title_input_' + dataId).val() == ''))\n    {\n  alert('Please enter a title');\n  return false;\n    }\n\n    var data = \"commit=Submit&lock_version=\" + D[dataId].lock_version +\n        \"&project_id=\" + projectId +\n        \"&id=\" + D[dataId].id +\n        \"&issue[subject]=\" + encodeURIComponent($('#edit_title_input_' + dataId).val()) +\n        \"&issue[description]=\" + encodeURIComponent($('#edit_description_' + dataId).val());\n\n    var url = url_for({ controller: 'issues',\n                        action    : 'edit'\n                      });\n\n    $(\"#edit_item_\" + dataId).replaceWith(generate_item(dataId));\n    $(\"#item_content_icons_editButton_\" + dataId).remove();\n    $(\"#icon_set_\" + dataId).addClass('updating');\n\n    $.ajax({\n  type: \"POST\",\n  dataType: \"json\",\n  url: url,\n  data: data,\n  success:    function(html){\n      item_updated(html, dataId);\n  },\n  error:   function (XMLHttpRequest, textStatus, errorThrown) {\n      // typically only one of textStatus or errorThrown will have info\n      // possible valuees for textstatus \"timeout\", \"error\", \"notmodified\" and \"parsererror\n      handle_error(XMLHttpRequest, textStatus, errorThrown, dataId, \"edit\");\n  },\n  timeout: 30000 //30 seconds\n    });\n\n    return false;\n}\n\nfunction cancel_new_item(dataId){\n  $(\"#new_item_wrapper\").remove();\n  $(\"#item_new_link\").show();\n\n  keyboard_shortcuts = true;\n  return false;\n}\n\nfunction item_added(item){\n  $(\"#new_item_wrapper\").remove();\n  D.push(item);\n  ITEMHASH[\"item\" + item.id] = D.length - 1;\n  add_item(D.length-1,\"top\",false);\n  keyboard_shortcuts = true;\n  // show_start_buttons();\n  update_panel_counts();\n  remove_new_link();\n  add_new_link();\n  return false;\n}\n\nfunction item_actioned(item, dataId, action){\n\n  collapse_item(dataId,false);\n  var pre_status = D[dataId].status.name;\n\n  var status_changed = (pre_status != item.status.name);\n\n  // New and estimate status are the same as far as the dashboard is concerned\n  if ((item.status.name == 'Estimate' && pre_status == 'New')||(item.status.name == 'New' && pre_status == 'Estimate')||(item.status.name == 'Open' && pre_status == 'New')||(item.status.name == 'New' && pre_status == 'Open'))\n  {\n    status_changed = false;\n  }\n\n  D[dataId] = item;\n  $('#item_lightbox_' + dataId).replaceWith(generate_item_lightbox(dataId));\n  update_lightbox_lock_version(dataId);\n\n  if (item.retro_id > 1){ //an item has moved into a retrospective, we remove it from the dashboard.\n    $(\"#item_\" + dataId).remove();\n    // update_panel_counts();\n  }\n  else if ((!status_changed) || (item.status.name == 'Accepted' && action != \"data_refresh\") || (item.status.name == 'Rejected' && action != \"data_refresh\"))\n  {\n    $('#item_' + dataId).replaceWith(generate_item(dataId));\n    // show_start_buttons();\n    //tODO: highlight the right item here\n  }\n  else\n  {\n    $(\"#item_\" + dataId).remove();\n    add_item(dataId,\"bottom\",action != \"data_refresh\");\n    // update_panel_counts();\n  }\n\n  keyboard_shortcuts = true;\n\n  $(\"#item_content_\" + dataId).effect(\"highlight\", {mode: 'show'}, 5000);\n\n  //we don't sort panels on data refresh\n  if (action != \"data_refresh\"){\n    if (action == \"add\") {\n      sort_panel('new');\n      $(\"#\" + item.status.name.toLowerCase() + \"_items\").scrollTo('#item_' + dataId, 300);\n    }\n\n    // if (action == \"open\" || item.status.name == \"Open\" || pre_status == \"Open\") {sort_panel(\"open\");}\n    // if ((action == \"deprioritize\")||(action == \"prioritize\")||(item.status.name == \"Open\")) {\n    //   sort_panel(item.status.name.toLowerCase());\n    //   $(\"#\" + item.status.name.toLowerCase() + \"_items\").scrollTo('#item_' + dataId, 300);\n    // }\n\n    adjust_button_container_widths();\n    save_local_data();\n    update_panel_counts();\n  }\n\n  //show/hide startable button if item is open\n  if (is_startable(item) == true){\n    $(\"#item_content_buttons_start_button_\" + dataId).show();\n  }\n  else{\n    $(\"#item_content_buttons_start_button_\" + dataId).hide();\n  }\n\n  return false;\n}\n\nfunction item_prioritized(item, dataId,action){\n  //sort_panel(item.status.name);\n  //TODO: put item in correct order on this list\n  D[dataId] = item;\n  $('#' + item.id).addClass('pri_' + item.pri);\n  $('#' + item.id).removeClass('pri_' + item.pri - 1);\n  $('#' + item.id).removeClass('pri_' + item.pri + 1);\n\n  return false;\n}\n\n\nfunction item_estimated(item, dataId){\n  D[dataId] = item;\n  $(\"#item_\" + dataId).replaceWith(generate_item(dataId));\n  $('#item_lightbox_' + dataId).replaceWith(generate_item_lightbox(dataId));\n  update_lightbox_lock_version(dataId);\n\n\n  keyboard_shortcuts = true;\n  return false;\n}\n\nfunction item_updated(item, dataId){\n  D[dataId] = item;\n  $(\"#item_\" + dataId).replaceWith(generate_item(dataId));\n  $('#item_lightbox_' + dataId).replaceWith(generate_item_lightbox(dataId));\n  update_lightbox_lock_version(dataId);\n\n\n  keyboard_shortcuts = true;\n  return false;\n}\n\nfunction comment_added(item, dataId){\n  $(\"#post_comment_button_\" + dataId).show();\n  D[dataId] = item;\n  $('#comments_container_' + dataId).replaceWith(generate_comments_section(dataId,false));\n  $('#new_comment_' + dataId).watermark('watermark',new_comment_text);\n  $('#new_comment_' + dataId).autogrow().mentions(projectId);\n}\n\nfunction todo_added(item, dataId){\n  D[dataId] = item;\n  $('#todo_container_' + item.id).html(generate_todos(dataId,false,true));\n}\n\nfunction todo_updated(item, dataId){\n  D[dataId] = item;\n  // $('#todo_container_' + item.id).html(generate_todos(item,false));\n}\n\nfunction ensure_numericality_of_num_hours(num_hours) {\n    if(num_hours == '') {\n  alert('Please enter the estimated number of hours for this hourly item.');\n  return false;\n    }\n    else if(isNaN(num_hours)) {\n  alert('Please enter a number for the estimated number of hours');\n  return false;\n    }\n\n    return true;\n}\n\nfunction isNumeric(form_value)\n{\n    if (form_value.match(/^[-+]?\\d+(\\.\\d+)?$/) == null)\n        return false;\n    else\n        return true;\n}\n\nfunction sortoptions(sort)\n{\n  var $this = $(this);\n  // sort\n  $this.removeOption(\"0\"); //removing loading\n  $this.removeOption(\"1\"); //removing administrator\n  $this.removeOption(currentUserId); //removing self\n  $this.sortOptions();\n}\n\nfunction generate_complexity_row(){\n  var html = '';\n  html = html + '                <tr id=\"complexity_row\">';\n  html = html + '                  <td class=\"letContentExpand\" colspan=\"1\">';\n  html = html + '                    <div>';\n  html = html + '                      <select id=\"new_story_complexity\" class=\"gt-SdField\" name=\"new_story_complexity\" >';\n  html = html +                         generate_complexity_dropdown();\n  html = html + '                      </select>';\n  html = html + '                    </div>';\n  html = html + '                  </td>';\n  html = html + '                  <td class=\"gt-SdLabelIcon\" colspan=\"1\">';\n  html = html + '                    <div class=\"gt-SdLabelIcon\">';\n  html = html + '                      <img src=\"/images/dice_No.png\" id=\"new_story_type_image\" name=\"new_story_type_image\">';\n  html = html + '                    </div>';\n  html = html + '                  </td>';\n  html = html + '                  <td class=\"helpIcon lastCell\" colspan=\"1\">';\n  html = html + '                    <div class=\"helpIcon\" id=\"story_newStory_details_help_story_types\">';\n  html = html + '                      <img id=\"help_image_complexity\" src=\"/images/question_mark.gif\"  class=\"help_question_mark\">';\n  html = html + '                    </div>';\n  html = html + '                  </td>';\n  html = html + '                </tr>';\n  return html;\n\n}\n\n\nfunction generate_complexity_dropdown() {\n    var html='';\n  if (credits_enabled){\n    html += '<option selected=\"true\" value=\"\">Credits (optional)</option>';\n\n    for(var i = 0;i<7;i++) {\n\n    credits = point_factor[i] * credit_base;\n    html += '<option value=\"' +  credits + '\">';\n    html += credits + \" credits\";\n    html += '</option>';\n      }\n\n    html += '<option value=\"-1\">Don\\'t know</option>';\n  }\n  else{\n    html += '<option value=\"0\">0 - Real easy</option>';\n    html += '<option value=\"' + point_factor[1] * credit_base + '\">1</option>';\n    html += '<option value=\"' + point_factor[2] * credit_base + '\">2</option>';\n    html += '<option selected=\"true\" value=\"' + point_factor[3] * credit_base + '\">3 - Average complexity</option>';\n    html += '<option value=\"' + point_factor[4] * credit_base + '\">4</option>';\n    html += '<option value=\"' + point_factor[5] * credit_base + '\">5</option>';\n    html += '<option value=\"' + point_factor[6] * credit_base + '\">6 - Super hard</option>';\n    html += '<option value=\"-1\">Don\\'t know</option>';\n  }\n\n    return html;\n}\n\n\nfunction new_item(){\n\nnew_attachments = [];\n\n//Login required\nif (!is_user_logged_in()){return;}\n\nkeyboard_shortcuts = false;\n\n\n\n$(\"#new_item_wrapper\").remove();\nhtml = '';\nhtml = html + '  <div class=\"item\" id=\"new_item_wrapper\">';\nhtml = html + '    <div class=\"storyItem unscheduled unestimatedText underEdit\" id=\"icebox_itemList_storynewStory_content\">';\n// html = html + '     <form action=\"#\">';\nhtml = html + '      <div class=\"itemCollapsedHeader\">';\nhtml = html + '        <div class=\"itemCollapsedInput\">';\nhtml = html + '          <input id=\"new_title_input\" class=\"titleInputField\" name=\"title_input\" value=\"\" type=\"text\">';\nhtml = html + '        </div>';\nhtml = html + '      </div>';\nhtml = html + '      <div>';\nhtml = html + '        <div id=\"new_details\" class=\"gt-Sd\">';\nhtml = html + '            <table class=\"gt-SdTable\">';\nhtml = html + '              <tbody>';\nhtml = html + generate_complexity_row();\nhtml = html + '                <tr>';\nhtml = html + '                  <td class=\"letContentExpand\" colspan=\"1\">';\nhtml = html + '                    <div>';\nhtml = html + '          <input id=\"new_tags\" class=\"issue-tags\" name=\"new_tas\" value=\"\" type=\"text\" size=\"30\">';\nhtml = html + '                    </div>';\nhtml = html + '                  </td>';\nhtml = html + '                  <td class=\"gt-SdLabelIcon\" colspan=\"1\">';\nhtml = html + '                    <div class=\"gt-SdLabelIcon\">';\nhtml = html + '                      <img src=\"/images/tag_blue.png\" id=\"new_story_type_image\" name=\"new_story_type_image\">';\nhtml = html + '                    </div>';\nhtml = html + '                  </td>';\nhtml = html + '                  <td class=\"helpIcon lastCell\" colspan=\"1\">';\nhtml = html + '                    <div class=\"helpIcon\" id=\"story_newStory_details_help_story_types\">';\nhtml = html + '                      <img id=\"help_image_tags_new\" src=\"/images/question_mark.gif\"  class=\"help_question_mark\">';\nhtml = html + '                    </div>';\nhtml = html + '                  </td>';\nhtml = html + '                </tr>';\nhtml = html + '              </tbody>';\nhtml = html + '            </table>';\nhtml = html + '            <div class=\"section\">';\nhtml = html + '              <table class=\"storyDescriptionTable\">';\nhtml = html + '                <tbody>';\nhtml = html + '                  <tr>';\nhtml = html + '                    <td class=\"header\">';\nhtml = html + '                      <div>';\nhtml = html + '                        Description';\nhtml = html + '                      </div>';\nhtml = html + '                    </td>';\nhtml = html + '                    <td class=\"lastCell\">';\nhtml = html + '                      <div class=\"helpIcon\">';\nhtml = html + '                        <img id=\"help_image_description_new\" src=\"/images/question_mark.gif\"  class=\"help_question_mark\">';\nhtml = html + '                      </div>';\nhtml = html + '                    </td>';\nhtml = html + '                  </tr>';\nhtml = html + '                  <tr>';\nhtml = html + '                    <td colspan=\"5\">';\nhtml = html + '                      <div>';\nhtml = html + '                        <textarea class = \"textAreaFocus\" id=\"new_description\" rows=\"2\" cols=\"20\" name=\"story[description]\"></textarea>     ';\nhtml = html + '                      <div>';\nhtml = html + '                          (Format using *<b>bold</b>* and _<i>italic</i>_ text.)';\nhtml = html + '                        </div>';\nhtml = html + '                      </div>';\nhtml = html + '                    </td>';\nhtml = html + '                  </tr>';\n\nhtml = html + '                  <tr><td colspan=\"5\">';\nhtml = html + '                  <table id=\"files_new\" class=\"attachments\"></table>';\nhtml = html + '                  <form id=\"file_upload_new\" action=\"/issues/0/attachments/create?container_type=Issue\" method=\"POST\" enctype=\"multipart/form-data\">';\nhtml = html + '                  <input type=\"file\" name=\"file\" multiple>';\nhtml = html + '                  <button>Upload</button>';\nhtml = html + '                  <a class=\"icon icon-attachment\" href=\"#\">Attach files</a>';\nhtml = html + '                  </form>';\nhtml = html + '                  </td></tr>';\n\nhtml = html + '                </tbody>';\nhtml = html + '              </table>';\nhtml = html + '            <table class=\"gt-SdTable\">';\nhtml = html + '              <tbody>';\nhtml = html + '                <tr>';\nhtml = html + '                  <td>';\nhtml = html + '                    <div class=\"gt-SdButton\">';\nhtml = html + '                      <input id=\"new_save_button\" value=\"Create\" type=\"submit\" onclick=\"save_new_item(false);return false;\">';\nhtml = html + '                    </div>';\nhtml = html + '                  </td>';\nhtml = html + '                  <td>';\nhtml = html + '                    <div class=\"gt-SdButton\">';\nhtml = html + '                      <input id=\"new_save_button\" value=\"Create & Prioritize\" type=\"submit\" onclick=\"save_new_item(true);return false;\">';\nhtml = html + '                    </div>';\nhtml = html + '                  </td>';\nhtml = html + '                  <td>';\nhtml = html + '                    <div class=\"gt-SdButton\">';\nhtml = html + '                      <input id=\"new_cancel_button\" value=\"Cancel\" type=\"submit\" onclick=\"cancel_new_item();return false;\">';\nhtml = html + '                    </div>';\nhtml = html + '                  </td>';\nhtml = html + '                  <td>';\nhtml = html + '                  </td>';\nhtml = html + '                </tr>';\nhtml = html + '              </tbody>';\nhtml = html + '            </table>';\nhtml = html + '            </div>';\nhtml = html + '        </div>';\nhtml = html + '      </div>';\n// html = html + '    </form>';\nhtml = html + '    </div>';\nhtml = html + '  </div>';\n\n\nshow_panel('new');\n$(\"#item_new_link\").hide();\n$(\"#new_items\").prepend(html);\n\n$(\"#new_title_input\").val(default_new_title).select();\n$(\"#new_description\").autogrow().mentions(projectId);\nmake_text_boxes_toggle_keyboard_shortcuts();\n\n$('#help_image_description_new').mybubbletip($('#help_description'), {\n  deltaDirection: 'right',\n  delayShow: 300,\n  delayHide: 100,\n  offsetLeft: 0,\n  bindShow: 'click'\n});\n\n$('#help_image_feature_new').mybubbletip($('#help_feature'), {\n  deltaDirection: 'up',\n  delayShow: 300,\n  delayHide: 100,\n  offsetTop: 0,\n  bindShow: 'click'\n});\n\n$('#help_image_tags_new').mybubbletip($('#help_tags'), {\n  deltaDirection: 'up',\n  delayShow: 300,\n  delayHide: 100,\n  offsetTop: 0,\n  bindShow: 'click'\n});\n\nif (credits_enabled){\n  complexity_help_id = \"#help_complexity_credits\";\n}\nelse{\n  complexity_help_id = \"#help_complexity_no_credits\";\n}\n\n$('#help_image_complexity').mybubbletip($(complexity_help_id), {\n  deltaDirection: 'up',\n  delayShow: 300,\n  delayHide: 100,\n  offsetTop: 0,\n  bindShow: 'click'\n});\n\n//arming file upload\n$('#file_upload_new').fileUploadUI({\n    uploadTable: $('#files_new'),\n    downloadTable: $('#files_new'),\n    buildUploadRow: function (files, index) {\n        return $('<tr><td>' + files[index].name + '<\\/td>' +\n                '<td class=\"file_upload_progress\"><div><\\/div><\\/td>' +\n                '<td class=\"file_upload_cancel\">' +\n                '<button class=\"ui-state-default ui-corner-all\" title=\"Cancel\">' +\n                '<span class=\"ui-icon ui-icon-cancel\">Cancel<\\/span>' +\n                '<\\/button><\\/td><\\/tr>');\n    },\n    buildDownloadRow: function (attachment) {\n        return $('<tr><td><a class=\"icon icon-attachment\" href=\"/attachments/' + attachment.id + '/' + attachment.filename + '\">' + attachment.filename + '</a> (' + attachment.filesize + ' Bytes)<\\/td><\\/tr>');\n    },\n  onComplete: function (event, files, index, xhr, handler){\n    new_attachments.push(handler.parseResponse(xhr).id);\n  }\n});\n\n$(\"#new_items\").scrollTo( '#new_item_wrapper', 800);\n\n$('#new_tags').tagsInput({\n   'autocomplete_url': 'http://localhost:3000/projects/' + projectId + '/all_tags',\n   'autocomplete':{selectFirst:true,width:'100px',autoFill:true},\n   'issue_id':null,\n   'height':'20px',\n   'width':$('#issue_tags_container').width(),\n   'defaultText':'add a tag'\n});\n\n\n}\n\nfunction is_item_editable(dataId) {\n  if (!currentUserCanEditIssue){\n    return false;\n  }\n  return !(D[dataId].status.name == 'Committed' ||\n     D[dataId].status.name == 'Done'      ||\n     D[dataId].status.name == 'Accepted'      ||\n     D[dataId].status.name == 'Rejected'      ||\n     D[dataId].status.name == 'Canceled'  ||\n     D[dataId].status.name == 'Archived');\n}\n\nfunction is_item_todos_editable(dataId) {\n  if (!currentUserCanEditIssue){\n    return false;\n  }\n  return !(\n     D[dataId].status.name == 'Done'      ||\n     D[dataId].status.name == 'Accepted'      ||\n     D[dataId].status.name == 'Rejected'      ||\n     D[dataId].status.name == 'Canceled'  ||\n     D[dataId].status.name == 'Archived');\n\n}\n\n\nfunction is_item_joinable(item) {\n  return true;\n}\n\nfunction is_item_estimatable(item) {\n  return true;\n  return (!credits_enabled);\n}\n\n\nfunction is_tracker_editable(dataId) {\n  return true;\n}\n\nfunction generate_expense_amount_editor(points,dataId){\n  var html = '';\n  html = html + '<div id=\"item_expense_amount_' + dataId + '\">Amount $' + points;\n  if (dataId == \"new\"){\n    html = html + ' (<a href=\"\" onclick=\"prompt_for_expense_amount(' + points + ', \\'' + dataId + '\\');return false;\">edit</a>)';\n  }\n  html = html + '          <input id=\"new_expense_amount_' + dataId + '\" class=\"hidden\" name=\"title_input\" value=\"' + points + '\" type=\"text\">';\n  html = html + '</div>';\n  return html;\n}\n\nfunction generate_item_edit(dataId){\n\nvar item_editable = is_item_editable(dataId);\nvar tracker_editable = is_tracker_editable(dataId);\n\n// The subject and description input elements, and the issue type\n// combo box are rendered readonly/disable if the item is not editable\nvar readonly = !item_editable ? \"readonly\" : \"\";\nvar disabled = !item_editable || !tracker_editable  ? \"disabled\" : \"\";\n\nvar html = '';\nhtml = html + '  <div class=\"item\" id=\"edit_item_' + dataId + '\">';\nhtml = html + '    <div class=\"storyItem underEdit\" id=\"editItem_content_' + dataId + '\">';\n// html = html + '     <form action=\"#\">';\nhtml = html + '      <div class=\"itemCollapsedHeader\">';\nhtml = html + '     <img id=\"item_content_icons_editButton_' + dataId + '\" class=\"toggleExpandedButton\" src=\"/images/story_expanded.png\" title=\"Collapse\" alt=\"Collapse\" onclick=\"collapse_item(' + dataId + ',true);return false;\">';\nhtml = html + '<div id=\"icon_set_' + dataId + '\" class=\"left\">&nbsp;</div>';\nhtml = html + '        <div class=\"itemCollapsedInput\">';\nhtml = html + '          <input id=\"edit_title_input_' + dataId + '\" class=\"titleInputField\" name=\"title_input\" value=\"' + h(D[dataId].subject) + '\" type=\"text\" ' + readonly + '>';\nhtml = html + '        </div>';\nhtml = html + '      </div>';\nhtml = html + '      <div>';\nhtml = html + '        <div id=\"edit_details_' + dataId + '\" class=\"gt-Sd\">';\nhtml = html + '            <table class=\"gt-SdTable\">';\nhtml = html + '              <tbody>';\nhtml = html + '                <tr>';\nif (item_editable){\n  html = html + '                  <td>';\n  html = html + '                    <div class=\"gt-SdButton\">';\n  html = html + '                      <input id=\"edit_save_button' + dataId + '\" value=\"Save\" type=\"submit\" onclick=\"save_edit_item(' + dataId + ');return false;\">';\n  html = html + '                    </div>';\n  html = html + '                  </td>';\n  html = html + '                  <td>';\n  html = html + '                    <div class=\"gt-SdButton\">';\n  html = html + '                      <input id=\"edit_cancel_button' + dataId + '\" value=\"Cancel\" type=\"submit\" onclick=\"collapse_item(' + dataId + ',false);return false;\">';\n  html = html + '                    </div>';\n  html = html + '                  </td>';\n}\nhtml = html + '                  <td>';\nhtml = html + '                    <div class=\"gt-SdButton\">';\nhtml = html + '                      <input id=\"edit_full_screen_button\" value=\"Full Screen\" type=\"submit\" onclick=\"full_screen(' + dataId + ');return false;\">';\nhtml = html + '                    </div>';\nhtml = html + '                  </td>';\nhtml = html + '                  <td style=\"width:100%;\">';\nhtml = html + '                    <div class=\"gt-SdActionButton\">';\nhtml = html + buttons_for(dataId,true);\nhtml = html + '                    </div>';\nhtml = html + '                  </td>';\nhtml = html + '                </tr>';\nhtml = html + '              </tbody>';\nhtml = html + '            </table>';\nhtml = html + '            <table class=\"gt-SdTable\">';\nhtml = html + '              <tbody>';\nhtml = html + '                <tr>';\nhtml = html + '                  <td class=\"letContentExpand\" colspan=\"1\">';\nhtml = html + '                    <div>';\nhtml = html + '            <input type=\"text\" id=\"issue_tags_edit_' + dataId + '\" size=\"60\" value=\"' + D[dataId].tags_copy + '\"></input>';\nhtml = html + '                    </div>';\nhtml = html + '                  </td>';\nhtml = html + '                  <td class=\"helpIcon\">';\n// html = html + '                      <img id=\"help_image_tag_' + dataId + '\" src=\"/images/question_mark.gif\" class=\"help_question_mark\">';\nhtml = html + '                  </td>';\nhtml = html + '                  <td class=\"lastCell created_by\">';\nhtml = html + '                <img id=\"gravatar_' + dataId +'\" display=\"hidden\" class=\"gravatar right\" src=\"\"/>';\nhtml = html +                      D[dataId].author.firstname + ' ' + D[dataId].author.lastname + '&nbsp;';\nhtml = html + '                  </td>';\nhtml = html + '                </tr>';\nhtml = html + '                <tr id=\"assigned_to_' + dataId + '\">';\nhtml = html + '                  <td class=\"letContentExpand\" colspan=\"3\">';\nhtml = html + '                  <div id=\"assigned_to_text_' + dataId + '\">';\nhtml = html + '</div>';\nhtml = html + '                  </td>';\nhtml = html + '                </tr>';\nhtml = html + '              </tbody>';\nhtml = html + '            </table>';\nhtml = html + '            <div class=\"section\">';\nhtml = html + '              <table class=\"storyDescriptionTable\">';\nhtml = html + '                <tbody>';\nhtml = html + '                  <tr>';\nhtml = html + '                    <td class=\"header\">';\nhtml = html + '                      <div>';\nhtml = html + '                        Description';\nhtml = html + '                      </div>';\nhtml = html + '                    </td>';\nhtml = html + '                    <td class=\"lastCell\">';\nhtml = html + '                      <div class=\"helpIcon_Description\">';\nhtml = html + '                        <img id=\"help_image_description_' + dataId + '\" src=\"/images/question_mark.gif\"  class=\"help_question_mark\">';\nhtml = html + '                      </div>';\nhtml = html + '                    </td>';\nhtml = html + '                  </tr>';\nhtml = html + '                  <tr>';\nhtml = html + '                    <td colspan=\"5\">';\nhtml = html + '                      <div>';\nhtml = html + '                        <textarea class = \"textAreaFocus\" id=\"edit_description_' + dataId + '\" rows=\"1\" cols=\"20\" name=\"story[description]\" ' + readonly + '>' + h(D[dataId].description) + '</textarea>     ';\nhtml = html + '                      <div>';\nhtml = html + '                          (Format using *<b>bold</b>* and _<i>italic</i>_ text.)';\nhtml = html + '                        </div>';\nhtml = html + '                      </div>';\nhtml = html + '                    </td>';\nhtml = html + '                  </tr>';\nhtml = html + '                </tbody>';\nhtml = html + '              </table>';\nhtml = html + '            </div>';\n\n//todos\nhtml = html + generate_todo_section(dataId);\n\n//comments\nhtml = html + generate_comments_section(dataId);\nhtml = html + generate_attachments_section(dataId);\n\n// request id\nhtml = html + '            <div class=\"section\">';\nhtml = html + '              <table class=\"storyDescriptionTable\">';\nhtml = html + '                <tbody>';\nhtml = html + '                  <tr>';\nhtml = html + '                    <td>';\nhtml = html + '    <div class=\"header\">';\nhtml = html + '      Item ID: <span style=\"font-weight:normal;\">' + D[dataId].id + '</span>';\nhtml = html + '                        <img id=\"help_image_requestid_' + dataId + '\" src=\"/images/question_mark.gif\"  class=\"help_question_mark\">';\nhtml = html + '    </div>';\nhtml = html + '                    </td>';\nhtml = html + '                  </tr>';\nhtml = html + '                  <tr>';\nhtml = html + '                    <td colspan=\"5\">';\nhtml = html + '                      <div>';\nhtml = html + '                        <input class=\"textAreaFocus\" type=\"text\" id=\"request_id_' + dataId + '\" value=\"http://' + window.location.hostname + '/issues/' +  D[dataId].id + '\" readonly>&nbsp;</input>     ';\nhtml = html + '                      </div>';\nhtml = html + '                    </td>';\nhtml = html + '                  </tr>';\nhtml = html + '                </tbody>';\nhtml = html + '              </table>';\nhtml = html + '              <table>';\nhtml = html + '                  <tr>';\nhtml = html + '                  <td align=\"right\">';\n\n// html = html + '                  <a href=\"\" onclick=\"full_screen(' + dataId + ',\\'true\\');return false;\">Attach files</a>';\n\nif (currentUserIsCore == 'true' || currentUserIsMember == 'true'){\nhtml = html + '                  <a href=\"\" onclick=\"full_screen(' + dataId + ');return false;\">Relations</a>';\n// html = html + '                  | <a href=\"\" onclick=\"full_screen(' + dataId + ');return false;\">Add Team Members</a>';\nhtml = html + '                  | <a href=\"\" onclick=\"full_screen(' + dataId + ');return false;\">Move</a>';\n}\n\nhtml = html + '                  </td>';\nhtml = html + '                  </tr>';\nhtml = html + '              </table>';\nhtml = html + '            </div>';\n\nreturn html;\n}\n\n\nfunction generate_attachments_section(dataId){\n\n  var html = '';\n  html = html + '            <div id=\"attachment_section_' + dataId + '\" class=\"section\">';\n  html = html + '              <table class=\"storyDescriptionTable\">';\n  html = html + '                <tbody>';\n  html = html + '                  <tr><td colspan=\"5\">';\n  html = html + '            <div class=\"header\">';\n  html = html + '                Attachments';\n  html = html + '            </div>';\n  html = html + '                  </td></tr>';\n  for(var i = 0; i < D[dataId].attachments.length; i++ ){\n    attachment = D[dataId].attachments[i];\n    html = html + '                  <tr><td colspan=\"5\">';\n    html = html + '                  <a class=\"icon icon-attachment\" href=\"/attachments/' + attachment.id + '/' + attachment.filename + '\">' + attachment.filename + '</a>';\n    html = html + '                  </td></tr>';\n  }\n  html = html + '                  <tr><td colspan=\"5\">';\n  html = html + '                  <table id=\"files_' + dataId + '\" class=\"attachments\"></table>';\n  html = html + '                  <form id=\"file_upload_' + dataId + '\" action=\"/issues/' + D[dataId].id + '/attachments/create?container_type=Issue\" method=\"POST\" enctype=\"multipart/form-data\">';\n  html = html + '                  <input type=\"file\" name=\"file\" multiple>';\n  html = html + '                  <button>Upload</button>';\n  html = html + '                  <a class=\"icon icon-attachment\" href=\"#\">Attach files</a>';\n  html = html + '                  </form>';\n  html = html + '                  </td></tr>';\n  html = html + '                </tbody>';\n  html = html + '              </table>';\n  html = html + '            </div>';\n  return html;\n\n}\n\n\nfunction generate_todo_section(dataId){\n\n  var item_editable = is_item_todos_editable(dataId);\n\n  var html = '';\n  html = html + '            <div id=\"todo_section_' + dataId + '\" class=\"section\">';\n  html = html + '     <form action=\"#\">';\n  html = html + '              <table class=\"storyDescriptionTable\">';\n  html = html + '                <tbody>';\n  html = html + '                  <tr><td colspan=\"5\">';\n  html = html + generate_todos(dataId,false,item_editable);\n  html = html + '                  </td></tr>';\n  if (item_editable){\n    html = html + '                  <tr>';\n    html = html + '                    <td colspan=\"5\">';\n    html = html + '                      <div>';\n    html = html + '                        <input class= \"tasksTextArea\" id=\"new_todo_' + dataId + '\"></input>     ';\n    html = html + '                        <div>';\n    html = html + '                           <input value=\"Add\" type=\"submit\" onclick=\"post_todo(' + dataId + '); return false;\">';\n    html = html + '                        </div>';\n    html = html + '                      </div>';\n    html = html + '                    </td>';\n    html = html + '                  </tr>';\n  }\n  html = html + '                </tbody>';\n  html = html + '              </table>';\n  html = html + '     </form>';\n  html = html + '            </div>';\n  return html;\n\n}\n\nfunction generate_todo_section_lightbox(dataId){\n  var item_editable = is_item_todos_editable(dataId);\n\n  var html = '';\n  html = html + '            <div id=\"todo_section_' + dataId + '\" class=\"section\">';\n  html = html + '     <form action=\"#\">';\n  html = html + '              <table id=\"todo_lightbox\">';\n  html = html + '                <tbody>';\n  html = html + '                  <tr><td colspan=\"5\">';\n  html = html + generate_todos(dataId,false, item_editable);\n  html = html + '                  </td></tr>';\n  html = html + '                  <tr>';\n  html = html + '                    <td colspan=\"5\">';\n  html = html + '                      <div>';\n  html = html + '                        <input class= \"tasksTextArea\" id=\"new_todo_' + dataId + '\"></input>     ';\n  html = html + '                        <div>';\n  html = html + '                           <input value=\"Add\" type=\"submit\" onclick=\"post_todo(' + dataId + '); return false;\">';\n  html = html + '                        </div>';\n  html = html + '                      </div>';\n  html = html + '                    </td>';\n  html = html + '                  </tr>';\n  html = html + '                </tbody>';\n  html = html + '              </table>';\n  html = html + '     </form>';\n  html = html + '            </div>';\n  return html;\n\n}\n\nfunction post_comment(dataId,from_prompt,action){\n\n//Login required\nif (!is_user_logged_in()){return false;}\n\n\ntry{\n  var text = \"\";\n\n\n  if (from_prompt){\n    text = $(\"#prompt_comment_\" + dataId).val();\n\n    //Try capturing comment from inner frame (in case of lightbox comment)\n    if (text == null){\n      text = $(\"#fancybox-frame\").contents().find(\"#prompt_comment_\" + dataId).val();\n    }\n  }\n  else{\n    text = $(\"#new_comment_\" + dataId).val();\n  }\n\n\n  if ((text == null) || (text.length < 2) || (text == new_comment_text)){\n    return false;\n  }\n  else\n  {\n    $(\"#post_comment_button_\" + dataId).hide();\n    var item = D[dataId];\n    try{\n      $(\"#notesTable_\" + item.id).append(generate_comment(currentUser,text,'1 second ago','new'));\n      $('#new_comment_' + dataId).val('');\n    }\n    catch(err){\n\n    }\n\n    $(\"#new_comment_\" + dataId).height(35);\n\n\n    var data = \"commit=Create&issue_id=\" + item.id + \"&comment=\" + encodeURIComponent(text);\n\n    var url = url_for({ controller: 'comments',\n                             action    : 'create'\n                            });\n\n    $.ajax({\n       type: \"POST\",\n       dataType: \"json\",\n       url: url,\n       data: data,\n       success:   function(html){\n        comment_added(html,dataId);\n      },\n       error:   function (XMLHttpRequest, textStatus, errorThrown) {\n      $(\"#post_comment_button_\" + dataId).show();\n      handle_error(XMLHttpRequest, textStatus, errorThrown, dataId, \"post\");\n      },\n      timeout: 30000 //30 seconds\n     });\n\n    return false;\n  }\n  }\ncatch(err){\n  return false;\n}\n}\n\nfunction post_todo(dataId){\n\n//Login required\nif (!is_user_logged_in()){return false;}\n\n\ntry{\n  var text = $(\"#new_todo_\" + dataId).val();\n  if ((text == null) || (text.length < 2)|| (text == new_todo_text)){\n    return false;\n  }\n  else\n  {\n    var item = D[dataId];\n    $(\"#notesTable_todos_\" + item.id).append(generate_todo(text,null,null));\n    $('#new_todo_' + dataId).val('');\n\n\n    var data = \"commit=Create&issue_id=\" + item.id + \"&todo[subject]=\" + encodeURIComponent(text);\n    data = data + '&todo[author_id]=' + currentUserId;\n\n\n    var url = url_for({ controller: 'todos',\n                             action    : 'create'\n                            });\n\n    $.ajax({\n       type: \"POST\",\n       dataType: \"json\",\n       url: url,\n       data: data,\n       success:   function(html){\n        todo_added(html,dataId);\n      },\n       error:   function (XMLHttpRequest, textStatus, errorThrown) {\n      handle_error(XMLHttpRequest, textStatus, errorThrown, dataId, \"post\");\n      },\n      timeout: 30000 //30 seconds\n     });\n\n    return false;\n  }\n  }\ncatch(err){\n  return false;\n}\n}\n\n\nfunction update_todo(todoId, dataId){\ntry{\n    var item = D[dataId];\n    var data = \"commit=Update&id=\" + todoId + \"&issue_id=\" + item.id; // + \"&todo[subject]=\" + text;\n\n    if ($('#task_' + todoId + '_complete').attr(\"checked\") == true){\n      $('#task_' + todoId  + '_subject').addClass('completed');\n      $('#task_' + todoId  + '_subject_text').html($('#task_' + todoId  + '_subject_text').html() + ' (' + currentUserLogin + ')' );\n      data = data + '&todo[completed_on]=' + Date();\n      data = data + '&todo[owner_login]=' + currentUserLogin;\n      data = data + '&todo[owner_id]=' + currentUserId;\n\n    }\n    else\n    {\n      $('#task_' + todoId  + '_subject').removeClass('completed');\n      $('#task_' + todoId  + '_subject_text').html(h($('#task_' + todoId  + '_subject_input').val()));\n      data = data + '&todo[completed_on]=';\n      data = data + '&todo[owner_login]=';\n      data = data + '&todo[owner_id]=';\n\n    }\n\n    var url = url_for({ controller: 'todos',\n                             action    : 'update'\n                            });\n\n    $.ajax({\n       type: \"POST\",\n       dataType: \"json\",\n       url: url,\n       data: data,\n       success:   function(html){\n        todo_updated(html,dataId);\n        update_todo_count(dataId);\n      },\n       error:   function (XMLHttpRequest, textStatus, errorThrown) {\n      handle_error(XMLHttpRequest, textStatus, errorThrown, dataId, \"post\");\n      },\n      timeout: 30000 //30 seconds\n     });\n\n    return false;\n  }\ncatch(err){\n  return false;\n}\n}\n\nfunction delete_todo(todoId, dataId){\ntry{\n    var item = D[dataId];\n    var data = \"commit=Destroy&id=\" + todoId + \"&issue_id=\" + item.id; // + \"&todo[subject]=\" + text;\n\n    $('#task_' + todoId).remove();\n\n    var url = url_for({ controller: 'todos',\n                             action    : 'destroy'\n                            });\n\n    $.ajax({\n       type: \"POST\",\n       dataType: \"json\",\n       url: url,\n       data: data,\n       success:   function(html){\n        todo_updated(html,dataId);\n        update_todo_count(dataId);\n      },\n       error:   function (XMLHttpRequest, textStatus, errorThrown) {\n      handle_error(XMLHttpRequest, textStatus, errorThrown, dataId, \"post\");\n      },\n      timeout: 30000 //30 seconds\n     });\n\n    return false;\n  }\ncatch(err){\n  return false;\n}\n}\n\nfunction update_todo_count(dataId){\n  $('#task_' + dataId  + '_count').html('(' + D[dataId].todos.length + ')');\n}\n\n// function update_comment_count(dataId){\n//   $('#comment_' + D[dataId].id  + '_count').html('(' + $('.noteInfo_' + D[dataId].id).length + ')');\n// }\n\n\n//View item history\nfunction full_screen(dataId,update){\n  show_issue_full(D[dataId].id,update);\n  collapse_item(dataId,false);\n}\n\n//Full page view in fancy box of a single issue\nfunction show_issue_full(itemId,update){\n\n  var url = url_for({ controller: 'issues',\n                             action    : 'show',\n                id    : itemId,\n                update : update\n                            });\n\n\n  if (update == 'true'){\n    url = url + '?update=true';\n  }\n\n  show_fancybox(url,'loading data...');\n\n  return false;\n}\n\n//Full page view in fancy box of a single retro\nfunction show_retro_full(retroId){\n  var url = '/projects/' + projectId + '/retros/' + retroId + '/show';\n  show_fancybox(url,'generating retrospective data...');\n\n  return false;\n}\n\nfunction timer_beat(timer){\n  //check that I haven't been inactive for too long\n  if (((new Date).getTime() - last_activity.getTime()) > INACTIVITY_THRESHOLD){\n    stop_timer(timer);\n  }\n  else if (timer_active == true){\n    new_dash_data();\n  }\n}\n\nfunction new_dash_data(){\n  if (timer_active == false){\n    return;\n  }\n  else{\n    timer_active = false;\n  }\n\n  replace_reloading_images_for_panels();\n\n  var data = \"seconds=\" + (((new Date).getTime() - last_data_pull.getTime())/1000);\n\n  data = data + \"&issuecount=\" + ISSUE_COUNT;\n\n  if ($('#include_subworkstreams_checkbox').attr(\"checked\") == true){\n    data = data + \"&include_subworkstreams=true\";\n  }\n\n\n  var url = url_for({ controller: 'projects',\n                           action    : 'new_dashdata',\n              id    : projectId\n                          });\n\n  $.ajax({\n     type: \"GET\",\n     dataType: \"json\",\n     contentType: \"application/json\",\n     url: url,\n     data: data,\n     success:    function(html){\n      $('#ajax-indicator').hide();\n      last_data_pull = new Date();\n      new_dash_data_response(html);\n    },\n     error:   function (XMLHttpRequest, textStatus, errorThrown) {\n      $('#ajax-indicator').hide();\n      last_data_pull = new Date();\n      save_local_data();\n      timer_active = true;\n    },\n    timeout: 30000 //30 seconds\n   });\n}\n\nfunction new_dash_data_response(data){\n  timer_active = true;\n\n  if ((data == null) || (data.length == 0)) {\n    save_local_data();\n    return;\n  }\n\n  //checking if this is a response with different item count\n  if (data[0].tags_copy == undefined){\n\n    // //we're getting a list of issue ids as a result of an issue moving that we didn't know about\n    //\n    // ISSUE_COUNT = data.length;\n    //\n    // for(var x=0; x < data.length; x++){\n    //   delete ITEMHASH[\"item\" + String(data[x])];\n    //   delete ITEMHASH[\"item\" + String(data[x])]; //handling duplicates\n    //   delete ITEMHASH[\"item\" + String(data[x])]; //handling duplicates\n    // }\n    //\n    // for(var idt in ITEMHASH){\n    //   D.splice(ITEMHASH[idt],1);\n    //   $(\"#item_\" + ITEMHASH[idt]).remove();\n    // }\n    //\n    // prepare_item_lookup_array();\n    // save_local_data();\n    return;\n  }\n\n  for(var i = 0; i < data.length; i++ ){\n\n    var item = data[i];\n    dataId = ITEMHASH[\"item\" + String(item.id)];\n\n    if (dataId == null){\n      D.push(data[i]);\n      ITEMHASH[\"item\" + item.id] = D.length - 1;\n      add_item(D.length-1,\"bottom\",false);\n    }\n    else{\n      if (String(new Date(D[dataId].updated_at)) == String(new Date(item.updated_at))){\n        continue;\n      }\n\n\n      if ($(\"#edit_item_\" + dataId).length > 0){\n        //item is being edited\n        $.jGrowl(\"An item you are editing (#\" + D[dataId].id + \") has been updated by another user. It's best to cancel your edits and re-open the item.\", { sticky:true, header: 'Item conflict'});\n        D[dataId] = item;\n        continue;\n      }\n\n      item_actioned(item, dataId,'data_refresh');\n    }\n  }\n\n  // sort_panel('open');\n  // sort_panel('inprogress');\n  adjust_button_container_widths();\n  update_panel_counts();\n  save_local_data();\n}\n\nfunction is_user_logged_in(){\n  if (currentUserId == ANONYMOUS_USER_ID){\n    ask_for_login();\n    return false;\n  }\n  else{\n    return true;\n  }\n}\n\nfunction ask_for_login(){\n  $.jGrowl(\"<a href='/login'>Sorry, you need to be logged in first.<br> </a>\" , { sticky:true, header: '<a href=\\'/login\\'>Login Required</a>'});\n}\n\n\nfunction handle_error (xhr, textStatus, errorThrown, dataId, action) {\n  if (xhr.status == 401 && currentUserId == ANONYMOUS_USER_ID){\n    ask_for_login();\n\n    if (dataId){\n      $('#item_' + dataId).replaceWith(generate_item(dataId));\n    }\n  }\n  else if (dataId){\n    $('#item_' + dataId).replaceWith(generate_item(dataId));\n    $('#item_lightbox_' + dataId).replaceWith(generate_item_lightbox(dataId));\n    update_lightbox_lock_version(dataId);\n\n\n    // sort_panel('open');\n    $('#featureicon_' + dataId).attr(\"src\", \"/images/error.png\");\n    $.jGrowl(\"Sorry, couldn't \" + action + \" item:<br>\" + h(D[dataId].subject) , { header: 'Error', position: 'bottom-right' });\n\n  }\n  else{\n    $(\"#new_item_wrapper\").remove();\n    $.jGrowl(\"Sorry, couldn't \" + action + \"<br>\" + XMLHttpRequest, { header: 'Error', position: 'bottom-right' });\n  }\n  keyboard_shortcuts = true;\n\n  // alert(\"Error: Couldn't \" + action);\n}\n"
  },
  {
    "path": "public/javascripts/dragdrop.js",
    "content": "// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)\n//           (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)\n//\n// script.aculo.us is freely distributable under the terms of an MIT-style license.\n// For details, see the script.aculo.us web site: http://script.aculo.us/\n\nif(Object.isUndefined(Effect))\n  throw(\"dragdrop.js requires including script.aculo.us' effects.js library\");\n\nvar Droppables = {\n  drops: [],\n\n  remove: function(element) {\n    this.drops = this.drops.reject(function(d) { return d.element==$(element) });\n  },\n\n  add: function(element) {\n    element = $(element);\n    var options = Object.extend({\n      greedy:     true,\n      hoverclass: null,\n      tree:       false\n    }, arguments[1] || { });\n\n    // cache containers\n    if(options.containment) {\n      options._containers = [];\n      var containment = options.containment;\n      if(Object.isArray(containment)) {\n        containment.each( function(c) { options._containers.push($(c)) });\n      } else {\n        options._containers.push($(containment));\n      }\n    }\n\n    if(options.accept) options.accept = [options.accept].flatten();\n\n    Element.makePositioned(element); // fix IE\n    options.element = element;\n\n    this.drops.push(options);\n  },\n\n  findDeepestChild: function(drops) {\n    deepest = drops[0];\n\n    for (i = 1; i < drops.length; ++i)\n      if (Element.isParent(drops[i].element, deepest.element))\n        deepest = drops[i];\n\n    return deepest;\n  },\n\n  isContained: function(element, drop) {\n    var containmentNode;\n    if(drop.tree) {\n      containmentNode = element.treeNode;\n    } else {\n      containmentNode = element.parentNode;\n    }\n    return drop._containers.detect(function(c) { return containmentNode == c });\n  },\n\n  isAffected: function(point, element, drop) {\n    return (\n      (drop.element!=element) &&\n      ((!drop._containers) ||\n        this.isContained(element, drop)) &&\n      ((!drop.accept) ||\n        (Element.classNames(element).detect(\n          function(v) { return drop.accept.include(v) } ) )) &&\n      Position.within(drop.element, point[0], point[1]) );\n  },\n\n  deactivate: function(drop) {\n    if(drop.hoverclass)\n      Element.removeClassName(drop.element, drop.hoverclass);\n    this.last_active = null;\n  },\n\n  activate: function(drop) {\n    if(drop.hoverclass)\n      Element.addClassName(drop.element, drop.hoverclass);\n    this.last_active = drop;\n  },\n\n  show: function(point, element) {\n    if(!this.drops.length) return;\n    var drop, affected = [];\n\n    this.drops.each( function(drop) {\n      if(Droppables.isAffected(point, element, drop))\n        affected.push(drop);\n    });\n\n    if(affected.length>0)\n      drop = Droppables.findDeepestChild(affected);\n\n    if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);\n    if (drop) {\n      Position.within(drop.element, point[0], point[1]);\n      if(drop.onHover)\n        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));\n\n      if (drop != this.last_active) Droppables.activate(drop);\n    }\n  },\n\n  fire: function(event, element) {\n    if(!this.last_active) return;\n    Position.prepare();\n\n    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))\n      if (this.last_active.onDrop) {\n        this.last_active.onDrop(element, this.last_active.element, event);\n        return true;\n      }\n  },\n\n  reset: function() {\n    if(this.last_active)\n      this.deactivate(this.last_active);\n  }\n};\n\nvar Draggables = {\n  drags: [],\n  observers: [],\n\n  register: function(draggable) {\n    if(this.drags.length == 0) {\n      this.eventMouseUp   = this.endDrag.bindAsEventListener(this);\n      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);\n      this.eventKeypress  = this.keyPress.bindAsEventListener(this);\n\n      Event.observe(document, \"mouseup\", this.eventMouseUp);\n      Event.observe(document, \"mousemove\", this.eventMouseMove);\n      Event.observe(document, \"keypress\", this.eventKeypress);\n    }\n    this.drags.push(draggable);\n  },\n\n  unregister: function(draggable) {\n    this.drags = this.drags.reject(function(d) { return d==draggable });\n    if(this.drags.length == 0) {\n      Event.stopObserving(document, \"mouseup\", this.eventMouseUp);\n      Event.stopObserving(document, \"mousemove\", this.eventMouseMove);\n      Event.stopObserving(document, \"keypress\", this.eventKeypress);\n    }\n  },\n\n  activate: function(draggable) {\n    if(draggable.options.delay) {\n      this._timeout = setTimeout(function() {\n        Draggables._timeout = null;\n        window.focus();\n        Draggables.activeDraggable = draggable;\n      }.bind(this), draggable.options.delay);\n    } else {\n      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari\n      this.activeDraggable = draggable;\n    }\n  },\n\n  deactivate: function() {\n    this.activeDraggable = null;\n  },\n\n  updateDrag: function(event) {\n    if(!this.activeDraggable) return;\n    var pointer = [Event.pointerX(event), Event.pointerY(event)];\n    // Mozilla-based browsers fire successive mousemove events with\n    // the same coordinates, prevent needless redrawing (moz bug?)\n    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;\n    this._lastPointer = pointer;\n\n    this.activeDraggable.updateDrag(event, pointer);\n  },\n\n  endDrag: function(event) {\n    if(this._timeout) {\n      clearTimeout(this._timeout);\n      this._timeout = null;\n    }\n    if(!this.activeDraggable) return;\n    this._lastPointer = null;\n    this.activeDraggable.endDrag(event);\n    this.activeDraggable = null;\n  },\n\n  keyPress: function(event) {\n    if(this.activeDraggable)\n      this.activeDraggable.keyPress(event);\n  },\n\n  addObserver: function(observer) {\n    this.observers.push(observer);\n    this._cacheObserverCallbacks();\n  },\n\n  removeObserver: function(element) {  // element instead of observer fixes mem leaks\n    this.observers = this.observers.reject( function(o) { return o.element==element });\n    this._cacheObserverCallbacks();\n  },\n\n  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'\n    if(this[eventName+'Count'] > 0)\n      this.observers.each( function(o) {\n        if(o[eventName]) o[eventName](eventName, draggable, event);\n      });\n    if(draggable.options[eventName]) draggable.options[eventName](draggable, event);\n  },\n\n  _cacheObserverCallbacks: function() {\n    ['onStart','onEnd','onDrag'].each( function(eventName) {\n      Draggables[eventName+'Count'] = Draggables.observers.select(\n        function(o) { return o[eventName]; }\n      ).length;\n    });\n  }\n};\n\n/*--------------------------------------------------------------------------*/\n\nvar Draggable = Class.create({\n  initialize: function(element) {\n    var defaults = {\n      handle: false,\n      reverteffect: function(element, top_offset, left_offset) {\n        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;\n        new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,\n          queue: {scope:'_draggable', position:'end'}\n        });\n      },\n      endeffect: function(element) {\n        var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;\n        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,\n          queue: {scope:'_draggable', position:'end'},\n          afterFinish: function(){\n            Draggable._dragging[element] = false\n          }\n        });\n      },\n      zindex: 1000,\n      revert: false,\n      quiet: false,\n      scroll: false,\n      scrollSensitivity: 20,\n      scrollSpeed: 15,\n      snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] }\n      delay: 0\n    };\n\n    if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))\n      Object.extend(defaults, {\n        starteffect: function(element) {\n          element._opacity = Element.getOpacity(element);\n          Draggable._dragging[element] = true;\n          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});\n        }\n      });\n\n    var options = Object.extend(defaults, arguments[1] || { });\n\n    this.element = $(element);\n\n    if(options.handle && Object.isString(options.handle))\n      this.handle = this.element.down('.'+options.handle, 0);\n\n    if(!this.handle) this.handle = $(options.handle);\n    if(!this.handle) this.handle = this.element;\n\n    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {\n      options.scroll = $(options.scroll);\n      this._isScrollChild = Element.childOf(this.element, options.scroll);\n    }\n\n    Element.makePositioned(this.element); // fix IE\n\n    this.options  = options;\n    this.dragging = false;\n\n    this.eventMouseDown = this.initDrag.bindAsEventListener(this);\n    Event.observe(this.handle, \"mousedown\", this.eventMouseDown);\n\n    Draggables.register(this);\n  },\n\n  destroy: function() {\n    Event.stopObserving(this.handle, \"mousedown\", this.eventMouseDown);\n    Draggables.unregister(this);\n  },\n\n  currentDelta: function() {\n    return([\n      parseInt(Element.getStyle(this.element,'left') || '0'),\n      parseInt(Element.getStyle(this.element,'top') || '0')]);\n  },\n\n  initDrag: function(event) {\n    if(!Object.isUndefined(Draggable._dragging[this.element]) &&\n      Draggable._dragging[this.element]) return;\n    if(Event.isLeftClick(event)) {\n      // abort on form elements, fixes a Firefox issue\n      var src = Event.element(event);\n      if((tag_name = src.tagName.toUpperCase()) && (\n        tag_name=='INPUT' ||\n        tag_name=='SELECT' ||\n        tag_name=='OPTION' ||\n        tag_name=='BUTTON' ||\n        tag_name=='TEXTAREA')) return;\n\n      var pointer = [Event.pointerX(event), Event.pointerY(event)];\n      var pos     = Position.cumulativeOffset(this.element);\n      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });\n\n      Draggables.activate(this);\n      Event.stop(event);\n    }\n  },\n\n  startDrag: function(event) {\n    this.dragging = true;\n    if(!this.delta)\n      this.delta = this.currentDelta();\n\n    if(this.options.zindex) {\n      this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);\n      this.element.style.zIndex = this.options.zindex;\n    }\n\n    if(this.options.ghosting) {\n      this._clone = this.element.cloneNode(true);\n      this._originallyAbsolute = (this.element.getStyle('position') == 'absolute');\n      if (!this._originallyAbsolute)\n        Position.absolutize(this.element);\n      this.element.parentNode.insertBefore(this._clone, this.element);\n    }\n\n    if(this.options.scroll) {\n      if (this.options.scroll == window) {\n        var where = this._getWindowScroll(this.options.scroll);\n        this.originalScrollLeft = where.left;\n        this.originalScrollTop = where.top;\n      } else {\n        this.originalScrollLeft = this.options.scroll.scrollLeft;\n        this.originalScrollTop = this.options.scroll.scrollTop;\n      }\n    }\n\n    Draggables.notify('onStart', this, event);\n\n    if(this.options.starteffect) this.options.starteffect(this.element);\n  },\n\n  updateDrag: function(event, pointer) {\n    if(!this.dragging) this.startDrag(event);\n\n    if(!this.options.quiet){\n      Position.prepare();\n      Droppables.show(pointer, this.element);\n    }\n\n    Draggables.notify('onDrag', this, event);\n\n    this.draw(pointer);\n    if(this.options.change) this.options.change(this);\n\n    if(this.options.scroll) {\n      this.stopScrolling();\n\n      var p;\n      if (this.options.scroll == window) {\n        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }\n      } else {\n        p = Position.page(this.options.scroll);\n        p[0] += this.options.scroll.scrollLeft + Position.deltaX;\n        p[1] += this.options.scroll.scrollTop + Position.deltaY;\n        p.push(p[0]+this.options.scroll.offsetWidth);\n        p.push(p[1]+this.options.scroll.offsetHeight);\n      }\n      var speed = [0,0];\n      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);\n      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);\n      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);\n      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);\n      this.startScrolling(speed);\n    }\n\n    // fix AppleWebKit rendering\n    if(Prototype.Browser.WebKit) window.scrollBy(0,0);\n\n    Event.stop(event);\n  },\n\n  finishDrag: function(event, success) {\n    this.dragging = false;\n\n    if(this.options.quiet){\n      Position.prepare();\n      var pointer = [Event.pointerX(event), Event.pointerY(event)];\n      Droppables.show(pointer, this.element);\n    }\n\n    if(this.options.ghosting) {\n      if (!this._originallyAbsolute)\n        Position.relativize(this.element);\n      delete this._originallyAbsolute;\n      Element.remove(this._clone);\n      this._clone = null;\n    }\n\n    var dropped = false;\n    if(success) {\n      dropped = Droppables.fire(event, this.element);\n      if (!dropped) dropped = false;\n    }\n    if(dropped && this.options.onDropped) this.options.onDropped(this.element);\n    Draggables.notify('onEnd', this, event);\n\n    var revert = this.options.revert;\n    if(revert && Object.isFunction(revert)) revert = revert(this.element);\n\n    var d = this.currentDelta();\n    if(revert && this.options.reverteffect) {\n      if (dropped == 0 || revert != 'failure')\n        this.options.reverteffect(this.element,\n          d[1]-this.delta[1], d[0]-this.delta[0]);\n    } else {\n      this.delta = d;\n    }\n\n    if(this.options.zindex)\n      this.element.style.zIndex = this.originalZ;\n\n    if(this.options.endeffect)\n      this.options.endeffect(this.element);\n\n    Draggables.deactivate(this);\n    Droppables.reset();\n  },\n\n  keyPress: function(event) {\n    if(event.keyCode!=Event.KEY_ESC) return;\n    this.finishDrag(event, false);\n    Event.stop(event);\n  },\n\n  endDrag: function(event) {\n    if(!this.dragging) return;\n    this.stopScrolling();\n    this.finishDrag(event, true);\n    Event.stop(event);\n  },\n\n  draw: function(point) {\n    var pos = Position.cumulativeOffset(this.element);\n    if(this.options.ghosting) {\n      var r   = Position.realOffset(this.element);\n      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;\n    }\n\n    var d = this.currentDelta();\n    pos[0] -= d[0]; pos[1] -= d[1];\n\n    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {\n      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;\n      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;\n    }\n\n    var p = [0,1].map(function(i){\n      return (point[i]-pos[i]-this.offset[i])\n    }.bind(this));\n\n    if(this.options.snap) {\n      if(Object.isFunction(this.options.snap)) {\n        p = this.options.snap(p[0],p[1],this);\n      } else {\n      if(Object.isArray(this.options.snap)) {\n        p = p.map( function(v, i) {\n          return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this));\n      } else {\n        p = p.map( function(v) {\n          return (v/this.options.snap).round()*this.options.snap }.bind(this));\n      }\n    }}\n\n    var style = this.element.style;\n    if((!this.options.constraint) || (this.options.constraint=='horizontal'))\n      style.left = p[0] + \"px\";\n    if((!this.options.constraint) || (this.options.constraint=='vertical'))\n      style.top  = p[1] + \"px\";\n\n    if(style.visibility==\"hidden\") style.visibility = \"\"; // fix gecko rendering\n  },\n\n  stopScrolling: function() {\n    if(this.scrollInterval) {\n      clearInterval(this.scrollInterval);\n      this.scrollInterval = null;\n      Draggables._lastScrollPointer = null;\n    }\n  },\n\n  startScrolling: function(speed) {\n    if(!(speed[0] || speed[1])) return;\n    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];\n    this.lastScrolled = new Date();\n    this.scrollInterval = setInterval(this.scroll.bind(this), 10);\n  },\n\n  scroll: function() {\n    var current = new Date();\n    var delta = current - this.lastScrolled;\n    this.lastScrolled = current;\n    if(this.options.scroll == window) {\n      with (this._getWindowScroll(this.options.scroll)) {\n        if (this.scrollSpeed[0] || this.scrollSpeed[1]) {\n          var d = delta / 1000;\n          this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );\n        }\n      }\n    } else {\n      this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;\n      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;\n    }\n\n    Position.prepare();\n    Droppables.show(Draggables._lastPointer, this.element);\n    Draggables.notify('onDrag', this);\n    if (this._isScrollChild) {\n      Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);\n      Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;\n      Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;\n      if (Draggables._lastScrollPointer[0] < 0)\n        Draggables._lastScrollPointer[0] = 0;\n      if (Draggables._lastScrollPointer[1] < 0)\n        Draggables._lastScrollPointer[1] = 0;\n      this.draw(Draggables._lastScrollPointer);\n    }\n\n    if(this.options.change) this.options.change(this);\n  },\n\n  _getWindowScroll: function(w) {\n    var T, L, W, H;\n    with (w.document) {\n      if (w.document.documentElement && documentElement.scrollTop) {\n        T = documentElement.scrollTop;\n        L = documentElement.scrollLeft;\n      } else if (w.document.body) {\n        T = body.scrollTop;\n        L = body.scrollLeft;\n      }\n      if (w.innerWidth) {\n        W = w.innerWidth;\n        H = w.innerHeight;\n      } else if (w.document.documentElement && documentElement.clientWidth) {\n        W = documentElement.clientWidth;\n        H = documentElement.clientHeight;\n      } else {\n        W = body.offsetWidth;\n        H = body.offsetHeight;\n      }\n    }\n    return { top: T, left: L, width: W, height: H };\n  }\n});\n\nDraggable._dragging = { };\n\n/*--------------------------------------------------------------------------*/\n\nvar SortableObserver = Class.create({\n  initialize: function(element, observer) {\n    this.element   = $(element);\n    this.observer  = observer;\n    this.lastValue = Sortable.serialize(this.element);\n  },\n\n  onStart: function() {\n    this.lastValue = Sortable.serialize(this.element);\n  },\n\n  onEnd: function() {\n    Sortable.unmark();\n    if(this.lastValue != Sortable.serialize(this.element))\n      this.observer(this.element)\n  }\n});\n\nvar Sortable = {\n  SERIALIZE_RULE: /^[^_\\-](?:[A-Za-z0-9\\-\\_]*)[_](.*)$/,\n\n  sortables: { },\n\n  _findRootElement: function(element) {\n    while (element.tagName.toUpperCase() != \"BODY\") {\n      if(element.id && Sortable.sortables[element.id]) return element;\n      element = element.parentNode;\n    }\n  },\n\n  options: function(element) {\n    element = Sortable._findRootElement($(element));\n    if(!element) return;\n    return Sortable.sortables[element.id];\n  },\n\n  destroy: function(element){\n    element = $(element);\n    var s = Sortable.sortables[element.id];\n\n    if(s) {\n      Draggables.removeObserver(s.element);\n      s.droppables.each(function(d){ Droppables.remove(d) });\n      s.draggables.invoke('destroy');\n\n      delete Sortable.sortables[s.element.id];\n    }\n  },\n\n  create: function(element) {\n    element = $(element);\n    var options = Object.extend({\n      element:     element,\n      tag:         'li',       // assumes li children, override with tag: 'tagname'\n      dropOnEmpty: false,\n      tree:        false,\n      treeTag:     'ul',\n      overlap:     'vertical', // one of 'vertical', 'horizontal'\n      constraint:  'vertical', // one of 'vertical', 'horizontal', false\n      containment: element,    // also takes array of elements (or id's); or false\n      handle:      false,      // or a CSS class\n      only:        false,\n      delay:       0,\n      hoverclass:  null,\n      ghosting:    false,\n      quiet:       false,\n      scroll:      false,\n      scrollSensitivity: 20,\n      scrollSpeed: 15,\n      format:      this.SERIALIZE_RULE,\n\n      // these take arrays of elements or ids and can be\n      // used for better initialization performance\n      elements:    false,\n      handles:     false,\n\n      onChange:    Prototype.emptyFunction,\n      onUpdate:    Prototype.emptyFunction\n    }, arguments[1] || { });\n\n    // clear any old sortable with same element\n    this.destroy(element);\n\n    // build options for the draggables\n    var options_for_draggable = {\n      revert:      true,\n      quiet:       options.quiet,\n      scroll:      options.scroll,\n      scrollSpeed: options.scrollSpeed,\n      scrollSensitivity: options.scrollSensitivity,\n      delay:       options.delay,\n      ghosting:    options.ghosting,\n      constraint:  options.constraint,\n      handle:      options.handle };\n\n    if(options.starteffect)\n      options_for_draggable.starteffect = options.starteffect;\n\n    if(options.reverteffect)\n      options_for_draggable.reverteffect = options.reverteffect;\n    else\n      if(options.ghosting) options_for_draggable.reverteffect = function(element) {\n        element.style.top  = 0;\n        element.style.left = 0;\n      };\n\n    if(options.endeffect)\n      options_for_draggable.endeffect = options.endeffect;\n\n    if(options.zindex)\n      options_for_draggable.zindex = options.zindex;\n\n    // build options for the droppables\n    var options_for_droppable = {\n      overlap:     options.overlap,\n      containment: options.containment,\n      tree:        options.tree,\n      hoverclass:  options.hoverclass,\n      onHover:     Sortable.onHover\n    };\n\n    var options_for_tree = {\n      onHover:      Sortable.onEmptyHover,\n      overlap:      options.overlap,\n      containment:  options.containment,\n      hoverclass:   options.hoverclass\n    };\n\n    // fix for gecko engine\n    Element.cleanWhitespace(element);\n\n    options.draggables = [];\n    options.droppables = [];\n\n    // drop on empty handling\n    if(options.dropOnEmpty || options.tree) {\n      Droppables.add(element, options_for_tree);\n      options.droppables.push(element);\n    }\n\n    (options.elements || this.findElements(element, options) || []).each( function(e,i) {\n      var handle = options.handles ? $(options.handles[i]) :\n        (options.handle ? $(e).select('.' + options.handle)[0] : e);\n      options.draggables.push(\n        new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));\n      Droppables.add(e, options_for_droppable);\n      if(options.tree) e.treeNode = element;\n      options.droppables.push(e);\n    });\n\n    if(options.tree) {\n      (Sortable.findTreeElements(element, options) || []).each( function(e) {\n        Droppables.add(e, options_for_tree);\n        e.treeNode = element;\n        options.droppables.push(e);\n      });\n    }\n\n    // keep reference\n    this.sortables[element.id] = options;\n\n    // for onupdate\n    Draggables.addObserver(new SortableObserver(element, options.onUpdate));\n\n  },\n\n  // return all suitable-for-sortable elements in a guaranteed order\n  findElements: function(element, options) {\n    return Element.findChildren(\n      element, options.only, options.tree ? true : false, options.tag);\n  },\n\n  findTreeElements: function(element, options) {\n    return Element.findChildren(\n      element, options.only, options.tree ? true : false, options.treeTag);\n  },\n\n  onHover: function(element, dropon, overlap) {\n    if(Element.isParent(dropon, element)) return;\n\n    if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {\n      return;\n    } else if(overlap>0.5) {\n      Sortable.mark(dropon, 'before');\n      if(dropon.previousSibling != element) {\n        var oldParentNode = element.parentNode;\n        element.style.visibility = \"hidden\"; // fix gecko rendering\n        dropon.parentNode.insertBefore(element, dropon);\n        if(dropon.parentNode!=oldParentNode)\n          Sortable.options(oldParentNode).onChange(element);\n        Sortable.options(dropon.parentNode).onChange(element);\n      }\n    } else {\n      Sortable.mark(dropon, 'after');\n      var nextElement = dropon.nextSibling || null;\n      if(nextElement != element) {\n        var oldParentNode = element.parentNode;\n        element.style.visibility = \"hidden\"; // fix gecko rendering\n        dropon.parentNode.insertBefore(element, nextElement);\n        if(dropon.parentNode!=oldParentNode)\n          Sortable.options(oldParentNode).onChange(element);\n        Sortable.options(dropon.parentNode).onChange(element);\n      }\n    }\n  },\n\n  onEmptyHover: function(element, dropon, overlap) {\n    var oldParentNode = element.parentNode;\n    var droponOptions = Sortable.options(dropon);\n\n    if(!Element.isParent(dropon, element)) {\n      var index;\n\n      var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});\n      var child = null;\n\n      if(children) {\n        var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);\n\n        for (index = 0; index < children.length; index += 1) {\n          if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {\n            offset -= Element.offsetSize (children[index], droponOptions.overlap);\n          } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {\n            child = index + 1 < children.length ? children[index + 1] : null;\n            break;\n          } else {\n            child = children[index];\n            break;\n          }\n        }\n      }\n\n      dropon.insertBefore(element, child);\n\n      Sortable.options(oldParentNode).onChange(element);\n      droponOptions.onChange(element);\n    }\n  },\n\n  unmark: function() {\n    if(Sortable._marker) Sortable._marker.hide();\n  },\n\n  mark: function(dropon, position) {\n    // mark on ghosting only\n    var sortable = Sortable.options(dropon.parentNode);\n    if(sortable && !sortable.ghosting) return;\n\n    if(!Sortable._marker) {\n      Sortable._marker =\n        ($('dropmarker') || Element.extend(document.createElement('DIV'))).\n          hide().addClassName('dropmarker').setStyle({position:'absolute'});\n      document.getElementsByTagName(\"body\").item(0).appendChild(Sortable._marker);\n    }\n    var offsets = Position.cumulativeOffset(dropon);\n    Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});\n\n    if(position=='after')\n      if(sortable.overlap == 'horizontal')\n        Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});\n      else\n        Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});\n\n    Sortable._marker.show();\n  },\n\n  _tree: function(element, options, parent) {\n    var children = Sortable.findElements(element, options) || [];\n\n    for (var i = 0; i < children.length; ++i) {\n      var match = children[i].id.match(options.format);\n\n      if (!match) continue;\n\n      var child = {\n        id: encodeURIComponent(match ? match[1] : null),\n        element: element,\n        parent: parent,\n        children: [],\n        position: parent.children.length,\n        container: $(children[i]).down(options.treeTag)\n      };\n\n      /* Get the element containing the children and recurse over it */\n      if (child.container)\n        this._tree(child.container, options, child);\n\n      parent.children.push (child);\n    }\n\n    return parent;\n  },\n\n  tree: function(element) {\n    element = $(element);\n    var sortableOptions = this.options(element);\n    var options = Object.extend({\n      tag: sortableOptions.tag,\n      treeTag: sortableOptions.treeTag,\n      only: sortableOptions.only,\n      name: element.id,\n      format: sortableOptions.format\n    }, arguments[1] || { });\n\n    var root = {\n      id: null,\n      parent: null,\n      children: [],\n      container: element,\n      position: 0\n    };\n\n    return Sortable._tree(element, options, root);\n  },\n\n  /* Construct a [i] index for a particular node */\n  _constructIndex: function(node) {\n    var index = '';\n    do {\n      if (node.id) index = '[' + node.position + ']' + index;\n    } while ((node = node.parent) != null);\n    return index;\n  },\n\n  sequence: function(element) {\n    element = $(element);\n    var options = Object.extend(this.options(element), arguments[1] || { });\n\n    return $(this.findElements(element, options) || []).map( function(item) {\n      return item.id.match(options.format) ? item.id.match(options.format)[1] : '';\n    });\n  },\n\n  setSequence: function(element, new_sequence) {\n    element = $(element);\n    var options = Object.extend(this.options(element), arguments[2] || { });\n\n    var nodeMap = { };\n    this.findElements(element, options).each( function(n) {\n        if (n.id.match(options.format))\n            nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];\n        n.parentNode.removeChild(n);\n    });\n\n    new_sequence.each(function(ident) {\n      var n = nodeMap[ident];\n      if (n) {\n        n[1].appendChild(n[0]);\n        delete nodeMap[ident];\n      }\n    });\n  },\n\n  serialize: function(element) {\n    element = $(element);\n    var options = Object.extend(Sortable.options(element), arguments[1] || { });\n    var name = encodeURIComponent(\n      (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);\n\n    if (options.tree) {\n      return Sortable.tree(element, arguments[1]).children.map( function (item) {\n        return [name + Sortable._constructIndex(item) + \"[id]=\" +\n                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));\n      }).flatten().join('&');\n    } else {\n      return Sortable.sequence(element, arguments[1]).map( function(item) {\n        return name + \"[]=\" + encodeURIComponent(item);\n      }).join('&');\n    }\n  }\n};\n\n// Returns true if child is contained within element\nElement.isParent = function(child, element) {\n  if (!child.parentNode || child == element) return false;\n  if (child.parentNode == element) return true;\n  return Element.isParent(child.parentNode, element);\n};\n\nElement.findChildren = function(element, only, recursive, tagName) {\n  if(!element.hasChildNodes()) return null;\n  tagName = tagName.toUpperCase();\n  if(only) only = [only].flatten();\n  var elements = [];\n  $A(element.childNodes).each( function(e) {\n    if(e.tagName && e.tagName.toUpperCase()==tagName &&\n      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))\n        elements.push(e);\n    if(recursive) {\n      var grandchildren = Element.findChildren(e, only, recursive, tagName);\n      if(grandchildren) elements.push(grandchildren);\n    }\n  });\n\n  return (elements.length>0 ? elements.flatten() : []);\n};\n\nElement.offsetSize = function (element, type) {\n  return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];\n};\n"
  },
  {
    "path": "public/javascripts/effects.js",
    "content": "// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)\n// Contributors:\n//  Justin Palmer (http://encytemedia.com/)\n//  Mark Pilgrim (http://diveintomark.org/)\n//  Martin Bialasinki\n//\n// script.aculo.us is freely distributable under the terms of an MIT-style license.\n// For details, see the script.aculo.us web site: http://script.aculo.us/\n\n// converts rgb() and #xxx to #xxxxxx format,\n// returns self (or first argument) if not convertable\nString.prototype.parseColor = function() {\n  var color = '#';\n  if (this.slice(0,4) == 'rgb(') {\n    var cols = this.slice(4,this.length-1).split(',');\n    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);\n  } else {\n    if (this.slice(0,1) == '#') {\n      if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();\n      if (this.length==7) color = this.toLowerCase();\n    }\n  }\n  return (color.length==7 ? color : (arguments[0] || this));\n};\n\n/*--------------------------------------------------------------------------*/\n\nElement.collectTextNodes = function(element) {\n  return $A($(element).childNodes).collect( function(node) {\n    return (node.nodeType==3 ? node.nodeValue :\n      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));\n  }).flatten().join('');\n};\n\nElement.collectTextNodesIgnoreClass = function(element, className) {\n  return $A($(element).childNodes).collect( function(node) {\n    return (node.nodeType==3 ? node.nodeValue :\n      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?\n        Element.collectTextNodesIgnoreClass(node, className) : ''));\n  }).flatten().join('');\n};\n\nElement.setContentZoom = function(element, percent) {\n  element = $(element);\n  element.setStyle({fontSize: (percent/100) + 'em'});\n  if (Prototype.Browser.WebKit) window.scrollBy(0,0);\n  return element;\n};\n\nElement.getInlineOpacity = function(element){\n  return $(element).style.opacity || '';\n};\n\nElement.forceRerendering = function(element) {\n  try {\n    element = $(element);\n    var n = document.createTextNode(' ');\n    element.appendChild(n);\n    element.removeChild(n);\n  } catch(e) { }\n};\n\n/*--------------------------------------------------------------------------*/\n\nvar Effect = {\n  _elementDoesNotExistError: {\n    name: 'ElementDoesNotExistError',\n    message: 'The specified DOM element does not exist, but is required for this effect to operate'\n  },\n  Transitions: {\n    linear: Prototype.K,\n    sinoidal: function(pos) {\n      return (-Math.cos(pos*Math.PI)/2) + .5;\n    },\n    reverse: function(pos) {\n      return 1-pos;\n    },\n    flicker: function(pos) {\n      var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;\n      return pos > 1 ? 1 : pos;\n    },\n    wobble: function(pos) {\n      return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;\n    },\n    pulse: function(pos, pulses) {\n      return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;\n    },\n    spring: function(pos) {\n      return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));\n    },\n    none: function(pos) {\n      return 0;\n    },\n    full: function(pos) {\n      return 1;\n    }\n  },\n  DefaultOptions: {\n    duration:   1.0,   // seconds\n    fps:        100,   // 100= assume 66fps max.\n    sync:       false, // true for combining\n    from:       0.0,\n    to:         1.0,\n    delay:      0.0,\n    queue:      'parallel'\n  },\n  tagifyText: function(element) {\n    var tagifyStyle = 'position:relative';\n    if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';\n\n    element = $(element);\n    $A(element.childNodes).each( function(child) {\n      if (child.nodeType==3) {\n        child.nodeValue.toArray().each( function(character) {\n          element.insertBefore(\n            new Element('span', {style: tagifyStyle}).update(\n              character == ' ' ? String.fromCharCode(160) : character),\n              child);\n        });\n        Element.remove(child);\n      }\n    });\n  },\n  multiple: function(element, effect) {\n    var elements;\n    if (((typeof element == 'object') ||\n        Object.isFunction(element)) &&\n       (element.length))\n      elements = element;\n    else\n      elements = $(element).childNodes;\n\n    var options = Object.extend({\n      speed: 0.1,\n      delay: 0.0\n    }, arguments[2] || { });\n    var masterDelay = options.delay;\n\n    $A(elements).each( function(element, index) {\n      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));\n    });\n  },\n  PAIRS: {\n    'slide':  ['SlideDown','SlideUp'],\n    'blind':  ['BlindDown','BlindUp'],\n    'appear': ['Appear','Fade']\n  },\n  toggle: function(element, effect) {\n    element = $(element);\n    effect = (effect || 'appear').toLowerCase();\n    var options = Object.extend({\n      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }\n    }, arguments[2] || { });\n    Effect[element.visible() ?\n      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);\n  }\n};\n\nEffect.DefaultOptions.transition = Effect.Transitions.sinoidal;\n\n/* ------------- core effects ------------- */\n\nEffect.ScopedQueue = Class.create(Enumerable, {\n  initialize: function() {\n    this.effects  = [];\n    this.interval = null;\n  },\n  _each: function(iterator) {\n    this.effects._each(iterator);\n  },\n  add: function(effect) {\n    var timestamp = new Date().getTime();\n\n    var position = Object.isString(effect.options.queue) ?\n      effect.options.queue : effect.options.queue.position;\n\n    switch(position) {\n      case 'front':\n        // move unstarted effects after this effect\n        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {\n            e.startOn  += effect.finishOn;\n            e.finishOn += effect.finishOn;\n          });\n        break;\n      case 'with-last':\n        timestamp = this.effects.pluck('startOn').max() || timestamp;\n        break;\n      case 'end':\n        // start effect after last queued effect has finished\n        timestamp = this.effects.pluck('finishOn').max() || timestamp;\n        break;\n    }\n\n    effect.startOn  += timestamp;\n    effect.finishOn += timestamp;\n\n    if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))\n      this.effects.push(effect);\n\n    if (!this.interval)\n      this.interval = setInterval(this.loop.bind(this), 15);\n  },\n  remove: function(effect) {\n    this.effects = this.effects.reject(function(e) { return e==effect });\n    if (this.effects.length == 0) {\n      clearInterval(this.interval);\n      this.interval = null;\n    }\n  },\n  loop: function() {\n    var timePos = new Date().getTime();\n    for(var i=0, len=this.effects.length;i<len;i++)\n      this.effects[i] && this.effects[i].loop(timePos);\n  }\n});\n\nEffect.Queues = {\n  instances: $H(),\n  get: function(queueName) {\n    if (!Object.isString(queueName)) return queueName;\n\n    return this.instances.get(queueName) ||\n      this.instances.set(queueName, new Effect.ScopedQueue());\n  }\n};\nEffect.Queue = Effect.Queues.get('global');\n\nEffect.Base = Class.create({\n  position: null,\n  start: function(options) {\n    function codeForEvent(options,eventName){\n      return (\n        (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +\n        (options[eventName] ? 'this.options.'+eventName+'(this);' : '')\n      );\n    }\n    if (options && options.transition === false) options.transition = Effect.Transitions.linear;\n    this.options      = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });\n    this.currentFrame = 0;\n    this.state        = 'idle';\n    this.startOn      = this.options.delay*1000;\n    this.finishOn     = this.startOn+(this.options.duration*1000);\n    this.fromToDelta  = this.options.to-this.options.from;\n    this.totalTime    = this.finishOn-this.startOn;\n    this.totalFrames  = this.options.fps*this.options.duration;\n\n    this.render = (function() {\n      function dispatch(effect, eventName) {\n        if (effect.options[eventName + 'Internal'])\n          effect.options[eventName + 'Internal'](effect);\n        if (effect.options[eventName])\n          effect.options[eventName](effect);\n      }\n\n      return function(pos) {\n        if (this.state === \"idle\") {\n          this.state = \"running\";\n          dispatch(this, 'beforeSetup');\n          if (this.setup) this.setup();\n          dispatch(this, 'afterSetup');\n        }\n        if (this.state === \"running\") {\n          pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;\n          this.position = pos;\n          dispatch(this, 'beforeUpdate');\n          if (this.update) this.update(pos);\n          dispatch(this, 'afterUpdate');\n        }\n      };\n    })();\n\n    this.event('beforeStart');\n    if (!this.options.sync)\n      Effect.Queues.get(Object.isString(this.options.queue) ?\n        'global' : this.options.queue.scope).add(this);\n  },\n  loop: function(timePos) {\n    if (timePos >= this.startOn) {\n      if (timePos >= this.finishOn) {\n        this.render(1.0);\n        this.cancel();\n        this.event('beforeFinish');\n        if (this.finish) this.finish();\n        this.event('afterFinish');\n        return;\n      }\n      var pos   = (timePos - this.startOn) / this.totalTime,\n          frame = (pos * this.totalFrames).round();\n      if (frame > this.currentFrame) {\n        this.render(pos);\n        this.currentFrame = frame;\n      }\n    }\n  },\n  cancel: function() {\n    if (!this.options.sync)\n      Effect.Queues.get(Object.isString(this.options.queue) ?\n        'global' : this.options.queue.scope).remove(this);\n    this.state = 'finished';\n  },\n  event: function(eventName) {\n    if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);\n    if (this.options[eventName]) this.options[eventName](this);\n  },\n  inspect: function() {\n    var data = $H();\n    for(property in this)\n      if (!Object.isFunction(this[property])) data.set(property, this[property]);\n    return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';\n  }\n});\n\nEffect.Parallel = Class.create(Effect.Base, {\n  initialize: function(effects) {\n    this.effects = effects || [];\n    this.start(arguments[1]);\n  },\n  update: function(position) {\n    this.effects.invoke('render', position);\n  },\n  finish: function(position) {\n    this.effects.each( function(effect) {\n      effect.render(1.0);\n      effect.cancel();\n      effect.event('beforeFinish');\n      if (effect.finish) effect.finish(position);\n      effect.event('afterFinish');\n    });\n  }\n});\n\nEffect.Tween = Class.create(Effect.Base, {\n  initialize: function(object, from, to) {\n    object = Object.isString(object) ? $(object) : object;\n    var args = $A(arguments), method = args.last(),\n      options = args.length == 5 ? args[3] : null;\n    this.method = Object.isFunction(method) ? method.bind(object) :\n      Object.isFunction(object[method]) ? object[method].bind(object) :\n      function(value) { object[method] = value };\n    this.start(Object.extend({ from: from, to: to }, options || { }));\n  },\n  update: function(position) {\n    this.method(position);\n  }\n});\n\nEffect.Event = Class.create(Effect.Base, {\n  initialize: function() {\n    this.start(Object.extend({ duration: 0 }, arguments[0] || { }));\n  },\n  update: Prototype.emptyFunction\n});\n\nEffect.Opacity = Class.create(Effect.Base, {\n  initialize: function(element) {\n    this.element = $(element);\n    if (!this.element) throw(Effect._elementDoesNotExistError);\n    // make this work on IE on elements without 'layout'\n    if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))\n      this.element.setStyle({zoom: 1});\n    var options = Object.extend({\n      from: this.element.getOpacity() || 0.0,\n      to:   1.0\n    }, arguments[1] || { });\n    this.start(options);\n  },\n  update: function(position) {\n    this.element.setOpacity(position);\n  }\n});\n\nEffect.Move = Class.create(Effect.Base, {\n  initialize: function(element) {\n    this.element = $(element);\n    if (!this.element) throw(Effect._elementDoesNotExistError);\n    var options = Object.extend({\n      x:    0,\n      y:    0,\n      mode: 'relative'\n    }, arguments[1] || { });\n    this.start(options);\n  },\n  setup: function() {\n    this.element.makePositioned();\n    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');\n    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');\n    if (this.options.mode == 'absolute') {\n      this.options.x = this.options.x - this.originalLeft;\n      this.options.y = this.options.y - this.originalTop;\n    }\n  },\n  update: function(position) {\n    this.element.setStyle({\n      left: (this.options.x  * position + this.originalLeft).round() + 'px',\n      top:  (this.options.y  * position + this.originalTop).round()  + 'px'\n    });\n  }\n});\n\n// for backwards compatibility\nEffect.MoveBy = function(element, toTop, toLeft) {\n  return new Effect.Move(element,\n    Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));\n};\n\nEffect.Scale = Class.create(Effect.Base, {\n  initialize: function(element, percent) {\n    this.element = $(element);\n    if (!this.element) throw(Effect._elementDoesNotExistError);\n    var options = Object.extend({\n      scaleX: true,\n      scaleY: true,\n      scaleContent: true,\n      scaleFromCenter: false,\n      scaleMode: 'box',        // 'box' or 'contents' or { } with provided values\n      scaleFrom: 100.0,\n      scaleTo:   percent\n    }, arguments[2] || { });\n    this.start(options);\n  },\n  setup: function() {\n    this.restoreAfterFinish = this.options.restoreAfterFinish || false;\n    this.elementPositioning = this.element.getStyle('position');\n\n    this.originalStyle = { };\n    ['top','left','width','height','fontSize'].each( function(k) {\n      this.originalStyle[k] = this.element.style[k];\n    }.bind(this));\n\n    this.originalTop  = this.element.offsetTop;\n    this.originalLeft = this.element.offsetLeft;\n\n    var fontSize = this.element.getStyle('font-size') || '100%';\n    ['em','px','%','pt'].each( function(fontSizeType) {\n      if (fontSize.indexOf(fontSizeType)>0) {\n        this.fontSize     = parseFloat(fontSize);\n        this.fontSizeType = fontSizeType;\n      }\n    }.bind(this));\n\n    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;\n\n    this.dims = null;\n    if (this.options.scaleMode=='box')\n      this.dims = [this.element.offsetHeight, this.element.offsetWidth];\n    if (/^content/.test(this.options.scaleMode))\n      this.dims = [this.element.scrollHeight, this.element.scrollWidth];\n    if (!this.dims)\n      this.dims = [this.options.scaleMode.originalHeight,\n                   this.options.scaleMode.originalWidth];\n  },\n  update: function(position) {\n    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);\n    if (this.options.scaleContent && this.fontSize)\n      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });\n    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);\n  },\n  finish: function(position) {\n    if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);\n  },\n  setDimensions: function(height, width) {\n    var d = { };\n    if (this.options.scaleX) d.width = width.round() + 'px';\n    if (this.options.scaleY) d.height = height.round() + 'px';\n    if (this.options.scaleFromCenter) {\n      var topd  = (height - this.dims[0])/2;\n      var leftd = (width  - this.dims[1])/2;\n      if (this.elementPositioning == 'absolute') {\n        if (this.options.scaleY) d.top = this.originalTop-topd + 'px';\n        if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';\n      } else {\n        if (this.options.scaleY) d.top = -topd + 'px';\n        if (this.options.scaleX) d.left = -leftd + 'px';\n      }\n    }\n    this.element.setStyle(d);\n  }\n});\n\nEffect.Highlight = Class.create(Effect.Base, {\n  initialize: function(element) {\n    this.element = $(element);\n    if (!this.element) throw(Effect._elementDoesNotExistError);\n    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });\n    this.start(options);\n  },\n  setup: function() {\n    // Prevent executing on elements not in the layout flow\n    if (this.element.getStyle('display')=='none') { this.cancel(); return; }\n    // Disable background image during the effect\n    this.oldStyle = { };\n    if (!this.options.keepBackgroundImage) {\n      this.oldStyle.backgroundImage = this.element.getStyle('background-image');\n      this.element.setStyle({backgroundImage: 'none'});\n    }\n    if (!this.options.endcolor)\n      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');\n    if (!this.options.restorecolor)\n      this.options.restorecolor = this.element.getStyle('background-color');\n    // init color calculations\n    this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));\n    this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));\n  },\n  update: function(position) {\n    this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){\n      return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });\n  },\n  finish: function() {\n    this.element.setStyle(Object.extend(this.oldStyle, {\n      backgroundColor: this.options.restorecolor\n    }));\n  }\n});\n\nEffect.ScrollTo = function(element) {\n  var options = arguments[1] || { },\n  scrollOffsets = document.viewport.getScrollOffsets(),\n  elementOffsets = $(element).cumulativeOffset();\n\n  if (options.offset) elementOffsets[1] += options.offset;\n\n  return new Effect.Tween(null,\n    scrollOffsets.top,\n    elementOffsets[1],\n    options,\n    function(p){ scrollTo(scrollOffsets.left, p.round()); }\n  );\n};\n\n/* ------------- combination effects ------------- */\n\nEffect.Fade = function(element) {\n  element = $(element);\n  var oldOpacity = element.getInlineOpacity();\n  var options = Object.extend({\n    from: element.getOpacity() || 1.0,\n    to:   0.0,\n    afterFinishInternal: function(effect) {\n      if (effect.options.to!=0) return;\n      effect.element.hide().setStyle({opacity: oldOpacity});\n    }\n  }, arguments[1] || { });\n  return new Effect.Opacity(element,options);\n};\n\nEffect.Appear = function(element) {\n  element = $(element);\n  var options = Object.extend({\n  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),\n  to:   1.0,\n  // force Safari to render floated elements properly\n  afterFinishInternal: function(effect) {\n    effect.element.forceRerendering();\n  },\n  beforeSetup: function(effect) {\n    effect.element.setOpacity(effect.options.from).show();\n  }}, arguments[1] || { });\n  return new Effect.Opacity(element,options);\n};\n\nEffect.Puff = function(element) {\n  element = $(element);\n  var oldStyle = {\n    opacity: element.getInlineOpacity(),\n    position: element.getStyle('position'),\n    top:  element.style.top,\n    left: element.style.left,\n    width: element.style.width,\n    height: element.style.height\n  };\n  return new Effect.Parallel(\n   [ new Effect.Scale(element, 200,\n      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),\n     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],\n     Object.extend({ duration: 1.0,\n      beforeSetupInternal: function(effect) {\n        Position.absolutize(effect.effects[0].element);\n      },\n      afterFinishInternal: function(effect) {\n         effect.effects[0].element.hide().setStyle(oldStyle); }\n     }, arguments[1] || { })\n   );\n};\n\nEffect.BlindUp = function(element) {\n  element = $(element);\n  element.makeClipping();\n  return new Effect.Scale(element, 0,\n    Object.extend({ scaleContent: false,\n      scaleX: false,\n      restoreAfterFinish: true,\n      afterFinishInternal: function(effect) {\n        effect.element.hide().undoClipping();\n      }\n    }, arguments[1] || { })\n  );\n};\n\nEffect.BlindDown = function(element) {\n  element = $(element);\n  var elementDimensions = element.getDimensions();\n  return new Effect.Scale(element, 100, Object.extend({\n    scaleContent: false,\n    scaleX: false,\n    scaleFrom: 0,\n    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},\n    restoreAfterFinish: true,\n    afterSetup: function(effect) {\n      effect.element.makeClipping().setStyle({height: '0px'}).show();\n    },\n    afterFinishInternal: function(effect) {\n      effect.element.undoClipping();\n    }\n  }, arguments[1] || { }));\n};\n\nEffect.SwitchOff = function(element) {\n  element = $(element);\n  var oldOpacity = element.getInlineOpacity();\n  return new Effect.Appear(element, Object.extend({\n    duration: 0.4,\n    from: 0,\n    transition: Effect.Transitions.flicker,\n    afterFinishInternal: function(effect) {\n      new Effect.Scale(effect.element, 1, {\n        duration: 0.3, scaleFromCenter: true,\n        scaleX: false, scaleContent: false, restoreAfterFinish: true,\n        beforeSetup: function(effect) {\n          effect.element.makePositioned().makeClipping();\n        },\n        afterFinishInternal: function(effect) {\n          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});\n        }\n      });\n    }\n  }, arguments[1] || { }));\n};\n\nEffect.DropOut = function(element) {\n  element = $(element);\n  var oldStyle = {\n    top: element.getStyle('top'),\n    left: element.getStyle('left'),\n    opacity: element.getInlineOpacity() };\n  return new Effect.Parallel(\n    [ new Effect.Move(element, {x: 0, y: 100, sync: true }),\n      new Effect.Opacity(element, { sync: true, to: 0.0 }) ],\n    Object.extend(\n      { duration: 0.5,\n        beforeSetup: function(effect) {\n          effect.effects[0].element.makePositioned();\n        },\n        afterFinishInternal: function(effect) {\n          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);\n        }\n      }, arguments[1] || { }));\n};\n\nEffect.Shake = function(element) {\n  element = $(element);\n  var options = Object.extend({\n    distance: 20,\n    duration: 0.5\n  }, arguments[1] || {});\n  var distance = parseFloat(options.distance);\n  var split = parseFloat(options.duration) / 10.0;\n  var oldStyle = {\n    top: element.getStyle('top'),\n    left: element.getStyle('left') };\n    return new Effect.Move(element,\n      { x:  distance, y: 0, duration: split, afterFinishInternal: function(effect) {\n    new Effect.Move(effect.element,\n      { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {\n    new Effect.Move(effect.element,\n      { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {\n    new Effect.Move(effect.element,\n      { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {\n    new Effect.Move(effect.element,\n      { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {\n    new Effect.Move(effect.element,\n      { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {\n        effect.element.undoPositioned().setStyle(oldStyle);\n  }}); }}); }}); }}); }}); }});\n};\n\nEffect.SlideDown = function(element) {\n  element = $(element).cleanWhitespace();\n  // SlideDown need to have the content of the element wrapped in a container element with fixed height!\n  var oldInnerBottom = element.down().getStyle('bottom');\n  var elementDimensions = element.getDimensions();\n  return new Effect.Scale(element, 100, Object.extend({\n    scaleContent: false,\n    scaleX: false,\n    scaleFrom: window.opera ? 0 : 1,\n    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},\n    restoreAfterFinish: true,\n    afterSetup: function(effect) {\n      effect.element.makePositioned();\n      effect.element.down().makePositioned();\n      if (window.opera) effect.element.setStyle({top: ''});\n      effect.element.makeClipping().setStyle({height: '0px'}).show();\n    },\n    afterUpdateInternal: function(effect) {\n      effect.element.down().setStyle({bottom:\n        (effect.dims[0] - effect.element.clientHeight) + 'px' });\n    },\n    afterFinishInternal: function(effect) {\n      effect.element.undoClipping().undoPositioned();\n      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }\n    }, arguments[1] || { })\n  );\n};\n\nEffect.SlideUp = function(element) {\n  element = $(element).cleanWhitespace();\n  var oldInnerBottom = element.down().getStyle('bottom');\n  var elementDimensions = element.getDimensions();\n  return new Effect.Scale(element, window.opera ? 0 : 1,\n   Object.extend({ scaleContent: false,\n    scaleX: false,\n    scaleMode: 'box',\n    scaleFrom: 100,\n    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},\n    restoreAfterFinish: true,\n    afterSetup: function(effect) {\n      effect.element.makePositioned();\n      effect.element.down().makePositioned();\n      if (window.opera) effect.element.setStyle({top: ''});\n      effect.element.makeClipping().show();\n    },\n    afterUpdateInternal: function(effect) {\n      effect.element.down().setStyle({bottom:\n        (effect.dims[0] - effect.element.clientHeight) + 'px' });\n    },\n    afterFinishInternal: function(effect) {\n      effect.element.hide().undoClipping().undoPositioned();\n      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});\n    }\n   }, arguments[1] || { })\n  );\n};\n\n// Bug in opera makes the TD containing this element expand for a instance after finish\nEffect.Squish = function(element) {\n  return new Effect.Scale(element, window.opera ? 1 : 0, {\n    restoreAfterFinish: true,\n    beforeSetup: function(effect) {\n      effect.element.makeClipping();\n    },\n    afterFinishInternal: function(effect) {\n      effect.element.hide().undoClipping();\n    }\n  });\n};\n\nEffect.Grow = function(element) {\n  element = $(element);\n  var options = Object.extend({\n    direction: 'center',\n    moveTransition: Effect.Transitions.sinoidal,\n    scaleTransition: Effect.Transitions.sinoidal,\n    opacityTransition: Effect.Transitions.full\n  }, arguments[1] || { });\n  var oldStyle = {\n    top: element.style.top,\n    left: element.style.left,\n    height: element.style.height,\n    width: element.style.width,\n    opacity: element.getInlineOpacity() };\n\n  var dims = element.getDimensions();\n  var initialMoveX, initialMoveY;\n  var moveX, moveY;\n\n  switch (options.direction) {\n    case 'top-left':\n      initialMoveX = initialMoveY = moveX = moveY = 0;\n      break;\n    case 'top-right':\n      initialMoveX = dims.width;\n      initialMoveY = moveY = 0;\n      moveX = -dims.width;\n      break;\n    case 'bottom-left':\n      initialMoveX = moveX = 0;\n      initialMoveY = dims.height;\n      moveY = -dims.height;\n      break;\n    case 'bottom-right':\n      initialMoveX = dims.width;\n      initialMoveY = dims.height;\n      moveX = -dims.width;\n      moveY = -dims.height;\n      break;\n    case 'center':\n      initialMoveX = dims.width / 2;\n      initialMoveY = dims.height / 2;\n      moveX = -dims.width / 2;\n      moveY = -dims.height / 2;\n      break;\n  }\n\n  return new Effect.Move(element, {\n    x: initialMoveX,\n    y: initialMoveY,\n    duration: 0.01,\n    beforeSetup: function(effect) {\n      effect.element.hide().makeClipping().makePositioned();\n    },\n    afterFinishInternal: function(effect) {\n      new Effect.Parallel(\n        [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),\n          new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),\n          new Effect.Scale(effect.element, 100, {\n            scaleMode: { originalHeight: dims.height, originalWidth: dims.width },\n            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})\n        ], Object.extend({\n             beforeSetup: function(effect) {\n               effect.effects[0].element.setStyle({height: '0px'}).show();\n             },\n             afterFinishInternal: function(effect) {\n               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);\n             }\n           }, options)\n      );\n    }\n  });\n};\n\nEffect.Shrink = function(element) {\n  element = $(element);\n  var options = Object.extend({\n    direction: 'center',\n    moveTransition: Effect.Transitions.sinoidal,\n    scaleTransition: Effect.Transitions.sinoidal,\n    opacityTransition: Effect.Transitions.none\n  }, arguments[1] || { });\n  var oldStyle = {\n    top: element.style.top,\n    left: element.style.left,\n    height: element.style.height,\n    width: element.style.width,\n    opacity: element.getInlineOpacity() };\n\n  var dims = element.getDimensions();\n  var moveX, moveY;\n\n  switch (options.direction) {\n    case 'top-left':\n      moveX = moveY = 0;\n      break;\n    case 'top-right':\n      moveX = dims.width;\n      moveY = 0;\n      break;\n    case 'bottom-left':\n      moveX = 0;\n      moveY = dims.height;\n      break;\n    case 'bottom-right':\n      moveX = dims.width;\n      moveY = dims.height;\n      break;\n    case 'center':\n      moveX = dims.width / 2;\n      moveY = dims.height / 2;\n      break;\n  }\n\n  return new Effect.Parallel(\n    [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),\n      new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),\n      new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })\n    ], Object.extend({\n         beforeStartInternal: function(effect) {\n           effect.effects[0].element.makePositioned().makeClipping();\n         },\n         afterFinishInternal: function(effect) {\n           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }\n       }, options)\n  );\n};\n\nEffect.Pulsate = function(element) {\n  element = $(element);\n  var options    = arguments[1] || { },\n    oldOpacity = element.getInlineOpacity(),\n    transition = options.transition || Effect.Transitions.linear,\n    reverser   = function(pos){\n      return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);\n    };\n\n  return new Effect.Opacity(element,\n    Object.extend(Object.extend({  duration: 2.0, from: 0,\n      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }\n    }, options), {transition: reverser}));\n};\n\nEffect.Fold = function(element) {\n  element = $(element);\n  var oldStyle = {\n    top: element.style.top,\n    left: element.style.left,\n    width: element.style.width,\n    height: element.style.height };\n  element.makeClipping();\n  return new Effect.Scale(element, 5, Object.extend({\n    scaleContent: false,\n    scaleX: false,\n    afterFinishInternal: function(effect) {\n    new Effect.Scale(element, 1, {\n      scaleContent: false,\n      scaleY: false,\n      afterFinishInternal: function(effect) {\n        effect.element.hide().undoClipping().setStyle(oldStyle);\n      } });\n  }}, arguments[1] || { }));\n};\n\nEffect.Morph = Class.create(Effect.Base, {\n  initialize: function(element) {\n    this.element = $(element);\n    if (!this.element) throw(Effect._elementDoesNotExistError);\n    var options = Object.extend({\n      style: { }\n    }, arguments[1] || { });\n\n    if (!Object.isString(options.style)) this.style = $H(options.style);\n    else {\n      if (options.style.include(':'))\n        this.style = options.style.parseStyle();\n      else {\n        this.element.addClassName(options.style);\n        this.style = $H(this.element.getStyles());\n        this.element.removeClassName(options.style);\n        var css = this.element.getStyles();\n        this.style = this.style.reject(function(style) {\n          return style.value == css[style.key];\n        });\n        options.afterFinishInternal = function(effect) {\n          effect.element.addClassName(effect.options.style);\n          effect.transforms.each(function(transform) {\n            effect.element.style[transform.style] = '';\n          });\n        };\n      }\n    }\n    this.start(options);\n  },\n\n  setup: function(){\n    function parseColor(color){\n      if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';\n      color = color.parseColor();\n      return $R(0,2).map(function(i){\n        return parseInt( color.slice(i*2+1,i*2+3), 16 );\n      });\n    }\n    this.transforms = this.style.map(function(pair){\n      var property = pair[0], value = pair[1], unit = null;\n\n      if (value.parseColor('#zzzzzz') != '#zzzzzz') {\n        value = value.parseColor();\n        unit  = 'color';\n      } else if (property == 'opacity') {\n        value = parseFloat(value);\n        if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))\n          this.element.setStyle({zoom: 1});\n      } else if (Element.CSS_LENGTH.test(value)) {\n          var components = value.match(/^([\\+\\-]?[0-9\\.]+)(.*)$/);\n          value = parseFloat(components[1]);\n          unit = (components.length == 3) ? components[2] : null;\n      }\n\n      var originalValue = this.element.getStyle(property);\n      return {\n        style: property.camelize(),\n        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),\n        targetValue: unit=='color' ? parseColor(value) : value,\n        unit: unit\n      };\n    }.bind(this)).reject(function(transform){\n      return (\n        (transform.originalValue == transform.targetValue) ||\n        (\n          transform.unit != 'color' &&\n          (isNaN(transform.originalValue) || isNaN(transform.targetValue))\n        )\n      );\n    });\n  },\n  update: function(position) {\n    var style = { }, transform, i = this.transforms.length;\n    while(i--)\n      style[(transform = this.transforms[i]).style] =\n        transform.unit=='color' ? '#'+\n          (Math.round(transform.originalValue[0]+\n            (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +\n          (Math.round(transform.originalValue[1]+\n            (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +\n          (Math.round(transform.originalValue[2]+\n            (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :\n        (transform.originalValue +\n          (transform.targetValue - transform.originalValue) * position).toFixed(3) +\n            (transform.unit === null ? '' : transform.unit);\n    this.element.setStyle(style, true);\n  }\n});\n\nEffect.Transform = Class.create({\n  initialize: function(tracks){\n    this.tracks  = [];\n    this.options = arguments[1] || { };\n    this.addTracks(tracks);\n  },\n  addTracks: function(tracks){\n    tracks.each(function(track){\n      track = $H(track);\n      var data = track.values().first();\n      this.tracks.push($H({\n        ids:     track.keys().first(),\n        effect:  Effect.Morph,\n        options: { style: data }\n      }));\n    }.bind(this));\n    return this;\n  },\n  play: function(){\n    return new Effect.Parallel(\n      this.tracks.map(function(track){\n        var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');\n        var elements = [$(ids) || $$(ids)].flatten();\n        return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });\n      }).flatten(),\n      this.options\n    );\n  }\n});\n\nElement.CSS_PROPERTIES = $w(\n  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +\n  'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +\n  'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +\n  'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +\n  'fontSize fontWeight height left letterSpacing lineHeight ' +\n  'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+\n  'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +\n  'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +\n  'right textIndent top width wordSpacing zIndex');\n\nElement.CSS_LENGTH = /^(([\\+\\-]?[0-9\\.]+)(em|ex|px|in|cm|mm|pt|pc|\\%))|0$/;\n\nString.__parseStyleElement = document.createElement('div');\nString.prototype.parseStyle = function(){\n  var style, styleRules = $H();\n  if (Prototype.Browser.WebKit)\n    style = new Element('div',{style:this}).style;\n  else {\n    String.__parseStyleElement.innerHTML = '<div style=\"' + this + '\"></div>';\n    style = String.__parseStyleElement.childNodes[0].style;\n  }\n\n  Element.CSS_PROPERTIES.each(function(property){\n    if (style[property]) styleRules.set(property, style[property]);\n  });\n\n  if (Prototype.Browser.IE && this.include('opacity'))\n    styleRules.set('opacity', this.match(/opacity:\\s*((?:0|1)?(?:\\.\\d*)?)/)[1]);\n\n  return styleRules;\n};\n\nif (document.defaultView && document.defaultView.getComputedStyle) {\n  Element.getStyles = function(element) {\n    var css = document.defaultView.getComputedStyle($(element), null);\n    return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {\n      styles[property] = css[property];\n      return styles;\n    });\n  };\n} else {\n  Element.getStyles = function(element) {\n    element = $(element);\n    var css = element.currentStyle, styles;\n    styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {\n      results[property] = css[property];\n      return results;\n    });\n    if (!styles.opacity) styles.opacity = element.getOpacity();\n    return styles;\n  };\n}\n\nEffect.Methods = {\n  morph: function(element, style) {\n    element = $(element);\n    new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));\n    return element;\n  },\n  visualEffect: function(element, effect, options) {\n    element = $(element);\n    var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);\n    new Effect[klass](element, options);\n    return element;\n  },\n  highlight: function(element, options) {\n    element = $(element);\n    new Effect.Highlight(element, options);\n    return element;\n  }\n};\n\n$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+\n  'pulsate shake puff squish switchOff dropOut').each(\n  function(effect) {\n    Effect.Methods[effect] = function(element, options){\n      element = $(element);\n      Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);\n      return element;\n    };\n  }\n);\n\n$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(\n  function(f) { Effect.Methods[f] = Element[f]; }\n);\n\nElement.addMethods(Effect.Methods);\n"
  },
  {
    "path": "public/javascripts/enterprise_map.js",
    "content": "var labelType, useGradients, nativeTextSupport, animate, rgraph;\n\n(function() {\n  var ua = navigator.userAgent,\n      iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),\n      typeOfCanvas = typeof HTMLCanvasElement,\n      nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),\n      textSupport = nativeCanvasSupport\n        && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');\n  //I'm setting this based on the fact that ExCanvas provides text support for IE\n  //and that as of today iPhone/iPad current text support is lame\n  labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';\n  nativeTextSupport = labelType == 'Native';\n  useGradients = nativeCanvasSupport;\n  animate = !(iStuff || !nativeCanvasSupport);\n})();\n\n// var Log = {\n//   elem: false,\n//   write: function(text){\n//     if (!this.elem)\n//       this.elem = document.getElementById('log');\n//     this.elem.innerHTML = text;\n//     this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';\n//   }\n// };\n\n\nfunction init() {\n    //init data\n\n   // var jsonpie = {\n   //    'id': 'root',\n   //    'name': 'RGraph based Pie Chart',\n   //    'data': {\n   //        '$type': 'none'\n   //    },\n   //    'children':[\n   //      {\n   //          'id':'pie1',\n   //          'name': 'pie1',\n   //          'data': {\n   //              '$angularWidth': 70,\n   //              '$color': '#f55'\n   //          },\n   //          'children': []\n   //      }\n   //    ]\n   //  };\n    //end\n\n      //     //init nodetypes\n      //     //Here we implement custom node rendering types for the RGraph\n      //     //Using this feature requires some javascript and canvas experience.\n      //     $jit.RGraph.Plot.NodeTypes.implement({\n      //         //This node type is used for plotting pie-chart slices as nodes\n      //         'nodepie': {\n      //           'render': function(node, canvas) {\n      //             var span = node.angleSpan, begin = span.begin, end = span.end;\n      //             var polarNode = node.pos.getp(true);\n      //             var polar = new $jit.Polar(polarNode.rho, begin);\n      //             var p1coord = polar.getc(true);\n      //             polar.theta = end;\n      //             var p2coord = polar.getc(true);\n      //\n      //             var ctx = canvas.getCtx();\n      //             ctx.beginPath();\n      //             ctx.moveTo(0, 0);\n      //             ctx.lineTo(p1coord.x, p1coord.y);\n      //             ctx.moveTo(0, 0);\n      //             ctx.lineTo(p2coord.x, p2coord.y);\n      //             ctx.moveTo(0, 0);\n      //             ctx.arc(0, 0, polarNode.rho, begin, end, false);\n      //             ctx.fill();\n      //           }\n      //         },\n      //         //Create a new node type that renders an entire RGraph visualization\n      //         //as node\n      //         'piechart': {\n      //           'render': function(node, canvas, animating) {\n      //             var ctx = canvas.getCtx(), pos = node.pos.getc(true);\n      //             ctx.save();\n      // // console.log('node' + node.data['$angularWidth'] + '  canvas:' + canvas + '  animating:' + animating);\n      //             ctx.translate(pos.x, pos.y);\n      //\n      //             pie.plot();\n      //             ctx.restore();\n      //           }\n      //          }\n      //     });\n      //     //end\n\n    // //init pie\n    // //This RGraph instance will be used as the node for\n    // //another RGraph instance.\n    // var pie = new $jit.RGraph({\n    //     'injectInto': 'infovis',\n    //     //Optional: create a background canvas and plot\n    //     //concentric circles in it.\n    //     'background': {\n    //       CanvasStyles: {\n    //         strokeStyle: '#eee'\n    //       }\n    //     },\n    //     //Add node/edge styles and set\n    //     //overridable=true if you want your\n    //     //styles to be individually overriden\n    //     Node: {\n    //         'overridable': true,\n    //          'type':'nodepie'\n    //     },\n    //     Edge: {\n    //         'type':'none'\n    //     },\n    //     //Parent-children distance\n    //     levelDistance: 30,\n    //     //Don't create labels in this visualization\n    //     withLabels: false,\n    //     //Don't clear the entire canvas when plotting\n    //     //this visualization\n    //     clearCanvas: false\n    // });\n    // //load graph.\n    // pie.loadJSON(jsonpie);\n    // pie.compute();\n    // //end\n\n    //init rgraph\n    rgraph = new $jit.RGraph({\n      injectInto: 'infovis',\n\n        // useCanvas: pie.canvas,\n        //Add node/edge styles and set\n        //overridable=true if you want your\n        //styles to be individually overriden\n        Node: {\n            //set the RGraph rendering function\n            //as node type\n       'overridable': true,\n           'type': 'circle'\n        },\n        Edge: {\n            color: '#ccc'\n        },\n        //Parent-children distance\n        levelDistance: 150,\n        //Duration\n        duration: 1500,\n        //Add styles to node labels on label creation\n        onCreateLabel: function(domElement, node){\n            domElement.innerHTML = node.name;\n            var style = domElement.style;\n            style.fontSize = \"1em\";\n            style.color = \"#111\";\n            style.cursor = \"pointer\";\n            domElement.onclick = function() {\n              rgraph.onClick(node.id, {\n                  hideLabels: false\n              });\n            };\n        },\n\n        onPlaceLabel: function(domElement, node){\n            var style = domElement.style;\n            var left = parseInt(style.left);\n            var w = domElement.offsetWidth;\n            style.left = (left - w / 2) + 'px';\n            style.display = '';\n        }\n    });\n    //load graph.\n    rgraph.loadJSON(json);\n    // rgraph.refresh();\n    //trigger small animation\n    rgraph.graph.eachNode(function(n) {\n      var pos = n.getPos();\n      pos.setc(-200, -200);\n    });\n    rgraph.compute('end');\n    rgraph.fx.animate({\n      modes:['polar'],\n      duration: 2000\n    });\n\n    //end\n}\n\nfunction refresh_data(){\n  //load JSON data.\n    // rgraph.loadJSON(json2);\n    // rgraph.refresh();\n    //trigger small animation\n  // rgraph.compute('end');\n  // rgraph.op.morph(json2,{\n  //   type: 'fade:con',\n  //   duration: 2500\n  // }//,{'position': 'linear','node-property': ['dim']}\n  // );\n\n  rgraph.op.morph(json2, {\n      type: 'fade:seq',\n      duration: 1500,\n      hideLabels: false\n    }, {\n    'node-property': 'dim'\n    });\n\n    // rgraph.refresh();\n\n}\n"
  },
  {
    "path": "public/javascripts/fancybox/jquery.fancybox-1.3.0.css",
    "content": "/*\n * FancyBox - jQuery Plugin\n * Simple and fancy lightbox alternative\n *\n * Copyright (c) 20010 Janis Skarnelis\n * Examples and documentation at: http://fancybox.net\n *\n * Version: 1.3.0 (02/02/2010)\n * Requires: jQuery v1.3+\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n */\n\n#fancybox-loading {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  height: 40px;\n  width: 40px;\n  margin-top: -20px;\n  margin-left: -20px;\n  cursor: pointer;\n  overflow: hidden;\n  background: transparent;\n  z-index: 1104;\n  display: none;\n}\n\n* html #fancybox-loading {  /* IE6 */\n  position: absolute;\n  margin-top: 0;\n}\n\n#fancybox-loading div {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 40px;\n  height: 480px;\n  background: transparent url('fancy_loading.png') no-repeat;\n}\n\n#fancybox-overlay {\n  position: fixed;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  background: #000;\n  z-index: 1100;\n  display: none;\n}\n\n* html #fancybox-overlay {  /* IE6 */\n  position: absolute;\n  width: 100%;\n}\n\n#fancybox-tmp {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  overflow: auto;\n  display: none;\n}\n\n#fancybox-wrap {\n  position: absolute;\n  top: 0;\n  left: 0;\n  margin: 0;\n  padding: 20px;\n  z-index: 1101;\n  display: none;\n}\n\n#fancybox-outer {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #FFF;\n}\n\n#fancybox-inner {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: 0;\n  outline: none;\n  overflow: hidden;\n}\n\n#fancybox-hide-sel-frame {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: transparent;\n}\n\n#fancybox-close {\n  position: absolute;\n  top: -15px;\n  right: -15px;\n  width: 32px;\n  height: 32px;\n  background: url('fancy_close.png') top left no-repeat;\n  cursor: pointer;\n  z-index: 1103;\n  display: none;\n}\n\n#fancybox_error {\n  color: #444;\n  font: normal 12px/20px Arial;\n}\n\n#fancybox-content {\n  height: auto;\n  width: auto;\n  padding: 0;\n  margin: 0;\n}\n\n#fancybox-img {\n  width: 100%;\n  height: 100%;\n  padding: 0;\n  margin: 0;\n  border: none;\n  outline: none;\n  line-height: 0;\n  vertical-align: top;\n  -ms-interpolation-mode: bicubic;\n}\n\n#fancybox-frame {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  border: none;\n  display: block;\n}\n\n#fancybox-title {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  font-family: Arial;\n  font-size: 12px;\n  z-index: 1102;\n}\n\n.fancybox-title-inside {\n  padding: 10px 0;\n  text-align: center;\n  color: #333;\n}\n\n.fancybox-title-outside {\n  padding-top: 5px;\n  color: #FFF;\n  text-align: center;\n  font-weight: bold;\n}\n\n.fancybox-title-over {\n  color: #FFF;\n  text-align: left;\n}\n\n#fancybox-title-over {\n  padding: 10px;\n  background: url('fancy_title_over.png');\n  display: block;\n}\n\n#fancybox-title-wrap {\n  display: inline-block;\n}\n\n#fancybox-title-wrap span {\n  height: 32px;\n  float: left;\n}\n\n#fancybox-title-left {\n  padding-left: 15px;\n  background: transparent url('fancy_title_left.png') repeat-x;\n}\n\n#fancybox-title-main {\n  font-weight: bold;\n  line-height: 29px;\n  background: transparent url('fancy_title_main.png') repeat-x;\n  color: #FFF;\n}\n\n#fancybox-title-right {\n  padding-left: 15px;\n  background: transparent url('fancy_title_right.png') repeat-x;\n}\n\n#fancybox-left, #fancybox-right {\n  position: absolute;\n  bottom: 0px;\n  height: 100%;\n  width: 35%;\n  cursor: pointer;\n  outline: none;\n  background-image: url('blank.gif');\n  z-index: 1102;\n  display: none;\n}\n\n#fancybox-left {\n  left: 0px;\n}\n\n#fancybox-right {\n  right: 0px;\n}\n\n#fancybox-left-ico, #fancybox-right-ico {\n  position: absolute;\n  top: 50%;\n  left: -9999px;\n  width: 30px;\n  height: 30px;\n  margin-top: -15px;\n  cursor: pointer;\n  z-index: 1102;\n  display: block;\n}\n\n#fancybox-left-ico {\n  background: transparent url('fancy_nav_left.png') no-repeat;\n}\n\n#fancybox-right-ico {\n  background: transparent url('fancy_nav_right.png') no-repeat;\n}\n\n#fancybox-left:hover, #fancybox-right:hover {\n  visibility: visible;    /* IE6 */\n}\n\n#fancybox-left:hover span {\n  left: 20px;\n}\n\n#fancybox-right:hover span {\n  left: auto;\n  right: 20px;\n}\n\ndiv.fancy-bg {\n  position: absolute;\n  padding: 0;\n  margin: 0;\n  border: 0;\n  z-index: 1001;\n}\n\ndiv#fancy-bg-n {\n  top: -20px;\n  left: 0;\n  width: 100%;\n  height: 20px;\n  background: transparent url('fancy_shadow_n.png') repeat-x;\n}\n\ndiv#fancy-bg-ne {\n  top: -20px;\n  right: -20px;\n  width: 20px;\n  height: 20px;\n  background: transparent url('fancy_shadow_ne.png') no-repeat;\n}\n\ndiv#fancy-bg-e {\n  top: 0;\n  right: -20px;\n  height: 100%;\n  width: 20px;\n  background: transparent url('fancy_shadow_e.png') repeat-y;\n}\n\ndiv#fancy-bg-se {\n  bottom: -20px;\n  right: -20px;\n  width: 20px;\n  height: 20px;\n  background: transparent url('fancy_shadow_se.png') no-repeat;\n}\n\ndiv#fancy-bg-s {\n  bottom: -20px;\n  left: 0;\n  width: 100%;\n  height: 20px;\n  background: transparent url('fancy_shadow_s.png') repeat-x;\n}\n\ndiv#fancy-bg-sw {\n  bottom: -20px;\n  left: -20px;\n  width: 20px;\n  height: 20px;\n  background: transparent url('fancy_shadow_sw.png') no-repeat;\n}\n\ndiv#fancy-bg-w {\n  top: 0;\n  left: -20px;\n  height: 100%;\n  width: 20px;\n  background: transparent url('fancy_shadow_w.png') repeat-y;\n}\n\ndiv#fancy-bg-nw {\n  top: -20px;\n  left: -20px;\n  width: 20px;\n  height: 20px;\n  background: transparent url('fancy_shadow_nw.png') no-repeat;\n}\n"
  },
  {
    "path": "public/javascripts/fancybox/jquery.fancybox-1.3.0.pack.js",
    "content": "/*\n * FancyBox - jQuery Plugin\n * Simple and fancy lightbox alternative\n *\n * Copyright (c) 20010 Janis Skarnelis\n * Examples and documentation at: http://fancybox.net\n *\n * Version: 1.3.0 (02/02/2010)\n * Requires: jQuery v1.3+\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n */\n\n;(function(b){function H(){v.hide();r.onerror=r.onload=null;F&&F.abort();l.empty()}function Q(){b.fancybox('<p id=\"fancybox_error\">The requested content cannot be loaded.<br />Please try again later.</p>',{scrolling:\"no\",padding:20,transitionIn:\"none\",transitionOut:\"none\"})}function B(){H();var a=q[s];e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data(\"fancybox\")==\"undefined\"?e:b(a).data(\"fancybox\"));var d,f,o=a.title||b(a).title||e.title||\"\";if(a.nodeName&&!e.orig)e.orig=b(a).children(\"img:first\").length?\nb(a).children(\"img:first\"):b(a);if(o==\"\"&&e.orig)o=e.orig.attr(\"alt\");d=a.nodeName&&/^(?:javascript|#)/i.test(a.href)?e.href||null:e.href||a.href||null;if(e.type){f=e.type;if(!d)d=e.content}else if(e.content)f=\"html\";else if(d)if(d.match(I))f=\"image\";else if(d.match(T))f=\"swf\";else if(b(a).hasClass(\"iframe\"))f=\"iframe\";else if(d.match(/#/)){a=d.substr(d.indexOf(\"#\"));f=b(a).length>0?\"inline\":\"ajax\"}else f=\"ajax\";else f=\"inline\";e.type=f;e.href=d;e.title=o;if(e.autoDimensions&&e.type!==\"iframe\"&&e.type!==\n\"swf\"){e.width=\"auto\";e.height=\"auto\"}if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=false;e.enableEscapeButton=false;e.showCloseButton=false}if(b.isFunction(e.onStart))if(e.onStart(q,s,e)===false){h=false;return}l.css(\"padding\",t+e.padding+e.margin);b(\".fancybox-inline-tmp\").unbind(\"fancybox-cancel\").bind(\"fancybox-change\",function(){b(this).replaceWith(i.children())});switch(f){case \"html\":l.html(e.content);G();break;case \"inline\":b('<div class=\"fancybox-inline-tmp\" />').hide().insertBefore(b(a)).bind(\"fancybox-cleanup\",\nfunction(){b(this).replaceWith(i.children())}).bind(\"fancybox-cancel\",function(){b(this).replaceWith(l.children())});b(a).appendTo(l);G();break;case \"image\":h=false;b.fancybox.showActivity();r=new Image;r.onerror=function(){Q()};r.onload=function(){r.onerror=null;r.onload=null;U()};r.src=d;break;case \"swf\":var u=\"\",w=\"\";u+='<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\"'+e.width+'\" height=\"'+e.height+'\"><param name=\"movie\" value=\"'+d+'\"></param>';b.each(e.swf,function(p,R){u+=\n'<param name=\"'+p+'\" value=\"'+R+'\"></param>';w+=\" \"+p+'=\"'+R+'\"'});u+='<embed src=\"'+d+'\" type=\"application/x-shockwave-flash\" width=\"'+e.width+'\" height=\"'+e.height+'\"'+w+\"></embed></object>\";l.html(u);G();break;case \"ajax\":a=d.split(\"#\",2);f=e.ajax.data||{};if(a.length>1){d=a[0];typeof f==\"string\"?(f+=\"&selector=\"+a[1]):(f.selector=a[1])}h=false;b.fancybox.showActivity();F=b.ajax(b.extend(e.ajax,{url:d,data:f,error:Q,success:function(p){if(F.status==200){l.html(p);G()}}}));break;case \"iframe\":b('<iframe id=\"fancybox-frame\" name=\"fancybox-frame'+\n(new Date).getTime()+'\" frameborder=\"0\" hspace=\"0\" scrolling=\"'+e.scrolling+'\" src=\"'+e.href+'\"></iframe>').appendTo(l);J();break}}function U(){h=true;e.width=r.width;e.height=r.height;b(\"<img />\").attr({id:\"fancybox-img\",src:r.src,alt:e.title}).appendTo(l);J()}function G(){l.width(e.width);l.height(e.height);if(e.width==\"auto\")e.width=l.width();if(e.height==\"auto\")e.height=l.height();J()}function J(){v.hide();if(g.is(\":visible\")&&b.isFunction(c.onCleanup))if(c.onCleanup(j,n,c)===false){b.event.trigger(\"fancybox-cancel\");\nh=false;return}j=q;n=s;c=e;i.get(0).scrollTop=0;i.get(0).scrollLeft=0;if(c.overlayShow){K&&b(\"select:not(#fancybox-tmp select)\").filter(function(){return this.style.visibility!==\"hidden\"}).css({visibility:\"hidden\"}).one(\"fancybox-cleanup\",function(){this.style.visibility=\"inherit\"});y.css({\"background-color\":c.overlayColor,opacity:c.overlayOpacity}).unbind().show()}m=V();W();if(g.is(\":visible\")){b(z.add(C).add(D)).hide();var a=g.position();k={top:a.top,left:a.left,width:g.width(),height:g.height()};\nvar d=k.width==m.width&&k.height==m.height;i.fadeOut(c.changeFade,function(){function f(){i.html(l.contents()).fadeIn(c.changeFade,L)}b.event.trigger(\"fancybox-change\");i.css({top:c.padding,left:c.padding,width:Math.max(k.width-c.padding*2,1),height:Math.max(k.height-c.padding*2,1)}).empty().css(\"overflow\",\"hidden\");A.prop=0;b(A).animate({prop:1},{duration:d?0:c.changeSpeed,easing:c.easingChange,step:M,complete:f})})}else{g.css(\"opacity\",1);if(c.transitionIn==\"elastic\"){k=S();i.css({top:c.padding,\nleft:c.padding,width:Math.max(k.width-c.padding*2,1),height:Math.max(k.height-c.padding*2,1)}).html(l.contents());g.css(k).show();if(c.opacity)m.opacity=0;A.prop=0;b(A).animate({prop:1},{duration:c.speedIn,easing:c.easingIn,step:M,complete:L})}else{i.css({top:c.padding,left:c.padding,width:Math.max(m.width-c.padding*2,1),height:Math.max(m.height-c.padding*2-x,1)}).html(l.contents());g.css(m).fadeIn(c.transitionIn==\"none\"?0:c.speedIn,L)}}}function M(a){var d=Math.round(k.width+(m.width-k.width)*a),\nf=Math.round(k.height+(m.height-k.height)*a),o=Math.round(k.top+(m.top-k.top)*a),u=Math.round(k.left+(m.left-k.left)*a);g.css({width:d+\"px\",height:f+\"px\",top:o+\"px\",left:u+\"px\"});d=Math.max(d-c.padding*2,0);f=Math.max(f-(c.padding*2+x*a),0);i.css({width:d+\"px\",height:f+\"px\"});if(typeof m.opacity!==\"undefined\")g.css(\"opacity\",a<0.5?0.5:a)}function L(){i.css(\"overflow\",overflow=c.scrolling==\"auto\"?c.type==\"image\"||c.type==\"iframe\"||c.type==\"swf\"?\"hidden\":\"auto\":c.scrolling==\"yes\"?\"auto\":\"visible\");\nif(!b.support.opacity){i.get(0).style.removeAttribute(\"filter\");g.get(0).style.removeAttribute(\"filter\")}b(\"#fancybox-title\").show();c.hideOnContentClick&&i.one(\"click\",b.fancybox.close);c.hideOnOverlayClick&&y.one(\"click\",b.fancybox.close);c.showCloseButton&&z.show();X();b(window).bind(\"resize.fb\",b.fancybox.center);c.centerOnScroll?b(window).bind(\"scroll.fb\",b.fancybox.center):b(window).unbind(\"scroll.fb\");b.isFunction(c.onComplete)&&c.onComplete(j,n,c);h=false;Y()}function V(){var a=N(),d={},f=\nc.margin,o=c.autoScale,u=(t+f)*2,w=(t+f)*2,p=c.padding*2;if(c.width.toString().indexOf(\"%\")>-1){d.width=a[0]*parseFloat(c.width)/100-t*2;o=false}else d.width=c.width+p;if(c.height.toString().indexOf(\"%\")>-1){d.height=a[1]*parseFloat(c.height)/100-t*2;o=false}else d.height=c.height+p;if(o&&(d.width>a[0]-u||d.height>a[1]-w))if(e.type==\"image\"||e.type==\"swf\"){u+=p;w+=p;o=Math.min(Math.min(a[0]-u,c.width)/c.width,Math.min(a[1]-w,c.height)/c.height);d.width=Math.round(o*(d.width-p))+p;d.height=Math.round(o*\n(d.height-p))+p}else{d.width=Math.min(d.width,a[0]-u);d.height=Math.min(d.height,a[1]-w)}d.top=a[3]+(a[1]-(d.height+t*2))*0.5;d.left=a[2]+(a[0]-(d.width+t*2))*0.5;if(c.autoScale==false){d.top=Math.max(a[3]+f,d.top);d.left=Math.max(a[2]+f,d.left)}return d}function S(){var a=e.orig?b(e.orig):false,d={};if(a&&a.length){a=Z(a);d={width:a.width+c.padding*2,height:a.height+c.padding*2,top:a.top-c.padding-t,left:a.left-c.padding-t}}else{a=N();d={width:1,height:1,top:a[3]+a[1]*0.5,left:a[2]+a[0]*0.5}}return d}\nfunction X(){b(document).unbind(\"keydown.fb\").bind(\"keydown.fb\",function(a){if(a.keyCode==27&&c.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if(a.keyCode==37){a.preventDefault();b.fancybox.prev()}else if(a.keyCode==39){a.preventDefault();b.fancybox.next()}});if(b.fn.mousewheel){g.unbind(\"mousewheel.fb\");j.length>1&&g.bind(\"mousewheel.fb\",function(a,d){a.preventDefault();h||d==0||(d>0?b.fancybox.prev():b.fancybox.next())})}if(c.showNavArrows){if(c.cyclic&&j.length>1||n!=0)C.show();\nif(c.cyclic&&j.length>1||n!=j.length-1)D.show()}}function Y(){if(j.length-1>n){var a=j[n+1].href;if(typeof a!==\"undefined\"&&a.match(I)){var d=new Image;d.src=a}}if(n>0){a=j[n-1].href;if(typeof a!==\"undefined\"&&a.match(I)){d=new Image;d.src=a}}}function $(){if(v.is(\":visible\")){b(\"div\",v).css(\"top\",O*-40+\"px\");O=(O+1)%12}else clearInterval(P)}function N(){return[b(window).width(),b(window).height(),b(document).scrollLeft(),b(document).scrollTop()]}function Z(a){var d=a.offset();d.top+=parseFloat(a.css(\"paddingTop\"))||\n0;d.left+=parseFloat(a.css(\"paddingLeft\"))||0;d.top+=parseFloat(a.css(\"border-top-width\"))||0;d.left+=parseFloat(a.css(\"border-left-width\"))||0;d.width=a.width();d.height=a.height();return d}function W(){b(\"#fancybox-title\").remove();x=0;if(c.titleShow!=false){var a=c.title;a=b.isFunction(c.titleFormat)?c.titleFormat(a,j,n,c):aa(a);if(!(!a||a==\"\")){var d=m.width-c.padding*2;b('<div id=\"fancybox-title\" class=\"'+(\"fancybox-title-\"+c.titlePosition)+'\" />').css({width:d,paddingLeft:c.padding,paddingRight:c.padding}).html(a).appendTo(\"body\");\nswitch(c.titlePosition){case \"inside\":x=b(\"#fancybox-title\").outerHeight(true)-c.padding;m.height+=x;break;case \"over\":b(\"#fancybox-title\").css(\"bottom\",c.padding);break;default:b(\"#fancybox-title\").css(\"bottom\",b(\"#fancybox-title\").outerHeight(true)*-1);break}b(\"#fancybox-title\").appendTo(E).hide();K&&b(\"#fancybox-title span\").fixPNG()}}}function aa(a){if(a&&a.length)switch(c.titlePosition){case \"inside\":return a;case \"over\":return'<span id=\"fancybox-title-over\">'+a+\"</span>\";default:return'<span id=\"fancybox-title-wrap\"><span id=\"fancybox-title-left\"></span><span id=\"fancybox-title-main\">'+\na+'</span><span id=\"fancybox-title-right\"></span></span>'}return false}function ba(){if(!b(\"#fancybox-wrap\").length){b(\"body\").append(l=b('<div id=\"fancybox-tmp\"></div>'),v=b('<div id=\"fancybox-loading\"><div></div></div>'),y=b('<div id=\"fancybox-overlay\"></div>'),g=b('<div id=\"fancybox-wrap\"></div>'));E=b('<div id=\"fancybox-outer\"></div>').append('<div class=\"fancy-bg\" id=\"fancy-bg-n\"></div><div class=\"fancy-bg\" id=\"fancy-bg-ne\"></div><div class=\"fancy-bg\" id=\"fancy-bg-e\"></div><div class=\"fancy-bg\" id=\"fancy-bg-se\"></div><div class=\"fancy-bg\" id=\"fancy-bg-s\"></div><div class=\"fancy-bg\" id=\"fancy-bg-sw\"></div><div class=\"fancy-bg\" id=\"fancy-bg-w\"></div><div class=\"fancy-bg\" id=\"fancy-bg-nw\"></div>').appendTo(g);\nE.append(i=b('<div id=\"fancybox-inner\"></div>'),z=b('<a id=\"fancybox-close\"></a>'),C=b('<a href=\"javascript:;\" id=\"fancybox-left\"><span class=\"fancy-ico\" id=\"fancybox-left-ico\"></span></a>'),D=b('<a href=\"javascript:;\" id=\"fancybox-right\"><span class=\"fancy-ico\" id=\"fancybox-right-ico\"></span></a>'));z.click(b.fancybox.close);v.click(b.fancybox.cancel);C.click(function(a){a.preventDefault();b.fancybox.prev()});D.click(function(a){a.preventDefault();b.fancybox.next()});b.support.opacity||E.find(\".fancy-bg\").fixPNG();\nif(K){b(z.add(\".fancy-ico\").add(\"div\",v)).fixPNG();y.get(0).style.setExpression(\"height\",\"document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'\");v.get(0).style.setExpression(\"top\",\"(-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px'\");E.prepend('<iframe id=\"fancybox-hide-sel-frame\" src=\"javascript:\\'\\';\" scrolling=\"no\" frameborder=\"0\" ></iframe>')}}}\nvar l,v,y,g,E,i,z,C,D,s=0,e={},q=[],n=0,c={},j=[],F=null,r=new Image,I=/\\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,T=/[^\\.]\\.(swf)\\s*$/i,P,O=1,k,m,h=false,t=20,A=b.extend(b(\"<div/>\")[0],{prop:0}),x=0,K=!b.support.opacity&&!window.XMLHttpRequest;b.fn.fixPNG=function(){return this.each(function(){var a=b(this).css(\"backgroundImage\");if(a.match(/^url\\([\"']?(.*\\.png)[\"']?\\)$/i)){a=RegExp.$1;b(this).css({backgroundImage:\"none\",filter:\"progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=\"+\n(b(this).css(\"backgroundRepeat\")==\"no-repeat\"?\"crop\":\"scale\")+\", src='\"+a+\"')\"}).each(function(){var d=b(this).css(\"position\");d!=\"absolute\"&&d!=\"relative\"&&b(this).css(\"position\",\"relative\")}).css(\"zoom\",1)}})};b.fn.fancybox=function(a){b(this).data(\"fancybox\",b.extend({},a));b(this).unbind(\"click.fb\").bind(\"click.fb\",function(d){d.preventDefault();if(!h){h=true;b(this).blur();q=[];s=0;d=b(this).attr(\"rel\")||\"\";if(!d||d==\"\"||d===\"nofollow\")q.push(this);else{q=b(\"a[rel=\"+d+\"], area[rel=\"+d+\"]\");s=\nq.index(this)}B();return false}});return this};b.fancybox=function(a,d){if(!h){h=true;q=[];s=0;if(b.isArray(a)){for(var f=0,o=a.length;f<o;f++)if(typeof a[f]==\"object\")b(a[f]).data(\"fancybox\",b.extend({},d,a[f]));else a[f]=b({}).data(\"fancybox\",b.extend({content:a[f]},d));q=jQuery.merge(q,a)}else{if(typeof a==\"object\")b(a).data(\"fancybox\",b.extend({},d,a));else a=b({}).data(\"fancybox\",b.extend({content:a},d));q.push(a)}B()}};b.fancybox.showActivity=function(){clearInterval(P);v.show();P=setInterval($,\n66)};b.fancybox.hideActivity=function(){v.hide()};b.fancybox.next=function(){return b.fancybox.pos(n+1)};b.fancybox.prev=function(){return b.fancybox.pos(n-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);if(a>-1&&j.length>a){s=a;B()}if(c.cyclic&&j.length>1&&a<0){s=j.length-1;B()}if(c.cyclic&&j.length>1&&a>=j.length){s=0;B()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger(\"fancybox-cancel\");H();e&&b.isFunction(e.onCancel)&&e.onCancel(q,s,e);h=false}};b.fancybox.close=function(){function a(){y.fadeOut(\"fast\");\ng.hide();b.event.trigger(\"fancybox-cleanup\");i.empty();b.isFunction(c.onClosed)&&c.onClosed(j,n,c);j=e=[];n=s=0;c=e={};h=false}if(!(h||g.is(\":hidden\"))){h=true;if(c&&b.isFunction(c.onCleanup))if(c.onCleanup(j,n,c)===false){h=false;return}H();b(z.add(C).add(D)).hide();b(\"#fancybox-title\").remove();g.add(i).add(y).unbind();b(window).unbind(\"resize.fb scroll.fb\");b(document).unbind(\"keydown.fb\");i.css(\"overflow\",\"hidden\");if(c.transitionOut==\"elastic\"){k=S();var d=g.position();m={top:d.top,left:d.left,\nwidth:g.width(),height:g.height()};if(c.opacity)m.opacity=1;A.prop=1;b(A).animate({prop:0},{duration:c.speedOut,easing:c.easingOut,step:M,complete:a})}else g.fadeOut(c.transitionOut==\"none\"?0:c.speedOut,a)}};b.fancybox.resize=function(){if(!(h||g.is(\":hidden\"))){h=true;var a=i.wrapInner(\"<div style='overflow:auto'></div>\").children(),d=a.height();g.css({height:d+c.padding*2+x});i.css({height:d});a.replaceWith(a.children());b.fancybox.center()}};b.fancybox.center=function(){h=true;var a=N(),d=c.margin,\nf={};f.top=a[3]+(a[1]-(g.height()-x+t*2))*0.5;f.left=a[2]+(a[0]-(g.width()+t*2))*0.5;f.top=Math.max(a[3]+d,f.top);f.left=Math.max(a[2]+d,f.left);g.css(f);h=false};b.fn.fancybox.defaults={padding:10,margin:20,opacity:false,modal:false,cyclic:false,scrolling:\"auto\",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:\"transparent\"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.3,overlayColor:\"#666\",titleShow:true,titlePosition:\"outside\",\ntitleFormat:null,transitionIn:\"fade\",transitionOut:\"fade\",speedIn:300,speedOut:300,changeSpeed:300,changeFade:\"fast\",easingIn:\"swing\",easingOut:\"swing\",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,onStart:null,onCancel:null,onComplete:null,onCleanup:null,onClosed:null};b(document).ready(function(){ba()})})(jQuery);\n"
  },
  {
    "path": "public/javascripts/fancybox/jquery.mousewheel-3.0.2.pack.js",
    "content": "/*! Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)\n * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)\n * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.\n * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.\n * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.\n *\n * Version: 3.0.2\n *\n * Requires: 1.2.2+\n */\n\n(function(b){function d(a){var f=[].slice.call(arguments,1),e=0;a=b.event.fix(a||window.event);a.type=\"mousewheel\";if(a.wheelDelta)e=a.wheelDelta/120;if(a.detail)e=-a.detail/3;f.unshift(a,e);return b.event.handle.apply(this,f)}var c=[\"DOMMouseScroll\",\"mousewheel\"];b.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=c.length;a;)this.addEventListener(c[--a],d,false);else this.onmousewheel=d},teardown:function(){if(this.removeEventListener)for(var a=c.length;a;)this.removeEventListener(c[--a],\nd,false);else this.onmousewheel=null}};b.fn.extend({mousewheel:function(a){return a?this.bind(\"mousewheel\",a):this.trigger(\"mousewheel\")},unmousewheel:function(a){return this.unbind(\"mousewheel\",a)}})})(jQuery);\n"
  },
  {
    "path": "public/javascripts/fileuploader.js",
    "content": "/**\n * http://github.com/valums/file-uploader\n *\n * Multiple file upload component with progress-bar, drag-and-drop.\n * © 2010 Andrew Valums ( andrew(at)valums.com )\n *\n * Licensed under GNU GPL 2 or later, see license.txt.\n */\n\n//\n// Helper functions\n//\n\nvar qq = qq || {};\n\n/**\n * Adds all missing properties from second obj to first obj\n */\nqq.extend = function(first, second){\n    for (var prop in second){\n        first[prop] = second[prop];\n    }\n};\n\n/**\n * Searches for a given element in the array, returns -1 if it is not present.\n * @param {Number} [from] The index at which to begin the search\n */\nqq.indexOf = function(arr, elt, from){\n    if (arr.indexOf) return arr.indexOf(elt, from);\n\n    from = from || 0;\n    var len = arr.length;\n\n    if (from < 0) from += len;\n\n    for (; from < len; from++){\n        if (from in arr && arr[from] === elt){\n            return from;\n        }\n    }\n    return -1;\n};\n\nqq.getUniqueId = (function(){\n    var id = 0;\n    return function(){ return id++; };\n})();\n\n//\n// Events\n\nqq.attach = function(element, type, fn){\n    if (element.addEventListener){\n        element.addEventListener(type, fn, false);\n    } else if (element.attachEvent){\n        element.attachEvent('on' + type, fn);\n    }\n};\nqq.detach = function(element, type, fn){\n    if (element.removeEventListener){\n        element.removeEventListener(type, fn, false);\n    } else if (element.attachEvent){\n        element.detachEvent('on' + type, fn);\n    }\n};\n\nqq.preventDefault = function(e){\n    if (e.preventDefault){\n        e.preventDefault();\n    } else{\n        e.returnValue = false;\n    }\n};\n\n//\n// Node manipulations\n\n/**\n * Insert node a before node b.\n */\nqq.insertBefore = function(a, b){\n    b.parentNode.insertBefore(a, b);\n};\nqq.remove = function(element){\n    element.parentNode.removeChild(element);\n};\n\nqq.contains = function(parent, descendant){\n    // compareposition returns false in this case\n    if (parent == descendant) return true;\n\n    if (parent.contains){\n        return parent.contains(descendant);\n    } else {\n        return !!(descendant.compareDocumentPosition(parent) & 8);\n    }\n};\n\n/**\n * Creates and returns element from html string\n * Uses innerHTML to create an element\n */\nqq.toElement = (function(){\n    var div = document.createElement('div');\n    return function(html){\n        div.innerHTML = html;\n        var element = div.firstChild;\n        div.removeChild(element);\n        return element;\n    };\n})();\n\n//\n// Node properties and attributes\n\n/**\n * Sets styles for an element.\n * Fixes opacity in IE6-8.\n */\nqq.css = function(element, styles){\n    if (styles.opacity != null){\n        if (typeof element.style.opacity != 'string' && typeof(element.filters) != 'undefined'){\n            styles.filter = 'alpha(opacity=' + Math.round(100 * styles.opacity) + ')';\n        }\n    }\n    qq.extend(element.style, styles);\n};\nqq.hasClass = function(element, name){\n    var re = new RegExp('(^| )' + name + '( |$)');\n    return re.test(element.className);\n};\nqq.addClass = function(element, name){\n    if (!qq.hasClass(element, name)){\n        element.className += ' ' + name;\n    }\n};\nqq.removeClass = function(element, name){\n    var re = new RegExp('(^| )' + name + '( |$)');\n    element.className = element.className.replace(re, ' ').replace(/^\\s+|\\s+$/g, \"\");\n};\nqq.setText = function(element, text){\n    element.innerText = text;\n    element.textContent = text;\n};\n\n//\n// Selecting elements\n\nqq.children = function(element){\n    var children = [],\n    child = element.firstChild;\n\n    while (child){\n        if (child.nodeType == 1){\n            children.push(child);\n        }\n        child = child.nextSibling;\n    }\n\n    return children;\n};\n\nqq.getByClass = function(element, className){\n    if (element.querySelectorAll){\n        return element.querySelectorAll('.' + className);\n    }\n\n    var result = [];\n    var candidates = element.getElementsByTagName(\"*\");\n    var len = candidates.length;\n\n    for (var i = 0; i < len; i++){\n        if (qq.hasClass(candidates[i], className)){\n            result.push(candidates[i]);\n        }\n    }\n    return result;\n};\n\n/**\n * obj2url() takes a json-object as argument and generates\n * a querystring. pretty much like jQuery.param()\n *\n * how to use:\n *\n *    `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');`\n *\n * will result in:\n *\n *    `http://any.url/upload?otherParam=value&a=b&c=d`\n *\n * @param  Object JSON-Object\n * @param  String current querystring-part\n * @return String encoded querystring\n */\nqq.obj2url = function(obj, temp, prefixDone){\n    var uristrings = [],\n        prefix = '&',\n        add = function(nextObj, i){\n            var nextTemp = temp\n                ? (/\\[\\]$/.test(temp)) // prevent double-encoding\n                   ? temp\n                   : temp+'['+i+']'\n                : i;\n            if ((nextTemp != 'undefined') && (i != 'undefined')) {\n                uristrings.push(\n                    (typeof nextObj === 'object')\n                        ? qq.obj2url(nextObj, nextTemp, true)\n                        : (Object.prototype.toString.call(nextObj) === '[object Function]')\n                            ? encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj())\n                            : encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj)\n                );\n            }\n        };\n\n    if (!prefixDone && temp) {\n      prefix = (/\\?/.test(temp)) ? (/\\?$/.test(temp)) ? '' : '&' : '?';\n      uristrings.push(temp);\n      uristrings.push(qq.obj2url(obj));\n    } else if ((Object.prototype.toString.call(obj) === '[object Array]') && (typeof obj != 'undefined') ) {\n        // we wont use a for-in-loop on an array (performance)\n        for (var i = 0, len = obj.length; i < len; ++i){\n            add(obj[i], i);\n        }\n    } else if ((typeof obj != 'undefined') && (obj !== null) && (typeof obj === \"object\")){\n        // for anything else but a scalar, we will use for-in-loop\n        for (var i in obj){\n            add(obj[i], i);\n        }\n    } else {\n        uristrings.push(encodeURIComponent(temp) + '=' + encodeURIComponent(obj));\n    }\n\n    return uristrings.join(prefix)\n                     .replace(/^&/, '')\n                     .replace(/%20/g, '+');\n};\n\n//\n//\n// Uploader Classes\n//\n//\n\nvar qq = qq || {};\n\n/**\n * Creates upload button, validates upload, but doesn't create file list or dd.\n */\nqq.FileUploaderBasic = function(o){\n    this._options = {\n        // set to true to see the server response\n        debug: false,\n        action: '/server/upload',\n        params: {},\n        button: null,\n        multiple: true,\n        maxConnections: 3,\n        // validation\n        allowedExtensions: [],\n        sizeLimit: 0,\n        minSizeLimit: 0,\n        // events\n        // return false to cancel submit\n        onSubmit: function(id, fileName){},\n        onProgress: function(id, fileName, loaded, total){},\n        onComplete: function(id, fileName, responseJSON){},\n        onCancel: function(id, fileName){},\n        // messages\n        messages: {\n            typeError: \"{file} has invalid extension. Only {extensions} are allowed.\",\n            sizeError: \"{file} is too large, maximum file size is {sizeLimit}.\",\n            minSizeError: \"{file} is too small, minimum file size is {minSizeLimit}.\",\n            emptyError: \"{file} is empty, please select files again without it.\",\n            onLeave: \"The files are being uploaded, if you leave now the upload will be cancelled.\"\n        },\n        showMessage: function(message){\n            alert(message);\n        }\n    };\n    qq.extend(this._options, o);\n\n    // number of files being uploaded\n    this._filesInProgress = 0;\n    this._handler = this._createUploadHandler();\n\n    if (this._options.button){\n        this._button = this._createUploadButton(this._options.button);\n    }\n\n    this._preventLeaveInProgress();\n};\n\nqq.FileUploaderBasic.prototype = {\n    setParams: function(params){\n        this._options.params = params;\n    },\n    getInProgress: function(){\n        return this._filesInProgress;\n    },\n    _createUploadButton: function(element){\n        var self = this;\n\n        return new qq.UploadButton({\n            element: element,\n            multiple: this._options.multiple && qq.UploadHandlerXhr.isSupported(),\n            onChange: function(input){\n                self._onInputChange(input);\n            }\n        });\n    },\n    _createUploadHandler: function(){\n        var self = this,\n            handlerClass;\n\n        if(qq.UploadHandlerXhr.isSupported()){\n            handlerClass = 'UploadHandlerXhr';\n        } else {\n            handlerClass = 'UploadHandlerForm';\n        }\n\n        var handler = new qq[handlerClass]({\n            debug: this._options.debug,\n            action: this._options.action,\n            maxConnections: this._options.maxConnections,\n            onProgress: function(id, fileName, loaded, total){\n                self._onProgress(id, fileName, loaded, total);\n                self._options.onProgress(id, fileName, loaded, total);\n            },\n            onComplete: function(id, fileName, result){\n                self._onComplete(id, fileName, result);\n                self._options.onComplete(id, fileName, result);\n            },\n            onCancel: function(id, fileName){\n                self._onCancel(id, fileName);\n                self._options.onCancel(id, fileName);\n            }\n        });\n\n        return handler;\n    },\n    _preventLeaveInProgress: function(){\n        var self = this;\n\n        qq.attach(window, 'beforeunload', function(e){\n            if (!self._filesInProgress){return;}\n\n            var e = e || window.event;\n            // for ie, ff\n            e.returnValue = self._options.messages.onLeave;\n            // for webkit\n            return self._options.messages.onLeave;\n        });\n    },\n    _onSubmit: function(id, fileName){\n        this._filesInProgress++;\n    },\n    _onProgress: function(id, fileName, loaded, total){\n    },\n    _onComplete: function(id, fileName, result){\n        this._filesInProgress--;\n        if (result.error){\n            this._options.showMessage(result.error);\n        }\n    },\n    _onCancel: function(id, fileName){\n        this._filesInProgress--;\n    },\n    _onInputChange: function(input){\n        if (this._handler instanceof qq.UploadHandlerXhr){\n            this._uploadFileList(input.files);\n        } else {\n            if (this._validateFile(input)){\n                this._uploadFile(input);\n            }\n        }\n        this._button.reset();\n    },\n    _uploadFileList: function(files){\n        for (var i=0; i<files.length; i++){\n            if ( !this._validateFile(files[i])){\n                return;\n            }\n        }\n\n        for (var i=0; i<files.length; i++){\n            this._uploadFile(files[i]);\n        }\n    },\n    _uploadFile: function(fileContainer){\n        var id = this._handler.add(fileContainer);\n        var fileName = this._handler.getName(id);\n\n        if (this._options.onSubmit(id, fileName) !== false){\n            this._onSubmit(id, fileName);\n            this._handler.upload(id, this._options.params);\n        }\n    },\n    _validateFile: function(file){\n        var name, size;\n\n        if (file.value){\n            // it is a file input\n            // get input value and remove path to normalize\n            name = file.value.replace(/.*(\\/|\\\\)/, \"\");\n        } else {\n            // fix missing properties in Safari\n            name = file.fileName != null ? file.fileName : file.name;\n            size = file.fileSize != null ? file.fileSize : file.size;\n        }\n\n        if (! this._isAllowedExtension(name)){\n            this._error('typeError', name);\n            return false;\n\n        } else if (size === 0){\n            this._error('emptyError', name);\n            return false;\n\n        } else if (size && this._options.sizeLimit && size > this._options.sizeLimit){\n            this._error('sizeError', name);\n            return false;\n\n        } else if (size && size < this._options.minSizeLimit){\n            this._error('minSizeError', name);\n            return false;\n        }\n\n        return true;\n    },\n    _error: function(code, fileName){\n        var message = this._options.messages[code];\n        function r(name, replacement){ message = message.replace(name, replacement); }\n\n        r('{file}', this._formatFileName(fileName));\n        r('{extensions}', this._options.allowedExtensions.join(', '));\n        r('{sizeLimit}', this._formatSize(this._options.sizeLimit));\n        r('{minSizeLimit}', this._formatSize(this._options.minSizeLimit));\n\n        this._options.showMessage(message);\n    },\n    _formatFileName: function(name){\n        if (name.length > 33){\n            name = name.slice(0, 19) + '...' + name.slice(-13);\n        }\n        return name;\n    },\n    _isAllowedExtension: function(fileName){\n        var ext = (-1 !== fileName.indexOf('.')) ? fileName.replace(/.*[.]/, '').toLowerCase() : '';\n        var allowed = this._options.allowedExtensions;\n\n        if (!allowed.length){return true;}\n\n        for (var i=0; i<allowed.length; i++){\n            if (allowed[i].toLowerCase() == ext){ return true;}\n        }\n\n        return false;\n    },\n    _formatSize: function(bytes){\n        var i = -1;\n        do {\n            bytes = bytes / 1024;\n            i++;\n        } while (bytes > 99);\n\n        return Math.max(bytes, 0.1).toFixed(1) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i];\n    }\n};\n\n\n/**\n * Class that creates upload widget with drag-and-drop and file list\n * @inherits qq.FileUploaderBasic\n */\nqq.FileUploader = function(o){\n    // call parent constructor\n    qq.FileUploaderBasic.apply(this, arguments);\n\n    // additional options\n    qq.extend(this._options, {\n        element: null,\n        // if set, will be used instead of qq-upload-list in template\n        listElement: null,\n\n        template: '<div class=\"qq-uploader\">' +\n                '<div class=\"qq-upload-drop-area\"><span>Drop files here to upload</span></div>' +\n                '<div class=\"qq-upload-button\">Upload a file</div>' +\n                '<ul class=\"qq-upload-list\"></ul>' +\n             '</div>',\n\n        // template for one item in file list\n        fileTemplate: '<li>' +\n                '<span class=\"qq-upload-file\"></span>' +\n                '<span class=\"qq-upload-spinner\"></span>' +\n                '<span class=\"qq-upload-size\"></span>' +\n                '<a class=\"qq-upload-cancel\" href=\"#\">Cancel</a>' +\n                '<span class=\"qq-upload-failed-text\">Failed</span>' +\n            '</li>',\n\n        classes: {\n            // used to get elements from templates\n            button: 'qq-upload-button',\n            drop: 'qq-upload-drop-area',\n            dropActive: 'qq-upload-drop-area-active',\n            list: 'qq-upload-list',\n\n            file: 'qq-upload-file',\n            spinner: 'qq-upload-spinner',\n            size: 'qq-upload-size',\n            cancel: 'qq-upload-cancel',\n\n            // added to list item when upload completes\n            // used in css to hide progress spinner\n            success: 'qq-upload-success',\n            fail: 'qq-upload-fail'\n        }\n    });\n    // overwrite options with user supplied\n    qq.extend(this._options, o);\n\n    this._element = this._options.element;\n    this._element.innerHTML = this._options.template;\n    this._listElement = this._options.listElement || this._find(this._element, 'list');\n\n    this._classes = this._options.classes;\n\n    this._button = this._createUploadButton(this._find(this._element, 'button'));\n\n    this._bindCancelEvent();\n    this._setupDragDrop();\n};\n\n// inherit from Basic Uploader\nqq.extend(qq.FileUploader.prototype, qq.FileUploaderBasic.prototype);\n\nqq.extend(qq.FileUploader.prototype, {\n    /**\n     * Gets one of the elements listed in this._options.classes\n     **/\n    _find: function(parent, type){\n        var element = qq.getByClass(parent, this._options.classes[type])[0];\n        if (!element){\n            throw new Error('element not found ' + type);\n        }\n\n        return element;\n    },\n    _setupDragDrop: function(){\n        var self = this,\n            dropArea = this._find(this._element, 'drop');\n\n        var dz = new qq.UploadDropZone({\n            element: dropArea,\n            onEnter: function(e){\n                qq.addClass(dropArea, self._classes.dropActive);\n                e.stopPropagation();\n            },\n            onLeave: function(e){\n                e.stopPropagation();\n            },\n            onLeaveNotDescendants: function(e){\n                qq.removeClass(dropArea, self._classes.dropActive);\n            },\n            onDrop: function(e){\n                dropArea.style.display = 'none';\n                qq.removeClass(dropArea, self._classes.dropActive);\n                self._uploadFileList(e.dataTransfer.files);\n            }\n        });\n\n        dropArea.style.display = 'none';\n\n        qq.attach(document, 'dragenter', function(e){\n            if (!dz._isValidFileDrag(e)) return;\n\n            dropArea.style.display = 'block';\n        });\n        qq.attach(document, 'dragleave', function(e){\n            if (!dz._isValidFileDrag(e)) return;\n\n            var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n            // only fire when leaving document out\n            if ( ! relatedTarget || relatedTarget.nodeName == \"HTML\"){\n                dropArea.style.display = 'none';\n            }\n        });\n    },\n    _onSubmit: function(id, fileName){\n        qq.FileUploaderBasic.prototype._onSubmit.apply(this, arguments);\n        this._addToList(id, fileName);\n    },\n    _onProgress: function(id, fileName, loaded, total){\n        qq.FileUploaderBasic.prototype._onProgress.apply(this, arguments);\n\n        var item = this._getItemByFileId(id);\n        var size = this._find(item, 'size');\n        size.style.display = 'inline';\n\n        var text;\n        if (loaded != total){\n            text = Math.round(loaded / total * 100) + '% from ' + this._formatSize(total);\n        } else {\n            text = this._formatSize(total);\n        }\n\n        qq.setText(size, text);\n    },\n    _onComplete: function(id, fileName, result){\n        qq.FileUploaderBasic.prototype._onComplete.apply(this, arguments);\n\n        // mark completed\n        var item = this._getItemByFileId(id);\n        qq.remove(this._find(item, 'cancel'));\n        qq.remove(this._find(item, 'spinner'));\n\n        if (result.success){\n            qq.addClass(item, this._classes.success);\n        } else {\n            qq.addClass(item, this._classes.fail);\n        }\n    },\n    _addToList: function(id, fileName){\n        var item = qq.toElement(this._options.fileTemplate);\n        item.qqFileId = id;\n\n        var fileElement = this._find(item, 'file');\n        qq.setText(fileElement, this._formatFileName(fileName));\n        this._find(item, 'size').style.display = 'none';\n\n        this._listElement.appendChild(item);\n    },\n    _getItemByFileId: function(id){\n        var item = this._listElement.firstChild;\n\n        // there can't be txt nodes in dynamically created list\n        // and we can  use nextSibling\n        while (item){\n            if (item.qqFileId == id) return item;\n            item = item.nextSibling;\n        }\n    },\n    /**\n     * delegate click event for cancel link\n     **/\n    _bindCancelEvent: function(){\n        var self = this,\n            list = this._listElement;\n\n        qq.attach(list, 'click', function(e){\n            e = e || window.event;\n            var target = e.target || e.srcElement;\n\n            if (qq.hasClass(target, self._classes.cancel)){\n                qq.preventDefault(e);\n\n                var item = target.parentNode;\n                self._handler.cancel(item.qqFileId);\n                qq.remove(item);\n            }\n        });\n    }\n});\n\nqq.UploadDropZone = function(o){\n    this._options = {\n        element: null,\n        onEnter: function(e){},\n        onLeave: function(e){},\n        // is not fired when leaving element by hovering descendants\n        onLeaveNotDescendants: function(e){},\n        onDrop: function(e){}\n    };\n    qq.extend(this._options, o);\n\n    this._element = this._options.element;\n\n    this._disableDropOutside();\n    this._attachEvents();\n};\n\nqq.UploadDropZone.prototype = {\n    _disableDropOutside: function(e){\n        // run only once for all instances\n        if (!qq.UploadDropZone.dropOutsideDisabled ){\n\n            qq.attach(document, 'dragover', function(e){\n                if (e.dataTransfer){\n                    e.dataTransfer.dropEffect = 'none';\n                    e.preventDefault();\n                }\n            });\n\n            qq.UploadDropZone.dropOutsideDisabled = true;\n        }\n    },\n    _attachEvents: function(){\n        var self = this;\n\n        qq.attach(self._element, 'dragover', function(e){\n            if (!self._isValidFileDrag(e)) return;\n\n            var effect = e.dataTransfer.effectAllowed;\n            if (effect == 'move' || effect == 'linkMove'){\n                e.dataTransfer.dropEffect = 'move'; // for FF (only move allowed)\n            } else {\n                e.dataTransfer.dropEffect = 'copy'; // for Chrome\n            }\n\n            e.stopPropagation();\n            e.preventDefault();\n        });\n\n        qq.attach(self._element, 'dragenter', function(e){\n            if (!self._isValidFileDrag(e)) return;\n\n            self._options.onEnter(e);\n        });\n\n        qq.attach(self._element, 'dragleave', function(e){\n            if (!self._isValidFileDrag(e)) return;\n\n            self._options.onLeave(e);\n\n            var relatedTarget = document.elementFromPoint(e.clientX, e.clientY);\n            // do not fire when moving a mouse over a descendant\n            if (qq.contains(this, relatedTarget)) return;\n\n            self._options.onLeaveNotDescendants(e);\n        });\n\n        qq.attach(self._element, 'drop', function(e){\n            if (!self._isValidFileDrag(e)) return;\n\n            e.preventDefault();\n            self._options.onDrop(e);\n        });\n    },\n    _isValidFileDrag: function(e){\n        var dt = e.dataTransfer,\n            // do not check dt.types.contains in webkit, because it crashes safari 4\n            isWebkit = navigator.userAgent.indexOf(\"AppleWebKit\") > -1;\n\n        // dt.effectAllowed is none in Safari 5\n        // dt.types.contains check is for firefox\n        return dt && dt.effectAllowed != 'none' &&\n            (dt.files || (!isWebkit && dt.types.contains && dt.types.contains('Files')));\n\n    }\n};\n\nqq.UploadButton = function(o){\n    this._options = {\n        element: null,\n        // if set to true adds multiple attribute to file input\n        multiple: false,\n        // name attribute of file input\n        name: 'file',\n        onChange: function(input){},\n        hoverClass: 'qq-upload-button-hover',\n        focusClass: 'qq-upload-button-focus'\n    };\n\n    qq.extend(this._options, o);\n\n    this._element = this._options.element;\n\n    // make button suitable container for input\n    qq.css(this._element, {\n        position: 'relative',\n        overflow: 'hidden',\n        // Make sure browse button is in the right side\n        // in Internet Explorer\n        direction: 'ltr'\n    });\n\n    this._input = this._createInput();\n};\n\nqq.UploadButton.prototype = {\n    /* returns file input element */\n    getInput: function(){\n        return this._input;\n    },\n    /* cleans/recreates the file input */\n    reset: function(){\n        if (this._input.parentNode){\n            qq.remove(this._input);\n        }\n\n        qq.removeClass(this._element, this._options.focusClass);\n        this._input = this._createInput();\n    },\n    _createInput: function(){\n        var input = document.createElement(\"input\");\n\n        if (this._options.multiple){\n            input.setAttribute(\"multiple\", \"multiple\");\n        }\n\n        input.setAttribute(\"type\", \"file\");\n        input.setAttribute(\"name\", this._options.name);\n\n        qq.css(input, {\n            position: 'absolute',\n            // in Opera only 'browse' button\n            // is clickable and it is located at\n            // the right side of the input\n            right: 0,\n            top: 0,\n            fontFamily: 'Arial',\n            // 4 persons reported this, the max values that worked for them were 243, 236, 236, 118\n            fontSize: '118px',\n            margin: 0,\n            padding: 0,\n            cursor: 'pointer',\n            opacity: 0\n        });\n\n        this._element.appendChild(input);\n\n        var self = this;\n        qq.attach(input, 'change', function(){\n            self._options.onChange(input);\n        });\n\n        qq.attach(input, 'mouseover', function(){\n            qq.addClass(self._element, self._options.hoverClass);\n        });\n        qq.attach(input, 'mouseout', function(){\n            qq.removeClass(self._element, self._options.hoverClass);\n        });\n        qq.attach(input, 'focus', function(){\n            qq.addClass(self._element, self._options.focusClass);\n        });\n        qq.attach(input, 'blur', function(){\n            qq.removeClass(self._element, self._options.focusClass);\n        });\n\n        // IE and Opera, unfortunately have 2 tab stops on file input\n        // which is unacceptable in our case, disable keyboard access\n        if (window.attachEvent){\n            // it is IE or Opera\n            input.setAttribute('tabIndex', \"-1\");\n        }\n\n        return input;\n    }\n};\n\n/**\n * Class for uploading files, uploading itself is handled by child classes\n */\nqq.UploadHandlerAbstract = function(o){\n    this._options = {\n        debug: false,\n        action: '/upload.php',\n        // maximum number of concurrent uploads\n        maxConnections: 999,\n        onProgress: function(id, fileName, loaded, total){},\n        onComplete: function(id, fileName, response){},\n        onCancel: function(id, fileName){}\n    };\n    qq.extend(this._options, o);\n\n    this._queue = [];\n    // params for files in queue\n    this._params = [];\n};\nqq.UploadHandlerAbstract.prototype = {\n    log: function(str){\n        if (this._options.debug && window.console) console.log('[uploader] ' + str);\n    },\n    /**\n     * Adds file or file input to the queue\n     * @returns id\n     **/\n    add: function(file){},\n    /**\n     * Sends the file identified by id and additional query params to the server\n     */\n    upload: function(id, params){\n        var len = this._queue.push(id);\n\n        var copy = {};\n        qq.extend(copy, params);\n        this._params[id] = copy;\n\n        // if too many active uploads, wait...\n        if (len <= this._options.maxConnections){\n            this._upload(id, this._params[id]);\n        }\n    },\n    /**\n     * Cancels file upload by id\n     */\n    cancel: function(id){\n        this._cancel(id);\n        this._dequeue(id);\n    },\n    /**\n     * Cancells all uploads\n     */\n    cancelAll: function(){\n        for (var i=0; i<this._queue.length; i++){\n            this._cancel(this._queue[i]);\n        }\n        this._queue = [];\n    },\n    /**\n     * Returns name of the file identified by id\n     */\n    getName: function(id){},\n    /**\n     * Returns size of the file identified by id\n     */\n    getSize: function(id){},\n    /**\n     * Returns id of files being uploaded or\n     * waiting for their turn\n     */\n    getQueue: function(){\n        return this._queue;\n    },\n    /**\n     * Actual upload method\n     */\n    _upload: function(id){},\n    /**\n     * Actual cancel method\n     */\n    _cancel: function(id){},\n    /**\n     * Removes element from queue, starts upload of next\n     */\n    _dequeue: function(id){\n        var i = qq.indexOf(this._queue, id);\n        this._queue.splice(i, 1);\n\n        var max = this._options.maxConnections;\n\n        if (this._queue.length >= max){\n            var nextId = this._queue[max-1];\n            this._upload(nextId, this._params[nextId]);\n        }\n    }\n};\n\n/**\n * Class for uploading files using form and iframe\n * @inherits qq.UploadHandlerAbstract\n */\nqq.UploadHandlerForm = function(o){\n    qq.UploadHandlerAbstract.apply(this, arguments);\n\n    this._inputs = {};\n};\n// @inherits qq.UploadHandlerAbstract\nqq.extend(qq.UploadHandlerForm.prototype, qq.UploadHandlerAbstract.prototype);\n\nqq.extend(qq.UploadHandlerForm.prototype, {\n    add: function(fileInput){\n        fileInput.setAttribute('name', 'qqfile');\n        var id = 'qq-upload-handler-iframe' + qq.getUniqueId();\n\n        this._inputs[id] = fileInput;\n\n        // remove file input from DOM\n        if (fileInput.parentNode){\n            qq.remove(fileInput);\n        }\n\n        return id;\n    },\n    getName: function(id){\n        // get input value and remove path to normalize\n        return this._inputs[id].value.replace(/.*(\\/|\\\\)/, \"\");\n    },\n    _cancel: function(id){\n        this._options.onCancel(id, this.getName(id));\n\n        delete this._inputs[id];\n\n        var iframe = document.getElementById(id);\n        if (iframe){\n            // to cancel request set src to something else\n            // we use src=\"javascript:false;\" because it doesn't\n            // trigger ie6 prompt on https\n            iframe.setAttribute('src', 'javascript:false;');\n\n            qq.remove(iframe);\n        }\n    },\n    _upload: function(id, params){\n        var input = this._inputs[id];\n\n        if (!input){\n            throw new Error('file with passed id was not added, or already uploaded or cancelled');\n        }\n\n        var fileName = this.getName(id);\n\n        var iframe = this._createIframe(id);\n        var form = this._createForm(iframe, params);\n        form.appendChild(input);\n\n        var self = this;\n        this._attachLoadEvent(iframe, function(){\n            self.log('iframe loaded');\n\n            var response = self._getIframeContentJSON(iframe);\n\n            self._options.onComplete(id, fileName, response);\n            self._dequeue(id);\n\n            delete self._inputs[id];\n            // timeout added to fix busy state in FF3.6\n            setTimeout(function(){\n                qq.remove(iframe);\n            }, 1);\n        });\n\n        form.submit();\n        qq.remove(form);\n\n        return id;\n    },\n    _attachLoadEvent: function(iframe, callback){\n        qq.attach(iframe, 'load', function(){\n            // when we remove iframe from dom\n            // the request stops, but in IE load\n            // event fires\n            if (!iframe.parentNode){\n                return;\n            }\n\n            // fixing Opera 10.53\n            if (iframe.contentDocument &&\n                iframe.contentDocument.body &&\n                iframe.contentDocument.body.innerHTML == \"false\"){\n                // In Opera event is fired second time\n                // when body.innerHTML changed from false\n                // to server response approx. after 1 sec\n                // when we upload file with iframe\n                return;\n            }\n\n            callback();\n        });\n    },\n    /**\n     * Returns json object received by iframe from server.\n     */\n    _getIframeContentJSON: function(iframe){\n        // iframe.contentWindow.document - for IE<7\n        var doc = iframe.contentDocument ? iframe.contentDocument: iframe.contentWindow.document,\n            response;\n\n        this.log(\"converting iframe's innerHTML to JSON\");\n        this.log(\"innerHTML = \" + doc.body.innerHTML);\n\n        try {\n            response = eval(\"(\" + doc.body.innerHTML + \")\");\n        } catch(err){\n            response = {};\n        }\n\n        return response;\n    },\n    /**\n     * Creates iframe with unique name\n     */\n    _createIframe: function(id){\n        // We can't use following code as the name attribute\n        // won't be properly registered in IE6, and new window\n        // on form submit will open\n        // var iframe = document.createElement('iframe');\n        // iframe.setAttribute('name', id);\n\n        var iframe = qq.toElement('<iframe src=\"javascript:false;\" name=\"' + id + '\" />');\n        // src=\"javascript:false;\" removes ie6 prompt on https\n\n        iframe.setAttribute('id', id);\n\n        iframe.style.display = 'none';\n        document.body.appendChild(iframe);\n\n        return iframe;\n    },\n    /**\n     * Creates form, that will be submitted to iframe\n     */\n    _createForm: function(iframe, params){\n        // We can't use the following code in IE6\n        // var form = document.createElement('form');\n        // form.setAttribute('method', 'post');\n        // form.setAttribute('enctype', 'multipart/form-data');\n        // Because in this case file won't be attached to request\n        var form = qq.toElement('<form method=\"post\" enctype=\"multipart/form-data\"></form>');\n\n        var queryString = qq.obj2url(params, this._options.action);\n\n        form.setAttribute('action', queryString);\n        form.setAttribute('target', iframe.name);\n        form.style.display = 'none';\n        document.body.appendChild(form);\n\n        return form;\n    }\n});\n\n/**\n * Class for uploading files using xhr\n * @inherits qq.UploadHandlerAbstract\n */\nqq.UploadHandlerXhr = function(o){\n    qq.UploadHandlerAbstract.apply(this, arguments);\n\n    this._files = [];\n    this._xhrs = [];\n\n    // current loaded size in bytes for each file\n    this._loaded = [];\n};\n\n// static method\nqq.UploadHandlerXhr.isSupported = function(){\n    var input = document.createElement('input');\n    input.type = 'file';\n\n    return (\n        'multiple' in input &&\n        typeof File != \"undefined\" &&\n        typeof (new XMLHttpRequest()).upload != \"undefined\" );\n};\n\n// @inherits qq.UploadHandlerAbstract\nqq.extend(qq.UploadHandlerXhr.prototype, qq.UploadHandlerAbstract.prototype)\n\nqq.extend(qq.UploadHandlerXhr.prototype, {\n    /**\n     * Adds file to the queue\n     * Returns id to use with upload, cancel\n     **/\n    add: function(file){\n        if (!(file instanceof File)){\n            throw new Error('Passed obj in not a File (in qq.UploadHandlerXhr)');\n        }\n\n        return this._files.push(file) - 1;\n    },\n    getName: function(id){\n        var file = this._files[id];\n        // fix missing name in Safari 4\n        return file.fileName != null ? file.fileName : file.name;\n    },\n    getSize: function(id){\n        var file = this._files[id];\n        return file.fileSize != null ? file.fileSize : file.size;\n    },\n    /**\n     * Returns uploaded bytes for file identified by id\n     */\n    getLoaded: function(id){\n        return this._loaded[id] || 0;\n    },\n    /**\n     * Sends the file identified by id and additional query params to the server\n     * @param {Object} params name-value string pairs\n     */\n    _upload: function(id, params){\n        var file = this._files[id],\n            name = this.getName(id),\n            size = this.getSize(id);\n\n        this._loaded[id] = 0;\n\n        var xhr = this._xhrs[id] = new XMLHttpRequest();\n        var self = this;\n\n        xhr.upload.onprogress = function(e){\n            if (e.lengthComputable){\n                self._loaded[id] = e.loaded;\n                self._options.onProgress(id, name, e.loaded, e.total);\n            }\n        };\n\n        xhr.onreadystatechange = function(){\n            if (xhr.readyState == 4){\n                self._onComplete(id, xhr);\n            }\n        };\n\n        // build query string\n        params = params || {};\n        params['qqfile'] = name;\n        var queryString = qq.obj2url(params, this._options.action);\n\n        xhr.open(\"POST\", queryString, true);\n        xhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n        xhr.setRequestHeader(\"X-File-Name\", encodeURIComponent(name));\n        xhr.setRequestHeader(\"Content-Type\", \"application/octet-stream\");\n        xhr.send(file);\n    },\n    _onComplete: function(id, xhr){\n        // the request was aborted/cancelled\n        if (!this._files[id]) return;\n\n        var name = this.getName(id);\n        var size = this.getSize(id);\n\n        this._options.onProgress(id, name, size, size);\n\n        if (xhr.status == 200){\n            this.log(\"xhr - server response received\");\n            this.log(\"responseText = \" + xhr.responseText);\n\n            var response;\n\n            try {\n                response = eval(\"(\" + xhr.responseText + \")\");\n            } catch(err){\n                response = {};\n            }\n\n            this._options.onComplete(id, name, response);\n\n        } else {\n            this._options.onComplete(id, name, {});\n        }\n\n        this._files[id] = null;\n        this._xhrs[id] = null;\n        this._dequeue(id);\n    },\n    _cancel: function(id){\n        this._options.onCancel(id, this.getName(id));\n\n        this._files[id] = null;\n\n        if (this._xhrs[id]){\n            this._xhrs[id].abort();\n            this._xhrs[id] = null;\n        }\n    }\n});\n"
  },
  {
    "path": "public/javascripts/hoverIntent.js",
    "content": "(function($){\n  /* hoverIntent by Brian Cherne */\n  $.fn.hoverIntent = function(f,g) {\n    // default configuration options\n    var cfg = {\n      sensitivity: 7,\n      interval: 100,\n      timeout: 0\n    };\n    // override configuration options with user supplied object\n    cfg = $.extend(cfg, g ? { over: f, out: g } : f );\n\n    // instantiate variables\n    // cX, cY = current X and Y position of mouse, updated by mousemove event\n    // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval\n    var cX, cY, pX, pY;\n\n    // A private function for getting mouse position\n    var track = function(ev) {\n      cX = ev.pageX;\n      cY = ev.pageY;\n    };\n\n    // A private function for comparing current and previous mouse position\n    var compare = function(ev,ob) {\n      ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);\n      // compare mouse positions to see if they've crossed the threshold\n      if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {\n        $(ob).unbind(\"mousemove\",track);\n        // set hoverIntent state to true (so mouseOut can be called)\n        ob.hoverIntent_s = 1;\n        return cfg.over.apply(ob,[ev]);\n      } else {\n        // set previous coordinates for next time\n        pX = cX; pY = cY;\n        // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)\n        ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );\n      }\n    };\n\n    // A private function for delaying the mouseOut function\n    var delay = function(ev,ob) {\n      ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);\n      ob.hoverIntent_s = 0;\n      return cfg.out.apply(ob,[ev]);\n    };\n\n    // A private function for handling mouse 'hovering'\n    var handleHover = function(e) {\n      // next three lines copied from jQuery.hover, ignore children onMouseOver/onMouseOut\n      var p = (e.type == \"mouseover\" ? e.fromElement : e.toElement) || e.relatedTarget;\n      while ( p && p != this ) { try { p = p.parentNode; } catch(e) { p = this; } }\n      if ( p == this ) { return false; }\n\n      // copy objects to be passed into t (required for event object to be passed in IE)\n      var ev = jQuery.extend({},e);\n      var ob = this;\n\n      // cancel hoverIntent timer if it exists\n      if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }\n\n      // else e.type == \"onmouseover\"\n      if (e.type == \"mouseover\") {\n        // set \"previous\" X and Y position based on initial entry point\n        pX = ev.pageX; pY = ev.pageY;\n        // update \"current\" X and Y position based on mousemove\n        $(ob).bind(\"mousemove\",track);\n        // start polling interval (self-calling timeout) to compare mouse coordinates over time\n        if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}\n\n      // else e.type == \"onmouseout\"\n      } else {\n        // unbind expensive mousemove event\n        $(ob).unbind(\"mousemove\",track);\n        // if hoverIntent state is true, then call the mouseOut function after the specified delay\n        if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}\n      }\n    };\n\n    // bind the function to the two event listeners\n    return this.mouseover(handleHover).mouseout(handleHover);\n  };\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/issue.js",
    "content": "\n"
  },
  {
    "path": "public/javascripts/jQuery.bubbletip-1.0.4.js",
    "content": "/*\n * bubbletip\n *\n * Copyright (c) 2009, UhLeeKa\n * Version:\n *      1.0.4\n * Licensed under the GPL license:\n *     http://www.gnu.org/licenses/gpl.html\n * Author Website:\n *     http://www.uhleeka.com\n * Description:\n *     A bubble-styled tooltip extension\n *      - multiple tips on a page\n *      - multiple tips per jQuery element\n *      - tips open outward in four directions:\n *         - up\n *         - down\n *         - left\n *         - right\n *      - tips can be:\n *         - anchored to the triggering jQuery element\n *         - absolutely positioned\n *         - opened at the current mouse coordinates\n *         - anchored to a specified jQuery element\n *      - IE png transparency is handled via filters\n */\n; (function($) {\n  var bindIndex = 0;\n  $.fn.extend({\n    bubbletip: function(tip, options) {\n      // check to see if the tip is a descendant of\n      // a table.bubbletip element and therefore\n      // has already been instantiated as a bubbletip\n      if ($('table.bubbletip #' + $(tip).id).length > 0) {\n        return this;\n      }\n\n      var _this, _tip, _options, _calc, _timeoutAnimate, _timeoutRefresh, _isActive, _isHiding, _wrapper, _bindIndex;\n\n      _this = $(this);\n      _tip = $(tip);\n      _bindIndex = bindIndex++;  // for window.resize namespace binding\n      _options = {\n        positionAt: 'element', // element | body | mouse\n        positionAtElement: _this,\n        offsetTop: 0,\n        offsetLeft: 0,\n        deltaPosition: 30,\n        deltaDirection: 'up', // direction: up | down | left | right\n        animationDuration: 250,\n        animationEasing: 'swing', // linear | swing\n        bindShow: 'mouseover', // mouseover | focus | click | etc.\n        bindHide: 'mouseout', // mouseout | blur | etc.\n        delayShow: 0,\n        delayHide: 500\n      };\n      if (options) {\n        _options = $.extend(_options, options);\n      }\n      // calculated values\n      _calc = {\n        top: 0,\n        left: 0,\n        delta: 0,\n        mouseTop: 0,\n        mouseLeft: 0,\n        tipHeight: 0,\n        bindShow: (_options.bindShow + ' ').replace(/ +/g, '.bubbletip' + _bindIndex),\n        bindHide: (_options.bindHide + ' ').replace(/ +/g, '.bubbletip' + _bindIndex)\n      };\n      _timeoutAnimate = null;\n      _timeoutRefresh = null;\n      _isActive = false;\n      _isHiding = false;\n\n      // store the tip id for removeBubbletip\n      if (!_this.data('bubbletip_tips')) {\n        _this.data('bubbletip_tips', [[_tip.get(0).id, _calc.bindShow, _calc.bindHide, _bindIndex]]);\n      } else {\n        _this.data('bubbletip_tips', $.merge(_this.data('bubbletip_tips'), [[_tip.get(0).id, _calc.bindShow, _calc.bindHide, _bindIndex]]));\n      }\n\n\n      // validate _options\n      if (!_options.positionAt.match(/^element|body|mouse$/i)) {\n        _options.positionAt = 'element';\n      }\n      if (!_options.deltaDirection.match(/^up|down|left|right$/i)) {\n        _options.deltaDirection = 'up';\n      }\n\n      // create the wrapper table element\n      if (_options.deltaDirection.match(/^up$/i)) {\n        _wrapper = $('<table class=\"bubbletip\" cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"bt-topleft\"></td><td class=\"bt-top\"></td><td class=\"bt-topright\"></td></tr><tr><td class=\"bt-left\"></td><td class=\"bt-content\"></td><td class=\"bt-right\"></td></tr><tr><td class=\"bt-bottomleft\"></td><td><table class=\"bt-bottom\" cellspacing=\"0\" cellpadding=\"0\"><tr><th></th><td><div></div></td><th></th></tr></table></td><td class=\"bt-bottomright\"></td></tr></tbody></table>');\n      } else if (_options.deltaDirection.match(/^down$/i)) {\n        _wrapper = $('<table class=\"bubbletip\" cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"bt-topleft\"></td><td><table class=\"bt-top\" cellspacing=\"0\" cellpadding=\"0\"><tr><th></th><td><div></div></td><th></th></tr></table></td><td class=\"bt-topright\"></td></tr><tr><td class=\"bt-left\"></td><td class=\"bt-content\"></td><td class=\"bt-right\"></td></tr><tr><td class=\"bt-bottomleft\"></td><td class=\"bt-bottom\"></td><td class=\"bt-bottomright\"></td></tr></tbody></table>');\n      } else if (_options.deltaDirection.match(/^left$/i)) {\n        _wrapper = $('<table class=\"bubbletip\" cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"bt-topleft\"></td><td class=\"bt-top\"></td><td class=\"bt-topright\"></td></tr><tr><td class=\"bt-left\"></td><td class=\"bt-content\"></td><td class=\"bt-right-tail\"><div class=\"bt-right\"></div><div class=\"bt-right-tail\"></div><div class=\"bt-right\"></div></td></tr><tr><td class=\"bt-bottomleft\"></td><td class=\"bt-bottom\"></td><td class=\"bt-bottomright\"></td></tr></tbody></table>');\n      } else if (_options.deltaDirection.match(/^right$/i)) {\n        _wrapper = $('<table class=\"bubbletip\" cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"bt-topleft\"></td><td class=\"bt-top\"></td><td class=\"bt-topright\"></td></tr><tr><td class=\"bt-left-tail\"><div class=\"bt-left\"></div><div class=\"bt-left-tail\"></div><div class=\"bt-left\"></div></td><td class=\"bt-content\"></td><td class=\"bt-right\"></td></tr><tr><td class=\"bt-bottomleft\"></td><td class=\"bt-bottom\"></td><td class=\"bt-bottomright\"></td></tr></tbody></table>');\n      }\n\n      // append the wrapper to the document body\n      _wrapper.appendTo('body');\n\n      // apply IE filters to _wrapper elements\n      if ((/msie/.test(navigator.userAgent.toLowerCase())) && (!/opera/.test(navigator.userAgent.toLowerCase()))) {\n        $('*', _wrapper).each(function() {\n          var image = $(this).css('background-image');\n          if (image.match(/^url\\([\"']?(.*\\.png)[\"']?\\)$/i)) {\n            image = RegExp.$1;\n            $(this).css({\n              'backgroundImage': 'none',\n              'filter': 'progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=' + ($(this).css('backgroundRepeat') == 'no-repeat' ? 'crop' : 'scale') + ', src=\\'' + image + '\\')'\n            }).each(function() {\n              var position = $(this).css('position');\n              if (position != 'absolute' && position != 'relative')\n                $(this).css('position', 'relative');\n            });\n          }\n        });\n      }\n\n      // move the tip element into the content section of the wrapper\n      $('.bt-content', _wrapper).append(_tip);\n      // show the tip (in case it is hidden) so that we can calculate its dimensions\n      _tip.show();\n      // handle left|right delta\n      if (_options.deltaDirection.match(/^left|right$/i)) {\n        // tail is 40px, so divide height by two and subtract 20px;\n        _calc.tipHeight = parseInt(_tip.height() / 2);\n        // handle odd integer height\n        if ((_tip.height() % 2) == 1) {\n          _calc.tipHeight++;\n        }\n        _calc.tipHeight = (_calc.tipHeight < 20) ? 1 : _calc.tipHeight - 20;\n        if (_options.deltaDirection.match(/^left$/i)) {\n          $('div.bt-right', _wrapper).css('height', _calc.tipHeight + 'px');\n        } else {\n          $('div.bt-left', _wrapper).css('height', _calc.tipHeight + 'px');\n        }\n      }\n      // set the opacity of the wrapper to 0\n      _wrapper.css('opacity', 0);\n      // execute initial calculations\n      _Calculate();\n\n      // handle window.resize\n      $(window).bind('resize.bubbletip' + _bindIndex, function() {\n        if (_timeoutRefresh) {\n          clearTimeout(_timeoutRefresh);\n        } else {\n          _wrapper.hide();\n        }\n        _timeoutRefresh = setTimeout(function() {\n          _Calculate();\n        }, 250);\n      });\n\n      // handle mouseover and mouseout events\n      $([_wrapper.get(0), this.get(0)]).bind(_calc.bindShow, function(e) {\n        if (_timeoutAnimate) {\n          clearTimeout(_timeoutAnimate);\n        }\n        _timeoutAnimate = setTimeout(function() {\n          if (_isActive) {\n            return;\n          }\n          _isActive = true;\n          if (_isHiding) {\n            _wrapper.stop(true, false);\n          }\n\n          var animation;\n\n          if (_options.positionAt.match(/^element|body$/i)) {\n            if (_options.deltaDirection.match(/^up|down$/i)) {\n              if (!_isHiding) {\n                _wrapper.css('top', parseInt(_calc.top + _calc.delta) + 'px');\n              }\n              animation = { 'opacity': 1, 'top': _calc.top + 'px' };\n            } else {\n              if (!_isHiding) {\n                _wrapper.css('left', parseInt(_calc.left + _calc.delta) + 'px');\n              }\n              animation = { 'opacity': 1, 'left': _calc.left + 'px' };\n            }\n          } else {\n            if (_options.deltaDirection.match(/^up|down$/i)) {\n              if (!_isHiding) {\n                _calc.mouseTop = e.pageY + _calc.top;\n                _wrapper.css({ 'top': parseInt(_calc.mouseTop + _calc.delta) + 'px', 'left': parseInt(e.pageX - (_wrapper.width() / 2)) + 'px' });\n              }\n              animation = { 'opacity': 1, 'top': _calc.mouseTop + 'px' };\n            } else {\n              if (!_isHiding) {\n                _calc.mouseLeft = e.pageX + _calc.left;\n                _wrapper.css({ 'left': parseInt(_calc.mouseLeft + _calc.delta) + 'px', 'top': parseInt(e.pageY - (_wrapper.height() / 2)) + 'px' });\n              }\n              animation = { 'opacity': 1, 'left': _calc.left + 'px' };\n            }\n          }\n          _isHiding = false;\n          _wrapper.show();\n          _wrapper.animate(animation, _options.animationDuration, _options.animationEasing, function() {\n            _wrapper.css('opacity', '');\n            _isActive = true;\n          });\n        }, _options.delayShow);\n\n        return false;\n      }).bind(_calc.bindHide, function() {\n        if (_timeoutAnimate) {\n          clearTimeout(_timeoutAnimate);\n        }\n        _timeoutAnimate = setTimeout(function() {\n          var animation;\n\n          _isActive = false;\n          _isHiding = true;\n          if (_options.positionAt.match(/^element|body$/i)) {\n            if (_options.deltaDirection.match(/^up|down$/i)) {\n              animation = { 'opacity': 0, 'top': parseInt(_calc.top - _calc.delta) + 'px' };\n            } else {\n              animation = { 'opacity': 0, 'left': parseInt(_calc.left - _calc.delta) + 'px' };\n            }\n          } else {\n            if (_options.deltaDirection.match(/^up|down$/i)) {\n              animation = { 'opacity': 0, 'top': parseInt(_calc.mouseTop - _calc.delta) + 'px' };\n            } else {\n              animation = { 'opacity': 0, 'left': parseInt(_calc.mouseLeft - _calc.delta) + 'px' };\n            }\n          }\n          _wrapper.animate(animation, _options.animationDuration, _options.animationEasing, function() {\n            _wrapper.hide();\n            _isHiding = false;\n          });\n\n        }, _options.delayHide);\n\n        return false;\n      });\n\n      function _Calculate() {\n        // calculate values\n        if (_options.positionAt.match(/^element$/i)) {\n          var offset = _options.positionAtElement.offset();\n          if (_options.deltaDirection.match(/^up$/i)) {\n            _calc.top = offset.top + _options.offsetTop - _wrapper.height();\n            _calc.left = offset.left + _options.offsetLeft + ((_options.positionAtElement.width() - _wrapper.width()) / 2);\n            _calc.delta = _options.deltaPosition;\n          } else if (_options.deltaDirection.match(/^down$/i)) {\n            _calc.top = offset.top + _options.positionAtElement.height() + _options.offsetTop;\n            _calc.left = offset.left + _options.offsetLeft + ((_options.positionAtElement.width() - _wrapper.width()) / 2);\n            _calc.delta = -_options.deltaPosition;\n          } else if (_options.deltaDirection.match(/^left$/i)) {\n            _calc.top = offset.top + _options.offsetTop + ((_options.positionAtElement.height() - _wrapper.height()) / 2);\n            _calc.left = offset.left + _options.offsetLeft - _wrapper.width();\n            _calc.delta = _options.deltaPosition;\n          } else if (_options.deltaDirection.match(/^right$/i)) {\n            _calc.top = offset.top + _options.offsetTop + ((_options.positionAtElement.height() - _wrapper.height()) / 2);\n            _calc.left = offset.left + _options.positionAtElement.width() + _options.offsetLeft;\n            _calc.delta = -_options.deltaPosition;\n          }\n        } else if (_options.positionAt.match(/^body$/i)) {\n          if (_options.deltaDirection.match(/^up|left$/i)) {\n            _calc.top = _options.offsetTop;\n            _calc.left = _options.offsetLeft;\n            // up or left\n            _calc.delta = _options.deltaPosition;\n          } else {\n            if (_options.deltaDirection.match(/^down$/i)) {\n              _calc.top = parseInt(_options.offsetTop + _wrapper.height());\n              _calc.left = _options.offsetLeft;\n            } else {\n              _calc.top = _options.offsetTop;\n              _calc.left = parseInt(_options.offsetLeft + _wrapper.width());\n            }\n            // down or right\n            _calc.delta = -_options.deltaPosition;\n          }\n        } else if (_options.positionAt.match(/^mouse$/i)) {\n          if (_options.deltaDirection.match(/^up|left$/i)) {\n            if (_options.deltaDirection.match(/^up$/i)) {\n              _calc.top = -(_options.offsetTop + _wrapper.height());\n              _calc.left = _options.offsetLeft;\n            } else if (_options.deltaDirection.match(/^left$/i)) {\n              _calc.top = _options.offsetTop;\n              _calc.left = -(_options.offsetLeft + _wrapper.width());\n            }\n            // up or left\n            _calc.delta = _options.deltaPosition;\n          } else {\n            _calc.top = _options.offsetTop;\n            _calc.left = _options.offsetLeft;\n            // down or right\n            _calc.delta = -_options.deltaPosition;\n          }\n        }\n        // hide\n        _wrapper.hide();\n        // handle the wrapper (element|body) positioning\n        if (_options.positionAt.match(/^element|body$/i)) {\n          _wrapper.css({\n            'position': 'absolute',\n            'top': _calc.top + 'px',\n            'left': _calc.left + 'px'\n          });\n        }\n      };\n      return this;\n    },\n    removeBubbletip: function(tips) {\n      var tipsActive;\n      var tipsToRemove = new Array();\n      var arr, i, ix;\n      var elem;\n\n      tipsActive = $.makeArray($(this).data('bubbletip_tips'));\n\n      // convert the parameter array of tip id's or elements to id's\n      arr = $.makeArray(tips);\n      for (i = 0; i < arr.length; i++) {\n        tipsToRemove.push($(arr[i]).get(0).id);\n      }\n\n      for (i = 0; i < tipsActive.length; i++) {\n        ix = null;\n        if ((tipsToRemove.length == 0) || ((ix = $.inArray(tipsActive[i][0], tipsToRemove)) >= 0)) {\n          // remove all tips if there are none specified\n          // otherwise, remove only specified tips\n\n          // find the surrounding table.bubbletip\n          elem = $('#' + tipsActive[i][0]).get(0).parentNode;\n          while (elem.tagName.toLowerCase() != 'table') {\n            elem = elem.parentNode;\n          }\n          // attach the tip element to body and hide\n          $(tipsActive[i][0]).appendTo('body').hide();\n          // remove the surrounding table.bubbletip\n          $(elem).remove();\n\n          // unbind show/hide events\n          $(this).unbind(tipsActive[i][1]).unbind([i][2]);\n\n          // unbind window.resize event\n          $(window).unbind('resize.bubbletip' + tipsActive[i][3]);\n        }\n      }\n\n      return this;\n    }\n  });\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jScrollPane",
    "content": "(function(A){A.jScrollPane={active:[]};A.fn.jScrollPane=function(C){C=A.extend({},A.fn.jScrollPane.defaults,C);var B=function(){return false};return this.each(function(){var O=A(this);O.css(\"overflow\",\"hidden\");var X=this;if(A(this).parent().is(\".jScrollPaneContainer\")){var Ac=C.maintainPosition?O.position().top:0;var L=A(this).parent();var d=L.innerWidth();var Ad=L.outerHeight();var M=Ad;A(\">.jScrollPaneTrack, >.jScrollArrowUp, >.jScrollArrowDown\",L).remove();O.css({top:0})}else{var Ac=0;this.originalPadding=O.css(\"paddingTop\")+\" \"+O.css(\"paddingRight\")+\" \"+O.css(\"paddingBottom\")+\" \"+O.css(\"paddingLeft\");this.originalSidePaddingTotal=(parseInt(O.css(\"paddingLeft\"))||0)+(parseInt(O.css(\"paddingRight\"))||0);var d=O.innerWidth();var Ad=O.innerHeight();var M=Ad;O.wrap(A(\"<div></div>\").attr({className:\"jScrollPaneContainer\"}).css({height:Ad+\"px\",width:d+\"px\"}));A(document).bind(\"emchange\",function(Ae,Af,p){O.jScrollPane(C)})}if(C.reinitialiseOnImageLoad){var N=A.data(X,\"jScrollPaneImagesToLoad\")||A(\"img\",O);var G=[];if(N.length){N.each(function(p,Ae){A(this).bind(\"load\",function(){if(A.inArray(p,G)==-1){G.push(Ae);N=A.grep(N,function(Ag,Af){return Ag!=Ae});A.data(X,\"jScrollPaneImagesToLoad\",N);C.reinitialiseOnImageLoad=false;O.jScrollPane(C)}}).each(function(Af,Ag){if(this.complete||this.complete===undefined){this.src=this.src}})})}}var o=this.originalSidePaddingTotal;var l={height:\"auto\",width:d-C.scrollbarWidth-C.scrollbarMargin-o+\"px\"};if(C.scrollbarOnLeft){l.paddingLeft=C.scrollbarMargin+C.scrollbarWidth+\"px\"}else{l.paddingRight=C.scrollbarMargin+\"px\"}O.css(l);var m=O.outerHeight();var i=Ad/m;if(i<0.99){var H=O.parent();H.append(A(\"<div></div>\").attr({className:\"jScrollPaneTrack\"}).css({width:C.scrollbarWidth+\"px\"}).append(A(\"<div></div>\").attr({className:\"jScrollPaneDrag\"}).css({width:C.scrollbarWidth+\"px\"}).append(A(\"<div></div>\").attr({className:\"jScrollPaneDragTop\"}).css({width:C.scrollbarWidth+\"px\"}),A(\"<div></div>\").attr({className:\"jScrollPaneDragBottom\"}).css({width:C.scrollbarWidth+\"px\"}))));var z=A(\">.jScrollPaneTrack\",H);var P=A(\">.jScrollPaneTrack .jScrollPaneDrag\",H);if(C.showArrows){var g;var Ab;var S;var r;var j=function(){if(r>4||r%4==0){y(u+Ab*b)}r++};var K=function(p){A(\"html\").unbind(\"mouseup\",K);g.removeClass(\"jScrollActiveArrowButton\");clearInterval(S)};var Z=function(){A(\"html\").bind(\"mouseup\",K);g.addClass(\"jScrollActiveArrowButton\");r=0;j();S=setInterval(j,100)};H.append(A(\"<a></a>\").attr({href:\"javascript:;\",className:\"jScrollArrowUp\"}).css({width:C.scrollbarWidth+\"px\"}).html(\"Scroll up\").bind(\"mousedown\",function(){g=A(this);Ab=-1;Z();this.blur();return false}).bind(\"click\",B),A(\"<a></a>\").attr({href:\"javascript:;\",className:\"jScrollArrowDown\"}).css({width:C.scrollbarWidth+\"px\"}).html(\"Scroll down\").bind(\"mousedown\",function(){g=A(this);Ab=1;Z();this.blur();return false}).bind(\"click\",B));var Q=A(\">.jScrollArrowUp\",H);var J=A(\">.jScrollArrowDown\",H);if(C.arrowSize){M=Ad-C.arrowSize-C.arrowSize;z.css({height:M+\"px\",top:C.arrowSize+\"px\"})}else{var s=Q.height();C.arrowSize=s;M=Ad-s-J.height();z.css({height:M+\"px\",top:s+\"px\"})}}var w=A(this).css({position:\"absolute\",overflow:\"visible\"});var D;var Y;var b;var u=0;var V=i*Ad/2;var a=function(Ae,Ag){var Af=Ag==\"X\"?\"Left\":\"Top\";return Ae[\"page\"+Ag]||(Ae[\"client\"+Ag]+(document.documentElement[\"scroll\"+Af]||document.body[\"scroll\"+Af]))||0};var f=function(){return false};var v=function(){n();D=P.offset(false);D.top-=u;Y=M-P[0].offsetHeight;b=2*C.wheelSpeed*Y/m};var E=function(p){v();V=a(p,\"Y\")-u-D.top;A(\"html\").bind(\"mouseup\",T).bind(\"mousemove\",h);if(A.browser.msie){A(\"html\").bind(\"dragstart\",f).bind(\"selectstart\",f)}return false};var T=function(){A(\"html\").unbind(\"mouseup\",T).unbind(\"mousemove\",h);V=i*Ad/2;if(A.browser.msie){A(\"html\").unbind(\"dragstart\",f).unbind(\"selectstart\",f)}};var y=function(Ae){Ae=Ae<0?0:(Ae>Y?Y:Ae);u=Ae;P.css({top:Ae+\"px\"});var Af=Ae/Y;w.css({top:((Ad-m)*Af)+\"px\"});O.trigger(\"scroll\");if(C.showArrows){Q[Ae==0?\"addClass\":\"removeClass\"](\"disabled\");J[Ae==Y?\"addClass\":\"removeClass\"](\"disabled\")}};var h=function(p){y(a(p,\"Y\")-D.top-V)};var q=Math.max(Math.min(i*(Ad-C.arrowSize*2),C.dragMaxHeight),C.dragMinHeight);P.css({height:q+\"px\"}).bind(\"mousedown\",E);var k;var R;var I;var t=function(){if(R>8||R%4==0){y((u-((u-I)/2)))}R++};var Aa=function(){clearInterval(k);A(\"html\").unbind(\"mouseup\",Aa).unbind(\"mousemove\",e)};var e=function(p){I=a(p,\"Y\")-D.top-V};var U=function(p){v();e(p);R=0;A(\"html\").bind(\"mouseup\",Aa).bind(\"mousemove\",e);k=setInterval(t,100);t()};z.bind(\"mousedown\",U);H.bind(\"mousewheel\",function(Ae,Ag){v();n();var Af=u;y(u-Ag*b);var p=Af!=u;return !p});var F;var W;function c(){var p=(F-u)/C.animateStep;if(p>1||p<-1){y(u+p)}else{y(F);n()}}var n=function(){if(W){clearInterval(W);delete F}};var x=function(Af,p){if(typeof Af==\"string\"){$e=A(Af,O);if(!$e.length){return}Af=$e.offset().top-O.offset().top}H.scrollTop(0);n();var Ae=-Af/(Ad-m)*Y;if(p||!C.animateTo){y(Ae)}else{F=Ae;W=setInterval(c,C.animateInterval)}};O[0].scrollTo=x;O[0].scrollBy=function(Ae){var p=-parseInt(w.css(\"top\"))||0;x(p+Ae)};v();x(-Ac,true);A(\"*\",this).bind(\"focus\",function(Ah){var Ag=A(this);var Aj=0;while(Ag[0]!=O[0]){Aj+=Ag.position().top;Ag=Ag.offsetParent()}var p=-parseInt(w.css(\"top\"))||0;var Ai=p+Ad;var Af=Aj>p&&Aj<Ai;if(!Af){var Ae=Aj-C.scrollbarMargin;if(Aj>p){Ae+=A(this).height()+15+C.scrollbarMargin-Ad}x(Ae)}});if(location.hash){x(location.hash)}A(document).bind(\"click\",function(Ae){$target=A(Ae.target);if($target.is(\"a\")){var p=$target.attr(\"href\");if(p.substr(0,1)==\"#\"){x(p)}}});A.jScrollPane.active.push(O[0])}else{O.css({height:Ad+\"px\",width:d-this.originalSidePaddingTotal+\"px\",padding:this.originalPadding});O.parent().unbind(\"mousewheel\")}})};A.fn.jScrollPane.defaults={scrollbarWidth:10,scrollbarMargin:5,wheelSpeed:18,showArrows:false,arrowSize:0,animateTo:false,dragMinHeight:1,dragMaxHeight:99999,animateInterval:100,animateStep:3,maintainPosition:true,scrollbarOnLeft:false,reinitialiseOnImageLoad:false};A(window).bind(\"unload\",function(){var C=A.jScrollPane.active;for(var B=0;B<C.length;B++){C[B].scrollTo=C[B].scrollBy=null}})})(jQuery);"
  },
  {
    "path": "public/javascripts/jScrollPane.js",
    "content": "(function(A){A.jScrollPane={active:[]};A.fn.jScrollPane=function(C){C=A.extend({},A.fn.jScrollPane.defaults,C);var B=function(){return false};return this.each(function(){var O=A(this);O.css(\"overflow\",\"hidden\");var X=this;if(A(this).parent().is(\".jScrollPaneContainer\")){var Ac=C.maintainPosition?O.position().top:0;var L=A(this).parent();var d=L.innerWidth();var Ad=L.outerHeight();var M=Ad;A(\">.jScrollPaneTrack, >.jScrollArrowUp, >.jScrollArrowDown\",L).remove();O.css({top:0})}else{var Ac=0;this.originalPadding=O.css(\"paddingTop\")+\" \"+O.css(\"paddingRight\")+\" \"+O.css(\"paddingBottom\")+\" \"+O.css(\"paddingLeft\");this.originalSidePaddingTotal=(parseInt(O.css(\"paddingLeft\"))||0)+(parseInt(O.css(\"paddingRight\"))||0);var d=O.innerWidth();var Ad=O.innerHeight();var M=Ad;O.wrap(A(\"<div></div>\").attr({className:\"jScrollPaneContainer\"}).css({height:Ad+\"px\",width:d+\"px\"}));A(document).bind(\"emchange\",function(Ae,Af,p){O.jScrollPane(C)})}if(C.reinitialiseOnImageLoad){var N=A.data(X,\"jScrollPaneImagesToLoad\")||A(\"img\",O);var G=[];if(N.length){N.each(function(p,Ae){A(this).bind(\"load\",function(){if(A.inArray(p,G)==-1){G.push(Ae);N=A.grep(N,function(Ag,Af){return Ag!=Ae});A.data(X,\"jScrollPaneImagesToLoad\",N);C.reinitialiseOnImageLoad=false;O.jScrollPane(C)}}).each(function(Af,Ag){if(this.complete||this.complete===undefined){this.src=this.src}})})}}var o=this.originalSidePaddingTotal;var l={height:\"auto\",width:d-C.scrollbarWidth-C.scrollbarMargin-o+\"px\"};if(C.scrollbarOnLeft){l.paddingLeft=C.scrollbarMargin+C.scrollbarWidth+\"px\"}else{l.paddingRight=C.scrollbarMargin+\"px\"}O.css(l);var m=O.outerHeight();var i=Ad/m;if(i<0.99){var H=O.parent();H.append(A(\"<div></div>\").attr({className:\"jScrollPaneTrack\"}).css({width:C.scrollbarWidth+\"px\"}).append(A(\"<div></div>\").attr({className:\"jScrollPaneDrag\"}).css({width:C.scrollbarWidth+\"px\"}).append(A(\"<div></div>\").attr({className:\"jScrollPaneDragTop\"}).css({width:C.scrollbarWidth+\"px\"}),A(\"<div></div>\").attr({className:\"jScrollPaneDragBottom\"}).css({width:C.scrollbarWidth+\"px\"}))));var z=A(\">.jScrollPaneTrack\",H);var P=A(\">.jScrollPaneTrack .jScrollPaneDrag\",H);if(C.showArrows){var g;var Ab;var S;var r;var j=function(){if(r>4||r%4==0){y(u+Ab*b)}r++};var K=function(p){A(\"html\").unbind(\"mouseup\",K);g.removeClass(\"jScrollActiveArrowButton\");clearInterval(S)};var Z=function(){A(\"html\").bind(\"mouseup\",K);g.addClass(\"jScrollActiveArrowButton\");r=0;j();S=setInterval(j,100)};H.append(A(\"<a></a>\").attr({href:\"javascript:;\",className:\"jScrollArrowUp\"}).css({width:C.scrollbarWidth+\"px\"}).html(\"Scroll up\").bind(\"mousedown\",function(){g=A(this);Ab=-1;Z();this.blur();return false}).bind(\"click\",B),A(\"<a></a>\").attr({href:\"javascript:;\",className:\"jScrollArrowDown\"}).css({width:C.scrollbarWidth+\"px\"}).html(\"Scroll down\").bind(\"mousedown\",function(){g=A(this);Ab=1;Z();this.blur();return false}).bind(\"click\",B));var Q=A(\">.jScrollArrowUp\",H);var J=A(\">.jScrollArrowDown\",H);if(C.arrowSize){M=Ad-C.arrowSize-C.arrowSize;z.css({height:M+\"px\",top:C.arrowSize+\"px\"})}else{var s=Q.height();C.arrowSize=s;M=Ad-s-J.height();z.css({height:M+\"px\",top:s+\"px\"})}}var w=A(this).css({position:\"absolute\",overflow:\"visible\"});var D;var Y;var b;var u=0;var V=i*Ad/2;var a=function(Ae,Ag){var Af=Ag==\"X\"?\"Left\":\"Top\";return Ae[\"page\"+Ag]||(Ae[\"client\"+Ag]+(document.documentElement[\"scroll\"+Af]||document.body[\"scroll\"+Af]))||0};var f=function(){return false};var v=function(){n();D=P.offset(false);D.top-=u;Y=M-P[0].offsetHeight;b=2*C.wheelSpeed*Y/m};var E=function(p){v();V=a(p,\"Y\")-u-D.top;A(\"html\").bind(\"mouseup\",T).bind(\"mousemove\",h);if(A.browser.msie){A(\"html\").bind(\"dragstart\",f).bind(\"selectstart\",f)}return false};var T=function(){A(\"html\").unbind(\"mouseup\",T).unbind(\"mousemove\",h);V=i*Ad/2;if(A.browser.msie){A(\"html\").unbind(\"dragstart\",f).unbind(\"selectstart\",f)}};var y=function(Ae){Ae=Ae<0?0:(Ae>Y?Y:Ae);u=Ae;P.css({top:Ae+\"px\"});var Af=Ae/Y;w.css({top:((Ad-m)*Af)+\"px\"});O.trigger(\"scroll\");if(C.showArrows){Q[Ae==0?\"addClass\":\"removeClass\"](\"disabled\");J[Ae==Y?\"addClass\":\"removeClass\"](\"disabled\")}};var h=function(p){y(a(p,\"Y\")-D.top-V)};var q=Math.max(Math.min(i*(Ad-C.arrowSize*2),C.dragMaxHeight),C.dragMinHeight);P.css({height:q+\"px\"}).bind(\"mousedown\",E);var k;var R;var I;var t=function(){if(R>8||R%4==0){y((u-((u-I)/2)))}R++};var Aa=function(){clearInterval(k);A(\"html\").unbind(\"mouseup\",Aa).unbind(\"mousemove\",e)};var e=function(p){I=a(p,\"Y\")-D.top-V};var U=function(p){v();e(p);R=0;A(\"html\").bind(\"mouseup\",Aa).bind(\"mousemove\",e);k=setInterval(t,100);t()};z.bind(\"mousedown\",U);H.bind(\"mousewheel\",function(Ae,Ag){v();n();var Af=u;y(u-Ag*b);var p=Af!=u;return !p});var F;var W;function c(){var p=(F-u)/C.animateStep;if(p>1||p<-1){y(u+p)}else{y(F);n()}}var n=function(){if(W){clearInterval(W);delete F}};var x=function(Af,p){if(typeof Af==\"string\"){$e=A(Af,O);if(!$e.length){return}Af=$e.offset().top-O.offset().top}H.scrollTop(0);n();var Ae=-Af/(Ad-m)*Y;if(p||!C.animateTo){y(Ae)}else{F=Ae;W=setInterval(c,C.animateInterval)}};O[0].scrollTo=x;O[0].scrollBy=function(Ae){var p=-parseInt(w.css(\"top\"))||0;x(p+Ae)};v();x(-Ac,true);A(\"*\",this).bind(\"focus\",function(Ah){var Ag=A(this);var Aj=0;while(Ag[0]!=O[0]){Aj+=Ag.position().top;Ag=Ag.offsetParent()}var p=-parseInt(w.css(\"top\"))||0;var Ai=p+Ad;var Af=Aj>p&&Aj<Ai;if(!Af){var Ae=Aj-C.scrollbarMargin;if(Aj>p){Ae+=A(this).height()+15+C.scrollbarMargin-Ad}x(Ae)}});if(location.hash){x(location.hash)}A(document).bind(\"click\",function(Ae){$target=A(Ae.target);if($target.is(\"a\")){var p=$target.attr(\"href\");if(p.substr(0,1)==\"#\"){x(p)}}});A.jScrollPane.active.push(O[0])}else{O.css({height:Ad+\"px\",width:d-this.originalSidePaddingTotal+\"px\",padding:this.originalPadding});O.parent().unbind(\"mousewheel\")}})};A.fn.jScrollPane.defaults={scrollbarWidth:10,scrollbarMargin:5,wheelSpeed:18,showArrows:false,arrowSize:0,animateTo:false,dragMinHeight:1,dragMaxHeight:99999,animateInterval:100,animateStep:3,maintainPosition:true,scrollbarOnLeft:false,reinitialiseOnImageLoad:false};A(window).bind(\"unload\",function(){var C=A.jScrollPane.active;for(var B=0;B<C.length;B++){C[B].scrollTo=C[B].scrollBy=null}})})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jit-yc.js",
    "content": "/*\n  > Redistribution and use in source and binary forms, with or without\n  > modification, are permitted provided that the following conditions are met:\n  >      * Redistributions of source code must retain the above copyright\n  >        notice, this list of conditions and the following disclaimer.\n  >      * Redistributions in binary form must reproduce the above copyright\n  >        notice, this list of conditions and the following disclaimer in the\n  >        documentation and/or other materials provided with the distribution.\n  >      * Neither the name of the organization nor the\n  >        names of its contributors may be used to endorse or promote products\n  >        derived from this software without specific prior written permission.\n  >\n  >  THIS SOFTWARE IS PROVIDED BY NICOLAS GARCIA BELMONTE ``AS IS'' AND ANY\n  >  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  >  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n  >  DISCLAIMED. IN NO EVENT SHALL NICOLAS GARCIA BELMONTE BE LIABLE FOR ANY\n  >  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n  >  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n  >  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n  >  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n  >  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n  >  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n (function(){window.$jit=function(z){z=z||window;for(var A in $jit){if($jit[A].$extend){z[A]=$jit[A]}}};$jit.version=\"2.0.0a\";var d=function(z){return document.getElementById(z)};d.empty=function(){};d.extend=function(B,z){for(var A in (z||{})){B[A]=z[A]}return B};d.lambda=function(z){return(typeof z==\"function\")?z:function(){return z}};d.time=Date.now||function(){return +new Date};d.splat=function(A){var z=d.type(A);return z?((z!=\"array\")?[A]:A):[]};d.type=function(A){var z=d.type.s.call(A).match(/^\\[object\\s(.*)\\]$/)[1].toLowerCase();if(z!=\"object\"){return z}if(A&&A.$$family){return A.$$family}return(A&&A.nodeName&&A.nodeType==1)?\"element\":z};d.type.s=Object.prototype.toString;d.each=function(E,D){var C=d.type(E);if(C==\"object\"){for(var B in E){D(E[B],B)}}else{for(var A=0,z=E.length;A<z;A++){D(E[A],A)}}};d.indexOf=function(C,B){if(Array.indexOf){return C.indexOf(B)}for(var A=0,z=C.length;A<z;A++){if(C[A]===B){return A}}return -1};d.map=function(B,A){var z=[];d.each(B,function(D,C){z.push(A(D,C))});return z};d.reduce=function(D,B,A){var z=D.length;if(z==0){return A}var C=arguments.length==3?A:D[--z];while(z--){C=B(C,D[z])}return C};d.merge=function(){var D={};for(var C=0,z=arguments.length;C<z;C++){var A=arguments[C];if(d.type(A)!=\"object\"){continue}for(var B in A){var F=A[B],E=D[B];D[B]=(E&&d.type(F)==\"object\"&&d.type(E)==\"object\")?d.merge(E,F):d.unlink(F)}}return D};d.unlink=function(B){var A;switch(d.type(B)){case\"object\":A={};for(var D in B){A[D]=d.unlink(B[D])}break;case\"array\":A=[];for(var C=0,z=B.length;C<z;C++){A[C]=d.unlink(B[C])}break;default:return B}return A};d.zip=function(){if(arguments.length===0){return[]}for(var B=0,A=[],z=arguments.length,E=arguments[0].length;B<E;B++){for(var C=0,D=[];C<z;C++){D.push(arguments[C][B])}A.push(D)}return A};d.rgbToHex=function(D,C){if(D.length<3){return null}if(D.length==4&&D[3]==0&&!C){return\"transparent\"}var A=[];for(var z=0;z<3;z++){var B=(D[z]-0).toString(16);A.push(B.length==1?\"0\"+B:B)}return C?A:\"#\"+A.join(\"\")};d.hexToRgb=function(B){if(B.length!=7){B=B.match(/^#?(\\w{1,2})(\\w{1,2})(\\w{1,2})$/);B.shift();if(B.length!=3){return null}var z=[];for(var A=0;A<3;A++){var C=B[A];if(C.length==1){C+=C}z.push(parseInt(C,16))}return z}else{B=parseInt(B.slice(1),16);return[B>>16,B>>8&255,B&255]}};d.rgbToHsl=function(B){r=B[0]/255,g=B[1]/255,b=B[2]/255;var z=Math.max(r,g,b),C=Math.min(r,g,b);var E,D,A=(z+C)/2;if(z==C){E=D=0}else{var F=z-C;D=A>0.5?F/(2-z-C):F/(z+C);switch(z){case r:E=(g-b)/F+(g<b?6:0);break;case g:E=(b-r)/F+2;break;case b:E=(r-g)/F+4;break}E/=6}return[Math.round(E*360),Math.round(D*100),Math.round(A*100)]};d.hslToRgb=function(D){var F=D[0]/360,I=D[1]/100,E=D[2]/100;var z,G,H;if(I==0){z=G=H=E}else{function C(L,K,J){if(J<0){J+=1}if(J>1){J-=1}if(J<1/6){return L+(K-L)*6*J}if(J<1/2){return K}if(J<2/3){return L+(K-L)*(2/3-J)*6}return L}var A=E<0.5?E*(1+I):E+I-E*I;var B=2*E-A;z=C(B,A,F+1/3);G=C(B,A,F);H=C(B,A,F-1/3)}return[Math.round(z*255),Math.round(G*255),Math.round(H*255)]};d.hslToHex=function(z){return d.rgbToHex(d.hslToRgb(z))};d.rgbToHsv=function(B){r=B[0]/255,g=B[1]/255,b=B[2]/255;var z=Math.max(r,g,b),C=Math.min(r,g,b);var E,D,A=z;var F=z-C;D=z==0?0:F/z;if(z==C){E=0}else{switch(z){case r:E=(g-b)/F+(g<b?6:0);break;case g:E=(b-r)/F+2;break;case b:E=(r-g)/F+4;break}E/=6}return[Math.round(E*360),Math.round(D*100),Math.round(A*100)]};d.hsvToRgb=function(C){var E=C[0]/360,K=C[1]/100,I=C[2]/100;var z,F,H;var D=Math.floor(E*6);var G=E*6-D;var B=I*(1-K);var A=I*(1-G*K);var J=I*(1-(1-G)*K);switch(D%6){case 0:z=I,F=J,H=B;break;case 1:z=A,F=I,H=B;break;case 2:z=B,F=I,H=J;break;case 3:z=B,F=A,H=I;break;case 4:z=J,F=B,H=I;break;case 5:z=I,F=B,H=A;break}return[Math.round(z*255),Math.round(F*255),Math.round(H*255)]};d.hsvToHex=function(z){return d.rgbToHex(d.hsvToRgb(z))};d.destroy=function(z){d.clean(z);if(z.parentNode){z.parentNode.removeChild(z)}if(z.clearAttributes){z.clearAttributes()}};d.clean=function(C){for(var B=C.childNodes,A=0,z=B.length;A<z;A++){d.destroy(B[A])}};d.addEvent=function(B,A,z){if(B.addEventListener){B.addEventListener(A,z,false)}else{B.attachEvent(\"on\"+A,z)}};d.addEvents=function(A,B){for(var z in B){d.addEvent(A,z,B[z])}};d.hasClass=function(A,z){return(\" \"+A.className+\" \").indexOf(\" \"+z+\" \")>-1};d.addClass=function(A,z){if(!d.hasClass(A,z)){A.className=(A.className+\" \"+z)}};d.removeClass=function(A,z){A.className=A.className.replace(new RegExp(\"(^|\\\\s)\"+z+\"(?:\\\\s|$)\"),\"$1\")};d.getPos=function(B){var E=D(B);var z=C(B);return{x:E.x-z.x,y:E.y-z.y};function D(G){var F={x:0,y:0};while(G&&!A(G)){F.x+=G.offsetLeft;F.y+=G.offsetTop;G=G.offsetParent}return F}function C(G){var F={x:0,y:0};while(G&&!A(G)){F.x+=G.scrollLeft;F.y+=G.scrollTop;G=G.parentNode}return F}function A(F){return(/^(?:body|html)$/i).test(F.tagName)}};d.event={get:function(A,z){z=z||window;return A||z.event},getWheel:function(z){return z.wheelDelta?z.wheelDelta/120:-(z.detail||0)/3},isRightClick:function(z){return(z.which==3||z.button==2)},getPos:function(C,B){B=B||window;C=C||B.event;var A=B.document;A=A.documentElement||A.body;if(C.touches&&C.touches.length){C=C.touches[0]}var z={x:C.pageX||(C.clientX+A.scrollLeft),y:C.pageY||(C.clientY+A.scrollTop)};return z},stop:function(z){if(z.stopPropagation){z.stopPropagation()}z.cancelBubble=true;if(z.preventDefault){z.preventDefault()}else{z.returnValue=false}}};$jit.util=$jit.id=d;var t=function(A){A=A||{};var z=function(){for(var D in this){if(typeof this[D]!=\"function\"){this[D]=d.unlink(this[D])}}this.constructor=z;if(t.prototyping){return this}var C=this.initialize?this.initialize.apply(this,arguments):this;this.$$family=\"class\";return C};for(var B in t.Mutators){if(!A[B]){continue}A=t.Mutators[B](A,A[B]);delete A[B]}d.extend(z,this);z.constructor=t;z.prototype=A;return z};t.Mutators={Implements:function(z,A){d.each(d.splat(A),function(C){t.prototyping=C;var B=(typeof C==\"function\")?new C:C;for(var D in B){if(!(D in z)){z[D]=B[D]}}delete t.prototyping});return z}};d.extend(t,{inherit:function(z,C){for(var B in C){var A=C[B];var E=z[B];var D=d.type(A);if(E&&D==\"function\"){if(A!=E){t.override(z,B,A)}}else{if(D==\"object\"){z[B]=d.merge(E,A)}else{z[B]=A}}}return z},override:function(A,z,D){var C=t.prototyping;if(C&&A[z]!=C[z]){C=null}var B=function(){var E=this.parent;this.parent=C?C[z]:A[z];var F=D.apply(this,arguments);this.parent=E;return F};A[z]=B}});t.prototype.implement=function(){var z=this.prototype;d.each(Array.prototype.slice.call(arguments||[]),function(A){t.inherit(z,A)});return this};$jit.Class=t;$jit.json={prune:function(A,z){this.each(A,function(C,B){if(B==z&&C.children){delete C.children;C.children=[]}})},getParent:function(z,D){if(z.id==D){return false}var C=z.children;if(C&&C.length>0){for(var B=0;B<C.length;B++){if(C[B].id==D){return z}else{var A=this.getParent(C[B],D);if(A){return A}}}}return false},getSubtree:function(z,D){if(z.id==D){return z}for(var B=0,C=z.children;B<C.length;B++){var A=this.getSubtree(C[B],D);if(A!=null){return A}}return null},eachLevel:function(z,E,B,D){if(E<=B){D(z,E);if(!z.children){return}for(var A=0,C=z.children;A<C.length;A++){this.eachLevel(C[A],E+1,B,D)}}},each:function(z,A){this.eachLevel(z,0,Number.MAX_VALUE,A)}};$jit.Trans={$extend:true,linear:function(z){return z}};var k=$jit.Trans;(function(){var z=function(C,B){B=d.splat(B);return d.extend(C,{easeIn:function(D){return C(D,B)},easeOut:function(D){return 1-C(1-D,B)},easeInOut:function(D){return(D<=0.5)?C(2*D,B)/2:(2-C(2*(1-D),B))/2}})};var A={Pow:function(C,B){return Math.pow(C,B[0]||6)},Expo:function(B){return Math.pow(2,8*(B-1))},Circ:function(B){return 1-Math.sin(Math.acos(B))},Sine:function(B){return 1-Math.sin((1-B)*Math.PI/2)},Back:function(C,B){B=B[0]||1.618;return Math.pow(C,2)*((B+1)*C-B)},Bounce:function(E){var D;for(var C=0,B=1;1;C+=B,B/=2){if(E>=(7-4*C)/11){D=B*B-Math.pow((11-6*C-11*E)/4,2);break}}return D},Elastic:function(C,B){return Math.pow(2,10*--C)*Math.cos(20*C*Math.PI*(B[0]||1)/3)}};d.each(A,function(C,B){k[B]=z(C)});d.each([\"Quad\",\"Cubic\",\"Quart\",\"Quint\"],function(C,B){k[C]=z(function(D){return Math.pow(D,[B+2])})})})();var x=new t({initialize:function(z){this.setOptions(z)},setOptions:function(z){var A={duration:2500,fps:40,transition:k.Quart.easeInOut,compute:d.empty,complete:d.empty,link:\"ignore\"};this.opt=d.merge(A,z||{});return this},step:function(){var A=d.time(),z=this.opt;if(A<this.time+z.duration){var B=z.transition((A-this.time)/z.duration);z.compute(B)}else{this.timer=clearInterval(this.timer);z.compute(1);z.complete()}},start:function(){if(!this.check()){return this}this.time=0;this.startTimer();return this},startTimer:function(){var z=this,A=this.opt.fps;if(this.timer){return false}this.time=d.time()-this.time;this.timer=setInterval((function(){z.step()}),Math.round(1000/A));return true},pause:function(){this.stopTimer();return this},resume:function(){this.startTimer();return this},stopTimer:function(){if(!this.timer){return false}this.time=d.time()-this.time;this.timer=clearInterval(this.timer);return true},check:function(){if(!this.timer){return true}if(this.opt.link==\"cancel\"){this.stopTimer();return true}return false}});var p=function(){var B=arguments;for(var D=0,z=B.length,A={};D<z;D++){var C=p[B[D]];if(C.$extend){d.extend(A,C)}else{A[B[D]]=C}}return A};p.AreaChart={$extend:true,animate:true,offset:25,labelOffset:3,type:\"stacked\",Tips:{enable:false,onShow:d.empty,onHide:d.empty},Events:{enable:false,onClick:d.empty},selectOnHover:true,showAggregates:true,showLabels:true,filterOnClick:false,restoreOnRightClick:false};p.Canvas={$extend:true,injectInto:\"id\",width:false,height:false,useCanvas:false,withLabels:true,background:false};p.Tree={$extend:true,orientation:\"left\",subtreeOffset:8,siblingOffset:5,indent:10,multitree:false,align:\"center\"};p.Node={$extend:false,overridable:false,type:\"circle\",color:\"#ccb\",alpha:1,dim:3,height:20,width:90,autoHeight:false,autoWidth:false,lineWidth:1,transform:true,align:\"center\",angularWidth:1,span:1,CanvasStyles:{}};p.Edge={$extend:false,overridable:false,type:\"line\",color:\"#ccb\",lineWidth:1,dim:15,alpha:1,CanvasStyles:{}};p.Fx={$extend:true,fps:40,duration:2500,transition:$jit.Trans.Quart.easeInOut,clearCanvas:true};p.Label={$extend:false,overridable:false,type:\"HTML\",style:\" \",size:10,family:\"sans-serif\",textAlign:\"center\",textBaseline:\"alphabetic\",color:\"#fff\"};p.Tips={$extend:false,enable:false,type:\"auto\",offsetX:20,offsetY:20,force:false,onShow:d.empty,onHide:d.empty};p.NodeStyles={$extend:false,enable:false,type:\"auto\",stylesHover:false,stylesClick:false};p.Events={$extend:false,enable:false,type:\"auto\",onClick:d.empty,onRightClick:d.empty,onMouseMove:d.empty,onMouseEnter:d.empty,onMouseLeave:d.empty,onDragStart:d.empty,onDragMove:d.empty,onDragCancel:d.empty,onDragEnd:d.empty,onTouchStart:d.empty,onTouchMove:d.empty,onTouchEnd:d.empty,onMouseWheel:d.empty};p.Navigation={$extend:false,enable:false,type:\"auto\",panning:false,zooming:false};p.Controller={$extend:true,onBeforeCompute:d.empty,onAfterCompute:d.empty,onCreateLabel:d.empty,onPlaceLabel:d.empty,onComplete:d.empty,onBeforePlotLine:d.empty,onAfterPlotLine:d.empty,onBeforePlotNode:d.empty,onAfterPlotNode:d.empty,request:false};var w={initialize:function(B,z){this.viz=z;this.canvas=z.canvas;this.config=z.config[B];this.nodeTypes=z.fx.nodeTypes;var A=this.config.type;this.dom=A==\"auto\"?(z.config.Label.type!=\"Native\"):(A!=\"Native\");this.labelContainer=this.dom&&z.labels.getLabelContainer();this.isEnabled()&&this.initializePost()},initializePost:d.empty,setAsProperty:d.lambda(false),isEnabled:function(){return this.config.enable},isLabel:function(C,B){C=d.event.get(C,B);var z=this.labelContainer,A=C.target||C.srcElement;if(A&&A.parentNode==z){return A}return false}};var j={onMouseUp:d.empty,onMouseDown:d.empty,onMouseMove:d.empty,onMouseOver:d.empty,onMouseOut:d.empty,onMouseWheel:d.empty,onTouchStart:d.empty,onTouchMove:d.empty,onTouchEnd:d.empty,onTouchCancel:d.empty};var v=new t({initialize:function(z){this.viz=z;this.canvas=z.canvas;this.node=false;this.registeredObjects=[];this.attachEvents()},attachEvents:function(){var B=this.canvas.getElement(),A=this;B.oncontextmenu=d.lambda(false);d.addEvents(B,{mouseup:function(E,D){var C=d.event.get(E,D);A.handleEvent(\"MouseUp\",E,D,A.makeEventObject(E,D),d.event.isRightClick(C))},mousedown:function(E,D){var C=d.event.get(E,D);A.handleEvent(\"MouseDown\",E,D,A.makeEventObject(E,D),d.event.isRightClick(C))},mousemove:function(D,C){A.handleEvent(\"MouseMove\",D,C,A.makeEventObject(D,C))},mouseover:function(D,C){A.handleEvent(\"MouseOver\",D,C,A.makeEventObject(D,C))},mouseout:function(D,C){A.handleEvent(\"MouseOut\",D,C,A.makeEventObject(D,C))},touchstart:function(D,C){A.handleEvent(\"TouchStart\",D,C,A.makeEventObject(D,C))},touchmove:function(D,C){A.handleEvent(\"TouchMove\",D,C,A.makeEventObject(D,C))},touchend:function(D,C){A.handleEvent(\"TouchEnd\",D,C,A.makeEventObject(D,C))}});var z=function(F,E){var D=d.event.get(F,E);var C=d.event.getWheel(D);A.handleEvent(\"MouseWheel\",F,E,C)};if(!document.getBoxObjectFor&&window.mozInnerScreenX==null){d.addEvent(B,\"mousewheel\",z)}else{B.addEventListener(\"DOMMouseScroll\",z,false)}},register:function(z){this.registeredObjects.push(z)},handleEvent:function(){var A=Array.prototype.slice.call(arguments),D=A.shift();for(var C=0,B=this.registeredObjects,z=B.length;C<z;C++){B[C][\"on\"+D].apply(B[C],A)}},makeEventObject:function(E,D){var B=this,C=this.viz.graph,A=this.viz.fx,z=A.nodeTypes;return{pos:false,node:false,contains:false,getNodeCalled:false,getPos:function(){if(this.pos){return this.pos}var H=B.viz.canvas,I=H.getSize(),J=H.getPos(),G=H.translateOffsetX,F=H.translateOffsetY,M=H.scaleOffsetX,K=H.scaleOffsetY,L=d.event.getPos(E,D);this.pos={x:(L.x-J.x-I.width/2-G)*1/M,y:(L.y-J.y-I.height/2-F)*1/K};return this.pos},getNode:function(){if(this.getNodeCalled){return this.node}this.getNodeCalled=true;if(B.node){var I=C.getNode(B.node),G=I&&z[I.getData(\"type\")],F=G&&G.contains&&G.contains.call(A,I,this.getPos());if(F){this.contains=F;return this.node=I}}for(var H in C.nodes){var I=C.nodes[H],G=I&&z[I.getData(\"type\")],F=G&&G.contains&&G.contains.call(A,I,this.getPos());if(F){this.contains=F;return B.node=this.node=I}}return B.node=this.node=false},getContains:function(){if(this.getNodeCalled){return this.contains}this.getNode();return this.contains}}}});var q={initializeExtras:function(){var A=new v(this),z=this;d.each([\"NodeStyles\",\"Tips\",\"Navigation\",\"Events\"],function(B){var C=new q.Classes[B](B,z);if(C.isEnabled()){A.register(C)}if(C.setAsProperty()){z[B.toLowerCase()]=C}})}};q.Classes={};q.Classes.Events=new t({Implements:[w,j],initializePost:function(){this.fx=this.viz.fx;this.types=this.viz.fx.nodeTypes;this.hoveredNode=false;this.pressedNode=false;this.touchedNode=false;this.touchMoved=false;this.moved=false},setAsProperty:d.lambda(true),onMouseUp:function(D,C,A,B){var z=d.event.get(D,C);if(B){this.config.onRightClick(this.hoveredNode,A,z)}else{this.config.onClick(this.pressedNode,A,z)}if(this.pressedNode){if(this.moved){this.config.onDragEnd(this.pressedNode,A,z)}else{this.config.onDragCancel(this.pressedNode,A,z)}this.pressedNode=this.moved=false}},onMouseOut:function(E,D,C){var A=d.event.get(E,D),B;if(this.dom&&(B=this.isLabel(E,D))){this.config.onMouseLeave(this.viz.graph.getNode(B.id),C,A);this.hoveredNode=false;return}var z=A.relatedTarget,F=this.canvas.getElement();while(z&&z.parentNode){if(F==z.parentNode){return}z=z.parentNode}if(this.hoveredNode){this.config.onMouseLeave(this.hoveredNode,C,A);this.hoveredNode=false}},onMouseOver:function(D,C,B){var z=d.event.get(D,C),A;if(this.dom&&(A=this.isLabel(D,C))){this.hoveredNode=this.viz.graph.getNode(A.id);this.config.onMouseEnter(this.hoveredNode,B,z)}},onMouseMove:function(F,E,D){var A,z=d.event.get(F,E);if(this.pressedNode){this.moved=true;this.config.onDragMove(this.pressedNode,D,z);return}if(this.dom){this.config.onMouseMove(this.hoveredNode,D,z)}else{if(this.hoveredNode){var G=this.hoveredNode;var C=this.types[G.getData(\"type\")];var B=C&&C.contains&&C.contains.call(this.fx,G,D.getPos());if(B){this.config.onMouseMove(G,D,z);return}else{this.config.onMouseLeave(G,D,z);this.hoveredNode=false}}if(this.hoveredNode=D.getNode()){this.config.onMouseEnter(this.hoveredNode,D,z)}else{this.config.onMouseMove(false,D,z)}}},onMouseWheel:function(A,z,B){this.config.onMouseWheel(B,d.event.get(A,z))},onMouseDown:function(C,B,A){var z=d.event.get(C,B);this.pressedNode=A.getNode();this.config.onDragStart(this.pressedNode,A,z)},onTouchStart:function(C,B,A){var z=d.event.get(C,B);this.touchedNode=A.getNode();this.config.onTouchStart(this.touchedNode,A,z)},onTouchMove:function(C,B,A){var z=d.event.get(C,B);if(this.touchedNode){this.touchMoved=true;this.config.onTouchMove(this.touchedNode,A,z)}},onTouchEnd:function(C,B,A){var z=d.event.get(C,B);if(this.touchedNode){if(this.touchMoved){this.config.onTouchEnd(this.touchedNode,A,z)}else{this.config.onTouchCancel(this.touchedNode,A,z)}this.touchedNode=this.touchMoved=false}}});q.Classes.Tips=new t({Implements:[w,j],initializePost:function(){if(document.body){var z=d(\"_tooltip\")||document.createElement(\"div\");z.id=\"_tooltip\";z.className=\"tip\";d.extend(z.style,{position:\"absolute\",display:\"none\",zIndex:13000});document.body.appendChild(z);this.tip=z;this.node=false}},setAsProperty:d.lambda(true),onMouseOut:function(B,A){if(this.dom&&this.isLabel(B,A)){this.hide(true);return}var z=B.relatedTarget,C=this.canvas.getElement();while(z&&z.parentNode){if(C==z.parentNode){return}z=z.parentNode}this.hide(false)},onMouseOver:function(B,A){var z;if(this.dom&&(z=this.isLabel(B,A))){this.node=this.viz.graph.getNode(z.id);this.config.onShow(this.tip,this.node,z)}},onMouseMove:function(C,B,z){if(this.dom&&this.isLabel(C,B)){this.setTooltipPosition(d.event.getPos(C,B))}if(!this.dom){var A=z.getNode();if(!A){this.hide(true);return}if(this.config.force||!this.node||this.node.id!=A.id){this.node=A;this.config.onShow(this.tip,A,z.getContains())}this.setTooltipPosition(d.event.getPos(C,B))}},setTooltipPosition:function(G){var C=this.tip,B=C.style,A=this.config;B.display=\"\";var E={height:document.body.clientHeight,width:document.body.clientWidth};var D={width:C.offsetWidth,height:C.offsetHeight};var z=A.offsetX,F=A.offsetY;B.top=((G.y+F+D.height>E.height)?(G.y-D.height-F):G.y+F)+\"px\";B.left=((G.x+D.width+z>E.width)?(G.x-D.width-z):G.x+z)+\"px\"},hide:function(z){this.tip.style.display=\"none\";z&&this.config.onHide()}});q.Classes.NodeStyles=new t({Implements:[w,j],initializePost:function(){this.fx=this.viz.fx;this.types=this.viz.fx.nodeTypes;this.nStyles=this.config;this.nodeStylesOnHover=this.nStyles.stylesHover;this.nodeStylesOnClick=this.nStyles.stylesClick;this.hoveredNode=false;this.fx.nodeFxAnimation=new x();this.down=false;this.move=false},onMouseOut:function(B,A){this.down=this.move=false;if(!this.hoveredNode){return}if(this.dom&&this.isLabel(B,A)){this.toggleStylesOnHover(this.hoveredNode,false)}var z=B.relatedTarget,C=this.canvas.getElement();while(z&&z.parentNode){if(C==z.parentNode){return}z=z.parentNode}this.toggleStylesOnHover(this.hoveredNode,false);this.hoveredNode=false},onMouseOver:function(C,B){var z;if(this.dom&&(z=this.isLabel(C,B))){var A=this.viz.graph.getNode(z.id);if(A.selected){return}this.hoveredNode=A;this.toggleStylesOnHover(this.hoveredNode,true)}},onMouseDown:function(D,C,A,B){if(B){return}var z;if(this.dom&&(z=this.isLabel(D,C))){this.down=this.viz.graph.getNode(z.id)}else{if(!this.dom){this.down=A.getNode()}}this.move=false},onMouseUp:function(C,B,z,A){if(A){return}if(!this.move){this.onClick(z.getNode())}this.down=this.move=false},getRestoredStyles:function(A,z){var C={},B=this[\"nodeStylesOn\"+z];for(var D in B){C[D]=A.styles[\"$\"+D]}return C},toggleStylesOnHover:function(z,A){if(this.nodeStylesOnHover){this.toggleStylesOn(\"Hover\",z,A)}},toggleStylesOnClick:function(z,A){if(this.nodeStylesOnClick){this.toggleStylesOn(\"Click\",z,A)}},toggleStylesOn:function(D,z,F){var G=this.viz;var E=this.nStyles;if(F){var C=this;if(!z.styles){z.styles=d.merge(z.data,{})}for(var H in this[\"nodeStylesOn\"+D]){var A=\"$\"+H;if(!(A in z.styles)){z.styles[A]=z.getData(H)}}G.fx.nodeFx(d.extend({elements:{id:z.id,properties:C[\"nodeStylesOn\"+D]},transition:k.Quart.easeOut,duration:300,fps:40},this.config))}else{var B=this.getRestoredStyles(z,D);G.fx.nodeFx(d.extend({elements:{id:z.id,properties:B},transition:k.Quart.easeOut,duration:300,fps:40},this.config))}},onClick:function(z){if(!z){return}var A=this.nodeStylesOnClick;if(!A){return}if(z.selected){this.toggleStylesOnClick(z,false);delete z.selected}else{this.viz.graph.eachNode(function(C){if(C.selected){for(var B in A){C.setData(B,C.styles[\"$\"+B],\"end\")}delete C.selected}});this.toggleStylesOnClick(z,true);z.selected=true;delete z.hovered;this.hoveredNode=false}},onMouseMove:function(F,E,C){if(this.down){this.move=true}if(this.dom&&this.isLabel(F,E)){return}var D=this.nodeStylesOnHover;if(!D){return}if(!this.dom){if(this.hoveredNode){var A=this.types[this.hoveredNode.getData(\"type\")];var z=A&&A.contains&&A.contains.call(this.fx,this.hoveredNode,C.getPos());if(z){return}}var B=C.getNode();if(!this.hoveredNode&&!B){return}if(B.hovered){return}if(B&&!B.selected){this.fx.nodeFxAnimation.stopTimer();this.viz.graph.eachNode(function(H){if(H.hovered&&!H.selected){for(var G in D){H.setData(G,H.styles[\"$\"+G],\"end\")}delete H.hovered}});B.hovered=true;this.hoveredNode=B;this.toggleStylesOnHover(B,true)}else{if(this.hoveredNode&&!this.hoveredNode.selected){this.fx.nodeFxAnimation.stopTimer();this.toggleStylesOnHover(this.hoveredNode,false);delete this.hoveredNode.hovered;this.hoveredNode=false}}}}});q.Classes.Navigation=new t({Implements:[w,j],initializePost:function(){this.pos=false;this.pressed=false},onMouseWheel:function(C,B,z){if(!this.config.zooming){return}d.event.stop(d.event.get(C,B));var D=this.config.zooming/1000,A=1+z*D;this.canvas.scale(A,A)},onMouseDown:function(E,D,C){if(!this.config.panning){return}if(this.config.panning==\"avoid nodes\"&&C.getNode()){return}this.pressed=true;this.pos=C.getPos();var B=this.canvas,A=B.translateOffsetX,z=B.translateOffsetY,G=B.scaleOffsetX,F=B.scaleOffsetY;this.pos.x*=G;this.pos.x+=A;this.pos.y*=F;this.pos.y+=z},onMouseMove:function(E,D,G){if(!this.config.panning){return}if(!this.pressed){return}if(this.config.panning==\"avoid nodes\"&&G.getNode()){return}var C=this.pos,F=G.getPos(),A=this.canvas,B=A.translateOffsetX,z=A.translateOffsetY,K=A.scaleOffsetX,I=A.scaleOffsetY;F.x*=K;F.y*=I;F.x+=B;F.y+=z;var J=F.x-C.x,H=F.y-C.y;this.pos=F;this.canvas.translate(J*1/K,H*1/I)},onMouseUp:function(C,B,A,z){if(!this.config.panning){return}this.pressed=false}});var n;(function(){var z=typeof HTMLCanvasElement,B=(z==\"object\"||z==\"function\");function A(C,D){var E=document.createElement(C);for(var F in D){if(typeof D[F]==\"object\"){d.extend(E[F],D[F])}else{E[F]=D[F]}}if(C==\"canvas\"&&!B&&G_vmlCanvasManager){E=G_vmlCanvasManager.initElement(document.body.appendChild(E))}return E}$jit.Canvas=n=new t({canvases:[],pos:false,element:false,labelContainer:false,translateOffsetX:0,translateOffsetY:0,scaleOffsetX:1,scaleOffsetY:1,initialize:function(N,H){this.viz=N;this.opt=H;var E=d.type(H.injectInto)==\"string\"?H.injectInto:H.injectInto.id,F=E+\"-label\",C=d(E),G=H.width||C.offsetWidth,O=H.height||C.offsetHeight;this.id=E;var I={injectInto:E,width:G,height:O};this.element=A(\"div\",{id:E+\"-canvaswidget\",style:{position:\"relative\",width:G+\"px\",height:O+\"px\"}});this.labelContainer=this.createLabelContainer(H.Label.type,F,I);this.canvases.push(new n.Base({config:d.extend({idSuffix:\"-canvas\"},I),plot:function(P){N.fx.plot()},resize:function(){N.refresh()}}));var J=H.background;if(J){var M=new n.Background[J.type](N,d.extend(J,I));this.canvases.push(new n.Base(M))}var L=this.canvases.length;while(L--){this.element.appendChild(this.canvases[L].canvas);if(L>0){this.canvases[L].plot()}}this.element.appendChild(this.labelContainer);C.appendChild(this.element);var D=null,K=this;d.addEvent(window,\"scroll\",function(){clearTimeout(D);D=setTimeout(function(){K.getPos(true)},500)})},getCtx:function(C){return this.canvases[C||0].getCtx()},getConfig:function(){return this.opt},getElement:function(){return this.element},getSize:function(C){return this.canvases[C||0].getSize()},resize:function(G,C){this.getPos(true);this.translateOffsetX=this.translateOffsetY=0;this.scaleOffsetX=this.scaleOffsetY=1;for(var E=0,D=this.canvases.length;E<D;E++){this.canvases[E].resize(G,C)}var F=this.element.style;F.width=G+\"px\";F.height=C+\"px\";if(this.labelContainer){this.labelContainer.style.width=G+\"px\"}},translate:function(C,G,F){this.translateOffsetX+=C*this.scaleOffsetX;this.translateOffsetY+=G*this.scaleOffsetY;for(var E=0,D=this.canvases.length;E<D;E++){this.canvases[E].translate(C,G,F)}},scale:function(H,E,F){var I=this.scaleOffsetX*H,G=this.scaleOffsetY*E;var K=this.translateOffsetX*(H-1)/I,J=this.translateOffsetY*(E-1)/G;this.scaleOffsetX=I;this.scaleOffsetY=G;for(var D=0,C=this.canvases.length;D<C;D++){this.canvases[D].scale(H,E,true)}this.translate(K,J,false)},getPos:function(C){if(C||!this.pos){return this.pos=d.getPos(this.getElement())}return this.pos},clear:function(C){this.canvases[C||0].clear()},path:function(D,E){var C=this.canvases[0].getCtx();C.beginPath();E(C);C[D]();C.closePath()},createLabelContainer:function(E,I,H){var G=\"http://www.w3.org/2000/svg\";if(E==\"HTML\"||E==\"Native\"){return A(\"div\",{id:I,style:{overflow:\"visible\",position:\"absolute\",top:0,left:0,width:H.width+\"px\",height:0}})}else{if(E==\"SVG\"){var F=document.createElementNS(G,\"svg:svg\");F.setAttribute(\"width\",H.width);F.setAttribute(\"height\",H.height);var D=F.style;D.position=\"absolute\";D.left=D.top=\"0px\";var C=document.createElementNS(G,\"svg:g\");C.setAttribute(\"width\",H.width);C.setAttribute(\"height\",H.height);C.setAttribute(\"x\",0);C.setAttribute(\"y\",0);C.setAttribute(\"id\",I);F.appendChild(C);return F}}}});n.Base=new t({translateOffsetX:0,translateOffsetY:0,scaleOffsetX:1,scaleOffsetY:1,initialize:function(C){this.viz=C;this.opt=C.config;this.size=false;this.createCanvas();this.translateToCenter()},createCanvas:function(){var D=this.opt,E=D.width,C=D.height;this.canvas=A(\"canvas\",{id:D.injectInto+D.idSuffix,width:E,height:C,style:{position:\"absolute\",top:0,left:0,width:E+\"px\",height:C+\"px\"}})},getCtx:function(){if(!this.ctx){return this.ctx=this.canvas.getContext(\"2d\")}return this.ctx},getSize:function(){if(this.size){return this.size}var C=this.canvas;return this.size={width:C.width,height:C.height}},translateToCenter:function(F){var D=this.getSize(),E=F?(D.width-F.width-this.translateOffsetX*2):D.width;height=F?(D.height-F.height-this.translateOffsetY*2):D.height;var C=this.getCtx();F&&C.scale(1/this.scaleOffsetX,1/this.scaleOffsetY);C.translate(E/2,height/2)},resize:function(F,C){var E=this.getSize(),D=this.canvas,G=D.style;this.size=false;D.width=F;D.height=C;G.width=F+\"px\";G.height=C+\"px\";if(!B){this.translateToCenter(E)}else{this.translateToCenter()}this.translateOffsetX=this.translateOffsetY=0;this.scaleOffsetX=this.scaleOffsetY=1;this.clear();this.viz.resize(F,C,this)},translate:function(C,G,D){var F=this.scaleOffsetX,E=this.scaleOffsetY;this.translateOffsetX+=C*F;this.translateOffsetY+=G*E;this.getCtx().translate(C,G);!D&&this.plot()},scale:function(C,E,D){this.scaleOffsetX*=C;this.scaleOffsetY*=E;this.getCtx().scale(C,E);!D&&this.plot()},clear:function(){var E=this.getSize(),D=this.translateOffsetX,C=this.translateOffsetY,G=this.scaleOffsetX,F=this.scaleOffsetY;this.getCtx().clearRect((-E.width/2-D)*1/G,(-E.height/2-C)*1/F,E.width*1/G,E.height*1/F)},plot:function(){this.clear();this.viz.plot(this)}});n.Background={};n.Background.Circles=new t({initialize:function(C,D){this.viz=C;this.config=d.merge({idSuffix:\"-bkcanvas\",levelDistance:100,numberOfCircles:6,CanvasStyles:{},offset:0},D)},resize:function(D,C,E){this.plot(E)},plot:function(C){var D=C.canvas,J=C.getCtx(),G=this.config,I=G.CanvasStyles;for(var K in I){J[K]=I[K]}var E=G.numberOfCircles,H=G.levelDistance;for(var F=1;F<=E;F++){J.beginPath();J.arc(0,0,H*F,0,2*Math.PI,false);J.stroke();J.closePath()}}})})();var c=function(A,z){this.theta=A;this.rho=z};$jit.Polar=c;c.prototype={getc:function(z){return this.toComplex(z)},getp:function(){return this},set:function(z){z=z.getp();this.theta=z.theta;this.rho=z.rho},setc:function(z,A){this.rho=Math.sqrt(z*z+A*A);this.theta=Math.atan2(A,z);if(this.theta<0){this.theta+=Math.PI*2}},setp:function(A,z){this.theta=A;this.rho=z},clone:function(){return new c(this.theta,this.rho)},toComplex:function(B){var z=Math.cos(this.theta)*this.rho;var A=Math.sin(this.theta)*this.rho;if(B){return{x:z,y:A}}return new s(z,A)},add:function(z){return new c(this.theta+z.theta,this.rho+z.rho)},scale:function(z){return new c(this.theta,this.rho*z)},equals:function(z){return this.theta==z.theta&&this.rho==z.rho},$add:function(z){this.theta=this.theta+z.theta;this.rho+=z.rho;return this},$madd:function(z){this.theta=(this.theta+z.theta)%(Math.PI*2);this.rho+=z.rho;return this},$scale:function(z){this.rho*=z;return this},interpolate:function(B,I){var C=Math.PI,F=C*2;var A=function(K){var J=(K<0)?(K%F)+F:K%F;return J};var E=this.theta,H=B.theta;var D,G=Math.abs(E-H);if(G==C){if(E>H){D=A((H+((E-F)-H)*I))}else{D=A((H-F+(E-(H))*I))}}else{if(G>=C){if(E>H){D=A((H+((E-F)-H)*I))}else{D=A((H-F+(E-(H-F))*I))}}else{D=A((H+(E-H)*I))}}var z=(this.rho-B.rho)*I+B.rho;return{theta:D,rho:z}}};var m=function(A,z){return new c(A,z)};c.KER=m(0,0);var s=function(z,A){this.x=z;this.y=A};$jit.Complex=s;s.prototype={getc:function(){return this},getp:function(z){return this.toPolar(z)},set:function(z){z=z.getc(true);this.x=z.x;this.y=z.y},setc:function(z,A){this.x=z;this.y=A},setp:function(A,z){this.x=Math.cos(A)*z;this.y=Math.sin(A)*z},clone:function(){return new s(this.x,this.y)},toPolar:function(B){var z=this.norm();var A=Math.atan2(this.y,this.x);if(A<0){A+=Math.PI*2}if(B){return{theta:A,rho:z}}return new c(A,z)},norm:function(){return Math.sqrt(this.squaredNorm())},squaredNorm:function(){return this.x*this.x+this.y*this.y},add:function(z){return new s(this.x+z.x,this.y+z.y)},prod:function(z){return new s(this.x*z.x-this.y*z.y,this.y*z.x+this.x*z.y)},conjugate:function(){return new s(this.x,-this.y)},scale:function(z){return new s(this.x*z,this.y*z)},equals:function(z){return this.x==z.x&&this.y==z.y},$add:function(z){this.x+=z.x;this.y+=z.y;return this},$prod:function(B){var z=this.x,A=this.y;this.x=z*B.x-A*B.y;this.y=A*B.x+z*B.y;return this},$conjugate:function(){this.y=-this.y;return this},$scale:function(z){this.x*=z;this.y*=z;return this},$div:function(C){var z=this.x,B=this.y;var A=C.squaredNorm();this.x=z*C.x+B*C.y;this.y=B*C.x-z*C.y;return this.$scale(1/A)}};var u=function(A,z){return new s(A,z)};s.KER=u(0,0);$jit.Graph=new t({initialize:function(B,A,z,F){var D={complex:false,Node:{}};this.Node=A;this.Edge=z;this.Label=F;this.opt=d.merge(D,B||{});this.nodes={};this.edges={};var C=this;this.nodeList={};for(var E in l){C.nodeList[E]=(function(G){return function(){var H=Array.prototype.slice.call(arguments);C.eachNode(function(I){I[G].apply(I,H)})}})(E)}},getNode:function(z){if(this.hasNode(z)){return this.nodes[z]}return false},getByName:function(z){for(var B in this.nodes){var A=this.nodes[B];if(A.name==z){return A}}return false},getAdjacence:function(A,z){if(A in this.edges){return this.edges[A][z]}return false},addNode:function(A){if(!this.nodes[A.id]){var z=this.edges[A.id]={};this.nodes[A.id]=new f.Node(d.extend({id:A.id,name:A.name,data:A.data||{},adjacencies:z},this.opt.Node),this.opt.complex,this.Node,this.Edge,this.Label)}return this.nodes[A.id]},addAdjacence:function(C,B,A){if(!this.hasNode(C.id)){this.addNode(C)}if(!this.hasNode(B.id)){this.addNode(B)}C=this.nodes[C.id];B=this.nodes[B.id];var D=this.edges[C.id]=this.edges[C.id]||{};var z=this.edges[B.id]=this.edges[B.id]||{};D[B.id]=z[C.id]=new f.Adjacence(C,B,A,this.Edge,this.Label);return D[B.id]},removeNode:function(B){if(this.hasNode(B)){delete this.nodes[B];var A=this.edges[B];for(var z in A){delete this.edges[z][B]}delete this.edges[B]}},removeAdjacence:function(A,z){delete this.edges[A][z];delete this.edges[z][A]},hasNode:function(z){return z in this.nodes},empty:function(){this.nodes={};this.edges={}}});var f=$jit.Graph;var l;(function(){var z=function(G,I,D,F,H){var E;D=D||\"current\";G=\"$\"+(G?G+\"-\":\"\");if(D==\"current\"){E=this.data}else{if(D==\"start\"){E=this.startData}else{if(D==\"end\"){E=this.endData}}}var C=G+I;if(F){return E[C]}if(!this.Config.overridable){return H[I]||0}return(C in E)?E[C]:((C in this.data)?this.data[C]:(H[I]||0))};var B=function(F,G,E,C){C=C||\"current\";F=\"$\"+(F?F+\"-\":\"\");var D;if(C==\"current\"){D=this.data}else{if(C==\"start\"){D=this.startData}else{if(C==\"end\"){D=this.endData}}}D[F+G]=E};var A=function(E,C){E=\"$\"+(E?E+\"-\":\"\");var D=this;d.each(C,function(G){var F=E+G;delete D.data[F];delete D.endData[F];delete D.startData[F]})};l={getData:function(E,C,D){return z.call(this,\"\",E,C,D,this.Config)},setData:function(E,D,C){B.call(this,\"\",E,D,C)},setDataset:function(F,G){F=d.splat(F);for(var C in G){for(var E=0,H=d.splat(G[C]),D=F.length;E<D;E++){this.setData(C,H[E],F[E])}}},removeData:function(){A.call(this,\"\",Array.prototype.slice.call(arguments))},getCanvasStyle:function(E,C,D){return z.call(this,\"canvas\",E,C,D,this.Config.CanvasStyles)},setCanvasStyle:function(E,D,C){B.call(this,\"canvas\",E,D,C)},setCanvasStyles:function(F,G){F=d.splat(F);for(var C in G){for(var E=0,H=d.splat(G[C]),D=F.length;E<D;E++){this.setCanvasStyle(C,H[E],F[E])}}},removeCanvasStyle:function(){A.call(this,\"canvas\",Array.prototype.slice.call(arguments))},getLabelData:function(E,C,D){return z.call(this,\"label\",E,C,D,this.Label)},setLabelData:function(E,D,C){B.call(this,\"label\",E,D,C)},setLabelDataset:function(F,G){F=d.splat(F);for(var C in G){for(var E=0,H=d.splat(G[C]),D=F.length;E<D;E++){this.setLabelData(C,H[E],F[E])}}},removeLabelData:function(){A.call(this,\"label\",Array.prototype.slice.call(arguments))}}})();f.Node=new t({initialize:function(B,D,A,z,E){var C={id:\"\",name:\"\",data:{},startData:{},endData:{},adjacencies:{},selected:false,drawn:false,exist:false,angleSpan:{begin:0,end:0},pos:(D&&u(0,0))||m(0,0),startPos:(D&&u(0,0))||m(0,0),endPos:(D&&u(0,0))||m(0,0)};d.extend(this,d.extend(C,B));this.Config=this.Node=A;this.Edge=z;this.Label=E},adjacentTo:function(z){return z.id in this.adjacencies},getAdjacency:function(z){return this.adjacencies[z]},getPos:function(z){z=z||\"current\";if(z==\"current\"){return this.pos}else{if(z==\"end\"){return this.endPos}else{if(z==\"start\"){return this.startPos}}}},setPos:function(A,z){z=z||\"current\";var B;if(z==\"current\"){B=this.pos}else{if(z==\"end\"){B=this.endPos}else{if(z==\"start\"){B=this.startPos}}}B.set(A)}});f.Node.implement(l);f.Adjacence=new t({initialize:function(A,D,B,z,C){this.nodeFrom=A;this.nodeTo=D;this.data=B||{};this.startData={};this.endData={};this.Config=this.Edge=z;this.Label=C}});f.Adjacence.implement(l);f.Util={filter:function(A){if(!A||!(d.type(A)==\"string\")){return function(){return true}}var z=A.split(\" \");return function(C){for(var B=0;B<z.length;B++){if(C[z[B]]){return false}}return true}},getNode:function(z,A){return z.nodes[A]},eachNode:function(D,C,z){var B=this.filter(z);for(var A in D.nodes){if(B(D.nodes[A])){C(D.nodes[A])}}},eachAdjacency:function(E,F,A){var B=E.adjacencies,D=this.filter(A);for(var G in B){var z=B[G];if(D(z)){if(z.nodeFrom!=E){var C=z.nodeFrom;z.nodeFrom=z.nodeTo;z.nodeTo=C}F(z,G)}}},computeLevels:function(F,G,C,B){C=C||0;var D=this.filter(B);this.eachNode(F,function(H){H._flag=false;H._depth=-1},B);var A=F.getNode(G);A._depth=C;var z=[A];while(z.length!=0){var E=z.pop();E._flag=true;this.eachAdjacency(E,function(H){var I=H.nodeTo;if(I._flag==false&&D(I)){if(I._depth<0){I._depth=E._depth+1+C}z.unshift(I)}},B)}},eachBFS:function(E,F,D,A){var B=this.filter(A);this.clean(E);var z=[E.getNode(F)];while(z.length!=0){var C=z.pop();C._flag=true;D(C,C._depth);this.eachAdjacency(C,function(G){var H=G.nodeTo;if(H._flag==false&&B(H)){H._flag=true;z.unshift(H)}},A)}},eachLevel:function(D,H,A,E,C){var G=D._depth,z=this.filter(C),F=this;A=A===false?Number.MAX_VALUE-G:A;(function B(K,I,J){var L=K._depth;if(L>=I&&L<=J&&z(K)){E(K,L)}if(L<J){F.eachAdjacency(K,function(M){var N=M.nodeTo;if(N._depth>L){B(N,I,J)}})}})(D,H+G,A+G)},eachSubgraph:function(A,B,z){this.eachLevel(A,0,false,B,z)},eachSubnode:function(A,B,z){this.eachLevel(A,1,1,B,z)},anySubnode:function(C,B,A){var z=false;B=B||d.lambda(true);var D=d.type(B)==\"string\"?function(E){return E[B]}:B;this.eachSubnode(C,function(E){if(D(E)){z=true}},A);return z},getSubnodes:function(E,F,z){var B=[],D=this;F=F||0;var C,A;if(d.type(F)==\"array\"){C=F[0];A=F[1]}else{C=F;A=Number.MAX_VALUE-E._depth}this.eachLevel(E,C,A,function(G){B.push(G)},z);return B},getParents:function(A){var z=[];this.eachAdjacency(A,function(B){var C=B.nodeTo;if(C._depth<A._depth){z.push(C)}});return z},isDescendantOf:function(C,D){if(C.id==D){return true}var B=this.getParents(C),z=false;for(var A=0;!z&&A<B.length;A++){z=z||this.isDescendantOf(B[A],D)}return z},clean:function(z){this.eachNode(z,function(A){A._flag=false})},getClosestNodeToOrigin:function(A,B,z){return this.getClosestNodeToPos(A,c.KER,B,z)},getClosestNodeToPos:function(B,E,D,z){var A=null;D=D||\"current\";E=E&&E.getc(true)||s.KER;var C=function(G,F){var I=G.x-F.x,H=G.y-F.y;return I*I+H*H};this.eachNode(B,function(F){A=(A==null||C(F.getPos(D).getc(true),E)<C(A.getPos(D).getc(true),E))?F:A},z);return A}};d.each([\"getNode\",\"eachNode\",\"computeLevels\",\"eachBFS\",\"clean\",\"getClosestNodeToPos\",\"getClosestNodeToOrigin\"],function(z){f.prototype[z]=function(){return f.Util[z].apply(f.Util,[this].concat(Array.prototype.slice.call(arguments)))}});d.each([\"eachAdjacency\",\"eachLevel\",\"eachSubgraph\",\"eachSubnode\",\"anySubnode\",\"getSubnodes\",\"getParents\",\"isDescendantOf\"],function(z){f.Node.prototype[z]=function(){return f.Util[z].apply(f.Util,[this].concat(Array.prototype.slice.call(arguments)))}});f.Op={options:{type:\"nothing\",duration:2000,hideLabels:true,fps:30},removeNode:function(E,C){var z=this.viz;var A=d.merge(this.options,z.controller,C);var G=d.splat(E);var B,D,F;switch(A.type){case\"nothing\":for(B=0;B<G.length;B++){z.graph.removeNode(G[B])}break;case\"replot\":this.removeNode(G,{type:\"nothing\"});z.labels.clearLabels();z.refresh(true);break;case\"fade:seq\":case\"fade\":D=this;for(B=0;B<G.length;B++){F=z.graph.getNode(G[B]);F.setData(\"alpha\",0,\"end\")}z.fx.animate(d.merge(A,{modes:[\"node-property:alpha\"],onComplete:function(){D.removeNode(G,{type:\"nothing\"});z.labels.clearLabels();z.reposition();z.fx.animate(d.merge(A,{modes:[\"linear\"]}))}}));break;case\"fade:con\":D=this;for(B=0;B<G.length;B++){F=z.graph.getNode(G[B]);F.setData(\"alpha\",0,\"end\");F.ignore=true}z.reposition();z.fx.animate(d.merge(A,{modes:[\"node-property:alpha\",\"linear\"],onComplete:function(){D.removeNode(G,{type:\"nothing\"})}}));break;case\"iter\":D=this;z.fx.sequence({condition:function(){return G.length!=0},step:function(){D.removeNode(G.shift(),{type:\"nothing\"});z.labels.clearLabels()},onComplete:function(){A.onComplete()},duration:Math.ceil(A.duration/G.length)});break;default:this.doError()}},removeEdge:function(G,E){var z=this.viz;var C=d.merge(this.options,z.controller,E);var B=(d.type(G[0])==\"string\")?[G]:G;var D,F,A;switch(C.type){case\"nothing\":for(D=0;D<B.length;D++){z.graph.removeAdjacence(B[D][0],B[D][1])}break;case\"replot\":this.removeEdge(B,{type:\"nothing\"});z.refresh(true);break;case\"fade:seq\":case\"fade\":F=this;for(D=0;D<B.length;D++){A=z.graph.getAdjacence(B[D][0],B[D][1]);if(A){A.setData(\"alpha\",0,\"end\")}}z.fx.animate(d.merge(C,{modes:[\"edge-property:alpha\"],onComplete:function(){F.removeEdge(B,{type:\"nothing\"});z.reposition();z.fx.animate(d.merge(C,{modes:[\"linear\"]}))}}));break;case\"fade:con\":F=this;for(D=0;D<B.length;D++){A=z.graph.getAdjacence(B[D][0],B[D][1]);if(A){A.setData(\"alpha\",0,\"end\");A.ignore=true}}z.reposition();z.fx.animate(d.merge(C,{modes:[\"edge-property:alpha\",\"linear\"],onComplete:function(){F.removeEdge(B,{type:\"nothing\"})}}));break;case\"iter\":F=this;z.fx.sequence({condition:function(){return B.length!=0},step:function(){F.removeEdge(B.shift(),{type:\"nothing\"});z.labels.clearLabels()},onComplete:function(){C.onComplete()},duration:Math.ceil(C.duration/B.length)});break;default:this.doError()}},sum:function(D,C){var z=this.viz;var B=d.merge(this.options,z.controller,C),A=z.root;var F;z.root=C.id||z.root;switch(B.type){case\"nothing\":F=z.construct(D);F.eachNode(function(H){H.eachAdjacency(function(I){z.graph.addAdjacence(I.nodeFrom,I.nodeTo,I.data)})});break;case\"replot\":z.refresh(true);this.sum(D,{type:\"nothing\"});z.refresh(true);break;case\"fade:seq\":case\"fade\":case\"fade:con\":that=this;F=z.construct(D);var G=this.preprocessSum(F);var E=!G?[\"node-property:alpha\"]:[\"node-property:alpha\",\"edge-property:alpha\"];z.reposition();if(B.type!=\"fade:con\"){z.fx.animate(d.merge(B,{modes:[\"linear\"],onComplete:function(){z.fx.animate(d.merge(B,{modes:E,onComplete:function(){B.onComplete()}}))}}))}else{z.graph.eachNode(function(H){if(H.id!=A&&H.pos.getp().equals(c.KER)){H.pos.set(H.endPos);H.startPos.set(H.endPos)}});z.fx.animate(d.merge(B,{modes:[\"linear\"].concat(E)}))}break;default:this.doError()}},morph:function(G,A,C){var E=this.viz;var H=d.merge(this.options,E.controller,A),D=E.root;var F;E.root=A.id||E.root;switch(H.type){case\"nothing\":F=E.construct(G);F.eachNode(function(K){var J=E.graph.hasNode(K.id);K.eachAdjacency(function(O){var N=!!E.graph.getAdjacence(O.nodeFrom.id,O.nodeTo.id);E.graph.addAdjacence(O.nodeFrom,O.nodeTo,O.data);if(N){var M=E.graph.getAdjacence(O.nodeFrom.id,O.nodeTo.id);for(var P in (O.data||{})){M.data[P]=O.data[P]}}});if(J){var I=E.graph.getNode(K.id);for(var L in (K.data||{})){I.data[L]=K.data[L]}}});E.graph.eachNode(function(I){I.eachAdjacency(function(J){if(!F.getAdjacence(J.nodeFrom.id,J.nodeTo.id)){E.graph.removeAdjacence(J.nodeFrom.id,J.nodeTo.id)}});if(!F.hasNode(I.id)){E.graph.removeNode(I.id)}});break;case\"replot\":E.labels.clearLabels(true);this.morph(G,{type:\"nothing\"});E.refresh(true);E.refresh(true);break;case\"fade:seq\":case\"fade\":case\"fade:con\":that=this;F=E.construct(G);E.graph.eachNode(function(J){var K=F.getNode(J.id);if(!K){J.setData(\"alpha\",1);J.setData(\"alpha\",1,\"start\");J.setData(\"alpha\",0,\"end\");J.ignore=true}else{var I=K.data;for(var L in I){if(L[0]==\"$\"&&L!=\"$type\"){J.endData[L]=I[L]}else{J.data[L]=I[L]}}}});E.graph.eachNode(function(I){if(I.ignore){return}I.eachAdjacency(function(J){if(J.nodeFrom.ignore||J.nodeTo.ignore){return}var K=F.getNode(J.nodeFrom.id);var L=F.getNode(J.nodeTo.id);if(!K.adjacentTo(L)){var J=E.graph.getAdjacence(K.id,L.id);z=true;J.setData(\"alpha\",1);J.setData(\"alpha\",1,\"start\");J.setData(\"alpha\",0,\"end\")}})});var z=this.preprocessSum(F);var B=!z?[\"node-property:alpha\"]:[\"node-property:alpha\",\"edge-property:alpha\"];B[0]=B[0]+((C&&(\"node-property\" in C))?d.splat(C[\"node-property\"]).join(\":\"):\"\");B[1]=(B[1]||\"edge-property:alpha\")+((C&&(\"edge-property\" in C))?d.splat(C[\"edge-property\"]).join(\":\"):\"\");if(C&&(\"label-property\" in C)){B.push(\"label-property\"+d.splat(C[\"label-property\"]).join(\":\"))}E.reposition();E.graph.eachNode(function(I){if(I.id!=D&&I.pos.getp().equals(c.KER)){I.pos.set(I.endPos);I.startPos.set(I.endPos)}});E.fx.animate(d.merge(H,{modes:[\"polar\"].concat(B),onComplete:function(){E.graph.eachNode(function(I){if(I.ignore){E.graph.removeNode(I.id)}});E.graph.eachNode(function(I){I.eachAdjacency(function(J){if(J.ignore){E.graph.removeAdjacence(J.nodeFrom.id,J.nodeTo.id)}})});H.onComplete()}}));break;default:}},contract:function(B,A){var z=this.viz;if(B.collapsed||!B.anySubnode(d.lambda(true))){return}A=d.merge(this.options,z.config,A||{},{modes:[\"node-property:alpha:span\",\"linear\"]});B.collapsed=true;(function C(D){D.eachSubnode(function(E){E.ignore=true;E.setData(\"alpha\",0,A.type==\"animate\"?\"end\":\"current\");C(E)})})(B);if(A.type==\"animate\"){z.compute(\"end\");if(z.rotated){z.rotate(z.rotated,\"none\",{property:\"end\"})}(function C(D){D.eachSubnode(function(E){E.setPos(B.getPos(\"end\"),\"end\");C(E)})})(B);z.fx.animate(A)}else{if(A.type==\"replot\"){z.refresh()}}},expand:function(B,A){if(!(\"collapsed\" in B)){return}var z=this.viz;A=d.merge(this.options,z.config,A||{},{modes:[\"node-property:alpha:span\",\"linear\"]});delete B.collapsed;(function C(D){D.eachSubnode(function(E){delete E.ignore;E.setData(\"alpha\",1,A.type==\"animate\"?\"end\":\"current\");C(E)})})(B);if(A.type==\"animate\"){z.compute(\"end\");if(z.rotated){z.rotate(z.rotated,\"none\",{property:\"end\"})}z.fx.animate(A)}else{if(A.type==\"replot\"){z.refresh()}}},preprocessSum:function(A){var z=this.viz;A.eachNode(function(C){if(!z.graph.hasNode(C.id)){z.graph.addNode(C);var D=z.graph.getNode(C.id);D.setData(\"alpha\",0);D.setData(\"alpha\",0,\"start\");D.setData(\"alpha\",1,\"end\")}});var B=false;A.eachNode(function(C){C.eachAdjacency(function(D){var E=z.graph.getNode(D.nodeFrom.id);var F=z.graph.getNode(D.nodeTo.id);if(!E.adjacentTo(F)){var D=z.graph.addAdjacence(E,F,D.data);if(E.startAlpha==E.endAlpha&&F.startAlpha==F.endAlpha){B=true;D.setData(\"alpha\",0);D.setData(\"alpha\",0,\"start\");D.setData(\"alpha\",1,\"end\")}}})});return B}};var a={none:{render:d.empty,contains:d.lambda(false)},circle:{render:function(C,D,z,B){var A=B.getCtx();A.beginPath();A.arc(D.x,D.y,z,0,Math.PI*2,true);A.closePath();A[C]()},contains:function(E,D,z){var B=E.x-D.x,A=E.y-D.y,C=B*B+A*A;return C<=z*z}},ellipse:{render:function(D,E,C,z,B){var A=B.getCtx();z/=2;C/=2;A.save();A.scale(C/z,z/C);A.beginPath();A.arc(E.x*(z/C),E.y*(C/z),z,0,Math.PI*2,true);A.closePath();A[D]();A.restore()},contains:function(G,F,C,z){C/=2;z/=2;var E=(C+z)/2,B=G.x-F.x,A=G.y-F.y,D=B*B+A*A;return D<=E*E}},square:{render:function(A,C,B,z){z.getCtx()[A+\"Rect\"](C.x-B,C.y-B,2*B,2*B)},contains:function(B,A,z){return Math.abs(A.x-B.x)<=z&&Math.abs(A.y-B.y)<=z}},rectangle:{render:function(C,D,B,z,A){A.getCtx()[C+\"Rect\"](D.x-B/2,D.y-z/2,B,z)},contains:function(C,B,A,z){return Math.abs(B.x-C.x)<=A/2&&Math.abs(B.y-C.y)<=z/2}},triangle:{render:function(F,G,C,z){var J=z.getCtx(),B=G.x,A=G.y-C,I=B-C,H=G.y+C,E=B+C,D=H;J.beginPath();J.moveTo(B,A);J.lineTo(I,H);J.lineTo(E,D);J.closePath();J[F]()},contains:function(B,A,z){return a.circle.contains(B,A,z)}},star:{render:function(D,F,E,A){var z=A.getCtx(),C=Math.PI/5;z.save();z.translate(F.x,F.y);z.beginPath();z.moveTo(E,0);for(var B=0;B<9;B++){z.rotate(C);if(B%2==0){z.lineTo((E/0.525731)*0.200811,0)}else{z.lineTo(E,0)}}z.closePath();z[D]();z.restore()},contains:function(B,A,z){return a.circle.contains(B,A,z)}}};var o={line:function(C,B,A){var z=A.getCtx();z.beginPath();z.moveTo(C.x,C.y);z.lineTo(B.x,B.y);z.stroke()},arrow:function(I,J,C,A,z){var K=z.getCtx();if(A){var B=I;I=J;J=B}var F=new s(J.x-I.x,J.y-I.y);F.$scale(C/F.norm());var D=new s(J.x-F.x,J.y-F.y),E=new s(-F.y/2,F.x/2),H=D.add(E),G=D.$add(E.$scale(-1));K.beginPath();K.moveTo(I.x,I.y);K.lineTo(J.x,J.y);K.stroke();K.beginPath();K.moveTo(H.x,H.y);K.lineTo(G.x,G.y);K.lineTo(J.x,J.y);K.closePath();K.fill()},hyperline:function(G,H,z,B){var I=B.getCtx();var C=D(G,H);if(C.a>1000||C.b>1000||C.ratio<0){I.beginPath();I.moveTo(G.x*z,G.y*z);I.lineTo(H.x*z,H.y*z);I.stroke()}else{var F=Math.atan2(H.y-C.y,H.x-C.x);var E=Math.atan2(G.y-C.y,G.x-C.x);var A=A(F,E);I.beginPath();I.arc(C.x*z,C.y*z,C.ratio*z,F,E,A);I.stroke()}function D(V,U){var N=(V.x*U.y-V.y*U.x),J=N;var M=V.squaredNorm(),L=U.squaredNorm();if(N==0){return{x:0,y:0,ratio:-1}}var T=(V.y*L-U.y*M+V.y-U.y)/N;var R=(U.x*M-V.x*L+U.x-V.x)/J;var S=-T/2;var Q=-R/2;var P=(T*T+R*R)/4-1;if(P<0){return{x:0,y:0,ratio:-1}}var O=Math.sqrt(P);var K={x:S,y:Q,ratio:O>1000?-1:O,a:T,b:R};return K}function A(J,K){return(J<K)?((J+Math.PI>K)?false:true):((K+Math.PI>J)?true:false)}}};f.Plot={nodeHelper:a,edgeHelper:o,Interpolator:{map:{border:\"color\",color:\"color\",width:\"number\",height:\"number\",dim:\"number\",alpha:\"number\",lineWidth:\"number\",angularWidth:\"number\",span:\"number\",valueArray:\"array-number\",dimArray:\"array-number\"},canvas:{globalAlpha:\"number\",fillStyle:\"color\",strokeStyle:\"color\",lineWidth:\"number\",shadowBlur:\"number\",shadowColor:\"color\",shadowOffsetX:\"number\",shadowOffsetY:\"number\",miterLimit:\"number\"},label:{size:\"number\",color:\"color\"},compute:function(B,A,z){return B+(A-B)*z},moebius:function(E,D,G,A){var C=A.scale(-G);if(C.norm()<1){var z=C.x,F=C.y;var B=E.startPos.getc().moebiusTransformation(C);E.pos.setc(B.x,B.y);C.x=z;C.y=F}},linear:function(A,z,D){var C=A.startPos.getc(true);var B=A.endPos.getc(true);A.pos.setc(this.compute(C.x,B.x,D),this.compute(C.y,B.y,D))},polar:function(B,A,E){var D=B.startPos.getp(true);var C=B.endPos.getp();var z=C.interpolate(D,E);B.pos.setp(z.theta,z.rho)},number:function(A,F,E,z,D){var C=A[z](F,\"start\");var B=A[z](F,\"end\");A[D](F,this.compute(C,B,E))},color:function(B,z,H,E,C){var F=d.hexToRgb(B[E](z,\"start\"));var G=d.hexToRgb(B[E](z,\"end\"));var D=this.compute;var A=d.rgbToHex([parseInt(D(F[0],G[0],H)),parseInt(D(F[1],G[1],H)),parseInt(D(F[2],G[2],H))]);B[C](z,A)},\"array-number\":function(C,B,M,J,E){var K=C[J](B,\"start\"),L=C[J](B,\"end\"),N=[];for(var H=0,D=K.length;H<D;H++){var A=K[H],z=L[H];if(A.length){for(var G=0,I=A.length,F=[];G<I;G++){F.push(this.compute(A[G],z[G],M))}N.push(F)}else{N.push(this.compute(A,z,M))}}C[E](B,N)},node:function(A,F,H,z,G,B){z=this[z];if(F){var E=F.length;for(var C=0;C<E;C++){var D=F[C];this[z[D]](A,D,H,G,B)}}else{for(var D in z){this[z[D]](A,D,H,G,B)}}},edge:function(B,A,G,C,z,F){var E=B.adjacencies;for(var D in E){this[\"node\"](E[D],A,G,C,z,F)}},\"node-property\":function(A,z,B){this[\"node\"](A,z,B,\"map\",\"getData\",\"setData\")},\"edge-property\":function(A,z,B){this[\"edge\"](A,z,B,\"map\",\"getData\",\"setData\")},\"label-property\":function(A,z,B){this[\"node\"](A,z,B,\"label\",\"getLabelData\",\"setLabelData\")},\"node-style\":function(A,z,B){this[\"node\"](A,z,B,\"canvas\",\"getCanvasStyle\",\"setCanvasStyle\")},\"edge-style\":function(A,z,B){this[\"edge\"](A,z,B,\"canvas\",\"getCanvasStyle\",\"setCanvasStyle\")}},sequence:function(A){var B=this;A=d.merge({condition:d.lambda(false),step:d.empty,onComplete:d.empty,duration:200},A||{});var z=setInterval(function(){if(A.condition()){A.step()}else{clearInterval(z);A.onComplete()}B.viz.refresh(true)},A.duration)},prepare:function(F){var E=this.viz.graph,C={\"node-property\":{getter:\"getData\",setter:\"setData\"},\"edge-property\":{getter:\"getData\",setter:\"setData\"},\"node-style\":{getter:\"getCanvasStyle\",setter:\"setCanvasStyle\"},\"edge-style\":{getter:\"getCanvasStyle\",setter:\"setCanvasStyle\"}};var A={};if(d.type(F)==\"array\"){for(var D=0,z=F.length;D<z;D++){var B=F[D].split(\":\");A[B.shift()]=B}}else{for(var G in F){if(G==\"position\"){A[F.position]=[]}else{A[G]=d.splat(F[G])}}}E.eachNode(function(H){H.startPos.set(H.pos);d.each([\"node-property\",\"node-style\"],function(K){if(K in A){var L=A[K];for(var J=0,I=L.length;J<I;J++){H[C[K].setter](L[J],H[C[K].getter](L[J]),\"start\")}}});d.each([\"edge-property\",\"edge-style\"],function(I){if(I in A){var J=A[I];H.eachAdjacency(function(L){for(var M=0,K=J.length;M<K;M++){L[C[I].setter](J[M],L[C[I].getter](J[M]),\"start\")}})}})});return A},animate:function(C,B){C=d.merge(this.viz.config,C||{});var D=this,A=this.viz,F=A.graph,G=this.Interpolator,E=C.type===\"nodefx\"?this.nodeFxAnimation:this.animation;var z=this.prepare(C.modes);if(C.hideLabels){this.labels.hideLabels(true)}E.setOptions(d.merge(C,{$animating:false,compute:function(H){F.eachNode(function(I){for(var J in z){G[J](I,z[J],H,B)}});D.plot(C,this.$animating,H);this.$animating=true},complete:function(){if(C.hideLabels){D.labels.hideLabels(false)}D.plot(C);C.onComplete();C.onAfterCompute()}})).start()},nodeFx:function(B){var G=this.viz,H=G.graph,E=this.nodeFxAnimation,I=d.merge(this.viz.config,{elements:{id:false,properties:{}},reposition:false});B=d.merge(I,B||{},{onBeforeCompute:d.empty,onAfterCompute:d.empty});E.stopTimer();var F=B.elements.properties;if(!B.elements.id){H.eachNode(function(K){for(var J in F){K.setData(J,F[J],\"end\")}})}else{var z=d.splat(B.elements.id);d.each(z,function(L){var K=H.getNode(L);if(K){for(var J in F){K.setData(J,F[J],\"end\")}}})}var D=[];for(var A in F){D.push(A)}var C=[\"node-property:\"+D.join(\":\")];if(B.reposition){C.push(\"linear\");G.compute(\"end\")}this.animate(d.merge(B,{modes:C,type:\"nodefx\"}))},plot:function(A,I){var G=this.viz,E=G.graph,B=G.canvas,z=G.root,F=this,H=B.getCtx(),D=Math.min,A=A||this.viz.controller;A.clearCanvas&&B.clear();var C=!!E.getNode(z).visited;E.eachNode(function(K){var J=K.getData(\"alpha\");K.eachAdjacency(function(L){var M=L.nodeTo;if(!!M.visited===C&&K.drawn&&M.drawn){!I&&A.onBeforePlotLine(L);H.save();H.globalAlpha=D(J,M.getData(\"alpha\"),L.getData(\"alpha\"));F.plotLine(L,B,I);H.restore();!I&&A.onAfterPlotLine(L)}});H.save();if(K.drawn){!I&&A.onBeforePlotNode(K);F.plotNode(K,B,I);!I&&A.onAfterPlotNode(K)}if(!F.labelsHidden&&A.withLabels){if(K.drawn&&J>=0.95){F.labels.plotLabel(B,K,A)}else{F.labels.hideLabel(K,false)}}H.restore();K.visited=!C})},plotTree:function(D,A,H){var E=this,F=this.viz,B=F.canvas,C=this.config,G=B.getCtx();var z=D.getData(\"alpha\");D.eachSubnode(function(J){if(A.plotSubtree(D,J)&&J.exist&&J.drawn){var I=D.getAdjacency(J.id);!H&&A.onBeforePlotLine(I);G.globalAlpha=Math.min(z,J.getData(\"alpha\"));E.plotLine(I,B,H);!H&&A.onAfterPlotLine(I);E.plotTree(J,A,H)}});if(D.drawn){!H&&A.onBeforePlotNode(D);this.plotNode(D,B,H);!H&&A.onAfterPlotNode(D);if(!A.hideLabels&&A.withLabels&&z>=0.95){this.labels.plotLabel(B,D,A)}else{this.labels.hideLabel(D,false)}}else{this.labels.hideLabel(D,true)}},plotNode:function(B,A,I){var F=B.getData(\"type\"),E=this.node.CanvasStyles;if(F!=\"none\"){var z=B.getData(\"lineWidth\"),D=B.getData(\"color\"),C=B.getData(\"alpha\"),G=A.getCtx();G.lineWidth=z;G.fillStyle=G.strokeStyle=D;G.globalAlpha=C;for(var H in E){G[H]=B.getCanvasStyle(H)}this.nodeTypes[F].render.call(this,B,A,I)}},plotLine:function(E,A,H){var D=E.getData(\"type\"),C=this.edge.CanvasStyles;if(D!=\"none\"){var z=E.getData(\"lineWidth\"),B=E.getData(\"color\"),F=A.getCtx();F.lineWidth=z;F.fillStyle=F.strokeStyle=B;for(var G in C){F[G]=E.getCanvasStyle(G)}this.edgeTypes[D].call(this,E,A,H)}}};f.Label={};f.Label.Native=new t({plotLabel:function(B,C,A){var z=B.getCtx();var D=C.pos.getc(true);z.font=C.getLabelData(\"style\")+\" \"+C.getLabelData(\"size\")+\"px \"+C.getLabelData(\"family\");z.textAlign=C.getLabelData(\"textAlign\");z.fillStyle=z.strokeStyle=C.getLabelData(\"color\");z.textBaseline=C.getLabelData(\"textBaseline\");this.renderLabel(B,C,A)},renderLabel:function(B,C,A){var z=B.getCtx();var D=C.pos.getc(true);z.fillText(C.name,D.x,D.y+C.getData(\"height\")/2)},hideLabel:d.empty,hideLabels:d.empty});f.Label.DOM=new t({labelsHidden:false,labelContainer:false,labels:{},getLabelContainer:function(){return this.labelContainer?this.labelContainer:this.labelContainer=document.getElementById(this.viz.config.labelContainer)},getLabel:function(z){return(z in this.labels&&this.labels[z]!=null)?this.labels[z]:this.labels[z]=document.getElementById(z)},hideLabels:function(A){var z=this.getLabelContainer();if(A){z.style.display=\"none\"}else{z.style.display=\"\"}this.labelsHidden=A},clearLabels:function(z){for(var A in this.labels){if(z||!this.viz.graph.hasNode(A)){this.disposeLabel(A);delete this.labels[A]}}},disposeLabel:function(A){var z=this.getLabel(A);if(z&&z.parentNode){z.parentNode.removeChild(z)}},hideLabel:function(D,z){D=d.splat(D);var A=z?\"\":\"none\",B,C=this;d.each(D,function(F){var E=C.getLabel(F.id);if(E){E.style.display=A}})},fitsInCanvas:function(B,z){var A=z.getSize();if(B.x>=A.width||B.x<0||B.y>=A.height||B.y<0){return false}return true}});f.Label.HTML=new t({Implements:f.Label.DOM,plotLabel:function(C,D,B){var E=D.id,z=this.getLabel(E);if(!z&&!(z=document.getElementById(E))){z=document.createElement(\"div\");var A=this.getLabelContainer();z.id=E;z.className=\"node\";z.style.position=\"absolute\";B.onCreateLabel(z,D);A.appendChild(z);this.labels[D.id]=z}this.placeLabel(z,D,B)}});f.Label.SVG=new t({Implements:f.Label.DOM,plotLabel:function(C,E,B){var G=E.id,z=this.getLabel(G);if(!z&&!(z=document.getElementById(G))){var D=\"http://www.w3.org/2000/svg\";z=document.createElementNS(D,\"svg:text\");var F=document.createElementNS(D,\"svg:tspan\");z.appendChild(F);var A=this.getLabelContainer();z.setAttribute(\"id\",G);z.setAttribute(\"class\",\"node\");A.appendChild(z);B.onCreateLabel(z,E);this.labels[E.id]=z}this.placeLabel(z,E,B)}});f.Geom=new t({initialize:function(z){this.viz=z;this.config=z.config;this.node=z.config.Node;this.edge=z.config.Edge},translate:function(A,z){z=d.splat(z);this.viz.graph.eachNode(function(B){d.each(z,function(C){B.getPos(C).$add(A)})})},setRightLevelToShow:function(C,z,E){var D=this.getRightLevelToShow(C,z),B=this.viz.labels,A=d.merge({execShow:true,execHide:true,onHide:d.empty,onShow:d.empty},E||{});C.eachLevel(0,this.config.levelsToShow,function(G){var F=G._depth-C._depth;if(F>D){A.onHide(G);if(A.execHide){G.drawn=false;G.exist=false;B.hideLabel(G,false)}}else{A.onShow(G);if(A.execShow){G.exist=true}}});C.drawn=true},getRightLevelToShow:function(C,A){var z=this.config;var D=z.levelsToShow;var B=z.constrained;if(!B){return D}while(!this.treeFitsInCanvas(C,A,D)&&D>1){D--}return D}});var e={construct:function(A){var B=(d.type(A)==\"array\");var z=new f(this.graphOptions,this.config.Node,this.config.Edge,this.config.Label);if(!B){(function(C,E){C.addNode(E);if(E.children){for(var D=0,F=E.children;D<F.length;D++){C.addAdjacence(E,F[D]);arguments.callee(C,F[D])}}})(z,A)}else{(function(K,L){var D=function(P){for(var O=0,M=L.length;O<M;O++){if(L[O].id==P){return L[O]}}var N={id:P,name:P};return K.addNode(N)};for(var H=0,E=L.length;H<E;H++){K.addNode(L[H]);var I=L[H].adjacencies;if(I){for(var F=0,J=I.length;F<J;F++){var C=I[F],G={};if(typeof I[F]!=\"string\"){G=C.data;C=C.nodeTo}K.addAdjacence(L[H],D(C),G)}}}})(z,A)}return z},loadJSON:function(A,z){this.json=A;if(this.labels&&this.labels.clearLabels){this.labels.clearLabels(true)}this.graph=this.construct(A);if(d.type(A)!=\"array\"){this.root=A.id}else{this.root=A[z?z:0].id}},toJSON:function(D){D=D||\"tree\";if(D==\"tree\"){var B={};var A=this.graph.getNode(this.root);var B=(function z(G){var E={};E.id=G.id;E.name=G.name;E.data=G.data;var F=[];G.eachSubnode(function(H){F.push(z(H))});E.children=F;return E})(A);return B}else{var B=[];var C=!!this.graph.getNode(this.root).visited;this.graph.eachNode(function(F){var E={};E.id=F.id;E.name=F.name;E.data=F.data;var G=[];F.eachAdjacency(function(H){var J=H.nodeTo;if(!!J.visited===C){var I={};I.nodeTo=J.id;I.data=H.data;G.push(I)}});E.adjacencies=G;B.push(E);F.visited=!C});return B}}};var i=$jit.Layouts={};var h={label:null,compute:function(C,D,A){this.initializeLabel(A);var z=this.label,B=z.style;C.eachNode(function(G){var K=G.getData(\"autoWidth\"),L=G.getData(\"autoHeight\");if(K||L){delete G.data.$width;delete G.data.$height;delete G.data.$dim;var E=G.getData(\"width\"),M=G.getData(\"height\");B.width=K?\"auto\":E+\"px\";B.height=L?\"auto\":M+\"px\";z.innerHTML=G.name;var I=z.offsetWidth,F=z.offsetHeight;var J=G.getData(\"type\");if(d.indexOf([\"circle\",\"square\",\"triangle\",\"star\"],J)===-1){G.setData(\"width\",I);G.setData(\"height\",F)}else{var H=I>F?I:F;G.setData(\"width\",H);G.setData(\"height\",H);G.setData(\"dim\",H)}}})},initializeLabel:function(z){if(!this.label){this.label=document.createElement(\"div\");document.body.appendChild(this.label)}this.setLabelStyles(z)},setLabelStyles:function(z){d.extend(this.label.style,{visibility:\"hidden\",position:\"absolute\",width:\"auto\",height:\"auto\"});this.label.className=\"jit-autoadjust-label\"}};i.Tree=(function(){var I=Array.prototype.slice;function G(S,N,K,Q,L){var P=N.Node;var M=N.multitree;if(P.overridable){var R=-1,O=-1;S.eachNode(function(V){if(V._depth==K&&(!M||(\"$orn\" in V.data)&&V.data.$orn==Q)){var T=V.getData(\"width\",L);var U=V.getData(\"height\",L);R=(R<T)?T:R;O=(O<U)?U:O}});return{width:R<0?P.width:R,height:O<0?P.height:O}}else{return P}}function J(L,O,N,K){var M=(K==\"left\"||K==\"right\")?\"y\":\"x\";L.getPos(O)[M]+=N}function E(L,M){var K=[];d.each(L,function(N){N=I.call(N);N[0]+=M;N[1]+=M;K.push(N)});return K}function H(N,K){if(N.length==0){return K}if(K.length==0){return N}var M=N.shift(),L=K.shift();return[[M[0],L[1]]].concat(H(N,K))}function C(K,L){L=L||[];if(K.length==0){return L}var M=K.pop();return C(K,H(M,L))}function F(N,L,O,K,M){if(N.length<=M||L.length<=M){return 0}var Q=N[M][1],P=L[M][0];return Math.max(F(N,L,O,K,++M)+O,Q-P+K)}function D(N,L,K){function M(Q,S,P){if(S.length<=P){return[]}var R=S[P],O=F(Q,R,L,K,0);return[O].concat(M(H(Q,E(R,O)),S,++P))}return M([],N,0)}function A(O,N,M){function K(R,T,Q){if(T.length<=Q){return[]}var S=T[Q],P=-F(S,R,N,M,0);return[P].concat(K(H(E(S,P),R),T,++Q))}O=I.call(O);var L=K([],O.reverse(),0);return L.reverse()}function z(Q,O,L,R){var M=D(Q,O,L),P=A(Q,O,L);if(R==\"left\"){P=M}else{if(R==\"right\"){M=P}}for(var N=0,K=[];N<M.length;N++){K[N]=(M[N]+P[N])/2}return K}function B(K,U,L,ab,Z){var N=ab.multitree;var T=[\"x\",\"y\"],Q=[\"width\",\"height\"];var M=+(Z==\"left\"||Z==\"right\");var R=T[M],aa=T[1-M];var W=ab.Node;var P=Q[M],Y=Q[1-M];var O=ab.siblingOffset;var X=ab.subtreeOffset;var V=ab.align;function S(ae,ai,am){var ad=ae.getData(P,L);var al=ai||(ae.getData(Y,L));var ap=[],an=[],aj=false;var ac=al+ab.levelDistance;ae.eachSubnode(function(ar){if(ar.exist&&(!N||(\"$orn\" in ar.data)&&ar.data.$orn==Z)){if(!aj){aj=G(K,ab,ar._depth,Z,L)}var aq=S(ar,aj[Y],am+ac);ap.push(aq.tree);an.push(aq.extent)}});var ah=z(an,X,O,V);for(var ag=0,af=[],ak=[];ag<ap.length;ag++){J(ap[ag],L,ah[ag],Z);ak.push(E(an[ag],ah[ag]))}var ao=[[-ad/2,ad/2]].concat(C(ak));ae.getPos(L)[R]=0;if(Z==\"top\"||Z==\"left\"){ae.getPos(L)[aa]=am}else{ae.getPos(L)[aa]=-am}return{tree:ae,extent:ao}}S(U,false,0)}return new t({compute:function(M,L){var N=M||\"start\";var K=this.graph.getNode(this.root);d.extend(K,{drawn:true,exist:true,selected:true});h.compute(this.graph,N,this.config);if(!!L||!(\"_depth\" in K)){this.graph.computeLevels(this.root,0,\"ignore\")}this.computePositions(K,N)},computePositions:function(O,K){var M=this.config;var L=M.multitree;var R=M.align;var N=R!==\"center\"&&M.indent;var S=M.orientation;var Q=L?[\"top\",\"right\",\"bottom\",\"left\"]:[S];var P=this;d.each(Q,function(T){B(P.graph,O,K,P.config,T,K);var U=[\"x\",\"y\"][+(T==\"left\"||T==\"right\")];(function V(W){W.eachSubnode(function(X){if(X.exist&&(!L||(\"$orn\" in X.data)&&X.data.$orn==T)){X.getPos(K)[U]+=W.getPos(K)[U];if(N){X.getPos(K)[U]+=R==\"left\"?N:-N}V(X)}})})(O)})}})})();$jit.ST=(function(){var A=[];function B(G){G=G||this.clickedNode;if(!this.config.constrained){return[]}var D=this.geom;var K=this.graph;var E=this.canvas;var C=G._depth,H=[];K.eachNode(function(L){if(L.exist&&!L.selected){if(L.isDescendantOf(G.id)){if(L._depth<=C){H.push(L)}}else{H.push(L)}}});var I=D.getRightLevelToShow(G,E);G.eachLevel(I,I,function(L){if(L.exist&&!L.selected){H.push(L)}});for(var J=0;J<A.length;J++){var F=this.graph.getNode(A[J]);if(!F.isDescendantOf(G.id)){H.push(F)}}return H}function z(E){var D=[],C=this.config;E=E||this.clickedNode;this.clickedNode.eachLevel(0,C.levelsToShow,function(F){if(C.multitree&&!(\"$orn\" in F.data)&&F.anySubnode(function(G){return G.exist&&!G.drawn})){D.push(F)}else{if(F.drawn&&!F.anySubnode(\"drawn\")){D.push(F)}}});return D}return new t({Implements:[e,q,i.Tree],initialize:function(C){var E=$jit.ST;var D={levelsToShow:2,levelDistance:30,constrained:true,Node:{type:\"rectangle\"},duration:700,offsetX:0,offsetY:0};this.controller=this.config=d.merge(p(\"Canvas\",\"Fx\",\"Tree\",\"Node\",\"Edge\",\"Controller\",\"Tips\",\"NodeStyles\",\"Events\",\"Navigation\",\"Label\"),D,C);var F=this.config;if(F.useCanvas){this.canvas=F.useCanvas;this.config.labelContainer=this.canvas.id+\"-label\"}else{if(F.background){F.background=d.merge({type:\"Circles\"},F.background)}this.canvas=new n(this,F);this.config.labelContainer=(typeof F.injectInto==\"string\"?F.injectInto:F.injectInto.id)+\"-label\"}this.graphOptions={complex:true};this.graph=new f(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new E.Label[F.Label.type](this);this.fx=new E.Plot(this);this.op=new E.Op(this);this.group=new E.Group(this);this.geom=new E.Geom(this);this.clickedNode=null;this.initializeExtras()},plot:function(){this.fx.plot(this.controller)},switchPosition:function(H,G,F){var C=this.geom,D=this.fx,E=this;if(!D.busy){D.busy=true;this.contract({onComplete:function(){C.switchOrientation(H);E.compute(\"end\",false);D.busy=false;if(G==\"animate\"){E.onClick(E.clickedNode.id,F)}else{if(G==\"replot\"){E.select(E.clickedNode.id,F)}}}},H)}},switchAlignment:function(E,D,C){this.config.align=E;if(D==\"animate\"){this.select(this.clickedNode.id,C)}else{if(D==\"replot\"){this.onClick(this.clickedNode.id,C)}}},addNodeInPath:function(C){A.push(C);this.select((this.clickedNode&&this.clickedNode.id)||this.root)},clearNodesInPath:function(C){A.length=0;this.select((this.clickedNode&&this.clickedNode.id)||this.root)},refresh:function(){this.reposition();this.select((this.clickedNode&&this.clickedNode.id)||this.root)},reposition:function(){this.graph.computeLevels(this.root,0,\"ignore\");this.geom.setRightLevelToShow(this.clickedNode,this.canvas);this.graph.eachNode(function(C){if(C.exist){C.drawn=true}});this.compute(\"end\")},requestNodes:function(E,F){var D=d.merge(this.controller,F),C=this.config.levelsToShow;if(D.request){var H=[],G=E._depth;E.eachLevel(0,C,function(I){if(I.drawn&&!I.anySubnode()){H.push(I);I._level=C-(I._depth-G)}});this.group.requestNodes(H,D)}else{D.onComplete()}},contract:function(G,H){var F=this.config.orientation;var C=this.geom,E=this.group;if(H){C.switchOrientation(H)}var D=B.call(this);if(H){C.switchOrientation(F)}E.contract(D,d.merge(this.controller,G))},move:function(D,E){this.compute(\"end\",false);var C=E.Move,F={x:C.offsetX,y:C.offsetY};if(C.enable){this.geom.translate(D.endPos.add(F).$scale(-1),\"end\")}this.fx.animate(d.merge(this.controller,{modes:[\"linear\"]},E))},expand:function(D,E){var C=z.call(this,D);this.group.expand(C,d.merge(this.controller,E))},selectPath:function(F){var E=this;this.graph.eachNode(function(H){H.selected=false});function G(I){if(I==null||I.selected){return}I.selected=true;d.each(E.group.getSiblings([I])[I.id],function(J){J.exist=true;J.drawn=true});var H=I.getParents();H=(H.length>0)?H[0]:null;G(H)}for(var C=0,D=[F.id].concat(A);C<D.length;C++){G(this.graph.getNode(D[C]))}},setRoot:function(J,I,H){if(this.busy){return}this.busy=true;var G=this,E=this.canvas;var C=this.graph.getNode(this.root);var D=this.graph.getNode(J);function F(){if(this.config.multitree&&D.data.$orn){var L=D.data.$orn;var M={left:\"right\",right:\"left\",top:\"bottom\",bottom:\"top\"}[L];C.data.$orn=M;(function K(N){N.eachSubnode(function(O){if(O.id!=J){O.data.$orn=M;K(O)}})})(C);delete D.data.$orn}this.root=J;this.clickedNode=D;this.graph.computeLevels(this.root,0,\"ignore\");this.geom.setRightLevelToShow(D,E,{execHide:false,onShow:function(N){if(!N.drawn){N.drawn=true;N.setData(\"alpha\",1,\"end\");N.setData(\"alpha\",0);N.pos.setc(D.pos.x,D.pos.y)}}});this.compute(\"end\");this.busy=true;this.fx.animate({modes:[\"linear\",\"node-property:alpha\"],onComplete:function(){G.busy=false;G.onClick(J,{onComplete:function(){H&&H.onComplete()}})}})}delete C.data.$orns;if(I==\"animate\"){F.call(this);G.selectPath(D)}else{if(I==\"replot\"){F.call(this);this.select(this.root)}}},addSubtree:function(C,E,D){if(E==\"replot\"){this.op.sum(C,d.extend({type:\"replot\"},D||{}))}else{if(E==\"animate\"){this.op.sum(C,d.extend({type:\"fade:seq\"},D||{}))}}},removeSubtree:function(H,D,G,F){var E=this.graph.getNode(H),C=[];E.eachLevel(+!D,false,function(I){C.push(I.id)});if(G==\"replot\"){this.op.removeNode(C,d.extend({type:\"replot\"},F||{}))}else{if(G==\"animate\"){this.op.removeNode(C,d.extend({type:\"fade:seq\"},F||{}))}}},select:function(C,F){var K=this.group,I=this.geom;var G=this.graph.getNode(C),E=this.canvas;var J=this.graph.getNode(this.root);var D=d.merge(this.controller,F);var H=this;D.onBeforeCompute(G);this.selectPath(G);this.clickedNode=G;this.requestNodes(G,{onComplete:function(){K.hide(K.prepare(B.call(H)),D);I.setRightLevelToShow(G,E);H.compute(\"current\");H.graph.eachNode(function(N){var M=N.pos.getc(true);N.startPos.setc(M.x,M.y);N.endPos.setc(M.x,M.y);N.visited=false});var L={x:D.offsetX,y:D.offsetY};H.geom.translate(G.endPos.add(L).$scale(-1),[\"start\",\"current\",\"end\"]);K.show(z.call(H));H.plot();D.onAfterCompute(H.clickedNode);D.onComplete()}})},onClick:function(D,K){var F=this.canvas,J=this,C=this.geom,G=this.config;var I={Move:{enable:true,offsetX:G.offsetX||0,offsetY:G.offsetY||0},setRightLevelToShowConfig:false,onBeforeRequest:d.empty,onBeforeContract:d.empty,onBeforeMove:d.empty,onBeforeExpand:d.empty};var E=d.merge(this.controller,I,K);if(!this.busy){this.busy=true;var H=this.graph.getNode(D);this.selectPath(H,this.clickedNode);this.clickedNode=H;E.onBeforeCompute(H);E.onBeforeRequest(H);this.requestNodes(H,{onComplete:function(){E.onBeforeContract(H);J.contract({onComplete:function(){C.setRightLevelToShow(H,F,E.setRightLevelToShowConfig);E.onBeforeMove(H);J.move(H,{Move:E.Move,onComplete:function(){E.onBeforeExpand(H);J.expand(H,{onComplete:function(){J.busy=false;E.onAfterCompute(D);E.onComplete()}})}})}})}})}}})})();$jit.ST.$extend=true;$jit.ST.Op=new t({Implements:f.Op,initialize:function(z){this.viz=z}});$jit.ST.Group=new t({initialize:function(z){this.viz=z;this.canvas=z.canvas;this.config=z.config;this.animation=new x;this.nodes=null},requestNodes:function(E,D){var C=0,A=E.length,G={};var B=function(){D.onComplete()};var z=this.viz;if(A==0){B()}for(var F=0;F<A;F++){G[E[F].id]=E[F];D.request(E[F].id,E[F]._level,{onComplete:function(I,H){if(H&&H.children){H.id=I;z.op.sum(H,{type:\"nothing\"})}if(++C==A){z.graph.computeLevels(z.root,0);B()}}})}},contract:function(B,A){var z=this.viz;var C=this;B=this.prepare(B);this.animation.setOptions(d.merge(A,{$animating:false,compute:function(D){if(D==1){D=0.99}C.plotStep(1-D,A,this.$animating);this.$animating=\"contract\"},complete:function(){C.hide(B,A)}})).start()},hide:function(B,A){var z=this.viz;for(var C=0;C<B.length;C++){if(true||!A||!A.request){B[C].eachLevel(1,false,function(E){if(E.exist){d.extend(E,{drawn:false,exist:false})}})}else{var D=[];B[C].eachLevel(1,false,function(E){D.push(E.id)});z.op.removeNode(D,{type:\"nothing\"});z.labels.clearLabels()}}A.onComplete()},expand:function(A,z){var B=this;this.show(A);this.animation.setOptions(d.merge(z,{$animating:false,compute:function(C){B.plotStep(C,z,this.$animating);this.$animating=\"expand\"},complete:function(){B.plotStep(undefined,z,false);z.onComplete()}})).start()},show:function(z){var A=this.config;this.prepare(z);d.each(z,function(C){if(A.multitree&&!(\"$orn\" in C.data)){delete C.data.$orns;var B=\" \";C.eachSubnode(function(D){if((\"$orn\" in D.data)&&B.indexOf(D.data.$orn)<0&&D.exist&&!D.drawn){B+=D.data.$orn+\" \"}});C.data.$orns=B}C.eachLevel(0,A.levelsToShow,function(D){if(D.exist){D.drawn=true}})})},prepare:function(z){this.nodes=this.getNodesWithChildren(z);return this.nodes},getNodesWithChildren:function(B){var A=[],D=this.config,z=this.viz.root;B.sort(function(H,G){return(H._depth<=G._depth)-(H._depth>=G._depth)});for(var E=0;E<B.length;E++){if(B[E].anySubnode(\"exist\")){for(var C=E+1,F=false;!F&&C<B.length;C++){if(!D.multitree||\"$orn\" in B[C].data){F=F||B[E].isDescendantOf(B[C].id)}}if(!F){A.push(B[E])}}}return A},plotStep:function(J,F,L){var I=this.viz,C=this.config,B=I.canvas,K=B.getCtx(),z=this.nodes;var E,D;var A={};for(E=0;E<z.length;E++){D=z[E];A[D.id]=[];var H=C.multitree&&!(\"$orn\" in D.data);var G=H&&D.data.$orns;D.eachSubgraph(function(M){if(H&&G&&G.indexOf(M.data.$orn)>0&&M.drawn){M.drawn=false;A[D.id].push(M)}else{if((!H||!G)&&M.drawn){M.drawn=false;A[D.id].push(M)}}});D.drawn=true}if(z.length>0){I.fx.plot()}for(E in A){d.each(A[E],function(M){M.drawn=true})}for(E=0;E<z.length;E++){D=z[E];K.save();I.fx.plotSubtree(D,F,J,L);K.restore()}},getSiblings:function(z){var A={};d.each(z,function(D){var C=D.getParents();if(C.length==0){A[D.id]=[D]}else{var B=[];C[0].eachSubnode(function(E){B.push(E)});A[D.id]=B}});return A}});$jit.ST.Geom=new t({Implements:f.Geom,switchOrientation:function(z){this.config.orientation=z},dispatch:function(){var A=Array.prototype.slice.call(arguments);var B=A.shift(),z=A.length;var C=function(D){return typeof D==\"function\"?D():D};if(z==2){return(B==\"top\"||B==\"bottom\")?C(A[0]):C(A[1])}else{if(z==4){switch(B){case\"top\":return C(A[0]);case\"right\":return C(A[1]);case\"bottom\":return C(A[2]);case\"left\":return C(A[3])}}}return undefined},getSize:function(G,F){var E=G.data,B=this.config;var A=B.siblingOffset;var D=(B.multitree&&(\"$orn\" in E)&&E.$orn)||B.orientation;var z=G.getData(\"width\")+A;var C=G.getData(\"height\")+A;if(!F){return this.dispatch(D,C,z)}else{return this.dispatch(D,z,C)}},getTreeBaseSize:function(D,E,A){var B=this.getSize(D,true),z=0,C=this;if(A(E,D)){return B}if(E===0){return 0}D.eachSubnode(function(F){z+=C.getTreeBaseSize(F,E-1,A)});return(B>z?B:z)+this.config.subtreeOffset},getEdge:function(E,D,C){var A=function(H,G){return function(){return E.pos.add(new s(H,G))}};var F=this.node;var z=E.getData(\"width\");var B=E.getData(\"height\");if(D==\"begin\"){if(F.align==\"center\"){return this.dispatch(C,A(0,B/2),A(-z/2,0),A(0,-B/2),A(z/2,0))}else{if(F.align==\"left\"){return this.dispatch(C,A(0,B),A(0,0),A(0,0),A(z,0))}else{if(F.align==\"right\"){return this.dispatch(C,A(0,0),A(-z,0),A(0,-B),A(0,0))}else{throw\"align: not implemented\"}}}}else{if(D==\"end\"){if(F.align==\"center\"){return this.dispatch(C,A(0,-B/2),A(z/2,0),A(0,B/2),A(-z/2,0))}else{if(F.align==\"left\"){return this.dispatch(C,A(0,0),A(z,0),A(0,B),A(0,0))}else{if(F.align==\"right\"){return this.dispatch(C,A(0,-B),A(0,0),A(0,0),A(-z,0))}else{throw\"align: not implemented\"}}}}}},getScaledTreePosition:function(D,F){var E=this.node;var z=D.getData(\"width\");var C=D.getData(\"height\");var B=(this.config.multitree&&(\"$orn\" in D.data)&&D.data.$orn)||this.config.orientation;var A=function(H,G){return function(){return D.pos.add(new s(H,G)).$scale(1-F)}};if(E.align==\"left\"){return this.dispatch(B,A(0,C),A(0,0),A(0,0),A(z,0))}else{if(E.align==\"center\"){return this.dispatch(B,A(0,C/2),A(-z/2,0),A(0,-C/2),A(z/2,0))}else{if(E.align==\"right\"){return this.dispatch(B,A(0,0),A(-z,0),A(0,-C),A(0,0))}else{throw\"align: not implemented\"}}}},treeFitsInCanvas:function(E,z,F){var B=z.getSize();var C=(this.config.multitree&&(\"$orn\" in E.data)&&E.data.$orn)||this.config.orientation;var A=this.dispatch(C,B.width,B.height);var D=this.getTreeBaseSize(E,F,function(H,G){return H===0||!G.anySubnode()});return(D<A)}});$jit.ST.Plot=new t({Implements:f.Plot,initialize:function(z){this.viz=z;this.config=z.config;this.node=this.config.Node;this.edge=this.config.Edge;this.animation=new x;this.nodeTypes=new $jit.ST.Plot.NodeTypes;this.edgeTypes=new $jit.ST.Plot.EdgeTypes;this.labels=z.labels},plotSubtree:function(C,z,D,H){var F=this.viz,A=F.canvas,B=F.config;D=Math.min(Math.max(0.001,D),1);if(D>=0){C.drawn=false;var G=A.getCtx();var E=F.geom.getScaledTreePosition(C,D);G.translate(E.x,E.y);G.scale(D,D)}this.plotTree(C,d.merge(z,{withLabels:true,hideLabels:!!D,plotSubtree:function(L,J){var I=B.multitree&&!(\"$orn\" in C.data);var K=I&&C.getData(\"orns\");return !I||K.indexOf(elem.getData(\"orn\"))>-1}}),H);if(D>=0){C.drawn=true}},getAlignedPos:function(E,C,z){var B=this.node;var D,A;if(B.align==\"center\"){D={x:E.x-C/2,y:E.y-z/2}}else{if(B.align==\"left\"){A=this.config.orientation;if(A==\"bottom\"||A==\"top\"){D={x:E.x-C/2,y:E.y}}else{D={x:E.x,y:E.y-z/2}}}else{if(B.align==\"right\"){A=this.config.orientation;if(A==\"bottom\"||A==\"top\"){D={x:E.x-C/2,y:E.y-z}}else{D={x:E.x-C,y:E.y-z/2}}}else{throw\"align: not implemented\"}}}return D},getOrientation:function(z){var B=this.config;var A=B.orientation;if(B.multitree){var C=z.nodeFrom;var D=z.nodeTo;A=((\"$orn\" in C.data)&&C.data.$orn)||((\"$orn\" in D.data)&&D.data.$orn)}return A}});$jit.ST.Label={};$jit.ST.Label.Native=new t({Implements:f.Label.Native,renderLabel:function(B,C,A){var z=B.getCtx();var D=C.pos.getc(true);z.fillText(C.name,D.x,D.y)}});$jit.ST.Label.DOM=new t({Implements:f.Label.DOM,placeLabel:function(R,L,H){var D=L.pos.getc(true),Q=this.viz.config,M=Q.Node,z=this.viz.canvas,E=L.getData(\"width\"),O=L.getData(\"height\"),A=z.getSize(),I,P;var C=z.translateOffsetX,B=z.translateOffsetY,G=z.scaleOffsetX,F=z.scaleOffsetY,K=D.x*G+C,J=D.y*F+B;if(M.align==\"center\"){I={x:Math.round(K-E/2+A.width/2),y:Math.round(J-O/2+A.height/2)}}else{if(M.align==\"left\"){P=Q.orientation;if(P==\"bottom\"||P==\"top\"){I={x:Math.round(K-E/2+A.width/2),y:Math.round(J+A.height/2)}}else{I={x:Math.round(K+A.width/2),y:Math.round(J-O/2+A.height/2)}}}else{if(M.align==\"right\"){P=Q.orientation;if(P==\"bottom\"||P==\"top\"){I={x:Math.round(K-E/2+A.width/2),y:Math.round(J-O+A.height/2)}}else{I={x:Math.round(K-E+A.width/2),y:Math.round(J-O/2+A.height/2)}}}else{throw\"align: not implemented\"}}}var N=R.style;N.left=I.x+\"px\";N.top=I.y+\"px\";N.display=this.fitsInCanvas(I,z)?\"\":\"none\";H.onPlaceLabel(R,L)}});$jit.ST.Label.SVG=new t({Implements:[$jit.ST.Label.DOM,f.Label.SVG],initialize:function(z){this.viz=z}});$jit.ST.Label.HTML=new t({Implements:[$jit.ST.Label.DOM,f.Label.HTML],initialize:function(z){this.viz=z}});$jit.ST.Plot.NodeTypes=new t({none:{render:d.empty,contains:d.lambda(false)},circle:{render:function(A,z){var C=A.getData(\"dim\"),D=this.getAlignedPos(A.pos.getc(true),C,C),B=C/2;this.nodeHelper.circle.render(\"fill\",{x:D.x+B,y:D.y+B},B,z)},contains:function(z,D){var B=z.getData(\"dim\"),C=this.getAlignedPos(z.pos.getc(true),B,B),A=B/2;this.nodeHelper.circle.contains({x:C.x+A,y:C.y+A},A)}},square:{render:function(A,z){var C=A.getData(\"dim\"),B=C/2,D=this.getAlignedPos(A.pos.getc(true),C,C);this.nodeHelper.square.render(\"fill\",{x:D.x+B,y:D.y+B},B,z)},contains:function(z,D){var B=z.getData(\"dim\"),C=this.getAlignedPos(z.pos.getc(true),B,B),A=B/2;this.nodeHelper.square.contains({x:C.x+A,y:C.y+A},A)}},ellipse:{render:function(C,A){var B=C.getData(\"width\"),z=C.getData(\"height\"),D=this.getAlignedPos(C.pos.getc(true),B,z);this.nodeHelper.ellipse.render(\"fill\",{x:D.x+B/2,y:D.y+z/2},B,z,A)},contains:function(B,D){var A=B.getData(\"width\"),z=B.getData(\"height\"),C=this.getAlignedPos(B.pos.getc(true),A,z);this.nodeHelper.ellipse.contains({x:C.x+A/2,y:C.y+z/2},A,z,canvas)}},rectangle:{render:function(C,A){var B=C.getData(\"width\"),z=C.getData(\"height\"),D=this.getAlignedPos(C.pos.getc(true),B,z);this.nodeHelper.rectangle.render(\"fill\",{x:D.x+B/2,y:D.y+z/2},B,z,A)},contains:function(B,D){var A=B.getData(\"width\"),z=B.getData(\"height\"),C=this.getAlignedPos(B.pos.getc(true),A,z);this.nodeHelper.rectangle.contains({x:C.x+A/2,y:C.y+z/2},A,z,canvas)}}});$jit.ST.Plot.EdgeTypes=new t({none:d.empty,line:function(A,C){var B=this.getOrientation(A),D=A.nodeFrom,E=A.nodeTo,z=D._depth<E._depth,G=this.viz.geom.getEdge(z?D:E,\"begin\",B),F=this.viz.geom.getEdge(z?E:D,\"end\",B);this.edgeHelper.line(G,F,C)},arrow:function(F,A){var E=this.getOrientation(F),B=F.nodeFrom,z=F.nodeTo,D=F.getData(\"dim\"),H=this.viz.geom.getEdge(B,\"begin\",E),I=this.viz.geom.getEdge(z,\"end\",E),G=F.data.$direction,C=(G&&G.length>1&&G[0]!=B.id);this.edgeHelper.arrow(H,I,D,C,A)},\"quadratic:begin\":function(F,z){var E=this.getOrientation(F);var D=F.nodeFrom,G=F.nodeTo,I=D._depth<G._depth,A=this.viz.geom.getEdge(I?D:G,\"begin\",E),B=this.viz.geom.getEdge(I?G:D,\"end\",E),C=F.getData(\"dim\"),H=z.getCtx();H.beginPath();H.moveTo(A.x,A.y);switch(E){case\"left\":H.quadraticCurveTo(A.x+C,A.y,B.x,B.y);break;case\"right\":H.quadraticCurveTo(A.x-C,A.y,B.x,B.y);break;case\"top\":H.quadraticCurveTo(A.x,A.y+C,B.x,B.y);break;case\"bottom\":H.quadraticCurveTo(A.x,A.y-C,B.x,B.y);break}H.stroke()},\"quadratic:end\":function(F,z){var E=this.getOrientation(F);var D=F.nodeFrom,G=F.nodeTo,I=D._depth<G._depth,A=this.viz.geom.getEdge(I?D:G,\"begin\",E),B=this.viz.geom.getEdge(I?G:D,\"end\",E),C=F.getData(\"dim\"),H=z.getCtx();H.beginPath();H.moveTo(A.x,A.y);switch(E){case\"left\":H.quadraticCurveTo(B.x-C,B.y,B.x,B.y);break;case\"right\":H.quadraticCurveTo(B.x+C,B.y,B.x,B.y);break;case\"top\":H.quadraticCurveTo(B.x,B.y-C,B.x,B.y);break;case\"bottom\":H.quadraticCurveTo(B.x,B.y+C,B.x,B.y);break}H.stroke()},bezier:function(F,z){var E=this.getOrientation(F),D=F.nodeFrom,G=F.nodeTo,I=D._depth<G._depth,A=this.viz.geom.getEdge(I?D:G,\"begin\",E),B=this.viz.geom.getEdge(I?G:D,\"end\",E),C=F.getData(\"dim\"),H=z.getCtx();H.beginPath();H.moveTo(A.x,A.y);switch(E){case\"left\":H.bezierCurveTo(A.x+C,A.y,B.x-C,B.y,B.x,B.y);break;case\"right\":H.bezierCurveTo(A.x-C,A.y,B.x+C,B.y,B.x,B.y);break;case\"top\":H.bezierCurveTo(A.x,A.y+C,B.x,B.y-C,B.x,B.y);break;case\"bottom\":H.bezierCurveTo(A.x,A.y-C,B.x,B.y+C,B.x,B.y);break}H.stroke()}});$jit.ST.Plot.NodeTypes.implement({\"areachart-stacked\":{render:function(W,E){var U=W.pos.getc(true),z=W.getData(\"width\"),B=W.getData(\"height\"),H=this.getAlignedPos(U,z,B),ab=H.x,aa=H.y,M=W.getData(\"stringArray\"),G=W.getData(\"dimArray\"),C=W.getData(\"valueArray\"),ad=d.reduce(C,function(aj,ak){return aj+ak[0]},0),ac=d.reduce(C,function(aj,ak){return aj+ak[1]},0),J=W.getData(\"colorArray\"),D=J.length,Y=W.getData(\"config\"),K=W.getData(\"gradient\"),ai=Y.showLabels,O=Y.showAggregates,ae=Y.Label,T=W.getData(\"prev\");var N=E.getCtx(),I=W.getData(\"border\");if(J&&G&&M){for(var ah=0,af=G.length,L=0,F=0,X=0;ah<af;ah++){N.fillStyle=N.strokeStyle=J[ah%D];N.save();if(K&&(G[ah][0]>0||G[ah][1]>0)){var R=L+G[ah][0],P=F+G[ah][1],ag=Math.atan((P-R)/z),Z=55;var V=N.createLinearGradient(ab+z/2,aa-(R+P)/2,ab+z/2+Z*Math.sin(ag),aa-(R+P)/2+Z*Math.cos(ag));var Q=d.rgbToHex(d.map(d.hexToRgb(J[ah%D].slice(1)),function(aj){return(aj*0.85)>>0}));V.addColorStop(0,J[ah%D]);V.addColorStop(1,Q);N.fillStyle=V}N.beginPath();N.moveTo(ab,aa-L);N.lineTo(ab+z,aa-F);N.lineTo(ab+z,aa-F-G[ah][1]);N.lineTo(ab,aa-L-G[ah][0]);N.lineTo(ab,aa-L);N.fill();N.restore();if(I){var S=I.name==M[ah];var A=S?0.7:0.8;var Q=d.rgbToHex(d.map(d.hexToRgb(J[ah%D].slice(1)),function(aj){return(aj*A)>>0}));N.strokeStyle=Q;N.lineWidth=S?4:1;N.save();N.beginPath();if(I.index===0){N.moveTo(ab,aa-L);N.lineTo(ab,aa-L-G[ah][0])}else{N.moveTo(ab+z,aa-F);N.lineTo(ab+z,aa-F-G[ah][1])}N.stroke();N.restore()}L+=(G[ah][0]||0);F+=(G[ah][1]||0);if(G[ah][0]>0){X+=(C[ah][0]||0)}}if(T&&ae.type==\"Native\"){N.save();N.beginPath();N.fillStyle=N.strokeStyle=ae.color;N.font=ae.style+\" \"+ae.size+\"px \"+ae.family;N.textAlign=\"center\";N.textBaseline=\"middle\";if(O(W.name,ad,ac,W)){N.fillText(X,ab,aa-L-Y.labelOffset-ae.size/2,z)}if(ai(W.name,ad,ac,W)){N.fillText(W.name,ab,aa+ae.size/2+Y.labelOffset)}N.restore()}}},contains:function(D,F){var K=D.pos.getc(true),A=D.getData(\"width\"),O=D.getData(\"height\"),N=this.getAlignedPos(K,A,O),M=N.x,L=N.y,P=D.getData(\"dimArray\"),z=F.x-M;if(F.x<M||F.x>M+A||F.y>L||F.y<L-O){return false}for(var G=0,E=P.length,J=L,B=L;G<E;G++){var C=P[G];J-=C[0];B-=C[1];var H=J+(B-J)*z/A;if(F.y>=H){var I=+(z>A/2);return{name:D.getData(\"stringArray\")[G],color:D.getData(\"colorArray\")[G],value:D.getData(\"valueArray\")[G][I],index:I}}}return false}}});$jit.AreaChart=new t({st:null,colors:[\"#416D9C\",\"#70A35E\",\"#EBB056\",\"#C74243\",\"#83548B\",\"#909291\",\"#557EAA\"],selected:{},busy:false,initialize:function(B){this.controller=this.config=d.merge(p(\"Canvas\",\"Label\",\"AreaChart\"),{Label:{type:\"Native\"}},B);var C=this.config.showLabels,A=d.type(C),D=this.config.showAggregates,z=d.type(D);this.config.showLabels=A==\"function\"?C:d.lambda(C);this.config.showAggregates=z==\"function\"?D:d.lambda(D);this.initializeViz()},initializeViz:function(){var B=this.config,E=this,z=B.type.split(\":\")[0],D={};var A=new $jit.ST({injectInto:B.injectInto,orientation:\"bottom\",levelDistance:0,siblingOffset:0,subtreeOffset:0,withLabels:B.Label.type!=\"Native\",useCanvas:B.useCanvas,Label:{type:B.Label.type},Node:{overridable:true,type:\"areachart-\"+z,align:\"left\",width:1,height:1},Edge:{type:\"none\"},Tips:{enable:B.Tips.enable,type:\"Native\",force:true,onShow:function(I,H,F){var G=F;B.Tips.onShow(I,G,H)}},Events:{enable:true,type:\"Native\",onClick:function(H,I,F){if(!B.filterOnClick&&!B.Events.enable){return}var G=I.getContains();if(G){B.filterOnClick&&E.filter(G.name)}B.Events.enable&&B.Events.onClick(G,I,F)},onRightClick:function(G,H,F){if(!B.restoreOnRightClick){return}E.restore()},onMouseMove:function(H,I,F){if(!B.selectOnHover){return}if(H){var G=I.getContains();E.select(H.id,G.name,G.index)}else{E.select(false,false,false)}}},onCreateLabel:function(L,I){var R=B.Label,Q=I.getData(\"valueArray\"),J=d.reduce(Q,function(S,T){return S+T[0]},0),O=d.reduce(Q,function(S,T){return S+T[1]},0);if(I.getData(\"prev\")){var N={wrapper:document.createElement(\"div\"),aggregate:document.createElement(\"div\"),label:document.createElement(\"div\")};var F=N.wrapper,P=N.label,G=N.aggregate,H=F.style,M=P.style,K=G.style;D[I.id]=N;F.appendChild(P);F.appendChild(G);if(!B.showLabels(I.name,J,O,I)){P.style.display=\"none\"}if(!B.showAggregates(I.name,J,O,I)){G.style.display=\"none\"}H.position=\"relative\";H.overflow=\"visible\";H.fontSize=R.size+\"px\";H.fontFamily=R.family;H.color=R.color;H.textAlign=\"center\";K.position=M.position=\"absolute\";L.style.width=I.getData(\"width\")+\"px\";L.style.height=I.getData(\"height\")+\"px\";P.innerHTML=I.name;L.appendChild(F)}},onPlaceLabel:function(W,Q){if(!Q.getData(\"prev\")){return}var U=D[Q.id],G=U.wrapper.style,F=U.label.style,P=U.aggregate.style,N=Q.getData(\"width\"),L=Q.getData(\"height\"),K=Q.getData(\"dimArray\"),H=Q.getData(\"valueArray\"),M=d.reduce(H,function(X,Y){return X+Y[0]},0),I=d.reduce(H,function(X,Y){return X+Y[1]},0),J=parseInt(G.fontSize,10),O=W.style;if(K&&H){if(B.showLabels(Q.name,M,I,Q)){F.display=\"\"}else{F.display=\"none\"}if(B.showAggregates(Q.name,M,I,Q)){P.display=\"\"}else{P.display=\"none\"}G.width=P.width=F.width=W.style.width=N+\"px\";P.left=F.left=-N/2+\"px\";for(var T=0,R=H.length,S=0,V=0;T<R;T++){if(K[T][0]>0){S+=H[T][0];V+=K[T][0]}}P.top=(-J-B.labelOffset)+\"px\";F.top=(B.labelOffset+V)+\"px\";W.style.top=parseInt(W.style.top,10)-V+\"px\";W.style.height=G.height=V+\"px\";U.aggregate.innerHTML=S}}});var C=A.canvas.getSize();A.config.offsetY=-C.height/2+B.offset+(B.showLabels&&(B.labelOffset+B.Label.size));this.st=A;this.canvas=this.st.canvas},loadJSON:function(Q){var N=d.time(),E=[],J=this.st,T=d.splat(Q.label),M=d.splat(Q.color||this.colors),R=this.config,A=!!R.type.split(\":\")[1],C=R.animate;for(var O=0,B=Q.values,L=B.length;O<L-1;O++){var S=B[O],H=B[O-1],I=B[O+1];var P=d.splat(B[O].values),z=d.splat(B[O+1].values);var D=d.zip(P,z);var G=0,F=0;E.push({id:N+S.label,name:S.label,data:{value:D,\"$valueArray\":D,\"$colorArray\":M,\"$stringArray\":T,\"$next\":I.label,\"$prev\":H?H.label:null,\"$config\":R,\"$gradient\":A},children:[]})}var K={id:N+\"$root\",name:\"\",data:{\"$type\":\"none\",\"$width\":1,\"$height\":1},children:E};J.loadJSON(K);this.normalizeDims();J.compute();J.select(J.root);if(C){J.fx.animate({modes:[\"node-property:height:dimArray\"],duration:1500})}},updateJSON:function(C,F){if(this.busy){return}this.busy=true;var B=this.st,E=B.graph,G=C.label&&d.splat(C.label),A=C.values,z=this.config.animate,D=this;d.each(A,function(H){var M=E.getByName(H.label);if(M){H.values=d.splat(H.values);var I=M.getData(\"stringArray\"),L=M.getData(\"valueArray\");d.each(L,function(N,O){N[0]=H.values[O];if(G){I[O]=G[O]}});M.setData(\"valueArray\",L);var J=M.getData(\"prev\");if(J){var K=E.getByName(J);var L=K.getData(\"valueArray\");d.each(L,function(N,O){N[1]=H.values[O]});K.setData(\"valueArray\",L)}}});this.normalizeDims();B.compute();B.select(B.root);if(z){B.fx.animate({modes:[\"node-property:height:dimArray\"],duration:1500,onComplete:function(){D.busy=false;F&&F.onComplete()}})}},filter:function(){if(this.busy){return}this.busy=true;if(this.config.Tips.enable){this.st.tips.hide()}this.select(false,false,false);var A=Array.prototype.slice.call(arguments);var z=this.st.graph.getNode(this.st.root);var B=this;z.eachAdjacency(function(C){var F=C.nodeTo,E=F.getData(\"dimArray\"),D=F.getData(\"stringArray\");F.setData(\"dimArray\",d.map(E,function(H,G){return(d.indexOf(A,D[G])>-1)?H:[0,0]}),\"end\")});this.st.fx.animate({modes:[\"node-property:dimArray\"],duration:1500,onComplete:function(){B.busy=false}})},restore:function(){if(this.busy){return}this.busy=true;if(this.config.Tips.enable){this.st.tips.hide()}this.select(false,false,false);this.normalizeDims();var z=this;this.st.fx.animate({modes:[\"node-property:height:dimArray\"],duration:1500,onComplete:function(){z.busy=false}})},select:function(E,A,z){if(!this.config.selectOnHover){return}var B=this.selected;if(B.id!=E||B.name!=A||B.index!=z){B.id=E;B.name=A;B.index=z;this.st.graph.eachNode(function(F){F.setData(\"border\",false)});if(E){var D=this.st.graph.getNode(E);D.setData(\"border\",B);var C=z===0?\"prev\":\"next\";C=D.getData(C);if(C){D=this.st.graph.getByName(C);if(D){D.setData(\"border\",{name:A,index:1-z})}}}this.st.plot()}},getLegend:function(){var B={};var C;this.st.graph.getNode(this.st.root).eachAdjacency(function(D){C=D.nodeTo});var A=C.getData(\"colorArray\"),z=A.length;d.each(C.getData(\"stringArray\"),function(E,D){B[E]=A[D%z]});return B},getMaxValue:function(){var z=0;this.st.graph.eachNode(function(E){var B=E.getData(\"valueArray\"),A=0,D=0;d.each(B,function(F){A+=+F[0];D+=+F[1]});var C=D>A?D:A;z=z>C?z:C});return z},normalizeDims:function(){var F=this.st.graph.getNode(this.st.root),C=0;F.eachAdjacency(function(){C++});var E=this.getMaxValue(),I=this.st.canvas.getSize(),B=this.config,D=B.offset,G=B.labelOffset+B.Label.size,z=(I.width-2*D)/C,A=B.animate,H=I.height-2*D-(B.showAggregates&&G)-(B.showLabels&&G);this.st.graph.eachNode(function(O){var L=0,N=0,J=[];d.each(O.getData(\"valueArray\"),function(P){L+=+P[0];N+=+P[1];J.push([0,0])});var M=N>L?N:L;O.setData(\"width\",z);if(A){O.setData(\"height\",M*H/E,\"end\");O.setData(\"dimArray\",d.map(O.getData(\"valueArray\"),function(P){return[P[0]*H/E,P[1]*H/E]}),\"end\");var K=O.getData(\"dimArray\");if(!K){O.setData(\"dimArray\",J)}}else{O.setData(\"height\",M*H/E);O.setData(\"dimArray\",d.map(O.getData(\"valueArray\"),function(P){return[P[0]*H/E,P[1]*H/E]}))}})}});i.Radial=new t({compute:function(A){var B=d.splat(A||[\"current\",\"start\",\"end\"]);h.compute(this.graph,B,this.config);this.graph.computeLevels(this.root,0,\"ignore\");var z=this.createLevelDistanceFunc();this.computeAngularWidths(B);this.computePositions(B,z)},computePositions:function(G,D){var I=G;var H=this.graph;var E=H.getNode(this.root);var F=this.parent;var z=this.config;for(var B=0,A=I.length;B<A;B++){var C=I[B];E.setPos(m(0,0),C);E.setData(\"span\",Math.PI*2,C)}E.angleSpan={begin:0,end:2*Math.PI};H.eachBFS(this.root,function(N){var T=N.angleSpan.end-N.angleSpan.begin;var V=N.angleSpan.begin;var U=D(N);var W=0,J=[],M={};N.eachSubnode(function(Z){W+=Z._treeAngularWidth;for(var aa=0,Y=I.length;aa<Y;aa++){var ac=I[aa],ab=Z.getData(\"dim\",ac);M[ac]=(ac in M)?(ab>M[ac]?ab:M[ac]):ab}J.push(Z)},\"ignore\");if(F&&F.id==N.id&&J.length>0&&J[0].dist){J.sort(function(Z,Y){return(Z.dist>=Y.dist)-(Z.dist<=Y.dist)})}for(var P=0,R=J.length;P<R;P++){var L=J[P];if(!L._flag){var X=L._treeAngularWidth/W*T;var K=V+X/2;for(var Q=0,O=I.length;Q<O;Q++){var S=I[Q];L.setPos(m(K,U),S);L.setData(\"span\",X,S);L.setData(\"dim-quotient\",L.getData(\"dim\",S)/M[S],S)}L.angleSpan={begin:V,end:V+X};V+=X}}},\"ignore\")},setAngularWidthForNodes:function(z){this.graph.eachBFS(this.root,function(C,A){var B=C.getData(\"angularWidth\",z[0])||5;C._angularWidth=B/A},\"ignore\")},setSubtreesAngularWidth:function(){var z=this;this.graph.eachNode(function(A){z.setSubtreeAngularWidth(A)},\"ignore\")},setSubtreeAngularWidth:function(C){var B=this,A=C._angularWidth,z=0;C.eachSubnode(function(D){B.setSubtreeAngularWidth(D);z+=D._treeAngularWidth},\"ignore\");C._treeAngularWidth=Math.max(A,z)},computeAngularWidths:function(z){this.setAngularWidthForNodes(z);this.setSubtreesAngularWidth()}});s.prototype.moebiusTransformation=function(B){var z=this.add(B);var A=B.$conjugate().$prod(this);A.x++;return z.$div(A)};f.Util.moebiusTransformation=function(B,D,C,A,z){this.eachNode(B,function(F){for(var E=0;E<C.length;E++){var H=D[E].scale(-1),G=A?A:C[E];F.getPos(C[E]).set(F.getPos(G).getc().moebiusTransformation(H))}},z)};$jit.Hypertree=new t({Implements:[e,q,i.Radial],initialize:function(z){var C=$jit.Hypertree;var A={radius:\"auto\",offset:0,Edge:{type:\"hyperline\"},duration:1500,fps:35};this.controller=this.config=d.merge(p(\"Canvas\",\"Node\",\"Edge\",\"Fx\",\"Tips\",\"NodeStyles\",\"Events\",\"Navigation\",\"Controller\",\"Label\"),A,z);var B=this.config;if(B.useCanvas){this.canvas=B.useCanvas;this.config.labelContainer=this.canvas.id+\"-label\"}else{if(B.background){B.background=d.merge({type:\"Circles\"},B.background)}this.canvas=new n(this,B);this.config.labelContainer=(typeof B.injectInto==\"string\"?B.injectInto:B.injectInto.id)+\"-label\"}this.graphOptions={complex:false,Node:{selected:false,exist:true,drawn:true}};this.graph=new f(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new C.Label[B.Label.type](this);this.fx=new C.Plot(this);this.op=new C.Op(this);this.json=null;this.root=null;this.busy=false;this.initializeExtras()},createLevelDistanceFunc:function(){var D=this.getRadius();var F=0,z=Math.max,A=this.config;this.graph.eachNode(function(G){F=z(G._depth,F)},\"ignore\");F++;var E=function(G){return function(I){I.scale=D;var K=I._depth+1;var J=0,H=Math.pow;while(K){J+=H(G,K--)}return J-A.offset}};for(var C=0.51;C<=1;C+=0.01){var B=(1-Math.pow(C,F))/(1-C);if(B>=2){return E(C-0.01)}}return E(0.75)},getRadius:function(){var z=this.config.radius;if(z!==\"auto\"){return z}var A=this.canvas.getSize();return Math.min(A.width,A.height)/2},refresh:function(z){if(z){this.reposition();this.graph.eachNode(function(A){A.startPos.rho=A.pos.rho=A.endPos.rho;A.startPos.theta=A.pos.theta=A.endPos.theta})}else{this.compute()}this.plot()},reposition:function(){this.compute(\"end\");var z=this.graph.getNode(this.root).pos.getc().scale(-1);f.Util.moebiusTransformation(this.graph,[z],[\"end\"],\"end\",\"ignore\");this.graph.eachNode(function(A){if(A.ignore){A.endPos.rho=A.pos.rho;A.endPos.theta=A.pos.theta}})},plot:function(){this.fx.plot()},onClick:function(B,z){var A=this.graph.getNode(B).pos.getc(true);this.move(A,z)},move:function(D,B){var A=u(D.x,D.y);if(this.busy===false&&A.norm()<1){this.busy=true;var z=this.graph.getClosestNodeToPos(A),C=this;this.graph.computeLevels(z.id,0);this.controller.onBeforeCompute(z);B=d.merge({onComplete:d.empty},B||{});this.fx.animate(d.merge({modes:[\"moebius\"],hideLabels:true},B,{onComplete:function(){C.busy=false;B.onComplete()}}),A)}}});$jit.Hypertree.$extend=true;(function(z){z.Op=new t({Implements:f.Op,initialize:function(A){this.viz=A}});z.Plot=new t({Implements:f.Plot,initialize:function(A){this.viz=A;this.config=A.config;this.node=this.config.Node;this.edge=this.config.Edge;this.animation=new x;this.nodeTypes=new z.Plot.NodeTypes;this.edgeTypes=new z.Plot.EdgeTypes;this.labels=A.labels}});z.Label={};z.Label.Native=new t({Implements:f.Label.Native,initialize:function(A){this.viz=A},renderLabel:function(C,E,B){var A=C.getCtx();var F=E.pos.getc(true);var D=this.viz.getRadius();A.fillText(E.name,F.x*D,F.y*D)}});z.Label.SVG=new t({Implements:f.Label.SVG,initialize:function(A){this.viz=A},placeLabel:function(L,F,G){var J=F.pos.getc(true),C=this.viz.canvas,D=C.translateOffsetX,B=C.translateOffsetY,K=C.scaleOffsetX,I=C.scaleOffsetY,H=C.getSize(),A=this.viz.getRadius();var E={x:Math.round((J.x*K)*A+D+H.width/2),y:Math.round((J.y*I)*A+B+H.height/2)};L.setAttribute(\"x\",E.x);L.setAttribute(\"y\",E.y);G.onPlaceLabel(L,F)}});z.Label.HTML=new t({Implements:f.Label.HTML,initialize:function(A){this.viz=A},placeLabel:function(M,G,H){var K=G.pos.getc(true),D=this.viz.canvas,E=D.translateOffsetX,C=D.translateOffsetY,L=D.scaleOffsetX,J=D.scaleOffsetY,I=D.getSize(),A=this.viz.getRadius();var F={x:Math.round((K.x*L)*A+E+I.width/2),y:Math.round((K.y*J)*A+C+I.height/2)};var B=M.style;B.left=F.x+\"px\";B.top=F.y+\"px\";B.display=this.fitsInCanvas(F,D)?\"\":\"none\";H.onPlaceLabel(M,G)}});z.Plot.NodeTypes=new t({none:{render:d.empty,contains:d.lambda(false)},circle:{render:function(C,A){var B=this.node,E=C.getData(\"dim\"),D=C.pos.getc();E=B.transform?E*(1-D.squaredNorm()):E;D.$scale(C.scale);if(E>0.2){this.nodeHelper.circle.render(\"fill\",D,E,A)}},contains:function(A,D){var B=A.getData(\"dim\"),C=A.pos.getc().$scale(A.scale);return this.nodeHelper.circle.contains(C,D,B)}},ellipse:{render:function(D,B){var E=D.pos.getc().$scale(D.scale),C=D.getData(\"width\"),A=D.getData(\"height\");this.nodeHelper.ellipse.render(\"fill\",E,C,A,B)},contains:function(C,E){var B=C.getData(\"width\"),A=C.getData(\"height\"),D=C.pos.getc().$scale(C.scale);return this.nodeHelper.circle.contains(D,E,B,A)}},square:{render:function(C,A){var B=this.node,E=C.getData(\"dim\"),D=C.pos.getc();E=B.transform?E*(1-D.squaredNorm()):E;D.$scale(C.scale);if(E>0.2){this.nodeHelper.square.render(\"fill\",D,E,A)}},contains:function(A,D){var B=A.getData(\"dim\"),C=A.pos.getc().$scale(A.scale);return this.nodeHelper.square.contains(C,D,B)}},rectangle:{render:function(E,B){var D=this.node,C=E.getData(\"width\"),A=E.getData(\"height\"),F=E.pos.getc();C=D.transform?C*(1-F.squaredNorm()):C;A=D.transform?A*(1-F.squaredNorm()):A;F.$scale(E.scale);if(C>0.2&&A>0.2){this.nodeHelper.rectangle.render(\"fill\",F,C,A,B)}},contains:function(C,E){var B=C.getData(\"width\"),A=C.getData(\"height\"),D=C.pos.getc().$scale(C.scale);return this.nodeHelper.square.contains(D,E,B,A)}},triangle:{render:function(C,A){var B=this.node,E=C.getData(\"dim\"),D=C.pos.getc();E=B.transform?E*(1-D.squaredNorm()):E;D.$scale(C.scale);if(E>0.2){this.nodeHelper.triangle.render(\"fill\",D,E,A)}},contains:function(A,D){var B=A.getData(\"dim\"),C=A.pos.getc().$scale(A.scale);return this.nodeHelper.triangle.contains(C,D,B)}},star:{render:function(C,A){var B=this.node,E=C.getData(\"dim\"),D=C.pos.getc();E=B.transform?E*(1-D.squaredNorm()):E;D.$scale(C.scale);if(E>0.2){this.nodeHelper.star.render(\"fill\",D,E,A)}},contains:function(A,D){var B=A.getData(\"dim\"),C=A.pos.getc().$scale(A.scale);return this.nodeHelper.star.contains(C,D,B)}}});z.Plot.EdgeTypes=new t({none:d.empty,line:function(A,B){var E=A.nodeFrom.pos.getc(true),D=A.nodeTo.pos.getc(true),C=A.nodeFrom.scale;this.edgeHelper.line({x:E.x*C,y:E.y*C},{x:D.x*C,y:D.y*C},B)},arrow:function(B,C){var H=B.nodeFrom.pos.getc(true),G=B.nodeTo.pos.getc(true),D=B.nodeFrom.scale,F=B.getData(\"dim\"),E=B.data.$direction,A=(E&&E.length>1&&E[0]!=B.nodeFrom.id);this.edgeHelper.arrow({x:H.x*D,y:H.y*D},{x:G.x*D,y:G.y*D},F,A,C)},hyperline:function(A,B){var E=A.nodeFrom.pos.getc(),D=A.nodeTo.pos.getc(),C=this.viz.getRadius();this.edgeHelper.hyperline(E,D,C,B)}})})($jit.Hypertree);i.TM={};i.TM.SliceAndDice=new t({compute:function(E){var A=this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root);this.controller.onBeforeCompute(A);var C=this.canvas.getSize(),B=this.config,D=C.width,z=C.height;this.graph.computeLevels(this.root,0,\"ignore\");A.getPos(E).setc(-D/2,-z/2);A.setData(\"width\",D,E);A.setData(\"height\",z+B.titleHeight,E);this.computePositions(A,A,this.layout.orientation,E);this.controller.onAfterCompute(A)},computePositions:function(I,G,S,B){var P=0;I.eachSubnode(function(U){P+=U.getData(\"area\",B)});var T=this.config,Q=T.offset,M=I.getData(\"width\",B),K=I.getData(\"height\",B)-T.titleHeight,A=I==G?1:(G.getData(\"area\",B)/P);var L,J,O,E,D,H,F;var R=(S==\"h\");if(R){S=\"v\";L=K;J=M*A;O=\"height\";E=\"y\";D=\"x\";H=T.titleHeight;F=0}else{S=\"h\";L=K*A;J=M;O=\"width\";E=\"x\";D=\"y\";H=0;F=T.titleHeight}var z=G.getPos(B);G.setData(\"width\",J,B);G.setData(\"height\",L,B);var N=0,C=this;G.eachSubnode(function(V){var U=V.getPos(B);U[E]=N+z[E]+H;U[D]=z[D]+F;C.computePositions(G,V,S,B);N+=V.getData(O,B)})}});i.TM.Area={compute:function(z){z=z||\"current\";var F=this.graph.getNode(this.clickedNode&&this.clickedNode.id||this.root);this.controller.onBeforeCompute(F);var B=this.config,I=this.canvas.getSize(),A=I.width,H=I.height,G=B.offset,C=A-G,E=H-G;this.graph.computeLevels(this.root,0,\"ignore\");F.getPos(z).setc(-A/2,-H/2);F.setData(\"width\",A,z);F.setData(\"height\",H,z);var D={top:-H/2+B.titleHeight,left:-A/2,width:C,height:E-B.titleHeight};this.computePositions(F,D,z);this.controller.onAfterCompute(F)},computeDim:function(D,E,G,C,B,z){if(D.length+E.length==1){var A=(D.length==1)?D:E;this.layoutLast(A,G,C,z);return}if(D.length>=2&&E.length==0){E=[D.shift()]}if(D.length==0){if(E.length>0){this.layoutRow(E,G,C,z)}return}var F=D[0];if(B(E,G)>=B([F].concat(E),G)){this.computeDim(D.slice(1),E.concat([F]),G,C,B,z)}else{var H=this.layoutRow(E,G,C,z);this.computeDim(D,[],H.dim,H,B,z)}},worstAspectRatio:function(z,H){if(!z||z.length==0){return Number.MAX_VALUE}var A=0,I=0,D=Number.MAX_VALUE;for(var F=0,E=z.length;F<E;F++){var B=z[F]._area;A+=B;D=D<B?D:B;I=I>B?I:B}var G=H*H,C=A*A;return Math.max(G*I/C,C/(G*D))},avgAspectRatio:function(D,A){if(!D||D.length==0){return Number.MAX_VALUE}var F=0;for(var B=0,z=D.length;B<z;B++){var E=D[B]._area;var C=E/A;F+=A>C?A/C:C/A}return F/z},layoutLast:function(A,z,D,C){var B=A[0];B.getPos(C).setc(D.left,D.top);B.setData(\"width\",D.width,C);B.setData(\"height\",D.height,C)}};i.TM.Squarified=new t({Implements:i.TM.Area,computePositions:function(D,G,A){var C=this.config;if(!(G.width>=G.height&&this.layout.horizontal())){this.layout.change()}var z=D.getSubnodes([1,1],\"ignore\");if(z.length>0){this.processChildrenLayout(D,z,G,A);for(var F=0,E=z.length;F<E;F++){var I=z[F];var J=C.offset,K=I.getData(\"height\",A)-J-C.titleHeight,B=I.getData(\"width\",A)-J;var H=I.getPos(A);G={width:B,height:K,top:H.y+C.titleHeight,left:H.x};this.computePositions(I,G,A)}}},processChildrenLayout:function(J,z,F,A){var D=F.width*F.height;var E,B=z.length,G=0,K=[];for(E=0;E<B;E++){K[E]=parseFloat(z[E].getData(\"area\",A));G+=K[E]}for(E=0;E<B;E++){z[E]._area=D*K[E]/G}var C=this.layout.horizontal()?F.height:F.width;z.sort(function(M,L){return(M._area<=L._area)-(M._area>=L._area)});var I=[z[0]];var H=z.slice(1);this.squarify(H,I,C,F,A)},squarify:function(A,D,z,C,B){this.computeDim(A,D,z,C,this.worstAspectRatio,B)},layoutRow:function(A,z,C,B){if(this.layout.horizontal()){return this.layoutV(A,z,C,B)}else{return this.layoutH(A,z,C,B)}},layoutV:function(z,K,G,A){var L=0,C=function(M){return M};d.each(z,function(M){L+=M._area});var B=C(L/K),H=0;for(var E=0,D=z.length;E<D;E++){var F=C(z[E]._area/B);var I=z[E];I.getPos(A).setc(G.left,G.top+H);I.setData(\"width\",B,A);I.setData(\"height\",F,A);H+=F}var J={height:G.height,width:G.width-B,top:G.top,left:G.left+B};J.dim=Math.min(J.width,J.height);if(J.dim!=J.height){this.layout.change()}return J},layoutH:function(z,I,E,A){var K=0;d.each(z,function(L){K+=L._area});var J=K/I,F=E.top,B=0;for(var D=0,C=z.length;D<C;D++){var G=z[D];var I=G._area/J;G.getPos(A).setc(E.left+B,F);G.setData(\"width\",I,A);G.setData(\"height\",J,A);B+=I}var H={height:E.height-J,width:E.width,top:E.top+J,left:E.left};H.dim=Math.min(H.width,H.height);if(H.dim!=H.width){this.layout.change()}return H}});i.TM.Strip=new t({Implements:i.TM.Area,computePositions:function(D,G,A){var z=D.getSubnodes([1,1],\"ignore\"),C=this.config;if(z.length>0){this.processChildrenLayout(D,z,G,A);for(var F=0,E=z.length;F<E;F++){var I=z[F];var J=C.offset,K=I.getData(\"height\",A)-J-C.titleHeight,B=I.getData(\"width\",A)-J;var H=I.getPos(A);G={width:B,height:K,top:H.y+C.titleHeight,left:H.x};this.computePositions(I,G,A)}}},processChildrenLayout:function(J,z,E,A){var C=E.width*E.height;var D,B=z.length,F=0,K=[];for(D=0;D<B;D++){K[D]=+z[D].getData(\"area\",A);F+=K[D]}for(D=0;D<B;D++){z[D]._area=C*K[D]/F}var I=this.layout.horizontal()?E.width:E.height;var H=[z[0]];var G=z.slice(1);this.stripify(G,H,I,E,A)},stripify:function(A,D,z,C,B){this.computeDim(A,D,z,C,this.avgAspectRatio,B)},layoutRow:function(A,z,C,B){if(this.layout.horizontal()){return this.layoutH(A,z,C,B)}else{return this.layoutV(A,z,C,B)}},layoutV:function(z,I,F,A){var J=0;d.each(z,function(K){J+=K._area});var B=J/I,G=0;for(var D=0,C=z.length;D<C;D++){var H=z[D];var E=H._area/B;H.getPos(A).setc(F.left,F.top+(I-E-G));H.setData(\"width\",B,A);H.setData(\"height\",E,A);G+=E}return{height:F.height,width:F.width-B,top:F.top,left:F.left+B,dim:I}},layoutH:function(z,H,E,A){var J=0;d.each(z,function(L){J+=L._area});var I=J/H,F=E.height-I,B=0;for(var D=0,C=z.length;D<C;D++){var G=z[D];var K=G._area/I;G.getPos(A).setc(E.left+B,E.top+F);G.setData(\"width\",K,A);G.setData(\"height\",I,A);B+=K}return{height:E.height-I,width:E.width,top:E.top,left:E.left,dim:H}}});i.Icicle=new t({compute:function(H){H=H||\"current\";var G=this.graph.getNode(this.root),C=this.config,K=this.canvas.getSize(),z=K.width,J=K.height,D=C.offset,F=C.constrained?C.levelsToShow:Number.MAX_VALUE;this.controller.onBeforeCompute(G);f.Util.computeLevels(this.graph,G.id,0,\"ignore\");var I=0;f.Util.eachLevel(G,0,false,function(M,L){if(L>I){I=L}});var B=this.graph.getNode(this.clickedNode&&this.clickedNode.id||G.id);var A=Math.min(I,F-1);var E=B._depth;if(this.layout.horizontal()){this.computeSubtree(B,-z/2,-J/2,z/(A+1),J,E,A,H)}else{this.computeSubtree(B,-z/2,-J/2,z,J/(A+1),E,A,H)}},computeSubtree:function(H,J,G,z,M,F,B,I){H.getPos(I).setc(J,G);H.setData(\"width\",z,I);H.setData(\"height\",M,I);var D,L=0,K=0;var A=f.Util.getSubnodes(H,[1,1]);if(!A.length){return}d.each(A,function(N){K+=N.getData(\"dim\")});for(var E=0,C=A.length;E<C;E++){if(this.layout.horizontal()){D=M*A[E].getData(\"dim\")/K;this.computeSubtree(A[E],J+z,G,z,D,F,B,I);G+=D}else{D=z*A[E].getData(\"dim\")/K;this.computeSubtree(A[E],J,G+M,D,M,F,B,I);J+=D}}}});$jit.Icicle=new t({Implements:[e,q,i.Icicle],layout:{orientation:\"h\",vertical:function(){return this.orientation==\"v\"},horizontal:function(){return this.orientation==\"h\"},change:function(){this.orientation=this.vertical()?\"h\":\"v\"}},initialize:function(z){var A={animate:false,orientation:\"h\",offset:2,levelsToShow:Number.MAX_VALUE,constrained:false,Node:{type:\"rectangle\",overridable:true},Edge:{type:\"none\"},Label:{type:\"Native\"},duration:700,fps:45};var C=p(\"Canvas\",\"Node\",\"Edge\",\"Fx\",\"Tips\",\"NodeStyles\",\"Events\",\"Navigation\",\"Controller\",\"Label\");this.controller=this.config=d.merge(C,A,z);this.layout.orientation=this.config.orientation;var B=this.config;if(B.useCanvas){this.canvas=B.useCanvas;this.config.labelContainer=this.canvas.id+\"-label\"}else{this.canvas=new n(this,B);this.config.labelContainer=(typeof B.injectInto==\"string\"?B.injectInto:B.injectInto.id)+\"-label\"}this.graphOptions={complex:true,Node:{selected:false,exist:true,drawn:true}};this.graph=new f(this.graphOptions,this.config.Node,this.config.Edge,this.config.Label);this.labels=new $jit.Icicle.Label[this.config.Label.type](this);this.fx=new $jit.Icicle.Plot(this);this.op=new $jit.Icicle.Op(this);this.group=new $jit.Icicle.Group(this);this.clickedNode=null;this.initializeExtras()},refresh:function(){var z=this.config.Label.type;if(z!=\"Native\"){var A=this;this.graph.eachNode(function(B){A.labels.hideLabel(B,false)})}this.compute();this.plot()},plot:function(){this.fx.plot(this.config)},enter:function(B){if(this.busy){return}this.busy=true;var A=this,z=this.config;var C={onComplete:function(){if(z.request){A.compute()}if(z.animate){A.graph.nodeList.setDataset([\"current\",\"end\"],{alpha:[1,0]});f.Util.eachSubgraph(B,function(D){D.setData(\"alpha\",1,\"end\")},\"ignore\");A.fx.animate({duration:500,modes:[\"node-property:alpha\"],onComplete:function(){A.clickedNode=B;A.compute(\"end\");A.fx.animate({modes:[\"linear\",\"node-property:width:height\"],duration:1000,onComplete:function(){A.busy=false;A.clickedNode=B}})}})}else{A.clickedNode=B;A.busy=false;A.refresh()}}};if(z.request){this.requestNodes(clickedNode,C)}else{C.onComplete()}},out:function(){if(this.busy){return}var E=this,D=f.Util,B=this.config,G=this.graph,A=D.getParents(G.getNode(this.clickedNode&&this.clickedNode.id||this.root)),C=A[0],z=C,F=this.clickedNode;this.busy=true;this.events.hoveredNode=false;if(!C){this.busy=false;return}callback={onComplete:function(){E.clickedNode=C;if(B.request){E.requestNodes(C,{onComplete:function(){E.compute();E.plot();E.busy=false}})}else{E.compute();E.plot();E.busy=false}}};if(B.animate){this.clickedNode=z;this.compute(\"end\");this.clickedNode=F;this.fx.animate({modes:[\"linear\",\"node-property:width:height\"],duration:1000,onComplete:function(){E.clickedNode=z;G.nodeList.setDataset([\"current\",\"end\"],{alpha:[0,1]});D.eachSubgraph(F,function(H){H.setData(\"alpha\",1)},\"ignore\");E.fx.animate({duration:500,modes:[\"node-property:alpha\"],onComplete:function(){callback.onComplete()}})}})}else{callback.onComplete()}},requestNodes:function(B,C){var A=d.merge(this.controller,C),z=this.config.constrained?this.config.levelsToShow:Number.MAX_VALUE;if(A.request){var E=[],D=B._depth;f.Util.eachLevel(B,0,z,function(F){if(F.drawn&&!f.Util.anySubnode(F)){E.push(F);F._level=F._depth-D;if(this.config.constrained){F._level=z-F._level}}});this.group.requestNodes(E,A)}else{A.onComplete()}}});$jit.Icicle.Op=new t({Implements:f.Op,initialize:function(z){this.viz=z}});$jit.Icicle.Group=new t({initialize:function(z){this.viz=z;this.canvas=z.canvas;this.config=z.config},requestNodes:function(E,D){var C=0,A=E.length,G={};var B=function(){D.onComplete()};var z=this.viz;if(A==0){B()}for(var F=0;F<A;F++){G[E[F].id]=E[F];D.request(E[F].id,E[F]._level,{onComplete:function(I,H){if(H&&H.children){H.id=I;z.op.sum(H,{type:\"nothing\"})}if(++C==A){f.Util.computeLevels(z.graph,z.root,0);B()}}})}}});$jit.Icicle.Plot=new t({Implements:f.Plot,initialize:function(z){this.viz=z;this.config=z.config;this.node=this.config.Node;this.edge=this.config.Edge;this.animation=new x;this.nodeTypes=new $jit.Icicle.Plot.NodeTypes;this.edgeTypes=new $jit.Icicle.Plot.EdgeTypes;this.labels=z.labels},plot:function(D,B){D=D||this.viz.controller;var z=this.viz,E=z.graph,A=E.getNode(z.clickedNode&&z.clickedNode.id||z.root),C=A._depth;z.canvas.clear();this.plotTree(A,d.merge(D,{withLabels:true,hideLabels:false,plotSubtree:function(F,G){return !z.config.constrained||(G._depth-C<z.config.levelsToShow)}}),B)}});$jit.Icicle.Label={};$jit.Icicle.Label.Native=new t({Implements:f.Label.Native,renderLabel:function(A,B,D){var G=A.getCtx(),z=B.getData(\"width\"),F=B.getData(\"height\"),H=B.getLabelData(\"size\"),C=G.measureText(B.name);if(F<(H*1.5)||z<C.width){return}var E=B.pos.getc(true);G.fillText(B.name,E.x+z/2,E.y+F/2)}});$jit.Icicle.Label.SVG=new t({Implements:f.Label.SVG,initialize:function(z){this.viz=z},placeLabel:function(A,D,B){var F=D.pos.getc(true),C=this.viz.canvas;var z=C.getSize();var E={x:Math.round(F.x+z.width/2),y:Math.round(F.y+z.height/2)};A.setAttribute(\"x\",E.x);A.setAttribute(\"y\",E.y);B.onPlaceLabel(A,D)}});$jit.Icicle.Label.HTML=new t({Implements:f.Label.HTML,initialize:function(z){this.viz=z},placeLabel:function(A,E,B){var G=E.pos.getc(true),C=this.viz.canvas;var z=C.getSize();var F={x:Math.round(G.x+z.width/2),y:Math.round(G.y+z.height/2)};var D=A.style;D.left=F.x+\"px\";D.top=F.y+\"px\";D.display=\"\";B.onPlaceLabel(A,E)}});$jit.Icicle.Plot.NodeTypes=new t({none:{render:d.empty},rectangle:{render:function(C,A,N){var B=this.viz.config;var F=B.offset;var z=C.getData(\"width\");var K=C.getData(\"height\");var E=C.getData(\"border\");var J=C.pos.getc(true);var I=J.x+F/2,G=J.y+F/2;var M=A.getCtx();if(z-F<2||K-F<2){return}if(B.cushion){var D=C.getData(\"color\");var L=M.createRadialGradient(I+(z-F)/2,G+(K-F)/2,1,I+(z-F)/2,G+(K-F)/2,z<K?K:z);var H=d.rgbToHex(d.map(d.hexToRgb(D),function(O){return O*0.3>>0}));L.addColorStop(0,D);L.addColorStop(1,H);M.fillStyle=L}if(E){M.strokeStyle=E;M.lineWidth=3}M.fillRect(I,G,Math.max(0,z-F),Math.max(0,K-F));E&&M.strokeRect(J.x,J.y,z,K)},contains:function(B,D){if(this.viz.clickedNode&&!$jit.Graph.Util.isDescendantOf(B,this.viz.clickedNode.id)){return false}var C=B.pos.getc(true),A=B.getData(\"width\"),z=B.getData(\"height\");return this.nodeHelper.rectangle.contains({x:C.x+A/2,y:C.y+z/2},D,A,z)}}});$jit.Icicle.Plot.EdgeTypes=new t({none:d.empty});$jit.RGraph=new t({Implements:[e,q,i.Radial],initialize:function(z){var A=$jit.RGraph;var B={interpolation:\"linear\",levelDistance:100};this.controller=this.config=d.merge(p(\"Canvas\",\"Node\",\"Edge\",\"Fx\",\"Controller\",\"Tips\",\"NodeStyles\",\"Events\",\"Navigation\",\"Label\"),B,z);var C=this.config;if(C.useCanvas){this.canvas=C.useCanvas;this.config.labelContainer=this.canvas.id+\"-label\"}else{if(C.background){C.background=d.merge({type:\"Circles\"},C.background)}this.canvas=new n(this,C);this.config.labelContainer=(typeof C.injectInto==\"string\"?C.injectInto:C.injectInto.id)+\"-label\"}this.graphOptions={complex:false,Node:{selected:false,exist:true,drawn:true}};this.graph=new f(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new A.Label[C.Label.type](this);this.fx=new A.Plot(this);this.op=new A.Op(this);this.json=null;this.root=null;this.busy=false;this.parent=false;this.initializeExtras()},createLevelDistanceFunc:function(){var z=this.config.levelDistance;return function(A){return(A._depth+1)*z}},refresh:function(){this.compute();this.plot()},reposition:function(){this.compute(\"end\")},plot:function(){this.fx.plot()},getNodeAndParentAngle:function(G){var B=false;var F=this.graph.getNode(G);var D=F.getParents();var C=(D.length>0)?D[0]:false;if(C){var z=C.pos.getc(),E=F.pos.getc();var A=z.add(E.scale(-1));B=Math.atan2(A.y,A.x);if(B<0){B+=2*Math.PI}}return{parent:C,theta:B}},tagChildren:function(D,F){if(D.angleSpan){var E=[];D.eachAdjacency(function(G){E.push(G.nodeTo)},\"ignore\");var z=E.length;for(var C=0;C<z&&F!=E[C].id;C++){}for(var B=(C+1)%z,A=0;F!=E[B].id;B=(B+1)%z){E[B].dist=A++}}},onClick:function(D,A){if(this.root!=D&&!this.busy){this.busy=true;this.root=D;that=this;this.controller.onBeforeCompute(this.graph.getNode(D));var B=this.getNodeAndParentAngle(D);this.tagChildren(B.parent,D);this.parent=B.parent;this.compute(\"end\");var z=B.theta-B.parent.endPos.theta;this.graph.eachNode(function(E){E.endPos.set(E.endPos.getp().add(m(z,0)))});var C=this.config.interpolation;A=d.merge({onComplete:d.empty},A||{});this.fx.animate(d.merge({hideLabels:true,modes:[C]},A,{onComplete:function(){that.busy=false;A.onComplete()}}))}}});$jit.RGraph.$extend=true;(function(z){z.Op=new t({Implements:f.Op,initialize:function(A){this.viz=A}});z.Plot=new t({Implements:f.Plot,initialize:function(A){this.viz=A;this.config=A.config;this.node=A.config.Node;this.edge=A.config.Edge;this.animation=new x;this.nodeTypes=new z.Plot.NodeTypes;this.edgeTypes=new z.Plot.EdgeTypes;this.labels=A.labels}});z.Label={};z.Label.Native=new t({Implements:f.Label.Native});z.Label.SVG=new t({Implements:f.Label.SVG,initialize:function(A){this.viz=A},placeLabel:function(K,E,F){var I=E.pos.getc(true),B=this.viz.canvas,C=B.translateOffsetX,A=B.translateOffsetY,J=B.scaleOffsetX,H=B.scaleOffsetY,G=B.getSize();var D={x:Math.round(I.x*J+C+G.width/2),y:Math.round(I.y*H+A+G.height/2)};K.setAttribute(\"x\",D.x);K.setAttribute(\"y\",D.y);F.onPlaceLabel(K,E)}});z.Label.HTML=new t({Implements:f.Label.HTML,initialize:function(A){this.viz=A},placeLabel:function(L,F,G){var J=F.pos.getc(true),C=this.viz.canvas,D=C.translateOffsetX,B=C.translateOffsetY,K=C.scaleOffsetX,I=C.scaleOffsetY,H=C.getSize();var E={x:Math.round(J.x*K+D+H.width/2),y:Math.round(J.y*I+B+H.height/2)};var A=L.style;A.left=E.x+\"px\";A.top=E.y+\"px\";A.display=this.fitsInCanvas(E,C)?\"\":\"none\";G.onPlaceLabel(L,F)}});z.Plot.NodeTypes=new t({none:{render:d.empty,contains:d.lambda(false)},circle:{render:function(B,A){var D=B.pos.getc(true),C=B.getData(\"dim\");this.nodeHelper.circle.render(\"fill\",D,C,A)},contains:function(A,D){var C=A.pos.getc(true),B=A.getData(\"dim\");return this.nodeHelper.circle.contains(C,D,B)}},ellipse:{render:function(D,B){var E=D.pos.getc(true),C=D.getData(\"width\"),A=D.getData(\"height\");this.nodeHelper.ellipse.render(\"fill\",E,C,A,B)},contains:function(C,E){var D=C.pos.getc(true),B=C.getData(\"width\"),A=C.getData(\"height\");return this.nodeHelper.ellipse.contains(D,E,B,A)}},square:{render:function(B,A){var D=B.pos.getc(true),C=B.getData(\"dim\");this.nodeHelper.square.render(\"fill\",D,C,A)},contains:function(A,D){var C=A.pos.getc(true),B=A.getData(\"dim\");return this.nodeHelper.square.contains(C,D,B)}},rectangle:{render:function(D,B){var E=D.pos.getc(true),C=D.getData(\"width\"),A=D.getData(\"height\");this.nodeHelper.rectangle.render(\"fill\",E,C,A,B)},contains:function(C,E){var D=C.pos.getc(true),B=C.getData(\"width\"),A=C.getData(\"height\");return this.nodeHelper.rectangle.contains(D,E,B,A)}},triangle:{render:function(B,A){var D=B.pos.getc(true),C=B.getData(\"dim\");this.nodeHelper.triangle.render(\"fill\",D,C,A)},contains:function(A,D){var C=A.pos.getc(true),B=A.getData(\"dim\");return this.nodeHelper.triangle.contains(C,D,B)}},star:{render:function(B,A){var D=B.pos.getc(true),C=B.getData(\"dim\");this.nodeHelper.star.render(\"fill\",D,C,A)},contains:function(A,D){var C=A.pos.getc(true),B=A.getData(\"dim\");return this.nodeHelper.star.contains(C,D,B)}}});z.Plot.EdgeTypes=new t({none:d.empty,line:function(A,B){var D=A.nodeFrom.pos.getc(true),C=A.nodeTo.pos.getc(true);this.edgeHelper.line(D,C,B)},arrow:function(B,C){var G=B.nodeFrom.pos.getc(true),F=B.nodeTo.pos.getc(true),E=B.getData(\"dim\"),D=B.data.$direction,A=(D&&D.length>1&&D[0]!=B.nodeFrom.id);this.edgeHelper.arrow(G,F,E,A,C)}})})($jit.RGraph);i.ForceDirected=new t({getOptions:function(F){var D=this.canvas.getSize();var A=D.width,C=D.height;var E=0;this.graph.eachNode(function(H){E++});var G=A*C/E,B=Math.sqrt(G);var z=this.config.levelDistance;return{width:A,height:C,tstart:A*0.1,nodef:function(H){return G/(H||1)},edgef:function(H){return B*(H-z)}}},compute:function(A,B){var C=d.splat(A||[\"current\",\"start\",\"end\"]);var z=this.getOptions();h.compute(this.graph,C,this.config);this.graph.computeLevels(this.root,0,\"ignore\");this.graph.eachNode(function(D){d.each(C,function(E){var F=D.getPos(E);if(F.equals(s.KER)){F.x=z.width/5*(Math.random()-0.5);F.y=z.height/5*(Math.random()-0.5)}D.disp={};d.each(C,function(G){D.disp[G]=u(0,0)})})});this.computePositions(C,z,B)},computePositions:function(D,B,E){var F=this.config.iterations,A=0,C=this;if(E){(function z(){for(var H=E.iter,G=0;G<H;G++){B.t=B.tstart*(1-A++/(F-1));C.computePositionStep(D,B);if(A>=F){E.onComplete();return}}E.onStep(Math.round(A/(F-1)*100));setTimeout(z,1)})()}else{for(;A<F;A++){B.t=B.tstart*(1-A/(F-1));this.computePositionStep(D,B)}}},computePositionStep:function(G,z){var H=this.graph;var B=Math.min,F=Math.max;var E=u(0,0);H.eachNode(function(J){d.each(G,function(K){J.disp[K].x=0;J.disp[K].y=0});H.eachNode(function(K){if(K.id!=J.id){d.each(G,function(O){var M=J.getPos(O),L=K.getPos(O);E.x=M.x-L.x;E.y=M.y-L.y;var N=E.norm()||1;J.disp[O].$add(E.$scale(z.nodef(N)/N))})}})});var A=!!H.getNode(this.root).visited;H.eachNode(function(J){J.eachAdjacency(function(K){var L=K.nodeTo;if(!!L.visited===A){d.each(G,function(P){var N=J.getPos(P),M=L.getPos(P);E.x=N.x-M.x;E.y=N.y-M.y;var O=E.norm()||1;J.disp[P].$add(E.$scale(-z.edgef(O)/O));L.disp[P].$add(E.$scale(-1))})}});J.visited=!A});var I=z.t,C=z.width/2,D=z.height/2;H.eachNode(function(J){d.each(G,function(M){var K=J.disp[M];var L=K.norm()||1;var M=J.getPos(M);M.$add(u(K.x*B(Math.abs(K.x),I)/L,K.y*B(Math.abs(K.y),I)/L));M.x=B(C,F(-C,M.x));M.y=B(D,F(-D,M.y))})})}});$jit.ForceDirected=new t({Implements:[e,q,i.ForceDirected],initialize:function(A){var z=$jit.ForceDirected;var B={iterations:50,levelDistance:50};this.controller=this.config=d.merge(p(\"Canvas\",\"Node\",\"Edge\",\"Fx\",\"Tips\",\"NodeStyles\",\"Events\",\"Navigation\",\"Controller\",\"Label\"),B,A);var C=this.config;if(C.useCanvas){this.canvas=C.useCanvas;this.config.labelContainer=this.canvas.id+\"-label\"}else{if(C.background){C.background=d.merge({type:\"Circles\"},C.background)}this.canvas=new n(this,C);this.config.labelContainer=(typeof C.injectInto==\"string\"?C.injectInto:C.injectInto.id)+\"-label\"}this.graphOptions={complex:true,Node:{selected:false,exist:true,drawn:true}};this.graph=new f(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new z.Label[C.Label.type](this);this.fx=new z.Plot(this);this.op=new z.Op(this);this.json=null;this.busy=false;this.initializeExtras()},refresh:function(){this.compute();this.plot()},reposition:function(){this.compute(\"end\")},computeIncremental:function(z){z=d.merge({iter:20,property:\"end\",onStep:d.empty,onComplete:d.empty},z||{});this.config.onBeforeCompute(this.graph.getNode(this.root));this.compute(z.property,z)},plot:function(){this.fx.plot()},animate:function(z){this.fx.animate(d.merge({modes:[\"linear\"]},z||{}))}});$jit.ForceDirected.$extend=true;(function(z){z.Op=new t({Implements:f.Op,initialize:function(A){this.viz=A}});z.Plot=new t({Implements:f.Plot,initialize:function(A){this.viz=A;this.config=A.config;this.node=A.config.Node;this.edge=A.config.Edge;this.animation=new x;this.nodeTypes=new z.Plot.NodeTypes;this.edgeTypes=new z.Plot.EdgeTypes;this.labels=A.labels}});z.Label={};z.Label.Native=new t({Implements:f.Label.Native});z.Label.SVG=new t({Implements:f.Label.SVG,initialize:function(A){this.viz=A},placeLabel:function(K,E,F){var I=E.pos.getc(true),B=this.viz.canvas,C=B.translateOffsetX,A=B.translateOffsetY,J=B.scaleOffsetX,H=B.scaleOffsetY,G=B.getSize();var D={x:Math.round(I.x*J+C+G.width/2),y:Math.round(I.y*H+A+G.height/2)};K.setAttribute(\"x\",D.x);K.setAttribute(\"y\",D.y);F.onPlaceLabel(K,E)}});z.Label.HTML=new t({Implements:f.Label.HTML,initialize:function(A){this.viz=A},placeLabel:function(L,F,G){var J=F.pos.getc(true),C=this.viz.canvas,D=C.translateOffsetX,B=C.translateOffsetY,K=C.scaleOffsetX,I=C.scaleOffsetY,H=C.getSize();var E={x:Math.round(J.x*K+D+H.width/2),y:Math.round(J.y*I+B+H.height/2)};var A=L.style;A.left=E.x+\"px\";A.top=E.y+\"px\";A.display=this.fitsInCanvas(E,C)?\"\":\"none\";G.onPlaceLabel(L,F)}});z.Plot.NodeTypes=new t({none:{render:d.empty,contains:d.lambda(false)},circle:{render:function(B,A){var D=B.pos.getc(true),C=B.getData(\"dim\");this.nodeHelper.circle.render(\"fill\",D,C,A)},contains:function(A,D){var C=A.pos.getc(true),B=A.getData(\"dim\");return this.nodeHelper.circle.contains(C,D,B)}},ellipse:{render:function(D,B){var E=D.pos.getc(true),C=D.getData(\"width\"),A=D.getData(\"height\");this.nodeHelper.ellipse.render(\"fill\",E,C,A,B)},contains:function(C,E){var D=C.pos.getc(true),B=C.getData(\"width\"),A=C.getData(\"height\");return this.nodeHelper.ellipse.contains(D,E,B,A)}},square:{render:function(B,A){var D=B.pos.getc(true),C=B.getData(\"dim\");this.nodeHelper.square.render(\"fill\",D,C,A)},contains:function(A,D){var C=A.pos.getc(true),B=A.getData(\"dim\");return this.nodeHelper.square.contains(C,D,B)}},rectangle:{render:function(D,B){var E=D.pos.getc(true),C=D.getData(\"width\"),A=D.getData(\"height\");this.nodeHelper.rectangle.render(\"fill\",E,C,A,B)},contains:function(C,E){var D=C.pos.getc(true),B=C.getData(\"width\"),A=C.getData(\"height\");return this.nodeHelper.rectangle.contains(D,E,B,A)}},triangle:{render:function(B,A){var D=B.pos.getc(true),C=B.getData(\"dim\");this.nodeHelper.triangle.render(\"fill\",D,C,A)},contains:function(A,D){var C=A.pos.getc(true),B=A.getData(\"dim\");return this.nodeHelper.triangle.contains(C,D,B)}},star:{render:function(B,A){var D=B.pos.getc(true),C=B.getData(\"dim\");this.nodeHelper.star.render(\"fill\",D,C,A)},contains:function(A,D){var C=A.pos.getc(true),B=A.getData(\"dim\");return this.nodeHelper.star.contains(C,D,B)}}});z.Plot.EdgeTypes=new t({none:d.empty,line:function(A,B){var D=A.nodeFrom.pos.getc(true),C=A.nodeTo.pos.getc(true);this.edgeHelper.line(D,C,B)},arrow:function(B,C){var G=B.nodeFrom.pos.getc(true),F=B.nodeTo.pos.getc(true),E=B.getData(\"dim\"),D=B.data.$direction,A=(D&&D.length>1&&D[0]!=B.nodeFrom.id);this.edgeHelper.arrow(G,F,E,A,C)}})})($jit.ForceDirected);$jit.TM={};var y=$jit.TM;$jit.TM.$extend=true;y.Base={layout:{orientation:\"h\",vertical:function(){return this.orientation==\"v\"},horizontal:function(){return this.orientation==\"h\"},change:function(){this.orientation=this.vertical()?\"h\":\"v\"}},initialize:function(z){var A={orientation:\"h\",titleHeight:13,offset:2,levelsToShow:3,constrained:false,animate:false,Node:{type:\"rectangle\",overridable:true,width:3,height:3,color:\"#444\"},Label:{textAlign:\"center\",textBaseline:\"top\"},Edge:{type:\"none\"},duration:700,fps:45};this.controller=this.config=d.merge(p(\"Canvas\",\"Node\",\"Edge\",\"Fx\",\"Controller\",\"Tips\",\"NodeStyles\",\"Events\",\"Navigation\",\"Label\"),A,z);this.layout.orientation=this.config.orientation;var B=this.config;if(B.useCanvas){this.canvas=B.useCanvas;this.config.labelContainer=this.canvas.id+\"-label\"}else{if(B.background){B.background=d.merge({type:\"Circles\"},B.background)}this.canvas=new n(this,B);this.config.labelContainer=(typeof B.injectInto==\"string\"?B.injectInto:B.injectInto.id)+\"-label\"}this.graphOptions={complex:true,Node:{selected:false,exist:true,drawn:true}};this.graph=new f(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new y.Label[B.Label.type](this);this.fx=new y.Plot(this);this.op=new y.Op(this);this.group=new y.Group(this);this.geom=new y.Geom(this);this.clickedNode=null;this.busy=false;this.initializeExtras()},refresh:function(){if(this.busy){return}this.busy=true;var A=this;if(this.config.animate){this.compute(\"end\");this.geom.setRightLevelToShow(this.graph.getNode(this.root));this.fx.animate(d.merge(this.config,{modes:[\"linear\",\"node-property:width:height\"],onComplete:function(){A.busy=false}}))}else{var z=this.config.Label.type;if(z!=\"Native\"){var A=this;this.graph.eachNode(function(B){A.labels.hideLabel(B,false)})}this.busy=false;this.compute();this.plot()}},plot:function(){this.fx.plot()},leaf:function(z){return z.getSubnodes([1,1],\"ignore\").length==0},enter:function(F){if(this.busy){return}this.busy=true;var B=this,A=this.config,D=this.graph,z=F,C=this.clickedNode;var E={onComplete:function(){if(A.levelsToShow>0){B.geom.setRightLevelToShow(F)}if(A.request){B.compute()}if(A.animate){D.nodeList.setDataset([\"current\",\"end\"],{alpha:[1,0]});F.eachSubgraph(function(G){G.setData(\"alpha\",1,\"end\")},\"ignore\");B.fx.animate({duration:500,modes:[\"node-property:alpha\"],onComplete:function(){B.clickedNode=z;B.compute(\"end\");B.clickedNode=C;B.fx.animate({modes:[\"linear\",\"node-property:width:height\"],duration:1000,onComplete:function(){B.busy=false;B.clickedNode=z}})}})}else{B.busy=false;B.clickedNode=F;B.refresh()}}};if(A.request){this.requestNodes(z,E)}else{E.onComplete()}},out:function(){if(this.busy){return}this.busy=true;this.events.hoveredNode=false;var D=this,B=this.config,F=this.graph,A=F.getNode(this.clickedNode&&this.clickedNode.id||this.root).getParents(),C=A[0],z=C,E=this.clickedNode;if(!C){this.busy=false;return}callback={onComplete:function(){D.clickedNode=C;if(B.request){D.requestNodes(C,{onComplete:function(){D.compute();D.plot();D.busy=false}})}else{D.compute();D.plot();D.busy=false}}};if(B.levelsToShow>0){this.geom.setRightLevelToShow(C)}if(B.animate){this.clickedNode=z;this.compute(\"end\");this.clickedNode=E;this.fx.animate({modes:[\"linear\",\"node-property:width:height\"],duration:1000,onComplete:function(){D.clickedNode=z;F.nodeList.setDataset([\"current\",\"end\"],{alpha:[0,1]});E.eachSubgraph(function(G){G.setData(\"alpha\",1)},\"ignore\");D.fx.animate({duration:500,modes:[\"node-property:alpha\"],onComplete:function(){callback.onComplete()}})}})}else{callback.onComplete()}},requestNodes:function(B,C){var A=d.merge(this.controller,C),z=this.config.levelsToShow;if(A.request){var E=[],D=B._depth;B.eachLevel(0,z,function(G){var F=z-(G._depth-D);if(G.drawn&&!G.anySubnode()&&F>0){E.push(G);G._level=F}});this.group.requestNodes(E,A)}else{A.onComplete()}}};y.Op=new t({Implements:f.Op,initialize:function(z){this.viz=z}});y.Geom=new t({Implements:f.Geom,getRightLevelToShow:function(){return this.viz.config.levelsToShow},setRightLevelToShow:function(A){var B=this.getRightLevelToShow(),z=this.viz.labels;A.eachLevel(0,B+1,function(D){var C=D._depth-A._depth;if(C>B){D.drawn=false;D.exist=false;D.ignore=true;z.hideLabel(D,false)}else{D.drawn=true;D.exist=true;delete D.ignore}});A.drawn=true;delete A.ignore}});y.Group=new t({initialize:function(z){this.viz=z;this.canvas=z.canvas;this.config=z.config},requestNodes:function(E,D){var C=0,A=E.length,G={};var B=function(){D.onComplete()};var z=this.viz;if(A==0){B()}for(var F=0;F<A;F++){G[E[F].id]=E[F];D.request(E[F].id,E[F]._level,{onComplete:function(I,H){if(H&&H.children){H.id=I;z.op.sum(H,{type:\"nothing\"})}if(++C==A){z.graph.computeLevels(z.root,0);B()}}})}}});y.Plot=new t({Implements:f.Plot,initialize:function(z){this.viz=z;this.config=z.config;this.node=this.config.Node;this.edge=this.config.Edge;this.animation=new x;this.nodeTypes=new y.Plot.NodeTypes;this.edgeTypes=new y.Plot.EdgeTypes;this.labels=z.labels},plot:function(B,A){var z=this.viz,C=z.graph;z.canvas.clear();this.plotTree(C.getNode(z.clickedNode&&z.clickedNode.id||z.root),d.merge(z.config,B||{},{withLabels:true,hideLabels:false,plotSubtree:function(E,D){return E.anySubnode(\"exist\")}}),A)}});y.Label={};y.Label.Native=new t({Implements:f.Label.Native,initialize:function(z){this.config=z.config;this.leaf=z.leaf},renderLabel:function(A,B,C){if(!this.leaf(B)&&!this.config.titleHeight){return}var E=B.pos.getc(true),H=A.getCtx(),z=B.getData(\"width\"),G=B.getData(\"height\"),F=E.x+z/2,D=E.y;H.fillText(B.name,F,D,z)}});y.Label.SVG=new t({Implements:f.Label.SVG,initialize:function(z){this.viz=z;this.leaf=z.leaf;this.config=z.config},placeLabel:function(J,D,E){var H=D.pos.getc(true),A=this.viz.canvas,B=A.translateOffsetX,z=A.translateOffsetY,I=A.scaleOffsetX,G=A.scaleOffsetY,F=A.getSize();var C={x:Math.round(H.x*I+B+F.width/2),y:Math.round(H.y*G+z+F.height/2)};J.setAttribute(\"x\",C.x);J.setAttribute(\"y\",C.y);if(!this.leaf(D)&&!this.config.titleHeight){J.style.display=\"none\"}E.onPlaceLabel(J,D)}});y.Label.HTML=new t({Implements:f.Label.HTML,initialize:function(z){this.viz=z;this.leaf=z.leaf;this.config=z.config},placeLabel:function(K,E,F){var I=E.pos.getc(true),B=this.viz.canvas,C=B.translateOffsetX,A=B.translateOffsetY,J=B.scaleOffsetX,H=B.scaleOffsetY,G=B.getSize();var D={x:Math.round(I.x*J+C+G.width/2),y:Math.round(I.y*H+A+G.height/2)};var z=K.style;z.left=D.x+\"px\";z.top=D.y+\"px\";z.width=E.getData(\"width\")*J+\"px\";z.height=E.getData(\"height\")*H+\"px\";z.zIndex=E._depth*100;z.display=\"\";if(!this.leaf(E)&&!this.config.titleHeight){K.style.display=\"none\"}F.onPlaceLabel(K,E)}});y.Plot.NodeTypes=new t({none:{render:d.empty},rectangle:{render:function(C,A,P){var G=this.viz.leaf(C),B=this.config,L=B.offset,F=B.titleHeight,K=C.pos.getc(true),z=C.getData(\"width\"),M=C.getData(\"height\"),E=C.getData(\"border\"),O=A.getCtx(),J=K.x+L/2,H=K.y+L/2;if(z<=L||M<=L){return}if(G){if(B.cushion){var N=O.createRadialGradient(J+(z-L)/2,H+(M-L)/2,1,J+(z-L)/2,H+(M-L)/2,z<M?M:z);var D=C.getData(\"color\");var I=d.rgbToHex(d.map(d.hexToRgb(D),function(Q){return Q*0.2>>0}));N.addColorStop(0,D);N.addColorStop(1,I);O.fillStyle=N}O.fillRect(J,H,z-L,M-L);if(E){O.save();O.strokeStyle=E;O.strokeRect(J,H,z-L,M-L);O.restore()}}else{if(F>0){O.fillRect(K.x+L/2,K.y+L/2,z-L,F-L);if(E){O.save();O.strokeStyle=E;O.strokeRect(K.x+L/2,K.y+L/2,z-L,M-L);O.restore()}}}},contains:function(C,E){if(this.viz.clickedNode&&!C.isDescendantOf(this.viz.clickedNode.id)){return false}var D=C.pos.getc(true),B=C.getData(\"width\"),A=this.viz.leaf(C),z=A?C.getData(\"height\"):this.config.titleHeight;return this.nodeHelper.rectangle.contains({x:D.x+B/2,y:D.y+z/2},E,B,z)}}});y.Plot.EdgeTypes=new t({none:d.empty});y.SliceAndDice=new t({Implements:[e,q,y.Base,i.TM.SliceAndDice]});y.Squarified=new t({Implements:[e,q,y.Base,i.TM.Squarified]});y.Strip=new t({Implements:[e,q,y.Base,i.TM.Strip]});p.BarChart={$extend:true,animate:true,type:\"stacked\",offset:25,labelOffset:3,barsOffset:0,hoveredColor:\"#9fd4ff\",orientation:\"horizontal\",showAggregates:true,showLabels:true,Tips:{enable:false,onShow:d.empty,onHide:d.empty},Events:{enable:false,onClick:d.empty}};$jit.ST.Plot.NodeTypes.implement({\"barchart-stacked\":{render:function(R,D){var I=R.pos.getc(true),Q=R.getData(\"width\"),O=R.getData(\"height\"),M=this.getAlignedPos(I,Q,O),L=M.x,K=M.y,N=R.getData(\"dimArray\"),G=R.getData(\"valueArray\"),F=R.getData(\"colorArray\"),C=F.length,Y=R.getData(\"stringArray\");var T=D.getCtx(),z={},U=R.getData(\"border\"),A=R.getData(\"gradient\"),aa=R.getData(\"config\"),B=aa.orientation==\"horizontal\",E=aa.showAggregates,P=aa.showLabels,J=aa.Label;if(F&&N&&Y){for(var X=0,S=N.length,W=0,H=0;X<S;X++){T.fillStyle=T.strokeStyle=F[X%C];if(A){var Z;if(B){Z=T.createLinearGradient(L+W+N[X]/2,K,L+W+N[X]/2,K+O)}else{Z=T.createLinearGradient(L,K-W-N[X]/2,L+Q,K-W-N[X]/2)}var V=d.rgbToHex(d.map(d.hexToRgb(F[X%C].slice(1)),function(ab){return(ab*0.5)>>0}));Z.addColorStop(0,V);Z.addColorStop(0.5,F[X%C]);Z.addColorStop(1,V);T.fillStyle=Z}if(B){T.fillRect(L+W,K,N[X],O)}else{T.fillRect(L,K-W-N[X],Q,N[X])}if(U&&U.name==Y[X]){z.acum=W;z.dimValue=N[X]}W+=(N[X]||0);H+=(G[X]||0)}if(U){T.save();T.lineWidth=2;T.strokeStyle=U.color;if(B){T.strokeRect(L+z.acum+1,K+1,z.dimValue-2,O-2)}else{T.strokeRect(L+1,K-z.acum-z.dimValue+1,Q-2,z.dimValue-2)}T.restore()}if(J.type==\"Native\"){T.save();T.fillStyle=T.strokeStyle=J.color;T.font=J.style+\" \"+J.size+\"px \"+J.family;T.textBaseline=\"middle\";if(E(R.name,H)){if(B){T.textAlign=\"right\";T.fillText(H,L+W-aa.labelOffset,K+O/2)}else{T.textAlign=\"center\";T.fillText(H,L+Q/2,K-O-J.size/2-aa.labelOffset)}}if(P(R.name,H,R)){if(B){T.textAlign=\"center\";T.translate(L-aa.labelOffset-J.size/2,K+O/2);T.rotate(Math.PI/2);T.fillText(R.name,0,0)}else{T.textAlign=\"center\";T.fillText(R.name,L+Q/2,K+J.size/2+aa.labelOffset)}}T.restore()}}},contains:function(E,G){var J=E.pos.getc(true),B=E.getData(\"width\"),O=E.getData(\"height\"),N=this.getAlignedPos(J,B,O),M=N.x,K=N.y,P=E.getData(\"dimArray\"),C=E.getData(\"config\"),A=G.x-M,z=C.orientation==\"horizontal\";if(z){if(G.x<M||G.x>M+B||G.y>K+O||G.y<K){return false}}else{if(G.x<M||G.x>M+B||G.y>K||G.y<K-O){return false}}for(var H=0,F=P.length,L=(z?M:K);H<F;H++){var D=P[H];if(z){L+=D;var I=L;if(G.x<=I){return{name:E.getData(\"stringArray\")[H],color:E.getData(\"colorArray\")[H],value:E.getData(\"valueArray\")[H]}}}else{L-=D;var I=L;if(G.y>=I){return{name:E.getData(\"stringArray\")[H],color:E.getData(\"colorArray\")[H],value:E.getData(\"valueArray\")[H]}}}}return false}},\"barchart-grouped\":{render:function(S,D){var J=S.pos.getc(true),R=S.getData(\"width\"),P=S.getData(\"height\"),N=this.getAlignedPos(J,R,P),M=N.x,L=N.y,O=S.getData(\"dimArray\"),H=S.getData(\"valueArray\"),Y=H.length,G=S.getData(\"colorArray\"),C=G.length,aa=S.getData(\"stringArray\");var U=D.getCtx(),z={},V=S.getData(\"border\"),A=S.getData(\"gradient\"),ac=S.getData(\"config\"),B=ac.orientation==\"horizontal\",F=ac.showAggregates,Q=ac.showLabels,K=ac.Label,E=(B?P:R)/Y;if(G&&O&&aa){for(var Z=0,T=Y,X=0,I=0;Z<T;Z++){U.fillStyle=U.strokeStyle=G[Z%C];if(A){var ab;if(B){ab=U.createLinearGradient(M+O[Z]/2,L+E*Z,M+O[Z]/2,L+E*(Z+1))}else{ab=U.createLinearGradient(M+E*Z,L-O[Z]/2,M+E*(Z+1),L-O[Z]/2)}var W=d.rgbToHex(d.map(d.hexToRgb(G[Z%C].slice(1)),function(ad){return(ad*0.5)>>0}));ab.addColorStop(0,W);ab.addColorStop(0.5,G[Z%C]);ab.addColorStop(1,W);U.fillStyle=ab}if(B){U.fillRect(M,L+E*Z,O[Z],E)}else{U.fillRect(M+E*Z,L-O[Z],E,O[Z])}if(V&&V.name==aa[Z]){z.acum=E*Z;z.dimValue=O[Z]}X+=(O[Z]||0);I+=(H[Z]||0)}if(V){U.save();U.lineWidth=2;U.strokeStyle=V.color;if(B){U.strokeRect(M+1,L+z.acum+1,z.dimValue-2,E-2)}else{U.strokeRect(M+z.acum+1,L-z.dimValue+1,E-2,z.dimValue-2)}U.restore()}if(K.type==\"Native\"){U.save();U.fillStyle=U.strokeStyle=K.color;U.font=K.style+\" \"+K.size+\"px \"+K.family;U.textBaseline=\"middle\";if(F(S.name,I)){if(B){U.textAlign=\"right\";U.fillText(I,M+Math.max.apply(null,O)-ac.labelOffset,L+P/2)}else{U.textAlign=\"center\";U.fillText(I,M+R/2,L-Math.max.apply(null,O)-K.size/2-ac.labelOffset)}}if(Q(S.name,I,S)){if(B){U.textAlign=\"center\";U.translate(M-ac.labelOffset-K.size/2,L+P/2);U.rotate(Math.PI/2);U.fillText(S.name,0,0)}else{U.textAlign=\"center\";U.fillText(S.name,M+R/2,L+K.size/2+ac.labelOffset)}}U.restore()}}},contains:function(K,G){var C=K.pos.getc(true),J=K.getData(\"width\"),I=K.getData(\"height\"),F=this.getAlignedPos(C,J,I),E=F.x,D=F.y,H=K.getData(\"dimArray\"),N=H.length,Q=K.getData(\"config\"),B=G.x-E,z=Q.orientation==\"horizontal\",A=(z?I:J)/N;if(z){if(G.x<E||G.x>E+J||G.y>D+I||G.y<D){return false}}else{if(G.x<E||G.x>E+J||G.y>D||G.y<D-I){return false}}for(var M=0,L=H.length;M<L;M++){var P=H[M];if(z){var O=D+A*M;if(G.x<=E+P&&G.y>=O&&G.y<=O+A){return{name:K.getData(\"stringArray\")[M],color:K.getData(\"colorArray\")[M],value:K.getData(\"valueArray\")[M]}}}else{var O=E+A*M;if(G.x>=O&&G.x<=O+A&&G.y>=D-P){return{name:K.getData(\"stringArray\")[M],color:K.getData(\"colorArray\")[M],value:K.getData(\"valueArray\")[M]}}}}return false}}});$jit.BarChart=new t({st:null,colors:[\"#416D9C\",\"#70A35E\",\"#EBB056\",\"#C74243\",\"#83548B\",\"#909291\",\"#557EAA\"],selected:{},busy:false,initialize:function(B){this.controller=this.config=d.merge(p(\"Canvas\",\"Label\",\"BarChart\"),{Label:{type:\"Native\"}},B);var C=this.config.showLabels,A=d.type(C),D=this.config.showAggregates,z=d.type(D);this.config.showLabels=A==\"function\"?C:d.lambda(C);this.config.showAggregates=z==\"function\"?D:d.lambda(D);this.initializeViz()},initializeViz:function(){var B=this.config,E=this;var z=B.type.split(\":\")[0],F=B.orientation==\"horizontal\",D={};var A=new $jit.ST({injectInto:B.injectInto,orientation:F?\"left\":\"bottom\",levelDistance:0,siblingOffset:B.barsOffset,subtreeOffset:0,withLabels:B.Label.type!=\"Native\",useCanvas:B.useCanvas,Label:{type:B.Label.type},Node:{overridable:true,type:\"barchart-\"+z,align:\"left\",width:1,height:1},Edge:{type:\"none\"},Tips:{enable:B.Tips.enable,type:\"Native\",force:true,onShow:function(J,I,G){var H=G;B.Tips.onShow(J,H,I)}},Events:{enable:true,type:\"Native\",onClick:function(I,J,G){if(!B.Events.enable){return}var H=J.getContains();B.Events.onClick(H,J,G)},onMouseMove:function(I,J,G){if(!B.hoveredColor){return}if(I){var H=J.getContains();E.select(I.id,H.name,H.index)}else{E.select(false,false,false)}}},onCreateLabel:function(L,J){var R=B.Label,P=J.getData(\"valueArray\"),O=d.reduce(P,function(S,T){return S+T},0);var N={wrapper:document.createElement(\"div\"),aggregate:document.createElement(\"div\"),label:document.createElement(\"div\")};var G=N.wrapper,Q=N.label,H=N.aggregate,I=G.style,M=Q.style,K=H.style;D[J.id]=N;G.appendChild(Q);G.appendChild(H);if(!B.showLabels(J.name,O,J)){M.display=\"none\"}if(!B.showAggregates(J.name,O,J)){K.display=\"none\"}I.position=\"relative\";I.overflow=\"visible\";I.fontSize=R.size+\"px\";I.fontFamily=R.family;I.color=R.color;I.textAlign=\"center\";K.position=M.position=\"absolute\";L.style.width=J.getData(\"width\")+\"px\";L.style.height=J.getData(\"height\")+\"px\";K.left=M.left=\"0px\";Q.innerHTML=J.name;L.appendChild(G)},onPlaceLabel:function(N,J){if(!D[J.id]){return}var P=D[J.id],K=P.wrapper.style,R=P.label.style,O=P.aggregate.style,S=B.type.split(\":\")[0]==\"grouped\",G=B.orientation==\"horizontal\",V=J.getData(\"dimArray\"),W=J.getData(\"valueArray\"),H=(S&&G)?Math.max.apply(null,V):J.getData(\"width\"),U=(S&&!G)?Math.max.apply(null,V):J.getData(\"height\"),I=parseInt(K.fontSize,10),Q=N.style;if(V&&W){K.width=O.width=R.width=N.style.width=H+\"px\";for(var M=0,L=W.length,T=0;M<L;M++){if(V[M]>0){T+=W[M]}}if(B.showLabels(J.name,T,J)){R.display=\"\"}else{R.display=\"none\"}if(B.showAggregates(J.name,T,J)){O.display=\"\"}else{O.display=\"none\"}if(B.orientation==\"horizontal\"){O.textAlign=\"right\";R.textAlign=\"left\";R.textIndex=O.textIndent=B.labelOffset+\"px\";O.top=R.top=(U-I)/2+\"px\";N.style.height=K.height=U+\"px\"}else{O.top=(-I-B.labelOffset)+\"px\";R.top=(B.labelOffset+U)+\"px\";N.style.top=parseInt(N.style.top,10)-U+\"px\";N.style.height=K.height=U+\"px\"}P.aggregate.innerHTML=T}}});var C=A.canvas.getSize();if(F){A.config.offsetX=+C.width/2-B.offset-(B.showLabels&&(B.labelOffset+B.Label.size))}else{A.config.offsetY=-C.height/2+B.offset+(B.showLabels&&(B.labelOffset+B.Label.size))}this.st=A;this.canvas=this.st.canvas},loadJSON:function(N){if(this.busy){return}this.busy=true;var L=d.time(),F=[],G=this.st,Q=d.splat(N.label),K=d.splat(N.color||this.colors),O=this.config,z=!!O.type.split(\":\")[1],C=O.animate,B=O.orientation==\"horizontal\",D=this;for(var M=0,A=N.values,I=A.length;M<I;M++){var P=A[M];var E=d.splat(A[M].values);var J=0;F.push({id:L+P.label,name:P.label,data:{value:E,\"$valueArray\":E,\"$colorArray\":K,\"$stringArray\":Q,\"$gradient\":z,\"$config\":O},children:[]})}var H={id:L+\"$root\",name:\"\",data:{\"$type\":\"none\",\"$width\":1,\"$height\":1},children:F};G.loadJSON(H);this.normalizeDims();G.compute();G.select(G.root);if(C){if(B){G.fx.animate({modes:[\"node-property:width:dimArray\"],duration:1500,onComplete:function(){D.busy=false}})}else{G.fx.animate({modes:[\"node-property:height:dimArray\"],duration:1500,onComplete:function(){D.busy=false}})}}else{this.busy=false}},updateJSON:function(C,F){if(this.busy){return}this.busy=true;var B=this.st;var E=B.graph;var A=C.values;var z=this.config.animate;var D=this;var G=this.config.orientation==\"horizontal\";d.each(A,function(H){var I=E.getByName(H.label);if(I){I.setData(\"valueArray\",d.splat(H.values));if(C.label){I.setData(\"stringArray\",d.splat(C.label))}}});this.normalizeDims();B.compute();B.select(B.root);if(z){if(G){B.fx.animate({modes:[\"node-property:width:dimArray\"],duration:1500,onComplete:function(){D.busy=false;F&&F.onComplete()}})}else{B.fx.animate({modes:[\"node-property:height:dimArray\"],duration:1500,onComplete:function(){D.busy=false;F&&F.onComplete()}})}}},select:function(B,z){if(!this.config.hoveredColor){return}var A=this.selected;if(A.id!=B||A.name!=z){A.id=B;A.name=z;A.color=this.config.hoveredColor;this.st.graph.eachNode(function(C){if(B==C.id){C.setData(\"border\",A)}else{C.setData(\"border\",false)}});this.st.plot()}},getLegend:function(){var B={};var C;this.st.graph.getNode(this.st.root).eachAdjacency(function(D){C=D.nodeTo});var A=C.getData(\"colorArray\"),z=A.length;d.each(C.getData(\"stringArray\"),function(E,D){B[E]=A[D%z]});return B},getMaxValue:function(){var A=0,z=this.config.type.split(\":\")[0]==\"stacked\";this.st.graph.eachNode(function(D){var B=D.getData(\"valueArray\"),C=0;if(!B){return}if(z){d.each(B,function(E){C+=+E})}else{C=Math.max.apply(null,B)}A=A>C?A:C});return A},setBarType:function(z){this.config.type=z;this.st.config.Node.type=\"barchart-\"+z.split(\":\")[0]},normalizeDims:function(){var I=this.st.graph.getNode(this.st.root),D=0;I.eachAdjacency(function(){D++});var F=this.getMaxValue(),K=this.st.canvas.getSize(),C=this.config,E=C.offset,A=C.orientation==\"horizontal\",z=(K[A?\"height\":\"width\"]-2*E-(D-1)*C.barsOffset)/D,B=C.animate,J=K[A?\"width\":\"height\"]-2*E-(!A&&C.showAggregates&&(C.Label.size+C.labelOffset))-(C.showLabels&&(C.Label.size+C.labelOffset)),H=A?\"height\":\"width\",G=A?\"width\":\"height\";this.st.graph.eachNode(function(O){var N=0,L=[];d.each(O.getData(\"valueArray\"),function(P){N+=+P;L.push(0)});O.setData(H,z);if(B){O.setData(G,N*J/F,\"end\");O.setData(\"dimArray\",d.map(O.getData(\"valueArray\"),function(P){return P*J/F}),\"end\");var M=O.getData(\"dimArray\");if(!M){O.setData(\"dimArray\",L)}}else{O.setData(G,N*J/F);O.setData(\"dimArray\",d.map(O.getData(\"valueArray\"),function(P){return P*J/F}))}})}});p.PieChart={$extend:true,animate:true,offset:25,sliceOffset:0,labelOffset:3,type:\"stacked\",hoveredColor:\"#9fd4ff\",Events:{enable:false,onClick:d.empty},Tips:{enable:false,onShow:d.empty,onHide:d.empty},showLabels:true,resizeLabels:false,updateHeights:false};$jit.Sunburst=new t({Implements:[e,q,i.Radial],initialize:function(z){var B=$jit.Sunburst;var A={interpolation:\"linear\",levelDistance:100,Node:{type:\"multipie\",height:0},Edge:{type:\"none\"},Label:{textAlign:\"start\",textBaseline:\"middle\"}};this.controller=this.config=d.merge(p(\"Canvas\",\"Node\",\"Edge\",\"Fx\",\"Tips\",\"NodeStyles\",\"Events\",\"Navigation\",\"Controller\",\"Label\"),A,z);var C=this.config;if(C.useCanvas){this.canvas=C.useCanvas;this.config.labelContainer=this.canvas.id+\"-label\"}else{if(C.background){C.background=d.merge({type:\"Circles\"},C.background)}this.canvas=new n(this,C);this.config.labelContainer=(typeof C.injectInto==\"string\"?C.injectInto:C.injectInto.id)+\"-label\"}this.graphOptions={complex:false,Node:{selected:false,exist:true,drawn:true}};this.graph=new f(this.graphOptions,this.config.Node,this.config.Edge);this.labels=new B.Label[C.Label.type](this);this.fx=new B.Plot(this);this.op=new B.Op(this);this.json=null;this.root=null;this.rotated=null;this.busy=false;this.initializeExtras()},createLevelDistanceFunc:function(){var z=this.config.levelDistance;return function(A){return(A._depth+1)*z}},refresh:function(){this.compute();this.plot()},reposition:function(){this.compute(\"end\")},rotate:function(B,C,A){var z=B.getPos(A.property||\"current\").getp(true).theta;this.rotated=B;this.rotateAngle(-z,C,A)},rotateAngle:function(B,E,A){var C=this;var z=d.merge(this.config,A||{},{modes:[\"polar\"]});var D=A.property||(E===\"animate\"?\"end\":\"current\");if(E===\"animate\"){this.fx.animation.pause()}this.graph.eachNode(function(G){var F=G.getPos(D);F.theta+=B;if(F.theta<0){F.theta+=Math.PI*2}});if(E==\"animate\"){this.fx.animate(z)}else{if(E==\"replot\"){this.fx.plot();this.busy=false}}},plot:function(){this.fx.plot()}});$jit.Sunburst.$extend=true;(function(z){z.Op=new t({Implements:f.Op,initialize:function(A){this.viz=A}});z.Plot=new t({Implements:f.Plot,initialize:function(A){this.viz=A;this.config=A.config;this.node=A.config.Node;this.edge=A.config.Edge;this.animation=new x;this.nodeTypes=new z.Plot.NodeTypes;this.edgeTypes=new z.Plot.EdgeTypes;this.labels=A.labels}});z.Label={};z.Label.Native=new t({Implements:f.Label.Native,initialize:function(A){this.viz=A;this.label=A.config.Label;this.config=A.config},renderLabel:function(D,F,H){var O=F.getData(\"span\");if(O<Math.PI/2&&Math.tan(O)*this.config.levelDistance*F._depth<10){return}var P=D.getCtx();var B=P.measureText(F.name);if(F.id==this.viz.root){var N=-B.width/2,L=0,M=0;var A=0}else{var E=5;var A=H.levelDistance-E;var K=F.pos.clone();K.rho+=E;var C=K.getp(true);var I=K.getc(true);var N=I.x,L=I.y;var G=Math.PI;var J=(C.theta>G/2&&C.theta<3*G/2);var M=J?C.theta+G:C.theta;if(J){N-=Math.abs(Math.cos(C.theta)*B.width);L+=Math.sin(C.theta)*B.width}else{if(F.id==this.viz.root){N-=B.width/2}}}P.save();P.translate(N,L);P.rotate(M);P.fillText(F.name,0,0);P.restore()}});z.Label.SVG=new t({Implements:f.Label.SVG,initialize:function(A){this.viz=A},placeLabel:function(O,D,F){var K=D.pos.getc(true),N=this.viz,B=this.viz.canvas;var G=B.getSize();var C={x:Math.round(K.x+G.width/2),y:Math.round(K.y+G.height/2)};O.setAttribute(\"x\",C.x);O.setAttribute(\"y\",C.y);var H=O.getBBox();if(H){var M=O.getAttribute(\"x\");var J=O.getAttribute(\"y\");var A=D.pos.getp(true);var E=Math.PI;var I=(A.theta>E/2&&A.theta<3*E/2);if(I){O.setAttribute(\"x\",M-H.width);O.setAttribute(\"y\",J-H.height)}else{if(D.id==N.root){O.setAttribute(\"x\",M-H.width/2)}}var L=I?A.theta+E:A.theta;if(D._depth){O.setAttribute(\"transform\",\"rotate(\"+L*360/(2*E)+\" \"+M+\" \"+J+\")\")}}F.onPlaceLabel(O,D)}});z.Label.HTML=new t({Implements:f.Label.HTML,initialize:function(A){this.viz=A},placeLabel:function(J,D,F){var H=D.pos.clone(),B=this.viz.canvas,I=D.getData(\"height\"),E=((I||D._depth==0)?I:this.viz.config.levelDistance)/2,G=B.getSize();H.rho+=E;H=H.getc(true);var C={x:Math.round(H.x+G.width/2),y:Math.round(H.y+G.height/2)};var A=J.style;A.left=C.x+\"px\";A.top=C.y+\"px\";A.display=this.fitsInCanvas(C,B)?\"\":\"none\";F.onPlaceLabel(J,D)}});z.Plot.NodeTypes=new t({none:{render:d.empty,contains:d.lambda(false),anglecontains:function(E,G){var D=E.getData(\"span\")/2,B=E.pos.theta;var C=B-D,A=B+D;if(C<0){C+=Math.PI*2}var F=Math.atan2(G.y,G.x);if(F<0){F+=Math.PI*2}if(C>A){return(F>C&&F<=Math.PI*2)||F<A}else{return F>C&&F<A}}},pie:{render:function(F,D){var J=F.getData(\"span\")/2,C=F.pos.theta;var E=C-J,G=C+J;var I=F.pos.getp(true);var A=new c(I.rho,E);var B=A.getc(true);A.theta=G;var H=A.getc(true);var K=D.getCtx();K.beginPath();K.moveTo(0,0);K.lineTo(B.x,B.y);K.moveTo(0,0);K.lineTo(H.x,H.y);K.moveTo(0,0);K.arc(0,0,I.rho*F.getData(\"dim-quotient\"),E,G,false);K.fill()},contains:function(C,E){if(this.nodeTypes.none.anglecontains.call(this,C,E)){var A=Math.sqrt(E.x*E.x+E.y*E.y);var B=this.config.levelDistance,D=C._depth;return(A<=B*D)}return false}},multipie:{render:function(G,E){var N=G.getData(\"height\");var H=N?N:this.config.levelDistance;var M=G.getData(\"span\")/2,D=G.pos.theta;var F=D-M,J=D+M;var L=G.pos.getp(true);var B=new c(L.rho,F);var C=B.getc(true);B.theta=J;var K=B.getc(true);B.rho+=H;var A=B.getc(true);B.theta=F;var I=B.getc(true);var O=E.getCtx();O.moveTo(0,0);O.beginPath();O.arc(0,0,L.rho,F,J,false);O.arc(0,0,L.rho+H,J,F,true);O.moveTo(C.x,C.y);O.lineTo(I.x,I.y);O.moveTo(K.x,K.y);O.lineTo(A.x,A.y);O.fill();if(G.collapsed){O.save();O.lineWidth=2;O.moveTo(0,0);O.beginPath();O.arc(0,0,L.rho+H+5,J-0.01,F+0.01,true);O.stroke();O.restore()}},contains:function(D,G){if(this.nodeTypes.none.anglecontains.call(this,D,G)){var B=Math.sqrt(G.x*G.x+G.y*G.y);var A=D.getData(\"height\");var E=A?A:this.config.levelDistance;var C=this.config.levelDistance,F=D._depth;return(B>=C*F)&&(B<=(C*F+E))}return false}},\"gradient-multipie\":{render:function(D,A){var I=A.getCtx();var H=D.getData(\"height\");var E=H?H:this.config.levelDistance;var B=I.createRadialGradient(0,0,D.getPos().rho,0,0,D.getPos().rho+E);var G=d.hexToRgb(D.getData(\"color\")),F=[];d.each(G,function(J){F.push(parseInt(J*0.5,10))});var C=d.rgbToHex(F);B.addColorStop(0,C);B.addColorStop(1,D.getData(\"color\"));I.fillStyle=B;this.nodeTypes.multipie.render.call(this,D,A)},contains:function(A,B){return this.nodeTypes.multipie.contains.call(this,A,B)}},\"gradient-pie\":{render:function(F,C){var A=C.getCtx();var G=A.createRadialGradient(0,0,0,0,0,F.getPos().rho);var E=d.hexToRgb(F.getData(\"color\")),B=[];d.each(E,function(H){B.push(parseInt(H*0.5,10))});var D=d.rgbToHex(B);G.addColorStop(1,D);G.addColorStop(0,F.getData(\"color\"));A.fillStyle=G;this.nodeTypes.pie.render.call(this,F,C)},contains:function(A,B){return this.nodeTypes.pie.contains.call(this,A,B)}}});z.Plot.EdgeTypes=new t({none:d.empty,line:function(A,B){var D=A.nodeFrom.pos.getc(true),C=A.nodeTo.pos.getc(true);this.edgeHelper.line(D,C,B)},arrow:function(B,C){var G=B.nodeFrom.pos.getc(true),F=B.nodeTo.pos.getc(true),E=B.getData(\"dim\"),D=B.data.$direction,A=(D&&D.length>1&&D[0]!=B.nodeFrom.id);this.edgeHelper.arrow(G,F,E,A,C)},hyperline:function(A,B){var E=A.nodeFrom.pos.getc(),D=A.nodeTo.pos.getc(),C=Math.max(E.norm(),D.norm());this.edgeHelper.hyperline(E.$scale(1/C),D.$scale(1/C),C,B)}})})($jit.Sunburst);$jit.Sunburst.Plot.NodeTypes.implement({\"piechart-stacked\":{render:function(X,D){var W=X.pos.getp(true),F=X.getData(\"dimArray\"),V=X.getData(\"valueArray\"),J=X.getData(\"colorArray\"),C=J.length,P=X.getData(\"stringArray\"),S=X.getData(\"span\")/2,N=X.pos.theta,I=N-S,M=N+S,U=new c;var Q=D.getCtx(),O={},L=X.getData(\"gradient\"),G=X.getData(\"border\"),ac=X.getData(\"config\"),al=ac.showLabels,ab=ac.resizeLabels,ae=ac.Label;var ah=ac.sliceOffset*Math.cos((I+M)/2);var H=ac.sliceOffset*Math.sin((I+M)/2);if(J&&F&&P){for(var ai=0,af=F.length,z=0,aa=0;ai<af;ai++){var E=F[ai],aj=J[ai%C];if(E<=0){continue}Q.fillStyle=Q.strokeStyle=aj;if(L&&E){var ag=Q.createRadialGradient(ah,H,z+ac.sliceOffset,ah,H,z+E+ac.sliceOffset);var A=d.hexToRgb(aj),Z=d.map(A,function(ao){return(ao*0.8)>>0}),B=d.rgbToHex(Z);ag.addColorStop(0,aj);ag.addColorStop(0.5,aj);ag.addColorStop(1,B);Q.fillStyle=ag}U.rho=z+ac.sliceOffset;U.theta=I;var ak=U.getc(true);U.theta=M;var R=U.getc(true);U.rho+=E;var am=U.getc(true);U.theta=I;var T=U.getc(true);Q.beginPath();Q.arc(ah,H,z+0.01,I,M,false);Q.arc(ah,H,z+E+0.01,M,I,true);Q.fill();if(G&&G.name==P[ai]){O.acum=z;O.dimValue=F[ai];O.begin=I;O.end=M}z+=(E||0);aa+=(V[ai]||0)}if(G){Q.save();Q.globalCompositeOperation=\"source-over\";Q.lineWidth=2;Q.strokeStyle=G.color;var ad=I<M?1:-1;Q.beginPath();Q.arc(ah,H,O.acum+0.01+1,O.begin,O.end,false);Q.arc(ah,H,O.acum+O.dimValue+0.01-1,O.end,O.begin,true);Q.closePath();Q.stroke();Q.restore()}if(al&&ae.type==\"Native\"){Q.save();Q.fillStyle=Q.strokeStyle=ae.color;var Y=ab?X.getData(\"normalizedDim\"):1,K=(ae.size*Y)>>0;K=K<+ab?+ab:K;Q.font=ae.style+\" \"+K+\"px \"+ae.family;Q.textBaseline=\"middle\";Q.textAlign=\"center\";U.rho=z+ac.labelOffset+ac.sliceOffset;U.theta=X.pos.theta;var an=U.getc(true);Q.fillText(X.name,an.x,an.y);Q.restore()}}},contains:function(C,G){if(this.nodeTypes.none.anglecontains.call(this,C,G)){var I=Math.sqrt(G.x*G.x+G.y*G.y);var z=this.config.levelDistance,F=C._depth;var A=C.getData(\"config\");if(I<=z*F+A.sliceOffset){var J=C.getData(\"dimArray\");for(var E=0,D=J.length,H=A.sliceOffset;E<D;E++){var B=J[E];if(I>=H&&I<=H+B){return{name:C.getData(\"stringArray\")[E],color:C.getData(\"colorArray\")[E],value:C.getData(\"valueArray\")[E],label:C.name}}H+=B}}return false}return false}}});$jit.PieChart=new t({sb:null,colors:[\"#416D9C\",\"#70A35E\",\"#EBB056\",\"#C74243\",\"#83548B\",\"#909291\",\"#557EAA\"],selected:{},busy:false,initialize:function(z){this.controller=this.config=d.merge(p(\"Canvas\",\"PieChart\",\"Label\"),{Label:{type:\"Native\"}},z);this.initializeViz()},initializeViz:function(){var A=this.config,D=this;var z=A.type.split(\":\")[0];var E=new $jit.Sunburst({injectInto:A.injectInto,useCanvas:A.useCanvas,withLabels:A.Label.type!=\"Native\",Label:{type:A.Label.type},Node:{overridable:true,type:\"piechart-\"+z,width:1,height:1},Edge:{type:\"none\"},Tips:{enable:A.Tips.enable,type:\"Native\",force:true,onShow:function(I,H,F){var G=F;A.Tips.onShow(I,G,H)}},Events:{enable:true,type:\"Native\",onClick:function(H,I,F){if(!A.Events.enable){return}var G=I.getContains();A.Events.onClick(G,I,F)},onMouseMove:function(H,I,F){if(!A.hoveredColor){return}if(H){var G=I.getContains();D.select(H.id,G.name,G.index)}else{D.select(false,false,false)}}},onCreateLabel:function(I,H){var F=A.Label;if(A.showLabels){var G=I.style;G.fontSize=F.size+\"px\";G.fontFamily=F.family;G.color=F.color;G.textAlign=\"center\";I.innerHTML=H.name}},onPlaceLabel:function(V,P){if(!A.showLabels){return}var J=P.pos.getp(true),M=P.getData(\"dimArray\"),S=P.getData(\"span\")/2,K=P.pos.theta,U=K-S,G=K+S,X=new c;var O=A.showLabels,I=A.resizeLabels,L=A.Label;if(M){for(var T=0,Q=M.length,R=0;T<Q;T++){R+=M[T]}var W=I?P.getData(\"normalizedDim\"):1,F=(L.size*W)>>0;F=F<+I?+I:F;V.style.fontSize=F+\"px\";X.rho=R+A.labelOffset+A.sliceOffset;X.theta=(U+G)/2;var J=X.getc(true);var H=D.canvas.getSize();var N={x:Math.round(J.x+H.width/2),y:Math.round(J.y+H.height/2)};V.style.left=N.x+\"px\";V.style.top=N.y+\"px\"}}});var C=E.canvas.getSize(),B=Math.min;E.config.levelDistance=B(C.width,C.height)/2-A.offset-A.sliceOffset;this.sb=E;this.canvas=this.sb.canvas;this.canvas.getCtx().globalCompositeOperation=\"lighter\"},loadJSON:function(N){var L=d.time(),F=[],z=this.sb,Q=d.splat(N.label),H=Q.length,K=d.splat(N.color||this.colors),C=K.length,O=this.config,A=!!O.type.split(\":\")[1],D=O.animate,J=H==1;for(var M=0,B=N.values,I=B.length;M<I;M++){var P=B[M];var E=d.splat(P.values);F.push({id:L+P.label,name:P.label,data:{value:E,\"$valueArray\":E,\"$colorArray\":J?d.splat(K[M%C]):K,\"$stringArray\":Q,\"$gradient\":A,\"$config\":O,\"$angularWidth\":d.reduce(E,function(R,S){return R+S})},children:[]})}var G={id:L+\"$root\",name:\"\",data:{\"$type\":\"none\",\"$width\":1,\"$height\":1},children:F};z.loadJSON(G);this.normalizeDims();z.refresh();if(D){z.fx.animate({modes:[\"node-property:dimArray\"],duration:1500})}},updateJSON:function(B,E){if(this.busy){return}this.busy=true;var F=this.sb;var D=F.graph;var A=B.values;var z=this.config.animate;var C=this;d.each(A,function(G){var I=D.getByName(G.label),H=d.splat(G.values);if(I){I.setData(\"valueArray\",H);I.setData(\"angularWidth\",d.reduce(H,function(J,K){return J+K}));if(B.label){I.setData(\"stringArray\",d.splat(B.label))}}});this.normalizeDims();if(z){F.compute(\"end\");F.fx.animate({modes:[\"node-property:dimArray:span\",\"linear\"],duration:1500,onComplete:function(){C.busy=false;E&&E.onComplete()}})}else{F.refresh()}},select:function(B,z){if(!this.config.hoveredColor){return}var A=this.selected;if(A.id!=B||A.name!=z){A.id=B;A.name=z;A.color=this.config.hoveredColor;this.sb.graph.eachNode(function(C){if(B==C.id){C.setData(\"border\",A)}else{C.setData(\"border\",false)}});this.sb.plot()}},getLegend:function(){var B={};var C;this.sb.graph.getNode(this.sb.root).eachAdjacency(function(D){C=D.nodeTo});var A=C.getData(\"colorArray\"),z=A.length;d.each(C.getData(\"stringArray\"),function(E,D){B[E]=A[D%z]});return B},getMaxValue:function(){var z=0;this.sb.graph.eachNode(function(C){var A=C.getData(\"valueArray\"),B=0;d.each(A,function(D){B+=+D});z=z>B?z:B});return z},normalizeDims:function(){var A=this.sb.graph.getNode(this.sb.root),z=0;A.eachAdjacency(function(){z++});var E=this.getMaxValue(),D=this.config,B=D.animate,C=this.sb.config.levelDistance;this.sb.graph.eachNode(function(J){var I=0,F=[];d.each(J.getData(\"valueArray\"),function(K){I+=+K;F.push(1)});var H=(F.length==1)&&!D.updateHeights;if(B){J.setData(\"dimArray\",d.map(J.getData(\"valueArray\"),function(K){return H?C:(K*C/E)}),\"end\");var G=J.getData(\"dimArray\");if(!G){J.setData(\"dimArray\",F)}}else{J.setData(\"dimArray\",d.map(J.getData(\"valueArray\"),function(K){return H?C:(K*C/E)}))}J.setData(\"normalizedDim\",I/E)})}})})();\n"
  },
  {
    "path": "public/javascripts/jit.js",
    "content": "/*\n  > Redistribution and use in source and binary forms, with or without\n  > modification, are permitted provided that the following conditions are met:\n  >      * Redistributions of source code must retain the above copyright\n  >        notice, this list of conditions and the following disclaimer.\n  >      * Redistributions in binary form must reproduce the above copyright\n  >        notice, this list of conditions and the following disclaimer in the\n  >        documentation and/or other materials provided with the distribution.\n  >      * Neither the name of the organization nor the\n  >        names of its contributors may be used to endorse or promote products\n  >        derived from this software without specific prior written permission.\n  >\n  >  THIS SOFTWARE IS PROVIDED BY NICOLAS GARCIA BELMONTE ``AS IS'' AND ANY\n  >  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  >  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n  >  DISCLAIMED. IN NO EVENT SHALL NICOLAS GARCIA BELMONTE BE LIABLE FOR ANY\n  >  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n  >  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n  >  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n  >  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n  >  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n  >  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n (function () {\n\n/*\n  File: Core.js\n\n */\n\n/*\n Object: $jit\n\n Defines the namespace for all library Classes and Objects.\n This variable is the *only* global variable defined in the Toolkit.\n There are also other interesting properties attached to this variable described below.\n */\nwindow.$jit = function(w) {\n  w = w || window;\n  for(var k in $jit) {\n    if($jit[k].$extend) {\n      w[k] = $jit[k];\n    }\n  }\n};\n\n$jit.version = '2.0.0a';\n/*\n  Object: $jit.id\n\n  Works just like *document.getElementById*\n\n  Example:\n  (start code js)\n  var element = $jit.id('elementId');\n  (end code)\n\n*/\n\n/*\n Object: $jit.util\n\n Contains utility functions.\n\n Some of the utility functions and the Class system were based in the MooTools Framework\n <http://mootools.net>. Copyright (c) 2006-2010 Valerio Proietti, <http://mad4milk.net/>.\n MIT license <http://mootools.net/license.txt>.\n\n These methods are generally also implemented in DOM manipulation frameworks like JQuery, MooTools and Prototype.\n I'd suggest you to use the functions from those libraries instead of using these, since their functions\n are widely used and tested in many different platforms/browsers. Use these functions only if you have to.\n\n */\nvar $ = function(d) {\n  return document.getElementById(d);\n};\n\n$.empty = function() {\n};\n\n/*\n  Method: extend\n\n  Augment an object by appending another object's properties.\n\n  Parameters:\n\n  original - (object) The object to be extended.\n  extended - (object) An object which properties are going to be appended to the original object.\n\n  Example:\n  (start code js)\n  $jit.util.extend({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 4 }); //{ 'a':1, 'b': 3, 'c': 4 }\n  (end code)\n*/\n$.extend = function(original, extended) {\n  for ( var key in (extended || {}))\n    original[key] = extended[key];\n  return original;\n};\n\n$.lambda = function(value) {\n  return (typeof value == 'function') ? value : function() {\n    return value;\n  };\n};\n\n$.time = Date.now || function() {\n  return +new Date;\n};\n\n/*\n  Method: splat\n\n  Returns an array wrapping *obj* if *obj* is not an array. Returns *obj* otherwise.\n\n  Parameters:\n\n  obj - (mixed) The object to be wrapped in an array.\n\n  Example:\n  (start code js)\n  $jit.util.splat(3);   //[3]\n  $jit.util.splat([3]); //[3]\n  (end code)\n*/\n$.splat = function(obj) {\n  var type = $.type(obj);\n  return type ? ((type != 'array') ? [ obj ] : obj) : [];\n};\n\n$.type = function(elem) {\n  var type = $.type.s.call(elem).match(/^\\[object\\s(.*)\\]$/)[1].toLowerCase();\n  if(type != 'object') return type;\n  if(elem && elem.$$family) return elem.$$family;\n  return (elem && elem.nodeName && elem.nodeType == 1)? 'element' : type;\n};\n$.type.s = Object.prototype.toString;\n\n/*\n  Method: each\n\n  Iterates through an iterable applying *f*.\n\n  Parameters:\n\n  iterable - (array) The original array.\n  fn - (function) The function to apply to the array elements.\n\n  Example:\n  (start code js)\n  $jit.util.each([3, 4, 5], function(n) { alert('number ' + n); });\n  (end code)\n*/\n$.each = function(iterable, fn) {\n  var type = $.type(iterable);\n  if (type == 'object') {\n    for ( var key in iterable)\n      fn(iterable[key], key);\n  } else {\n    for ( var i = 0, l = iterable.length; i < l; i++)\n      fn(iterable[i], i);\n  }\n};\n\n$.indexOf = function(array, item) {\n  if(Array.indexOf) return array.indexOf(item);\n  for(var i=0,l=array.length; i<l; i++) {\n    if(array[i] === item) return i;\n  }\n  return -1;\n};\n\n/*\n  Method: map\n\n  Maps or collects an array by applying *f*.\n\n  Parameters:\n\n  array - (array) The original array.\n  f - (function) The function to apply to the array elements.\n\n  Example:\n  (start code js)\n  $jit.util.map([3, 4, 5], function(n) { return n*n; }); //[9, 16, 25]\n  (end code)\n*/\n$.map = function(array, f) {\n  var ans = [];\n  $.each(array, function(elem, i) {\n    ans.push(f(elem, i));\n  });\n  return ans;\n};\n\n/*\n  Method: reduce\n\n  Iteratively applies the binary function *f* storing the result in an accumulator.\n\n  Parameters:\n\n  array - (array) The original array.\n  f - (function) The function to apply to the array elements.\n  opt - (optional|mixed) The starting value for the acumulator.\n\n  Example:\n  (start code js)\n  $jit.util.reduce([3, 4, 5], function(x, y) { return x + y; }, 0); //12\n  (end code)\n*/\n$.reduce = function(array, f, opt) {\n  var l = array.length;\n  if(l==0) return opt;\n  var acum = arguments.length == 3? opt : array[--l];\n  while(l--) {\n    acum = f(acum, array[l]);\n  }\n  return acum;\n};\n\n/*\n  Method: merge\n\n  Merges n-objects and their sub-objects creating a new, fresh object.\n\n  Parameters:\n\n  An arbitrary number of objects.\n\n  Example:\n  (start code js)\n  $jit.util.merge({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 4 }); //{ 'a':1, 'b': 3, 'c': 4 }\n  (end code)\n*/\n$.merge = function() {\n  var mix = {};\n  for ( var i = 0, l = arguments.length; i < l; i++) {\n    var object = arguments[i];\n    if ($.type(object) != 'object')\n      continue;\n    for ( var key in object) {\n      var op = object[key], mp = mix[key];\n      mix[key] = (mp && $.type(op) == 'object' && $.type(mp) == 'object') ? $\n          .merge(mp, op) : $.unlink(op);\n    }\n  }\n  return mix;\n};\n\n$.unlink = function(object) {\n  var unlinked;\n  switch ($.type(object)) {\n  case 'object':\n    unlinked = {};\n    for ( var p in object)\n      unlinked[p] = $.unlink(object[p]);\n    break;\n  case 'array':\n    unlinked = [];\n    for ( var i = 0, l = object.length; i < l; i++)\n      unlinked[i] = $.unlink(object[i]);\n    break;\n  default:\n    return object;\n  }\n  return unlinked;\n};\n\n$.zip = function() {\n  if(arguments.length === 0) return [];\n  for(var j=0, ans=[], l=arguments.length, ml=arguments[0].length; j<ml; j++) {\n    for(var i=0, row=[]; i<l; i++) {\n      row.push(arguments[i][j]);\n    }\n    ans.push(row);\n  }\n  return ans;\n};\n\n/*\n  Method: rgbToHex\n\n  Converts an RGB array into a Hex string.\n\n  Parameters:\n\n  srcArray - (array) An array with R, G and B values\n\n  Example:\n  (start code js)\n  $jit.util.rgbToHex([255, 255, 255]); //'#ffffff'\n  (end code)\n*/\n$.rgbToHex = function(srcArray, array) {\n  if (srcArray.length < 3)\n    return null;\n  if (srcArray.length == 4 && srcArray[3] == 0 && !array)\n    return 'transparent';\n  var hex = [];\n  for ( var i = 0; i < 3; i++) {\n    var bit = (srcArray[i] - 0).toString(16);\n    hex.push(bit.length == 1 ? '0' + bit : bit);\n  }\n  return array ? hex : '#' + hex.join('');\n};\n\n/*\n  Method: hexToRgb\n\n  Converts an Hex color string into an RGB array.\n\n  Parameters:\n\n  hex - (string) A color hex string.\n\n  Example:\n  (start code js)\n  $jit.util.hexToRgb('#fff'); //[255, 255, 255]\n  (end code)\n*/\n$.hexToRgb = function(hex) {\n  if (hex.length != 7) {\n    hex = hex.match(/^#?(\\w{1,2})(\\w{1,2})(\\w{1,2})$/);\n    hex.shift();\n    if (hex.length != 3)\n      return null;\n    var rgb = [];\n    for ( var i = 0; i < 3; i++) {\n      var value = hex[i];\n      if (value.length == 1)\n        value += value;\n      rgb.push(parseInt(value, 16));\n    }\n    return rgb;\n  } else {\n    hex = parseInt(hex.slice(1), 16);\n    return [ hex >> 16, hex >> 8 & 0xff, hex & 0xff ];\n  }\n};\n\n// hsl/hsv manipulation functions adapted from\n// http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript\n\n$.rgbToHsl = function(rgbArray) {\n  r = rgbArray[0] / 255, g = rgbArray[1] / 255, b = rgbArray[2] / 255;\n\n  var max = Math.max(r, g, b), min = Math.min(r, g, b);\n  var h, s, l = (max + min) / 2;\n\n  if(max == min) {\n    h = s = 0; // achromatic\n  } else {\n    var d = max - min;\n    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n    switch(max){\n      case r:h = (g - b) / d + (g < b ? 6 : 0); break;\n      case g: h = (b - r) / d + 2; break;\n      case b: h = (r - g) / d + 4; break;\n    }\n    h /= 6;\n  }\n\n  return [Math.round(h*360), Math.round(s*100), Math.round(l*100)];\n};\n\n$.hslToRgb = function(hslArray){\n  var h = hslArray[0] / 360, s = hslArray[1] / 100, l = hslArray[2] / 100;\n  var r, g, b;\n\n  if(s == 0) {\n    r = g = b = l; // achromatic\n  } else {\n    function hue2rgb(p, q, t) {\n      if(t < 0) t += 1;\n      if(t > 1) t -= 1;\n      if(t < 1/6) return p + (q - p) * 6 * t;\n      if(t < 1/2) return q;\n      if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;\n      return p;\n    }\n\n    var q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n    var p = 2 * l - q;\n    r = hue2rgb(p, q, h + 1/3);\n    g = hue2rgb(p, q, h);\n    b = hue2rgb(p, q, h - 1/3);\n  }\n\n  return [Math.round(r*255), Math.round(g*255), Math.round(b*255)];\n};\n\n$.hslToHex = function(hslArray) {\n  return $.rgbToHex($.hslToRgb(hslArray));\n};\n\n$.rgbToHsv = function (rgbArray) {\n  r = rgbArray[0]/255, g = rgbArray[1]/255, b = rgbArray[2]/255;\n  var max = Math.max(r, g, b), min = Math.min(r, g, b);\n  var h, s, v = max;\n\n  var d = max - min;\n  s = max == 0 ? 0 : d / max;\n\n  if(max == min) {\n    h = 0; // achromatic\n  } else {\n    switch(max) {\n      case r: h = (g - b) / d + (g < b ? 6 : 0); break;\n      case g: h = (b - r) / d + 2; break;\n      case b: h = (r - g) / d + 4; break;\n    }\n    h /= 6;\n  }\n\n  return [Math.round(h*360), Math.round(s*100), Math.round(v*100)];\n};\n\n$.hsvToRgb = function(hsvArray){\n  var h = hsvArray[0] / 360, s = hsvArray[1] / 100, v = hsvArray[2] / 100;\n  var r, g, b;\n\n  var i = Math.floor(h * 6);\n  var f = h * 6 - i;\n  var p = v * (1 - s);\n  var q = v * (1 - f * s);\n  var t = v * (1 - (1 - f) * s);\n\n  switch(i % 6) {\n    case 0: r = v, g = t, b = p; break;\n    case 1: r = q, g = v, b = p; break;\n    case 2: r = p, g = v, b = t; break;\n    case 3: r = p, g = q, b = v; break;\n    case 4: r = t, g = p, b = v; break;\n    case 5: r = v, g = p, b = q; break;\n  }\n\n  return [Math.round(r*255), Math.round(g*255), Math.round(b*255)];\n};\n\n$.hsvToHex = function(hsvArray) {\n  return $.rgbToHex($.hsvToRgb(hsvArray));\n};\n\n$.destroy = function(elem) {\n  $.clean(elem);\n  if (elem.parentNode)\n    elem.parentNode.removeChild(elem);\n  if (elem.clearAttributes)\n    elem.clearAttributes();\n};\n\n$.clean = function(elem) {\n  for (var ch = elem.childNodes, i = 0, l = ch.length; i < l; i++) {\n    $.destroy(ch[i]);\n  }\n};\n\n/*\n  Method: addEvent\n\n  Cross-browser add event listener.\n\n  Parameters:\n\n  obj - (obj) The Element to attach the listener to.\n  type - (string) The listener type. For example 'click', or 'mousemove'.\n  fn - (function) The callback function to be used when the event is fired.\n\n  Example:\n  (start code js)\n  $jit.util.addEvent(elem, 'click', function(){ alert('hello'); });\n  (end code)\n*/\n$.addEvent = function(obj, type, fn) {\n  if (obj.addEventListener)\n    obj.addEventListener(type, fn, false);\n  else\n    obj.attachEvent('on' + type, fn);\n};\n\n$.addEvents = function(obj, typeObj) {\n  for(var type in typeObj) {\n    $.addEvent(obj, type, typeObj[type]);\n  }\n};\n\n$.hasClass = function(obj, klass) {\n  return (' ' + obj.className + ' ').indexOf(' ' + klass + ' ') > -1;\n};\n\n$.addClass = function(obj, klass) {\n  if (!$.hasClass(obj, klass))\n    obj.className = (obj.className + \" \" + klass);\n};\n\n$.removeClass = function(obj, klass) {\n  obj.className = obj.className.replace(new RegExp(\n      '(^|\\\\s)' + klass + '(?:\\\\s|$)'), '$1');\n};\n\n$.getPos = function(elem) {\n  var offset = getOffsets(elem);\n  var scroll = getScrolls(elem);\n  return {\n    x: offset.x - scroll.x,\n    y: offset.y - scroll.y\n  };\n\n  function getOffsets(elem) {\n    var position = {\n      x: 0,\n      y: 0\n    };\n    while (elem && !isBody(elem)) {\n      position.x += elem.offsetLeft;\n      position.y += elem.offsetTop;\n      elem = elem.offsetParent;\n    }\n    return position;\n  }\n\n  function getScrolls(elem) {\n    var position = {\n      x: 0,\n      y: 0\n    };\n    while (elem && !isBody(elem)) {\n      position.x += elem.scrollLeft;\n      position.y += elem.scrollTop;\n      elem = elem.parentNode;\n    }\n    return position;\n  }\n\n  function isBody(element) {\n    return (/^(?:body|html)$/i).test(element.tagName);\n  }\n};\n\n$.event = {\n  get: function(e, win) {\n    win = win || window;\n    return e || win.event;\n  },\n  getWheel: function(e) {\n    return e.wheelDelta? e.wheelDelta / 120 : -(e.detail || 0) / 3;\n  },\n  isRightClick: function(e) {\n    return (e.which == 3 || e.button == 2);\n  },\n  getPos: function(e, win) {\n    // get mouse position\n    win = win || window;\n    e = e || win.event;\n    var doc = win.document;\n    doc = doc.documentElement || doc.body;\n    //TODO(nico): make touch event handling better\n    if(e.touches && e.touches.length) {\n      e = e.touches[0];\n    }\n    var page = {\n      x: e.pageX || (e.clientX + doc.scrollLeft),\n      y: e.pageY || (e.clientY + doc.scrollTop)\n    };\n    return page;\n  },\n  stop: function(e) {\n    if (e.stopPropagation) e.stopPropagation();\n    e.cancelBubble = true;\n    if (e.preventDefault) e.preventDefault();\n    else e.returnValue = false;\n  }\n};\n\n$jit.util = $jit.id = $;\n\nvar Class = function(properties) {\n  properties = properties || {};\n  var klass = function() {\n    for ( var key in this) {\n      if (typeof this[key] != 'function')\n        this[key] = $.unlink(this[key]);\n    }\n    this.constructor = klass;\n    if (Class.prototyping)\n      return this;\n    var instance = this.initialize ? this.initialize.apply(this, arguments)\n        : this;\n    //typize\n    this.$$family = 'class';\n    return instance;\n  };\n\n  for ( var mutator in Class.Mutators) {\n    if (!properties[mutator])\n      continue;\n    properties = Class.Mutators[mutator](properties, properties[mutator]);\n    delete properties[mutator];\n  }\n\n  $.extend(klass, this);\n  klass.constructor = Class;\n  klass.prototype = properties;\n  return klass;\n};\n\nClass.Mutators = {\n\n  Implements: function(self, klasses) {\n    $.each($.splat(klasses), function(klass) {\n      Class.prototyping = klass;\n      var instance = (typeof klass == 'function') ? new klass : klass;\n      for ( var prop in instance) {\n        if (!(prop in self)) {\n          self[prop] = instance[prop];\n        }\n      }\n      delete Class.prototyping;\n    });\n    return self;\n  }\n\n};\n\n$.extend(Class, {\n\n  inherit: function(object, properties) {\n    for ( var key in properties) {\n      var override = properties[key];\n      var previous = object[key];\n      var type = $.type(override);\n      if (previous && type == 'function') {\n        if (override != previous) {\n          Class.override(object, key, override);\n        }\n      } else if (type == 'object') {\n        object[key] = $.merge(previous, override);\n      } else {\n        object[key] = override;\n      }\n    }\n    return object;\n  },\n\n  override: function(object, name, method) {\n    var parent = Class.prototyping;\n    if (parent && object[name] != parent[name])\n      parent = null;\n    var override = function() {\n      var previous = this.parent;\n      this.parent = parent ? parent[name] : object[name];\n      var value = method.apply(this, arguments);\n      this.parent = previous;\n      return value;\n    };\n    object[name] = override;\n  }\n\n});\n\nClass.prototype.implement = function() {\n  var proto = this.prototype;\n  $.each(Array.prototype.slice.call(arguments || []), function(properties) {\n    Class.inherit(proto, properties);\n  });\n  return this;\n};\n\n$jit.Class = Class;\n\n/*\n  Object: $jit.json\n\n  Provides JSON utility functions.\n\n  Most of these functions are JSON-tree traversal and manipulation functions.\n*/\n$jit.json = {\n  /*\n     Method: prune\n\n     Clears all tree nodes having depth greater than maxLevel.\n\n     Parameters:\n\n        tree - (object) A JSON tree object. For more information please see <Loader.loadJSON>.\n        maxLevel - (number) An integer specifying the maximum level allowed for this tree. All nodes having depth greater than max level will be deleted.\n\n  */\n  prune: function(tree, maxLevel) {\n    this.each(tree, function(elem, i) {\n      if (i == maxLevel && elem.children) {\n        delete elem.children;\n        elem.children = [];\n      }\n    });\n  },\n  /*\n     Method: getParent\n\n     Returns the parent node of the node having _id_ as id.\n\n     Parameters:\n\n        tree - (object) A JSON tree object. See also <Loader.loadJSON>.\n        id - (string) The _id_ of the child node whose parent will be returned.\n\n    Returns:\n\n        A tree JSON node if any, or false otherwise.\n\n  */\n  getParent: function(tree, id) {\n    if (tree.id == id)\n      return false;\n    var ch = tree.children;\n    if (ch && ch.length > 0) {\n      for ( var i = 0; i < ch.length; i++) {\n        if (ch[i].id == id)\n          return tree;\n        else {\n          var ans = this.getParent(ch[i], id);\n          if (ans)\n            return ans;\n        }\n      }\n    }\n    return false;\n  },\n  /*\n     Method: getSubtree\n\n     Returns the subtree that matches the given id.\n\n     Parameters:\n\n        tree - (object) A JSON tree object. See also <Loader.loadJSON>.\n        id - (string) A node *unique* identifier.\n\n     Returns:\n\n        A subtree having a root node matching the given id. Returns null if no subtree matching the id is found.\n\n  */\n  getSubtree: function(tree, id) {\n    if (tree.id == id)\n      return tree;\n    for ( var i = 0, ch = tree.children; i < ch.length; i++) {\n      var t = this.getSubtree(ch[i], id);\n      if (t != null)\n        return t;\n    }\n    return null;\n  },\n  /*\n     Method: eachLevel\n\n      Iterates on tree nodes with relative depth less or equal than a specified level.\n\n     Parameters:\n\n        tree - (object) A JSON tree or subtree. See also <Loader.loadJSON>.\n        initLevel - (number) An integer specifying the initial relative level. Usually zero.\n        toLevel - (number) An integer specifying a top level. This method will iterate only through nodes with depth less than or equal this number.\n        action - (function) A function that receives a node and an integer specifying the actual level of the node.\n\n    Example:\n   (start code js)\n     $jit.json.eachLevel(tree, 0, 3, function(node, depth) {\n        alert(node.name + ' ' + depth);\n     });\n   (end code)\n  */\n  eachLevel: function(tree, initLevel, toLevel, action) {\n    if (initLevel <= toLevel) {\n      action(tree, initLevel);\n      if(!tree.children) return;\n      for ( var i = 0, ch = tree.children; i < ch.length; i++) {\n        this.eachLevel(ch[i], initLevel + 1, toLevel, action);\n      }\n    }\n  },\n  /*\n     Method: each\n\n      A JSON tree iterator.\n\n     Parameters:\n\n        tree - (object) A JSON tree or subtree. See also <Loader.loadJSON>.\n        action - (function) A function that receives a node.\n\n    Example:\n    (start code js)\n      $jit.json.each(tree, function(node) {\n        alert(node.name);\n      });\n    (end code)\n\n  */\n  each: function(tree, action) {\n    this.eachLevel(tree, 0, Number.MAX_VALUE, action);\n  }\n};\n\n\n/*\n     An object containing multiple type of transformations.\n*/\n\n$jit.Trans = {\n  $extend: true,\n\n  linear: function(p){\n    return p;\n  }\n};\n\nvar Trans = $jit.Trans;\n\n(function(){\n\n  var makeTrans = function(transition, params){\n    params = $.splat(params);\n    return $.extend(transition, {\n      easeIn: function(pos){\n        return transition(pos, params);\n      },\n      easeOut: function(pos){\n        return 1 - transition(1 - pos, params);\n      },\n      easeInOut: function(pos){\n        return (pos <= 0.5)? transition(2 * pos, params) / 2 : (2 - transition(\n            2 * (1 - pos), params)) / 2;\n      }\n    });\n  };\n\n  var transitions = {\n\n    Pow: function(p, x){\n      return Math.pow(p, x[0] || 6);\n    },\n\n    Expo: function(p){\n      return Math.pow(2, 8 * (p - 1));\n    },\n\n    Circ: function(p){\n      return 1 - Math.sin(Math.acos(p));\n    },\n\n    Sine: function(p){\n      return 1 - Math.sin((1 - p) * Math.PI / 2);\n    },\n\n    Back: function(p, x){\n      x = x[0] || 1.618;\n      return Math.pow(p, 2) * ((x + 1) * p - x);\n    },\n\n    Bounce: function(p){\n      var value;\n      for ( var a = 0, b = 1; 1; a += b, b /= 2) {\n        if (p >= (7 - 4 * a) / 11) {\n          value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);\n          break;\n        }\n      }\n      return value;\n    },\n\n    Elastic: function(p, x){\n      return Math.pow(2, 10 * --p)\n          * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);\n    }\n\n  };\n\n  $.each(transitions, function(val, key){\n    Trans[key] = makeTrans(val);\n  });\n\n  $.each( [\n      'Quad', 'Cubic', 'Quart', 'Quint'\n  ], function(elem, i){\n    Trans[elem] = makeTrans(function(p){\n      return Math.pow(p, [\n        i + 2\n      ]);\n    });\n  });\n\n})();\n\n/*\n   A Class that can perform animations for generic objects.\n\n   If you are looking for animation transitions please take a look at the <Trans> object.\n\n   Used by:\n\n   <Graph.Plot>\n\n   Based on:\n\n   The Animation class is based in the MooTools Framework <http://mootools.net>. Copyright (c) 2006-2009 Valerio Proietti, <http://mad4milk.net/>. MIT license <http://mootools.net/license.txt>.\n\n*/\n\nvar Animation = new Class( {\n\n  initialize: function(options){\n    this.setOptions(options);\n  },\n\n  setOptions: function(options){\n    var opt = {\n      duration: 2500,\n      fps: 40,\n      transition: Trans.Quart.easeInOut,\n      compute: $.empty,\n      complete: $.empty,\n      link: 'ignore'\n    };\n    this.opt = $.merge(opt, options || {});\n    return this;\n  },\n\n  step: function(){\n    var time = $.time(), opt = this.opt;\n    if (time < this.time + opt.duration) {\n      var delta = opt.transition((time - this.time) / opt.duration);\n      opt.compute(delta);\n    } else {\n      this.timer = clearInterval(this.timer);\n      opt.compute(1);\n      opt.complete();\n    }\n  },\n\n  start: function(){\n    if (!this.check())\n      return this;\n    this.time = 0;\n    this.startTimer();\n    return this;\n  },\n\n  startTimer: function(){\n    var that = this, fps = this.opt.fps;\n    if (this.timer)\n      return false;\n    this.time = $.time() - this.time;\n    this.timer = setInterval((function(){\n      that.step();\n    }), Math.round(1000 / fps));\n    return true;\n  },\n\n  pause: function(){\n    this.stopTimer();\n    return this;\n  },\n\n  resume: function(){\n    this.startTimer();\n    return this;\n  },\n\n  stopTimer: function(){\n    if (!this.timer)\n      return false;\n    this.time = $.time() - this.time;\n    this.timer = clearInterval(this.timer);\n    return true;\n  },\n\n  check: function(){\n    if (!this.timer)\n      return true;\n    if (this.opt.link == 'cancel') {\n      this.stopTimer();\n      return true;\n    }\n    return false;\n  }\n});\n\n\nvar Options = function() {\n  var args = arguments;\n  for(var i=0, l=args.length, ans={}; i<l; i++) {\n    var opt = Options[args[i]];\n    if(opt.$extend) {\n      $.extend(ans, opt);\n    } else {\n      ans[args[i]] = opt;\n    }\n  }\n  return ans;\n};\n\n/*\n * File: Options.AreaChart.js\n *\n*/\n\n/*\n  Object: Options.AreaChart\n\n  <AreaChart> options.\n  Other options included in the AreaChart are <Options.Canvas>, <Options.Label>, <Options.Tips> and <Options.Events>.\n\n  Syntax:\n\n  (start code js)\n\n  Options.AreaChart = {\n    animate: true,\n    offset: 25,\n    labelOffset: 3,\n    type: 'stacked',\n    selectOnHover: true,\n    showAggregates: true,\n    showLabels: true,\n    filterOnClick: false,\n    restoreOnRightClick: false\n  };\n\n  (end code)\n\n  Example:\n\n  (start code js)\n\n  var areaChart = new $jit.AreaChart({\n    animate: true,\n    type: 'stacked:gradient',\n    selectOnHover: true,\n    filterOnClick: true,\n    restoreOnRightClick: true\n  });\n\n  (end code)\n\n  Parameters:\n\n  animate - (boolean) Default's *true*. Whether to add animated transitions when filtering/restoring stacks.\n  offset - (number) Default's *25*. Adds margin between the visualization and the canvas.\n  labelOffset - (number) Default's *3*. Adds margin between the label and the default place where it should be drawn.\n  type - (string) Default's *'stacked'*. Stack style. Posible values are 'stacked', 'stacked:gradient' to add gradients.\n  selectOnHover - (boolean) Default's *true*. If true, it will add a mark to the hovered stack.\n  showAggregates - (boolean) Default's *true*. Display the sum of the values of the different stacks.\n  showLabels - (boolean) Default's *true*. Display the name of the slots.\n  filterOnClick - (boolean) Default's *true*. Select the clicked stack by hiding all other stacks.\n  restoreOnRightClick - (boolean) Default's *true*. Show all stacks by right clicking.\n\n*/\n\nOptions.AreaChart = {\n  $extend: true,\n\n  animate: true,\n  offset: 25, // page offset\n  labelOffset: 3, // label offset\n  type: 'stacked', // gradient\n  Tips: {\n    enable: false,\n    onShow: $.empty,\n    onHide: $.empty\n  },\n  Events: {\n    enable: false,\n    onClick: $.empty\n  },\n  selectOnHover: true,\n  showAggregates: true,\n  showLabels: true,\n  filterOnClick: false,\n  restoreOnRightClick: false\n};\n\n/*\n * File: Options.Canvas.js\n *\n*/\n\n/*\n  Object: Options.Canvas\n\n  These are Canvas general options, like where to append it in the DOM, its dimensions, background,\n  and other more advanced options.\n\n  Syntax:\n\n  (start code js)\n\n  Options.Canvas = {\n    injectInto: 'id',\n    width: false,\n    height: false,\n    useCanvas: false,\n    withLabels: true,\n    background: false\n  };\n  (end code)\n\n  Example:\n\n  (start code js)\n  var viz = new $jit.Viz({\n    injectInto: 'someContainerId',\n    width: 500,\n    height: 700\n  });\n  (end code)\n\n  Parameters:\n\n  injectInto - *required* (string|element) The id of the DOM container for the visualization. It can also be an Element provided that it has an id.\n  width - (number) Default's to the *container's offsetWidth*. The width of the canvas.\n  height - (number) Default's to the *container's offsetHeight*. The height of the canvas.\n  useCanvas - (boolean|object) Default's *false*. You can pass another <Canvas> instance to be used by the visualization.\n  withLabels - (boolean) Default's *true*. Whether to use a label container for the visualization.\n  background - (boolean|object) Default's *false*. An object containing information about the rendering of a background canvas.\n*/\n\nOptions.Canvas = {\n    $extend: true,\n\n    injectInto: 'id',\n    width: false,\n    height: false,\n    useCanvas: false,\n    withLabels: true,\n    background: false\n};\n\n/*\n * File: Options.Tree.js\n *\n*/\n\n/*\n  Object: Options.Tree\n\n  Options related to (strict) Tree layout algorithms. These options are used by the <ST> visualization.\n\n  Syntax:\n\n  (start code js)\n  Options.Tree = {\n    orientation: \"left\",\n    subtreeOffset: 8,\n    siblingOffset: 5,\n    indent:10,\n    multitree: false,\n    align:\"center\"\n  };\n  (end code)\n\n  Example:\n\n  (start code js)\n  var st = new $jit.ST({\n    orientation: 'left',\n    subtreeOffset: 1,\n    siblingOFfset: 5,\n    multitree: true\n  });\n  (end code)\n\n  Parameters:\n\n  subtreeOffset - (number) Default's 8. Separation offset between subtrees.\n  siblingOffset - (number) Default's 5. Separation offset between siblings.\n  orientation - (string) Default's 'left'. Tree orientation layout. Possible values are 'left', 'top', 'right', 'bottom'.\n  align - (string) Default's *center*. Whether the tree alignment is 'left', 'center' or 'right'.\n  indent - (number) Default's 10. Used when *align* is left or right and shows an indentation between parent and children.\n  multitree - (boolean) Default's *false*. Used with the node $orn data property for creating multitrees.\n\n*/\nOptions.Tree = {\n    $extend: true,\n\n    orientation: \"left\",\n    subtreeOffset: 8,\n    siblingOffset: 5,\n    indent:10,\n    multitree: false,\n    align:\"center\"\n};\n\n\n/*\n * File: Options.Node.js\n *\n*/\n\n/*\n  Object: Options.Node\n\n  Provides Node rendering options for Tree and Graph based visualizations.\n\n  Syntax:\n\n  (start code js)\n  Options.Node = {\n    overridable: false,\n    type: 'circle',\n    color: '#ccb',\n    alpha: 1,\n    dim: 3,\n    height: 20,\n    width: 90,\n    autoHeight: false,\n    autoWidth: false,\n    lineWidth: 1,\n    transform: true,\n    align: \"center\",\n    angularWidth:1,\n    span:1,\n    CanvasStyles: {}\n  };\n  (end code)\n\n  Example:\n\n  (start code js)\n  var viz = new $jit.Viz({\n    Node: {\n      overridable: true,\n      width: 30,\n      autoHeight: true,\n      type: 'rectangle'\n    }\n  });\n  (end code)\n\n  Parameters:\n\n  overridable - (boolean) Default's *false*. Determine whether or not general node properties can be overridden by a particular <Graph.Node>.\n  type - (string) Default's *circle*. Node's shape. Node built-in types include 'circle', 'rectangle', 'square', 'ellipse', 'triangle', 'star'. The default Node type might vary in each visualization. You can also implement (non built-in) custom Node types into your visualizations.\n  color - (string) Default's *#ccb*. Node color.\n  alpha - (number) Default's *1*. The Node's alpha value. *1* is for full opacity.\n  dim - (number) Default's *3*. An extra parameter used by other node shapes such as circle or square, to determine the shape's diameter.\n  height - (number) Default's *20*. Used by 'rectangle' and 'ellipse' node types. The height of the node shape.\n  width - (number) Default's *90*. Used by 'rectangle' and 'ellipse' node types. The width of the node shape.\n  autoHeight - (boolean) Default's *false*. Whether to set an auto height for the node depending on the content of the Node's label.\n  autoWidth - (boolean) Default's *false*. Whether to set an auto width for the node depending on the content of the Node's label.\n  lineWidth - (number) Default's *1*. Used only by some Node shapes. The line width of the strokes of a node.\n  transform - (boolean) Default's *true*. Only used by the <Hypertree> visualization. Whether to scale the nodes according to the moebius transformation.\n  align - (string) Default's *center*. Possible values are 'center', 'left' or 'right'. Used only by the <ST> visualization, these parameters are used for aligning nodes when some of they dimensions vary.\n  angularWidth - (number) Default's *1*. Used in radial layouts (like <RGraph> or <Sunburst> visualizations). The amount of relative 'space' set for a node.\n  span - (number) Default's *1*. Used in radial layouts (like <RGraph> or <Sunburst> visualizations). The angle span amount set for a node.\n  CanvasStyles - (object) Default's an empty object (i.e. {}). Attach any other canvas specific property that you'd set to the canvas context before plotting a Node.\n\n*/\nOptions.Node = {\n  $extend: false,\n\n  overridable: false,\n  type: 'circle',\n  color: '#ccb',\n  alpha: 1,\n  dim: 3,\n  height: 20,\n  width: 90,\n  autoHeight: false,\n  autoWidth: false,\n  lineWidth: 1,\n  transform: true,\n  align: \"center\",\n  angularWidth:1,\n  span:1,\n  //Raw canvas styles to be\n  //applied to the context instance\n  //before plotting a node\n  CanvasStyles: {}\n};\n\n\n/*\n * File: Options.Edge.js\n *\n*/\n\n/*\n  Object: Options.Edge\n\n  Provides Edge rendering options for Tree and Graph based visualizations.\n\n  Syntax:\n\n  (start code js)\n  Options.Edge = {\n    overridable: false,\n    type: 'line',\n    color: '#ccb',\n    lineWidth: 1,\n    dim:15,\n    alpha: 1,\n    CanvasStyles: {}\n  };\n  (end code)\n\n  Example:\n\n  (start code js)\n  var viz = new $jit.Viz({\n    Edge: {\n      overridable: true,\n      type: 'line',\n      color: '#fff',\n      CanvasStyles: {\n        shadowColor: '#ccc',\n        shadowBlur: 10\n      }\n    }\n  });\n  (end code)\n\n  Parameters:\n\n   overridable - (boolean) Default's *false*. Determine whether or not general edges properties can be overridden by a particular <Graph.Adjacence>.\n   type - (string) Default's 'line'. Edge styles include 'line', 'hyperline', 'arrow'. The default Edge type might vary in each visualization. You can also implement custom Edge types.\n   color - (string) Default's '#ccb'. Edge color.\n   lineWidth - (number) Default's *1*. Line/Edge width.\n   alpha - (number) Default's *1*. The Edge's alpha value. *1* is for full opacity.\n   dim - (number) Default's *15*. An extra parameter used by other complex shapes such as quadratic, bezier or arrow, to determine the shape's diameter.\n   CanvasStyles - (object) Default's an empty object (i.e. {}). Attach any other canvas specific property that you'd set to the canvas context before plotting an Edge.\n\n  See also:\n\n   If you want to know more about how to customize Node/Edge data per element, in the JSON or programmatically, take a look at this article.\n*/\nOptions.Edge = {\n  $extend: false,\n\n  overridable: false,\n  type: 'line',\n  color: '#ccb',\n  lineWidth: 1,\n  dim:15,\n  alpha: 1,\n\n  //Raw canvas styles to be\n  //applied to the context instance\n  //before plotting an edge\n  CanvasStyles: {}\n};\n\n\n/*\n * File: Options.Fx.js\n *\n*/\n\n/*\n  Object: Options.Fx\n\n  Provides animation options like duration of the animations, frames per second and animation transitions.\n\n  Syntax:\n\n  (start code js)\n    Options.Fx = {\n      fps:40,\n      duration: 2500,\n      transition: $jit.Trans.Quart.easeInOut,\n      clearCanvas: true\n    };\n  (end code)\n\n  Example:\n\n  (start code js)\n  var viz = new $jit.Viz({\n    duration: 1000,\n    fps: 35,\n    transition: $jit.Trans.linear\n  });\n  (end code)\n\n  Parameters:\n\n  clearCanvas - (boolean) Default's *true*. Whether to clear the frame/canvas when the viz is plotted or animated.\n  duration - (number) Default's *2500*. Duration of the animation in milliseconds.\n  fps - (number) Default's *40*. Frames per second.\n  transition - (object) Default's *$jit.Trans.Quart.easeInOut*. The transition used for the animations. See below for a more detailed explanation.\n\n  Object: $jit.Trans\n\n  This object is used for specifying different animation transitions in all visualizations.\n\n  There are many different type of animation transitions.\n\n  linear:\n\n  Displays a linear transition\n\n  >Trans.linear\n\n  (see Linear.png)\n\n  Quad:\n\n  Displays a Quadratic transition.\n\n  >Trans.Quad.easeIn\n  >Trans.Quad.easeOut\n  >Trans.Quad.easeInOut\n\n (see Quad.png)\n\n Cubic:\n\n Displays a Cubic transition.\n\n >Trans.Cubic.easeIn\n >Trans.Cubic.easeOut\n >Trans.Cubic.easeInOut\n\n (see Cubic.png)\n\n Quart:\n\n Displays a Quartetic transition.\n\n >Trans.Quart.easeIn\n >Trans.Quart.easeOut\n >Trans.Quart.easeInOut\n\n (see Quart.png)\n\n Quint:\n\n Displays a Quintic transition.\n\n >Trans.Quint.easeIn\n >Trans.Quint.easeOut\n >Trans.Quint.easeInOut\n\n (see Quint.png)\n\n Expo:\n\n Displays an Exponential transition.\n\n >Trans.Expo.easeIn\n >Trans.Expo.easeOut\n >Trans.Expo.easeInOut\n\n (see Expo.png)\n\n Circ:\n\n Displays a Circular transition.\n\n >Trans.Circ.easeIn\n >Trans.Circ.easeOut\n >Trans.Circ.easeInOut\n\n (see Circ.png)\n\n Sine:\n\n Displays a Sineousidal transition.\n\n >Trans.Sine.easeIn\n >Trans.Sine.easeOut\n >Trans.Sine.easeInOut\n\n (see Sine.png)\n\n Back:\n\n >Trans.Back.easeIn\n >Trans.Back.easeOut\n >Trans.Back.easeInOut\n\n (see Back.png)\n\n Bounce:\n\n Bouncy transition.\n\n >Trans.Bounce.easeIn\n >Trans.Bounce.easeOut\n >Trans.Bounce.easeInOut\n\n (see Bounce.png)\n\n Elastic:\n\n Elastic curve.\n\n >Trans.Elastic.easeIn\n >Trans.Elastic.easeOut\n >Trans.Elastic.easeInOut\n\n (see Elastic.png)\n\n Based on:\n\n Easing and Transition animation methods are based in the MooTools Framework <http://mootools.net>. Copyright (c) 2006-2010 Valerio Proietti, <http://mad4milk.net/>. MIT license <http://mootools.net/license.txt>.\n\n\n*/\nOptions.Fx = {\n  $extend: true,\n\n  fps:40,\n  duration: 2500,\n  transition: $jit.Trans.Quart.easeInOut,\n  clearCanvas: true\n};\n\n/*\n * File: Options.Label.js\n *\n*/\n/*\n  Object: Options.Label\n\n  Provides styling for Labels such as font size, family, etc. Also sets Node labels as HTML, SVG or Native canvas elements.\n\n  Syntax:\n\n  (start code js)\n    Options.Label = {\n      overridable: false,\n      type: 'HTML', //'SVG', 'Native'\n      style: ' ',\n      size: 10,\n      family: 'sans-serif',\n      textAlign: 'center',\n      textBaseline: 'alphabetic',\n      color: '#fff'\n    };\n  (end code)\n\n  Example:\n\n  (start code js)\n  var viz = new $jit.Viz({\n    Label: {\n      type: 'Native',\n      size: 11,\n      color: '#ccc'\n    }\n  });\n  (end code)\n\n  Parameters:\n\n  overridable - (boolean) Default's *false*. Determine whether or not general label properties can be overridden by a particular <Graph.Node>.\n  type - (string) Default's *HTML*. The type for the labels. Can be 'HTML', 'SVG' or 'Native' canvas labels.\n  style - (string) Default's *empty string*. Can be 'italic' or 'bold'. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.\n  size - (number) Default's *10*. The font's size. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.\n  family - (string) Default's *sans-serif*. The font's family. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.\n  color - (string) Default's *#fff*. The font's color. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.\n*/\nOptions.Label = {\n  $extend: false,\n\n  overridable: false,\n  type: 'HTML', //'SVG', 'Native'\n  style: ' ',\n  size: 10,\n  family: 'sans-serif',\n  textAlign: 'center',\n  textBaseline: 'alphabetic',\n  color: '#fff'\n};\n\n\n/*\n * File: Options.Tips.js\n *\n */\n\n/*\n  Object: Options.Tips\n\n  Tips options\n\n  Syntax:\n\n  (start code js)\n  Options.Tips = {\n    enable: false,\n    type: 'auto',\n    offsetX: 20,\n    offsetY: 20,\n    onShow: $.empty,\n    onHide: $.empty\n  };\n  (end code)\n\n  Example:\n\n  (start code js)\n  var viz = new $jit.Viz({\n    Tips: {\n      enable: true,\n      type: 'Native',\n      offsetX: 10,\n      offsetY: 10,\n      onShow: function(tip, node) {\n        tip.innerHTML = node.name;\n      }\n    }\n  });\n  (end code)\n\n  Parameters:\n\n  enable - (boolean) Default's *false*. If *true*, a tooltip will be shown when a node is hovered. The tooltip is a div DOM element having \"tip\" as CSS class.\n  type - (string) Default's *auto*. Defines where to attach the MouseEnter/Leave tooltip events. Possible values are 'Native' to attach them to the canvas or 'HTML' to attach them to DOM label elements (if defined). 'auto' sets this property to the value of <Options.Label>'s *type* property.\n  offsetX - (number) Default's *20*. An offset added to the current tooltip x-position (which is the same as the current mouse position). Default's 20.\n  offsetY - (number) Default's *20*. An offset added to the current tooltip y-position (which is the same as the current mouse position). Default's 20.\n  onShow(tip, node) - This callack is used right before displaying a tooltip. The first formal parameter is the tip itself (which is a DivElement). The second parameter may be a <Graph.Node> for graph based visualizations or an object with label, value properties for charts.\n  onHide() - This callack is used when hiding a tooltip.\n\n*/\nOptions.Tips = {\n  $extend: false,\n\n  enable: false,\n  type: 'auto',\n  offsetX: 20,\n  offsetY: 20,\n  force: false,\n  onShow: $.empty,\n  onHide: $.empty\n};\n\n\n/*\n * File: Options.NodeStyles.js\n *\n */\n\n/*\n  Object: Options.NodeStyles\n\n  Apply different styles when a node is hovered or selected.\n\n  Syntax:\n\n  (start code js)\n  Options.NodeStyles = {\n    enable: false,\n    type: 'auto',\n    stylesHover: false,\n    stylesClick: false\n  };\n  (end code)\n\n  Example:\n\n  (start code js)\n  var viz = new $jit.Viz({\n    NodeStyles: {\n      enable: true,\n      type: 'Native',\n      stylesHover: {\n        dim: 30,\n        color: '#fcc'\n      },\n      duration: 600\n    }\n  });\n  (end code)\n\n  Parameters:\n\n  enable - (boolean) Default's *false*. Whether to enable this option.\n  type - (string) Default's *auto*. Use this to attach the hover/click events in the nodes or the nodes labels (if they have been defined as DOM elements: 'HTML' or 'SVG', see <Options.Label> for more details). The default 'auto' value will set NodeStyles to the same type defined for <Options.Label>.\n  stylesHover - (boolean|object) Default's *false*. An object with node styles just like the ones defined for <Options.Node> or *false* otherwise.\n  stylesClick - (boolean|object) Default's *false*. An object with node styles just like the ones defined for <Options.Node> or *false* otherwise.\n*/\n\nOptions.NodeStyles = {\n  $extend: false,\n\n  enable: false,\n  type: 'auto',\n  stylesHover: false,\n  stylesClick: false\n};\n\n\n/*\n * File: Options.Events.js\n *\n*/\n\n/*\n  Object: Options.Events\n\n  Configuration for adding mouse/touch event handlers to Nodes.\n\n  Syntax:\n\n  (start code js)\n  Options.Events = {\n    enable: false,\n    type: 'auto',\n    onClick: $.empty,\n    onRightClick: $.empty,\n    onMouseMove: $.empty,\n    onMouseEnter: $.empty,\n    onMouseLeave: $.empty,\n    onDragStart: $.empty,\n    onDragMove: $.empty,\n    onDragCancel: $.empty,\n    onDragEnd: $.empty,\n    onTouchStart: $.empty,\n    onTouchMove: $.empty,\n    onTouchEnd: $.empty,\n    onTouchCancel: $.empty,\n    onMouseWheel: $.empty\n  };\n  (end code)\n\n  Example:\n\n  (start code js)\n  var viz = new $jit.Viz({\n    Events: {\n      enable: true,\n      onClick: function(node, eventInfo, e) {\n        viz.doSomething();\n      },\n      onMouseEnter: function(node, eventInfo, e) {\n        viz.canvas.getElement().style.cursor = 'pointer';\n      },\n      onMouseLeave: function(node, eventInfo, e) {\n        viz.canvas.getElement().style.cursor = '';\n      }\n    }\n  });\n  (end code)\n\n  Parameters:\n\n  enable - (boolean) Default's *false*. Whether to enable the Event system.\n  type - (string) Default's 'auto'. Whether to attach the events onto the HTML labels (via event delegation) or to use the custom 'Native' canvas Event System of the library. 'auto' is set when you let the <Options.Label> *type* parameter decide this.\n  onClick(node, eventInfo, e) - Triggered when a user performs a click in the canvas. *node* is the <Graph.Node> clicked or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.\n  onRightClick(node, eventInfo, e) - Triggered when a user performs a right click in the canvas. *node* is the <Graph.Node> right clicked or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.\n  onMouseMove(node, eventInfo, e) - Triggered when the user moves the mouse. *node* is the <Graph.Node> under the cursor as it's moving over the canvas or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner).  *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.\n  onMouseEnter(node, eventInfo, e) - Triggered when a user moves the mouse over a node. *node* is the <Graph.Node> that the mouse just entered. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.\n  onMouseLeave(node, eventInfo, e) - Triggered when the user mouse-outs a node. *node* is the <Graph.Node> 'mouse-outed'. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.\n  onDragStart(node, eventInfo, e) - Triggered when the user mouse-downs over a node. *node* is the <Graph.Node> being pressed. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.\n  onDragMove(node, eventInfo, e) - Triggered when a user, after pressing the mouse button over a node, moves the mouse around. *node* is the <Graph.Node> being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.\n  onDragEnd(node, eventInfo, e) - Triggered when a user finished dragging a node. *node* is the <Graph.Node> being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.\n  onDragCancel(node, eventInfo, e) - Triggered when the user releases the mouse button over a <Graph.Node> that wasn't dragged (i.e. the user didn't perform any mouse movement after pressing the mouse button). *node* is the <Graph.Node> being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.\n  onTouchStart(node, eventInfo, e) - Behaves just like onDragStart.\n  onTouchMove(node, eventInfo, e) - Behaves just like onDragMove.\n  onTouchEnd(node, eventInfo, e) - Behaves just like onDragEnd.\n  onTouchCancel(node, eventInfo, e) - Behaves just like onDragCancel.\n  onMouseWheel(delta, e) - Triggered when the user uses the mouse scroll over the canvas. *delta* is 1 or -1 depending on the sense of the mouse scroll.\n*/\n\nOptions.Events = {\n  $extend: false,\n\n  enable: false,\n  type: 'auto',\n  onClick: $.empty,\n  onRightClick: $.empty,\n  onMouseMove: $.empty,\n  onMouseEnter: $.empty,\n  onMouseLeave: $.empty,\n  onDragStart: $.empty,\n  onDragMove: $.empty,\n  onDragCancel: $.empty,\n  onDragEnd: $.empty,\n  onTouchStart: $.empty,\n  onTouchMove: $.empty,\n  onTouchEnd: $.empty,\n  onMouseWheel: $.empty\n};\n\n/*\n * File: Options.Navigation.js\n *\n*/\n\n/*\n  Object: Options.Navigation\n\n  Panning and zooming options for Graph/Tree based visualizations. These options are implemented\n  by all visualizations except charts (<AreaChart>, <BarChart> and <PieChart>).\n\n  Syntax:\n\n  (start code js)\n\n  Options.Navigation = {\n    enable: false,\n    type: 'auto',\n    panning: false, //true, 'avoid nodes'\n    zooming: false\n  };\n\n  (end code)\n\n  Example:\n\n  (start code js)\n  var viz = new $jit.Viz({\n    Navigation: {\n      enable: true,\n      panning: 'avoid nodes',\n      zooming: 20\n    }\n  });\n  (end code)\n\n  Parameters:\n\n  enable - (boolean) Default's *false*. Whether to enable Navigation capabilities.\n  panning - (boolean|string) Default's *false*. Set this property to *true* if you want to add Drag and Drop panning support to the visualization. You can also set this parameter to 'avoid nodes' to enable DnD panning but disable it if the DnD is taking place over a node. This is useful when some other events like Drag & Drop for nodes are added to <Graph.Nodes>.\n  zooming - (boolean|number) Default's *false*. Set this property to a numeric value to turn mouse-scroll zooming on. The number will be proportional to the mouse-scroll sensitivity.\n\n*/\n\nOptions.Navigation = {\n  $extend: false,\n\n  enable: false,\n  type: 'auto',\n  panning: false, //true | 'avoid nodes'\n  zooming: false\n};\n\n/*\n * File: Options.Controller.js\n *\n*/\n\n/*\n  Object: Options.Controller\n\n  Provides controller methods. Controller methods are callback functions that get called at different stages\n  of the animation, computing or plotting of the visualization.\n\n  Implemented by:\n\n  All visualizations except charts (<AreaChart>, <BarChart> and <PieChart>).\n\n  Syntax:\n\n  (start code js)\n\n  Options.Controller = {\n    onBeforeCompute: $.empty,\n    onAfterCompute:  $.empty,\n    onCreateLabel:   $.empty,\n    onPlaceLabel:    $.empty,\n    onComplete:      $.empty,\n    onBeforePlotLine:$.empty,\n    onAfterPlotLine: $.empty,\n    onBeforePlotNode:$.empty,\n    onAfterPlotNode: $.empty,\n    request:         false\n  };\n\n  (end code)\n\n  Example:\n\n  (start code js)\n  var viz = new $jit.Viz({\n    onBeforePlotNode: function(node) {\n      if(node.selected) {\n        node.setData('color', '#ffc');\n      } else {\n        node.removeData('color');\n      }\n    },\n    onBeforePlotLine: function(adj) {\n      if(adj.nodeFrom.selected && adj.nodeTo.selected) {\n        adj.setData('color', '#ffc');\n      } else {\n        adj.removeData('color');\n      }\n    },\n    onAfterCompute: function() {\n      alert(\"computed!\");\n    }\n  });\n  (end code)\n\n  Parameters:\n\n   onBeforeCompute(node) - This method is called right before performing all computations and animations. The selected <Graph.Node> is passed as parameter.\n   onAfterCompute() - This method is triggered after all animations or computations ended.\n   onCreateLabel(domElement, node) - This method receives a new label DIV element as first parameter, and the corresponding <Graph.Node> as second parameter. This method will only be called once for each label. This method is useful when adding events or styles to the labels used by the JIT.\n   onPlaceLabel(domElement, node) - This method receives a label DIV element as first parameter and the corresponding <Graph.Node> as second parameter. This method is called each time a label has been placed in the visualization, for example at each step of an animation, and thus it allows you to update the labels properties, such as size or position. Note that onPlaceLabel will be triggered after updating the labels positions. That means that, for example, the left and top css properties are already updated to match the nodes positions. Width and height properties are not set however.\n   onBeforePlotNode(node) - This method is triggered right before plotting each <Graph.Node>. This method is useful for changing a node style right before plotting it.\n   onAfterPlotNode(node) - This method is triggered right after plotting each <Graph.Node>.\n   onBeforePlotLine(adj) - This method is triggered right before plotting a <Graph.Adjacence>. This method is useful for adding some styles to a particular edge before being plotted.\n   onAfterPlotLine(adj) - This method is triggered right after plotting a <Graph.Adjacence>.\n\n    *Used in <ST>, <TM.Base> and <Icicle> visualizations*\n\n    request(nodeId, level, onComplete) - This method is used for buffering information into the visualization. When clicking on an empty node, the visualization will make a request for this node's subtrees, specifying a given level for this subtree (defined by _levelsToShow_). Once the request is completed, the onComplete callback should be called with the given result. This is useful to provide on-demand information into the visualizations withought having to load the entire information from start. The parameters used by this method are _nodeId_, which is the id of the root of the subtree to request, _level_ which is the depth of the subtree to be requested (0 would mean just the root node). _onComplete_ is an object having the callback method _onComplete.onComplete(json)_ that should be called once the json has been retrieved.\n\n */\nOptions.Controller = {\n  $extend: true,\n\n  onBeforeCompute: $.empty,\n  onAfterCompute:  $.empty,\n  onCreateLabel:   $.empty,\n  onPlaceLabel:    $.empty,\n  onComplete:      $.empty,\n  onBeforePlotLine:$.empty,\n  onAfterPlotLine: $.empty,\n  onBeforePlotNode:$.empty,\n  onAfterPlotNode: $.empty,\n  request:         false\n};\n\n\n/*\n * File: Extras.js\n *\n * Provides Extras such as Tips and Style Effects.\n *\n * Description:\n *\n * Provides the <Tips> and <NodeStyles> classes and functions.\n *\n */\n\n/*\n * Manager for mouse events (clicking and mouse moving).\n *\n * This class is used for registering objects implementing onClick\n * and onMousemove methods. These methods are called when clicking or\n * moving the mouse around  the Canvas.\n * For now, <Tips> and <NodeStyles> are classes implementing these methods.\n *\n */\nvar ExtrasInitializer = {\n  initialize: function(className, viz) {\n    this.viz = viz;\n    this.canvas = viz.canvas;\n    this.config = viz.config[className];\n    this.nodeTypes = viz.fx.nodeTypes;\n    var type = this.config.type;\n    this.dom = type == 'auto'? (viz.config.Label.type != 'Native') : (type != 'Native');\n    this.labelContainer = this.dom && viz.labels.getLabelContainer();\n    this.isEnabled() && this.initializePost();\n  },\n  initializePost: $.empty,\n  setAsProperty: $.lambda(false),\n  isEnabled: function() {\n    return this.config.enable;\n  },\n  isLabel: function(e, win) {\n    e = $.event.get(e, win);\n    var labelContainer = this.labelContainer,\n        target = e.target || e.srcElement;\n    if(target && target.parentNode == labelContainer)\n      return target;\n    return false;\n  }\n};\n\nvar EventsInterface = {\n  onMouseUp: $.empty,\n  onMouseDown: $.empty,\n  onMouseMove: $.empty,\n  onMouseOver: $.empty,\n  onMouseOut: $.empty,\n  onMouseWheel: $.empty,\n  onTouchStart: $.empty,\n  onTouchMove: $.empty,\n  onTouchEnd: $.empty,\n  onTouchCancel: $.empty\n};\n\nvar MouseEventsManager = new Class({\n  initialize: function(viz) {\n    this.viz = viz;\n    this.canvas = viz.canvas;\n    this.node = false;\n    this.registeredObjects = [];\n    this.attachEvents();\n  },\n\n  attachEvents: function() {\n    var htmlCanvas = this.canvas.getElement(),\n        that = this;\n    htmlCanvas.oncontextmenu = $.lambda(false);\n    $.addEvents(htmlCanvas, {\n      'mouseup': function(e, win) {\n        var event = $.event.get(e, win);\n        that.handleEvent('MouseUp', e, win,\n            that.makeEventObject(e, win),\n            $.event.isRightClick(event));\n      },\n      'mousedown': function(e, win) {\n        var event = $.event.get(e, win);\n        that.handleEvent('MouseDown', e, win, that.makeEventObject(e, win),\n            $.event.isRightClick(event));\n      },\n      'mousemove': function(e, win) {\n        that.handleEvent('MouseMove', e, win, that.makeEventObject(e, win));\n      },\n      'mouseover': function(e, win) {\n        that.handleEvent('MouseOver', e, win, that.makeEventObject(e, win));\n      },\n      'mouseout': function(e, win) {\n        that.handleEvent('MouseOut', e, win, that.makeEventObject(e, win));\n      },\n      'touchstart': function(e, win) {\n        that.handleEvent('TouchStart', e, win, that.makeEventObject(e, win));\n      },\n      'touchmove': function(e, win) {\n        that.handleEvent('TouchMove', e, win, that.makeEventObject(e, win));\n      },\n      'touchend': function(e, win) {\n        that.handleEvent('TouchEnd', e, win, that.makeEventObject(e, win));\n      }\n    });\n    //attach mousewheel event\n    var handleMouseWheel = function(e, win) {\n      var event = $.event.get(e, win);\n      var wheel = $.event.getWheel(event);\n      that.handleEvent('MouseWheel', e, win, wheel);\n    };\n    //TODO(nico): this is a horrible check for non-gecko browsers!\n    if(!document.getBoxObjectFor && window.mozInnerScreenX == null) {\n      $.addEvent(htmlCanvas, 'mousewheel', handleMouseWheel);\n    } else {\n      htmlCanvas.addEventListener('DOMMouseScroll', handleMouseWheel, false);\n    }\n  },\n\n  register: function(obj) {\n    this.registeredObjects.push(obj);\n  },\n\n  handleEvent: function() {\n    var args = Array.prototype.slice.call(arguments),\n        type = args.shift();\n    for(var i=0, regs=this.registeredObjects, l=regs.length; i<l; i++) {\n      regs[i]['on' + type].apply(regs[i], args);\n    }\n  },\n\n  makeEventObject: function(e, win) {\n    var that = this,\n        graph = this.viz.graph,\n        fx = this.viz.fx,\n        types = fx.nodeTypes;\n    return {\n      pos: false,\n      node: false,\n      contains: false,\n      getNodeCalled: false,\n      getPos: function() {\n        if(this.pos) return this.pos;\n        var canvas = that.viz.canvas,\n            s = canvas.getSize(),\n            p = canvas.getPos(),\n            ox = canvas.translateOffsetX,\n            oy = canvas.translateOffsetY,\n            sx = canvas.scaleOffsetX,\n            sy = canvas.scaleOffsetY,\n            pos = $.event.getPos(e, win);\n        this.pos = {\n          x: (pos.x - p.x - s.width/2 - ox) * 1/sx,\n          y: (pos.y - p.y - s.height/2 - oy) * 1/sy\n        };\n        return this.pos;\n      },\n      getNode: function() {\n        if(this.getNodeCalled) return this.node;\n        this.getNodeCalled = true;\n        if(that.node) {\n          var n = graph.getNode(that.node),\n              geom = n && types[n.getData('type')],\n              contains = geom && geom.contains && geom.contains.call(fx, n, this.getPos());\n          if(contains) {\n            this.contains = contains;\n            return this.node = n;\n          }\n        }\n        for(var id in graph.nodes) {\n          var n = graph.nodes[id],\n              geom = n && types[n.getData('type')],\n              contains = geom && geom.contains && geom.contains.call(fx, n, this.getPos());\n          if(contains) {\n            this.contains = contains;\n            return that.node = this.node = n;\n          }\n        }\n        return that.node = this.node = false;\n      },\n      getContains: function() {\n        if(this.getNodeCalled) return this.contains;\n        this.getNode();\n        return this.contains;\n      }\n    };\n  }\n});\n\n/*\n * Provides the initialization function for <NodeStyles> and <Tips> implemented\n * by all main visualizations.\n *\n */\nvar Extras = {\n  initializeExtras: function() {\n    var mem = new MouseEventsManager(this), that = this;\n    $.each(['NodeStyles', 'Tips', 'Navigation', 'Events'], function(k) {\n      var obj = new Extras.Classes[k](k, that);\n      if(obj.isEnabled()) {\n        mem.register(obj);\n      }\n      if(obj.setAsProperty()) {\n        that[k.toLowerCase()] = obj;\n      }\n    });\n  }\n};\n\nExtras.Classes = {};\n/*\n  Class: Events\n\n  This class defines an Event API to be accessed by the user.\n  The methods implemented are the ones defined in the <Options.Events> object.\n*/\n\nExtras.Classes.Events = new Class({\n  Implements: [ExtrasInitializer, EventsInterface],\n\n  initializePost: function() {\n    this.fx = this.viz.fx;\n    this.types = this.viz.fx.nodeTypes;\n    this.hoveredNode = false;\n    this.pressedNode = false;\n    this.touchedNode = false;\n    this.touchMoved = false;\n    this.moved = false;\n  },\n\n  setAsProperty: $.lambda(true),\n\n  onMouseUp: function(e, win, event, isRightClick) {\n    var evt = $.event.get(e, win);\n    if(isRightClick) {\n      this.config.onRightClick(this.hoveredNode, event, evt);\n    } else {\n      this.config.onClick(this.pressedNode, event, evt);\n    }\n    if(this.pressedNode) {\n      if(this.moved) {\n        this.config.onDragEnd(this.pressedNode, event, evt);\n      } else {\n        this.config.onDragCancel(this.pressedNode, event, evt);\n      }\n      this.pressedNode = this.moved = false;\n    }\n  },\n\n  onMouseOut: function(e, win, event) {\n   //mouseout a label\n   var evt = $.event.get(e, win), label;\n   if(this.dom && (label = this.isLabel(e, win))) {\n     this.config.onMouseLeave(this.viz.graph.getNode(label.id),\n                              event, evt);\n     this.hoveredNode = false;\n     return;\n   }\n   //mouseout canvas\n   var rt = evt.relatedTarget,\n       canvasWidget = this.canvas.getElement();\n   while(rt && rt.parentNode) {\n     if(canvasWidget == rt.parentNode) return;\n     rt = rt.parentNode;\n   }\n   if(this.hoveredNode) {\n     this.config.onMouseLeave(this.hoveredNode,\n         event, evt);\n     this.hoveredNode = false;\n   }\n  },\n\n  onMouseOver: function(e, win, event) {\n    //mouseover a label\n    var evt = $.event.get(e, win), label;\n    if(this.dom && (label = this.isLabel(e, win))) {\n      this.hoveredNode = this.viz.graph.getNode(label.id);\n      this.config.onMouseEnter(this.hoveredNode,\n                               event, evt);\n    }\n  },\n\n  onMouseMove: function(e, win, event) {\n   var label, evt = $.event.get(e, win);\n   if(this.pressedNode) {\n     this.moved = true;\n     this.config.onDragMove(this.pressedNode, event, evt);\n     return;\n   }\n   if(this.dom) {\n     this.config.onMouseMove(this.hoveredNode,\n         event, evt);\n   } else {\n     if(this.hoveredNode) {\n       var hn = this.hoveredNode;\n       var geom = this.types[hn.getData('type')];\n       var contains = geom && geom.contains\n         && geom.contains.call(this.fx, hn, event.getPos());\n       if(contains) {\n         this.config.onMouseMove(hn, event, evt);\n         return;\n       } else {\n         this.config.onMouseLeave(hn, event, evt);\n         this.hoveredNode = false;\n       }\n     }\n     if(this.hoveredNode = event.getNode()) {\n       this.config.onMouseEnter(this.hoveredNode, event, evt);\n     } else {\n       this.config.onMouseMove(false, event, evt);\n     }\n   }\n  },\n\n  onMouseWheel: function(e, win, delta) {\n    this.config.onMouseWheel(delta, $.event.get(e, win));\n  },\n\n  onMouseDown: function(e, win, event) {\n    var evt = $.event.get(e, win);\n    this.pressedNode = event.getNode();\n    this.config.onDragStart(this.pressedNode, event, evt);\n  },\n\n  onTouchStart: function(e, win, event) {\n    var evt = $.event.get(e, win);\n    this.touchedNode = event.getNode();\n    this.config.onTouchStart(this.touchedNode, event, evt);\n  },\n\n  onTouchMove: function(e, win, event) {\n    var evt = $.event.get(e, win);\n    if(this.touchedNode) {\n      this.touchMoved = true;\n      this.config.onTouchMove(this.touchedNode, event, evt);\n    }\n  },\n\n  onTouchEnd: function(e, win, event) {\n    var evt = $.event.get(e, win);\n    if(this.touchedNode) {\n      if(this.touchMoved) {\n        this.config.onTouchEnd(this.touchedNode, event, evt);\n      } else {\n        this.config.onTouchCancel(this.touchedNode, event, evt);\n      }\n      this.touchedNode = this.touchMoved = false;\n    }\n  }\n});\n\n/*\n   Class: Tips\n\n   A class containing tip related functions. This class is used internally.\n\n   Used by:\n\n   <ST>, <Sunburst>, <Hypertree>, <RGraph>, <TM>, <ForceDirected>, <Icicle>\n\n   See also:\n\n   <Options.Tips>\n*/\n\nExtras.Classes.Tips = new Class({\n  Implements: [ExtrasInitializer, EventsInterface],\n\n  initializePost: function() {\n    //add DOM tooltip\n    if(document.body) {\n      var tip = $('_tooltip') || document.createElement('div');\n      tip.id = '_tooltip';\n      tip.className = 'tip';\n      $.extend(tip.style, {\n        position: 'absolute',\n        display: 'none',\n        zIndex: 13000\n      });\n      document.body.appendChild(tip);\n      this.tip = tip;\n      this.node = false;\n    }\n  },\n\n  setAsProperty: $.lambda(true),\n\n  onMouseOut: function(e, win) {\n    //mouseout a label\n    if(this.dom && this.isLabel(e, win)) {\n      this.hide(true);\n      return;\n    }\n    //mouseout canvas\n    var rt = e.relatedTarget,\n        canvasWidget = this.canvas.getElement();\n    while(rt && rt.parentNode) {\n      if(canvasWidget == rt.parentNode) return;\n      rt = rt.parentNode;\n    }\n    this.hide(false);\n  },\n\n  onMouseOver: function(e, win) {\n    //mouseover a label\n    var label;\n    if(this.dom && (label = this.isLabel(e, win))) {\n      this.node = this.viz.graph.getNode(label.id);\n      this.config.onShow(this.tip, this.node, label);\n    }\n  },\n\n  onMouseMove: function(e, win, opt) {\n    if(this.dom && this.isLabel(e, win)) {\n      this.setTooltipPosition($.event.getPos(e, win));\n    }\n    if(!this.dom) {\n      var node = opt.getNode();\n      if(!node) {\n        this.hide(true);\n        return;\n      }\n      if(this.config.force || !this.node || this.node.id != node.id) {\n        this.node = node;\n        this.config.onShow(this.tip, node, opt.getContains());\n      }\n      this.setTooltipPosition($.event.getPos(e, win));\n    }\n  },\n\n  setTooltipPosition: function(pos) {\n    var tip = this.tip,\n        style = tip.style,\n        cont = this.config;\n    style.display = '';\n    //get window dimensions\n    var win = {\n      'height': document.body.clientHeight,\n      'width': document.body.clientWidth\n    };\n    //get tooltip dimensions\n    var obj = {\n      'width': tip.offsetWidth,\n      'height': tip.offsetHeight\n    };\n    //set tooltip position\n    var x = cont.offsetX, y = cont.offsetY;\n    style.top = ((pos.y + y + obj.height > win.height)?\n        (pos.y - obj.height - y) : pos.y + y) + 'px';\n    style.left = ((pos.x + obj.width + x > win.width)?\n        (pos.x - obj.width - x) : pos.x + x) + 'px';\n  },\n\n  hide: function(triggerCallback) {\n    this.tip.style.display = 'none';\n    triggerCallback && this.config.onHide();\n  }\n});\n\n/*\n  Class: NodeStyles\n\n  Change node styles when clicking or hovering a node. This class is used internally.\n\n  Used by:\n\n  <ST>, <Sunburst>, <Hypertree>, <RGraph>, <TM>, <ForceDirected>, <Icicle>\n\n  See also:\n\n  <Options.NodeStyles>\n*/\nExtras.Classes.NodeStyles = new Class({\n  Implements: [ExtrasInitializer, EventsInterface],\n\n  initializePost: function() {\n    this.fx = this.viz.fx;\n    this.types = this.viz.fx.nodeTypes;\n    this.nStyles = this.config;\n    this.nodeStylesOnHover = this.nStyles.stylesHover;\n    this.nodeStylesOnClick = this.nStyles.stylesClick;\n    this.hoveredNode = false;\n    this.fx.nodeFxAnimation = new Animation();\n\n    this.down = false;\n    this.move = false;\n  },\n\n  onMouseOut: function(e, win) {\n    this.down = this.move = false;\n    if(!this.hoveredNode) return;\n    //mouseout a label\n    if(this.dom && this.isLabel(e, win)) {\n      this.toggleStylesOnHover(this.hoveredNode, false);\n    }\n    //mouseout canvas\n    var rt = e.relatedTarget,\n        canvasWidget = this.canvas.getElement();\n    while(rt && rt.parentNode) {\n      if(canvasWidget == rt.parentNode) return;\n      rt = rt.parentNode;\n    }\n    this.toggleStylesOnHover(this.hoveredNode, false);\n    this.hoveredNode = false;\n  },\n\n  onMouseOver: function(e, win) {\n    //mouseover a label\n    var label;\n    if(this.dom && (label = this.isLabel(e, win))) {\n      var node = this.viz.graph.getNode(label.id);\n      if(node.selected) return;\n      this.hoveredNode = node;\n      this.toggleStylesOnHover(this.hoveredNode, true);\n    }\n  },\n\n  onMouseDown: function(e, win, event, isRightClick) {\n    if(isRightClick) return;\n    var label;\n    if(this.dom && (label = this.isLabel(e, win))) {\n      this.down = this.viz.graph.getNode(label.id);\n    } else if(!this.dom) {\n      this.down = event.getNode();\n    }\n    this.move = false;\n  },\n\n  onMouseUp: function(e, win, event, isRightClick) {\n    if(isRightClick) return;\n    if(!this.move) {\n      this.onClick(event.getNode());\n    }\n    this.down = this.move = false;\n  },\n\n  getRestoredStyles: function(node, type) {\n    var restoredStyles = {},\n        nStyles = this['nodeStylesOn' + type];\n    for(var prop in nStyles) {\n      restoredStyles[prop] = node.styles['$' + prop];\n    }\n    return restoredStyles;\n  },\n\n  toggleStylesOnHover: function(node, set) {\n    if(this.nodeStylesOnHover) {\n      this.toggleStylesOn('Hover', node, set);\n    }\n  },\n\n  toggleStylesOnClick: function(node, set) {\n    if(this.nodeStylesOnClick) {\n      this.toggleStylesOn('Click', node, set);\n    }\n  },\n\n  toggleStylesOn: function(type, node, set) {\n    var viz = this.viz;\n    var nStyles = this.nStyles;\n    if(set) {\n      var that = this;\n      if(!node.styles) {\n        node.styles = $.merge(node.data, {});\n      }\n      for(var s in this['nodeStylesOn' + type]) {\n        var $s = '$' + s;\n        if(!($s in node.styles)) {\n            node.styles[$s] = node.getData(s);\n        }\n      }\n      viz.fx.nodeFx($.extend({\n        'elements': {\n          'id': node.id,\n          'properties': that['nodeStylesOn' + type]\n         },\n         transition: Trans.Quart.easeOut,\n         duration:300,\n         fps:40\n      }, this.config));\n    } else {\n      var restoredStyles = this.getRestoredStyles(node, type);\n      viz.fx.nodeFx($.extend({\n        'elements': {\n          'id': node.id,\n          'properties': restoredStyles\n         },\n         transition: Trans.Quart.easeOut,\n         duration:300,\n         fps:40\n      }, this.config));\n    }\n  },\n\n  onClick: function(node) {\n    if(!node) return;\n    var nStyles = this.nodeStylesOnClick;\n    if(!nStyles) return;\n    //if the node is selected then unselect it\n    if(node.selected) {\n      this.toggleStylesOnClick(node, false);\n      delete node.selected;\n    } else {\n      //unselect all selected nodes...\n      this.viz.graph.eachNode(function(n) {\n        if(n.selected) {\n          for(var s in nStyles) {\n            n.setData(s, n.styles['$' + s], 'end');\n          }\n          delete n.selected;\n        }\n      });\n      //select clicked node\n      this.toggleStylesOnClick(node, true);\n      node.selected = true;\n      delete node.hovered;\n      this.hoveredNode = false;\n    }\n  },\n\n  onMouseMove: function(e, win, event) {\n    //if mouse button is down and moving set move=true\n    if(this.down) this.move = true;\n    //already handled by mouseover/out\n    if(this.dom && this.isLabel(e, win)) return;\n    var nStyles = this.nodeStylesOnHover;\n    if(!nStyles) return;\n\n    if(!this.dom) {\n      if(this.hoveredNode) {\n        var geom = this.types[this.hoveredNode.getData('type')];\n        var contains = geom && geom.contains && geom.contains.call(this.fx,\n            this.hoveredNode, event.getPos());\n        if(contains) return;\n      }\n      var node = event.getNode();\n      //if no node is being hovered then just exit\n      if(!this.hoveredNode && !node) return;\n      //if the node is hovered then exit\n      if(node.hovered) return;\n      //select hovered node\n      if(node && !node.selected) {\n        //check if an animation is running and exit it\n        this.fx.nodeFxAnimation.stopTimer();\n        //unselect all hovered nodes...\n        this.viz.graph.eachNode(function(n) {\n          if(n.hovered && !n.selected) {\n            for(var s in nStyles) {\n              n.setData(s, n.styles['$' + s], 'end');\n            }\n            delete n.hovered;\n          }\n        });\n        //select hovered node\n        node.hovered = true;\n        this.hoveredNode = node;\n        this.toggleStylesOnHover(node, true);\n      } else if(this.hoveredNode && !this.hoveredNode.selected) {\n        //check if an animation is running and exit it\n        this.fx.nodeFxAnimation.stopTimer();\n        //unselect hovered node\n        this.toggleStylesOnHover(this.hoveredNode, false);\n        delete this.hoveredNode.hovered;\n        this.hoveredNode = false;\n      }\n    }\n  }\n});\n\nExtras.Classes.Navigation = new Class({\n  Implements: [ExtrasInitializer, EventsInterface],\n\n  initializePost: function() {\n    this.pos = false;\n    this.pressed = false;\n  },\n\n  onMouseWheel: function(e, win, scroll) {\n    if(!this.config.zooming) return;\n    $.event.stop($.event.get(e, win));\n    var val = this.config.zooming / 1000,\n        ans = 1 + scroll * val;\n    this.canvas.scale(ans, ans);\n  },\n\n  onMouseDown: function(e, win, eventInfo) {\n    if(!this.config.panning) return;\n    if(this.config.panning == 'avoid nodes' && eventInfo.getNode()) return;\n    this.pressed = true;\n    this.pos = eventInfo.getPos();\n    var canvas = this.canvas,\n        ox = canvas.translateOffsetX,\n        oy = canvas.translateOffsetY,\n        sx = canvas.scaleOffsetX,\n        sy = canvas.scaleOffsetY;\n    this.pos.x *= sx;\n    this.pos.x += ox;\n    this.pos.y *= sy;\n    this.pos.y += oy;\n  },\n\n  onMouseMove: function(e, win, eventInfo) {\n    if(!this.config.panning) return;\n    if(!this.pressed) return;\n    if(this.config.panning == 'avoid nodes' && eventInfo.getNode()) return;\n    var thispos = this.pos,\n        currentPos = eventInfo.getPos(),\n        canvas = this.canvas,\n        ox = canvas.translateOffsetX,\n        oy = canvas.translateOffsetY,\n        sx = canvas.scaleOffsetX,\n        sy = canvas.scaleOffsetY;\n    currentPos.x *= sx;\n    currentPos.y *= sy;\n    currentPos.x += ox;\n    currentPos.y += oy;\n    var x = currentPos.x - thispos.x,\n        y = currentPos.y - thispos.y;\n    this.pos = currentPos;\n    this.canvas.translate(x * 1/sx, y * 1/sy);\n  },\n\n  onMouseUp: function(e, win, eventInfo, isRightClick) {\n    if(!this.config.panning) return;\n    this.pressed = false;\n  }\n});\n\n\n/*\n * File: Canvas.js\n *\n */\n\n/*\n Class: Canvas\n\n   A canvas widget used by all visualizations. The canvas object can be accessed by doing *viz.canvas*. If you want to\n   know more about <Canvas> options take a look at <Options.Canvas>.\n\n A canvas widget is a set of DOM elements that wrap the native canvas DOM Element providing a consistent API and behavior\n across all browsers. It can also include Elements to add DOM (SVG or HTML) label support to all visualizations.\n\n Example:\n\n Suppose we have this HTML\n\n (start code xml)\n   <div id=\"infovis\"></div>\n (end code)\n\n Now we create a new Visualization\n\n (start code js)\n   var viz = new $jit.Viz({\n     //Where to inject the canvas. Any div container will do.\n     'injectInto':'infovis',\n     //width and height for canvas.\n     //Default's to the container offsetWidth and Height.\n     'width': 900,\n     'height':500\n   });\n (end code)\n\n The generated HTML will look like this\n\n (start code xml)\n <div id=\"infovis\">\n   <div id=\"infovis-canvaswidget\" style=\"position:relative;\">\n   <canvas id=\"infovis-canvas\" width=900 height=500\n   style=\"position:absolute; top:0; left:0; width:900px; height:500px;\" />\n   <div id=\"infovis-label\"\n   style=\"overflow:visible; position:absolute; top:0; left:0; width:900px; height:0px\">\n   </div>\n   </div>\n </div>\n (end code)\n\n As you can see, the generated HTML consists of a canvas DOM Element of id *infovis-canvas* and a div label container\n of id *infovis-label*, wrapped in a main div container of id *infovis-canvaswidget*.\n */\n\nvar Canvas;\n(function() {\n  //check for native canvas support\n  var canvasType = typeof HTMLCanvasElement,\n      supportsCanvas = (canvasType == 'object' || canvasType == 'function');\n  //create element function\n  function $E(tag, props) {\n    var elem = document.createElement(tag);\n    for(var p in props) {\n      if(typeof props[p] == \"object\") {\n        $.extend(elem[p], props[p]);\n      } else {\n        elem[p] = props[p];\n      }\n    }\n    if (tag == \"canvas\" && !supportsCanvas && G_vmlCanvasManager) {\n      elem = G_vmlCanvasManager.initElement(document.body.appendChild(elem));\n    }\n    return elem;\n  }\n  //canvas widget which we will call just Canvas\n  $jit.Canvas = Canvas = new Class({\n    canvases: [],\n    pos: false,\n    element: false,\n    labelContainer: false,\n    translateOffsetX: 0,\n    translateOffsetY: 0,\n    scaleOffsetX: 1,\n    scaleOffsetY: 1,\n\n    initialize: function(viz, opt) {\n      this.viz = viz;\n      this.opt = opt;\n      var id = $.type(opt.injectInto) == 'string'?\n          opt.injectInto:opt.injectInto.id,\n          idLabel = id + \"-label\",\n          wrapper = $(id),\n          width = opt.width || wrapper.offsetWidth,\n          height = opt.height || wrapper.offsetHeight;\n      this.id = id;\n      //canvas options\n      var canvasOptions = {\n        injectInto: id,\n        width: width,\n        height: height\n      };\n      //create main wrapper\n      this.element = $E('div', {\n        'id': id + '-canvaswidget',\n        'style': {\n          'position': 'relative',\n          'width': width + 'px',\n          'height': height + 'px'\n        }\n      });\n      //create label container\n      this.labelContainer = this.createLabelContainer(opt.Label.type,\n          idLabel, canvasOptions);\n      //create primary canvas\n      this.canvases.push(new Canvas.Base({\n        config: $.extend({idSuffix: '-canvas'}, canvasOptions),\n        plot: function(base) {\n          viz.fx.plot();\n        },\n        resize: function() {\n          viz.refresh();\n        }\n      }));\n      //create secondary canvas\n      var back = opt.background;\n      if(back) {\n        var backCanvas = new Canvas.Background[back.type](viz, $.extend(back, canvasOptions));\n        this.canvases.push(new Canvas.Base(backCanvas));\n      }\n      //insert canvases\n      var len = this.canvases.length;\n      while(len--) {\n        this.element.appendChild(this.canvases[len].canvas);\n        if(len > 0) {\n          this.canvases[len].plot();\n        }\n      }\n      this.element.appendChild(this.labelContainer);\n      wrapper.appendChild(this.element);\n      //Update canvas position when the page is scrolled.\n      var timer = null, that = this;\n      $.addEvent(window, 'scroll', function() {\n        clearTimeout(timer);\n        timer = setTimeout(function() {\n          that.getPos(true); //update canvas position\n        }, 500);\n      });\n    },\n    /*\n      Method: getCtx\n\n      Returns the main canvas context object\n\n      Example:\n\n      (start code js)\n       var ctx = canvas.getCtx();\n       //Now I can use the native canvas context\n       //and for example change some canvas styles\n       ctx.globalAlpha = 1;\n      (end code)\n    */\n    getCtx: function(i) {\n      return this.canvases[i || 0].getCtx();\n    },\n    /*\n      Method: getConfig\n\n      Returns the current Configuration for this Canvas Widget.\n\n      Example:\n\n      (start code js)\n       var config = canvas.getConfig();\n      (end code)\n    */\n    getConfig: function() {\n      return this.opt;\n    },\n    /*\n      Method: getElement\n\n      Returns the main Canvas DOM wrapper\n\n      Example:\n\n      (start code js)\n       var wrapper = canvas.getElement();\n       //Returns <div id=\"infovis-canvaswidget\" ... >...</div> as element\n      (end code)\n    */\n    getElement: function() {\n      return this.element;\n    },\n    /*\n      Method: getSize\n\n      Returns canvas dimensions.\n\n      Returns:\n\n      An object with *width* and *height* properties.\n\n      Example:\n      (start code js)\n      canvas.getSize(); //returns { width: 900, height: 500 }\n      (end code)\n    */\n    getSize: function(i) {\n      return this.canvases[i || 0].getSize();\n    },\n    /*\n      Method: resize\n\n      Resizes the canvas.\n\n      Parameters:\n\n      width - New canvas width.\n      height - New canvas height.\n\n      Example:\n\n      (start code js)\n       canvas.resize(width, height);\n      (end code)\n\n    */\n    resize: function(width, height) {\n      this.getPos(true);\n      this.translateOffsetX = this.translateOffsetY = 0;\n      this.scaleOffsetX = this.scaleOffsetY = 1;\n      for(var i=0, l=this.canvases.length; i<l; i++) {\n        this.canvases[i].resize(width, height);\n      }\n      var style = this.element.style;\n      style.width = width + 'px';\n      style.height = height + 'px';\n      if(this.labelContainer)\n        this.labelContainer.style.width = width + 'px';\n    },\n    /*\n      Method: translate\n\n      Applies a translation to the canvas.\n\n      Parameters:\n\n      x - (number) x offset.\n      y - (number) y offset.\n      disablePlot - (boolean) Default's *false*. Set this to *true* if you don't want to refresh the visualization.\n\n      Example:\n\n      (start code js)\n       canvas.translate(30, 30);\n      (end code)\n\n    */\n    translate: function(x, y, disablePlot) {\n      this.translateOffsetX += x*this.scaleOffsetX;\n      this.translateOffsetY += y*this.scaleOffsetY;\n      for(var i=0, l=this.canvases.length; i<l; i++) {\n        this.canvases[i].translate(x, y, disablePlot);\n      }\n    },\n    /*\n      Method: scale\n\n      Scales the canvas.\n\n      Parameters:\n\n      x - (number) scale value.\n      y - (number) scale value.\n      disablePlot - (boolean) Default's *false*. Set this to *true* if you don't want to refresh the visualization.\n\n      Example:\n\n      (start code js)\n       canvas.scale(0.5, 0.5);\n      (end code)\n\n    */\n    scale: function(x, y, disablePlot) {\n      var px = this.scaleOffsetX * x,\n          py = this.scaleOffsetY * y;\n      var dx = this.translateOffsetX * (x -1) / px,\n          dy = this.translateOffsetY * (y -1) / py;\n      this.scaleOffsetX = px;\n      this.scaleOffsetY = py;\n      for(var i=0, l=this.canvases.length; i<l; i++) {\n        this.canvases[i].scale(x, y, true);\n      }\n      this.translate(dx, dy, false);\n    },\n    /*\n      Method: getPos\n\n      Returns the canvas position as an *x, y* object.\n\n      Parameters:\n\n      force - (boolean) Default's *false*. Set this to *true* if you want to recalculate the position without using any cache information.\n\n      Returns:\n\n      An object with *x* and *y* properties.\n\n      Example:\n      (start code js)\n      canvas.getPos(true); //returns { x: 900, y: 500 }\n      (end code)\n    */\n    getPos: function(force){\n      if(force || !this.pos) {\n        return this.pos = $.getPos(this.getElement());\n      }\n      return this.pos;\n    },\n    /*\n       Method: clear\n\n       Clears the canvas.\n    */\n    clear: function(i){\n      this.canvases[i||0].clear();\n    },\n\n    path: function(type, action){\n      var ctx = this.canvases[0].getCtx();\n      ctx.beginPath();\n      action(ctx);\n      ctx[type]();\n      ctx.closePath();\n    },\n\n    createLabelContainer: function(type, idLabel, dim) {\n      var NS = 'http://www.w3.org/2000/svg';\n      if(type == 'HTML' || type == 'Native') {\n        return $E('div', {\n          'id': idLabel,\n          'style': {\n            'overflow': 'visible',\n            'position': 'absolute',\n            'top': 0,\n            'left': 0,\n            'width': dim.width + 'px',\n            'height': 0\n          }\n        });\n      } else if(type == 'SVG') {\n        var svgContainer = document.createElementNS(NS, 'svg:svg');\n        svgContainer.setAttribute(\"width\", dim.width);\n        svgContainer.setAttribute('height', dim.height);\n        var style = svgContainer.style;\n        style.position = 'absolute';\n        style.left = style.top = '0px';\n        var labelContainer = document.createElementNS(NS, 'svg:g');\n        labelContainer.setAttribute('width', dim.width);\n        labelContainer.setAttribute('height', dim.height);\n        labelContainer.setAttribute('x', 0);\n        labelContainer.setAttribute('y', 0);\n        labelContainer.setAttribute('id', idLabel);\n        svgContainer.appendChild(labelContainer);\n        return svgContainer;\n      }\n    }\n  });\n  //base canvas wrapper\n  Canvas.Base = new Class({\n    translateOffsetX: 0,\n    translateOffsetY: 0,\n    scaleOffsetX: 1,\n    scaleOffsetY: 1,\n\n    initialize: function(viz) {\n      this.viz = viz;\n      this.opt = viz.config;\n      this.size = false;\n      this.createCanvas();\n      this.translateToCenter();\n    },\n    createCanvas: function() {\n      var opt = this.opt,\n          width = opt.width,\n          height = opt.height;\n      this.canvas = $E('canvas', {\n        'id': opt.injectInto + opt.idSuffix,\n        'width': width,\n        'height': height,\n        'style': {\n          'position': 'absolute',\n          'top': 0,\n          'left': 0,\n          'width': width + 'px',\n          'height': height + 'px'\n        }\n      });\n    },\n    getCtx: function() {\n      if(!this.ctx)\n        return this.ctx = this.canvas.getContext('2d');\n      return this.ctx;\n    },\n    getSize: function() {\n      if(this.size) return this.size;\n      var canvas = this.canvas;\n      return this.size = {\n        width: canvas.width,\n        height: canvas.height\n      };\n    },\n    translateToCenter: function(ps) {\n      var size = this.getSize(),\n          width = ps? (size.width - ps.width - this.translateOffsetX*2) : size.width;\n          height = ps? (size.height - ps.height - this.translateOffsetY*2) : size.height;\n      var ctx = this.getCtx();\n      ps && ctx.scale(1/this.scaleOffsetX, 1/this.scaleOffsetY);\n      ctx.translate(width/2, height/2);\n    },\n    resize: function(width, height) {\n      var size = this.getSize(),\n          canvas = this.canvas,\n          styles = canvas.style;\n      this.size = false;\n      canvas.width = width;\n      canvas.height = height;\n      styles.width = width + \"px\";\n      styles.height = height + \"px\";\n      //small ExCanvas fix\n      if(!supportsCanvas) {\n        this.translateToCenter(size);\n      } else {\n        this.translateToCenter();\n      }\n      this.translateOffsetX =\n        this.translateOffsetY = 0;\n      this.scaleOffsetX =\n        this.scaleOffsetY = 1;\n      this.clear();\n      this.viz.resize(width, height, this);\n    },\n    translate: function(x, y, disablePlot) {\n      var sx = this.scaleOffsetX,\n          sy = this.scaleOffsetY;\n      this.translateOffsetX += x*sx;\n      this.translateOffsetY += y*sy;\n      this.getCtx().translate(x, y);\n      !disablePlot && this.plot();\n    },\n    scale: function(x, y, disablePlot) {\n      this.scaleOffsetX *= x;\n      this.scaleOffsetY *= y;\n      this.getCtx().scale(x, y);\n      !disablePlot && this.plot();\n    },\n    clear: function(){\n      var size = this.getSize(),\n          ox = this.translateOffsetX,\n          oy = this.translateOffsetY,\n          sx = this.scaleOffsetX,\n          sy = this.scaleOffsetY;\n      this.getCtx().clearRect((-size.width / 2 - ox) * 1/sx,\n                              (-size.height / 2 - oy) * 1/sy,\n                              size.width * 1/sx, size.height * 1/sy);\n    },\n    plot: function() {\n      this.clear();\n      this.viz.plot(this);\n    }\n  });\n  //background canvases\n  //TODO(nico): document this!\n  Canvas.Background = {};\n  Canvas.Background.Circles = new Class({\n    initialize: function(viz, options) {\n      this.viz = viz;\n      this.config = $.merge({\n        idSuffix: '-bkcanvas',\n        levelDistance: 100,\n        numberOfCircles: 6,\n        CanvasStyles: {},\n        offset: 0\n      }, options);\n    },\n    resize: function(width, height, base) {\n      this.plot(base);\n    },\n    plot: function(base) {\n      var canvas = base.canvas,\n          ctx = base.getCtx(),\n          conf = this.config,\n          styles = conf.CanvasStyles;\n      //set canvas styles\n      for(var s in styles) ctx[s] = styles[s];\n      var n = conf.numberOfCircles,\n          rho = conf.levelDistance;\n      for(var i=1; i<=n; i++) {\n        ctx.beginPath();\n        ctx.arc(0, 0, rho * i, 0, 2 * Math.PI, false);\n        ctx.stroke();\n        ctx.closePath();\n      }\n      //TODO(nico): print labels too!\n    }\n  });\n})();\n\n\n/*\n * File: Polar.js\n *\n * Defines the <Polar> class.\n *\n * Description:\n *\n * The <Polar> class, just like the <Complex> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.\n *\n * See also:\n *\n * <http://en.wikipedia.org/wiki/Polar_coordinates>\n *\n*/\n\n/*\n   Class: Polar\n\n   A multi purpose polar representation.\n\n   Description:\n\n   The <Polar> class, just like the <Complex> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.\n\n   See also:\n\n   <http://en.wikipedia.org/wiki/Polar_coordinates>\n\n   Parameters:\n\n      theta - An angle.\n      rho - The norm.\n*/\n\nvar Polar = function(theta, rho) {\n  this.theta = theta;\n  this.rho = rho;\n};\n\n$jit.Polar = Polar;\n\nPolar.prototype = {\n    /*\n       Method: getc\n\n       Returns a complex number.\n\n       Parameters:\n\n       simple - _optional_ If *true*, this method will return only an object holding x and y properties and not a <Complex> instance. Default's *false*.\n\n      Returns:\n\n          A complex number.\n    */\n    getc: function(simple) {\n        return this.toComplex(simple);\n    },\n\n    /*\n       Method: getp\n\n       Returns a <Polar> representation.\n\n       Returns:\n\n          A variable in polar coordinates.\n    */\n    getp: function() {\n        return this;\n    },\n\n\n    /*\n       Method: set\n\n       Sets a number.\n\n       Parameters:\n\n       v - A <Complex> or <Polar> instance.\n\n    */\n    set: function(v) {\n        v = v.getp();\n        this.theta = v.theta; this.rho = v.rho;\n    },\n\n    /*\n       Method: setc\n\n       Sets a <Complex> number.\n\n       Parameters:\n\n       x - A <Complex> number real part.\n       y - A <Complex> number imaginary part.\n\n    */\n    setc: function(x, y) {\n        this.rho = Math.sqrt(x * x + y * y);\n        this.theta = Math.atan2(y, x);\n        if(this.theta < 0) this.theta += Math.PI * 2;\n    },\n\n    /*\n       Method: setp\n\n       Sets a polar number.\n\n       Parameters:\n\n       theta - A <Polar> number angle property.\n       rho - A <Polar> number rho property.\n\n    */\n    setp: function(theta, rho) {\n        this.theta = theta;\n        this.rho = rho;\n    },\n\n    /*\n       Method: clone\n\n       Returns a copy of the current object.\n\n       Returns:\n\n          A copy of the real object.\n    */\n    clone: function() {\n        return new Polar(this.theta, this.rho);\n    },\n\n    /*\n       Method: toComplex\n\n        Translates from polar to cartesian coordinates and returns a new <Complex> instance.\n\n        Parameters:\n\n        simple - _optional_ If *true* this method will only return an object with x and y properties (and not the whole <Complex> instance). Default's *false*.\n\n        Returns:\n\n          A new <Complex> instance.\n    */\n    toComplex: function(simple) {\n        var x = Math.cos(this.theta) * this.rho;\n        var y = Math.sin(this.theta) * this.rho;\n        if(simple) return { 'x': x, 'y': y};\n        return new Complex(x, y);\n    },\n\n    /*\n       Method: add\n\n        Adds two <Polar> instances.\n\n       Parameters:\n\n       polar - A <Polar> number.\n\n       Returns:\n\n          A new Polar instance.\n    */\n    add: function(polar) {\n        return new Polar(this.theta + polar.theta, this.rho + polar.rho);\n    },\n\n    /*\n       Method: scale\n\n        Scales a polar norm.\n\n        Parameters:\n\n        number - A scale factor.\n\n        Returns:\n\n          A new Polar instance.\n    */\n    scale: function(number) {\n        return new Polar(this.theta, this.rho * number);\n    },\n\n    /*\n       Method: equals\n\n       Comparison method.\n\n       Returns *true* if the theta and rho properties are equal.\n\n       Parameters:\n\n       c - A <Polar> number.\n\n       Returns:\n\n       *true* if the theta and rho parameters for these objects are equal. *false* otherwise.\n    */\n    equals: function(c) {\n        return this.theta == c.theta && this.rho == c.rho;\n    },\n\n    /*\n       Method: $add\n\n        Adds two <Polar> instances affecting the current object.\n\n       Paramters:\n\n       polar - A <Polar> instance.\n\n       Returns:\n\n          The changed object.\n    */\n    $add: function(polar) {\n        this.theta = this.theta + polar.theta; this.rho += polar.rho;\n        return this;\n    },\n\n    /*\n       Method: $madd\n\n        Adds two <Polar> instances affecting the current object. The resulting theta angle is modulo 2pi.\n\n       Parameters:\n\n       polar - A <Polar> instance.\n\n       Returns:\n\n          The changed object.\n    */\n    $madd: function(polar) {\n        this.theta = (this.theta + polar.theta) % (Math.PI * 2); this.rho += polar.rho;\n        return this;\n    },\n\n\n    /*\n       Method: $scale\n\n        Scales a polar instance affecting the object.\n\n      Parameters:\n\n      number - A scaling factor.\n\n      Returns:\n\n          The changed object.\n    */\n    $scale: function(number) {\n        this.rho *= number;\n        return this;\n    },\n\n    /*\n       Method: interpolate\n\n        Calculates a polar interpolation between two points at a given delta moment.\n\n        Parameters:\n\n        elem - A <Polar> instance.\n        delta - A delta factor ranging [0, 1].\n\n       Returns:\n\n          A new <Polar> instance representing an interpolation between _this_ and _elem_\n    */\n    interpolate: function(elem, delta) {\n        var pi = Math.PI, pi2 = pi * 2;\n        var ch = function(t) {\n            var a =  (t < 0)? (t % pi2) + pi2 : t % pi2;\n            return a;\n        };\n        var tt = this.theta, et = elem.theta;\n        var sum, diff = Math.abs(tt - et);\n        if(diff == pi) {\n          if(tt > et) {\n            sum = ch((et + ((tt - pi2) - et) * delta)) ;\n          } else {\n            sum = ch((et - pi2 + (tt - (et)) * delta));\n          }\n        } else if(diff >= pi) {\n          if(tt > et) {\n            sum = ch((et + ((tt - pi2) - et) * delta)) ;\n          } else {\n            sum = ch((et - pi2 + (tt - (et - pi2)) * delta));\n          }\n        } else {\n          sum = ch((et + (tt - et) * delta)) ;\n        }\n        var r = (this.rho - elem.rho) * delta + elem.rho;\n        return {\n          'theta': sum,\n          'rho': r\n        };\n    }\n};\n\n\nvar $P = function(a, b) { return new Polar(a, b); };\n\nPolar.KER = $P(0, 0);\n\n\n\n/*\n * File: Complex.js\n *\n * Defines the <Complex> class.\n *\n * Description:\n *\n * The <Complex> class, just like the <Polar> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.\n *\n * See also:\n *\n * <http://en.wikipedia.org/wiki/Complex_number>\n *\n*/\n\n/*\n   Class: Complex\n\n   A multi-purpose Complex Class with common methods.\n\n   Description:\n\n   The <Complex> class, just like the <Polar> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.\n\n   See also:\n\n   <http://en.wikipedia.org/wiki/Complex_number>\n\n   Parameters:\n\n   x - _optional_ A Complex number real part.\n   y - _optional_ A Complex number imaginary part.\n\n*/\n\nvar Complex = function(x, y) {\n  this.x = x;\n  this.y = y;\n};\n\n$jit.Complex = Complex;\n\nComplex.prototype = {\n    /*\n       Method: getc\n\n       Returns a complex number.\n\n       Returns:\n\n          A complex number.\n    */\n    getc: function() {\n        return this;\n    },\n\n    /*\n       Method: getp\n\n       Returns a <Polar> representation of this number.\n\n       Parameters:\n\n       simple - _optional_ If *true*, this method will return only an object holding theta and rho properties and not a <Polar> instance. Default's *false*.\n\n       Returns:\n\n          A variable in <Polar> coordinates.\n    */\n    getp: function(simple) {\n        return this.toPolar(simple);\n    },\n\n\n    /*\n       Method: set\n\n       Sets a number.\n\n       Parameters:\n\n       c - A <Complex> or <Polar> instance.\n\n    */\n    set: function(c) {\n      c = c.getc(true);\n      this.x = c.x;\n      this.y = c.y;\n    },\n\n    /*\n       Method: setc\n\n       Sets a complex number.\n\n       Parameters:\n\n       x - A <Complex> number Real part.\n       y - A <Complex> number Imaginary part.\n\n    */\n    setc: function(x, y) {\n        this.x = x;\n        this.y = y;\n    },\n\n    /*\n       Method: setp\n\n       Sets a polar number.\n\n       Parameters:\n\n       theta - A <Polar> number theta property.\n       rho - A <Polar> number rho property.\n\n    */\n    setp: function(theta, rho) {\n        this.x = Math.cos(theta) * rho;\n        this.y = Math.sin(theta) * rho;\n    },\n\n    /*\n       Method: clone\n\n       Returns a copy of the current object.\n\n       Returns:\n\n          A copy of the real object.\n    */\n    clone: function() {\n        return new Complex(this.x, this.y);\n    },\n\n    /*\n       Method: toPolar\n\n       Transforms cartesian to polar coordinates.\n\n       Parameters:\n\n       simple - _optional_ If *true* this method will only return an object with theta and rho properties (and not the whole <Polar> instance). Default's *false*.\n\n       Returns:\n\n          A new <Polar> instance.\n    */\n\n    toPolar: function(simple) {\n        var rho = this.norm();\n        var atan = Math.atan2(this.y, this.x);\n        if(atan < 0) atan += Math.PI * 2;\n        if(simple) return { 'theta': atan, 'rho': rho };\n        return new Polar(atan, rho);\n    },\n    /*\n       Method: norm\n\n       Calculates a <Complex> number norm.\n\n       Returns:\n\n          A real number representing the complex norm.\n    */\n    norm: function () {\n        return Math.sqrt(this.squaredNorm());\n    },\n\n    /*\n       Method: squaredNorm\n\n       Calculates a <Complex> number squared norm.\n\n       Returns:\n\n          A real number representing the complex squared norm.\n    */\n    squaredNorm: function () {\n        return this.x*this.x + this.y*this.y;\n    },\n\n    /*\n       Method: add\n\n       Returns the result of adding two complex numbers.\n\n       Does not alter the original object.\n\n       Parameters:\n\n          pos - A <Complex> instance.\n\n       Returns:\n\n         The result of adding two complex numbers.\n    */\n    add: function(pos) {\n        return new Complex(this.x + pos.x, this.y + pos.y);\n    },\n\n    /*\n       Method: prod\n\n       Returns the result of multiplying two <Complex> numbers.\n\n       Does not alter the original object.\n\n       Parameters:\n\n          pos - A <Complex> instance.\n\n       Returns:\n\n         The result of multiplying two complex numbers.\n    */\n    prod: function(pos) {\n        return new Complex(this.x*pos.x - this.y*pos.y, this.y*pos.x + this.x*pos.y);\n    },\n\n    /*\n       Method: conjugate\n\n       Returns the conjugate of this <Complex> number.\n\n       Does not alter the original object.\n\n       Returns:\n\n         The conjugate of this <Complex> number.\n    */\n    conjugate: function() {\n        return new Complex(this.x, -this.y);\n    },\n\n\n    /*\n       Method: scale\n\n       Returns the result of scaling a <Complex> instance.\n\n       Does not alter the original object.\n\n       Parameters:\n\n          factor - A scale factor.\n\n       Returns:\n\n         The result of scaling this complex to a factor.\n    */\n    scale: function(factor) {\n        return new Complex(this.x * factor, this.y * factor);\n    },\n\n    /*\n       Method: equals\n\n       Comparison method.\n\n       Returns *true* if both real and imaginary parts are equal.\n\n       Parameters:\n\n       c - A <Complex> instance.\n\n       Returns:\n\n       A boolean instance indicating if both <Complex> numbers are equal.\n    */\n    equals: function(c) {\n        return this.x == c.x && this.y == c.y;\n    },\n\n    /*\n       Method: $add\n\n       Returns the result of adding two <Complex> numbers.\n\n       Alters the original object.\n\n       Parameters:\n\n          pos - A <Complex> instance.\n\n       Returns:\n\n         The result of adding two complex numbers.\n    */\n    $add: function(pos) {\n        this.x += pos.x; this.y += pos.y;\n        return this;\n    },\n\n    /*\n       Method: $prod\n\n       Returns the result of multiplying two <Complex> numbers.\n\n       Alters the original object.\n\n       Parameters:\n\n          pos - A <Complex> instance.\n\n       Returns:\n\n         The result of multiplying two complex numbers.\n    */\n    $prod:function(pos) {\n        var x = this.x, y = this.y;\n        this.x = x*pos.x - y*pos.y;\n        this.y = y*pos.x + x*pos.y;\n        return this;\n    },\n\n    /*\n       Method: $conjugate\n\n       Returns the conjugate for this <Complex>.\n\n       Alters the original object.\n\n       Returns:\n\n         The conjugate for this complex.\n    */\n    $conjugate: function() {\n        this.y = -this.y;\n        return this;\n    },\n\n    /*\n       Method: $scale\n\n       Returns the result of scaling a <Complex> instance.\n\n       Alters the original object.\n\n       Parameters:\n\n          factor - A scale factor.\n\n       Returns:\n\n         The result of scaling this complex to a factor.\n    */\n    $scale: function(factor) {\n        this.x *= factor; this.y *= factor;\n        return this;\n    },\n\n    /*\n       Method: $div\n\n       Returns the division of two <Complex> numbers.\n\n       Alters the original object.\n\n       Parameters:\n\n          pos - A <Complex> number.\n\n       Returns:\n\n         The result of scaling this complex to a factor.\n    */\n    $div: function(pos) {\n        var x = this.x, y = this.y;\n        var sq = pos.squaredNorm();\n        this.x = x * pos.x + y * pos.y; this.y = y * pos.x - x * pos.y;\n        return this.$scale(1 / sq);\n    }\n};\n\nvar $C = function(a, b) { return new Complex(a, b); };\n\nComplex.KER = $C(0, 0);\n\n\n\n/*\n * File: Graph.js\n *\n*/\n\n/*\n Class: Graph\n\n A Graph Class that provides useful manipulation functions. You can find more manipulation methods in the <Graph.Util> object.\n\n An instance of this class can be accessed by using the *graph* parameter of any tree or graph visualization.\n\n Example:\n\n (start code js)\n   //create new visualization\n   var viz = new $jit.Viz(options);\n   //load JSON data\n   viz.loadJSON(json);\n   //access model\n   viz.graph; //<Graph> instance\n (end code)\n\n Implements:\n\n The following <Graph.Util> methods are implemented in <Graph>\n\n  - <Graph.Util.getNode>\n  - <Graph.Util.eachNode>\n  - <Graph.Util.computeLevels>\n  - <Graph.Util.eachBFS>\n  - <Graph.Util.clean>\n  - <Graph.Util.getClosestNodeToPos>\n  - <Graph.Util.getClosestNodeToOrigin>\n\n*/\n\n$jit.Graph = new Class({\n\n  initialize: function(opt, Node, Edge, Label) {\n    var innerOptions = {\n    'complex': false,\n    'Node': {}\n    };\n    this.Node = Node;\n    this.Edge = Edge;\n    this.Label = Label;\n    this.opt = $.merge(innerOptions, opt || {});\n    this.nodes = {};\n    this.edges = {};\n\n    //add nodeList methods\n    var that = this;\n    this.nodeList = {};\n    for(var p in Accessors) {\n      that.nodeList[p] = (function(p) {\n        return function() {\n          var args = Array.prototype.slice.call(arguments);\n          that.eachNode(function(n) {\n            n[p].apply(n, args);\n          });\n        };\n      })(p);\n    }\n\n },\n\n/*\n     Method: getNode\n\n     Returns a <Graph.Node> by *id*.\n\n     Parameters:\n\n     id - (string) A <Graph.Node> id.\n\n     Example:\n\n     (start code js)\n       var node = graph.getNode('nodeId');\n     (end code)\n*/\n getNode: function(id) {\n    if(this.hasNode(id)) return this.nodes[id];\n    return false;\n },\n\n /*\n   Method: getByName\n\n   Returns a <Graph.Node> by *name*.\n\n   Parameters:\n\n   name - (string) A <Graph.Node> name.\n\n   Example:\n\n   (start code js)\n     var node = graph.getByName('someName');\n   (end code)\n  */\n  getByName: function(name) {\n    for(var id in this.nodes) {\n      var n = this.nodes[id];\n      if(n.name == name) return n;\n    }\n    return false;\n  },\n\n/*\n   Method: getAdjacence\n\n   Returns a <Graph.Adjacence> object connecting nodes with ids *id* and *id2*.\n\n   Parameters:\n\n   id - (string) A <Graph.Node> id.\n   id2 - (string) A <Graph.Node> id.\n*/\n  getAdjacence: function (id, id2) {\n    if(id in this.edges) {\n      return this.edges[id][id2];\n    }\n    return false;\n },\n\n    /*\n     Method: addNode\n\n     Adds a node.\n\n     Parameters:\n\n      obj - An object with the properties described below\n\n      id - (string) A node id\n      name - (string) A node's name\n      data - (object) A node's data hash\n\n    See also:\n    <Graph.Node>\n\n  */\n  addNode: function(obj) {\n   if(!this.nodes[obj.id]) {\n     var edges = this.edges[obj.id] = {};\n     this.nodes[obj.id] = new Graph.Node($.extend({\n        'id': obj.id,\n        'name': obj.name,\n        'data': obj.data || {},\n        'adjacencies': edges\n      }, this.opt.Node),\n      this.opt.complex,\n      this.Node,\n      this.Edge,\n      this.Label);\n    }\n    return this.nodes[obj.id];\n  },\n\n    /*\n     Method: addAdjacence\n\n     Connects nodes specified by *obj* and *obj2*. If not found, nodes are created.\n\n     Parameters:\n\n      obj - (object) A <Graph.Node> object.\n      obj2 - (object) Another <Graph.Node> object.\n      data - (object) A data object. Used to store some extra information in the <Graph.Adjacence> object created.\n\n    See also:\n\n    <Graph.Node>, <Graph.Adjacence>\n    */\n  addAdjacence: function (obj, obj2, data) {\n    if(!this.hasNode(obj.id)) { this.addNode(obj); }\n    if(!this.hasNode(obj2.id)) { this.addNode(obj2); }\n    obj = this.nodes[obj.id]; obj2 = this.nodes[obj2.id];\n    var adjsObj = this.edges[obj.id] = this.edges[obj.id] || {};\n    var adjsObj2 = this.edges[obj2.id] = this.edges[obj2.id] || {};\n    adjsObj[obj2.id] = adjsObj2[obj.id] = new Graph.Adjacence(obj, obj2, data, this.Edge, this.Label);\n    return adjsObj[obj2.id];\n },\n\n    /*\n     Method: removeNode\n\n     Removes a <Graph.Node> matching the specified *id*.\n\n     Parameters:\n\n     id - (string) A node's id.\n\n    */\n  removeNode: function(id) {\n    if(this.hasNode(id)) {\n      delete this.nodes[id];\n      var adjs = this.edges[id];\n      for(var to in adjs) {\n        delete this.edges[to][id];\n      }\n      delete this.edges[id];\n    }\n  },\n\n/*\n     Method: removeAdjacence\n\n     Removes a <Graph.Adjacence> matching *id1* and *id2*.\n\n     Parameters:\n\n     id1 - (string) A <Graph.Node> id.\n     id2 - (string) A <Graph.Node> id.\n*/\n  removeAdjacence: function(id1, id2) {\n    delete this.edges[id1][id2];\n    delete this.edges[id2][id1];\n  },\n\n   /*\n     Method: hasNode\n\n     Returns a boolean indicating if the node belongs to the <Graph> or not.\n\n     Parameters:\n\n        id - (string) Node id.\n   */\n  hasNode: function(id) {\n    return id in this.nodes;\n  },\n\n  /*\n    Method: empty\n\n    Empties the Graph\n\n  */\n  empty: function() { this.nodes = {}; this.edges = {};}\n\n});\n\nvar Graph = $jit.Graph;\n\n/*\n Object: Accessors\n\n Defines a set of methods for data, canvas and label styles manipulation implemented by <Graph.Node> and <Graph.Adjacence> instances.\n\n */\nvar Accessors;\n\n(function () {\n  var getDataInternal = function(prefix, prop, type, force, prefixConfig) {\n    var data;\n    type = type || 'current';\n    prefix = \"$\" + (prefix ? prefix + \"-\" : \"\");\n\n    if(type == 'current') {\n      data = this.data;\n    } else if(type == 'start') {\n      data = this.startData;\n    } else if(type == 'end') {\n      data = this.endData;\n    }\n\n    var dollar = prefix + prop;\n\n    if(force) {\n      return data[dollar];\n    }\n\n    if(!this.Config.overridable)\n      return prefixConfig[prop] || 0;\n\n    return (dollar in data) ?\n      data[dollar] : ((dollar in this.data) ? this.data[dollar] : (prefixConfig[prop] || 0));\n  }\n\n  var setDataInternal = function(prefix, prop, value, type) {\n    type = type || 'current';\n    prefix = '$' + (prefix ? prefix + '-' : '');\n\n    var data;\n\n    if(type == 'current') {\n      data = this.data;\n    } else if(type == 'start') {\n      data = this.startData;\n    } else if(type == 'end') {\n      data = this.endData;\n    }\n\n    data[prefix + prop] = value;\n  }\n\n  var removeDataInternal = function(prefix, properties) {\n    prefix = '$' + (prefix ? prefix + '-' : '');\n    var that = this;\n    $.each(properties, function(prop) {\n      var pref = prefix + prop;\n      delete that.data[pref];\n      delete that.endData[pref];\n      delete that.startData[pref];\n    });\n  }\n\n  Accessors = {\n    /*\n    Method: getData\n\n    Returns the specified data value property.\n    This is useful for querying special/reserved <Graph.Node> data properties\n    (i.e dollar prefixed properties).\n\n    Parameters:\n\n      prop  - (string) The name of the property. The dollar sign is not needed. For\n              example *getData(width)* will return *data.$width*.\n      type  - (string) The type of the data property queried. Default's \"current\". You can access *start* and *end*\n              data properties also. These properties are used when making animations.\n      force - (boolean) Whether to obtain the true value of the property (equivalent to\n              *data.$prop*) or to check for *node.overridable = true* first.\n\n    Returns:\n\n      The value of the dollar prefixed property or the global Node/Edge property\n      value if *overridable=false*\n\n    Example:\n    (start code js)\n     node.getData('width'); //will return node.data.$width if Node.overridable=true;\n    (end code)\n    */\n    getData: function(prop, type, force) {\n      return getDataInternal.call(this, \"\", prop, type, force, this.Config);\n    },\n\n\n    /*\n    Method: setData\n\n    Sets the current data property with some specific value.\n    This method is only useful for reserved (dollar prefixed) properties.\n\n    Parameters:\n\n      prop  - (string) The name of the property. The dollar sign is not necessary. For\n              example *setData(width)* will set *data.$width*.\n      value - (mixed) The value to store.\n      type  - (string) The type of the data property to store. Default's \"current\" but\n              can also be \"start\" or \"end\".\n\n    Example:\n\n    (start code js)\n     node.setData('width', 30);\n    (end code)\n\n    If we were to make an animation of a node/edge width then we could do\n\n    (start code js)\n      var node = viz.getNode('nodeId');\n      //set start and end values\n      node.setData('width', 10, 'start');\n      node.setData('width', 30, 'end');\n      //will animate nodes width property\n      viz.fx.animate({\n        modes: ['node-property:width'],\n        duration: 1000\n      });\n    (end code)\n    */\n    setData: function(prop, value, type) {\n      setDataInternal.call(this, \"\", prop, value, type);\n    },\n\n    /*\n    Method: setDataset\n\n    Convenience method to set multiple data values at once.\n\n    Parameters:\n\n    types - (array|string) A set of 'current', 'end' or 'start' values.\n    obj - (object) A hash containing the names and values of the properties to be altered.\n\n    Example:\n    (start code js)\n      node.setDataset(['current', 'end'], {\n        'width': [100, 5],\n        'color': ['#fff', '#ccc']\n      });\n      //...or also\n      node.setDataset('end', {\n        'width': 5,\n        'color': '#ccc'\n      });\n    (end code)\n\n    See also:\n\n    <Accessors.setData>\n\n    */\n    setDataset: function(types, obj) {\n      types = $.splat(types);\n      for(var attr in obj) {\n        for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {\n          this.setData(attr, val[i], types[i]);\n        }\n      }\n    },\n\n    /*\n    Method: removeData\n\n    Remove data properties.\n\n    Parameters:\n\n    One or more property names as arguments. The dollar sign is not needed.\n\n    Example:\n    (start code js)\n    node.removeData('width'); //now the default width value is returned\n    (end code)\n    */\n    removeData: function() {\n      removeDataInternal.call(this, \"\", Array.prototype.slice.call(arguments));\n    },\n\n    /*\n    Method: getCanvasStyle\n\n    Returns the specified canvas style data value property. This is useful for\n    querying special/reserved <Graph.Node> canvas style data properties (i.e.\n    dollar prefixed properties that match with $canvas-<name of canvas style>).\n\n    Parameters:\n\n      prop  - (string) The name of the property. The dollar sign is not needed. For\n              example *getCanvasStyle(shadowBlur)* will return *data[$canvas-shadowBlur]*.\n      type  - (string) The type of the data property queried. Default's *current*. You can access *start* and *end*\n              data properties also.\n\n    Example:\n    (start code js)\n      node.getCanvasStyle('shadowBlur');\n    (end code)\n\n    See also:\n\n    <Accessors.getData>\n    */\n    getCanvasStyle: function(prop, type, force) {\n      return getDataInternal.call(\n          this, 'canvas', prop, type, force, this.Config.CanvasStyles);\n    },\n\n    /*\n    Method: setCanvasStyle\n\n    Sets the canvas style data property with some specific value.\n    This method is only useful for reserved (dollar prefixed) properties.\n\n    Parameters:\n\n    prop - (string) Name of the property. Can be any canvas property like 'shadowBlur', 'shadowColor', 'strokeStyle', etc.\n    value - (mixed) The value to set to the property.\n    type - (string) Default's *current*. Whether to set *start*, *current* or *end* type properties.\n\n    Example:\n\n    (start code js)\n     node.setCanvasStyle('shadowBlur', 30);\n    (end code)\n\n    If we were to make an animation of a node/edge shadowBlur canvas style then we could do\n\n    (start code js)\n      var node = viz.getNode('nodeId');\n      //set start and end values\n      node.setCanvasStyle('shadowBlur', 10, 'start');\n      node.setCanvasStyle('shadowBlur', 30, 'end');\n      //will animate nodes canvas style property for nodes\n      viz.fx.animate({\n        modes: ['node-style:shadowBlur'],\n        duration: 1000\n      });\n    (end code)\n\n    See also:\n\n    <Accessors.setData>.\n    */\n    setCanvasStyle: function(prop, value, type) {\n      setDataInternal.call(this, 'canvas', prop, value, type);\n    },\n\n    /*\n    Method: setCanvasStyles\n\n    Convenience method to set multiple styles at once.\n\n    Parameters:\n\n    types - (array|string) A set of 'current', 'end' or 'start' values.\n    obj - (object) A hash containing the names and values of the properties to be altered.\n\n    See also:\n\n    <Accessors.setDataset>.\n    */\n    setCanvasStyles: function(types, obj) {\n      types = $.splat(types);\n      for(var attr in obj) {\n        for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {\n          this.setCanvasStyle(attr, val[i], types[i]);\n        }\n      }\n    },\n\n    /*\n    Method: removeCanvasStyle\n\n    Remove canvas style properties from data.\n\n    Parameters:\n\n    A variable number of canvas style strings.\n\n    See also:\n\n    <Accessors.removeData>.\n    */\n    removeCanvasStyle: function() {\n      removeDataInternal.call(this, 'canvas', Array.prototype.slice.call(arguments));\n    },\n\n    /*\n    Method: getLabelData\n\n    Returns the specified label data value property. This is useful for\n    querying special/reserved <Graph.Node> label options (i.e.\n    dollar prefixed properties that match with $label-<name of label style>).\n\n    Parameters:\n\n      prop  - (string) The name of the property. The dollar sign prefix is not needed. For\n              example *getLabelData(size)* will return *data[$label-size]*.\n      type  - (string) The type of the data property queried. Default's *current*. You can access *start* and *end*\n              data properties also.\n\n    See also:\n\n    <Accessors.getData>.\n    */\n    getLabelData: function(prop, type, force) {\n      return getDataInternal.call(\n          this, 'label', prop, type, force, this.Label);\n    },\n\n    /*\n    Method: setLabelData\n\n    Sets the current label data with some specific value.\n    This method is only useful for reserved (dollar prefixed) properties.\n\n    Parameters:\n\n    prop - (string) Name of the property. Can be any canvas property like 'shadowBlur', 'shadowColor', 'strokeStyle', etc.\n    value - (mixed) The value to set to the property.\n    type - (string) Default's *current*. Whether to set *start*, *current* or *end* type properties.\n\n    Example:\n\n    (start code js)\n     node.setLabelData('size', 30);\n    (end code)\n\n    If we were to make an animation of a node label size then we could do\n\n    (start code js)\n      var node = viz.getNode('nodeId');\n      //set start and end values\n      node.setLabelData('size', 10, 'start');\n      node.setLabelData('size', 30, 'end');\n      //will animate nodes label size\n      viz.fx.animate({\n        modes: ['label-property:size'],\n        duration: 1000\n      });\n    (end code)\n\n    See also:\n\n    <Accessors.setData>.\n    */\n    setLabelData: function(prop, value, type) {\n      setDataInternal.call(this, 'label', prop, value, type);\n    },\n\n    /*\n    Method: setLabelDataset\n\n    Convenience function to set multiple label data at once.\n\n    Parameters:\n\n    types - (array|string) A set of 'current', 'end' or 'start' values.\n    obj - (object) A hash containing the names and values of the properties to be altered.\n\n    See also:\n\n    <Accessors.setDataset>.\n    */\n    setLabelDataset: function(types, obj) {\n      types = $.splat(types);\n      for(var attr in obj) {\n        for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {\n          this.setLabelData(attr, val[i], types[i]);\n        }\n      }\n    },\n\n    /*\n    Method: removeLabelData\n\n    Remove label properties from data.\n\n    Parameters:\n\n    A variable number of label property strings.\n\n    See also:\n\n    <Accessors.removeData>.\n    */\n    removeLabelData: function() {\n      removeDataInternal.call(this, 'label', Array.prototype.slice.call(arguments));\n    }\n  };\n})();\n\n/*\n     Class: Graph.Node\n\n     A <Graph> node.\n\n     Implements:\n\n     <Accessors> methods.\n\n     The following <Graph.Util> methods are implemented by <Graph.Node>\n\n    - <Graph.Util.eachAdjacency>\n    - <Graph.Util.eachLevel>\n    - <Graph.Util.eachSubgraph>\n    - <Graph.Util.eachSubnode>\n    - <Graph.Util.anySubnode>\n    - <Graph.Util.getSubnodes>\n    - <Graph.Util.getParents>\n    - <Graph.Util.isDescendantOf>\n*/\nGraph.Node = new Class({\n\n  initialize: function(opt, complex, Node, Edge, Label) {\n    var innerOptions = {\n      'id': '',\n      'name': '',\n      'data': {},\n      'startData': {},\n      'endData': {},\n      'adjacencies': {},\n\n      'selected': false,\n      'drawn': false,\n      'exist': false,\n\n      'angleSpan': {\n        'begin': 0,\n        'end' : 0\n      },\n\n      'pos': (complex && $C(0, 0)) || $P(0, 0),\n      'startPos': (complex && $C(0, 0)) || $P(0, 0),\n      'endPos': (complex && $C(0, 0)) || $P(0, 0)\n    };\n\n    $.extend(this, $.extend(innerOptions, opt));\n    this.Config = this.Node = Node;\n    this.Edge = Edge;\n    this.Label = Label;\n  },\n\n    /*\n       Method: adjacentTo\n\n       Indicates if the node is adjacent to the node specified by id\n\n       Parameters:\n\n          id - (string) A node id.\n\n       Example:\n       (start code js)\n        node.adjacentTo('nodeId') == true;\n       (end code)\n    */\n    adjacentTo: function(node) {\n        return node.id in this.adjacencies;\n    },\n\n    /*\n       Method: getAdjacency\n\n       Returns a <Graph.Adjacence> object connecting the current <Graph.Node> and the node having *id* as id.\n\n       Parameters:\n\n          id - (string) A node id.\n    */\n    getAdjacency: function(id) {\n        return this.adjacencies[id];\n    },\n\n    /*\n      Method: getPos\n\n      Returns the position of the node.\n\n      Parameters:\n\n         type - (string) Default's *current*. Possible values are \"start\", \"end\" or \"current\".\n\n      Returns:\n\n        A <Complex> or <Polar> instance.\n\n      Example:\n      (start code js)\n       var pos = node.getPos('end');\n      (end code)\n   */\n   getPos: function(type) {\n       type = type || \"current\";\n       if(type == \"current\") {\n         return this.pos;\n       } else if(type == \"end\") {\n         return this.endPos;\n       } else if(type == \"start\") {\n         return this.startPos;\n       }\n   },\n   /*\n     Method: setPos\n\n     Sets the node's position.\n\n     Parameters:\n\n        value - (object) A <Complex> or <Polar> instance.\n        type - (string) Default's *current*. Possible values are \"start\", \"end\" or \"current\".\n\n     Example:\n     (start code js)\n      node.setPos(new $jit.Complex(0, 0), 'end');\n     (end code)\n  */\n  setPos: function(value, type) {\n      type = type || \"current\";\n      var pos;\n      if(type == \"current\") {\n        pos = this.pos;\n      } else if(type == \"end\") {\n        pos = this.endPos;\n      } else if(type == \"start\") {\n        pos = this.startPos;\n      }\n      pos.set(value);\n  }\n});\n\nGraph.Node.implement(Accessors);\n\n/*\n     Class: Graph.Adjacence\n\n     A <Graph> adjacence (or edge) connecting two <Graph.Nodes>.\n\n     Implements:\n\n     <Accessors> methods.\n\n     See also:\n\n     <Graph>, <Graph.Node>\n\n     Properties:\n\n      nodeFrom - A <Graph.Node> connected by this edge.\n      nodeTo - Another  <Graph.Node> connected by this edge.\n      data - Node data property containing a hash (i.e {}) with custom options.\n*/\nGraph.Adjacence = new Class({\n\n  initialize: function(nodeFrom, nodeTo, data, Edge, Label) {\n    this.nodeFrom = nodeFrom;\n    this.nodeTo = nodeTo;\n    this.data = data || {};\n    this.startData = {};\n    this.endData = {};\n    this.Config = this.Edge = Edge;\n    this.Label = Label;\n  }\n});\n\nGraph.Adjacence.implement(Accessors);\n\n/*\n   Object: Graph.Util\n\n   <Graph> traversal and processing utility object.\n\n   Note:\n\n   For your convenience some of these methods have also been appended to <Graph> and <Graph.Node> classes.\n*/\nGraph.Util = {\n    /*\n       filter\n\n       For internal use only. Provides a filtering function based on flags.\n    */\n    filter: function(param) {\n        if(!param || !($.type(param) == 'string')) return function() { return true; };\n        var props = param.split(\" \");\n        return function(elem) {\n            for(var i=0; i<props.length; i++) {\n              if(elem[props[i]]) {\n                return false;\n              }\n            }\n            return true;\n        };\n    },\n    /*\n       Method: getNode\n\n       Returns a <Graph.Node> by *id*.\n\n       Also implemented by:\n\n       <Graph>\n\n       Parameters:\n\n       graph - (object) A <Graph> instance.\n       id - (string) A <Graph.Node> id.\n\n       Example:\n\n       (start code js)\n         $jit.Graph.Util.getNode(graph, 'nodeid');\n         //or...\n         graph.getNode('nodeid');\n       (end code)\n    */\n    getNode: function(graph, id) {\n        return graph.nodes[id];\n    },\n\n    /*\n       Method: eachNode\n\n       Iterates over <Graph> nodes performing an *action*.\n\n       Also implemented by:\n\n       <Graph>.\n\n       Parameters:\n\n       graph - (object) A <Graph> instance.\n       action - (function) A callback function having a <Graph.Node> as first formal parameter.\n\n       Example:\n       (start code js)\n         $jit.Graph.Util.eachNode(graph, function(node) {\n          alert(node.name);\n         });\n         //or...\n         graph.eachNode(function(node) {\n           alert(node.name);\n         });\n       (end code)\n    */\n    eachNode: function(graph, action, flags) {\n        var filter = this.filter(flags);\n        for(var i in graph.nodes) {\n          if(filter(graph.nodes[i])) action(graph.nodes[i]);\n        }\n    },\n\n    /*\n       Method: eachAdjacency\n\n       Iterates over <Graph.Node> adjacencies applying the *action* function.\n\n       Also implemented by:\n\n       <Graph.Node>.\n\n       Parameters:\n\n       node - (object) A <Graph.Node>.\n       action - (function) A callback function having <Graph.Adjacence> as first formal parameter.\n\n       Example:\n       (start code js)\n         $jit.Graph.Util.eachAdjacency(node, function(adj) {\n          alert(adj.nodeTo.name);\n         });\n         //or...\n         node.eachAdjacency(function(adj) {\n           alert(adj.nodeTo.name);\n         });\n       (end code)\n    */\n    eachAdjacency: function(node, action, flags) {\n        var adj = node.adjacencies, filter = this.filter(flags);\n        for(var id in adj) {\n          var a = adj[id];\n          if(filter(a)) {\n            if(a.nodeFrom != node) {\n              var tmp = a.nodeFrom;\n              a.nodeFrom = a.nodeTo;\n              a.nodeTo = tmp;\n            }\n            action(a, id);\n          }\n        }\n    },\n\n     /*\n       Method: computeLevels\n\n       Performs a BFS traversal setting the correct depth for each node.\n\n       Also implemented by:\n\n       <Graph>.\n\n       Note:\n\n       The depth of each node can then be accessed by\n       >node._depth\n\n       Parameters:\n\n       graph - (object) A <Graph>.\n       id - (string) A starting node id for the BFS traversal.\n       startDepth - (optional|number) A minimum depth value. Default's 0.\n\n    */\n    computeLevels: function(graph, id, startDepth, flags) {\n        startDepth = startDepth || 0;\n        var filter = this.filter(flags);\n        this.eachNode(graph, function(elem) {\n            elem._flag = false;\n            elem._depth = -1;\n        }, flags);\n        var root = graph.getNode(id);\n        root._depth = startDepth;\n        var queue = [root];\n        while(queue.length != 0) {\n            var node = queue.pop();\n            node._flag = true;\n            this.eachAdjacency(node, function(adj) {\n                var n = adj.nodeTo;\n                if(n._flag == false && filter(n)) {\n                    if(n._depth < 0) n._depth = node._depth + 1 + startDepth;\n                    queue.unshift(n);\n                }\n            }, flags);\n        }\n    },\n\n    /*\n       Method: eachBFS\n\n       Performs a BFS traversal applying *action* to each <Graph.Node>.\n\n       Also implemented by:\n\n       <Graph>.\n\n       Parameters:\n\n       graph - (object) A <Graph>.\n       id - (string) A starting node id for the BFS traversal.\n       action - (function) A callback function having a <Graph.Node> as first formal parameter.\n\n       Example:\n       (start code js)\n         $jit.Graph.Util.eachBFS(graph, 'mynodeid', function(node) {\n          alert(node.name);\n         });\n         //or...\n         graph.eachBFS('mynodeid', function(node) {\n           alert(node.name);\n         });\n       (end code)\n    */\n    eachBFS: function(graph, id, action, flags) {\n        var filter = this.filter(flags);\n        this.clean(graph);\n        var queue = [graph.getNode(id)];\n        while(queue.length != 0) {\n            var node = queue.pop();\n            node._flag = true;\n            action(node, node._depth);\n            this.eachAdjacency(node, function(adj) {\n                var n = adj.nodeTo;\n                if(n._flag == false && filter(n)) {\n                    n._flag = true;\n                    queue.unshift(n);\n                }\n            }, flags);\n        }\n    },\n\n    /*\n       Method: eachLevel\n\n       Iterates over a node's subgraph applying *action* to the nodes of relative depth between *levelBegin* and *levelEnd*.\n\n       Also implemented by:\n\n       <Graph.Node>.\n\n       Parameters:\n\n       node - (object) A <Graph.Node>.\n       levelBegin - (number) A relative level value.\n       levelEnd - (number) A relative level value.\n       action - (function) A callback function having a <Graph.Node> as first formal parameter.\n\n    */\n    eachLevel: function(node, levelBegin, levelEnd, action, flags) {\n        var d = node._depth, filter = this.filter(flags), that = this;\n        levelEnd = levelEnd === false? Number.MAX_VALUE -d : levelEnd;\n        (function loopLevel(node, levelBegin, levelEnd) {\n            var d = node._depth;\n            if(d >= levelBegin && d <= levelEnd && filter(node)) action(node, d);\n            if(d < levelEnd) {\n                that.eachAdjacency(node, function(adj) {\n                    var n = adj.nodeTo;\n                    if(n._depth > d) loopLevel(n, levelBegin, levelEnd);\n                });\n            }\n        })(node, levelBegin + d, levelEnd + d);\n    },\n\n    /*\n       Method: eachSubgraph\n\n       Iterates over a node's children recursively.\n\n       Also implemented by:\n\n       <Graph.Node>.\n\n       Parameters:\n       node - (object) A <Graph.Node>.\n       action - (function) A callback function having a <Graph.Node> as first formal parameter.\n\n       Example:\n       (start code js)\n         $jit.Graph.Util.eachSubgraph(node, function(node) {\n           alert(node.name);\n         });\n         //or...\n         node.eachSubgraph(function(node) {\n           alert(node.name);\n         });\n       (end code)\n    */\n    eachSubgraph: function(node, action, flags) {\n      this.eachLevel(node, 0, false, action, flags);\n    },\n\n    /*\n       Method: eachSubnode\n\n       Iterates over a node's children (without deeper recursion).\n\n       Also implemented by:\n\n       <Graph.Node>.\n\n       Parameters:\n       node - (object) A <Graph.Node>.\n       action - (function) A callback function having a <Graph.Node> as first formal parameter.\n\n       Example:\n       (start code js)\n         $jit.Graph.Util.eachSubnode(node, function(node) {\n          alert(node.name);\n         });\n         //or...\n         node.eachSubnode(function(node) {\n           alert(node.name);\n         });\n       (end code)\n    */\n    eachSubnode: function(node, action, flags) {\n        this.eachLevel(node, 1, 1, action, flags);\n    },\n\n    /*\n       Method: anySubnode\n\n       Returns *true* if any subnode matches the given condition.\n\n       Also implemented by:\n\n       <Graph.Node>.\n\n       Parameters:\n       node - (object) A <Graph.Node>.\n       cond - (function) A callback function returning a Boolean instance. This function has as first formal parameter a <Graph.Node>.\n\n       Example:\n       (start code js)\n         $jit.Graph.Util.anySubnode(node, function(node) { return node.name == \"mynodename\"; });\n         //or...\n         node.anySubnode(function(node) { return node.name == 'mynodename'; });\n       (end code)\n    */\n    anySubnode: function(node, cond, flags) {\n      var flag = false;\n      cond = cond || $.lambda(true);\n      var c = $.type(cond) == 'string'? function(n) { return n[cond]; } : cond;\n      this.eachSubnode(node, function(elem) {\n        if(c(elem)) flag = true;\n      }, flags);\n      return flag;\n    },\n\n    /*\n       Method: getSubnodes\n\n       Collects all subnodes for a specified node.\n       The *level* parameter filters nodes having relative depth of *level* from the root node.\n\n       Also implemented by:\n\n       <Graph.Node>.\n\n       Parameters:\n       node - (object) A <Graph.Node>.\n       level - (optional|number) Default's *0*. A starting relative depth for collecting nodes.\n\n       Returns:\n       An array of nodes.\n\n    */\n    getSubnodes: function(node, level, flags) {\n        var ans = [], that = this;\n        level = level || 0;\n        var levelStart, levelEnd;\n        if($.type(level) == 'array') {\n            levelStart = level[0];\n            levelEnd = level[1];\n        } else {\n            levelStart = level;\n            levelEnd = Number.MAX_VALUE - node._depth;\n        }\n        this.eachLevel(node, levelStart, levelEnd, function(n) {\n            ans.push(n);\n        }, flags);\n        return ans;\n    },\n\n\n    /*\n       Method: getParents\n\n       Returns an Array of <Graph.Nodes> which are parents of the given node.\n\n       Also implemented by:\n\n       <Graph.Node>.\n\n       Parameters:\n       node - (object) A <Graph.Node>.\n\n       Returns:\n       An Array of <Graph.Nodes>.\n\n       Example:\n       (start code js)\n         var pars = $jit.Graph.Util.getParents(node);\n         //or...\n         var pars = node.getParents();\n\n         if(pars.length > 0) {\n           //do stuff with parents\n         }\n       (end code)\n    */\n    getParents: function(node) {\n        var ans = [];\n        this.eachAdjacency(node, function(adj) {\n            var n = adj.nodeTo;\n            if(n._depth < node._depth) ans.push(n);\n        });\n        return ans;\n    },\n\n    /*\n    Method: isDescendantOf\n\n    Returns a boolean indicating if some node is descendant of the node with the given id.\n\n    Also implemented by:\n\n    <Graph.Node>.\n\n\n    Parameters:\n    node - (object) A <Graph.Node>.\n    id - (string) A <Graph.Node> id.\n\n    Example:\n    (start code js)\n      $jit.Graph.Util.isDescendantOf(node, \"nodeid\"); //true|false\n      //or...\n      node.isDescendantOf('nodeid');//true|false\n    (end code)\n */\n isDescendantOf: function(node, id) {\n    if(node.id == id) return true;\n    var pars = this.getParents(node), ans = false;\n    for ( var i = 0; !ans && i < pars.length; i++) {\n    ans = ans || this.isDescendantOf(pars[i], id);\n  }\n    return ans;\n },\n\n /*\n     Method: clean\n\n     Cleans flags from nodes.\n\n     Also implemented by:\n\n     <Graph>.\n\n     Parameters:\n     graph - A <Graph> instance.\n  */\n  clean: function(graph) { this.eachNode(graph, function(elem) { elem._flag = false; }); },\n\n  /*\n    Method: getClosestNodeToOrigin\n\n    Returns the closest node to the center of canvas.\n\n    Also implemented by:\n\n    <Graph>.\n\n    Parameters:\n\n     graph - (object) A <Graph> instance.\n     prop - (optional|string) Default's 'current'. A <Graph.Node> position property. Possible properties are 'start', 'current' or 'end'.\n\n  */\n  getClosestNodeToOrigin: function(graph, prop, flags) {\n   return this.getClosestNodeToPos(graph, Polar.KER, prop, flags);\n  },\n\n  /*\n    Method: getClosestNodeToPos\n\n    Returns the closest node to the given position.\n\n    Also implemented by:\n\n    <Graph>.\n\n    Parameters:\n\n     graph - (object) A <Graph> instance.\n     pos - (object) A <Complex> or <Polar> instance.\n     prop - (optional|string) Default's *current*. A <Graph.Node> position property. Possible properties are 'start', 'current' or 'end'.\n\n  */\n  getClosestNodeToPos: function(graph, pos, prop, flags) {\n   var node = null;\n   prop = prop || 'current';\n   pos = pos && pos.getc(true) || Complex.KER;\n   var distance = function(a, b) {\n     var d1 = a.x - b.x, d2 = a.y - b.y;\n     return d1 * d1 + d2 * d2;\n   };\n   this.eachNode(graph, function(elem) {\n     node = (node == null || distance(elem.getPos(prop).getc(true), pos) < distance(\n         node.getPos(prop).getc(true), pos)) ? elem : node;\n   }, flags);\n   return node;\n  }\n};\n\n//Append graph methods to <Graph>\n$.each(['getNode', 'eachNode', 'computeLevels', 'eachBFS', 'clean', 'getClosestNodeToPos', 'getClosestNodeToOrigin'], function(m) {\n  Graph.prototype[m] = function() {\n    return Graph.Util[m].apply(Graph.Util, [this].concat(Array.prototype.slice.call(arguments)));\n  };\n});\n\n//Append node methods to <Graph.Node>\n$.each(['eachAdjacency', 'eachLevel', 'eachSubgraph', 'eachSubnode', 'anySubnode', 'getSubnodes', 'getParents', 'isDescendantOf'], function(m) {\n  Graph.Node.prototype[m] = function() {\n    return Graph.Util[m].apply(Graph.Util, [this].concat(Array.prototype.slice.call(arguments)));\n  };\n});\n\n/*\n * File: Graph.Op.js\n *\n*/\n\n/*\n   Object: Graph.Op\n\n   Perform <Graph> operations like adding/removing <Graph.Nodes> or <Graph.Adjacences>,\n   morphing a <Graph> into another <Graph>, contracting or expanding subtrees, etc.\n\n*/\nGraph.Op = {\n\n    options: {\n      type: 'nothing',\n      duration: 2000,\n      hideLabels: true,\n      fps:30\n    },\n    /*\n       Method: removeNode\n\n       Removes one or more <Graph.Nodes> from the visualization.\n       It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.\n\n       Parameters:\n\n        node - (string|array) The node's id. Can also be an array having many ids.\n        opt - (object) Animation options. It's an object with optional properties described below\n        type - (string) Default's *nothing*. Type of the animation. Can be \"nothing\", \"replot\", \"fade:seq\",  \"fade:con\" or \"iter\".\n        duration - Described in <Options.Fx>.\n        fps - Described in <Options.Fx>.\n        transition - Described in <Options.Fx>.\n        hideLabels - (boolean) Default's *true*. Hide labels during the animation.\n\n      Example:\n      (start code js)\n        var viz = new $jit.Viz(options);\n        viz.op.removeNode('nodeId', {\n          type: 'fade:seq',\n          duration: 1000,\n          hideLabels: false,\n          transition: $jit.Trans.Quart.easeOut\n        });\n        //or also\n        viz.op.removeNode(['someId', 'otherId'], {\n          type: 'fade:con',\n          duration: 1500\n        });\n      (end code)\n    */\n\n    removeNode: function(node, opt) {\n        var viz = this.viz;\n        var options = $.merge(this.options, viz.controller, opt);\n        var n = $.splat(node);\n        var i, that, nodeObj;\n        switch(options.type) {\n            case 'nothing':\n                for(i=0; i<n.length; i++) viz.graph.removeNode(n[i]);\n                break;\n\n            case 'replot':\n                this.removeNode(n, { type: 'nothing' });\n                viz.labels.clearLabels();\n                viz.refresh(true);\n                break;\n\n            case 'fade:seq': case 'fade':\n                that = this;\n                // set alpha to 0 for nodes to remove.\n                for(i=0; i<n.length; i++) {\n                    nodeObj = viz.graph.getNode(n[i]);\n                    nodeObj.setData('alpha', 0, 'end');\n                }\n                viz.fx.animate($.merge(options, {\n                    modes: ['node-property:alpha'],\n                    onComplete: function() {\n                        that.removeNode(n, { type: 'nothing' });\n                        viz.labels.clearLabels();\n                        viz.reposition();\n                        viz.fx.animate($.merge(options, {\n                            modes: ['linear']\n                        }));\n                    }\n                }));\n                break;\n\n            case 'fade:con':\n                that = this;\n                //set alpha to 0 for nodes to remove. Tag them for being ignored on computing positions.\n                for(i=0; i<n.length; i++) {\n                    nodeObj = viz.graph.getNode(n[i]);\n                    nodeObj.setData('alpha', 0, 'end');\n                    nodeObj.ignore = true;\n                }\n                viz.reposition();\n                viz.fx.animate($.merge(options, {\n                    modes: ['node-property:alpha', 'linear'],\n                    onComplete: function() {\n                        that.removeNode(n, { type: 'nothing' });\n                    }\n                }));\n                break;\n\n            case 'iter':\n                that = this;\n                viz.fx.sequence({\n                    condition: function() { return n.length != 0; },\n                    step: function() { that.removeNode(n.shift(), { type: 'nothing' });  viz.labels.clearLabels(); },\n                    onComplete: function() { options.onComplete(); },\n                    duration: Math.ceil(options.duration / n.length)\n                });\n                break;\n\n            default: this.doError();\n        }\n    },\n\n    /*\n       Method: removeEdge\n\n       Removes one or more <Graph.Adjacences> from the visualization.\n       It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.\n\n       Parameters:\n\n       vertex - (array) An array having two strings which are the ids of the nodes connected by this edge (i.e ['id1', 'id2']). Can also be a two dimensional array holding many edges (i.e [['id1', 'id2'], ['id3', 'id4'], ...]).\n       opt - (object) Animation options. It's an object with optional properties described below\n       type - (string) Default's *nothing*. Type of the animation. Can be \"nothing\", \"replot\", \"fade:seq\",  \"fade:con\" or \"iter\".\n       duration - Described in <Options.Fx>.\n       fps - Described in <Options.Fx>.\n       transition - Described in <Options.Fx>.\n       hideLabels - (boolean) Default's *true*. Hide labels during the animation.\n\n      Example:\n      (start code js)\n        var viz = new $jit.Viz(options);\n        viz.op.removeEdge(['nodeId', 'otherId'], {\n          type: 'fade:seq',\n          duration: 1000,\n          hideLabels: false,\n          transition: $jit.Trans.Quart.easeOut\n        });\n        //or also\n        viz.op.removeEdge([['someId', 'otherId'], ['id3', 'id4']], {\n          type: 'fade:con',\n          duration: 1500\n        });\n      (end code)\n\n    */\n    removeEdge: function(vertex, opt) {\n        var viz = this.viz;\n        var options = $.merge(this.options, viz.controller, opt);\n        var v = ($.type(vertex[0]) == 'string')? [vertex] : vertex;\n        var i, that, adj;\n        switch(options.type) {\n            case 'nothing':\n                for(i=0; i<v.length; i++)   viz.graph.removeAdjacence(v[i][0], v[i][1]);\n                break;\n\n            case 'replot':\n                this.removeEdge(v, { type: 'nothing' });\n                viz.refresh(true);\n                break;\n\n            case 'fade:seq': case 'fade':\n                that = this;\n                //set alpha to 0 for edges to remove.\n                for(i=0; i<v.length; i++) {\n                    adj = viz.graph.getAdjacence(v[i][0], v[i][1]);\n                    if(adj) {\n                        adj.setData('alpha', 0,'end');\n                    }\n                }\n                viz.fx.animate($.merge(options, {\n                    modes: ['edge-property:alpha'],\n                    onComplete: function() {\n                        that.removeEdge(v, { type: 'nothing' });\n                        viz.reposition();\n                        viz.fx.animate($.merge(options, {\n                            modes: ['linear']\n                        }));\n                    }\n                }));\n                break;\n\n            case 'fade:con':\n                that = this;\n                //set alpha to 0 for nodes to remove. Tag them for being ignored when computing positions.\n                for(i=0; i<v.length; i++) {\n                    adj = viz.graph.getAdjacence(v[i][0], v[i][1]);\n                    if(adj) {\n                        adj.setData('alpha',0 ,'end');\n                        adj.ignore = true;\n                    }\n                }\n                viz.reposition();\n                viz.fx.animate($.merge(options, {\n                    modes: ['edge-property:alpha', 'linear'],\n                    onComplete: function() {\n                        that.removeEdge(v, { type: 'nothing' });\n                    }\n                }));\n                break;\n\n            case 'iter':\n                that = this;\n                viz.fx.sequence({\n                    condition: function() { return v.length != 0; },\n                    step: function() { that.removeEdge(v.shift(), { type: 'nothing' }); viz.labels.clearLabels(); },\n                    onComplete: function() { options.onComplete(); },\n                    duration: Math.ceil(options.duration / v.length)\n                });\n                break;\n\n            default: this.doError();\n        }\n    },\n\n    /*\n       Method: sum\n\n       Adds a new graph to the visualization.\n       The JSON graph (or tree) must at least have a common node with the current graph plotted by the visualization.\n       The resulting graph can be defined as follows <http://mathworld.wolfram.com/GraphSum.html>\n\n       Parameters:\n\n       json - (object) A json tree or graph structure. See also <Loader.loadJSON>.\n       opt - (object) Animation options. It's an object with optional properties described below\n       type - (string) Default's *nothing*. Type of the animation. Can be \"nothing\", \"replot\", \"fade:seq\",  \"fade:con\".\n       duration - Described in <Options.Fx>.\n       fps - Described in <Options.Fx>.\n       transition - Described in <Options.Fx>.\n       hideLabels - (boolean) Default's *true*. Hide labels during the animation.\n\n      Example:\n      (start code js)\n        //...json contains a tree or graph structure...\n\n        var viz = new $jit.Viz(options);\n        viz.op.sum(json, {\n          type: 'fade:seq',\n          duration: 1000,\n          hideLabels: false,\n          transition: $jit.Trans.Quart.easeOut\n        });\n        //or also\n        viz.op.sum(json, {\n          type: 'fade:con',\n          duration: 1500\n        });\n      (end code)\n\n    */\n    sum: function(json, opt) {\n        var viz = this.viz;\n        var options = $.merge(this.options, viz.controller, opt), root = viz.root;\n        var graph;\n        viz.root = opt.id || viz.root;\n        switch(options.type) {\n            case 'nothing':\n                graph = viz.construct(json);\n                graph.eachNode(function(elem) {\n                    elem.eachAdjacency(function(adj) {\n                        viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);\n                    });\n                });\n                break;\n\n            case 'replot':\n                viz.refresh(true);\n                this.sum(json, { type: 'nothing' });\n                viz.refresh(true);\n                break;\n\n            case 'fade:seq': case 'fade': case 'fade:con':\n                that = this;\n                graph = viz.construct(json);\n\n                //set alpha to 0 for nodes to add.\n                var fadeEdges = this.preprocessSum(graph);\n                var modes = !fadeEdges? ['node-property:alpha'] : ['node-property:alpha', 'edge-property:alpha'];\n                viz.reposition();\n                if(options.type != 'fade:con') {\n                    viz.fx.animate($.merge(options, {\n                        modes: ['linear'],\n                        onComplete: function() {\n                            viz.fx.animate($.merge(options, {\n                                modes: modes,\n                                onComplete: function() {\n                                    options.onComplete();\n                                }\n                            }));\n                        }\n                    }));\n                } else {\n                    viz.graph.eachNode(function(elem) {\n                        if (elem.id != root && elem.pos.getp().equals(Polar.KER)) {\n                          elem.pos.set(elem.endPos); elem.startPos.set(elem.endPos);\n                        }\n                    });\n                    viz.fx.animate($.merge(options, {\n                        modes: ['linear'].concat(modes)\n                    }));\n                }\n                break;\n\n            default: this.doError();\n        }\n    },\n\n    /*\n       Method: morph\n\n       This method will transform the current visualized graph into the new JSON representation passed in the method.\n       The JSON object must at least have the root node in common with the current visualized graph.\n\n       Parameters:\n\n       json - (object) A json tree or graph structure. See also <Loader.loadJSON>.\n       opt - (object) Animation options. It's an object with optional properties described below\n       type - (string) Default's *nothing*. Type of the animation. Can be \"nothing\", \"replot\", \"fade:con\".\n       duration - Described in <Options.Fx>.\n       fps - Described in <Options.Fx>.\n       transition - Described in <Options.Fx>.\n       hideLabels - (boolean) Default's *true*. Hide labels during the animation.\n       id - (string) The shared <Graph.Node> id between both graphs.\n\n       extraModes - (optional|object) When morphing with an animation, dollar prefixed data parameters are added to\n                    *endData* and not *data* itself. This way you can animate dollar prefixed parameters during your morphing operation.\n                    For animating these extra-parameters you have to specify an object that has animation groups as keys and animation\n                    properties as values, just like specified in <Graph.Plot.animate>.\n\n      Example:\n      (start code js)\n        //...json contains a tree or graph structure...\n\n        var viz = new $jit.Viz(options);\n        viz.op.morph(json, {\n          type: 'fade',\n          duration: 1000,\n          hideLabels: false,\n          transition: $jit.Trans.Quart.easeOut\n        });\n        //or also\n        viz.op.morph(json, {\n          type: 'fade',\n          duration: 1500\n        });\n        //if the json data contains dollar prefixed params\n        //like $width or $height these too can be animated\n        viz.op.morph(json, {\n          type: 'fade',\n          duration: 1500\n        }, {\n          'node-property': ['width', 'height']\n        });\n      (end code)\n\n    */\n    morph: function(json, opt, extraModes) {\n        var viz = this.viz;\n        var options = $.merge(this.options, viz.controller, opt), root = viz.root;\n        var graph;\n        //TODO(nico) this hack makes morphing work with the Hypertree.\n        //Need to check if it has been solved and this can be removed.\n        viz.root = opt.id || viz.root;\n        switch(options.type) {\n            case 'nothing':\n                graph = viz.construct(json);\n                graph.eachNode(function(elem) {\n                  var nodeExists = viz.graph.hasNode(elem.id);\n                  elem.eachAdjacency(function(adj) {\n                    var adjExists = !!viz.graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id);\n                    viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);\n                    //Update data properties if the node existed\n                    if(adjExists) {\n                      var addedAdj = viz.graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id);\n                      for(var prop in (adj.data || {})) {\n                        addedAdj.data[prop] = adj.data[prop];\n                      }\n                    }\n                  });\n                  //Update data properties if the node existed\n                  if(nodeExists) {\n                    var addedNode = viz.graph.getNode(elem.id);\n                    for(var prop in (elem.data || {})) {\n                      addedNode.data[prop] = elem.data[prop];\n                    }\n                  }\n                });\n                viz.graph.eachNode(function(elem) {\n                    elem.eachAdjacency(function(adj) {\n                        if(!graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id)) {\n                            viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);\n                        }\n                    });\n                    if(!graph.hasNode(elem.id)) viz.graph.removeNode(elem.id);\n                });\n\n                break;\n\n            case 'replot':\n                viz.labels.clearLabels(true);\n                this.morph(json, { type: 'nothing' });\n                viz.refresh(true);\n                viz.refresh(true);\n                break;\n\n            case 'fade:seq': case 'fade': case 'fade:con':\n                that = this;\n                graph = viz.construct(json);\n                //preprocessing for nodes to delete.\n                viz.graph.eachNode(function(elem) {\n                  var graphNode = graph.getNode(elem.id);\n                  if(!graphNode) {\n                      elem.setData('alpha', 1);\n                      elem.setData('alpha', 1, 'start');\n                      elem.setData('alpha', 0, 'end');\n                      elem.ignore = true;\n                    } else {\n                      //Update node data information\n                      var graphNodeData = graphNode.data;\n                      for(var prop in graphNodeData) {\n                        if(prop[0] == '$' && prop != '$type') {\n                          elem.endData[prop] = graphNodeData[prop];\n                        } else {\n                          elem.data[prop] = graphNodeData[prop];\n                        }\n                      }\n                    }\n                });\n                viz.graph.eachNode(function(elem) {\n                    if(elem.ignore) return;\n                    elem.eachAdjacency(function(adj) {\n                        if(adj.nodeFrom.ignore || adj.nodeTo.ignore) return;\n                        var nodeFrom = graph.getNode(adj.nodeFrom.id);\n                        var nodeTo = graph.getNode(adj.nodeTo.id);\n                        if(!nodeFrom.adjacentTo(nodeTo)) {\n                            var adj = viz.graph.getAdjacence(nodeFrom.id, nodeTo.id);\n                            fadeEdges = true;\n                            adj.setData('alpha', 1);\n                            adj.setData('alpha', 1, 'start');\n                            adj.setData('alpha', 0, 'end');\n                        }\n                    });\n                });\n                //preprocessing for adding nodes.\n                var fadeEdges = this.preprocessSum(graph);\n\n                var modes = !fadeEdges? ['node-property:alpha'] :\n                                        ['node-property:alpha',\n                                         'edge-property:alpha'];\n                //Append extra node-property animations (if any)\n        // console.log(\"modes 0\" + modes[0]);\n        // console.log(\"extra modes \" + extraModes);\n                modes[0] = modes[0] + ((extraModes && ('node-property' in extraModes))?\n                    $.splat(extraModes['node-property']).join(':') : '');\n        modes[0] = \"node-property:dim\"; //HACK HACK BUGBUG\n                //Append extra edge-property animations (if any)\n                modes[1] = (modes[1] || 'edge-property:alpha') + ((extraModes && ('edge-property' in extraModes))?\n                    $.splat(extraModes['edge-property']).join(':') : '');\n                //Add label-property animations (if any)\n                if(extraModes && ('label-property' in extraModes)) {\n                  modes.push('label-property' + $.splat(extraModes['label-property']).join(':'))\n                }\n        // console.log(\"modes: \" + modes[0]);\n                viz.reposition();\n                viz.graph.eachNode(function(elem) {\n                    if (elem.id != root && elem.pos.getp().equals(Polar.KER)) {\n                      elem.pos.set(elem.endPos); elem.startPos.set(elem.endPos);\n                    }\n                });\n                viz.fx.animate($.merge(options, {\n                    modes: ['polar'].concat(modes),\n                    onComplete: function() {\n                        viz.graph.eachNode(function(elem) {\n                            if(elem.ignore) viz.graph.removeNode(elem.id);\n                        });\n                        viz.graph.eachNode(function(elem) {\n                            elem.eachAdjacency(function(adj) {\n                                if(adj.ignore) viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);\n                            });\n                        });\n                        options.onComplete();\n                    }\n                }));\n                break;\n\n            default:;\n        }\n    },\n\n\n  /*\n    Method: contract\n\n    Collapses the subtree of the given node. The node will have a _collapsed=true_ property.\n\n    Parameters:\n\n    node - (object) A <Graph.Node>.\n    opt - (object) An object containing options described below\n    type - (string) Whether to 'replot' or 'animate' the contraction.\n\n    There are also a number of Animation options. For more information see <Options.Fx>.\n\n    Example:\n    (start code js)\n     var viz = new $jit.Viz(options);\n     viz.op.contract(node, {\n       type: 'animate',\n       duration: 1000,\n       hideLabels: true,\n       transition: $jit.Trans.Quart.easeOut\n     });\n   (end code)\n\n   */\n    contract: function(node, opt) {\n      var viz = this.viz;\n      if(node.collapsed || !node.anySubnode($.lambda(true))) return;\n      opt = $.merge(this.options, viz.config, opt || {}, {\n        'modes': ['node-property:alpha:span', 'linear']\n      });\n      node.collapsed = true;\n      (function subn(n) {\n        n.eachSubnode(function(ch) {\n          ch.ignore = true;\n          ch.setData('alpha', 0, opt.type == 'animate'? 'end' : 'current');\n          subn(ch);\n        });\n      })(node);\n      if(opt.type == 'animate') {\n        viz.compute('end');\n        if(viz.rotated) {\n          viz.rotate(viz.rotated, 'none', {\n            'property':'end'\n          });\n        }\n        (function subn(n) {\n          n.eachSubnode(function(ch) {\n            ch.setPos(node.getPos('end'), 'end');\n            subn(ch);\n          });\n        })(node);\n        viz.fx.animate(opt);\n      } else if(opt.type == 'replot'){\n        viz.refresh();\n      }\n    },\n\n    /*\n    Method: expand\n\n    Expands the previously contracted subtree. The given node must have the _collapsed=true_ property.\n\n    Parameters:\n\n    node - (object) A <Graph.Node>.\n    opt - (object) An object containing options described below\n    type - (string) Whether to 'replot' or 'animate'.\n\n    There are also a number of Animation options. For more information see <Options.Fx>.\n\n    Example:\n    (start code js)\n      var viz = new $jit.Viz(options);\n      viz.op.expand(node, {\n        type: 'animate',\n        duration: 1000,\n        hideLabels: true,\n        transition: $jit.Trans.Quart.easeOut\n      });\n    (end code)\n\n   */\n    expand: function(node, opt) {\n      if(!('collapsed' in node)) return;\n      var viz = this.viz;\n      opt = $.merge(this.options, viz.config, opt || {}, {\n        'modes': ['node-property:alpha:span', 'linear']\n      });\n      delete node.collapsed;\n      (function subn(n) {\n        n.eachSubnode(function(ch) {\n          delete ch.ignore;\n          ch.setData('alpha', 1, opt.type == 'animate'? 'end' : 'current');\n          subn(ch);\n        });\n      })(node);\n      if(opt.type == 'animate') {\n        viz.compute('end');\n        if(viz.rotated) {\n          viz.rotate(viz.rotated, 'none', {\n            'property':'end'\n          });\n        }\n        viz.fx.animate(opt);\n      } else if(opt.type == 'replot'){\n        viz.refresh();\n      }\n    },\n\n    preprocessSum: function(graph) {\n        var viz = this.viz;\n        graph.eachNode(function(elem) {\n            if(!viz.graph.hasNode(elem.id)) {\n                viz.graph.addNode(elem);\n                var n = viz.graph.getNode(elem.id);\n                n.setData('alpha', 0);\n                n.setData('alpha', 0, 'start');\n                n.setData('alpha', 1, 'end');\n            }\n        });\n        var fadeEdges = false;\n        graph.eachNode(function(elem) {\n            elem.eachAdjacency(function(adj) {\n                var nodeFrom = viz.graph.getNode(adj.nodeFrom.id);\n                var nodeTo = viz.graph.getNode(adj.nodeTo.id);\n                if(!nodeFrom.adjacentTo(nodeTo)) {\n                    var adj = viz.graph.addAdjacence(nodeFrom, nodeTo, adj.data);\n                    if(nodeFrom.startAlpha == nodeFrom.endAlpha\n                    && nodeTo.startAlpha == nodeTo.endAlpha) {\n                        fadeEdges = true;\n                        adj.setData('alpha', 0);\n                        adj.setData('alpha', 0, 'start');\n                        adj.setData('alpha', 1, 'end');\n                    }\n                }\n            });\n        });\n        return fadeEdges;\n    }\n};\n\n\n\n/*\n   File: Helpers.js\n\n   Helpers are objects that contain rendering primitives (like rectangles, ellipses, etc), for plotting nodes and edges.\n   Helpers also contain implementations of the *contains* method, a method returning a boolean indicating whether the mouse\n   position is over the rendered shape.\n\n   Helpers are very useful when implementing new NodeTypes, since you can access them through *this.nodeHelper* and\n   *this.edgeHelper* <Graph.Plot> properties, providing you with simple primitives and mouse-position check functions.\n\n   Example:\n   (start code js)\n   //implement a new node type\n   $jit.Viz.Plot.NodeTypes.implement({\n     'customNodeType': {\n       'render': function(node, canvas) {\n         this.nodeHelper.circle.render ...\n       },\n       'contains': function(node, pos) {\n         this.nodeHelper.circle.contains ...\n       }\n     }\n   });\n   //implement an edge type\n   //edges do not implement the contains method\n   $jit.Viz.Plot.EdgeTypes.implement({\n     'customEdgeType': function(adj, canvas) {\n       this.edgeHelper.line ...\n     }\n   });\n   (end code)\n\n*/\n\n/*\n   Object: NodeHelper\n\n   Contains rendering and other type of primitives for simple shapes.\n */\nvar NodeHelper = {\n  'none': {\n    'render': $.empty,\n    'contains': $.lambda(false)\n  },\n  /*\n   Object: NodeHelper.circle\n   */\n  'circle': {\n    /*\n     Method: render\n\n     Renders a circle into the canvas.\n\n     Parameters:\n\n     type - (string) Possible options are 'fill' or 'stroke'.\n     pos - (object) An *x*, *y* object with the position of the center of the circle.\n     radius - (number) The radius of the circle to be rendered.\n     canvas - (object) A <Canvas> instance.\n\n     Example:\n     (start code js)\n     NodeHelper.circle.render('fill', { x: 10, y: 30 }, 30, viz.canvas);\n     (end code)\n     */\n    'render': function(type, pos, radius, canvas){\n      var ctx = canvas.getCtx();\n      ctx.beginPath();\n      ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2, true);\n      ctx.closePath();\n      ctx[type]();\n    },\n    /*\n    Method: contains\n\n    Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.\n\n    Parameters:\n\n    npos - (object) An *x*, *y* object with the <Graph.Node> position.\n    pos - (object) An *x*, *y* object with the position to check.\n    radius - (number) The radius of the rendered circle.\n\n    Example:\n    (start code js)\n    NodeHelper.circle.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30); //true\n    (end code)\n    */\n    'contains': function(npos, pos, radius){\n      var diffx = npos.x - pos.x,\n          diffy = npos.y - pos.y,\n          diff = diffx * diffx + diffy * diffy;\n      return diff <= radius * radius;\n    }\n  },\n  /*\n  Object: NodeHelper.ellipse\n  */\n  'ellipse': {\n    /*\n    Method: render\n\n    Renders an ellipse into the canvas.\n\n    Parameters:\n\n    type - (string) Possible options are 'fill' or 'stroke'.\n    pos - (object) An *x*, *y* object with the position of the center of the ellipse.\n    width - (number) The width of the ellipse.\n    height - (number) The height of the ellipse.\n    canvas - (object) A <Canvas> instance.\n\n    Example:\n    (start code js)\n    NodeHelper.ellipse.render('fill', { x: 10, y: 30 }, 30, 40, viz.canvas);\n    (end code)\n    */\n    'render': function(type, pos, width, height, canvas){\n      var ctx = canvas.getCtx();\n      height /= 2;\n      width /= 2;\n      ctx.save();\n      ctx.scale(width / height, height / width);\n      ctx.beginPath();\n      ctx.arc(pos.x * (height / width), pos.y * (width / height), height, 0,\n          Math.PI * 2, true);\n      ctx.closePath();\n      ctx[type]();\n      ctx.restore();\n    },\n    /*\n    Method: contains\n\n    Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.\n\n    Parameters:\n\n    npos - (object) An *x*, *y* object with the <Graph.Node> position.\n    pos - (object) An *x*, *y* object with the position to check.\n    width - (number) The width of the rendered ellipse.\n    height - (number) The height of the rendered ellipse.\n\n    Example:\n    (start code js)\n    NodeHelper.ellipse.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30, 40);\n    (end code)\n    */\n    'contains': function(npos, pos, width, height){\n      // TODO(nico): be more precise...\n      width /= 2;\n      height /= 2;\n      var dist = (width + height) / 2,\n          diffx = npos.x - pos.x,\n          diffy = npos.y - pos.y,\n          diff = diffx * diffx + diffy * diffy;\n      return diff <= dist * dist;\n    }\n  },\n  /*\n  Object: NodeHelper.square\n  */\n  'square': {\n    /*\n    Method: render\n\n    Renders a square into the canvas.\n\n    Parameters:\n\n    type - (string) Possible options are 'fill' or 'stroke'.\n    pos - (object) An *x*, *y* object with the position of the center of the square.\n    dim - (number) The radius (or half-diameter) of the square.\n    canvas - (object) A <Canvas> instance.\n\n    Example:\n    (start code js)\n    NodeHelper.square.render('stroke', { x: 10, y: 30 }, 40, viz.canvas);\n    (end code)\n    */\n    'render': function(type, pos, dim, canvas){\n      canvas.getCtx()[type + \"Rect\"](pos.x - dim, pos.y - dim, 2*dim, 2*dim);\n    },\n    /*\n    Method: contains\n\n    Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.\n\n    Parameters:\n\n    npos - (object) An *x*, *y* object with the <Graph.Node> position.\n    pos - (object) An *x*, *y* object with the position to check.\n    dim - (number) The radius (or half-diameter) of the square.\n\n    Example:\n    (start code js)\n    NodeHelper.square.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30);\n    (end code)\n    */\n    'contains': function(npos, pos, dim){\n      return Math.abs(pos.x - npos.x) <= dim && Math.abs(pos.y - npos.y) <= dim;\n    }\n  },\n  /*\n  Object: NodeHelper.rectangle\n  */\n  'rectangle': {\n    /*\n    Method: render\n\n    Renders a rectangle into the canvas.\n\n    Parameters:\n\n    type - (string) Possible options are 'fill' or 'stroke'.\n    pos - (object) An *x*, *y* object with the position of the center of the rectangle.\n    width - (number) The width of the rectangle.\n    height - (number) The height of the rectangle.\n    canvas - (object) A <Canvas> instance.\n\n    Example:\n    (start code js)\n    NodeHelper.rectangle.render('fill', { x: 10, y: 30 }, 30, 40, viz.canvas);\n    (end code)\n    */\n    'render': function(type, pos, width, height, canvas){\n      canvas.getCtx()[type + \"Rect\"](pos.x - width / 2, pos.y - height / 2,\n                                      width, height);\n    },\n    /*\n    Method: contains\n\n    Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.\n\n    Parameters:\n\n    npos - (object) An *x*, *y* object with the <Graph.Node> position.\n    pos - (object) An *x*, *y* object with the position to check.\n    width - (number) The width of the rendered rectangle.\n    height - (number) The height of the rendered rectangle.\n\n    Example:\n    (start code js)\n    NodeHelper.rectangle.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30, 40);\n    (end code)\n    */\n    'contains': function(npos, pos, width, height){\n      return Math.abs(pos.x - npos.x) <= width / 2\n          && Math.abs(pos.y - npos.y) <= height / 2;\n    }\n  },\n  /*\n  Object: NodeHelper.triangle\n  */\n  'triangle': {\n    /*\n    Method: render\n\n    Renders a triangle into the canvas.\n\n    Parameters:\n\n    type - (string) Possible options are 'fill' or 'stroke'.\n    pos - (object) An *x*, *y* object with the position of the center of the triangle.\n    dim - (number) The dimension of the triangle.\n    canvas - (object) A <Canvas> instance.\n\n    Example:\n    (start code js)\n    NodeHelper.triangle.render('stroke', { x: 10, y: 30 }, 40, viz.canvas);\n    (end code)\n    */\n    'render': function(type, pos, dim, canvas){\n      var ctx = canvas.getCtx(),\n          c1x = pos.x,\n          c1y = pos.y - dim,\n          c2x = c1x - dim,\n          c2y = pos.y + dim,\n          c3x = c1x + dim,\n          c3y = c2y;\n      ctx.beginPath();\n      ctx.moveTo(c1x, c1y);\n      ctx.lineTo(c2x, c2y);\n      ctx.lineTo(c3x, c3y);\n      ctx.closePath();\n      ctx[type]();\n    },\n    /*\n    Method: contains\n\n    Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.\n\n    Parameters:\n\n    npos - (object) An *x*, *y* object with the <Graph.Node> position.\n    pos - (object) An *x*, *y* object with the position to check.\n    dim - (number) The dimension of the shape.\n\n    Example:\n    (start code js)\n    NodeHelper.triangle.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30);\n    (end code)\n    */\n    'contains': function(npos, pos, dim) {\n      return NodeHelper.circle.contains(npos, pos, dim);\n    }\n  },\n  /*\n  Object: NodeHelper.star\n  */\n  'star': {\n    /*\n    Method: render\n\n    Renders a star into the canvas.\n\n    Parameters:\n\n    type - (string) Possible options are 'fill' or 'stroke'.\n    pos - (object) An *x*, *y* object with the position of the center of the star.\n    dim - (number) The dimension of the star.\n    canvas - (object) A <Canvas> instance.\n\n    Example:\n    (start code js)\n    NodeHelper.star.render('stroke', { x: 10, y: 30 }, 40, viz.canvas);\n    (end code)\n    */\n    'render': function(type, pos, dim, canvas){\n      var ctx = canvas.getCtx(),\n          pi5 = Math.PI / 5;\n      ctx.save();\n      ctx.translate(pos.x, pos.y);\n      ctx.beginPath();\n      ctx.moveTo(dim, 0);\n      for (var i = 0; i < 9; i++) {\n        ctx.rotate(pi5);\n        if (i % 2 == 0) {\n          ctx.lineTo((dim / 0.525731) * 0.200811, 0);\n        } else {\n          ctx.lineTo(dim, 0);\n        }\n      }\n      ctx.closePath();\n      ctx[type]();\n      ctx.restore();\n    },\n    /*\n    Method: contains\n\n    Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.\n\n    Parameters:\n\n    npos - (object) An *x*, *y* object with the <Graph.Node> position.\n    pos - (object) An *x*, *y* object with the position to check.\n    dim - (number) The dimension of the shape.\n\n    Example:\n    (start code js)\n    NodeHelper.star.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, 30);\n    (end code)\n    */\n    'contains': function(npos, pos, dim) {\n      return NodeHelper.circle.contains(npos, pos, dim);\n    }\n  }\n};\n\n/*\n  Object: EdgeHelper\n\n  Contains rendering primitives for simple edge shapes.\n*/\nvar EdgeHelper = {\n    /*\n    Method: line\n\n    Renders a line into the canvas.\n\n    Parameters:\n\n    from - (object) An *x*, *y* object with the starting position of the line.\n    to - (object) An *x*, *y* object with the ending position of the line.\n    canvas - (object) A <Canvas> instance.\n\n    Example:\n    (start code js)\n    EdgeHelper.line({ x: 10, y: 30 }, { x: 10, y: 50 }, viz.canvas);\n    (end code)\n    */\n  'line': function(from, to, canvas){\n    var ctx = canvas.getCtx();\n    ctx.beginPath();\n    ctx.moveTo(from.x, from.y);\n    ctx.lineTo(to.x, to.y);\n    ctx.stroke();\n  },\n  /*\n  Method: arrow\n\n  Renders an arrow into the canvas.\n\n  Parameters:\n\n  from - (object) An *x*, *y* object with the starting position of the arrow.\n  to - (object) An *x*, *y* object with the ending position of the arrow.\n  dim - (number) The dimension of the arrow.\n  swap - (boolean) Whether to set the arrow pointing to the starting position or the ending position.\n  canvas - (object) A <Canvas> instance.\n\n  Example:\n  (start code js)\n  EdgeHelper.arrow({ x: 10, y: 30 }, { x: 10, y: 50 }, 13, false, viz.canvas);\n  (end code)\n  */\n  'arrow': function(from, to, dim, swap, canvas){\n    var ctx = canvas.getCtx();\n    // invert edge direction\n    if (swap) {\n      var tmp = from;\n      from = to;\n      to = tmp;\n    }\n    var vect = new Complex(to.x - from.x, to.y - from.y);\n    vect.$scale(dim / vect.norm());\n    var intermediatePoint = new Complex(to.x - vect.x, to.y - vect.y),\n        normal = new Complex(-vect.y / 2, vect.x / 2),\n        v1 = intermediatePoint.add(normal),\n        v2 = intermediatePoint.$add(normal.$scale(-1));\n\n    ctx.beginPath();\n    ctx.moveTo(from.x, from.y);\n    ctx.lineTo(to.x, to.y);\n    ctx.stroke();\n    ctx.beginPath();\n    ctx.moveTo(v1.x, v1.y);\n    ctx.lineTo(v2.x, v2.y);\n    ctx.lineTo(to.x, to.y);\n    ctx.closePath();\n    ctx.fill();\n  },\n  /*\n  Method: hyperline\n\n  Renders a hyperline into the canvas. A hyperline are the lines drawn for the <Hypertree> visualization.\n\n  Parameters:\n\n  from - (object) An *x*, *y* object with the starting position of the hyperline. *x* and *y* must belong to [0, 1).\n  to - (object) An *x*, *y* object with the ending position of the hyperline. *x* and *y* must belong to [0, 1).\n  r - (number) The scaling factor.\n  canvas - (object) A <Canvas> instance.\n\n  Example:\n  (start code js)\n  EdgeHelper.hyperline({ x: 10, y: 30 }, { x: 10, y: 50 }, 100, viz.canvas);\n  (end code)\n  */\n  'hyperline': function(from, to, r, canvas){\n    var ctx = canvas.getCtx();\n    var centerOfCircle = computeArcThroughTwoPoints(from, to);\n    if (centerOfCircle.a > 1000 || centerOfCircle.b > 1000\n        || centerOfCircle.ratio < 0) {\n      ctx.beginPath();\n      ctx.moveTo(from.x * r, from.y * r);\n      ctx.lineTo(to.x * r, to.y * r);\n      ctx.stroke();\n    } else {\n      var angleBegin = Math.atan2(to.y - centerOfCircle.y, to.x\n          - centerOfCircle.x);\n      var angleEnd = Math.atan2(from.y - centerOfCircle.y, from.x\n          - centerOfCircle.x);\n      var sense = sense(angleBegin, angleEnd);\n      ctx.beginPath();\n      ctx.arc(centerOfCircle.x * r, centerOfCircle.y * r, centerOfCircle.ratio\n          * r, angleBegin, angleEnd, sense);\n      ctx.stroke();\n    }\n    /*\n      Calculates the arc parameters through two points.\n\n      More information in <http://en.wikipedia.org/wiki/Poincar%C3%A9_disc_model#Analytic_geometry_constructions_in_the_hyperbolic_plane>\n\n      Parameters:\n\n      p1 - A <Complex> instance.\n      p2 - A <Complex> instance.\n      scale - The Disk's diameter.\n\n      Returns:\n\n      An object containing some arc properties.\n    */\n    function computeArcThroughTwoPoints(p1, p2){\n      var aDen = (p1.x * p2.y - p1.y * p2.x), bDen = aDen;\n      var sq1 = p1.squaredNorm(), sq2 = p2.squaredNorm();\n      // Fall back to a straight line\n      if (aDen == 0)\n        return {\n          x: 0,\n          y: 0,\n          ratio: -1\n        };\n\n      var a = (p1.y * sq2 - p2.y * sq1 + p1.y - p2.y) / aDen;\n      var b = (p2.x * sq1 - p1.x * sq2 + p2.x - p1.x) / bDen;\n      var x = -a / 2;\n      var y = -b / 2;\n      var squaredRatio = (a * a + b * b) / 4 - 1;\n      // Fall back to a straight line\n      if (squaredRatio < 0)\n        return {\n          x: 0,\n          y: 0,\n          ratio: -1\n        };\n      var ratio = Math.sqrt(squaredRatio);\n      var out = {\n        x: x,\n        y: y,\n        ratio: ratio > 1000? -1 : ratio,\n        a: a,\n        b: b\n      };\n\n      return out;\n    }\n    /*\n      Sets angle direction to clockwise (true) or counterclockwise (false).\n\n      Parameters:\n\n         angleBegin - Starting angle for drawing the arc.\n         angleEnd - The HyperLine will be drawn from angleBegin to angleEnd.\n\n      Returns:\n\n         A Boolean instance describing the sense for drawing the HyperLine.\n    */\n    function sense(angleBegin, angleEnd){\n      return (angleBegin < angleEnd)? ((angleBegin + Math.PI > angleEnd)? false\n          : true) : ((angleEnd + Math.PI > angleBegin)? true : false);\n    }\n  }\n};\n\n\n/*\n * File: Graph.Plot.js\n */\n\n/*\n   Object: Graph.Plot\n\n   <Graph> rendering and animation methods.\n\n   Properties:\n\n   nodeHelper - <NodeHelper> object.\n   edgeHelper - <EdgeHelper> object.\n*/\nGraph.Plot = {\n    //Add helpers\n    nodeHelper: NodeHelper,\n    edgeHelper: EdgeHelper,\n\n    Interpolator: {\n        //node/edge property parsers\n        'map': {\n          'border': 'color',\n          'color': 'color',\n          'width': 'number',\n          'height': 'number',\n          'dim': 'number',\n          'alpha': 'number',\n          'lineWidth': 'number',\n          'angularWidth':'number',\n          'span':'number',\n          'valueArray':'array-number',\n          'dimArray':'array-number'\n          //'colorArray':'array-color'\n        },\n\n        //canvas specific parsers\n        'canvas': {\n          'globalAlpha': 'number',\n          'fillStyle': 'color',\n          'strokeStyle': 'color',\n          'lineWidth': 'number',\n          'shadowBlur': 'number',\n          'shadowColor': 'color',\n          'shadowOffsetX': 'number',\n          'shadowOffsetY': 'number',\n          'miterLimit': 'number'\n        },\n\n        //label parsers\n        'label': {\n          'size': 'number',\n          'color': 'color'\n        },\n\n        //Number interpolator\n        'compute': function(from, to, delta) {\n          return from + (to - from) * delta;\n        },\n\n        //Position interpolators\n        'moebius': function(elem, props, delta, vector) {\n          var v = vector.scale(-delta);\n          if(v.norm() < 1) {\n              var x = v.x, y = v.y;\n              var ans = elem.startPos\n                .getc().moebiusTransformation(v);\n              elem.pos.setc(ans.x, ans.y);\n              v.x = x; v.y = y;\n            }\n        },\n\n        'linear': function(elem, props, delta) {\n            var from = elem.startPos.getc(true);\n            var to = elem.endPos.getc(true);\n            elem.pos.setc(this.compute(from.x, to.x, delta),\n                          this.compute(from.y, to.y, delta));\n        },\n\n        'polar': function(elem, props, delta) {\n          var from = elem.startPos.getp(true);\n          var to = elem.endPos.getp();\n          var ans = to.interpolate(from, delta);\n          elem.pos.setp(ans.theta, ans.rho);\n        },\n\n        //Graph's Node/Edge interpolators\n        'number': function(elem, prop, delta, getter, setter) {\n          var from = elem[getter](prop, 'start');\n          var to = elem[getter](prop, 'end');\n          elem[setter](prop, this.compute(from, to, delta));\n        },\n\n        'color': function(elem, prop, delta, getter, setter) {\n          var from = $.hexToRgb(elem[getter](prop, 'start'));\n          var to = $.hexToRgb(elem[getter](prop, 'end'));\n          var comp = this.compute;\n          var val = $.rgbToHex([parseInt(comp(from[0], to[0], delta)),\n                                parseInt(comp(from[1], to[1], delta)),\n                                parseInt(comp(from[2], to[2], delta))]);\n\n          elem[setter](prop, val);\n        },\n\n        'array-number': function(elem, prop, delta, getter, setter) {\n          var from = elem[getter](prop, 'start'),\n              to = elem[getter](prop, 'end'),\n              cur = [];\n          for(var i=0, l=from.length; i<l; i++) {\n            var fromi = from[i], toi = to[i];\n            if(fromi.length) {\n              for(var j=0, len=fromi.length, curi=[]; j<len; j++) {\n                curi.push(this.compute(fromi[j], toi[j], delta));\n              }\n              cur.push(curi);\n            } else {\n              cur.push(this.compute(fromi, toi, delta));\n            }\n          }\n          elem[setter](prop, cur);\n        },\n\n        'node': function(elem, props, delta, map, getter, setter) {\n          map = this[map];\n          if(props) {\n            var len = props.length;\n            for(var i=0; i<len; i++) {\n              var pi = props[i];\n              this[map[pi]](elem, pi, delta, getter, setter);\n            }\n          } else {\n            for(var pi in map) {\n              this[map[pi]](elem, pi, delta, getter, setter);\n            }\n          }\n        },\n\n        'edge': function(elem, props, delta, mapKey, getter, setter) {\n            var adjs = elem.adjacencies;\n            for(var id in adjs) this['node'](adjs[id], props, delta, mapKey, getter, setter);\n        },\n\n        'node-property': function(elem, props, delta) {\n    // console.log(\"called with: elem:\" + elem + \" props: \" + props + \"  delta:\" + delta)\n          this['node'](elem, props, delta, 'map', 'getData', 'setData');\n        },\n\n        'edge-property': function(elem, props, delta) {\n          this['edge'](elem, props, delta, 'map', 'getData', 'setData');\n        },\n\n        'label-property': function(elem, props, delta) {\n          this['node'](elem, props, delta, 'label', 'getLabelData', 'setLabelData');\n        },\n\n        'node-style': function(elem, props, delta) {\n          this['node'](elem, props, delta, 'canvas', 'getCanvasStyle', 'setCanvasStyle');\n        },\n\n        'edge-style': function(elem, props, delta) {\n          this['edge'](elem, props, delta, 'canvas', 'getCanvasStyle', 'setCanvasStyle');\n        }\n    },\n\n\n    /*\n       sequence\n\n       Iteratively performs an action while refreshing the state of the visualization.\n\n       Parameters:\n\n       options - (object) An object containing some sequence options described below\n       condition - (function) A function returning a boolean instance in order to stop iterations.\n       step - (function) A function to execute on each step of the iteration.\n       onComplete - (function) A function to execute when the sequence finishes.\n       duration - (number) Duration (in milliseconds) of each step.\n\n      Example:\n       (start code js)\n        var rg = new $jit.RGraph(options);\n        var i = 0;\n        rg.fx.sequence({\n          condition: function() {\n           return i == 10;\n          },\n          step: function() {\n            alert(i++);\n          },\n          onComplete: function() {\n           alert('done!');\n          }\n        });\n       (end code)\n\n    */\n    sequence: function(options) {\n        var that = this;\n        options = $.merge({\n          condition: $.lambda(false),\n          step: $.empty,\n          onComplete: $.empty,\n          duration: 200\n        }, options || {});\n\n        var interval = setInterval(function() {\n          if(options.condition()) {\n            options.step();\n          } else {\n            clearInterval(interval);\n            options.onComplete();\n          }\n          that.viz.refresh(true);\n        }, options.duration);\n    },\n\n    /*\n      prepare\n\n      Prepare graph position and other attribute values before performing an Animation.\n      This method is used internally by the Toolkit.\n\n      See also:\n\n       <Animation>, <Graph.Plot.animate>\n\n    */\n    prepare: function(modes) {\n      var graph = this.viz.graph,\n          accessors = {\n            'node-property': {\n              'getter': 'getData',\n              'setter': 'setData'\n            },\n            'edge-property': {\n              'getter': 'getData',\n              'setter': 'setData'\n            },\n            'node-style': {\n              'getter': 'getCanvasStyle',\n              'setter': 'setCanvasStyle'\n            },\n            'edge-style': {\n              'getter': 'getCanvasStyle',\n              'setter': 'setCanvasStyle'\n            }\n          };\n\n      //parse modes\n      var m = {};\n      if($.type(modes) == 'array') {\n        for(var i=0, len=modes.length; i < len; i++) {\n          var elems = modes[i].split(':');\n          m[elems.shift()] = elems;\n        }\n      } else {\n        for(var p in modes) {\n          if(p == 'position') {\n            m[modes.position] = [];\n          } else {\n            m[p] = $.splat(modes[p]);\n          }\n        }\n      }\n\n      graph.eachNode(function(node) {\n        node.startPos.set(node.pos);\n        $.each(['node-property', 'node-style'], function(p) {\n          if(p in m) {\n            var prop = m[p];\n            for(var i=0, l=prop.length; i < l; i++) {\n              node[accessors[p].setter](prop[i], node[accessors[p].getter](prop[i]), 'start');\n            }\n          }\n        });\n        $.each(['edge-property', 'edge-style'], function(p) {\n          if(p in m) {\n            var prop = m[p];\n            node.eachAdjacency(function(adj) {\n              for(var i=0, l=prop.length; i < l; i++) {\n                adj[accessors[p].setter](prop[i], adj[accessors[p].getter](prop[i]), 'start');\n              }\n            });\n          }\n        });\n      });\n      return m;\n    },\n\n    /*\n       Method: animate\n\n       Animates a <Graph> by interpolating some <Graph.Node>, <Graph.Adjacence> or <Graph.Label> properties.\n\n       Parameters:\n\n       opt - (object) Animation options. The object properties are described below\n       duration - (optional) Described in <Options.Fx>.\n       fps - (optional) Described in <Options.Fx>.\n       hideLabels - (optional|boolean) Whether to hide labels during the animation.\n       modes - (required|object) An object with animation modes (described below).\n\n       Animation modes:\n\n       Animation modes are strings representing different node/edge and graph properties that you'd like to animate.\n       They are represented by an object that has as keys main categories of properties to animate and as values a list\n       of these specific properties. The properties are described below\n\n       position - Describes the way nodes' positions must be interpolated. Possible values are 'linear', 'polar' or 'moebius'.\n       node-property - Describes which Node properties will be interpolated. These properties can be any of the ones defined in <Options.Node>.\n       edge-property - Describes which Edge properties will be interpolated. These properties can be any the ones defined in <Options.Edge>.\n       label-property - Describes which Label properties will be interpolated. These properties can be any of the ones defined in <Options.Label> like color or size.\n       node-style - Describes which Node Canvas Styles will be interpolated. These are specific canvas properties like fillStyle, strokeStyle, lineWidth, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, etc.\n       edge-style - Describes which Edge Canvas Styles will be interpolated. These are specific canvas properties like fillStyle, strokeStyle, lineWidth, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, etc.\n\n       Example:\n       (start code js)\n       var viz = new $jit.Viz(options);\n       //...tweak some Data, CanvasStyles or LabelData properties...\n       viz.fx.animate({\n         modes: {\n           'position': 'linear',\n           'node-property': ['width', 'height'],\n           'node-style': 'shadowColor',\n           'label-property': 'size'\n         },\n         hideLabels: false\n       });\n       //...can also be written like this...\n       viz.fx.animate({\n         modes: ['linear',\n                 'node-property:width:height',\n                 'node-style:shadowColor',\n                 'label-property:size'],\n         hideLabels: false\n       });\n       (end code)\n    */\n    animate: function(opt, versor) {\n      opt = $.merge(this.viz.config, opt || {});\n      var that = this,\n          viz = this.viz,\n          graph  = viz.graph,\n          interp = this.Interpolator,\n          animation =  opt.type === 'nodefx'? this.nodeFxAnimation : this.animation;\n      //prepare graph values\n      var m = this.prepare(opt.modes);\n\n      //animate\n      if(opt.hideLabels) this.labels.hideLabels(true);\n      animation.setOptions($.merge(opt, {\n        $animating: false,\n        compute: function(delta) {\n          graph.eachNode(function(node) {\n            for(var p in m) {\n        // console.log(\"p: \" + p + \" m:\" + m[p]);\n              interp[p](node, m[p], delta, versor);\n            }\n          });\n          that.plot(opt, this.$animating, delta);\n          this.$animating = true;\n        },\n        complete: function() {\n          if(opt.hideLabels) that.labels.hideLabels(false);\n          that.plot(opt);\n          opt.onComplete();\n          opt.onAfterCompute();\n        }\n      })).start();\n    },\n\n    /*\n      nodeFx\n\n      Apply animation to node properties like color, width, height, dim, etc.\n\n      Parameters:\n\n      options - Animation options. This object properties is described below\n      elements - The Elements to be transformed. This is an object that has a properties\n\n      (start code js)\n      'elements': {\n        //can also be an array of ids\n        'id': 'id-of-node-to-transform',\n        //properties to be modified. All properties are optional.\n        'properties': {\n          'color': '#ccc', //some color\n          'width': 10, //some width\n          'height': 10, //some height\n          'dim': 20, //some dim\n          'lineWidth': 10 //some line width\n        }\n      }\n      (end code)\n\n      - _reposition_ Whether to recalculate positions and add a motion animation.\n      This might be used when changing _width_ or _height_ properties in a <Layouts.Tree> like layout. Default's *false*.\n\n      - _onComplete_ A method that is called when the animation completes.\n\n      ...and all other <Graph.Plot.animate> options like _duration_, _fps_, _transition_, etc.\n\n      Example:\n      (start code js)\n       var rg = new RGraph(canvas, config); //can be also Hypertree or ST\n       rg.fx.nodeFx({\n         'elements': {\n           'id':'mynodeid',\n           'properties': {\n             'color':'#ccf'\n           },\n           'transition': Trans.Quart.easeOut\n         }\n       });\n      (end code)\n   */\n   nodeFx: function(opt) {\n     var viz = this.viz,\n         graph  = viz.graph,\n         animation = this.nodeFxAnimation,\n         options = $.merge(this.viz.config, {\n           'elements': {\n             'id': false,\n             'properties': {}\n           },\n           'reposition': false\n         });\n     opt = $.merge(options, opt || {}, {\n       onBeforeCompute: $.empty,\n       onAfterCompute: $.empty\n     });\n     //check if an animation is running\n     animation.stopTimer();\n     var props = opt.elements.properties;\n     //set end values for nodes\n     if(!opt.elements.id) {\n       graph.eachNode(function(n) {\n         for(var prop in props) {\n           n.setData(prop, props[prop], 'end');\n         }\n       });\n     } else {\n       var ids = $.splat(opt.elements.id);\n       $.each(ids, function(id) {\n         var n = graph.getNode(id);\n         if(n) {\n           for(var prop in props) {\n             n.setData(prop, props[prop], 'end');\n           }\n         }\n       });\n     }\n     //get keys\n     var propnames = [];\n     for(var prop in props) propnames.push(prop);\n     //add node properties modes\n     var modes = ['node-property:' + propnames.join(':')];\n     //set new node positions\n     if(opt.reposition) {\n       modes.push('linear');\n       viz.compute('end');\n     }\n     //animate\n     this.animate($.merge(opt, {\n       modes: modes,\n       type: 'nodefx'\n     }));\n   },\n\n\n    /*\n       Method: plot\n\n       Plots a <Graph>.\n\n       Parameters:\n\n       opt - (optional) Plotting options. Most of them are described in <Options.Fx>.\n\n       Example:\n\n       (start code js)\n       var viz = new $jit.Viz(options);\n       viz.fx.plot();\n       (end code)\n\n    */\n    plot: function(opt, animating) {\n      var viz = this.viz,\n      aGraph = viz.graph,\n      canvas = viz.canvas,\n      id = viz.root,\n      that = this,\n      ctx = canvas.getCtx(),\n      min = Math.min,\n      opt = opt || this.viz.controller;\n      opt.clearCanvas && canvas.clear();\n\n      var T = !!aGraph.getNode(id).visited;\n      aGraph.eachNode(function(node) {\n        var nodeAlpha = node.getData('alpha');\n        node.eachAdjacency(function(adj) {\n          var nodeTo = adj.nodeTo;\n          if(!!nodeTo.visited === T && node.drawn && nodeTo.drawn) {\n            !animating && opt.onBeforePlotLine(adj);\n            ctx.save();\n            ctx.globalAlpha = min(nodeAlpha,\n                nodeTo.getData('alpha'),\n                adj.getData('alpha'));\n            that.plotLine(adj, canvas, animating);\n            ctx.restore();\n            !animating && opt.onAfterPlotLine(adj);\n          }\n        });\n        ctx.save();\n        if(node.drawn) {\n          !animating && opt.onBeforePlotNode(node);\n          that.plotNode(node, canvas, animating);\n          !animating && opt.onAfterPlotNode(node);\n        }\n        if(!that.labelsHidden && opt.withLabels) {\n          if(node.drawn && nodeAlpha >= 0.95) {\n            that.labels.plotLabel(canvas, node, opt);\n          } else {\n            that.labels.hideLabel(node, false);\n          }\n        }\n        ctx.restore();\n        node.visited = !T;\n      });\n    },\n\n  /*\n      Plots a Subtree.\n   */\n   plotTree: function(node, opt, animating) {\n       var that = this,\n       viz = this.viz,\n       canvas = viz.canvas,\n       config = this.config,\n       ctx = canvas.getCtx();\n       var nodeAlpha = node.getData('alpha');\n       node.eachSubnode(function(elem) {\n         if(opt.plotSubtree(node, elem) && elem.exist && elem.drawn) {\n             var adj = node.getAdjacency(elem.id);\n             !animating && opt.onBeforePlotLine(adj);\n             ctx.globalAlpha = Math.min(nodeAlpha, elem.getData('alpha'));\n             that.plotLine(adj, canvas, animating);\n             !animating && opt.onAfterPlotLine(adj);\n             that.plotTree(elem, opt, animating);\n         }\n       });\n       if(node.drawn) {\n           !animating && opt.onBeforePlotNode(node);\n           this.plotNode(node, canvas, animating);\n           !animating && opt.onAfterPlotNode(node);\n           if(!opt.hideLabels && opt.withLabels && nodeAlpha >= 0.95)\n               this.labels.plotLabel(canvas, node, opt);\n           else\n               this.labels.hideLabel(node, false);\n       } else {\n           this.labels.hideLabel(node, true);\n       }\n   },\n\n  /*\n       Method: plotNode\n\n       Plots a <Graph.Node>.\n\n       Parameters:\n\n       node - (object) A <Graph.Node>.\n       canvas - (object) A <Canvas> element.\n\n    */\n    plotNode: function(node, canvas, animating) {\n        var f = node.getData('type'),\n            ctxObj = this.node.CanvasStyles;\n        if(f != 'none') {\n          var width = node.getData('lineWidth'),\n              color = node.getData('color'),\n              alpha = node.getData('alpha'),\n              ctx = canvas.getCtx();\n\n          ctx.lineWidth = width;\n          ctx.fillStyle = ctx.strokeStyle = color;\n          ctx.globalAlpha = alpha;\n\n          for(var s in ctxObj) {\n            ctx[s] = node.getCanvasStyle(s);\n          }\n\n          this.nodeTypes[f].render.call(this, node, canvas, animating);\n        }\n    },\n\n    /*\n       Method: plotLine\n\n       Plots a <Graph.Adjacence>.\n\n       Parameters:\n\n       adj - (object) A <Graph.Adjacence>.\n       canvas - (object) A <Canvas> instance.\n\n    */\n    plotLine: function(adj, canvas, animating) {\n      var f = adj.getData('type'),\n          ctxObj = this.edge.CanvasStyles;\n      if(f != 'none') {\n        var width = adj.getData('lineWidth'),\n            color = adj.getData('color'),\n            ctx = canvas.getCtx();\n\n        ctx.lineWidth = width;\n        ctx.fillStyle = ctx.strokeStyle = color;\n\n        for(var s in ctxObj) {\n          ctx[s] = adj.getCanvasStyle(s);\n        }\n\n        this.edgeTypes[f].call(this, adj, canvas, animating);\n      }\n    }\n\n};\n\n\n\n/*\n * File: Graph.Label.js\n *\n*/\n\n/*\n   Object: Graph.Label\n\n   An interface for plotting/hiding/showing labels.\n\n   Description:\n\n   This is a generic interface for plotting/hiding/showing labels.\n   The <Graph.Label> interface is implemented in multiple ways to provide\n   different label types.\n\n   For example, the Graph.Label interface is implemented as <Graph.Label.HTML> to provide\n   HTML label elements. Also we provide the <Graph.Label.SVG> interface for SVG type labels.\n   The <Graph.Label.Native> interface implements these methods with the native Canvas text rendering functions.\n\n   All subclasses (<Graph.Label.HTML>, <Graph.Label.SVG> and <Graph.Label.Native>) implement the method plotLabel.\n*/\n\nGraph.Label = {};\n\n/*\n   Class: Graph.Label.Native\n\n   Implements labels natively, using the Canvas text API.\n*/\nGraph.Label.Native = new Class({\n    /*\n       Method: plotLabel\n\n       Plots a label for a given node.\n\n       Parameters:\n\n       canvas - (object) A <Canvas> instance.\n       node - (object) A <Graph.Node>.\n       controller - (object) A configuration object.\n\n       Example:\n\n       (start code js)\n       var viz = new $jit.Viz(options);\n       var node = viz.graph.getNode('nodeId');\n       viz.labels.plotLabel(viz.canvas, node, viz.config);\n       (end code)\n    */\n    plotLabel: function(canvas, node, controller) {\n      var ctx = canvas.getCtx();\n      var pos = node.pos.getc(true);\n\n      ctx.font = node.getLabelData('style') + ' ' + node.getLabelData('size') + 'px ' + node.getLabelData('family');\n      ctx.textAlign = node.getLabelData('textAlign');\n      ctx.fillStyle = ctx.strokeStyle = node.getLabelData('color');\n      ctx.textBaseline = node.getLabelData('textBaseline');\n\n      this.renderLabel(canvas, node, controller);\n    },\n\n    /*\n       renderLabel\n\n       Does the actual rendering of the label in the canvas. The default\n       implementation renders the label close to the position of the node, this\n       method should be overriden to position the labels differently.\n\n       Parameters:\n\n       canvas - A <Canvas> instance.\n       node - A <Graph.Node>.\n       controller - A configuration object. See also <Hypertree>, <RGraph>, <ST>.\n    */\n    renderLabel: function(canvas, node, controller) {\n      var ctx = canvas.getCtx();\n      var pos = node.pos.getc(true);\n      ctx.fillText(node.name, pos.x, pos.y + node.getData(\"height\") / 2);\n    },\n\n    hideLabel: $.empty,\n    hideLabels: $.empty\n});\n\n/*\n   Class: Graph.Label.DOM\n\n   Abstract Class implementing some DOM label methods.\n\n   Implemented by:\n\n   <Graph.Label.HTML> and <Graph.Label.SVG>.\n\n*/\nGraph.Label.DOM = new Class({\n    //A flag value indicating if node labels are being displayed or not.\n    labelsHidden: false,\n    //Label container\n    labelContainer: false,\n    //Label elements hash.\n    labels: {},\n\n    /*\n       Method: getLabelContainer\n\n       Lazy fetcher for the label container.\n\n       Returns:\n\n       The label container DOM element.\n\n       Example:\n\n      (start code js)\n        var viz = new $jit.Viz(options);\n        var labelContainer = viz.labels.getLabelContainer();\n        alert(labelContainer.innerHTML);\n      (end code)\n    */\n    getLabelContainer: function() {\n      return this.labelContainer ?\n        this.labelContainer :\n        this.labelContainer = document.getElementById(this.viz.config.labelContainer);\n    },\n\n    /*\n       Method: getLabel\n\n       Lazy fetcher for the label element.\n\n       Parameters:\n\n       id - (string) The label id (which is also a <Graph.Node> id).\n\n       Returns:\n\n       The label element.\n\n       Example:\n\n      (start code js)\n        var viz = new $jit.Viz(options);\n        var label = viz.labels.getLabel('someid');\n        alert(label.innerHTML);\n      (end code)\n\n    */\n    getLabel: function(id) {\n      return (id in this.labels && this.labels[id] != null) ?\n        this.labels[id] :\n        this.labels[id] = document.getElementById(id);\n    },\n\n    /*\n       Method: hideLabels\n\n       Hides all labels (by hiding the label container).\n\n       Parameters:\n\n       hide - (boolean) A boolean value indicating if the label container must be hidden or not.\n\n       Example:\n       (start code js)\n        var viz = new $jit.Viz(options);\n        rg.labels.hideLabels(true);\n       (end code)\n\n    */\n    hideLabels: function (hide) {\n      var container = this.getLabelContainer();\n      if(hide)\n        container.style.display = 'none';\n      else\n        container.style.display = '';\n      this.labelsHidden = hide;\n    },\n\n    /*\n       Method: clearLabels\n\n       Clears the label container.\n\n       Useful when using a new visualization with the same canvas element/widget.\n\n       Parameters:\n\n       force - (boolean) Forces deletion of all labels.\n\n       Example:\n       (start code js)\n        var viz = new $jit.Viz(options);\n        viz.labels.clearLabels();\n        (end code)\n    */\n    clearLabels: function(force) {\n      for(var id in this.labels) {\n        if (force || !this.viz.graph.hasNode(id)) {\n          this.disposeLabel(id);\n          delete this.labels[id];\n        }\n      }\n    },\n\n    /*\n       Method: disposeLabel\n\n       Removes a label.\n\n       Parameters:\n\n       id - (string) A label id (which generally is also a <Graph.Node> id).\n\n       Example:\n       (start code js)\n        var viz = new $jit.Viz(options);\n        viz.labels.disposeLabel('labelid');\n       (end code)\n    */\n    disposeLabel: function(id) {\n      var elem = this.getLabel(id);\n      if(elem && elem.parentNode) {\n        elem.parentNode.removeChild(elem);\n      }\n    },\n\n    /*\n       Method: hideLabel\n\n       Hides the corresponding <Graph.Node> label.\n\n       Parameters:\n\n       node - (object) A <Graph.Node>. Can also be an array of <Graph.Nodes>.\n       show - (boolean) If *true*, nodes will be shown. Otherwise nodes will be hidden.\n\n       Example:\n       (start code js)\n        var rg = new $jit.Viz(options);\n        viz.labels.hideLabel(viz.graph.getNode('someid'), false);\n       (end code)\n    */\n    hideLabel: function(node, show) {\n      node = $.splat(node);\n      var st = show ? \"\" : \"none\", lab, that = this;\n      $.each(node, function(n) {\n        var lab = that.getLabel(n.id);\n        if (lab) {\n          lab.style.display = st;\n        }\n      });\n    },\n\n    /*\n       fitsInCanvas\n\n       Returns _true_ or _false_ if the label for the node is contained in the canvas dom element or not.\n\n       Parameters:\n\n       pos - A <Complex> instance (I'm doing duck typing here so any object with _x_ and _y_ parameters will do).\n       canvas - A <Canvas> instance.\n\n       Returns:\n\n       A boolean value specifying if the label is contained in the <Canvas> DOM element or not.\n\n    */\n    fitsInCanvas: function(pos, canvas) {\n      var size = canvas.getSize();\n      if(pos.x >= size.width || pos.x < 0\n         || pos.y >= size.height || pos.y < 0) return false;\n       return true;\n    }\n});\n\n/*\n   Class: Graph.Label.HTML\n\n   Implements HTML labels.\n\n   Extends:\n\n   All <Graph.Label.DOM> methods.\n\n*/\nGraph.Label.HTML = new Class({\n    Implements: Graph.Label.DOM,\n\n    /*\n       Method: plotLabel\n\n       Plots a label for a given node.\n\n       Parameters:\n\n       canvas - (object) A <Canvas> instance.\n       node - (object) A <Graph.Node>.\n       controller - (object) A configuration object.\n\n      Example:\n\n       (start code js)\n       var viz = new $jit.Viz(options);\n       var node = viz.graph.getNode('nodeId');\n       viz.labels.plotLabel(viz.canvas, node, viz.config);\n       (end code)\n\n\n    */\n    plotLabel: function(canvas, node, controller) {\n      var id = node.id, tag = this.getLabel(id);\n\n      if(!tag && !(tag = document.getElementById(id))) {\n        tag = document.createElement('div');\n        var container = this.getLabelContainer();\n        tag.id = id;\n        tag.className = 'node';\n        tag.style.position = 'absolute';\n        controller.onCreateLabel(tag, node);\n        container.appendChild(tag);\n        this.labels[node.id] = tag;\n      }\n\n      this.placeLabel(tag, node, controller);\n    }\n});\n\n/*\n   Class: Graph.Label.SVG\n\n   Implements SVG labels.\n\n   Extends:\n\n   All <Graph.Label.DOM> methods.\n*/\nGraph.Label.SVG = new Class({\n    Implements: Graph.Label.DOM,\n\n    /*\n       Method: plotLabel\n\n       Plots a label for a given node.\n\n       Parameters:\n\n       canvas - (object) A <Canvas> instance.\n       node - (object) A <Graph.Node>.\n       controller - (object) A configuration object.\n\n       Example:\n\n       (start code js)\n       var viz = new $jit.Viz(options);\n       var node = viz.graph.getNode('nodeId');\n       viz.labels.plotLabel(viz.canvas, node, viz.config);\n       (end code)\n\n\n    */\n    plotLabel: function(canvas, node, controller) {\n      var id = node.id, tag = this.getLabel(id);\n      if(!tag && !(tag = document.getElementById(id))) {\n        var ns = 'http://www.w3.org/2000/svg';\n          tag = document.createElementNS(ns, 'svg:text');\n        var tspan = document.createElementNS(ns, 'svg:tspan');\n        tag.appendChild(tspan);\n        var container = this.getLabelContainer();\n        tag.setAttribute('id', id);\n        tag.setAttribute('class', 'node');\n        container.appendChild(tag);\n        controller.onCreateLabel(tag, node);\n        this.labels[node.id] = tag;\n      }\n      this.placeLabel(tag, node, controller);\n    }\n});\n\n\n\nGraph.Geom = new Class({\n\n  initialize: function(viz) {\n    this.viz = viz;\n    this.config = viz.config;\n    this.node = viz.config.Node;\n    this.edge = viz.config.Edge;\n  },\n  /*\n    Applies a translation to the tree.\n\n    Parameters:\n\n    pos - A <Complex> number specifying translation vector.\n    prop - A <Graph.Node> position property ('pos', 'start' or 'end').\n\n    Example:\n\n    (start code js)\n      st.geom.translate(new Complex(300, 100), 'end');\n    (end code)\n  */\n  translate: function(pos, prop) {\n     prop = $.splat(prop);\n     this.viz.graph.eachNode(function(elem) {\n         $.each(prop, function(p) { elem.getPos(p).$add(pos); });\n     });\n  },\n  /*\n    Hides levels of the tree until it properly fits in canvas.\n  */\n  setRightLevelToShow: function(node, canvas, callback) {\n     var level = this.getRightLevelToShow(node, canvas),\n         fx = this.viz.labels,\n         opt = $.merge({\n           execShow:true,\n           execHide:true,\n           onHide: $.empty,\n           onShow: $.empty\n         }, callback || {});\n     node.eachLevel(0, this.config.levelsToShow, function(n) {\n         var d = n._depth - node._depth;\n         if(d > level) {\n             opt.onHide(n);\n             if(opt.execHide) {\n               n.drawn = false;\n               n.exist = false;\n               fx.hideLabel(n, false);\n             }\n         } else {\n             opt.onShow(n);\n             if(opt.execShow) {\n               n.exist = true;\n             }\n         }\n     });\n     node.drawn= true;\n  },\n  /*\n    Returns the right level to show for the current tree in order to fit in canvas.\n  */\n  getRightLevelToShow: function(node, canvas) {\n     var config = this.config;\n     var level = config.levelsToShow;\n     var constrained = config.constrained;\n     if(!constrained) return level;\n     while(!this.treeFitsInCanvas(node, canvas, level) && level > 1) { level-- ; }\n     return level;\n  }\n});\n\n/*\n * File: Loader.js\n *\n */\n\n/*\n   Object: Loader\n\n   Provides methods for loading and serving JSON data.\n*/\nvar Loader = {\n     construct: function(json) {\n        var isGraph = ($.type(json) == 'array');\n        var ans = new Graph(this.graphOptions, this.config.Node, this.config.Edge, this.config.Label);\n        if(!isGraph)\n            //make tree\n            (function (ans, json) {\n                ans.addNode(json);\n                if(json.children) {\n                  for(var i=0, ch = json.children; i<ch.length; i++) {\n                    ans.addAdjacence(json, ch[i]);\n                    arguments.callee(ans, ch[i]);\n                  }\n                }\n            })(ans, json);\n        else\n            //make graph\n            (function (ans, json) {\n                var getNode = function(id) {\n                  for(var i=0, l=json.length; i<l; i++) {\n                    if(json[i].id == id) {\n                      return json[i];\n                    }\n                  }\n                  // The node was not defined in the JSON\n                  // Let's create it\n                  var newNode = {\n                    \"id\" : id,\n                    \"name\" : id\n                  };\n                  return ans.addNode(newNode);\n                };\n\n                for(var i=0, l=json.length; i<l; i++) {\n                  ans.addNode(json[i]);\n                  var adj = json[i].adjacencies;\n                  if (adj) {\n                    for(var j=0, lj=adj.length; j<lj; j++) {\n                      var node = adj[j], data = {};\n                      if(typeof adj[j] != 'string') {\n                        data = node.data;\n                        node = node.nodeTo;\n                      }\n                      ans.addAdjacence(json[i], getNode(node), data);\n                    }\n                  }\n                }\n            })(ans, json);\n\n        return ans;\n    },\n\n    /*\n     Method: loadJSON\n\n     Loads a JSON structure to the visualization. The JSON structure can be a JSON *tree* or *graph* structure.\n\n      A JSON tree or graph structure consists of nodes, each having as properties\n\n       id - (string) A unique identifier for the node\n       name - (string) A node's name\n       data - (object) The data optional property contains a hash (i.e {})\n       where you can store all the information you want about this node.\n\n      For JSON *Tree* structures, there's an extra optional property *children* of type Array which contains the node's children.\n\n      Example:\n\n      (start code js)\n        var json = {\n          \"id\": \"aUniqueIdentifier\",\n          \"name\": \"usually a nodes name\",\n          \"data\": {\n            \"some key\": \"some value\",\n            \"some other key\": \"some other value\"\n           },\n          \"children\": [ *other nodes or empty* ]\n        };\n      (end code)\n\n        JSON *Graph* structures consist of an array of nodes, each specifying the nodes to which the current node is connected.\n        For JSON *Graph* structures, the *children* property is replaced by the *adjacencies* property.\n\n        There are two types of *Graph* structures, *simple* and *extended* graph structures.\n\n        For *simple* Graph structures, the adjacencies property contains an array of strings, each specifying the\n        id of the node connected to the main node.\n\n        Example:\n\n        (start code js)\n        var json = [\n          {\n            \"id\": \"aUniqueIdentifier\",\n            \"name\": \"usually a nodes name\",\n            \"data\": {\n              \"some key\": \"some value\",\n              \"some other key\": \"some other value\"\n             },\n            \"adjacencies\": [\"anotherUniqueIdentifier\", \"yetAnotherUniqueIdentifier\", 'etc']\n          },\n\n          'other nodes go here...'\n        ];\n        (end code)\n\n        For *extended Graph structures*, the adjacencies property contains an array of Adjacency objects that have as properties\n\n        nodeTo - (string) The other node connected by this adjacency.\n        data - (object) A data property, where we can store custom key/value information.\n\n        Example:\n\n        (start code js)\n        var json = [\n          {\n            \"id\": \"aUniqueIdentifier\",\n            \"name\": \"usually a nodes name\",\n            \"data\": {\n              \"some key\": \"some value\",\n              \"some other key\": \"some other value\"\n             },\n            \"adjacencies\": [\n            {\n              nodeTo:\"aNodeId\",\n              data: {} //put whatever you want here\n            },\n            'other adjacencies go here...'\n          },\n\n          'other nodes go here...'\n        ];\n        (end code)\n\n       About the data property:\n\n       As described before, you can store custom data in the *data* property of JSON *nodes* and *adjacencies*.\n       You can use almost any string as key for the data object. Some keys though are reserved by the toolkit, and\n       have special meanings. This is the case for keys starting with a dollar sign, for example, *$width*.\n\n       For JSON *node* objects, adding dollar prefixed properties that match the names of the options defined in\n       <Options.Node> will override the general value for that option with that particular value. For this to work\n       however, you do have to set *overridable = true* in <Options.Node>.\n\n       The same thing is true for JSON adjacencies. Dollar prefixed data properties will alter values set in <Options.Edge>\n       if <Options.Edge> has *overridable = true*.\n\n       When loading JSON data into TreeMaps, the *data* property must contain a value for the *$area* key,\n       since this is the value which will be taken into account when creating the layout.\n       The same thing goes for the *$color* parameter.\n\n       In JSON Nodes you can use also *$label-* prefixed properties to refer to <Options.Label> properties. For example,\n       *$label-size* will refer to <Options.Label> size property. Also, in JSON nodes and adjacencies you can set\n       canvas specific properties individually by using the *$canvas-* prefix. For example, *$canvas-shadowBlur* will refer\n       to the *shadowBlur* property.\n\n       These properties can also be accessed after loading the JSON data from <Graph.Nodes> and <Graph.Adjacences>\n       by using <Accessors>. For more information take a look at the <Graph> and <Accessors> documentation.\n\n       Finally, these properties can also be used to create advanced animations like with <Options.NodeStyles>. For more\n       information about creating animations please take a look at the <Graph.Plot> and <Graph.Plot.animate> documentation.\n\n       loadJSON Parameters:\n\n        json - A JSON Tree or Graph structure.\n        i - For Graph structures only. Sets the indexed node as root for the visualization.\n\n    */\n    loadJSON: function(json, i) {\n      this.json = json;\n      //if they're canvas labels erase them.\n      if(this.labels && this.labels.clearLabels) {\n        this.labels.clearLabels(true);\n      }\n      this.graph = this.construct(json);\n      if($.type(json) != 'array'){\n        this.root = json.id;\n      } else {\n        this.root = json[i? i : 0].id;\n      }\n    },\n\n    /*\n      Method: toJSON\n\n      Returns a JSON tree/graph structure from the visualization's <Graph>.\n      See <Loader.loadJSON> for the graph formats available.\n\n      See also:\n\n      <Loader.loadJSON>\n\n      Parameters:\n\n      type - (string) Default's \"tree\". The type of the JSON structure to be returned.\n      Possible options are \"tree\" or \"graph\".\n    */\n    toJSON: function(type) {\n      type = type || \"tree\";\n      if(type == 'tree') {\n        var ans = {};\n        var rootNode = this.graph.getNode(this.root);\n        var ans = (function recTree(node) {\n          var ans = {};\n          ans.id = node.id;\n          ans.name = node.name;\n          ans.data = node.data;\n          var ch =[];\n          node.eachSubnode(function(n) {\n            ch.push(recTree(n));\n          });\n          ans.children = ch;\n          return ans;\n        })(rootNode);\n        return ans;\n      } else {\n        var ans = [];\n        var T = !!this.graph.getNode(this.root).visited;\n        this.graph.eachNode(function(node) {\n          var ansNode = {};\n          ansNode.id = node.id;\n          ansNode.name = node.name;\n          ansNode.data = node.data;\n          var adjs = [];\n          node.eachAdjacency(function(adj) {\n            var nodeTo = adj.nodeTo;\n            if(!!nodeTo.visited === T) {\n              var ansAdj = {};\n              ansAdj.nodeTo = nodeTo.id;\n              ansAdj.data = adj.data;\n              adjs.push(ansAdj);\n            }\n          });\n          ansNode.adjacencies = adjs;\n          ans.push(ansNode);\n          node.visited = !T;\n        });\n        return ans;\n      }\n    }\n};\n\n\n\n/*\n * File: Layouts.js\n *\n * Implements base Tree and Graph layouts.\n *\n * Description:\n *\n * Implements base Tree and Graph layouts like Radial, Tree, etc.\n *\n */\n\n/*\n * Object: Layouts\n *\n * Parent object for common layouts.\n *\n */\nvar Layouts = $jit.Layouts = {};\n\n\n//Some util shared layout functions are defined here.\nvar NodeDim = {\n  label: null,\n\n  compute: function(graph, prop, opt) {\n    this.initializeLabel(opt);\n    var label = this.label, style = label.style;\n    graph.eachNode(function(n) {\n      var autoWidth  = n.getData('autoWidth'),\n          autoHeight = n.getData('autoHeight');\n      if(autoWidth || autoHeight) {\n        //delete dimensions since these are\n        //going to be overridden now.\n        delete n.data.$width;\n        delete n.data.$height;\n        delete n.data.$dim;\n\n        var width  = n.getData('width'),\n            height = n.getData('height');\n        //reset label dimensions\n        style.width  = autoWidth? 'auto' : width + 'px';\n        style.height = autoHeight? 'auto' : height + 'px';\n\n        //TODO(nico) should let the user choose what to insert here.\n        label.innerHTML = n.name;\n\n        var offsetWidth  = label.offsetWidth,\n            offsetHeight = label.offsetHeight;\n        var type = n.getData('type');\n        if($.indexOf(['circle', 'square', 'triangle', 'star'], type) === -1) {\n          n.setData('width', offsetWidth);\n          n.setData('height', offsetHeight);\n        } else {\n          var dim = offsetWidth > offsetHeight? offsetWidth : offsetHeight;\n          n.setData('width', dim);\n          n.setData('height', dim);\n          n.setData('dim', dim);\n        }\n      }\n    });\n  },\n\n  initializeLabel: function(opt) {\n    if(!this.label) {\n      this.label = document.createElement('div');\n      document.body.appendChild(this.label);\n    }\n    this.setLabelStyles(opt);\n  },\n\n  setLabelStyles: function(opt) {\n    $.extend(this.label.style, {\n      'visibility': 'hidden',\n      'position': 'absolute',\n      'width': 'auto',\n      'height': 'auto'\n    });\n    this.label.className = 'jit-autoadjust-label';\n  }\n};\n\n\n/*\n * Class: Layouts.Tree\n *\n * Implements a Tree Layout.\n *\n * Implemented By:\n *\n * <ST>\n *\n * Inspired by:\n *\n * Drawing Trees (Andrew J. Kennedy) <http://research.microsoft.com/en-us/um/people/akenn/fun/drawingtrees.pdf>\n *\n */\nLayouts.Tree = (function() {\n  //Layout functions\n  var slice = Array.prototype.slice;\n\n  /*\n     Calculates the max width and height nodes for a tree level\n  */\n  function getBoundaries(graph, config, level, orn, prop) {\n    var dim = config.Node;\n    var multitree = config.multitree;\n    if (dim.overridable) {\n      var w = -1, h = -1;\n      graph.eachNode(function(n) {\n        if (n._depth == level\n            && (!multitree || ('$orn' in n.data) && n.data.$orn == orn)) {\n          var dw = n.getData('width', prop);\n          var dh = n.getData('height', prop);\n          w = (w < dw) ? dw : w;\n          h = (h < dh) ? dh : h;\n        }\n      });\n      return {\n        'width' : w < 0 ? dim.width : w,\n        'height' : h < 0 ? dim.height : h\n      };\n    } else {\n      return dim;\n    }\n  }\n\n\n  function movetree(node, prop, val, orn) {\n    var p = (orn == \"left\" || orn == \"right\") ? \"y\" : \"x\";\n    node.getPos(prop)[p] += val;\n  }\n\n\n  function moveextent(extent, val) {\n    var ans = [];\n    $.each(extent, function(elem) {\n      elem = slice.call(elem);\n      elem[0] += val;\n      elem[1] += val;\n      ans.push(elem);\n    });\n    return ans;\n  }\n\n\n  function merge(ps, qs) {\n    if (ps.length == 0)\n      return qs;\n    if (qs.length == 0)\n      return ps;\n    var p = ps.shift(), q = qs.shift();\n    return [ [ p[0], q[1] ] ].concat(merge(ps, qs));\n  }\n\n\n  function mergelist(ls, def) {\n    def = def || [];\n    if (ls.length == 0)\n      return def;\n    var ps = ls.pop();\n    return mergelist(ls, merge(ps, def));\n  }\n\n\n  function fit(ext1, ext2, subtreeOffset, siblingOffset, i) {\n    if (ext1.length <= i || ext2.length <= i)\n      return 0;\n\n    var p = ext1[i][1], q = ext2[i][0];\n    return Math.max(fit(ext1, ext2, subtreeOffset, siblingOffset, ++i)\n        + subtreeOffset, p - q + siblingOffset);\n  }\n\n\n  function fitlistl(es, subtreeOffset, siblingOffset) {\n    function $fitlistl(acc, es, i) {\n      if (es.length <= i)\n        return [];\n      var e = es[i], ans = fit(acc, e, subtreeOffset, siblingOffset, 0);\n      return [ ans ].concat($fitlistl(merge(acc, moveextent(e, ans)), es, ++i));\n    }\n    ;\n    return $fitlistl( [], es, 0);\n  }\n\n\n  function fitlistr(es, subtreeOffset, siblingOffset) {\n    function $fitlistr(acc, es, i) {\n      if (es.length <= i)\n        return [];\n      var e = es[i], ans = -fit(e, acc, subtreeOffset, siblingOffset, 0);\n      return [ ans ].concat($fitlistr(merge(moveextent(e, ans), acc), es, ++i));\n    }\n    ;\n    es = slice.call(es);\n    var ans = $fitlistr( [], es.reverse(), 0);\n    return ans.reverse();\n  }\n\n\n  function fitlist(es, subtreeOffset, siblingOffset, align) {\n    var esl = fitlistl(es, subtreeOffset, siblingOffset), esr = fitlistr(es,\n        subtreeOffset, siblingOffset);\n\n    if (align == \"left\")\n      esr = esl;\n    else if (align == \"right\")\n      esl = esr;\n\n    for ( var i = 0, ans = []; i < esl.length; i++) {\n      ans[i] = (esl[i] + esr[i]) / 2;\n    }\n    return ans;\n  }\n\n\n  function design(graph, node, prop, config, orn) {\n    var multitree = config.multitree;\n    var auxp = [ 'x', 'y' ], auxs = [ 'width', 'height' ];\n    var ind = +(orn == \"left\" || orn == \"right\");\n    var p = auxp[ind], notp = auxp[1 - ind];\n\n    var cnode = config.Node;\n    var s = auxs[ind], nots = auxs[1 - ind];\n\n    var siblingOffset = config.siblingOffset;\n    var subtreeOffset = config.subtreeOffset;\n    var align = config.align;\n\n    function $design(node, maxsize, acum) {\n      var sval = node.getData(s, prop);\n      var notsval = maxsize\n          || (node.getData(nots, prop));\n\n      var trees = [], extents = [], chmaxsize = false;\n      var chacum = notsval + config.levelDistance;\n      node.eachSubnode(function(n) {\n            if (n.exist\n                && (!multitree || ('$orn' in n.data) && n.data.$orn == orn)) {\n\n              if (!chmaxsize)\n                chmaxsize = getBoundaries(graph, config, n._depth, orn, prop);\n\n              var s = $design(n, chmaxsize[nots], acum + chacum);\n              trees.push(s.tree);\n              extents.push(s.extent);\n            }\n          });\n      var positions = fitlist(extents, subtreeOffset, siblingOffset, align);\n      for ( var i = 0, ptrees = [], pextents = []; i < trees.length; i++) {\n        movetree(trees[i], prop, positions[i], orn);\n        pextents.push(moveextent(extents[i], positions[i]));\n      }\n      var resultextent = [ [ -sval / 2, sval / 2 ] ]\n          .concat(mergelist(pextents));\n      node.getPos(prop)[p] = 0;\n\n      if (orn == \"top\" || orn == \"left\") {\n        node.getPos(prop)[notp] = acum;\n      } else {\n        node.getPos(prop)[notp] = -acum;\n      }\n\n      return {\n        tree : node,\n        extent : resultextent\n      };\n    }\n\n    $design(node, false, 0);\n  }\n\n\n  return new Class({\n    /*\n    Method: compute\n\n    Computes nodes' positions.\n\n     */\n    compute : function(property, computeLevels) {\n      var prop = property || 'start';\n      var node = this.graph.getNode(this.root);\n      $.extend(node, {\n        'drawn' : true,\n        'exist' : true,\n        'selected' : true\n      });\n      NodeDim.compute(this.graph, prop, this.config);\n      if (!!computeLevels || !(\"_depth\" in node)) {\n        this.graph.computeLevels(this.root, 0, \"ignore\");\n      }\n\n      this.computePositions(node, prop);\n    },\n\n    computePositions : function(node, prop) {\n      var config = this.config;\n      var multitree = config.multitree;\n      var align = config.align;\n      var indent = align !== 'center' && config.indent;\n      var orn = config.orientation;\n      var orns = multitree ? [ 'top', 'right', 'bottom', 'left' ] : [ orn ];\n      var that = this;\n      $.each(orns, function(orn) {\n        //calculate layout\n          design(that.graph, node, prop, that.config, orn, prop);\n          var i = [ 'x', 'y' ][+(orn == \"left\" || orn == \"right\")];\n          //absolutize\n          (function red(node) {\n            node.eachSubnode(function(n) {\n              if (n.exist\n                  && (!multitree || ('$orn' in n.data) && n.data.$orn == orn)) {\n\n                n.getPos(prop)[i] += node.getPos(prop)[i];\n                if (indent) {\n                  n.getPos(prop)[i] += align == 'left' ? indent : -indent;\n                }\n                red(n);\n              }\n            });\n          })(node);\n        });\n    }\n  });\n\n})();\n\n/*\n * File: Spacetree.js\n */\n\n/*\n   Class: ST\n\n  A Tree layout with advanced contraction and expansion animations.\n\n  Inspired by:\n\n  SpaceTree: Supporting Exploration in Large Node Link Tree, Design Evolution and Empirical Evaluation (Catherine Plaisant, Jesse Grosjean, Benjamin B. Bederson)\n  <http://hcil.cs.umd.edu/trs/2002-05/2002-05.pdf>\n\n  Drawing Trees (Andrew J. Kennedy) <http://research.microsoft.com/en-us/um/people/akenn/fun/drawingtrees.pdf>\n\n  Note:\n\n  This visualization was built and engineered from scratch, taking only the papers as inspiration, and only shares some features with the visualization described in those papers.\n\n  Implements:\n\n  All <Loader> methods\n\n  Constructor Options:\n\n  Inherits options from\n\n  - <Options.Canvas>\n  - <Options.Controller>\n  - <Options.Tree>\n  - <Options.Node>\n  - <Options.Edge>\n  - <Options.Label>\n  - <Options.Events>\n  - <Options.Tips>\n  - <Options.NodeStyles>\n  - <Options.Navigation>\n\n  Additionally, there are other parameters and some default values changed\n\n  constrained - (boolean) Default's *true*. Whether to show the entire tree when loaded or just the number of levels specified by _levelsToShow_.\n  levelsToShow - (number) Default's *2*. The number of levels to show for a subtree. This number is relative to the selected node.\n  levelDistance - (number) Default's *30*. The distance between two consecutive levels of the tree.\n  Node.type - Described in <Options.Node>. Default's set to *rectangle*.\n  offsetX - (number) Default's *0*. The x-offset distance from the selected node to the center of the canvas.\n  offsetY - (number) Default's *0*. The y-offset distance from the selected node to the center of the canvas.\n  duration - Described in <Options.Fx>. It's default value has been changed to *700*.\n\n  Instance Properties:\n\n  canvas - Access a <Canvas> instance.\n  graph - Access a <Graph> instance.\n  op - Access a <ST.Op> instance.\n  fx - Access a <ST.Plot> instance.\n  labels - Access a <ST.Label> interface implementation.\n\n */\n\n$jit.ST= (function() {\n    // Define some private methods first...\n    // Nodes in path\n    var nodesInPath = [];\n    // Nodes to contract\n    function getNodesToHide(node) {\n      node = node || this.clickedNode;\n      if(!this.config.constrained) {\n        return [];\n      }\n      var Geom = this.geom;\n      var graph = this.graph;\n      var canvas = this.canvas;\n      var level = node._depth, nodeArray = [];\n      graph.eachNode(function(n) {\n          if(n.exist && !n.selected) {\n              if(n.isDescendantOf(node.id)) {\n                if(n._depth <= level) nodeArray.push(n);\n              } else {\n                nodeArray.push(n);\n              }\n          }\n      });\n      var leafLevel = Geom.getRightLevelToShow(node, canvas);\n      node.eachLevel(leafLevel, leafLevel, function(n) {\n          if(n.exist && !n.selected) nodeArray.push(n);\n      });\n\n      for (var i = 0; i < nodesInPath.length; i++) {\n        var n = this.graph.getNode(nodesInPath[i]);\n        if(!n.isDescendantOf(node.id)) {\n          nodeArray.push(n);\n        }\n      }\n      return nodeArray;\n    };\n    // Nodes to expand\n     function getNodesToShow(node) {\n        var nodeArray = [], config = this.config;\n        node = node || this.clickedNode;\n        this.clickedNode.eachLevel(0, config.levelsToShow, function(n) {\n            if(config.multitree && !('$orn' in n.data)\n                && n.anySubnode(function(ch){ return ch.exist && !ch.drawn; })) {\n              nodeArray.push(n);\n            } else if(n.drawn && !n.anySubnode(\"drawn\")) {\n              nodeArray.push(n);\n            }\n        });\n        return nodeArray;\n     };\n    // Now define the actual class.\n    return new Class({\n\n        Implements: [Loader, Extras, Layouts.Tree],\n\n        initialize: function(controller) {\n          var $ST = $jit.ST;\n\n          var config= {\n                levelsToShow: 2,\n                levelDistance: 30,\n                constrained: true,\n                Node: {\n                  type: 'rectangle'\n                },\n                duration: 700,\n                offsetX: 0,\n                offsetY: 0\n            };\n\n            this.controller = this.config = $.merge(\n                Options(\"Canvas\", \"Fx\", \"Tree\", \"Node\", \"Edge\", \"Controller\",\n                    \"Tips\", \"NodeStyles\", \"Events\", \"Navigation\", \"Label\"), config, controller);\n\n            var canvasConfig = this.config;\n            if(canvasConfig.useCanvas) {\n              this.canvas = canvasConfig.useCanvas;\n              this.config.labelContainer = this.canvas.id + '-label';\n            } else {\n              if(canvasConfig.background) {\n                canvasConfig.background = $.merge({\n                  type: 'Circles'\n                }, canvasConfig.background);\n              }\n              this.canvas = new Canvas(this, canvasConfig);\n              this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';\n            }\n\n            this.graphOptions = {\n                'complex': true\n            };\n            this.graph = new Graph(this.graphOptions, this.config.Node, this.config.Edge);\n            this.labels = new $ST.Label[canvasConfig.Label.type](this);\n            this.fx = new $ST.Plot(this);\n            this.op = new $ST.Op(this);\n            this.group = new $ST.Group(this);\n            this.geom = new $ST.Geom(this);\n            this.clickedNode=  null;\n            // initialize extras\n            this.initializeExtras();\n        },\n\n        /*\n         Method: plot\n\n         Plots the <ST>. This is a shortcut to *fx.plot*.\n\n        */\n        plot: function() { this.fx.plot(this.controller); },\n\n\n        /*\n         Method: switchPosition\n\n         Switches the tree orientation.\n\n         Parameters:\n\n        pos - (string) The new tree orientation. Possible values are \"top\", \"left\", \"right\" and \"bottom\".\n        method - (string) Set this to \"animate\" if you want to animate the tree when switching its position. You can also set this parameter to \"replot\" to just replot the subtree.\n        onComplete - (optional|object) This callback is called once the \"switching\" animation is complete.\n\n         Example:\n\n         (start code js)\n           st.switchPosition(\"right\", \"animate\", {\n            onComplete: function() {\n              alert('completed!');\n            }\n           });\n         (end code)\n        */\n        switchPosition: function(pos, method, onComplete) {\n          var Geom = this.geom, Plot = this.fx, that = this;\n          if(!Plot.busy) {\n              Plot.busy = true;\n              this.contract({\n                  onComplete: function() {\n                      Geom.switchOrientation(pos);\n                      that.compute('end', false);\n                      Plot.busy = false;\n                      if(method == 'animate') {\n                        that.onClick(that.clickedNode.id, onComplete);\n                      } else if(method == 'replot') {\n                        that.select(that.clickedNode.id, onComplete);\n                      }\n                  }\n              }, pos);\n          }\n        },\n\n        /*\n        Method: switchAlignment\n\n        Switches the tree alignment.\n\n        Parameters:\n\n       align - (string) The new tree alignment. Possible values are \"left\", \"center\" and \"right\".\n       method - (string) Set this to \"animate\" if you want to animate the tree after aligning its position. You can also set this parameter to \"replot\" to just replot the subtree.\n       onComplete - (optional|object) This callback is called once the \"switching\" animation is complete.\n\n        Example:\n\n        (start code js)\n          st.switchAlignment(\"right\", \"animate\", {\n           onComplete: function() {\n             alert('completed!');\n           }\n          });\n        (end code)\n       */\n       switchAlignment: function(align, method, onComplete) {\n        this.config.align = align;\n        if(method == 'animate') {\n          this.select(this.clickedNode.id, onComplete);\n        } else if(method == 'replot') {\n          this.onClick(this.clickedNode.id, onComplete);\n        }\n       },\n\n       /*\n        Method: addNodeInPath\n\n        Adds a node to the current path as selected node. The selected node will be visible (as in non-collapsed) at all times.\n\n\n        Parameters:\n\n       id - (string) A <Graph.Node> id.\n\n        Example:\n\n        (start code js)\n          st.addNodeInPath(\"nodeId\");\n        (end code)\n       */\n       addNodeInPath: function(id) {\n           nodesInPath.push(id);\n           this.select((this.clickedNode && this.clickedNode.id) || this.root);\n       },\n\n       /*\n       Method: clearNodesInPath\n\n       Removes all nodes tagged as selected by the <ST.addNodeInPath> method.\n\n       See also:\n\n       <ST.addNodeInPath>\n\n       Example:\n\n       (start code js)\n         st.clearNodesInPath();\n       (end code)\n      */\n       clearNodesInPath: function(id) {\n           nodesInPath.length = 0;\n           this.select((this.clickedNode && this.clickedNode.id) || this.root);\n       },\n\n       /*\n         Method: refresh\n\n         Computes positions and plots the tree.\n\n       */\n       refresh: function() {\n           this.reposition();\n           this.select((this.clickedNode && this.clickedNode.id) || this.root);\n       },\n\n       reposition: function() {\n            this.graph.computeLevels(this.root, 0, \"ignore\");\n             this.geom.setRightLevelToShow(this.clickedNode, this.canvas);\n            this.graph.eachNode(function(n) {\n                if(n.exist) n.drawn = true;\n            });\n            this.compute('end');\n        },\n\n        requestNodes: function(node, onComplete) {\n          var handler = $.merge(this.controller, onComplete),\n          lev = this.config.levelsToShow;\n          if(handler.request) {\n              var leaves = [], d = node._depth;\n              node.eachLevel(0, lev, function(n) {\n                  if(n.drawn &&\n                   !n.anySubnode()) {\n                   leaves.push(n);\n                   n._level = lev - (n._depth - d);\n                  }\n              });\n              this.group.requestNodes(leaves, handler);\n          }\n            else\n              handler.onComplete();\n        },\n\n        contract: function(onComplete, switched) {\n          var orn  = this.config.orientation;\n          var Geom = this.geom, Group = this.group;\n          if(switched) Geom.switchOrientation(switched);\n          var nodes = getNodesToHide.call(this);\n          if(switched) Geom.switchOrientation(orn);\n          Group.contract(nodes, $.merge(this.controller, onComplete));\n        },\n\n         move: function(node, onComplete) {\n            this.compute('end', false);\n            var move = onComplete.Move, offset = {\n                'x': move.offsetX,\n                'y': move.offsetY\n            };\n            if(move.enable) {\n                this.geom.translate(node.endPos.add(offset).$scale(-1), \"end\");\n            }\n            this.fx.animate($.merge(this.controller, { modes: ['linear'] }, onComplete));\n         },\n\n        expand: function (node, onComplete) {\n            var nodeArray = getNodesToShow.call(this, node);\n            this.group.expand(nodeArray, $.merge(this.controller, onComplete));\n        },\n\n        selectPath: function(node) {\n          var that = this;\n          this.graph.eachNode(function(n) { n.selected = false; });\n          function path(node) {\n              if(node == null || node.selected) return;\n              node.selected = true;\n              $.each(that.group.getSiblings([node])[node.id],\n              function(n) {\n                   n.exist = true;\n                   n.drawn = true;\n              });\n              var parents = node.getParents();\n              parents = (parents.length > 0)? parents[0] : null;\n              path(parents);\n          };\n          for(var i=0, ns = [node.id].concat(nodesInPath); i < ns.length; i++) {\n              path(this.graph.getNode(ns[i]));\n          }\n        },\n\n        /*\n        Method: setRoot\n\n         Switches the current root node. Changes the topology of the Tree.\n\n        Parameters:\n           id - (string) The id of the node to be set as root.\n           method - (string) Set this to \"animate\" if you want to animate the tree after adding the subtree. You can also set this parameter to \"replot\" to just replot the subtree.\n           onComplete - (optional|object) An action to perform after the animation (if any).\n\n        Example:\n\n        (start code js)\n          st.setRoot('nodeId', 'animate', {\n             onComplete: function() {\n               alert('complete!');\n             }\n          });\n        (end code)\n     */\n     setRoot: function(id, method, onComplete) {\n          if(this.busy) return;\n          this.busy = true;\n          var that = this, canvas = this.canvas;\n          var rootNode = this.graph.getNode(this.root);\n          var clickedNode = this.graph.getNode(id);\n          function $setRoot() {\n              if(this.config.multitree && clickedNode.data.$orn) {\n                var orn = clickedNode.data.$orn;\n                var opp = {\n                    'left': 'right',\n                    'right': 'left',\n                    'top': 'bottom',\n                    'bottom': 'top'\n                }[orn];\n                rootNode.data.$orn = opp;\n                (function tag(rootNode) {\n                    rootNode.eachSubnode(function(n) {\n                      if(n.id != id) {\n                        n.data.$orn = opp;\n                        tag(n);\n                      }\n                    });\n                })(rootNode);\n                delete clickedNode.data.$orn;\n              }\n              this.root = id;\n              this.clickedNode = clickedNode;\n              this.graph.computeLevels(this.root, 0, \"ignore\");\n              this.geom.setRightLevelToShow(clickedNode, canvas, {\n                execHide: false,\n                onShow: function(node) {\n                  if(!node.drawn) {\n                    node.drawn = true;\n                    node.setData('alpha', 1, 'end');\n                    node.setData('alpha', 0);\n                    node.pos.setc(clickedNode.pos.x, clickedNode.pos.y);\n                  }\n                }\n              });\n              this.compute('end');\n              this.busy = true;\n              this.fx.animate({\n                modes: ['linear', 'node-property:alpha'],\n                onComplete: function() {\n                  that.busy = false;\n                  that.onClick(id, {\n                    onComplete: function() {\n                      onComplete && onComplete.onComplete();\n                    }\n                  });\n                }\n              });\n          }\n\n          // delete previous orientations (if any)\n          delete rootNode.data.$orns;\n\n          if(method == 'animate') {\n            $setRoot.call(this);\n            that.selectPath(clickedNode);\n          } else if(method == 'replot') {\n            $setRoot.call(this);\n            this.select(this.root);\n          }\n     },\n\n     /*\n           Method: addSubtree\n\n            Adds a subtree.\n\n           Parameters:\n              subtree - (object) A JSON Tree object. See also <Loader.loadJSON>.\n              method - (string) Set this to \"animate\" if you want to animate the tree after adding the subtree. You can also set this parameter to \"replot\" to just replot the subtree.\n              onComplete - (optional|object) An action to perform after the animation (if any).\n\n           Example:\n\n           (start code js)\n             st.addSubtree(json, 'animate', {\n                onComplete: function() {\n                  alert('complete!');\n                }\n             });\n           (end code)\n        */\n        addSubtree: function(subtree, method, onComplete) {\n            if(method == 'replot') {\n                this.op.sum(subtree, $.extend({ type: 'replot' }, onComplete || {}));\n            } else if (method == 'animate') {\n                this.op.sum(subtree, $.extend({ type: 'fade:seq' }, onComplete || {}));\n            }\n        },\n\n        /*\n           Method: removeSubtree\n\n            Removes a subtree.\n\n           Parameters:\n              id - (string) The _id_ of the subtree to be removed.\n              removeRoot - (boolean) Default's *false*. Remove the root of the subtree or only its subnodes.\n              method - (string) Set this to \"animate\" if you want to animate the tree after removing the subtree. You can also set this parameter to \"replot\" to just replot the subtree.\n              onComplete - (optional|object) An action to perform after the animation (if any).\n\n          Example:\n\n          (start code js)\n            st.removeSubtree('idOfSubtreeToBeRemoved', false, 'animate', {\n              onComplete: function() {\n                alert('complete!');\n              }\n            });\n          (end code)\n\n        */\n        removeSubtree: function(id, removeRoot, method, onComplete) {\n            var node = this.graph.getNode(id), subids = [];\n            node.eachLevel(+!removeRoot, false, function(n) {\n                subids.push(n.id);\n            });\n            if(method == 'replot') {\n                this.op.removeNode(subids, $.extend({ type: 'replot' }, onComplete || {}));\n            } else if (method == 'animate') {\n                this.op.removeNode(subids, $.extend({ type: 'fade:seq'}, onComplete || {}));\n            }\n        },\n\n        /*\n           Method: select\n\n            Selects a node in the <ST> without performing an animation. Useful when selecting\n            nodes which are currently hidden or deep inside the tree.\n\n          Parameters:\n            id - (string) The id of the node to select.\n            onComplete - (optional|object) an onComplete callback.\n\n          Example:\n          (start code js)\n            st.select('mynodeid', {\n              onComplete: function() {\n                alert('complete!');\n              }\n            });\n          (end code)\n        */\n        select: function(id, onComplete) {\n            var group = this.group, geom = this.geom;\n            var node=  this.graph.getNode(id), canvas = this.canvas;\n            var root  = this.graph.getNode(this.root);\n            var complete = $.merge(this.controller, onComplete);\n            var that = this;\n\n            complete.onBeforeCompute(node);\n            this.selectPath(node);\n            this.clickedNode= node;\n            this.requestNodes(node, {\n                onComplete: function(){\n                    group.hide(group.prepare(getNodesToHide.call(that)), complete);\n                    geom.setRightLevelToShow(node, canvas);\n                    that.compute(\"current\");\n                    that.graph.eachNode(function(n) {\n                        var pos = n.pos.getc(true);\n                        n.startPos.setc(pos.x, pos.y);\n                        n.endPos.setc(pos.x, pos.y);\n                        n.visited = false;\n                    });\n                    var offset = { x: complete.offsetX, y: complete.offsetY };\n                    that.geom.translate(node.endPos.add(offset).$scale(-1), [\"start\", \"current\", \"end\"]);\n                    group.show(getNodesToShow.call(that));\n                    that.plot();\n                    complete.onAfterCompute(that.clickedNode);\n                    complete.onComplete();\n                }\n            });\n        },\n\n      /*\n         Method: onClick\n\n        Animates the <ST> to center the node specified by *id*.\n\n        Parameters:\n\n        id - (string) A node id.\n        options - (optional|object) A group of options and callbacks described below.\n        onComplete - (object) An object callback called when the animation finishes.\n        Move - (object) An object that has as properties _offsetX_ or _offsetY_ for adding some offset position to the centered node.\n\n        Example:\n\n        (start code js)\n          st.onClick('mynodeid', {\n            Move: {\n              enable: true,\n              offsetX: 30,\n              offsetY: 5\n            },\n            onComplete: function() {\n                alert('yay!');\n            }\n          });\n        (end code)\n\n        */\n      onClick: function (id, options) {\n        var canvas = this.canvas, that = this, Geom = this.geom, config = this.config;\n        var innerController = {\n            Move: {\n              enable: true,\n              offsetX: config.offsetX || 0,\n              offsetY: config.offsetY || 0\n            },\n            setRightLevelToShowConfig: false,\n            onBeforeRequest: $.empty,\n            onBeforeContract: $.empty,\n            onBeforeMove: $.empty,\n            onBeforeExpand: $.empty\n        };\n        var complete = $.merge(this.controller, innerController, options);\n\n        if(!this.busy) {\n            this.busy = true;\n            var node = this.graph.getNode(id);\n            this.selectPath(node, this.clickedNode);\n             this.clickedNode = node;\n            complete.onBeforeCompute(node);\n            complete.onBeforeRequest(node);\n            this.requestNodes(node, {\n                onComplete: function() {\n                    complete.onBeforeContract(node);\n                    that.contract({\n                        onComplete: function() {\n                            Geom.setRightLevelToShow(node, canvas, complete.setRightLevelToShowConfig);\n                            complete.onBeforeMove(node);\n                            that.move(node, {\n                                Move: complete.Move,\n                                onComplete: function() {\n                                    complete.onBeforeExpand(node);\n                                    that.expand(node, {\n                                        onComplete: function() {\n                                            that.busy = false;\n                                            complete.onAfterCompute(id);\n                                            complete.onComplete();\n                                        }\n                                    }); // expand\n                                }\n                            }); // move\n                        }\n                    });// contract\n                }\n            });// request\n        }\n      }\n    });\n\n})();\n\n$jit.ST.$extend = true;\n\n/*\n   Class: ST.Op\n\n   Custom extension of <Graph.Op>.\n\n   Extends:\n\n   All <Graph.Op> methods\n\n   See also:\n\n   <Graph.Op>\n\n*/\n$jit.ST.Op = new Class({\n    Implements: Graph.Op,\n\n    initialize: function(viz) {\n        this.viz = viz;\n    }\n});\n\n/*\n\n     Performs operations on group of nodes.\n\n*/\n$jit.ST.Group = new Class({\n\n    initialize: function(viz) {\n        this.viz = viz;\n        this.canvas = viz.canvas;\n        this.config = viz.config;\n        this.animation = new Animation;\n        this.nodes = null;\n    },\n\n    /*\n\n       Calls the request method on the controller to request a subtree for each node.\n    */\n    requestNodes: function(nodes, controller) {\n        var counter = 0, len = nodes.length, nodeSelected = {};\n        var complete = function() { controller.onComplete(); };\n        var viz = this.viz;\n        if(len == 0) complete();\n        for(var i=0; i<len; i++) {\n            nodeSelected[nodes[i].id] = nodes[i];\n            controller.request(nodes[i].id, nodes[i]._level, {\n                onComplete: function(nodeId, data) {\n                    if(data && data.children) {\n                        data.id = nodeId;\n                        viz.op.sum(data, { type: 'nothing' });\n                    }\n                    if(++counter == len) {\n                        viz.graph.computeLevels(viz.root, 0);\n                        complete();\n                    }\n                }\n            });\n        }\n    },\n\n    /*\n\n       Collapses group of nodes.\n    */\n    contract: function(nodes, controller) {\n        var viz = this.viz;\n        var that = this;\n\n        nodes = this.prepare(nodes);\n        this.animation.setOptions($.merge(controller, {\n            $animating: false,\n            compute: function(delta) {\n              if(delta == 1) delta = 0.99;\n              that.plotStep(1 - delta, controller, this.$animating);\n              this.$animating = 'contract';\n            },\n\n            complete: function() {\n                that.hide(nodes, controller);\n            }\n        })).start();\n    },\n\n    hide: function(nodes, controller) {\n        var viz = this.viz;\n        for(var i=0; i<nodes.length; i++) {\n            // TODO nodes are requested on demand, but not\n            // deleted when hidden. Would that be a good feature?\n            // Currently that feature is buggy, so I'll turn it off\n            // Actually this feature is buggy because trimming should take\n            // place onAfterCompute and not right after collapsing nodes.\n            if (true || !controller || !controller.request) {\n                nodes[i].eachLevel(1, false, function(elem){\n                    if (elem.exist) {\n                        $.extend(elem, {\n                            'drawn': false,\n                            'exist': false\n                        });\n                    }\n                });\n            } else {\n                var ids = [];\n                nodes[i].eachLevel(1, false, function(n) {\n                    ids.push(n.id);\n                });\n                viz.op.removeNode(ids, { 'type': 'nothing' });\n                viz.labels.clearLabels();\n            }\n        }\n        controller.onComplete();\n    },\n\n\n    /*\n       Expands group of nodes.\n    */\n    expand: function(nodes, controller) {\n        var that = this;\n        this.show(nodes);\n        this.animation.setOptions($.merge(controller, {\n            $animating: false,\n            compute: function(delta) {\n                that.plotStep(delta, controller, this.$animating);\n                this.$animating = 'expand';\n            },\n\n            complete: function() {\n                that.plotStep(undefined, controller, false);\n                controller.onComplete();\n            }\n        })).start();\n\n    },\n\n    show: function(nodes) {\n        var config = this.config;\n        this.prepare(nodes);\n        $.each(nodes, function(n) {\n          // check for root nodes if multitree\n          if(config.multitree && !('$orn' in n.data)) {\n            delete n.data.$orns;\n            var orns = ' ';\n            n.eachSubnode(function(ch) {\n              if(('$orn' in ch.data)\n                  && orns.indexOf(ch.data.$orn) < 0\n                  && ch.exist && !ch.drawn) {\n                orns += ch.data.$orn + ' ';\n              }\n            });\n            n.data.$orns = orns;\n          }\n            n.eachLevel(0, config.levelsToShow, function(n) {\n              if(n.exist) n.drawn = true;\n            });\n        });\n    },\n\n    prepare: function(nodes) {\n        this.nodes = this.getNodesWithChildren(nodes);\n        return this.nodes;\n    },\n\n    /*\n       Filters an array of nodes leaving only nodes with children.\n    */\n    getNodesWithChildren: function(nodes) {\n        var ans = [], config = this.config, root = this.viz.root;\n        nodes.sort(function(a, b) { return (a._depth <= b._depth) - (a._depth >= b._depth); });\n        for(var i=0; i<nodes.length; i++) {\n            if(nodes[i].anySubnode(\"exist\")) {\n              for (var j = i+1, desc = false; !desc && j < nodes.length; j++) {\n                    if(!config.multitree || '$orn' in nodes[j].data) {\n                    desc = desc || nodes[i].isDescendantOf(nodes[j].id);\n                    }\n                }\n                if(!desc) ans.push(nodes[i]);\n            }\n        }\n        return ans;\n    },\n\n    plotStep: function(delta, controller, animating) {\n        var viz = this.viz,\n        config = this.config,\n        canvas = viz.canvas,\n        ctx = canvas.getCtx(),\n        nodes = this.nodes;\n        var i, node;\n        // hide nodes that are meant to be collapsed/expanded\n        var nds = {};\n        for(i=0; i<nodes.length; i++) {\n          node = nodes[i];\n          nds[node.id] = [];\n          var root = config.multitree && !('$orn' in node.data);\n          var orns = root && node.data.$orns;\n          node.eachSubgraph(function(n) {\n            // TODO(nico): Cleanup\n            // special check for root node subnodes when\n            // multitree is checked.\n            if(root && orns && orns.indexOf(n.data.$orn) > 0\n                && n.drawn) {\n              n.drawn = false;\n                  nds[node.id].push(n);\n              } else if((!root || !orns) && n.drawn) {\n                n.drawn = false;\n                nds[node.id].push(n);\n              }\n            });\n            node.drawn = true;\n        }\n        // plot the whole (non-scaled) tree\n        if(nodes.length > 0) viz.fx.plot();\n        // show nodes that were previously hidden\n        for(i in nds) {\n          $.each(nds[i], function(n) { n.drawn = true; });\n        }\n        // plot each scaled subtree\n        for(i=0; i<nodes.length; i++) {\n          node = nodes[i];\n          ctx.save();\n          viz.fx.plotSubtree(node, controller, delta, animating);\n          ctx.restore();\n        }\n      },\n\n      getSiblings: function(nodes) {\n        var siblings = {};\n        $.each(nodes, function(n) {\n            var par = n.getParents();\n            if (par.length == 0) {\n                siblings[n.id] = [n];\n            } else {\n                var ans = [];\n                par[0].eachSubnode(function(sn) {\n                    ans.push(sn);\n                });\n                siblings[n.id] = ans;\n            }\n        });\n        return siblings;\n    }\n});\n\n/*\n   ST.Geom\n\n   Performs low level geometrical computations.\n\n   Access:\n\n   This instance can be accessed with the _geom_ parameter of the st instance created.\n\n   Example:\n\n   (start code js)\n    var st = new ST(canvas, config);\n    st.geom.translate //or can also call any other <ST.Geom> method\n   (end code)\n\n*/\n\n$jit.ST.Geom = new Class({\n    Implements: Graph.Geom,\n    /*\n       Changes the tree current orientation to the one specified.\n\n       You should usually use <ST.switchPosition> instead.\n    */\n    switchOrientation: function(orn) {\n      this.config.orientation = orn;\n    },\n\n    /*\n       Makes a value dispatch according to the current layout\n       Works like a CSS property, either _top-right-bottom-left_ or _top|bottom - left|right_.\n     */\n    dispatch: function() {\n        // TODO(nico) should store Array.prototype.slice.call somewhere.\n        var args = Array.prototype.slice.call(arguments);\n        var s = args.shift(), len = args.length;\n        var val = function(a) { return typeof a == 'function'? a() : a; };\n        if(len == 2) {\n            return (s == \"top\" || s == \"bottom\")? val(args[0]) : val(args[1]);\n        } else if(len == 4) {\n            switch(s) {\n                case \"top\": return val(args[0]);\n                case \"right\": return val(args[1]);\n                case \"bottom\": return val(args[2]);\n                case \"left\": return val(args[3]);\n            }\n        }\n        return undefined;\n    },\n\n    /*\n       Returns label height or with, depending on the tree current orientation.\n    */\n    getSize: function(n, invert) {\n        var data = n.data, config = this.config;\n        var siblingOffset = config.siblingOffset;\n        var s = (config.multitree\n            && ('$orn' in data)\n            && data.$orn) || config.orientation;\n        var w = n.getData('width') + siblingOffset;\n        var h = n.getData('height') + siblingOffset;\n        if(!invert)\n            return this.dispatch(s, h, w);\n        else\n            return this.dispatch(s, w, h);\n    },\n\n    /*\n       Calculates a subtree base size. This is an utility function used by _getBaseSize_\n    */\n    getTreeBaseSize: function(node, level, leaf) {\n        var size = this.getSize(node, true), baseHeight = 0, that = this;\n        if(leaf(level, node)) return size;\n        if(level === 0) return 0;\n        node.eachSubnode(function(elem) {\n            baseHeight += that.getTreeBaseSize(elem, level -1, leaf);\n        });\n        return (size > baseHeight? size : baseHeight) + this.config.subtreeOffset;\n    },\n\n\n    /*\n       getEdge\n\n       Returns a Complex instance with the begin or end position of the edge to be plotted.\n\n       Parameters:\n\n       node - A <Graph.Node> that is connected to this edge.\n       type - Returns the begin or end edge position. Possible values are 'begin' or 'end'.\n\n       Returns:\n\n       A <Complex> number specifying the begin or end position.\n    */\n    getEdge: function(node, type, s) {\n      var $C = function(a, b) {\n          return function(){\n            return node.pos.add(new Complex(a, b));\n          };\n        };\n        var dim = this.node;\n        var w = node.getData('width');\n        var h = node.getData('height');\n\n        if(type == 'begin') {\n            if(dim.align == \"center\") {\n                return this.dispatch(s, $C(0, h/2), $C(-w/2, 0),\n                                     $C(0, -h/2),$C(w/2, 0));\n            } else if(dim.align == \"left\") {\n                return this.dispatch(s, $C(0, h), $C(0, 0),\n                                     $C(0, 0), $C(w, 0));\n            } else if(dim.align == \"right\") {\n                return this.dispatch(s, $C(0, 0), $C(-w, 0),\n                                     $C(0, -h),$C(0, 0));\n            } else throw \"align: not implemented\";\n\n\n        } else if(type == 'end') {\n            if(dim.align == \"center\") {\n                return this.dispatch(s, $C(0, -h/2), $C(w/2, 0),\n                                     $C(0, h/2),  $C(-w/2, 0));\n            } else if(dim.align == \"left\") {\n                return this.dispatch(s, $C(0, 0), $C(w, 0),\n                                     $C(0, h), $C(0, 0));\n            } else if(dim.align == \"right\") {\n                return this.dispatch(s, $C(0, -h),$C(0, 0),\n                                     $C(0, 0), $C(-w, 0));\n            } else throw \"align: not implemented\";\n        }\n    },\n\n    /*\n       Adjusts the tree position due to canvas scaling or translation.\n    */\n    getScaledTreePosition: function(node, scale) {\n        var dim = this.node;\n        var w = node.getData('width');\n        var h = node.getData('height');\n        var s = (this.config.multitree\n            && ('$orn' in node.data)\n            && node.data.$orn) || this.config.orientation;\n\n        var $C = function(a, b) {\n          return function(){\n            return node.pos.add(new Complex(a, b)).$scale(1 - scale);\n          };\n        };\n        if(dim.align == \"left\") {\n            return this.dispatch(s, $C(0, h), $C(0, 0),\n                                 $C(0, 0), $C(w, 0));\n        } else if(dim.align == \"center\") {\n            return this.dispatch(s, $C(0, h / 2), $C(-w / 2, 0),\n                                 $C(0, -h / 2),$C(w / 2, 0));\n        } else if(dim.align == \"right\") {\n            return this.dispatch(s, $C(0, 0), $C(-w, 0),\n                                 $C(0, -h),$C(0, 0));\n        } else throw \"align: not implemented\";\n    },\n\n    /*\n       treeFitsInCanvas\n\n       Returns a Boolean if the current subtree fits in canvas.\n\n       Parameters:\n\n       node - A <Graph.Node> which is the current root of the subtree.\n       canvas - The <Canvas> object.\n       level - The depth of the subtree to be considered.\n    */\n    treeFitsInCanvas: function(node, canvas, level) {\n        var csize = canvas.getSize();\n        var s = (this.config.multitree\n            && ('$orn' in node.data)\n            && node.data.$orn) || this.config.orientation;\n\n        var size = this.dispatch(s, csize.width, csize.height);\n        var baseSize = this.getTreeBaseSize(node, level, function(level, node) {\n          return level === 0 || !node.anySubnode();\n        });\n        return (baseSize < size);\n    }\n});\n\n/*\n  Class: ST.Plot\n\n  Custom extension of <Graph.Plot>.\n\n  Extends:\n\n  All <Graph.Plot> methods\n\n  See also:\n\n  <Graph.Plot>\n\n*/\n$jit.ST.Plot = new Class({\n\n    Implements: Graph.Plot,\n\n    initialize: function(viz) {\n        this.viz = viz;\n        this.config = viz.config;\n        this.node = this.config.Node;\n        this.edge = this.config.Edge;\n        this.animation = new Animation;\n        this.nodeTypes = new $jit.ST.Plot.NodeTypes;\n        this.edgeTypes = new $jit.ST.Plot.EdgeTypes;\n        this.labels = viz.labels;\n    },\n\n    /*\n       Plots a subtree from the spacetree.\n    */\n    plotSubtree: function(node, opt, scale, animating) {\n        var viz = this.viz, canvas = viz.canvas, config = viz.config;\n        scale = Math.min(Math.max(0.001, scale), 1);\n        if(scale >= 0) {\n            node.drawn = false;\n            var ctx = canvas.getCtx();\n            var diff = viz.geom.getScaledTreePosition(node, scale);\n            ctx.translate(diff.x, diff.y);\n            ctx.scale(scale, scale);\n        }\n        this.plotTree(node, $.merge(opt, {\n          'withLabels': true,\n          'hideLabels': !!scale,\n          'plotSubtree': function(n, ch) {\n            var root = config.multitree && !('$orn' in node.data);\n            var orns = root && node.getData('orns');\n            return !root || orns.indexOf(elem.getData('orn')) > -1;\n          }\n        }), animating);\n        if(scale >= 0) node.drawn = true;\n    },\n\n    /*\n        Method: getAlignedPos\n\n        Returns a *x, y* object with the position of the top/left corner of a <ST> node.\n\n        Parameters:\n\n        pos - (object) A <Graph.Node> position.\n        width - (number) The width of the node.\n        height - (number) The height of the node.\n\n     */\n    getAlignedPos: function(pos, width, height) {\n        var nconfig = this.node;\n        var square, orn;\n        if(nconfig.align == \"center\") {\n            square = {\n                x: pos.x - width / 2,\n                y: pos.y - height / 2\n            };\n        } else if (nconfig.align == \"left\") {\n            orn = this.config.orientation;\n            if(orn == \"bottom\" || orn == \"top\") {\n                square = {\n                    x: pos.x - width / 2,\n                    y: pos.y\n                };\n            } else {\n                square = {\n                    x: pos.x,\n                    y: pos.y - height / 2\n                };\n            }\n        } else if(nconfig.align == \"right\") {\n            orn = this.config.orientation;\n            if(orn == \"bottom\" || orn == \"top\") {\n                square = {\n                    x: pos.x - width / 2,\n                    y: pos.y - height\n                };\n            } else {\n                square = {\n                    x: pos.x - width,\n                    y: pos.y - height / 2\n                };\n            }\n        } else throw \"align: not implemented\";\n\n        return square;\n    },\n\n    getOrientation: function(adj) {\n      var config = this.config;\n      var orn = config.orientation;\n\n      if(config.multitree) {\n          var nodeFrom = adj.nodeFrom;\n          var nodeTo = adj.nodeTo;\n        orn = (('$orn' in nodeFrom.data)\n            && nodeFrom.data.$orn)\n            || (('$orn' in nodeTo.data)\n            && nodeTo.data.$orn);\n      }\n\n      return orn;\n    }\n});\n\n/*\n  Class: ST.Label\n\n  Custom extension of <Graph.Label>.\n  Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.\n\n  Extends:\n\n  All <Graph.Label> methods and subclasses.\n\n  See also:\n\n  <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.\n */\n$jit.ST.Label = {};\n\n/*\n   ST.Label.Native\n\n   Custom extension of <Graph.Label.Native>.\n\n   Extends:\n\n   All <Graph.Label.Native> methods\n\n   See also:\n\n   <Graph.Label.Native>\n*/\n$jit.ST.Label.Native = new Class({\n  Implements: Graph.Label.Native,\n\n  renderLabel: function(canvas, node, controller) {\n    var ctx = canvas.getCtx();\n    var coord = node.pos.getc(true);\n    ctx.fillText(node.name, coord.x, coord.y);\n  }\n});\n\n$jit.ST.Label.DOM = new Class({\n  Implements: Graph.Label.DOM,\n\n  /*\n      placeLabel\n\n      Overrides abstract method placeLabel in <Graph.Plot>.\n\n      Parameters:\n\n      tag - A DOM label element.\n      node - A <Graph.Node>.\n      controller - A configuration/controller object passed to the visualization.\n\n    */\n    placeLabel: function(tag, node, controller) {\n        var pos = node.pos.getc(true),\n            config = this.viz.config,\n            dim = config.Node,\n            canvas = this.viz.canvas,\n            w = node.getData('width'),\n            h = node.getData('height'),\n            radius = canvas.getSize(),\n            labelPos, orn;\n\n        var ox = canvas.translateOffsetX,\n            oy = canvas.translateOffsetY,\n            sx = canvas.scaleOffsetX,\n            sy = canvas.scaleOffsetY,\n            posx = pos.x * sx + ox,\n            posy = pos.y * sy + oy;\n\n        if(dim.align == \"center\") {\n            labelPos= {\n                x: Math.round(posx - w / 2 + radius.width/2),\n                y: Math.round(posy - h / 2 + radius.height/2)\n            };\n        } else if (dim.align == \"left\") {\n            orn = config.orientation;\n            if(orn == \"bottom\" || orn == \"top\") {\n                labelPos= {\n                    x: Math.round(posx - w / 2 + radius.width/2),\n                    y: Math.round(posy + radius.height/2)\n                };\n            } else {\n                labelPos= {\n                    x: Math.round(posx + radius.width/2),\n                    y: Math.round(posy - h / 2 + radius.height/2)\n                };\n            }\n        } else if(dim.align == \"right\") {\n            orn = config.orientation;\n            if(orn == \"bottom\" || orn == \"top\") {\n                labelPos= {\n                    x: Math.round(posx - w / 2 + radius.width/2),\n                    y: Math.round(posy - h + radius.height/2)\n                };\n            } else {\n                labelPos= {\n                    x: Math.round(posx - w + radius.width/2),\n                    y: Math.round(posy - h / 2 + radius.height/2)\n                };\n            }\n        } else throw \"align: not implemented\";\n\n        var style = tag.style;\n        style.left = labelPos.x + 'px';\n        style.top  = labelPos.y + 'px';\n        style.display = this.fitsInCanvas(labelPos, canvas)? '' : 'none';\n        controller.onPlaceLabel(tag, node);\n    }\n});\n\n/*\n  ST.Label.SVG\n\n  Custom extension of <Graph.Label.SVG>.\n\n  Extends:\n\n  All <Graph.Label.SVG> methods\n\n  See also:\n\n  <Graph.Label.SVG>\n*/\n$jit.ST.Label.SVG = new Class({\n  Implements: [$jit.ST.Label.DOM, Graph.Label.SVG],\n\n  initialize: function(viz) {\n    this.viz = viz;\n  }\n});\n\n/*\n   ST.Label.HTML\n\n   Custom extension of <Graph.Label.HTML>.\n\n   Extends:\n\n   All <Graph.Label.HTML> methods.\n\n   See also:\n\n   <Graph.Label.HTML>\n\n*/\n$jit.ST.Label.HTML = new Class({\n  Implements: [$jit.ST.Label.DOM, Graph.Label.HTML],\n\n  initialize: function(viz) {\n    this.viz = viz;\n  }\n});\n\n\n/*\n  Class: ST.Plot.NodeTypes\n\n  This class contains a list of <Graph.Node> built-in types.\n  Node types implemented are 'none', 'circle', 'rectangle', 'ellipse' and 'square'.\n\n  You can add your custom node types, customizing your visualization to the extreme.\n\n  Example:\n\n  (start code js)\n    ST.Plot.NodeTypes.implement({\n      'mySpecialType': {\n        'render': function(node, canvas) {\n          //print your custom node to canvas\n        },\n        //optional\n        'contains': function(node, pos) {\n          //return true if pos is inside the node or false otherwise\n        }\n      }\n    });\n  (end code)\n\n*/\n$jit.ST.Plot.NodeTypes = new Class({\n  'none': {\n    'render': $.empty,\n    'contains': $.lambda(false)\n  },\n  'circle': {\n    'render': function(node, canvas) {\n      var dim  = node.getData('dim'),\n          pos = this.getAlignedPos(node.pos.getc(true), dim, dim),\n          dim2 = dim/2;\n      this.nodeHelper.circle.render('fill', {x:pos.x+dim2, y:pos.y+dim2}, dim2, canvas);\n    },\n    'contains': function(node, pos) {\n      var dim  = node.getData('dim'),\n          npos = this.getAlignedPos(node.pos.getc(true), dim, dim),\n          dim2 = dim/2;\n      this.nodeHelper.circle.contains({x:npos.x+dim2, y:npos.y+dim2}, dim2);\n    }\n  },\n  'square': {\n    'render': function(node, canvas) {\n      var dim  = node.getData('dim'),\n          dim2 = dim/2,\n          pos = this.getAlignedPos(node.pos.getc(true), dim, dim);\n      this.nodeHelper.square.render('fill', {x:pos.x+dim2, y:pos.y+dim2}, dim2, canvas);\n    },\n    'contains': function(node, pos) {\n      var dim  = node.getData('dim'),\n          npos = this.getAlignedPos(node.pos.getc(true), dim, dim),\n          dim2 = dim/2;\n      this.nodeHelper.square.contains({x:npos.x+dim2, y:npos.y+dim2}, dim2);\n    }\n  },\n  'ellipse': {\n    'render': function(node, canvas) {\n      var width = node.getData('width'),\n          height = node.getData('height'),\n          pos = this.getAlignedPos(node.pos.getc(true), width, height);\n      this.nodeHelper.ellipse.render('fill', {x:pos.x+width/2, y:pos.y+height/2}, width, height, canvas);\n    },\n    'contains': function(node, pos) {\n      var width = node.getData('width'),\n          height = node.getData('height'),\n          npos = this.getAlignedPos(node.pos.getc(true), width, height);\n      this.nodeHelper.ellipse.contains({x:npos.x+width/2, y:npos.y+height/2}, width, height, canvas);\n    }\n  },\n  'rectangle': {\n    'render': function(node, canvas) {\n      var width = node.getData('width'),\n          height = node.getData('height'),\n          pos = this.getAlignedPos(node.pos.getc(true), width, height);\n      this.nodeHelper.rectangle.render('fill', {x:pos.x+width/2, y:pos.y+height/2}, width, height, canvas);\n    },\n    'contains': function(node, pos) {\n      var width = node.getData('width'),\n          height = node.getData('height'),\n          npos = this.getAlignedPos(node.pos.getc(true), width, height);\n      this.nodeHelper.rectangle.contains({x:npos.x+width/2, y:npos.y+height/2}, width, height, canvas);\n    }\n  }\n});\n\n/*\n  Class: ST.Plot.EdgeTypes\n\n  This class contains a list of <Graph.Adjacence> built-in types.\n  Edge types implemented are 'none', 'line', 'arrow', 'quadratic:begin', 'quadratic:end', 'bezier'.\n\n  You can add your custom edge types, customizing your visualization to the extreme.\n\n  Example:\n\n  (start code js)\n    ST.Plot.EdgeTypes.implement({\n      'mySpecialType': function(adj, canvas) {\n        //print your custom edge to canvas\n      }\n    });\n  (end code)\n\n*/\n$jit.ST.Plot.EdgeTypes = new Class({\n    'none': $.empty,\n    'line': function(adj, canvas) {\n      var orn = this.getOrientation(adj),\n          nodeFrom = adj.nodeFrom,\n          nodeTo = adj.nodeTo,\n          rel = nodeFrom._depth < nodeTo._depth,\n          from = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn),\n          to =  this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn);\n      this.edgeHelper.line(from, to, canvas);\n     },\n     'arrow': function(adj, canvas) {\n       var orn = this.getOrientation(adj),\n           node = adj.nodeFrom,\n           child = adj.nodeTo,\n           dim = adj.getData('dim'),\n           from = this.viz.geom.getEdge(node, 'begin', orn),\n           to = this.viz.geom.getEdge(child, 'end', orn),\n           direction = adj.data.$direction,\n           inv = (direction && direction.length>1 && direction[0] != node.id);\n       this.edgeHelper.arrow(from, to, dim, inv, canvas);\n     },\n    'quadratic:begin': function(adj, canvas) {\n      var orn = this.getOrientation(adj);\n      var nodeFrom = adj.nodeFrom,\n          nodeTo = adj.nodeTo,\n          rel = nodeFrom._depth < nodeTo._depth,\n          begin = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn),\n          end =  this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn),\n          dim = adj.getData('dim'),\n          ctx = canvas.getCtx();\n      ctx.beginPath();\n      ctx.moveTo(begin.x, begin.y);\n      switch(orn) {\n        case \"left\":\n          ctx.quadraticCurveTo(begin.x + dim, begin.y, end.x, end.y);\n          break;\n        case \"right\":\n          ctx.quadraticCurveTo(begin.x - dim, begin.y, end.x, end.y);\n          break;\n        case \"top\":\n          ctx.quadraticCurveTo(begin.x, begin.y + dim, end.x, end.y);\n          break;\n        case \"bottom\":\n          ctx.quadraticCurveTo(begin.x, begin.y - dim, end.x, end.y);\n          break;\n      }\n      ctx.stroke();\n    },\n    'quadratic:end': function(adj, canvas) {\n      var orn = this.getOrientation(adj);\n      var nodeFrom = adj.nodeFrom,\n          nodeTo = adj.nodeTo,\n          rel = nodeFrom._depth < nodeTo._depth,\n          begin = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn),\n          end =  this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn),\n          dim = adj.getData('dim'),\n          ctx = canvas.getCtx();\n      ctx.beginPath();\n      ctx.moveTo(begin.x, begin.y);\n      switch(orn) {\n        case \"left\":\n          ctx.quadraticCurveTo(end.x - dim, end.y, end.x, end.y);\n          break;\n        case \"right\":\n          ctx.quadraticCurveTo(end.x + dim, end.y, end.x, end.y);\n          break;\n        case \"top\":\n          ctx.quadraticCurveTo(end.x, end.y - dim, end.x, end.y);\n          break;\n        case \"bottom\":\n          ctx.quadraticCurveTo(end.x, end.y + dim, end.x, end.y);\n          break;\n      }\n      ctx.stroke();\n    },\n    'bezier': function(adj, canvas) {\n      var orn = this.getOrientation(adj),\n          nodeFrom = adj.nodeFrom,\n          nodeTo = adj.nodeTo,\n          rel = nodeFrom._depth < nodeTo._depth,\n          begin = this.viz.geom.getEdge(rel? nodeFrom:nodeTo, 'begin', orn),\n          end =  this.viz.geom.getEdge(rel? nodeTo:nodeFrom, 'end', orn),\n          dim = adj.getData('dim'),\n          ctx = canvas.getCtx();\n      ctx.beginPath();\n      ctx.moveTo(begin.x, begin.y);\n      switch(orn) {\n        case \"left\":\n          ctx.bezierCurveTo(begin.x + dim, begin.y, end.x - dim, end.y, end.x, end.y);\n          break;\n        case \"right\":\n          ctx.bezierCurveTo(begin.x - dim, begin.y, end.x + dim, end.y, end.x, end.y);\n          break;\n        case \"top\":\n          ctx.bezierCurveTo(begin.x, begin.y + dim, end.x, end.y - dim, end.x, end.y);\n          break;\n        case \"bottom\":\n          ctx.bezierCurveTo(begin.x, begin.y - dim, end.x, end.y + dim, end.x, end.y);\n          break;\n      }\n      ctx.stroke();\n    }\n});\n\n\n\n/*\n * File: AreaChart.js\n *\n*/\n\n$jit.ST.Plot.NodeTypes.implement({\n  'areachart-stacked' : {\n    'render' : function(node, canvas) {\n      var pos = node.pos.getc(true),\n          width = node.getData('width'),\n          height = node.getData('height'),\n          algnPos = this.getAlignedPos(pos, width, height),\n          x = algnPos.x, y = algnPos.y,\n          stringArray = node.getData('stringArray'),\n          dimArray = node.getData('dimArray'),\n          valArray = node.getData('valueArray'),\n          valLeft = $.reduce(valArray, function(x, y) { return x + y[0]; }, 0),\n          valRight = $.reduce(valArray, function(x, y) { return x + y[1]; }, 0),\n          colorArray = node.getData('colorArray'),\n          colorLength = colorArray.length,\n          config = node.getData('config'),\n          gradient = node.getData('gradient'),\n          showLabels = config.showLabels,\n          aggregates = config.showAggregates,\n          label = config.Label,\n          prev = node.getData('prev');\n\n      var ctx = canvas.getCtx(), border = node.getData('border');\n      if (colorArray && dimArray && stringArray) {\n        for (var i=0, l=dimArray.length, acumLeft=0, acumRight=0, valAcum=0; i<l; i++) {\n          ctx.fillStyle = ctx.strokeStyle = colorArray[i % colorLength];\n          ctx.save();\n          if(gradient && (dimArray[i][0] > 0 || dimArray[i][1] > 0)) {\n            var h1 = acumLeft + dimArray[i][0],\n                h2 = acumRight + dimArray[i][1],\n                alpha = Math.atan((h2 - h1) / width),\n                delta = 55;\n            var linear = ctx.createLinearGradient(x + width/2,\n                y - (h1 + h2)/2,\n                x + width/2 + delta * Math.sin(alpha),\n                y - (h1 + h2)/2 + delta * Math.cos(alpha));\n            var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)),\n                function(v) { return (v * 0.85) >> 0; }));\n            linear.addColorStop(0, colorArray[i % colorLength]);\n            linear.addColorStop(1, color);\n            ctx.fillStyle = linear;\n          }\n          ctx.beginPath();\n          ctx.moveTo(x, y - acumLeft);\n          ctx.lineTo(x + width, y - acumRight);\n          ctx.lineTo(x + width, y - acumRight - dimArray[i][1]);\n          ctx.lineTo(x, y - acumLeft - dimArray[i][0]);\n          ctx.lineTo(x, y - acumLeft);\n          ctx.fill();\n          ctx.restore();\n          if(border) {\n            var strong = border.name == stringArray[i];\n            var perc = strong? 0.7 : 0.8;\n            var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)),\n                function(v) { return (v * perc) >> 0; }));\n            ctx.strokeStyle = color;\n            ctx.lineWidth = strong? 4 : 1;\n            ctx.save();\n            ctx.beginPath();\n            if(border.index === 0) {\n              ctx.moveTo(x, y - acumLeft);\n              ctx.lineTo(x, y - acumLeft - dimArray[i][0]);\n            } else {\n              ctx.moveTo(x + width, y - acumRight);\n              ctx.lineTo(x + width, y - acumRight - dimArray[i][1]);\n            }\n            ctx.stroke();\n            ctx.restore();\n          }\n          acumLeft += (dimArray[i][0] || 0);\n          acumRight += (dimArray[i][1] || 0);\n\n          if(dimArray[i][0] > 0)\n            valAcum += (valArray[i][0] || 0);\n        }\n        if(prev && label.type == 'Native') {\n          ctx.save();\n          ctx.beginPath();\n          ctx.fillStyle = ctx.strokeStyle = label.color;\n          ctx.font = label.style + ' ' + label.size + 'px ' + label.family;\n          ctx.textAlign = 'center';\n          ctx.textBaseline = 'middle';\n          if(aggregates(node.name, valLeft, valRight, node)) {\n            ctx.fillText(valAcum, x, y - acumLeft - config.labelOffset - label.size/2, width);\n          }\n          if(showLabels(node.name, valLeft, valRight, node)) {\n            ctx.fillText(node.name, x, y + label.size/2 + config.labelOffset);\n          }\n          ctx.restore();\n        }\n      }\n    },\n    'contains': function(node, mpos) {\n      var pos = node.pos.getc(true),\n          width = node.getData('width'),\n          height = node.getData('height'),\n          algnPos = this.getAlignedPos(pos, width, height),\n          x = algnPos.x, y = algnPos.y,\n          dimArray = node.getData('dimArray'),\n          rx = mpos.x - x;\n      //bounding box check\n      if(mpos.x < x || mpos.x > x + width\n        || mpos.y > y || mpos.y < y - height) {\n        return false;\n      }\n      //deep check\n      for(var i=0, l=dimArray.length, lAcum=y, rAcum=y; i<l; i++) {\n        var dimi = dimArray[i];\n        lAcum -= dimi[0];\n        rAcum -= dimi[1];\n        var intersec = lAcum + (rAcum - lAcum) * rx / width;\n        if(mpos.y >= intersec) {\n          var index = +(rx > width/2);\n          return {\n            'name': node.getData('stringArray')[i],\n            'color': node.getData('colorArray')[i],\n            'value': node.getData('valueArray')[i][index],\n            'index': index\n          };\n        }\n      }\n      return false;\n    }\n  }\n});\n\n/*\n  Class: AreaChart\n\n  A visualization that displays stacked area charts.\n\n  Constructor Options:\n\n  See <Options.AreaChart>.\n\n*/\n$jit.AreaChart = new Class({\n  st: null,\n  colors: [\"#416D9C\", \"#70A35E\", \"#EBB056\", \"#C74243\", \"#83548B\", \"#909291\", \"#557EAA\"],\n  selected: {},\n  busy: false,\n\n  initialize: function(opt) {\n    this.controller = this.config =\n      $.merge(Options(\"Canvas\", \"Label\", \"AreaChart\"), {\n        Label: { type: 'Native' }\n      }, opt);\n    //set functions for showLabels and showAggregates\n    var showLabels = this.config.showLabels,\n        typeLabels = $.type(showLabels),\n        showAggregates = this.config.showAggregates,\n        typeAggregates = $.type(showAggregates);\n    this.config.showLabels = typeLabels == 'function'? showLabels : $.lambda(showLabels);\n    this.config.showAggregates = typeAggregates == 'function'? showAggregates : $.lambda(showAggregates);\n\n    this.initializeViz();\n  },\n\n  initializeViz: function() {\n    var config = this.config,\n        that = this,\n        nodeType = config.type.split(\":\")[0],\n        nodeLabels = {};\n\n    var st = new $jit.ST({\n      injectInto: config.injectInto,\n      orientation: \"bottom\",\n      levelDistance: 0,\n      siblingOffset: 0,\n      subtreeOffset: 0,\n      withLabels: config.Label.type != 'Native',\n      useCanvas: config.useCanvas,\n      Label: {\n        type: config.Label.type\n      },\n      Node: {\n        overridable: true,\n        type: 'areachart-' + nodeType,\n        align: 'left',\n        width: 1,\n        height: 1\n      },\n      Edge: {\n        type: 'none'\n      },\n      Tips: {\n        enable: config.Tips.enable,\n        type: 'Native',\n        force: true,\n        onShow: function(tip, node, contains) {\n          var elem = contains;\n          config.Tips.onShow(tip, elem, node);\n        }\n      },\n      Events: {\n        enable: true,\n        type: 'Native',\n        onClick: function(node, eventInfo, evt) {\n          if(!config.filterOnClick && !config.Events.enable) return;\n          var elem = eventInfo.getContains();\n          if(elem) config.filterOnClick && that.filter(elem.name);\n          config.Events.enable && config.Events.onClick(elem, eventInfo, evt);\n        },\n        onRightClick: function(node, eventInfo, evt) {\n          if(!config.restoreOnRightClick) return;\n          that.restore();\n        },\n        onMouseMove: function(node, eventInfo, evt) {\n          if(!config.selectOnHover) return;\n          if(node) {\n            var elem = eventInfo.getContains();\n            that.select(node.id, elem.name, elem.index);\n          } else {\n            that.select(false, false, false);\n          }\n        }\n      },\n      onCreateLabel: function(domElement, node) {\n        var labelConf = config.Label,\n            valueArray = node.getData('valueArray'),\n            acumLeft = $.reduce(valueArray, function(x, y) { return x + y[0]; }, 0),\n            acumRight = $.reduce(valueArray, function(x, y) { return x + y[1]; }, 0);\n        if(node.getData('prev')) {\n          var nlbs = {\n            wrapper: document.createElement('div'),\n            aggregate: document.createElement('div'),\n            label: document.createElement('div')\n          };\n          var wrapper = nlbs.wrapper,\n              label = nlbs.label,\n              aggregate = nlbs.aggregate,\n              wrapperStyle = wrapper.style,\n              labelStyle = label.style,\n              aggregateStyle = aggregate.style;\n          //store node labels\n          nodeLabels[node.id] = nlbs;\n          //append labels\n          wrapper.appendChild(label);\n          wrapper.appendChild(aggregate);\n          if(!config.showLabels(node.name, acumLeft, acumRight, node)) {\n            label.style.display = 'none';\n          }\n          if(!config.showAggregates(node.name, acumLeft, acumRight, node)) {\n            aggregate.style.display = 'none';\n          }\n          wrapperStyle.position = 'relative';\n          wrapperStyle.overflow = 'visible';\n          wrapperStyle.fontSize = labelConf.size + 'px';\n          wrapperStyle.fontFamily = labelConf.family;\n          wrapperStyle.color = labelConf.color;\n          wrapperStyle.textAlign = 'center';\n          aggregateStyle.position = labelStyle.position = 'absolute';\n\n          domElement.style.width = node.getData('width') + 'px';\n          domElement.style.height = node.getData('height') + 'px';\n          label.innerHTML = node.name;\n\n          domElement.appendChild(wrapper);\n        }\n      },\n      onPlaceLabel: function(domElement, node) {\n        if(!node.getData('prev')) return;\n        var labels = nodeLabels[node.id],\n            wrapperStyle = labels.wrapper.style,\n            labelStyle = labels.label.style,\n            aggregateStyle = labels.aggregate.style,\n            width = node.getData('width'),\n            height = node.getData('height'),\n            dimArray = node.getData('dimArray'),\n            valArray = node.getData('valueArray'),\n            acumLeft = $.reduce(valArray, function(x, y) { return x + y[0]; }, 0),\n            acumRight = $.reduce(valArray, function(x, y) { return x + y[1]; }, 0),\n            font = parseInt(wrapperStyle.fontSize, 10),\n            domStyle = domElement.style;\n\n        if(dimArray && valArray) {\n          if(config.showLabels(node.name, acumLeft, acumRight, node)) {\n            labelStyle.display = '';\n          } else {\n            labelStyle.display = 'none';\n          }\n          if(config.showAggregates(node.name, acumLeft, acumRight, node)) {\n            aggregateStyle.display = '';\n          } else {\n            aggregateStyle.display = 'none';\n          }\n          wrapperStyle.width = aggregateStyle.width = labelStyle.width = domElement.style.width = width + 'px';\n          aggregateStyle.left = labelStyle.left = -width/2 + 'px';\n          for(var i=0, l=valArray.length, acum=0, leftAcum=0; i<l; i++) {\n            if(dimArray[i][0] > 0) {\n              acum+= valArray[i][0];\n              leftAcum+= dimArray[i][0];\n            }\n          }\n          aggregateStyle.top = (-font - config.labelOffset) + 'px';\n          labelStyle.top = (config.labelOffset + leftAcum) + 'px';\n          domElement.style.top = parseInt(domElement.style.top, 10) - leftAcum + 'px';\n          domElement.style.height = wrapperStyle.height = leftAcum + 'px';\n          labels.aggregate.innerHTML = acum;\n        }\n      }\n    });\n\n    var size = st.canvas.getSize();\n    st.config.offsetY = -size.height/2 + config.offset\n      + (config.showLabels && (config.labelOffset + config.Label.size));\n    this.st = st;\n    this.canvas = this.st.canvas;\n  },\n\n /*\n  Method: loadJSON\n\n  Loads JSON data into the visualization.\n\n  Parameters:\n\n  json - The JSON data format. This format is described in <http://blog.thejit.org/2010/04/24/new-javascript-infovis-toolkit-visualizations/#json-data-format>.\n\n  Example:\n  (start code js)\n  var areaChart = new $jit.AreaChart(options);\n  areaChart.loadJSON(json);\n  (end code)\n */\n  loadJSON: function(json) {\n    var prefix = $.time(),\n        ch = [],\n        st = this.st,\n        name = $.splat(json.label),\n        color = $.splat(json.color || this.colors),\n        config = this.config,\n        gradient = !!config.type.split(\":\")[1],\n        animate = config.animate;\n\n    for(var i=0, values=json.values, l=values.length; i<l-1; i++) {\n      var val = values[i], prev = values[i-1], next = values[i+1];\n      var valLeft = $.splat(values[i].values), valRight = $.splat(values[i+1].values);\n      var valArray = $.zip(valLeft, valRight);\n      var acumLeft = 0, acumRight = 0;\n      ch.push({\n        'id': prefix + val.label,\n        'name': val.label,\n        'data': {\n          'value': valArray,\n          '$valueArray': valArray,\n          '$colorArray': color,\n          '$stringArray': name,\n          '$next': next.label,\n          '$prev': prev? prev.label:null,\n          '$config': config,\n          '$gradient': gradient\n        },\n        'children': []\n      });\n    }\n    var root = {\n      'id': prefix + '$root',\n      'name': '',\n      'data': {\n        '$type': 'none',\n        '$width': 1,\n        '$height': 1\n      },\n      'children': ch\n    };\n    st.loadJSON(root);\n\n    this.normalizeDims();\n    st.compute();\n    st.select(st.root);\n    if(animate) {\n      st.fx.animate({\n        modes: ['node-property:height:dimArray'],\n        duration:1500\n      });\n    }\n  },\n\n /*\n  Method: updateJSON\n\n  Use this method when updating values for the current JSON data. If the items specified by the JSON data already exist in the graph then their values will be updated.\n\n  Parameters:\n\n  json - (object) JSON data to be updated. The JSON format corresponds to the one described in <AreaChart.loadJSON>.\n  onComplete - (object) A callback object to be called when the animation transition when updating the data end.\n\n  Example:\n\n  (start code js)\n  areaChart.updateJSON(json, {\n    onComplete: function() {\n      alert('update complete!');\n    }\n  });\n  (end code)\n */\n  updateJSON: function(json, onComplete) {\n    if(this.busy) return;\n    this.busy = true;\n\n    var st = this.st,\n        graph = st.graph,\n        labels = json.label && $.splat(json.label),\n        values = json.values,\n        animate = this.config.animate,\n        that = this;\n    $.each(values, function(v) {\n      var n = graph.getByName(v.label);\n      if(n) {\n        v.values = $.splat(v.values);\n        var stringArray = n.getData('stringArray'),\n            valArray = n.getData('valueArray');\n        $.each(valArray, function(a, i) {\n          a[0] = v.values[i];\n          if(labels) stringArray[i] = labels[i];\n        });\n        n.setData('valueArray', valArray);\n        var prev = n.getData('prev');\n        if(prev) {\n          var p = graph.getByName(prev);\n          var valArray = p.getData('valueArray');\n          $.each(valArray, function(a, i) {\n            a[1] = v.values[i];\n          });\n          p.setData('valueArray', valArray);\n        }\n      }\n    });\n    this.normalizeDims();\n    st.compute();\n    st.select(st.root);\n    if(animate) {\n      st.fx.animate({\n        modes: ['node-property:height:dimArray'],\n        duration:1500,\n        onComplete: function() {\n          that.busy = false;\n          onComplete && onComplete.onComplete();\n        }\n      });\n    }\n  },\n\n/*\n  Method: filter\n\n  Filter selected stacks, collapsing all other stacks. You can filter multiple stacks at the same time.\n\n  Parameters:\n\n  Variable strings arguments with the name of the stacks.\n\n  Example:\n\n  (start code js)\n  areaChart.filter('label A', 'label C');\n  (end code)\n\n  See also:\n\n  <AreaChart.restore>.\n */\n  filter: function() {\n    if(this.busy) return;\n    this.busy = true;\n    if(this.config.Tips.enable) this.st.tips.hide();\n    this.select(false, false, false);\n    var args = Array.prototype.slice.call(arguments);\n    var rt = this.st.graph.getNode(this.st.root);\n    var that = this;\n    rt.eachAdjacency(function(adj) {\n      var n = adj.nodeTo,\n          dimArray = n.getData('dimArray'),\n          stringArray = n.getData('stringArray');\n      n.setData('dimArray', $.map(dimArray, function(d, i) {\n        return ($.indexOf(args, stringArray[i]) > -1)? d:[0, 0];\n      }), 'end');\n    });\n    this.st.fx.animate({\n      modes: ['node-property:dimArray'],\n      duration:1500,\n      onComplete: function() {\n        that.busy = false;\n      }\n    });\n  },\n\n  /*\n  Method: restore\n\n  Sets all stacks that could have been filtered visible.\n\n  Example:\n\n  (start code js)\n  areaChart.restore();\n  (end code)\n\n  See also:\n\n  <AreaChart.filter>.\n */\n  restore: function() {\n    if(this.busy) return;\n    this.busy = true;\n    if(this.config.Tips.enable) this.st.tips.hide();\n    this.select(false, false, false);\n    this.normalizeDims();\n    var that = this;\n    this.st.fx.animate({\n      modes: ['node-property:height:dimArray'],\n      duration:1500,\n      onComplete: function() {\n        that.busy = false;\n      }\n    });\n  },\n  //adds the little brown bar when hovering the node\n  select: function(id, name, index) {\n    if(!this.config.selectOnHover) return;\n    var s = this.selected;\n    if(s.id != id || s.name != name\n        || s.index != index) {\n      s.id = id;\n      s.name = name;\n      s.index = index;\n      this.st.graph.eachNode(function(n) {\n        n.setData('border', false);\n      });\n      if(id) {\n        var n = this.st.graph.getNode(id);\n        n.setData('border', s);\n        var link = index === 0? 'prev':'next';\n        link = n.getData(link);\n        if(link) {\n          n = this.st.graph.getByName(link);\n          if(n) {\n            n.setData('border', {\n              name: name,\n              index: 1-index\n            });\n          }\n        }\n      }\n      this.st.plot();\n    }\n  },\n\n  /*\n    Method: getLegend\n\n    Returns an object containing as keys the legend names and as values hex strings with color values.\n\n    Example:\n\n    (start code js)\n    var legend = areaChart.getLegend();\n    (end code)\n */\n  getLegend: function() {\n    var legend = {};\n    var n;\n    this.st.graph.getNode(this.st.root).eachAdjacency(function(adj) {\n      n = adj.nodeTo;\n    });\n    var colors = n.getData('colorArray'),\n        len = colors.length;\n    $.each(n.getData('stringArray'), function(s, i) {\n      legend[s] = colors[i % len];\n    });\n    return legend;\n  },\n\n  /*\n    Method: getMaxValue\n\n    Returns the maximum accumulated value for the stacks. This method is used for normalizing the graph heights according to the canvas height.\n\n    Example:\n\n    (start code js)\n    var ans = areaChart.getMaxValue();\n    (end code)\n\n    In some cases it could be useful to override this method to normalize heights for a group of AreaCharts, like when doing small multiples.\n\n    Example:\n\n    (start code js)\n    //will return 100 for all AreaChart instances,\n    //displaying all of them with the same scale\n    $jit.AreaChart.implement({\n      'getMaxValue': function() {\n        return 100;\n      }\n    });\n    (end code)\n\n*/\n  getMaxValue: function() {\n    var maxValue = 0;\n    this.st.graph.eachNode(function(n) {\n      var valArray = n.getData('valueArray'),\n          acumLeft = 0, acumRight = 0;\n      $.each(valArray, function(v) {\n        acumLeft += +v[0];\n        acumRight += +v[1];\n      });\n      var acum = acumRight>acumLeft? acumRight:acumLeft;\n      maxValue = maxValue>acum? maxValue:acum;\n    });\n    return maxValue;\n  },\n\n  normalizeDims: function() {\n    //number of elements\n    var root = this.st.graph.getNode(this.st.root), l=0;\n    root.eachAdjacency(function() {\n      l++;\n    });\n    var maxValue = this.getMaxValue(),\n        size = this.st.canvas.getSize(),\n        config = this.config,\n        offset = config.offset,\n        labelOffset = config.labelOffset + config.Label.size,\n        fixedDim = (size.width - 2 * offset) / l,\n        animate = config.animate,\n        height = size.height - 2 * offset - (config.showAggregates && labelOffset)\n          - (config.showLabels && labelOffset);\n    this.st.graph.eachNode(function(n) {\n      var acumLeft = 0, acumRight = 0, animateValue = [];\n      $.each(n.getData('valueArray'), function(v) {\n        acumLeft += +v[0];\n        acumRight += +v[1];\n        animateValue.push([0, 0]);\n      });\n      var acum = acumRight>acumLeft? acumRight:acumLeft;\n      n.setData('width', fixedDim);\n      if(animate) {\n        n.setData('height', acum * height / maxValue, 'end');\n        n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {\n          return [n[0] * height / maxValue, n[1] * height / maxValue];\n        }), 'end');\n        var dimArray = n.getData('dimArray');\n        if(!dimArray) {\n          n.setData('dimArray', animateValue);\n        }\n      } else {\n        n.setData('height', acum * height / maxValue);\n        n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {\n          return [n[0] * height / maxValue, n[1] * height / maxValue];\n        }));\n      }\n    });\n  }\n});\n\n/*\n * Class: Layouts.Radial\n *\n * Implements a Radial Layout.\n *\n * Implemented By:\n *\n * <RGraph>, <Hypertree>\n *\n */\nLayouts.Radial = new Class({\n\n  /*\n   * Method: compute\n   *\n   * Computes nodes' positions.\n   *\n   * Parameters:\n   *\n   * property - _optional_ A <Graph.Node> position property to store the new\n   * positions. Possible values are 'pos', 'end' or 'start'.\n   *\n   */\n  compute : function(property) {\n    var prop = $.splat(property || [ 'current', 'start', 'end' ]);\n    NodeDim.compute(this.graph, prop, this.config);\n    this.graph.computeLevels(this.root, 0, \"ignore\");\n    var lengthFunc = this.createLevelDistanceFunc();\n    this.computeAngularWidths(prop);\n    this.computePositions(prop, lengthFunc);\n  },\n\n  /*\n   * computePositions\n   *\n   * Performs the main algorithm for computing node positions.\n   */\n  computePositions : function(property, getLength) {\n    var propArray = property;\n    var graph = this.graph;\n    var root = graph.getNode(this.root);\n    var parent = this.parent;\n    var config = this.config;\n\n    for ( var i=0, l=propArray.length; i < l; i++) {\n      var pi = propArray[i];\n      root.setPos($P(0, 0), pi);\n      root.setData('span', Math.PI * 2, pi);\n    }\n\n    root.angleSpan = {\n      begin : 0,\n      end : 2 * Math.PI\n    };\n\n    graph.eachBFS(this.root, function(elem) {\n      var angleSpan = elem.angleSpan.end - elem.angleSpan.begin;\n      var angleInit = elem.angleSpan.begin;\n      var len = getLength(elem);\n      //Calculate the sum of all angular widths\n      var totalAngularWidths = 0, subnodes = [], maxDim = {};\n      elem.eachSubnode(function(sib) {\n        totalAngularWidths += sib._treeAngularWidth;\n        //get max dim\n        for ( var i=0, l=propArray.length; i < l; i++) {\n          var pi = propArray[i], dim = sib.getData('dim', pi);\n          maxDim[pi] = (pi in maxDim)? (dim > maxDim[pi]? dim : maxDim[pi]) : dim;\n        }\n        subnodes.push(sib);\n      }, \"ignore\");\n      //Maintain children order\n      //Second constraint for <http://bailando.sims.berkeley.edu/papers/infovis01.htm>\n      if (parent && parent.id == elem.id && subnodes.length > 0\n          && subnodes[0].dist) {\n        subnodes.sort(function(a, b) {\n          return (a.dist >= b.dist) - (a.dist <= b.dist);\n        });\n      }\n      //Calculate nodes positions.\n      for (var k = 0, ls=subnodes.length; k < ls; k++) {\n        var child = subnodes[k];\n        if (!child._flag) {\n          var angleProportion = child._treeAngularWidth / totalAngularWidths * angleSpan;\n          var theta = angleInit + angleProportion / 2;\n\n          for ( var i=0, l=propArray.length; i < l; i++) {\n            var pi = propArray[i];\n            child.setPos($P(theta, len), pi);\n            child.setData('span', angleProportion, pi);\n            child.setData('dim-quotient', child.getData('dim', pi) / maxDim[pi], pi);\n          }\n\n          child.angleSpan = {\n            begin : angleInit,\n            end : angleInit + angleProportion\n          };\n          angleInit += angleProportion;\n        }\n      }\n    }, \"ignore\");\n  },\n\n  /*\n   * Method: setAngularWidthForNodes\n   *\n   * Sets nodes angular widths.\n   */\n  setAngularWidthForNodes : function(prop) {\n    this.graph.eachBFS(this.root, function(elem, i) {\n      var diamValue = elem.getData('angularWidth', prop[0]) || 5;\n      elem._angularWidth = diamValue / i;\n    }, \"ignore\");\n  },\n\n  /*\n   * Method: setSubtreesAngularWidth\n   *\n   * Sets subtrees angular widths.\n   */\n  setSubtreesAngularWidth : function() {\n    var that = this;\n    this.graph.eachNode(function(elem) {\n      that.setSubtreeAngularWidth(elem);\n    }, \"ignore\");\n  },\n\n  /*\n   * Method: setSubtreeAngularWidth\n   *\n   * Sets the angular width for a subtree.\n   */\n  setSubtreeAngularWidth : function(elem) {\n    var that = this, nodeAW = elem._angularWidth, sumAW = 0;\n    elem.eachSubnode(function(child) {\n      that.setSubtreeAngularWidth(child);\n      sumAW += child._treeAngularWidth;\n    }, \"ignore\");\n    elem._treeAngularWidth = Math.max(nodeAW, sumAW);\n  },\n\n  /*\n   * Method: computeAngularWidths\n   *\n   * Computes nodes and subtrees angular widths.\n   */\n  computeAngularWidths : function(prop) {\n    this.setAngularWidthForNodes(prop);\n    this.setSubtreesAngularWidth();\n  }\n\n});\n\n\n/*\n * File: Hypertree.js\n *\n*/\n\n/*\n     Complex\n\n     A multi-purpose Complex Class with common methods. Extended for the Hypertree.\n\n*/\n/*\n   moebiusTransformation\n\n   Calculates a moebius transformation for this point / complex.\n    For more information go to:\n        http://en.wikipedia.org/wiki/Moebius_transformation.\n\n   Parameters:\n\n      c - An initialized Complex instance representing a translation Vector.\n*/\n\nComplex.prototype.moebiusTransformation = function(c) {\n  var num = this.add(c);\n  var den = c.$conjugate().$prod(this);\n  den.x++;\n  return num.$div(den);\n};\n\n/*\n    moebiusTransformation\n\n    Calculates a moebius transformation for the hyperbolic tree.\n\n    <http://en.wikipedia.org/wiki/Moebius_transformation>\n\n     Parameters:\n\n        graph - A <Graph> instance.\n        pos - A <Complex>.\n        prop - A property array.\n        theta - Rotation angle.\n        startPos - _optional_ start position.\n*/\nGraph.Util.moebiusTransformation = function(graph, pos, prop, startPos, flags) {\n  this.eachNode(graph, function(elem) {\n    for ( var i = 0; i < prop.length; i++) {\n      var p = pos[i].scale(-1), property = startPos ? startPos : prop[i];\n      elem.getPos(prop[i]).set(elem.getPos(property).getc().moebiusTransformation(p));\n    }\n  }, flags);\n};\n\n/*\n   Class: Hypertree\n\n   A Hyperbolic Tree/Graph visualization.\n\n   Inspired by:\n\n   A Focus+Context Technique Based on Hyperbolic Geometry for Visualizing Large Hierarchies (John Lamping, Ramana Rao, and Peter Pirolli).\n   <http://www.cs.tau.ac.il/~asharf/shrek/Projects/HypBrowser/startree-chi95.pdf>\n\n  Note:\n\n  This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the Hypertree described in the paper.\n\n  Implements:\n\n  All <Loader> methods\n\n  Constructor Options:\n\n  Inherits options from\n\n  - <Options.Canvas>\n  - <Options.Controller>\n  - <Options.Node>\n  - <Options.Edge>\n  - <Options.Label>\n  - <Options.Events>\n  - <Options.Tips>\n  - <Options.NodeStyles>\n  - <Options.Navigation>\n\n  Additionally, there are other parameters and some default values changed\n\n  radius - (string|number) Default's *auto*. The radius of the disc to plot the <Hypertree> in. 'auto' will take the smaller value from the width and height canvas dimensions. You can also set this to a custom value, for example *250*.\n  offset - (number) Default's *0*. A number in the range [0, 1) that will be substracted to each node position to make a more compact <Hypertree>. This will avoid placing nodes too far from each other when a there's a selected node.\n  fps - Described in <Options.Fx>. It's default value has been changed to *35*.\n  duration - Described in <Options.Fx>. It's default value has been changed to *1500*.\n  Edge.type - Described in <Options.Edge>. It's default value has been changed to *hyperline*.\n\n  Instance Properties:\n\n  canvas - Access a <Canvas> instance.\n  graph - Access a <Graph> instance.\n  op - Access a <Hypertree.Op> instance.\n  fx - Access a <Hypertree.Plot> instance.\n  labels - Access a <Hypertree.Label> interface implementation.\n\n*/\n\n$jit.Hypertree = new Class( {\n\n  Implements: [ Loader, Extras, Layouts.Radial ],\n\n  initialize: function(controller) {\n    var $Hypertree = $jit.Hypertree;\n\n    var config = {\n      radius: \"auto\",\n      offset: 0,\n      Edge: {\n        type: 'hyperline'\n      },\n      duration: 1500,\n      fps: 35\n    };\n    this.controller = this.config = $.merge(Options(\"Canvas\", \"Node\", \"Edge\",\n        \"Fx\", \"Tips\", \"NodeStyles\", \"Events\", \"Navigation\", \"Controller\", \"Label\"), config, controller);\n\n    var canvasConfig = this.config;\n    if(canvasConfig.useCanvas) {\n      this.canvas = canvasConfig.useCanvas;\n      this.config.labelContainer = this.canvas.id + '-label';\n    } else {\n      if(canvasConfig.background) {\n        canvasConfig.background = $.merge({\n          type: 'Circles'\n        }, canvasConfig.background);\n      }\n      this.canvas = new Canvas(this, canvasConfig);\n      this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';\n    }\n\n    this.graphOptions = {\n      'complex': false,\n      'Node': {\n        'selected': false,\n        'exist': true,\n        'drawn': true\n      }\n    };\n    this.graph = new Graph(this.graphOptions, this.config.Node,\n        this.config.Edge);\n    this.labels = new $Hypertree.Label[canvasConfig.Label.type](this);\n    this.fx = new $Hypertree.Plot(this);\n    this.op = new $Hypertree.Op(this);\n    this.json = null;\n    this.root = null;\n    this.busy = false;\n    // initialize extras\n    this.initializeExtras();\n  },\n\n  /*\n\n  createLevelDistanceFunc\n\n  Returns the levelDistance function used for calculating a node distance\n  to its origin. This function returns a function that is computed\n  per level and not per node, such that all nodes with the same depth will have the\n  same distance to the origin. The resulting function gets the\n  parent node as parameter and returns a float.\n\n  */\n  createLevelDistanceFunc: function() {\n    // get max viz. length.\n    var r = this.getRadius();\n    // get max depth.\n    var depth = 0, max = Math.max, config = this.config;\n    this.graph.eachNode(function(node) {\n      depth = max(node._depth, depth);\n    }, \"ignore\");\n    depth++;\n    // node distance generator\n    var genDistFunc = function(a) {\n      return function(node) {\n        node.scale = r;\n        var d = node._depth + 1;\n        var acum = 0, pow = Math.pow;\n        while (d) {\n          acum += pow(a, d--);\n        }\n        return acum - config.offset;\n      };\n    };\n    // estimate better edge length.\n    for ( var i = 0.51; i <= 1; i += 0.01) {\n      var valSeries = (1 - Math.pow(i, depth)) / (1 - i);\n      if (valSeries >= 2) { return genDistFunc(i - 0.01); }\n    }\n    return genDistFunc(0.75);\n  },\n\n  /*\n    Method: getRadius\n\n    Returns the current radius of the visualization. If *config.radius* is *auto* then it\n    calculates the radius by taking the smaller size of the <Canvas> widget.\n\n    See also:\n\n    <Canvas.getSize>\n\n  */\n  getRadius: function() {\n    var rad = this.config.radius;\n    if (rad !== \"auto\") { return rad; }\n    var s = this.canvas.getSize();\n    return Math.min(s.width, s.height) / 2;\n  },\n\n  /*\n    Method: refresh\n\n    Computes positions and plots the tree.\n\n    Parameters:\n\n    reposition - (optional|boolean) Set this to *true* to force all positions (current, start, end) to match.\n\n   */\n  refresh: function(reposition) {\n    if (reposition) {\n      this.reposition();\n      this.graph.eachNode(function(node) {\n        node.startPos.rho = node.pos.rho = node.endPos.rho;\n        node.startPos.theta = node.pos.theta = node.endPos.theta;\n      });\n    } else {\n      this.compute();\n    }\n    this.plot();\n  },\n\n  /*\n   reposition\n\n   Computes nodes' positions and restores the tree to its previous position.\n\n   For calculating nodes' positions the root must be placed on its origin. This method does this\n     and then attemps to restore the hypertree to its previous position.\n\n  */\n  reposition: function() {\n    this.compute('end');\n    var vector = this.graph.getNode(this.root).pos.getc().scale(-1);\n    Graph.Util.moebiusTransformation(this.graph, [ vector ], [ 'end' ],\n        'end', \"ignore\");\n    this.graph.eachNode(function(node) {\n      if (node.ignore) {\n        node.endPos.rho = node.pos.rho;\n        node.endPos.theta = node.pos.theta;\n      }\n    });\n  },\n\n  /*\n   Method: plot\n\n   Plots the <Hypertree>. This is a shortcut to *fx.plot*.\n\n  */\n  plot: function() {\n    this.fx.plot();\n  },\n\n  /*\n   Method: onClick\n\n   Animates the <Hypertree> to center the node specified by *id*.\n\n   Parameters:\n\n   id - A <Graph.Node> id.\n   opt - (optional|object) An object containing some extra properties described below\n   hideLabels - (boolean) Default's *true*. Hide labels when performing the animation.\n\n   Example:\n\n   (start code js)\n     ht.onClick('someid');\n     //or also...\n     ht.onClick('someid', {\n      hideLabels: false\n     });\n    (end code)\n\n  */\n  onClick: function(id, opt) {\n    var pos = this.graph.getNode(id).pos.getc(true);\n    this.move(pos, opt);\n  },\n\n  /*\n   Method: move\n\n   Translates the tree to the given position.\n\n   Parameters:\n\n   pos - (object) A *x, y* coordinate object where x, y in [0, 1), to move the tree to.\n   opt - This object has been defined in <Hypertree.onClick>\n\n   Example:\n\n   (start code js)\n     ht.move({ x: 0, y: 0.7 }, {\n       hideLabels: false\n     });\n   (end code)\n\n  */\n  move: function(pos, opt) {\n    var versor = $C(pos.x, pos.y);\n    if (this.busy === false && versor.norm() < 1) {\n      this.busy = true;\n      var root = this.graph.getClosestNodeToPos(versor), that = this;\n      this.graph.computeLevels(root.id, 0);\n      this.controller.onBeforeCompute(root);\n      opt = $.merge( {\n        onComplete: $.empty\n      }, opt || {});\n      this.fx.animate($.merge( {\n        modes: [ 'moebius' ],\n        hideLabels: true\n      }, opt, {\n        onComplete: function() {\n          that.busy = false;\n          opt.onComplete();\n        }\n      }), versor);\n    }\n  }\n});\n\n$jit.Hypertree.$extend = true;\n\n(function(Hypertree) {\n\n  /*\n     Class: Hypertree.Op\n\n     Custom extension of <Graph.Op>.\n\n     Extends:\n\n     All <Graph.Op> methods\n\n     See also:\n\n     <Graph.Op>\n\n  */\n  Hypertree.Op = new Class( {\n\n    Implements: Graph.Op,\n\n    initialize: function(viz) {\n      this.viz = viz;\n    }\n  });\n\n  /*\n     Class: Hypertree.Plot\n\n    Custom extension of <Graph.Plot>.\n\n    Extends:\n\n    All <Graph.Plot> methods\n\n    See also:\n\n    <Graph.Plot>\n\n  */\n  Hypertree.Plot = new Class( {\n\n    Implements: Graph.Plot,\n\n    initialize: function(viz) {\n      this.viz = viz;\n      this.config = viz.config;\n      this.node = this.config.Node;\n      this.edge = this.config.Edge;\n      this.animation = new Animation;\n      this.nodeTypes = new Hypertree.Plot.NodeTypes;\n      this.edgeTypes = new Hypertree.Plot.EdgeTypes;\n      this.labels = viz.labels;\n    }\n  });\n\n  /*\n    Object: Hypertree.Label\n\n    Custom extension of <Graph.Label>.\n    Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.\n\n    Extends:\n\n    All <Graph.Label> methods and subclasses.\n\n    See also:\n\n    <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.\n\n   */\n  Hypertree.Label = {};\n\n  /*\n     Hypertree.Label.Native\n\n     Custom extension of <Graph.Label.Native>.\n\n     Extends:\n\n     All <Graph.Label.Native> methods\n\n     See also:\n\n     <Graph.Label.Native>\n\n  */\n  Hypertree.Label.Native = new Class( {\n    Implements: Graph.Label.Native,\n\n    initialize: function(viz) {\n      this.viz = viz;\n    },\n\n    renderLabel: function(canvas, node, controller) {\n      var ctx = canvas.getCtx();\n      var coord = node.pos.getc(true);\n      var s = this.viz.getRadius();\n      ctx.fillText(node.name, coord.x * s, coord.y * s);\n    }\n  });\n\n  /*\n     Hypertree.Label.SVG\n\n    Custom extension of <Graph.Label.SVG>.\n\n    Extends:\n\n    All <Graph.Label.SVG> methods\n\n    See also:\n\n    <Graph.Label.SVG>\n\n  */\n  Hypertree.Label.SVG = new Class( {\n    Implements: Graph.Label.SVG,\n\n    initialize: function(viz) {\n      this.viz = viz;\n    },\n\n    /*\n       placeLabel\n\n       Overrides abstract method placeLabel in <Graph.Plot>.\n\n       Parameters:\n\n       tag - A DOM label element.\n       node - A <Graph.Node>.\n       controller - A configuration/controller object passed to the visualization.\n\n     */\n    placeLabel: function(tag, node, controller) {\n      var pos = node.pos.getc(true),\n          canvas = this.viz.canvas,\n          ox = canvas.translateOffsetX,\n          oy = canvas.translateOffsetY,\n          sx = canvas.scaleOffsetX,\n          sy = canvas.scaleOffsetY,\n          radius = canvas.getSize(),\n          r = this.viz.getRadius();\n      var labelPos = {\n        x: Math.round((pos.x * sx) * r + ox + radius.width / 2),\n        y: Math.round((pos.y * sy) * r + oy + radius.height / 2)\n      };\n      tag.setAttribute('x', labelPos.x);\n      tag.setAttribute('y', labelPos.y);\n      controller.onPlaceLabel(tag, node);\n    }\n  });\n\n  /*\n     Hypertree.Label.HTML\n\n     Custom extension of <Graph.Label.HTML>.\n\n     Extends:\n\n     All <Graph.Label.HTML> methods.\n\n     See also:\n\n     <Graph.Label.HTML>\n\n  */\n  Hypertree.Label.HTML = new Class( {\n    Implements: Graph.Label.HTML,\n\n    initialize: function(viz) {\n      this.viz = viz;\n    },\n    /*\n       placeLabel\n\n       Overrides abstract method placeLabel in <Graph.Plot>.\n\n       Parameters:\n\n       tag - A DOM label element.\n       node - A <Graph.Node>.\n       controller - A configuration/controller object passed to the visualization.\n\n     */\n    placeLabel: function(tag, node, controller) {\n      var pos = node.pos.getc(true),\n          canvas = this.viz.canvas,\n          ox = canvas.translateOffsetX,\n          oy = canvas.translateOffsetY,\n          sx = canvas.scaleOffsetX,\n          sy = canvas.scaleOffsetY,\n          radius = canvas.getSize(),\n          r = this.viz.getRadius();\n      var labelPos = {\n        x: Math.round((pos.x * sx) * r + ox + radius.width / 2),\n        y: Math.round((pos.y * sy) * r + oy + radius.height / 2)\n      };\n      var style = tag.style;\n      style.left = labelPos.x + 'px';\n      style.top = labelPos.y + 'px';\n      style.display = this.fitsInCanvas(labelPos, canvas) ? '' : 'none';\n\n      controller.onPlaceLabel(tag, node);\n    }\n  });\n\n  /*\n    Class: Hypertree.Plot.NodeTypes\n\n    This class contains a list of <Graph.Node> built-in types.\n    Node types implemented are 'none', 'circle', 'triangle', 'rectangle', 'star', 'ellipse' and 'square'.\n\n    You can add your custom node types, customizing your visualization to the extreme.\n\n    Example:\n\n    (start code js)\n      Hypertree.Plot.NodeTypes.implement({\n        'mySpecialType': {\n          'render': function(node, canvas) {\n            //print your custom node to canvas\n          },\n          //optional\n          'contains': function(node, pos) {\n            //return true if pos is inside the node or false otherwise\n          }\n        }\n      });\n    (end code)\n\n  */\n  Hypertree.Plot.NodeTypes = new Class({\n    'none': {\n      'render': $.empty,\n      'contains': $.lambda(false)\n    },\n    'circle': {\n      'render': function(node, canvas) {\n        var nconfig = this.node,\n            dim = node.getData('dim'),\n            p = node.pos.getc();\n        dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim;\n        p.$scale(node.scale);\n        if (dim > 0.2) {\n          this.nodeHelper.circle.render('fill', p, dim, canvas);\n        }\n      },\n      'contains': function(node, pos) {\n        var dim = node.getData('dim'),\n            npos = node.pos.getc().$scale(node.scale);\n        return this.nodeHelper.circle.contains(npos, pos, dim);\n      }\n    },\n    'ellipse': {\n      'render': function(node, canvas) {\n        var pos = node.pos.getc().$scale(node.scale),\n            width = node.getData('width'),\n            height = node.getData('height');\n        this.nodeHelper.ellipse.render('fill', pos, width, height, canvas);\n      },\n      'contains': function(node, pos) {\n        var width = node.getData('width'),\n            height = node.getData('height'),\n            npos = node.pos.getc().$scale(node.scale);\n        return this.nodeHelper.circle.contains(npos, pos, width, height);\n      }\n    },\n    'square': {\n      'render': function(node, canvas) {\n        var nconfig = this.node,\n            dim = node.getData('dim'),\n            p = node.pos.getc();\n        dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim;\n        p.$scale(node.scale);\n        if (dim > 0.2) {\n          this.nodeHelper.square.render('fill', p, dim, canvas);\n        }\n      },\n      'contains': function(node, pos) {\n        var dim = node.getData('dim'),\n            npos = node.pos.getc().$scale(node.scale);\n        return this.nodeHelper.square.contains(npos, pos, dim);\n      }\n    },\n    'rectangle': {\n      'render': function(node, canvas) {\n        var nconfig = this.node,\n            width = node.getData('width'),\n            height = node.getData('height'),\n            pos = node.pos.getc();\n        width = nconfig.transform? width * (1 - pos.squaredNorm()) : width;\n        height = nconfig.transform? height * (1 - pos.squaredNorm()) : height;\n        pos.$scale(node.scale);\n        if (width > 0.2 && height > 0.2) {\n          this.nodeHelper.rectangle.render('fill', pos, width, height, canvas);\n        }\n      },\n      'contains': function(node, pos) {\n        var width = node.getData('width'),\n            height = node.getData('height'),\n            npos = node.pos.getc().$scale(node.scale);\n        return this.nodeHelper.square.contains(npos, pos, width, height);\n      }\n    },\n    'triangle': {\n      'render': function(node, canvas) {\n        var nconfig = this.node,\n            dim = node.getData('dim'),\n            p = node.pos.getc();\n        dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim;\n        p.$scale(node.scale);\n        if (dim > 0.2) {\n          this.nodeHelper.triangle.render('fill', p, dim, canvas);\n        }\n      },\n      'contains': function(node, pos) {\n        var dim = node.getData('dim'),\n            npos = node.pos.getc().$scale(node.scale);\n        return this.nodeHelper.triangle.contains(npos, pos, dim);\n      }\n    },\n    'star': {\n      'render': function(node, canvas) {\n        var nconfig = this.node,\n            dim = node.getData('dim'),\n            p = node.pos.getc();\n        dim = nconfig.transform? dim * (1 - p.squaredNorm()) : dim;\n        p.$scale(node.scale);\n        if (dim > 0.2) {\n          this.nodeHelper.star.render('fill', p, dim, canvas);\n        }\n      },\n      'contains': function(node, pos) {\n        var dim = node.getData('dim'),\n            npos = node.pos.getc().$scale(node.scale);\n        return this.nodeHelper.star.contains(npos, pos, dim);\n      }\n    }\n  });\n\n  /*\n   Class: Hypertree.Plot.EdgeTypes\n\n    This class contains a list of <Graph.Adjacence> built-in types.\n    Edge types implemented are 'none', 'line', 'arrow' and 'hyperline'.\n\n    You can add your custom edge types, customizing your visualization to the extreme.\n\n    Example:\n\n    (start code js)\n      Hypertree.Plot.EdgeTypes.implement({\n        'mySpecialType': function(adj, canvas) {\n          //print your custom edge to canvas\n        }\n      });\n    (end code)\n\n  */\n  Hypertree.Plot.EdgeTypes = new Class({\n    'none': $.empty,\n    'line': function(adj, canvas) {\n      var from = adj.nodeFrom.pos.getc(true),\n          to = adj.nodeTo.pos.getc(true),\n          r = adj.nodeFrom.scale;\n      this.edgeHelper.line({x:from.x*r, y:from.y*r}, {x:to.x*r, y:to.y*r}, canvas);\n    },\n    'arrow': function(adj, canvas) {\n      var from = adj.nodeFrom.pos.getc(true),\n          to = adj.nodeTo.pos.getc(true),\n          r = adj.nodeFrom.scale,\n          dim = adj.getData('dim'),\n          direction = adj.data.$direction,\n          inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id);\n      this.edgeHelper.arrow({x:from.x*r, y:from.y*r}, {x:to.x*r, y:to.y*r}, dim, inv, canvas);\n    },\n    'hyperline': function(adj, canvas) {\n      var from = adj.nodeFrom.pos.getc(),\n          to = adj.nodeTo.pos.getc(),\n          dim = this.viz.getRadius();\n      this.edgeHelper.hyperline(from, to, dim, canvas);\n    }\n  });\n\n})($jit.Hypertree);\n\n\n/*\n * Class: Layouts.TM\n *\n * Implements TreeMaps layouts (SliceAndDice, Squarified, Strip).\n *\n * Implemented By:\n *\n * <TM>\n *\n */\nLayouts.TM = {};\n\nLayouts.TM.SliceAndDice = new Class({\n  compute: function(prop) {\n    var root = this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root);\n    this.controller.onBeforeCompute(root);\n    var size = this.canvas.getSize(),\n        config = this.config,\n        width = size.width,\n        height = size.height;\n    this.graph.computeLevels(this.root, 0, \"ignore\");\n    //set root position and dimensions\n    root.getPos(prop).setc(-width/2, -height/2);\n    root.setData('width', width, prop);\n    root.setData('height', height + config.titleHeight, prop);\n    this.computePositions(root, root, this.layout.orientation, prop);\n    this.controller.onAfterCompute(root);\n  },\n\n  computePositions: function(par, ch, orn, prop) {\n    //compute children areas\n    var totalArea = 0;\n    par.eachSubnode(function(n) {\n      totalArea += n.getData('area', prop);\n    });\n\n    var config = this.config,\n        offst = config.offset,\n        width  = par.getData('width', prop),\n        height = par.getData('height', prop) - config.titleHeight,\n        fact = par == ch? 1: (ch.getData('area', prop) / totalArea);\n\n    var otherSize, size, dim, pos, pos2, posth, pos2th;\n    var horizontal = (orn == \"h\");\n    if(horizontal) {\n      orn = 'v';\n      otherSize = height;\n      size = width * fact;\n      dim = 'height';\n      pos = 'y';\n      pos2 = 'x';\n      posth = config.titleHeight;\n      pos2th = 0;\n    } else {\n      orn = 'h';\n      otherSize = height * fact;\n      size = width;\n      dim = 'width';\n      pos = 'x';\n      pos2 = 'y';\n      posth = 0;\n      pos2th = config.titleHeight;\n    }\n    var cpos = ch.getPos(prop);\n    ch.setData('width', size, prop);\n    ch.setData('height', otherSize, prop);\n    var offsetSize = 0, tm = this;\n    ch.eachSubnode(function(n) {\n      var p = n.getPos(prop);\n      p[pos] = offsetSize + cpos[pos] + posth;\n      p[pos2] = cpos[pos2] + pos2th;\n      tm.computePositions(ch, n, orn, prop);\n      offsetSize += n.getData(dim, prop);\n    });\n  }\n\n});\n\nLayouts.TM.Area = {\n /*\n    Method: compute\n\n   Called by loadJSON to calculate recursively all node positions and lay out the tree.\n\n    Parameters:\n\n       json - A JSON tree. See also <Loader.loadJSON>.\n       coord - A coordinates object specifying width, height, left and top style properties.\n */\n compute: function(prop) {\n    prop = prop || \"current\";\n    var root = this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root);\n    this.controller.onBeforeCompute(root);\n    var config = this.config,\n        size = this.canvas.getSize(),\n        width = size.width,\n        height = size.height,\n        offst = config.offset,\n        offwdth = width - offst,\n        offhght = height - offst;\n    this.graph.computeLevels(this.root, 0, \"ignore\");\n    //set root position and dimensions\n    root.getPos(prop).setc(-width/2, -height/2);\n    root.setData('width', width, prop);\n    root.setData('height', height, prop);\n    //create a coordinates object\n    var coord = {\n        'top': -height/2 + config.titleHeight,\n        'left': -width/2,\n        'width': offwdth,\n        'height': offhght - config.titleHeight\n    };\n    this.computePositions(root, coord, prop);\n    this.controller.onAfterCompute(root);\n },\n\n /*\n    Method: computeDim\n\n   Computes dimensions and positions of a group of nodes\n   according to a custom layout row condition.\n\n    Parameters:\n\n       tail - An array of nodes.\n       initElem - An array of nodes (containing the initial node to be laid).\n       w - A fixed dimension where nodes will be layed out.\n       coord - A coordinates object specifying width, height, left and top style properties.\n       comp - A custom comparison function\n */\n computeDim: function(tail, initElem, w, coord, comp, prop) {\n   if(tail.length + initElem.length == 1) {\n     var l = (tail.length == 1)? tail : initElem;\n     this.layoutLast(l, w, coord, prop);\n     return;\n   }\n   if(tail.length >= 2 && initElem.length == 0) {\n     initElem = [tail.shift()];\n   }\n   if(tail.length == 0) {\n     if(initElem.length > 0) this.layoutRow(initElem, w, coord, prop);\n     return;\n   }\n   var c = tail[0];\n   if(comp(initElem, w) >= comp([c].concat(initElem), w)) {\n     this.computeDim(tail.slice(1), initElem.concat([c]), w, coord, comp, prop);\n   } else {\n     var newCoords = this.layoutRow(initElem, w, coord, prop);\n     this.computeDim(tail, [], newCoords.dim, newCoords, comp, prop);\n   }\n },\n\n\n /*\n    Method: worstAspectRatio\n\n   Calculates the worst aspect ratio of a group of rectangles.\n\n    See also:\n\n       <http://en.wikipedia.org/wiki/Aspect_ratio>\n\n    Parameters:\n\n     ch - An array of nodes.\n     w  - The fixed dimension where rectangles are being laid out.\n\n    Returns:\n\n        The worst aspect ratio.\n\n\n */\n worstAspectRatio: function(ch, w) {\n   if(!ch || ch.length == 0) return Number.MAX_VALUE;\n   var areaSum = 0, maxArea = 0, minArea = Number.MAX_VALUE;\n   for(var i=0, l=ch.length; i<l; i++) {\n     var area = ch[i]._area;\n     areaSum += area;\n     minArea = minArea < area? minArea : area;\n     maxArea = maxArea > area? maxArea : area;\n   }\n   var sqw = w * w, sqAreaSum = areaSum * areaSum;\n   return Math.max(sqw * maxArea / sqAreaSum,\n           sqAreaSum / (sqw * minArea));\n },\n\n /*\n    Method: avgAspectRatio\n\n   Calculates the average aspect ratio of a group of rectangles.\n\n       See also:\n\n       <http://en.wikipedia.org/wiki/Aspect_ratio>\n\n    Parameters:\n\n     ch - An array of nodes.\n       w - The fixed dimension where rectangles are being laid out.\n\n    Returns:\n\n        The average aspect ratio.\n\n\n */\n avgAspectRatio: function(ch, w) {\n   if(!ch || ch.length == 0) return Number.MAX_VALUE;\n   var arSum = 0;\n   for(var i=0, l=ch.length; i<l; i++) {\n     var area = ch[i]._area;\n     var h = area / w;\n     arSum += w > h? w / h : h / w;\n   }\n   return arSum / l;\n },\n\n /*\n    layoutLast\n\n   Performs the layout of the last computed sibling.\n\n    Parameters:\n\n       ch - An array of nodes.\n       w - A fixed dimension where nodes will be layed out.\n     coord - A coordinates object specifying width, height, left and top style properties.\n */\n layoutLast: function(ch, w, coord, prop) {\n   var child = ch[0];\n   child.getPos(prop).setc(coord.left, coord.top);\n   child.setData('width', coord.width, prop);\n   child.setData('height', coord.height, prop);\n }\n};\n\n\nLayouts.TM.Squarified = new Class({\n Implements: Layouts.TM.Area,\n\n computePositions: function(node, coord, prop) {\n   var config = this.config;\n\n   if (!(coord.width >= coord.height\n       && this.layout.horizontal()))\n     this.layout.change();\n\n   var ch = node.getSubnodes([1, 1], \"ignore\");\n   if(ch.length > 0) {\n     this.processChildrenLayout(node, ch, coord, prop);\n     for(var i=0, l=ch.length; i<l; i++) {\n       var chi = ch[i];\n       var offst = config.offset,\n           height = chi.getData('height', prop) - offst - config.titleHeight,\n           width = chi.getData('width', prop) - offst;\n       var chipos = chi.getPos(prop);\n       coord = {\n         'width': width,\n         'height': height,\n         'top': chipos.y + config.titleHeight,\n         'left': chipos.x\n       };\n       this.computePositions(chi, coord, prop);\n     }\n   }\n },\n\n /*\n    Method: processChildrenLayout\n\n   Computes children real areas and other useful parameters for performing the Squarified algorithm.\n\n    Parameters:\n\n       par - The parent node of the json subtree.\n       ch - An Array of nodes\n     coord - A coordinates object specifying width, height, left and top style properties.\n */\n processChildrenLayout: function(par, ch, coord, prop) {\n   //compute children real areas\n   var parentArea = coord.width * coord.height;\n   var i, l=ch.length, totalChArea=0, chArea = [];\n   for(i=0; i<l; i++) {\n     chArea[i] = parseFloat(ch[i].getData('area', prop));\n     totalChArea += chArea[i];\n   }\n   for(i=0; i<l; i++) {\n     ch[i]._area = parentArea * chArea[i] / totalChArea;\n   }\n   var minimumSideValue = this.layout.horizontal()? coord.height : coord.width;\n   ch.sort(function(a, b) { return (a._area <= b._area) - (a._area >= b._area); });\n   var initElem = [ch[0]];\n   var tail = ch.slice(1);\n   this.squarify(tail, initElem, minimumSideValue, coord, prop);\n },\n\n /*\n   Method: squarify\n\n   Performs an heuristic method to calculate div elements sizes in order to have a good aspect ratio.\n\n    Parameters:\n\n       tail - An array of nodes.\n       initElem - An array of nodes, containing the initial node to be laid out.\n       w - A fixed dimension where nodes will be laid out.\n       coord - A coordinates object specifying width, height, left and top style properties.\n */\n squarify: function(tail, initElem, w, coord, prop) {\n   this.computeDim(tail, initElem, w, coord, this.worstAspectRatio, prop);\n },\n\n /*\n    Method: layoutRow\n\n   Performs the layout of an array of nodes.\n\n    Parameters:\n\n       ch - An array of nodes.\n       w - A fixed dimension where nodes will be laid out.\n       coord - A coordinates object specifying width, height, left and top style properties.\n */\n layoutRow: function(ch, w, coord, prop) {\n   if(this.layout.horizontal()) {\n     return this.layoutV(ch, w, coord, prop);\n   } else {\n     return this.layoutH(ch, w, coord, prop);\n   }\n },\n\n layoutV: function(ch, w, coord, prop) {\n   var totalArea = 0, rnd = function(x) { return x; };\n   $.each(ch, function(elem) { totalArea += elem._area; });\n   var width = rnd(totalArea / w), top =  0;\n   for(var i=0, l=ch.length; i<l; i++) {\n     var h = rnd(ch[i]._area / width);\n     var chi = ch[i];\n     chi.getPos(prop).setc(coord.left, coord.top + top);\n     chi.setData('width', width, prop);\n     chi.setData('height', h, prop);\n     top += h;\n   }\n   var ans = {\n     'height': coord.height,\n     'width': coord.width - width,\n     'top': coord.top,\n     'left': coord.left + width\n   };\n   //take minimum side value.\n   ans.dim = Math.min(ans.width, ans.height);\n   if(ans.dim != ans.height) this.layout.change();\n   return ans;\n },\n\n layoutH: function(ch, w, coord, prop) {\n   var totalArea = 0;\n   $.each(ch, function(elem) { totalArea += elem._area; });\n   var height = totalArea / w,\n       top = coord.top,\n       left = 0;\n\n   for(var i=0, l=ch.length; i<l; i++) {\n     var chi = ch[i];\n     var w = chi._area / height;\n     chi.getPos(prop).setc(coord.left + left, top);\n     chi.setData('width', w, prop);\n     chi.setData('height', height, prop);\n     left += w;\n   }\n   var ans = {\n     'height': coord.height - height,\n     'width': coord.width,\n     'top': coord.top + height,\n     'left': coord.left\n   };\n   ans.dim = Math.min(ans.width, ans.height);\n   if(ans.dim != ans.width) this.layout.change();\n   return ans;\n }\n});\n\nLayouts.TM.Strip = new Class({\n  Implements: Layouts.TM.Area,\n\n    /*\n      Method: compute\n\n     Called by loadJSON to calculate recursively all node positions and lay out the tree.\n\n      Parameters:\n\n         json - A JSON subtree. See also <Loader.loadJSON>.\n       coord - A coordinates object specifying width, height, left and top style properties.\n    */\n    computePositions: function(node, coord, prop) {\n     var ch = node.getSubnodes([1, 1], \"ignore\"), config = this.config;\n     if(ch.length > 0) {\n       this.processChildrenLayout(node, ch, coord, prop);\n       for(var i=0, l=ch.length; i<l; i++) {\n         var chi = ch[i];\n         var offst = config.offset,\n             height = chi.getData('height', prop) - offst - config.titleHeight,\n             width  = chi.getData('width', prop)  - offst;\n         var chipos = chi.getPos(prop);\n         coord = {\n           'width': width,\n           'height': height,\n           'top': chipos.y + config.titleHeight,\n           'left': chipos.x\n         };\n         this.computePositions(chi, coord, prop);\n       }\n     }\n    },\n\n    /*\n      Method: processChildrenLayout\n\n     Computes children real areas and other useful parameters for performing the Strip algorithm.\n\n      Parameters:\n\n         par - The parent node of the json subtree.\n         ch - An Array of nodes\n         coord - A coordinates object specifying width, height, left and top style properties.\n    */\n    processChildrenLayout: function(par, ch, coord, prop) {\n     //compute children real areas\n      var parentArea = coord.width * coord.height;\n      var i, l=ch.length, totalChArea=0, chArea = [];\n      for(i=0; i<l; i++) {\n        chArea[i] = +ch[i].getData('area', prop);\n        totalChArea += chArea[i];\n      }\n      for(i=0; i<l; i++) {\n        ch[i]._area = parentArea * chArea[i] / totalChArea;\n      }\n     var side = this.layout.horizontal()? coord.width : coord.height;\n     var initElem = [ch[0]];\n     var tail = ch.slice(1);\n     this.stripify(tail, initElem, side, coord, prop);\n    },\n\n    /*\n      Method: stripify\n\n     Performs an heuristic method to calculate div elements sizes in order to have\n     a good compromise between aspect ratio and order.\n\n      Parameters:\n\n         tail - An array of nodes.\n         initElem - An array of nodes.\n         w - A fixed dimension where nodes will be layed out.\n       coord - A coordinates object specifying width, height, left and top style properties.\n    */\n    stripify: function(tail, initElem, w, coord, prop) {\n     this.computeDim(tail, initElem, w, coord, this.avgAspectRatio, prop);\n    },\n\n    /*\n      Method: layoutRow\n\n     Performs the layout of an array of nodes.\n\n      Parameters:\n\n         ch - An array of nodes.\n         w - A fixed dimension where nodes will be laid out.\n         coord - A coordinates object specifying width, height, left and top style properties.\n    */\n    layoutRow: function(ch, w, coord, prop) {\n     if(this.layout.horizontal()) {\n       return this.layoutH(ch, w, coord, prop);\n     } else {\n       return this.layoutV(ch, w, coord, prop);\n     }\n    },\n\n    layoutV: function(ch, w, coord, prop) {\n     var totalArea = 0;\n     $.each(ch, function(elem) { totalArea += elem._area; });\n     var width = totalArea / w, top =  0;\n     for(var i=0, l=ch.length; i<l; i++) {\n       var chi = ch[i];\n       var h = chi._area / width;\n       chi.getPos(prop).setc(coord.left,\n           coord.top + (w - h - top));\n       chi.setData('width', width, prop);\n       chi.setData('height', h, prop);\n       top += h;\n     }\n\n     return {\n       'height': coord.height,\n       'width': coord.width - width,\n       'top': coord.top,\n       'left': coord.left + width,\n       'dim': w\n     };\n    },\n\n    layoutH: function(ch, w, coord, prop) {\n     var totalArea = 0;\n     $.each(ch, function(elem) { totalArea += elem._area; });\n     var height = totalArea / w,\n         top = coord.height - height,\n         left = 0;\n\n     for(var i=0, l=ch.length; i<l; i++) {\n       var chi = ch[i];\n       var s = chi._area / height;\n       chi.getPos(prop).setc(coord.left + left, coord.top + top);\n       chi.setData('width', s, prop);\n       chi.setData('height', height, prop);\n       left += s;\n     }\n     return {\n       'height': coord.height - height,\n       'width': coord.width,\n       'top': coord.top,\n       'left': coord.left,\n       'dim': w\n     };\n    }\n });\n\n/*\n * Class: Layouts.Icicle\n *\n * Implements the icicle tree layout.\n *\n * Implemented By:\n *\n * <Icicle>\n *\n */\n\nLayouts.Icicle = new Class({\n /*\n  * Method: compute\n  *\n  * Called by loadJSON to calculate all node positions.\n  *\n  * Parameters:\n  *\n  * posType - The nodes' position to compute. Either \"start\", \"end\" or\n  *            \"current\". Defaults to \"current\".\n  */\n  compute: function(posType) {\n    posType = posType || \"current\";\n\n    var root = this.graph.getNode(this.root),\n        config = this.config,\n        size = this.canvas.getSize(),\n        width = size.width,\n        height = size.height,\n        offset = config.offset,\n        levelsToShow = config.constrained ? config.levelsToShow : Number.MAX_VALUE;\n\n    this.controller.onBeforeCompute(root);\n\n    Graph.Util.computeLevels(this.graph, root.id, 0, \"ignore\");\n\n    var treeDepth = 0;\n\n    Graph.Util.eachLevel(root, 0, false, function (n, d) { if(d > treeDepth) treeDepth = d; });\n\n    var startNode = this.graph.getNode(this.clickedNode && this.clickedNode.id || root.id);\n    var maxDepth = Math.min(treeDepth, levelsToShow-1);\n    var initialDepth = startNode._depth;\n    if(this.layout.horizontal()) {\n      this.computeSubtree(startNode, -width/2, -height/2, width/(maxDepth+1), height, initialDepth, maxDepth, posType);\n    } else {\n      this.computeSubtree(startNode, -width/2, -height/2, width, height/(maxDepth+1), initialDepth, maxDepth, posType);\n    }\n  },\n\n  computeSubtree: function (root, x, y, width, height, initialDepth, maxDepth, posType) {\n    root.getPos(posType).setc(x, y);\n    root.setData('width', width, posType);\n    root.setData('height', height, posType);\n\n    var nodeLength, prevNodeLength = 0, totalDim = 0;\n    var children = Graph.Util.getSubnodes(root, [1, 1]); // next level from this node\n\n    if(!children.length)\n      return;\n\n    $.each(children, function(e) { totalDim += e.getData('dim'); });\n\n    for(var i=0, l=children.length; i < l; i++) {\n      if(this.layout.horizontal()) {\n        nodeLength = height * children[i].getData('dim') / totalDim;\n        this.computeSubtree(children[i], x+width, y, width, nodeLength, initialDepth, maxDepth, posType);\n        y += nodeLength;\n      } else {\n        nodeLength = width * children[i].getData('dim') / totalDim;\n        this.computeSubtree(children[i], x, y+height, nodeLength, height, initialDepth, maxDepth, posType);\n        x += nodeLength;\n      }\n    }\n  }\n});\n\n\n\n/*\n * File: Icicle.js\n *\n*/\n\n/*\n  Class: Icicle\n\n  Icicle space filling visualization.\n\n  Implements:\n\n  All <Loader> methods\n\n  Constructor Options:\n\n  Inherits options from\n\n  - <Options.Canvas>\n  - <Options.Controller>\n  - <Options.Node>\n  - <Options.Edge>\n  - <Options.Label>\n  - <Options.Events>\n  - <Options.Tips>\n  - <Options.NodeStyles>\n  - <Options.Navigation>\n\n  Additionally, there are other parameters and some default values changed\n\n  orientation - (string) Default's *h*. Whether to set horizontal or vertical layouts. Possible values are 'h' and 'v'.\n  offset - (number) Default's *2*. Boxes offset.\n  constrained - (boolean) Default's *false*. Whether to show the entire tree when loaded or just the number of levels specified by _levelsToShow_.\n  levelsToShow - (number) Default's *3*. The number of levels to show for a subtree. This number is relative to the selected node.\n  animate - (boolean) Default's *false*. Whether to animate transitions.\n  Node.type - Described in <Options.Node>. Default's *rectangle*.\n  Label.type - Described in <Options.Label>. Default's *Native*.\n  duration - Described in <Options.Fx>. Default's *700*.\n  fps - Described in <Options.Fx>. Default's *45*.\n\n  Instance Properties:\n\n  canvas - Access a <Canvas> instance.\n  graph - Access a <Graph> instance.\n  op - Access a <Icicle.Op> instance.\n  fx - Access a <Icicle.Plot> instance.\n  labels - Access a <Icicle.Label> interface implementation.\n\n*/\n\n$jit.Icicle = new Class({\n  Implements: [ Loader, Extras, Layouts.Icicle ],\n\n  layout: {\n    orientation: \"h\",\n    vertical: function(){\n      return this.orientation == \"v\";\n    },\n    horizontal: function(){\n      return this.orientation == \"h\";\n    },\n    change: function(){\n      this.orientation = this.vertical()? \"h\" : \"v\";\n    }\n  },\n\n  initialize: function(controller) {\n    var config = {\n      animate: false,\n      orientation: \"h\",\n      offset: 2,\n      levelsToShow: Number.MAX_VALUE,\n      constrained: false,\n      Node: {\n        type: 'rectangle',\n        overridable: true\n      },\n      Edge: {\n        type: 'none'\n      },\n      Label: {\n        type: 'Native'\n      },\n      duration: 700,\n      fps: 45\n    };\n\n    var opts = Options(\"Canvas\", \"Node\", \"Edge\", \"Fx\", \"Tips\", \"NodeStyles\",\n                       \"Events\", \"Navigation\", \"Controller\", \"Label\");\n    this.controller = this.config = $.merge(opts, config, controller);\n    this.layout.orientation = this.config.orientation;\n\n    var canvasConfig = this.config;\n    if (canvasConfig.useCanvas) {\n      this.canvas = canvasConfig.useCanvas;\n      this.config.labelContainer = this.canvas.id + '-label';\n    } else {\n      this.canvas = new Canvas(this, canvasConfig);\n      this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';\n    }\n\n    this.graphOptions = {\n      'complex': true,\n      'Node': {\n        'selected': false,\n        'exist': true,\n        'drawn': true\n      }\n    };\n\n    this.graph = new Graph(\n      this.graphOptions, this.config.Node, this.config.Edge, this.config.Label);\n\n    this.labels = new $jit.Icicle.Label[this.config.Label.type](this);\n    this.fx = new $jit.Icicle.Plot(this);\n    this.op = new $jit.Icicle.Op(this);\n    this.group = new $jit.Icicle.Group(this);\n    this.clickedNode = null;\n\n    this.initializeExtras();\n  },\n\n  /*\n    Method: refresh\n\n    Computes positions and plots the tree.\n  */\n  refresh: function(){\n    var labelType = this.config.Label.type;\n    if(labelType != 'Native') {\n      var that = this;\n      this.graph.eachNode(function(n) { that.labels.hideLabel(n, false); });\n    }\n    this.compute();\n    this.plot();\n  },\n\n  /*\n    Method: plot\n\n    Plots the Icicle visualization. This is a shortcut to *fx.plot*.\n\n   */\n  plot: function(){\n    this.fx.plot(this.config);\n  },\n\n  /*\n    Method: enter\n\n    Sets the node as root.\n\n     Parameters:\n\n     node - (object) A <Graph.Node>.\n\n   */\n  enter: function (node) {\n    if (this.busy)\n      return;\n    this.busy = true;\n\n    var that = this,\n        config = this.config;\n\n    var callback = {\n      onComplete: function() {\n        //compute positions of newly inserted nodes\n        if(config.request)\n          that.compute();\n\n        if(config.animate) {\n          that.graph.nodeList.setDataset(['current', 'end'], {\n            'alpha': [1, 0] //fade nodes\n          });\n\n          Graph.Util.eachSubgraph(node, function(n) {\n            n.setData('alpha', 1, 'end');\n          }, \"ignore\");\n\n          that.fx.animate({\n            duration: 500,\n            modes:['node-property:alpha'],\n            onComplete: function() {\n              that.clickedNode = node;\n              that.compute('end');\n\n              that.fx.animate({\n                modes:['linear', 'node-property:width:height'],\n                duration: 1000,\n                onComplete: function() {\n                  that.busy = false;\n                  that.clickedNode = node;\n                }\n              });\n            }\n          });\n        } else {\n          that.clickedNode = node;\n          that.busy = false;\n          that.refresh();\n        }\n      }\n    };\n\n    if(config.request) {\n      this.requestNodes(clickedNode, callback);\n    } else {\n      callback.onComplete();\n    }\n  },\n\n  /*\n    Method: out\n\n    Sets the parent node of the current selected node as root.\n\n   */\n  out: function(){\n    if(this.busy)\n      return;\n\n    var that = this,\n        GUtil = Graph.Util,\n        config = this.config,\n        graph = this.graph,\n        parents = GUtil.getParents(graph.getNode(this.clickedNode && this.clickedNode.id || this.root)),\n        parent = parents[0],\n        clickedNode = parent,\n        previousClickedNode = this.clickedNode;\n\n    this.busy = true;\n    this.events.hoveredNode = false;\n\n    if(!parent) {\n      this.busy = false;\n      return;\n    }\n\n    //final plot callback\n    callback = {\n      onComplete: function() {\n        that.clickedNode = parent;\n        if(config.request) {\n          that.requestNodes(parent, {\n            onComplete: function() {\n              that.compute();\n              that.plot();\n              that.busy = false;\n            }\n          });\n        } else {\n          that.compute();\n          that.plot();\n          that.busy = false;\n        }\n      }\n    };\n\n    //animate node positions\n    if(config.animate) {\n      this.clickedNode = clickedNode;\n      this.compute('end');\n      //animate the visible subtree only\n      this.clickedNode = previousClickedNode;\n      this.fx.animate({\n        modes:['linear', 'node-property:width:height'],\n        duration: 1000,\n        onComplete: function() {\n          //animate the parent subtree\n          that.clickedNode = clickedNode;\n          //change nodes alpha\n          graph.nodeList.setDataset(['current', 'end'], {\n            'alpha': [0, 1]\n          });\n          GUtil.eachSubgraph(previousClickedNode, function(node) {\n            node.setData('alpha', 1);\n          }, \"ignore\");\n          that.fx.animate({\n            duration: 500,\n            modes:['node-property:alpha'],\n            onComplete: function() {\n              callback.onComplete();\n            }\n          });\n        }\n      });\n    } else {\n      callback.onComplete();\n    }\n  },\n  requestNodes: function(node, onComplete){\n    var handler = $.merge(this.controller, onComplete),\n        levelsToShow = this.config.constrained ? this.config.levelsToShow : Number.MAX_VALUE;\n\n    if (handler.request) {\n      var leaves = [], d = node._depth;\n      Graph.Util.eachLevel(node, 0, levelsToShow, function(n){\n        if (n.drawn && !Graph.Util.anySubnode(n)) {\n          leaves.push(n);\n          n._level = n._depth - d;\n          if (this.config.constrained)\n            n._level = levelsToShow - n._level;\n\n        }\n      });\n      this.group.requestNodes(leaves, handler);\n    } else {\n      handler.onComplete();\n    }\n  }\n});\n\n/*\n  Class: Icicle.Op\n\n  Custom extension of <Graph.Op>.\n\n  Extends:\n\n  All <Graph.Op> methods\n\n  See also:\n\n  <Graph.Op>\n\n  */\n$jit.Icicle.Op = new Class({\n  Implements: Graph.Op,\n\n  initialize: function(viz) {\n    this.viz = viz;\n  }\n});\n\n/*\n * Performs operations on group of nodes.\n */\n$jit.Icicle.Group = new Class({\n\n  initialize: function(viz){\n    this.viz = viz;\n    this.canvas = viz.canvas;\n    this.config = viz.config;\n  },\n\n  /*\n   * Calls the request method on the controller to request a subtree for each node.\n   */\n  requestNodes: function(nodes, controller){\n    var counter = 0, len = nodes.length, nodeSelected = {};\n    var complete = function(){\n      controller.onComplete();\n    };\n    var viz = this.viz;\n    if (len == 0)\n      complete();\n    for(var i = 0; i < len; i++) {\n      nodeSelected[nodes[i].id] = nodes[i];\n      controller.request(nodes[i].id, nodes[i]._level, {\n        onComplete: function(nodeId, data){\n          if (data && data.children) {\n            data.id = nodeId;\n            viz.op.sum(data, {\n              type: 'nothing'\n            });\n          }\n          if (++counter == len) {\n            Graph.Util.computeLevels(viz.graph, viz.root, 0);\n            complete();\n          }\n        }\n      });\n    }\n  }\n});\n\n/*\n  Class: Icicle.Plot\n\n  Custom extension of <Graph.Plot>.\n\n  Extends:\n\n  All <Graph.Plot> methods\n\n  See also:\n\n  <Graph.Plot>\n\n  */\n$jit.Icicle.Plot = new Class({\n  Implements: Graph.Plot,\n\n  initialize: function(viz){\n    this.viz = viz;\n    this.config = viz.config;\n    this.node = this.config.Node;\n    this.edge = this.config.Edge;\n    this.animation = new Animation;\n    this.nodeTypes = new $jit.Icicle.Plot.NodeTypes;\n    this.edgeTypes = new $jit.Icicle.Plot.EdgeTypes;\n    this.labels = viz.labels;\n  },\n\n  plot: function(opt, animating){\n    opt = opt || this.viz.controller;\n    var viz = this.viz,\n        graph = viz.graph,\n        root = graph.getNode(viz.clickedNode && viz.clickedNode.id || viz.root),\n        initialDepth = root._depth;\n\n    viz.canvas.clear();\n    this.plotTree(root, $.merge(opt, {\n      'withLabels': true,\n      'hideLabels': false,\n      'plotSubtree': function(root, node) {\n        return !viz.config.constrained ||\n               (node._depth - initialDepth < viz.config.levelsToShow);\n      }\n    }), animating);\n  }\n});\n\n/*\n  Class: Icicle.Label\n\n  Custom extension of <Graph.Label>.\n  Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.\n\n  Extends:\n\n  All <Graph.Label> methods and subclasses.\n\n  See also:\n\n  <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.\n\n  */\n$jit.Icicle.Label = {};\n\n/*\n  Icicle.Label.Native\n\n  Custom extension of <Graph.Label.Native>.\n\n  Extends:\n\n  All <Graph.Label.Native> methods\n\n  See also:\n\n  <Graph.Label.Native>\n\n  */\n$jit.Icicle.Label.Native = new Class({\n  Implements: Graph.Label.Native,\n\n  renderLabel: function(canvas, node, controller) {\n    var ctx = canvas.getCtx(),\n        width = node.getData('width'),\n        height = node.getData('height'),\n        size = node.getLabelData('size'),\n        m = ctx.measureText(node.name);\n\n    // Guess as much as possible if the label will fit in the node\n    if(height < (size * 1.5) || width < m.width)\n      return;\n\n    var pos = node.pos.getc(true);\n    ctx.fillText(node.name,\n                 pos.x + width / 2,\n                 pos.y + height / 2);\n  }\n});\n\n/*\n  Icicle.Label.SVG\n\n  Custom extension of <Graph.Label.SVG>.\n\n  Extends:\n\n  All <Graph.Label.SVG> methods\n\n  See also:\n\n  <Graph.Label.SVG>\n*/\n$jit.Icicle.Label.SVG = new Class( {\n  Implements: Graph.Label.SVG,\n\n  initialize: function(viz){\n    this.viz = viz;\n  },\n\n  /*\n    placeLabel\n\n    Overrides abstract method placeLabel in <Graph.Plot>.\n\n    Parameters:\n\n    tag - A DOM label element.\n    node - A <Graph.Node>.\n    controller - A configuration/controller object passed to the visualization.\n   */\n  placeLabel: function(tag, node, controller){\n    var pos = node.pos.getc(true), canvas = this.viz.canvas;\n    var radius = canvas.getSize();\n    var labelPos = {\n      x: Math.round(pos.x + radius.width / 2),\n      y: Math.round(pos.y + radius.height / 2)\n    };\n    tag.setAttribute('x', labelPos.x);\n    tag.setAttribute('y', labelPos.y);\n\n    controller.onPlaceLabel(tag, node);\n  }\n});\n\n/*\n  Icicle.Label.HTML\n\n  Custom extension of <Graph.Label.HTML>.\n\n  Extends:\n\n  All <Graph.Label.HTML> methods.\n\n  See also:\n\n  <Graph.Label.HTML>\n\n  */\n$jit.Icicle.Label.HTML = new Class( {\n  Implements: Graph.Label.HTML,\n\n  initialize: function(viz){\n    this.viz = viz;\n  },\n\n  /*\n    placeLabel\n\n    Overrides abstract method placeLabel in <Graph.Plot>.\n\n    Parameters:\n\n    tag - A DOM label element.\n    node - A <Graph.Node>.\n    controller - A configuration/controller object passed to the visualization.\n   */\n  placeLabel: function(tag, node, controller){\n    var pos = node.pos.getc(true), canvas = this.viz.canvas;\n    var radius = canvas.getSize();\n    var labelPos = {\n      x: Math.round(pos.x + radius.width / 2),\n      y: Math.round(pos.y + radius.height / 2)\n    };\n\n    var style = tag.style;\n    style.left = labelPos.x + 'px';\n    style.top = labelPos.y + 'px';\n    style.display = '';\n\n    controller.onPlaceLabel(tag, node);\n  }\n});\n\n/*\n  Class: Icicle.Plot.NodeTypes\n\n  This class contains a list of <Graph.Node> built-in types.\n  Node types implemented are 'none', 'rectangle'.\n\n  You can add your custom node types, customizing your visualization to the extreme.\n\n  Example:\n\n  (start code js)\n    Icicle.Plot.NodeTypes.implement({\n      'mySpecialType': {\n        'render': function(node, canvas) {\n          //print your custom node to canvas\n        },\n        //optional\n        'contains': function(node, pos) {\n          //return true if pos is inside the node or false otherwise\n        }\n      }\n    });\n  (end code)\n\n  */\n$jit.Icicle.Plot.NodeTypes = new Class( {\n  'none': {\n    'render': $.empty\n  },\n\n  'rectangle': {\n    'render': function(node, canvas, animating) {\n      var config = this.viz.config;\n      var offset = config.offset;\n      var width = node.getData('width');\n      var height = node.getData('height');\n      var border = node.getData('border');\n      var pos = node.pos.getc(true);\n      var posx = pos.x + offset / 2, posy = pos.y + offset / 2;\n      var ctx = canvas.getCtx();\n\n      if(width - offset < 2 || height - offset < 2) return;\n\n      if(config.cushion) {\n        var color = node.getData('color');\n        var lg = ctx.createRadialGradient(posx + (width - offset)/2,\n                                          posy + (height - offset)/2, 1,\n                                          posx + (width-offset)/2, posy + (height-offset)/2,\n                                          width < height? height : width);\n        var colorGrad = $.rgbToHex($.map($.hexToRgb(color),\n            function(r) { return r * 0.3 >> 0; }));\n        lg.addColorStop(0, color);\n        lg.addColorStop(1, colorGrad);\n        ctx.fillStyle = lg;\n      }\n\n      if (border) {\n        ctx.strokeStyle = border;\n        ctx.lineWidth = 3;\n      }\n\n      ctx.fillRect(posx, posy, Math.max(0, width - offset), Math.max(0, height - offset));\n      border && ctx.strokeRect(pos.x, pos.y, width, height);\n    },\n\n    'contains': function(node, pos) {\n      if(this.viz.clickedNode && !$jit.Graph.Util.isDescendantOf(node, this.viz.clickedNode.id)) return false;\n      var npos = node.pos.getc(true),\n          width = node.getData('width'),\n          height = node.getData('height');\n      return this.nodeHelper.rectangle.contains({x: npos.x + width/2, y: npos.y + height/2}, pos, width, height);\n    }\n  }\n});\n\n$jit.Icicle.Plot.EdgeTypes = new Class( {\n  'none': $.empty\n});\n\n\n\n/*\n * File: RGraph.js\n *\n */\n\n/*\n   Class: RGraph\n\n   A radial graph visualization with advanced animations.\n\n   Inspired by:\n\n   Animated Exploration of Dynamic Graphs with Radial Layout (Ka-Ping Yee, Danyel Fisher, Rachna Dhamija, Marti Hearst) <http://bailando.sims.berkeley.edu/papers/infovis01.htm>\n\n   Note:\n\n   This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the visualization described in the paper.\n\n  Implements:\n\n  All <Loader> methods\n\n   Constructor Options:\n\n   Inherits options from\n\n   - <Options.Canvas>\n   - <Options.Controller>\n   - <Options.Node>\n   - <Options.Edge>\n   - <Options.Label>\n   - <Options.Events>\n   - <Options.Tips>\n   - <Options.NodeStyles>\n   - <Options.Navigation>\n\n   Additionally, there are other parameters and some default values changed\n\n   interpolation - (string) Default's *linear*. Describes the way nodes are interpolated. Possible values are 'linear' and 'polar'.\n   levelDistance - (number) Default's *100*. The distance between levels of the tree.\n\n   Instance Properties:\n\n   canvas - Access a <Canvas> instance.\n   graph - Access a <Graph> instance.\n   op - Access a <RGraph.Op> instance.\n   fx - Access a <RGraph.Plot> instance.\n   labels - Access a <RGraph.Label> interface implementation.\n*/\n\n$jit.RGraph = new Class( {\n\n  Implements: [\n      Loader, Extras, Layouts.Radial\n  ],\n\n  initialize: function(controller){\n    var $RGraph = $jit.RGraph;\n\n    var config = {\n      interpolation: 'linear',\n      levelDistance: 100\n    };\n\n    this.controller = this.config = $.merge(Options(\"Canvas\", \"Node\", \"Edge\",\n        \"Fx\", \"Controller\", \"Tips\", \"NodeStyles\", \"Events\", \"Navigation\", \"Label\"), config, controller);\n\n    var canvasConfig = this.config;\n    if(canvasConfig.useCanvas) {\n      this.canvas = canvasConfig.useCanvas;\n      this.config.labelContainer = this.canvas.id + '-label';\n    } else {\n      if(canvasConfig.background) {\n        canvasConfig.background = $.merge({\n          type: 'Circles'\n        }, canvasConfig.background);\n      }\n      this.canvas = new Canvas(this, canvasConfig);\n      this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';\n    }\n\n    this.graphOptions = {\n      'complex': false,\n      'Node': {\n        'selected': false,\n        'exist': true,\n        'drawn': true\n      }\n    };\n    this.graph = new Graph(this.graphOptions, this.config.Node,\n        this.config.Edge);\n    this.labels = new $RGraph.Label[canvasConfig.Label.type](this);\n    this.fx = new $RGraph.Plot(this);\n    this.op = new $RGraph.Op(this);\n    this.json = null;\n    this.root = null;\n    this.busy = false;\n    this.parent = false;\n    // initialize extras\n    this.initializeExtras();\n  },\n\n  /*\n\n    createLevelDistanceFunc\n\n    Returns the levelDistance function used for calculating a node distance\n    to its origin. This function returns a function that is computed\n    per level and not per node, such that all nodes with the same depth will have the\n    same distance to the origin. The resulting function gets the\n    parent node as parameter and returns a float.\n\n   */\n  createLevelDistanceFunc: function(){\n    var ld = this.config.levelDistance;\n    return function(elem){\n      return (elem._depth + 1) * ld;\n    };\n  },\n\n  /*\n     Method: refresh\n\n     Computes positions and plots the tree.\n\n   */\n  refresh: function(){\n    this.compute();\n    this.plot();\n  },\n\n  reposition: function(){\n    this.compute('end');\n  },\n\n  /*\n   Method: plot\n\n   Plots the RGraph. This is a shortcut to *fx.plot*.\n  */\n  plot: function(){\n    this.fx.plot();\n  },\n  /*\n   getNodeAndParentAngle\n\n   Returns the _parent_ of the given node, also calculating its angle span.\n  */\n  getNodeAndParentAngle: function(id){\n    var theta = false;\n    var n = this.graph.getNode(id);\n    var ps = n.getParents();\n    var p = (ps.length > 0)? ps[0] : false;\n    if (p) {\n      var posParent = p.pos.getc(), posChild = n.pos.getc();\n      var newPos = posParent.add(posChild.scale(-1));\n      theta = Math.atan2(newPos.y, newPos.x);\n      if (theta < 0)\n        theta += 2 * Math.PI;\n    }\n    return {\n      parent: p,\n      theta: theta\n    };\n  },\n  /*\n   tagChildren\n\n   Enumerates the children in order to maintain child ordering (second constraint of the paper).\n  */\n  tagChildren: function(par, id){\n    if (par.angleSpan) {\n      var adjs = [];\n      par.eachAdjacency(function(elem){\n        adjs.push(elem.nodeTo);\n      }, \"ignore\");\n      var len = adjs.length;\n      for ( var i = 0; i < len && id != adjs[i].id; i++)\n        ;\n      for ( var j = (i + 1) % len, k = 0; id != adjs[j].id; j = (j + 1) % len) {\n        adjs[j].dist = k++;\n      }\n    }\n  },\n  /*\n  Method: onClick\n\n  Animates the <RGraph> to center the node specified by *id*.\n\n   Parameters:\n\n   id - A <Graph.Node> id.\n   opt - (optional|object) An object containing some extra properties described below\n   hideLabels - (boolean) Default's *true*. Hide labels when performing the animation.\n\n   Example:\n\n   (start code js)\n     rgraph.onClick('someid');\n     //or also...\n     rgraph.onClick('someid', {\n      hideLabels: false\n     });\n    (end code)\n\n  */\n  onClick: function(id, opt){\n    if (this.root != id && !this.busy) {\n      this.busy = true;\n      this.root = id;\n      that = this;\n      this.controller.onBeforeCompute(this.graph.getNode(id));\n      var obj = this.getNodeAndParentAngle(id);\n\n      // second constraint\n      this.tagChildren(obj.parent, id);\n      this.parent = obj.parent;\n      this.compute('end');\n\n      // first constraint\n      var thetaDiff = obj.theta - obj.parent.endPos.theta;\n      this.graph.eachNode(function(elem){\n        elem.endPos.set(elem.endPos.getp().add($P(thetaDiff, 0)));\n      });\n\n      var mode = this.config.interpolation;\n      opt = $.merge( {\n        onComplete: $.empty\n      }, opt || {});\n\n      this.fx.animate($.merge( {\n        hideLabels: true,\n        modes: [\n          mode\n        ]\n      }, opt, {\n        onComplete: function(){\n          that.busy = false;\n          opt.onComplete();\n        }\n      }));\n    }\n  }\n});\n\n$jit.RGraph.$extend = true;\n\n(function(RGraph){\n\n  /*\n     Class: RGraph.Op\n\n     Custom extension of <Graph.Op>.\n\n     Extends:\n\n     All <Graph.Op> methods\n\n     See also:\n\n     <Graph.Op>\n\n  */\n  RGraph.Op = new Class( {\n\n    Implements: Graph.Op,\n\n    initialize: function(viz){\n      this.viz = viz;\n    }\n  });\n\n  /*\n     Class: RGraph.Plot\n\n    Custom extension of <Graph.Plot>.\n\n    Extends:\n\n    All <Graph.Plot> methods\n\n    See also:\n\n    <Graph.Plot>\n\n  */\n  RGraph.Plot = new Class( {\n\n    Implements: Graph.Plot,\n\n    initialize: function(viz){\n      this.viz = viz;\n      this.config = viz.config;\n      this.node = viz.config.Node;\n      this.edge = viz.config.Edge;\n      this.animation = new Animation;\n      this.nodeTypes = new RGraph.Plot.NodeTypes;\n      this.edgeTypes = new RGraph.Plot.EdgeTypes;\n      this.labels = viz.labels;\n    }\n  });\n\n  /*\n    Object: RGraph.Label\n\n    Custom extension of <Graph.Label>.\n    Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.\n\n    Extends:\n\n    All <Graph.Label> methods and subclasses.\n\n    See also:\n\n    <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.\n\n   */\n  RGraph.Label = {};\n\n  /*\n     RGraph.Label.Native\n\n     Custom extension of <Graph.Label.Native>.\n\n     Extends:\n\n     All <Graph.Label.Native> methods\n\n     See also:\n\n     <Graph.Label.Native>\n\n  */\n  RGraph.Label.Native = new Class( {\n    Implements: Graph.Label.Native\n  });\n\n  /*\n     RGraph.Label.SVG\n\n    Custom extension of <Graph.Label.SVG>.\n\n    Extends:\n\n    All <Graph.Label.SVG> methods\n\n    See also:\n\n    <Graph.Label.SVG>\n\n  */\n  RGraph.Label.SVG = new Class( {\n    Implements: Graph.Label.SVG,\n\n    initialize: function(viz){\n      this.viz = viz;\n    },\n\n    /*\n       placeLabel\n\n       Overrides abstract method placeLabel in <Graph.Plot>.\n\n       Parameters:\n\n       tag - A DOM label element.\n       node - A <Graph.Node>.\n       controller - A configuration/controller object passed to the visualization.\n\n     */\n    placeLabel: function(tag, node, controller){\n      var pos = node.pos.getc(true),\n          canvas = this.viz.canvas,\n          ox = canvas.translateOffsetX,\n          oy = canvas.translateOffsetY,\n          sx = canvas.scaleOffsetX,\n          sy = canvas.scaleOffsetY,\n          radius = canvas.getSize();\n      var labelPos = {\n        x: Math.round(pos.x * sx + ox + radius.width / 2),\n        y: Math.round(pos.y * sy + oy + radius.height / 2)\n      };\n      tag.setAttribute('x', labelPos.x);\n      tag.setAttribute('y', labelPos.y);\n\n      controller.onPlaceLabel(tag, node);\n    }\n  });\n\n  /*\n     RGraph.Label.HTML\n\n     Custom extension of <Graph.Label.HTML>.\n\n     Extends:\n\n     All <Graph.Label.HTML> methods.\n\n     See also:\n\n     <Graph.Label.HTML>\n\n  */\n  RGraph.Label.HTML = new Class( {\n    Implements: Graph.Label.HTML,\n\n    initialize: function(viz){\n      this.viz = viz;\n    },\n    /*\n       placeLabel\n\n       Overrides abstract method placeLabel in <Graph.Plot>.\n\n       Parameters:\n\n       tag - A DOM label element.\n       node - A <Graph.Node>.\n       controller - A configuration/controller object passed to the visualization.\n\n     */\n    placeLabel: function(tag, node, controller){\n      var pos = node.pos.getc(true),\n          canvas = this.viz.canvas,\n          ox = canvas.translateOffsetX,\n          oy = canvas.translateOffsetY,\n          sx = canvas.scaleOffsetX,\n          sy = canvas.scaleOffsetY,\n          radius = canvas.getSize();\n      var labelPos = {\n        x: Math.round(pos.x * sx + ox + radius.width / 2),\n        y: Math.round(pos.y * sy + oy + radius.height / 2)\n      };\n\n      var style = tag.style;\n      style.left = labelPos.x + 'px';\n      style.top = labelPos.y + 'px';\n      style.display = this.fitsInCanvas(labelPos, canvas)? '' : 'none';\n\n      controller.onPlaceLabel(tag, node);\n    }\n  });\n\n  /*\n    Class: RGraph.Plot.NodeTypes\n\n    This class contains a list of <Graph.Node> built-in types.\n    Node types implemented are 'none', 'circle', 'triangle', 'rectangle', 'star', 'ellipse' and 'square'.\n\n    You can add your custom node types, customizing your visualization to the extreme.\n\n    Example:\n\n    (start code js)\n      RGraph.Plot.NodeTypes.implement({\n        'mySpecialType': {\n          'render': function(node, canvas) {\n            //print your custom node to canvas\n          },\n          //optional\n          'contains': function(node, pos) {\n            //return true if pos is inside the node or false otherwise\n          }\n        }\n      });\n    (end code)\n\n  */\n  RGraph.Plot.NodeTypes = new Class({\n    'none': {\n      'render': $.empty,\n      'contains': $.lambda(false)\n    },\n    'circle': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            dim = node.getData('dim');\n        this.nodeHelper.circle.render('fill', pos, dim, canvas);\n      },\n      'contains': function(node, pos){\n        var npos = node.pos.getc(true),\n            dim = node.getData('dim');\n        return this.nodeHelper.circle.contains(npos, pos, dim);\n      }\n    },\n    'ellipse': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            width = node.getData('width'),\n            height = node.getData('height');\n        this.nodeHelper.ellipse.render('fill', pos, width, height, canvas);\n        },\n      // TODO(nico): be more precise...\n      'contains': function(node, pos){\n        var npos = node.pos.getc(true),\n            width = node.getData('width'),\n            height = node.getData('height');\n        return this.nodeHelper.ellipse.contains(npos, pos, width, height);\n      }\n    },\n    'square': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            dim = node.getData('dim');\n        this.nodeHelper.square.render('fill', pos, dim, canvas);\n      },\n      'contains': function(node, pos){\n        var npos = node.pos.getc(true),\n            dim = node.getData('dim');\n        return this.nodeHelper.square.contains(npos, pos, dim);\n      }\n    },\n    'rectangle': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            width = node.getData('width'),\n            height = node.getData('height');\n        this.nodeHelper.rectangle.render('fill', pos, width, height, canvas);\n      },\n      'contains': function(node, pos){\n        var npos = node.pos.getc(true),\n            width = node.getData('width'),\n            height = node.getData('height');\n        return this.nodeHelper.rectangle.contains(npos, pos, width, height);\n      }\n    },\n    'triangle': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            dim = node.getData('dim');\n        this.nodeHelper.triangle.render('fill', pos, dim, canvas);\n      },\n      'contains': function(node, pos) {\n        var npos = node.pos.getc(true),\n            dim = node.getData('dim');\n        return this.nodeHelper.triangle.contains(npos, pos, dim);\n      }\n    },\n    'star': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            dim = node.getData('dim');\n        this.nodeHelper.star.render('fill', pos, dim, canvas);\n      },\n      'contains': function(node, pos) {\n        var npos = node.pos.getc(true),\n            dim = node.getData('dim');\n        return this.nodeHelper.star.contains(npos, pos, dim);\n      }\n    }\n  });\n\n  /*\n    Class: RGraph.Plot.EdgeTypes\n\n    This class contains a list of <Graph.Adjacence> built-in types.\n    Edge types implemented are 'none', 'line' and 'arrow'.\n\n    You can add your custom edge types, customizing your visualization to the extreme.\n\n    Example:\n\n    (start code js)\n      RGraph.Plot.EdgeTypes.implement({\n        'mySpecialType': function(adj, canvas) {\n          //print your custom edge to canvas\n        }\n      });\n    (end code)\n\n  */\n  RGraph.Plot.EdgeTypes = new Class({\n    'none': $.empty,\n    'line': function(adj, canvas) {\n      var from = adj.nodeFrom.pos.getc(true),\n          to = adj.nodeTo.pos.getc(true);\n      this.edgeHelper.line(from, to, canvas);\n    },\n    'arrow': function(adj, canvas) {\n      var from = adj.nodeFrom.pos.getc(true),\n          to = adj.nodeTo.pos.getc(true),\n          dim = adj.getData('dim'),\n          direction = adj.data.$direction,\n          inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id);\n      this.edgeHelper.arrow(from, to, dim, inv, canvas);\n    }\n  });\n\n})($jit.RGraph);\n\n\n/*\n * File: Layouts.ForceDirected.js\n *\n*/\n\n/*\n * Class: Layouts.ForceDirected\n *\n * Implements a Force Directed Layout.\n *\n * Implemented By:\n *\n * <ForceDirected>\n *\n * Credits:\n *\n * Marcus Cobden <http://marcuscobden.co.uk>\n *\n */\nLayouts.ForceDirected = new Class({\n\n  getOptions: function(random) {\n    var s = this.canvas.getSize();\n    var w = s.width, h = s.height;\n    //count nodes\n    var count = 0;\n    this.graph.eachNode(function(n) {\n      count++;\n    });\n    var k2 = w * h / count, k = Math.sqrt(k2);\n    var l = this.config.levelDistance;\n\n    return {\n      width: w,\n      height: h,\n      tstart: w * 0.1,\n      nodef: function(x) { return k2 / (x || 1); },\n      edgef: function(x) { return /* x * x / k; */ k * (x - l); }\n    };\n  },\n\n  compute: function(property, incremental) {\n    var prop = $.splat(property || ['current', 'start', 'end']);\n    var opt = this.getOptions();\n    NodeDim.compute(this.graph, prop, this.config);\n    this.graph.computeLevels(this.root, 0, \"ignore\");\n    this.graph.eachNode(function(n) {\n      $.each(prop, function(p) {\n        var pos = n.getPos(p);\n        if(pos.equals(Complex.KER)) {\n          pos.x = opt.width/5 * (Math.random() - 0.5);\n          pos.y = opt.height/5 * (Math.random() - 0.5);\n        }\n        //initialize disp vector\n        n.disp = {};\n        $.each(prop, function(p) {\n          n.disp[p] = $C(0, 0);\n        });\n      });\n    });\n    this.computePositions(prop, opt, incremental);\n  },\n\n  computePositions: function(property, opt, incremental) {\n    var times = this.config.iterations, i = 0, that = this;\n    if(incremental) {\n      (function iter() {\n        for(var total=incremental.iter, j=0; j<total; j++) {\n          opt.t = opt.tstart * (1 - i++/(times -1));\n          that.computePositionStep(property, opt);\n          if(i >= times) {\n            incremental.onComplete();\n            return;\n          }\n        }\n        incremental.onStep(Math.round(i / (times -1) * 100));\n        setTimeout(iter, 1);\n      })();\n    } else {\n      for(; i < times; i++) {\n        opt.t = opt.tstart * (1 - i/(times -1));\n        this.computePositionStep(property, opt);\n      }\n    }\n  },\n\n  computePositionStep: function(property, opt) {\n    var graph = this.graph;\n    var min = Math.min, max = Math.max;\n    var dpos = $C(0, 0);\n    //calculate repulsive forces\n    graph.eachNode(function(v) {\n      //initialize disp\n      $.each(property, function(p) {\n        v.disp[p].x = 0; v.disp[p].y = 0;\n      });\n      graph.eachNode(function(u) {\n        if(u.id != v.id) {\n          $.each(property, function(p) {\n            var vp = v.getPos(p), up = u.getPos(p);\n            dpos.x = vp.x - up.x;\n            dpos.y = vp.y - up.y;\n            var norm = dpos.norm() || 1;\n            v.disp[p].$add(dpos\n                .$scale(opt.nodef(norm) / norm));\n          });\n        }\n      });\n    });\n    //calculate attractive forces\n    var T = !!graph.getNode(this.root).visited;\n    graph.eachNode(function(node) {\n      node.eachAdjacency(function(adj) {\n        var nodeTo = adj.nodeTo;\n        if(!!nodeTo.visited === T) {\n          $.each(property, function(p) {\n            var vp = node.getPos(p), up = nodeTo.getPos(p);\n            dpos.x = vp.x - up.x;\n            dpos.y = vp.y - up.y;\n            var norm = dpos.norm() || 1;\n            node.disp[p].$add(dpos.$scale(-opt.edgef(norm) / norm));\n            nodeTo.disp[p].$add(dpos.$scale(-1));\n          });\n        }\n      });\n      node.visited = !T;\n    });\n    //arrange positions to fit the canvas\n    var t = opt.t, w2 = opt.width / 2, h2 = opt.height / 2;\n    graph.eachNode(function(u) {\n      $.each(property, function(p) {\n        var disp = u.disp[p];\n        var norm = disp.norm() || 1;\n        var p = u.getPos(p);\n        p.$add($C(disp.x * min(Math.abs(disp.x), t) / norm,\n            disp.y * min(Math.abs(disp.y), t) / norm));\n        p.x = min(w2, max(-w2, p.x));\n        p.y = min(h2, max(-h2, p.y));\n      });\n    });\n  }\n});\n\n/*\n * File: ForceDirected.js\n */\n\n/*\n   Class: ForceDirected\n\n   A visualization that lays graphs using a Force-Directed layout algorithm.\n\n   Inspired by:\n\n   Force-Directed Drawing Algorithms (Stephen G. Kobourov) <http://www.cs.brown.edu/~rt/gdhandbook/chapters/force-directed.pdf>\n\n  Implements:\n\n  All <Loader> methods\n\n   Constructor Options:\n\n   Inherits options from\n\n   - <Options.Canvas>\n   - <Options.Controller>\n   - <Options.Node>\n   - <Options.Edge>\n   - <Options.Label>\n   - <Options.Events>\n   - <Options.Tips>\n   - <Options.NodeStyles>\n   - <Options.Navigation>\n\n   Additionally, there are two parameters\n\n   levelDistance - (number) Default's *50*. The natural length desired for the edges.\n   iterations - (number) Default's *50*. The number of iterations for the spring layout simulation. Depending on the browser's speed you could set this to a more 'interesting' number, like *200*.\n\n   Instance Properties:\n\n   canvas - Access a <Canvas> instance.\n   graph - Access a <Graph> instance.\n   op - Access a <ForceDirected.Op> instance.\n   fx - Access a <ForceDirected.Plot> instance.\n   labels - Access a <ForceDirected.Label> interface implementation.\n\n*/\n\n$jit.ForceDirected = new Class( {\n\n  Implements: [ Loader, Extras, Layouts.ForceDirected ],\n\n  initialize: function(controller) {\n    var $ForceDirected = $jit.ForceDirected;\n\n    var config = {\n      iterations: 50,\n      levelDistance: 50\n    };\n\n    this.controller = this.config = $.merge(Options(\"Canvas\", \"Node\", \"Edge\",\n        \"Fx\", \"Tips\", \"NodeStyles\", \"Events\", \"Navigation\", \"Controller\", \"Label\"), config, controller);\n\n    var canvasConfig = this.config;\n    if(canvasConfig.useCanvas) {\n      this.canvas = canvasConfig.useCanvas;\n      this.config.labelContainer = this.canvas.id + '-label';\n    } else {\n      if(canvasConfig.background) {\n        canvasConfig.background = $.merge({\n          type: 'Circles'\n        }, canvasConfig.background);\n      }\n      this.canvas = new Canvas(this, canvasConfig);\n      this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';\n    }\n\n    this.graphOptions = {\n      'complex': true,\n      'Node': {\n        'selected': false,\n        'exist': true,\n        'drawn': true\n      }\n    };\n    this.graph = new Graph(this.graphOptions, this.config.Node,\n        this.config.Edge);\n    this.labels = new $ForceDirected.Label[canvasConfig.Label.type](this);\n    this.fx = new $ForceDirected.Plot(this);\n    this.op = new $ForceDirected.Op(this);\n    this.json = null;\n    this.busy = false;\n    // initialize extras\n    this.initializeExtras();\n  },\n\n  /*\n    Method: refresh\n\n    Computes positions and plots the tree.\n  */\n  refresh: function() {\n    this.compute();\n    this.plot();\n  },\n\n  reposition: function() {\n    this.compute('end');\n  },\n\n/*\n  Method: computeIncremental\n\n  Performs the Force Directed algorithm incrementally.\n\n  Description:\n\n  ForceDirected algorithms can perform many computations and lead to JavaScript taking too much time to complete.\n  This method splits the algorithm into smaller parts allowing the user to track the evolution of the algorithm and\n  avoiding browser messages such as \"This script is taking too long to complete\".\n\n  Parameters:\n\n  opt - (object) The object properties are described below\n\n  iter - (number) Default's *20*. Split the algorithm into pieces of _iter_ iterations. For example, if the _iterations_ configuration property\n  of your <ForceDirected> class is 100, then you could set _iter_ to 20 to split the main algorithm into 5 smaller pieces.\n\n  property - (string) Default's *end*. Whether to update starting, current or ending node positions. Possible values are 'end', 'start', 'current'.\n  You can also set an array of these properties. If you'd like to keep the current node positions but to perform these\n  computations for final animation positions then you can just choose 'end'.\n\n  onStep - (function) A callback function called when each \"small part\" of the algorithm completed. This function gets as first formal\n  parameter a percentage value.\n\n  onComplete - A callback function called when the algorithm completed.\n\n  Example:\n\n  In this example I calculate the end positions and then animate the graph to those positions\n\n  (start code js)\n  var fd = new $jit.ForceDirected(...);\n  fd.computeIncremental({\n    iter: 20,\n    property: 'end',\n    onStep: function(perc) {\n      Log.write(\"loading \" + perc + \"%\");\n    },\n    onComplete: function() {\n      Log.write(\"done\");\n      fd.animate();\n    }\n  });\n  (end code)\n\n  In this example I calculate all positions and (re)plot the graph\n\n  (start code js)\n  var fd = new ForceDirected(...);\n  fd.computeIncremental({\n    iter: 20,\n    property: ['end', 'start', 'current'],\n    onStep: function(perc) {\n      Log.write(\"loading \" + perc + \"%\");\n    },\n    onComplete: function() {\n      Log.write(\"done\");\n      fd.plot();\n    }\n  });\n  (end code)\n\n  */\n  computeIncremental: function(opt) {\n    opt = $.merge( {\n      iter: 20,\n      property: 'end',\n      onStep: $.empty,\n      onComplete: $.empty\n    }, opt || {});\n\n    this.config.onBeforeCompute(this.graph.getNode(this.root));\n    this.compute(opt.property, opt);\n  },\n\n  /*\n    Method: plot\n\n    Plots the ForceDirected graph. This is a shortcut to *fx.plot*.\n   */\n  plot: function() {\n    this.fx.plot();\n  },\n\n  /*\n     Method: animate\n\n     Animates the graph from the current positions to the 'end' node positions.\n  */\n  animate: function(opt) {\n    this.fx.animate($.merge( {\n      modes: [ 'linear' ]\n    }, opt || {}));\n  }\n});\n\n$jit.ForceDirected.$extend = true;\n\n(function(ForceDirected) {\n\n  /*\n     Class: ForceDirected.Op\n\n     Custom extension of <Graph.Op>.\n\n     Extends:\n\n     All <Graph.Op> methods\n\n     See also:\n\n     <Graph.Op>\n\n  */\n  ForceDirected.Op = new Class( {\n\n    Implements: Graph.Op,\n\n    initialize: function(viz) {\n      this.viz = viz;\n    }\n  });\n\n  /*\n    Class: ForceDirected.Plot\n\n    Custom extension of <Graph.Plot>.\n\n    Extends:\n\n    All <Graph.Plot> methods\n\n    See also:\n\n    <Graph.Plot>\n\n  */\n  ForceDirected.Plot = new Class( {\n\n    Implements: Graph.Plot,\n\n    initialize: function(viz) {\n      this.viz = viz;\n      this.config = viz.config;\n      this.node = viz.config.Node;\n      this.edge = viz.config.Edge;\n      this.animation = new Animation;\n      this.nodeTypes = new ForceDirected.Plot.NodeTypes;\n      this.edgeTypes = new ForceDirected.Plot.EdgeTypes;\n      this.labels = viz.labels;\n    }\n  });\n\n  /*\n    Class: ForceDirected.Label\n\n    Custom extension of <Graph.Label>.\n    Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.\n\n    Extends:\n\n    All <Graph.Label> methods and subclasses.\n\n    See also:\n\n    <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.\n\n  */\n  ForceDirected.Label = {};\n\n  /*\n     ForceDirected.Label.Native\n\n     Custom extension of <Graph.Label.Native>.\n\n     Extends:\n\n     All <Graph.Label.Native> methods\n\n     See also:\n\n     <Graph.Label.Native>\n\n  */\n  ForceDirected.Label.Native = new Class( {\n    Implements: Graph.Label.Native\n  });\n\n  /*\n    ForceDirected.Label.SVG\n\n    Custom extension of <Graph.Label.SVG>.\n\n    Extends:\n\n    All <Graph.Label.SVG> methods\n\n    See also:\n\n    <Graph.Label.SVG>\n\n  */\n  ForceDirected.Label.SVG = new Class( {\n    Implements: Graph.Label.SVG,\n\n    initialize: function(viz) {\n      this.viz = viz;\n    },\n\n    /*\n       placeLabel\n\n       Overrides abstract method placeLabel in <Graph.Label>.\n\n       Parameters:\n\n       tag - A DOM label element.\n       node - A <Graph.Node>.\n       controller - A configuration/controller object passed to the visualization.\n\n     */\n    placeLabel: function(tag, node, controller) {\n      var pos = node.pos.getc(true),\n          canvas = this.viz.canvas,\n          ox = canvas.translateOffsetX,\n          oy = canvas.translateOffsetY,\n          sx = canvas.scaleOffsetX,\n          sy = canvas.scaleOffsetY,\n          radius = canvas.getSize();\n      var labelPos = {\n        x: Math.round(pos.x * sx + ox + radius.width / 2),\n        y: Math.round(pos.y * sy + oy + radius.height / 2)\n      };\n      tag.setAttribute('x', labelPos.x);\n      tag.setAttribute('y', labelPos.y);\n\n      controller.onPlaceLabel(tag, node);\n    }\n  });\n\n  /*\n     ForceDirected.Label.HTML\n\n     Custom extension of <Graph.Label.HTML>.\n\n     Extends:\n\n     All <Graph.Label.HTML> methods.\n\n     See also:\n\n     <Graph.Label.HTML>\n\n  */\n  ForceDirected.Label.HTML = new Class( {\n    Implements: Graph.Label.HTML,\n\n    initialize: function(viz) {\n      this.viz = viz;\n    },\n    /*\n       placeLabel\n\n       Overrides abstract method placeLabel in <Graph.Plot>.\n\n       Parameters:\n\n       tag - A DOM label element.\n       node - A <Graph.Node>.\n       controller - A configuration/controller object passed to the visualization.\n\n     */\n    placeLabel: function(tag, node, controller) {\n      var pos = node.pos.getc(true),\n          canvas = this.viz.canvas,\n          ox = canvas.translateOffsetX,\n          oy = canvas.translateOffsetY,\n          sx = canvas.scaleOffsetX,\n          sy = canvas.scaleOffsetY,\n          radius = canvas.getSize();\n      var labelPos = {\n        x: Math.round(pos.x * sx + ox + radius.width / 2),\n        y: Math.round(pos.y * sy + oy + radius.height / 2)\n      };\n      var style = tag.style;\n      style.left = labelPos.x + 'px';\n      style.top = labelPos.y + 'px';\n      style.display = this.fitsInCanvas(labelPos, canvas) ? '' : 'none';\n\n      controller.onPlaceLabel(tag, node);\n    }\n  });\n\n  /*\n    Class: ForceDirected.Plot.NodeTypes\n\n    This class contains a list of <Graph.Node> built-in types.\n    Node types implemented are 'none', 'circle', 'triangle', 'rectangle', 'star', 'ellipse' and 'square'.\n\n    You can add your custom node types, customizing your visualization to the extreme.\n\n    Example:\n\n    (start code js)\n      ForceDirected.Plot.NodeTypes.implement({\n        'mySpecialType': {\n          'render': function(node, canvas) {\n            //print your custom node to canvas\n          },\n          //optional\n          'contains': function(node, pos) {\n            //return true if pos is inside the node or false otherwise\n          }\n        }\n      });\n    (end code)\n\n  */\n  ForceDirected.Plot.NodeTypes = new Class({\n    'none': {\n      'render': $.empty,\n      'contains': $.lambda(false)\n    },\n    'circle': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            dim = node.getData('dim');\n        this.nodeHelper.circle.render('fill', pos, dim, canvas);\n      },\n      'contains': function(node, pos){\n        var npos = node.pos.getc(true),\n            dim = node.getData('dim');\n        return this.nodeHelper.circle.contains(npos, pos, dim);\n      }\n    },\n    'ellipse': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            width = node.getData('width'),\n            height = node.getData('height');\n        this.nodeHelper.ellipse.render('fill', pos, width, height, canvas);\n        },\n      // TODO(nico): be more precise...\n      'contains': function(node, pos){\n        var npos = node.pos.getc(true),\n            width = node.getData('width'),\n            height = node.getData('height');\n        return this.nodeHelper.ellipse.contains(npos, pos, width, height);\n      }\n    },\n    'square': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            dim = node.getData('dim');\n        this.nodeHelper.square.render('fill', pos, dim, canvas);\n      },\n      'contains': function(node, pos){\n        var npos = node.pos.getc(true),\n            dim = node.getData('dim');\n        return this.nodeHelper.square.contains(npos, pos, dim);\n      }\n    },\n    'rectangle': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            width = node.getData('width'),\n            height = node.getData('height');\n        this.nodeHelper.rectangle.render('fill', pos, width, height, canvas);\n      },\n      'contains': function(node, pos){\n        var npos = node.pos.getc(true),\n            width = node.getData('width'),\n            height = node.getData('height');\n        return this.nodeHelper.rectangle.contains(npos, pos, width, height);\n      }\n    },\n    'triangle': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            dim = node.getData('dim');\n        this.nodeHelper.triangle.render('fill', pos, dim, canvas);\n      },\n      'contains': function(node, pos) {\n        var npos = node.pos.getc(true),\n            dim = node.getData('dim');\n        return this.nodeHelper.triangle.contains(npos, pos, dim);\n      }\n    },\n    'star': {\n      'render': function(node, canvas){\n        var pos = node.pos.getc(true),\n            dim = node.getData('dim');\n        this.nodeHelper.star.render('fill', pos, dim, canvas);\n      },\n      'contains': function(node, pos) {\n        var npos = node.pos.getc(true),\n            dim = node.getData('dim');\n        return this.nodeHelper.star.contains(npos, pos, dim);\n      }\n    }\n  });\n\n  /*\n    Class: ForceDirected.Plot.EdgeTypes\n\n    This class contains a list of <Graph.Adjacence> built-in types.\n    Edge types implemented are 'none', 'line' and 'arrow'.\n\n    You can add your custom edge types, customizing your visualization to the extreme.\n\n    Example:\n\n    (start code js)\n      ForceDirected.Plot.EdgeTypes.implement({\n        'mySpecialType': function(adj, canvas) {\n          //print your custom edge to canvas\n        }\n      });\n    (end code)\n\n  */\n  ForceDirected.Plot.EdgeTypes = new Class({\n    'none': $.empty,\n    'line': function(adj, canvas) {\n      var from = adj.nodeFrom.pos.getc(true),\n          to = adj.nodeTo.pos.getc(true);\n      this.edgeHelper.line(from, to, canvas);\n    },\n    'arrow': function(adj, canvas) {\n      var from = adj.nodeFrom.pos.getc(true),\n          to = adj.nodeTo.pos.getc(true),\n          dim = adj.getData('dim'),\n          direction = adj.data.$direction,\n          inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id);\n      this.edgeHelper.arrow(from, to, dim, inv, canvas);\n    }\n  });\n\n})($jit.ForceDirected);\n\n\n/*\n * File: Treemap.js\n *\n*/\n\n$jit.TM = {};\n\nvar TM = $jit.TM;\n\n$jit.TM.$extend = true;\n\n/*\n  Class: TM.Base\n\n  Abstract class providing base functionality for <TM.Squarified>, <TM.Strip> and <TM.SliceAndDice> visualizations.\n\n  Implements:\n\n  All <Loader> methods\n\n  Constructor Options:\n\n  Inherits options from\n\n  - <Options.Canvas>\n  - <Options.Controller>\n  - <Options.Node>\n  - <Options.Edge>\n  - <Options.Label>\n  - <Options.Events>\n  - <Options.Tips>\n  - <Options.NodeStyles>\n  - <Options.Navigation>\n\n  Additionally, there are other parameters and some default values changed\n\n  orientation - (string) Default's *h*. Whether to set horizontal or vertical layouts. Possible values are 'h' and 'v'.\n  titleHeight - (number) Default's *13*. The height of the title rectangle for inner (non-leaf) nodes.\n  offset - (number) Default's *2*. Boxes offset.\n  constrained - (boolean) Default's *false*. Whether to show the entire tree when loaded or just the number of levels specified by _levelsToShow_.\n  levelsToShow - (number) Default's *3*. The number of levels to show for a subtree. This number is relative to the selected node.\n  animate - (boolean) Default's *false*. Whether to animate transitions.\n  Node.type - Described in <Options.Node>. Default's *rectangle*.\n  duration - Described in <Options.Fx>. Default's *700*.\n  fps - Described in <Options.Fx>. Default's *45*.\n\n  Instance Properties:\n\n  canvas - Access a <Canvas> instance.\n  graph - Access a <Graph> instance.\n  op - Access a <TM.Op> instance.\n  fx - Access a <TM.Plot> instance.\n  labels - Access a <TM.Label> interface implementation.\n\n  Inspired by:\n\n  Squarified Treemaps (Mark Bruls, Kees Huizing, and Jarke J. van Wijk) <http://www.win.tue.nl/~vanwijk/stm.pdf>\n\n  Tree visualization with tree-maps: 2-d space-filling approach (Ben Shneiderman) <http://hcil.cs.umd.edu/trs/91-03/91-03.html>\n\n   Note:\n\n   This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the visualization described in the paper.\n\n*/\nTM.Base = {\n  layout: {\n    orientation: \"h\",\n    vertical: function(){\n      return this.orientation == \"v\";\n    },\n    horizontal: function(){\n      return this.orientation == \"h\";\n    },\n    change: function(){\n      this.orientation = this.vertical()? \"h\" : \"v\";\n    }\n  },\n\n  initialize: function(controller){\n    var config = {\n      orientation: \"h\",\n      titleHeight: 13,\n      offset: 2,\n      levelsToShow: 3,\n      constrained: false,\n      animate: false,\n      Node: {\n        type: 'rectangle',\n        overridable: true,\n        //we all know why this is not zero,\n        //right, Firefox?\n        width: 3,\n        height: 3,\n        color: '#444'\n      },\n      Label: {\n        textAlign: 'center',\n        textBaseline: 'top'\n      },\n      Edge: {\n        type: 'none'\n      },\n      duration: 700,\n      fps: 45\n    };\n\n    this.controller = this.config = $.merge(Options(\"Canvas\", \"Node\", \"Edge\",\n        \"Fx\", \"Controller\", \"Tips\", \"NodeStyles\", \"Events\", \"Navigation\", \"Label\"), config, controller);\n    this.layout.orientation = this.config.orientation;\n\n    var canvasConfig = this.config;\n    if (canvasConfig.useCanvas) {\n      this.canvas = canvasConfig.useCanvas;\n      this.config.labelContainer = this.canvas.id + '-label';\n    } else {\n      if(canvasConfig.background) {\n        canvasConfig.background = $.merge({\n          type: 'Circles'\n        }, canvasConfig.background);\n      }\n      this.canvas = new Canvas(this, canvasConfig);\n      this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';\n    }\n\n    this.graphOptions = {\n      'complex': true,\n      'Node': {\n        'selected': false,\n        'exist': true,\n        'drawn': true\n      }\n    };\n    this.graph = new Graph(this.graphOptions, this.config.Node,\n        this.config.Edge);\n    this.labels = new TM.Label[canvasConfig.Label.type](this);\n    this.fx = new TM.Plot(this);\n    this.op = new TM.Op(this);\n    this.group = new TM.Group(this);\n    this.geom = new TM.Geom(this);\n    this.clickedNode = null;\n    this.busy = false;\n    // initialize extras\n    this.initializeExtras();\n  },\n\n  /*\n    Method: refresh\n\n    Computes positions and plots the tree.\n  */\n  refresh: function(){\n    if(this.busy) return;\n    this.busy = true;\n    var that = this;\n    if(this.config.animate) {\n      this.compute('end');\n      this.geom.setRightLevelToShow(this.graph.getNode(this.root));\n      this.fx.animate($.merge(this.config, {\n        modes: ['linear', 'node-property:width:height'],\n        onComplete: function() {\n          that.busy = false;\n        }\n      }));\n    } else {\n      var labelType = this.config.Label.type;\n      if(labelType != 'Native') {\n        var that = this;\n        this.graph.eachNode(function(n) { that.labels.hideLabel(n, false); });\n      }\n      this.busy = false;\n      this.compute();\n      this.plot();\n    }\n  },\n\n  /*\n    Method: plot\n\n    Plots the TreeMap. This is a shortcut to *fx.plot*.\n\n   */\n  plot: function(){\n    this.fx.plot();\n  },\n\n  /*\n  Method: leaf\n\n  Returns whether the node is a leaf.\n\n   Parameters:\n\n   n - (object) A <Graph.Node>.\n\n */\n  leaf: function(n){\n    return n.getSubnodes([\n        1, 1\n    ], \"ignore\").length == 0;\n  },\n\n  /*\n  Method: enter\n\n  Sets the node as root.\n\n   Parameters:\n\n   n - (object) A <Graph.Node>.\n\n */\n  enter: function(n){\n    if(this.busy) return;\n    this.busy = true;\n\n    var that = this,\n        config = this.config,\n        graph = this.graph,\n        clickedNode = n,\n        previousClickedNode = this.clickedNode;\n\n    var callback = {\n      onComplete: function() {\n        //ensure that nodes are shown for that level\n        if(config.levelsToShow > 0) {\n          that.geom.setRightLevelToShow(n);\n        }\n        //compute positions of newly inserted nodes\n        if(config.request) that.compute();\n        if(config.animate) {\n          //fade nodes\n          graph.nodeList.setDataset(['current', 'end'], {\n            'alpha': [1, 0]\n          });\n          n.eachSubgraph(function(n) {\n            n.setData('alpha', 1, 'end');\n          }, \"ignore\");\n          that.fx.animate({\n            duration: 500,\n            modes:['node-property:alpha'],\n            onComplete: function() {\n              //compute end positions\n              that.clickedNode = clickedNode;\n              that.compute('end');\n              //animate positions\n              //TODO(nico) commenting this line didn't seem to throw errors...\n              that.clickedNode = previousClickedNode;\n              that.fx.animate({\n                modes:['linear', 'node-property:width:height'],\n                duration: 1000,\n                onComplete: function() {\n                  that.busy = false;\n                  //TODO(nico) check comment above\n                  that.clickedNode = clickedNode;\n                }\n              });\n            }\n          });\n        } else {\n          that.busy = false;\n          that.clickedNode = n;\n          that.refresh();\n        }\n      }\n    };\n    if(config.request) {\n      this.requestNodes(clickedNode, callback);\n    } else {\n      callback.onComplete();\n    }\n  },\n\n  /*\n  Method: out\n\n  Sets the parent node of the current selected node as root.\n\n */\n  out: function(){\n    if(this.busy) return;\n    this.busy = true;\n    this.events.hoveredNode = false;\n    var that = this,\n        config = this.config,\n        graph = this.graph,\n        parents = graph.getNode(this.clickedNode\n            && this.clickedNode.id || this.root).getParents(),\n        parent = parents[0],\n        clickedNode = parent,\n        previousClickedNode = this.clickedNode;\n\n    //if no parents return\n    if(!parent) {\n      this.busy = false;\n      return;\n    }\n    //final plot callback\n    callback = {\n      onComplete: function() {\n        that.clickedNode = parent;\n        if(config.request) {\n          that.requestNodes(parent, {\n            onComplete: function() {\n              that.compute();\n              that.plot();\n              that.busy = false;\n            }\n          });\n        } else {\n          that.compute();\n          that.plot();\n          that.busy = false;\n        }\n      }\n    };\n    //prune tree\n    if (config.levelsToShow > 0)\n      this.geom.setRightLevelToShow(parent);\n    //animate node positions\n    if(config.animate) {\n      this.clickedNode = clickedNode;\n      this.compute('end');\n      //animate the visible subtree only\n      this.clickedNode = previousClickedNode;\n      this.fx.animate({\n        modes:['linear', 'node-property:width:height'],\n        duration: 1000,\n        onComplete: function() {\n          //animate the parent subtree\n          that.clickedNode = clickedNode;\n          //change nodes alpha\n          graph.nodeList.setDataset(['current', 'end'], {\n            'alpha': [0, 1]\n          });\n          previousClickedNode.eachSubgraph(function(node) {\n            node.setData('alpha', 1);\n          }, \"ignore\");\n          that.fx.animate({\n            duration: 500,\n            modes:['node-property:alpha'],\n            onComplete: function() {\n              callback.onComplete();\n            }\n          });\n        }\n      });\n    } else {\n      callback.onComplete();\n    }\n  },\n\n  requestNodes: function(node, onComplete){\n    var handler = $.merge(this.controller, onComplete),\n        lev = this.config.levelsToShow;\n    if (handler.request) {\n      var leaves = [], d = node._depth;\n      node.eachLevel(0, lev, function(n){\n        var nodeLevel = lev - (n._depth - d);\n        if (n.drawn && !n.anySubnode() && nodeLevel > 0) {\n          leaves.push(n);\n          n._level = nodeLevel;\n        }\n      });\n      this.group.requestNodes(leaves, handler);\n    } else {\n      handler.onComplete();\n    }\n  }\n};\n\n/*\n  Class: TM.Op\n\n  Custom extension of <Graph.Op>.\n\n  Extends:\n\n  All <Graph.Op> methods\n\n  See also:\n\n  <Graph.Op>\n\n  */\nTM.Op = new Class({\n  Implements: Graph.Op,\n\n  initialize: function(viz){\n    this.viz = viz;\n  }\n});\n\n//extend level methods of Graph.Geom\nTM.Geom = new Class({\n  Implements: Graph.Geom,\n\n  getRightLevelToShow: function() {\n    return this.viz.config.levelsToShow;\n  },\n\n  setRightLevelToShow: function(node) {\n    var level = this.getRightLevelToShow(),\n        fx = this.viz.labels;\n    node.eachLevel(0, level+1, function(n) {\n      var d = n._depth - node._depth;\n      if(d > level) {\n        n.drawn = false;\n        n.exist = false;\n        n.ignore = true;\n        fx.hideLabel(n, false);\n      } else {\n        n.drawn = true;\n        n.exist = true;\n        delete n.ignore;\n      }\n    });\n    node.drawn = true;\n    delete node.ignore;\n  }\n});\n\n/*\n\nPerforms operations on group of nodes.\n\n*/\nTM.Group = new Class( {\n\n  initialize: function(viz){\n    this.viz = viz;\n    this.canvas = viz.canvas;\n    this.config = viz.config;\n  },\n\n  /*\n\n    Calls the request method on the controller to request a subtree for each node.\n  */\n  requestNodes: function(nodes, controller){\n    var counter = 0, len = nodes.length, nodeSelected = {};\n    var complete = function(){\n      controller.onComplete();\n    };\n    var viz = this.viz;\n    if (len == 0)\n      complete();\n    for ( var i = 0; i < len; i++) {\n      nodeSelected[nodes[i].id] = nodes[i];\n      controller.request(nodes[i].id, nodes[i]._level, {\n        onComplete: function(nodeId, data){\n          if (data && data.children) {\n            data.id = nodeId;\n            viz.op.sum(data, {\n              type: 'nothing'\n            });\n          }\n          if (++counter == len) {\n            viz.graph.computeLevels(viz.root, 0);\n            complete();\n          }\n        }\n      });\n    }\n  }\n});\n\n/*\n  Class: TM.Plot\n\n  Custom extension of <Graph.Plot>.\n\n  Extends:\n\n  All <Graph.Plot> methods\n\n  See also:\n\n  <Graph.Plot>\n\n  */\nTM.Plot = new Class({\n\n  Implements: Graph.Plot,\n\n  initialize: function(viz){\n    this.viz = viz;\n    this.config = viz.config;\n    this.node = this.config.Node;\n    this.edge = this.config.Edge;\n    this.animation = new Animation;\n    this.nodeTypes = new TM.Plot.NodeTypes;\n    this.edgeTypes = new TM.Plot.EdgeTypes;\n    this.labels = viz.labels;\n  },\n\n  plot: function(opt, animating){\n    var viz = this.viz,\n        graph = viz.graph;\n    viz.canvas.clear();\n    this.plotTree(graph.getNode(viz.clickedNode && viz.clickedNode.id || viz.root), $.merge(viz.config, opt || {}, {\n      'withLabels': true,\n      'hideLabels': false,\n      'plotSubtree': function(n, ch){\n        return n.anySubnode(\"exist\");\n      }\n    }), animating);\n  }\n});\n\n/*\n  Class: TM.Label\n\n  Custom extension of <Graph.Label>.\n  Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.\n\n  Extends:\n\n  All <Graph.Label> methods and subclasses.\n\n  See also:\n\n  <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.\n\n*/\nTM.Label = {};\n\n/*\n TM.Label.Native\n\n Custom extension of <Graph.Label.Native>.\n\n Extends:\n\n All <Graph.Label.Native> methods\n\n See also:\n\n <Graph.Label.Native>\n*/\nTM.Label.Native = new Class({\n  Implements: Graph.Label.Native,\n\n  initialize: function(viz) {\n    this.config = viz.config;\n    this.leaf = viz.leaf;\n  },\n\n  renderLabel: function(canvas, node, controller){\n    if(!this.leaf(node) && !this.config.titleHeight) return;\n    var pos = node.pos.getc(true),\n        ctx = canvas.getCtx(),\n        width = node.getData('width'),\n        height = node.getData('height'),\n        x = pos.x + width/2,\n        y = pos.y;\n\n    ctx.fillText(node.name, x, y, width);\n  }\n});\n\n/*\n TM.Label.SVG\n\n  Custom extension of <Graph.Label.SVG>.\n\n  Extends:\n\n  All <Graph.Label.SVG> methods\n\n  See also:\n\n  <Graph.Label.SVG>\n*/\nTM.Label.SVG = new Class( {\n  Implements: Graph.Label.SVG,\n\n  initialize: function(viz){\n    this.viz = viz;\n    this.leaf = viz.leaf;\n    this.config = viz.config;\n  },\n\n  /*\n  placeLabel\n\n  Overrides abstract method placeLabel in <Graph.Plot>.\n\n  Parameters:\n\n  tag - A DOM label element.\n  node - A <Graph.Node>.\n  controller - A configuration/controller object passed to the visualization.\n\n  */\n  placeLabel: function(tag, node, controller){\n    var pos = node.pos.getc(true),\n        canvas = this.viz.canvas,\n        ox = canvas.translateOffsetX,\n        oy = canvas.translateOffsetY,\n        sx = canvas.scaleOffsetX,\n        sy = canvas.scaleOffsetY,\n        radius = canvas.getSize();\n    var labelPos = {\n      x: Math.round(pos.x * sx + ox + radius.width / 2),\n      y: Math.round(pos.y * sy + oy + radius.height / 2)\n    };\n    tag.setAttribute('x', labelPos.x);\n    tag.setAttribute('y', labelPos.y);\n\n    if(!this.leaf(node) && !this.config.titleHeight) {\n      tag.style.display = 'none';\n    }\n    controller.onPlaceLabel(tag, node);\n  }\n});\n\n/*\n TM.Label.HTML\n\n Custom extension of <Graph.Label.HTML>.\n\n Extends:\n\n All <Graph.Label.HTML> methods.\n\n See also:\n\n <Graph.Label.HTML>\n\n*/\nTM.Label.HTML = new Class( {\n  Implements: Graph.Label.HTML,\n\n  initialize: function(viz){\n    this.viz = viz;\n    this.leaf = viz.leaf;\n    this.config = viz.config;\n  },\n\n  /*\n    placeLabel\n\n    Overrides abstract method placeLabel in <Graph.Plot>.\n\n    Parameters:\n\n    tag - A DOM label element.\n    node - A <Graph.Node>.\n    controller - A configuration/controller object passed to the visualization.\n\n  */\n  placeLabel: function(tag, node, controller){\n    var pos = node.pos.getc(true),\n        canvas = this.viz.canvas,\n        ox = canvas.translateOffsetX,\n        oy = canvas.translateOffsetY,\n        sx = canvas.scaleOffsetX,\n        sy = canvas.scaleOffsetY,\n        radius = canvas.getSize();\n    var labelPos = {\n      x: Math.round(pos.x * sx + ox + radius.width / 2),\n      y: Math.round(pos.y * sy + oy + radius.height / 2)\n    };\n\n    var style = tag.style;\n    style.left = labelPos.x + 'px';\n    style.top = labelPos.y + 'px';\n    style.width = node.getData('width') * sx + 'px';\n    style.height = node.getData('height') * sy + 'px';\n    style.zIndex = node._depth * 100;\n    style.display = '';\n\n    if(!this.leaf(node) && !this.config.titleHeight) {\n      tag.style.display = 'none';\n    }\n    controller.onPlaceLabel(tag, node);\n  }\n});\n\n/*\n  Class: TM.Plot.NodeTypes\n\n  This class contains a list of <Graph.Node> built-in types.\n  Node types implemented are 'none', 'rectangle'.\n\n  You can add your custom node types, customizing your visualization to the extreme.\n\n  Example:\n\n  (start code js)\n    TM.Plot.NodeTypes.implement({\n      'mySpecialType': {\n        'render': function(node, canvas) {\n          //print your custom node to canvas\n        },\n        //optional\n        'contains': function(node, pos) {\n          //return true if pos is inside the node or false otherwise\n        }\n      }\n    });\n  (end code)\n\n*/\nTM.Plot.NodeTypes = new Class( {\n  'none': {\n    'render': $.empty\n  },\n\n  'rectangle': {\n    'render': function(node, canvas, animating){\n      var leaf = this.viz.leaf(node),\n          config = this.config,\n          offst = config.offset,\n          titleHeight = config.titleHeight,\n          pos = node.pos.getc(true),\n          width = node.getData('width'),\n          height = node.getData('height'),\n          border = node.getData('border'),\n          ctx = canvas.getCtx(),\n          posx = pos.x + offst / 2,\n          posy = pos.y + offst / 2;\n      if(width <= offst || height <= offst) return;\n      if (leaf) {\n        if(config.cushion) {\n          var lg = ctx.createRadialGradient(posx + (width-offst)/2, posy + (height-offst)/2, 1,\n              posx + (width-offst)/2, posy + (height-offst)/2, width < height? height : width);\n          var color = node.getData('color');\n          var colorGrad = $.rgbToHex($.map($.hexToRgb(color),\n              function(r) { return r * 0.2 >> 0; }));\n          lg.addColorStop(0, color);\n          lg.addColorStop(1, colorGrad);\n          ctx.fillStyle = lg;\n        }\n        ctx.fillRect(posx, posy, width - offst, height - offst);\n        if(border) {\n          ctx.save();\n          ctx.strokeStyle = border;\n          ctx.strokeRect(posx, posy, width - offst, height - offst);\n          ctx.restore();\n        }\n      } else if(titleHeight > 0){\n        ctx.fillRect(pos.x + offst / 2, pos.y + offst / 2, width - offst,\n            titleHeight - offst);\n        if(border) {\n          ctx.save();\n          ctx.strokeStyle = border;\n          ctx.strokeRect(pos.x + offst / 2, pos.y + offst / 2, width - offst,\n              height - offst);\n          ctx.restore();\n        }\n      }\n    },\n    'contains': function(node, pos) {\n      if(this.viz.clickedNode && !node.isDescendantOf(this.viz.clickedNode.id)) return false;\n      var npos = node.pos.getc(true),\n          width = node.getData('width'),\n          leaf = this.viz.leaf(node),\n          height = leaf? node.getData('height') : this.config.titleHeight;\n      return this.nodeHelper.rectangle.contains({x: npos.x + width/2, y: npos.y + height/2}, pos, width, height);\n    }\n  }\n});\n\nTM.Plot.EdgeTypes = new Class( {\n  'none': $.empty\n});\n\n/*\n  Class: TM.SliceAndDice\n\n  A slice and dice TreeMap visualization.\n\n  Implements:\n\n  All <TM.Base> methods and properties.\n*/\nTM.SliceAndDice = new Class( {\n  Implements: [\n      Loader, Extras, TM.Base, Layouts.TM.SliceAndDice\n  ]\n});\n\n/*\n  Class: TM.Squarified\n\n  A squarified TreeMap visualization.\n\n  Implements:\n\n  All <TM.Base> methods and properties.\n*/\nTM.Squarified = new Class( {\n  Implements: [\n      Loader, Extras, TM.Base, Layouts.TM.Squarified\n  ]\n});\n\n/*\n  Class: TM.Strip\n\n  A strip TreeMap visualization.\n\n  Implements:\n\n  All <TM.Base> methods and properties.\n*/\nTM.Strip = new Class( {\n  Implements: [\n      Loader, Extras, TM.Base, Layouts.TM.Strip\n  ]\n});\n\n\n/*\n * File: Options.BarChart.js\n *\n*/\n\n/*\n  Object: Options.BarChart\n\n  <BarChart> options.\n  Other options included in the BarChart are <Options.Canvas>, <Options.Label>, <Options.Tips> and <Options.Events>.\n\n  Syntax:\n\n  (start code js)\n\n  Options.BarChart = {\n    animate: true,\n    offset: 25,\n    labelOffset: 3,\n    barsOffset: 0,\n    type: 'stacked',\n    hoveredColor: '#9fd4ff',\n    orientation: 'horizontal',\n    showAggregates: true,\n    showLabels: true\n  };\n\n  (end code)\n\n  Example:\n\n  (start code js)\n\n  var barChart = new $jit.BarChart({\n    animate: true,\n    barsOffset: 10,\n    type: 'stacked:gradient'\n  });\n\n  (end code)\n\n  Parameters:\n\n  animate - (boolean) Default's *true*. Whether to add animated transitions when filtering/restoring stacks.\n  offset - (number) Default's *25*. Adds margin between the visualization and the canvas.\n  labelOffset - (number) Default's *3*. Adds margin between the label and the default place where it should be drawn.\n  barsOffset - (number) Default's *0*. Separation between bars.\n  type - (string) Default's *'stacked'*. Stack style. Posible values are 'stacked', 'stacked:gradient' to add gradients.\n  hoveredColor - (boolean|string) Default's *'#9fd4ff'*. Sets the selected color for a hovered bar stack.\n  orientation - (string) Default's 'horizontal'. Sets the direction of the bars. Possible options are 'vertical' or 'horizontal'.\n  showAggregates - (boolean) Default's *true*. Display the sum of the values of the different stacks.\n  showLabels - (boolean) Default's *true*. Display the name of the slots.\n\n*/\n\nOptions.BarChart = {\n  $extend: true,\n\n  animate: true,\n  type: 'stacked', //stacked, grouped, : gradient\n  offset: 25, //page offset\n  labelOffset: 3, //label offset\n  barsOffset: 0, //distance between bars\n  hoveredColor: '#9fd4ff',\n  orientation: 'horizontal',\n  showAggregates: true,\n  showLabels: true,\n  Tips: {\n    enable: false,\n    onShow: $.empty,\n    onHide: $.empty\n  },\n  Events: {\n    enable: false,\n    onClick: $.empty\n  }\n};\n\n/*\n * File: BarChart.js\n *\n*/\n\n$jit.ST.Plot.NodeTypes.implement({\n  'barchart-stacked' : {\n    'render' : function(node, canvas) {\n      var pos = node.pos.getc(true),\n          width = node.getData('width'),\n          height = node.getData('height'),\n          algnPos = this.getAlignedPos(pos, width, height),\n          x = algnPos.x, y = algnPos.y,\n          dimArray = node.getData('dimArray'),\n          valueArray = node.getData('valueArray'),\n          colorArray = node.getData('colorArray'),\n          colorLength = colorArray.length,\n          stringArray = node.getData('stringArray');\n\n      var ctx = canvas.getCtx(),\n          opt = {},\n          border = node.getData('border'),\n          gradient = node.getData('gradient'),\n          config = node.getData('config'),\n          horz = config.orientation == 'horizontal',\n          aggregates = config.showAggregates,\n          showLabels = config.showLabels,\n          label = config.Label;\n\n      if (colorArray && dimArray && stringArray) {\n        for (var i=0, l=dimArray.length, acum=0, valAcum=0; i<l; i++) {\n          ctx.fillStyle = ctx.strokeStyle = colorArray[i % colorLength];\n          if(gradient) {\n            var linear;\n            if(horz) {\n              linear = ctx.createLinearGradient(x + acum + dimArray[i]/2, y,\n                  x + acum + dimArray[i]/2, y + height);\n            } else {\n              linear = ctx.createLinearGradient(x, y - acum - dimArray[i]/2,\n                  x + width, y - acum- dimArray[i]/2);\n            }\n            var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)),\n                function(v) { return (v * 0.5) >> 0; }));\n            linear.addColorStop(0, color);\n            linear.addColorStop(0.5, colorArray[i % colorLength]);\n            linear.addColorStop(1, color);\n            ctx.fillStyle = linear;\n          }\n          if(horz) {\n            ctx.fillRect(x + acum, y, dimArray[i], height);\n          } else {\n            ctx.fillRect(x, y - acum - dimArray[i], width, dimArray[i]);\n          }\n          if(border && border.name == stringArray[i]) {\n            opt.acum = acum;\n            opt.dimValue = dimArray[i];\n          }\n          acum += (dimArray[i] || 0);\n          valAcum += (valueArray[i] || 0);\n        }\n        if(border) {\n          ctx.save();\n          ctx.lineWidth = 2;\n          ctx.strokeStyle = border.color;\n          if(horz) {\n            ctx.strokeRect(x + opt.acum + 1, y + 1, opt.dimValue -2, height - 2);\n          } else {\n            ctx.strokeRect(x + 1, y - opt.acum - opt.dimValue + 1, width -2, opt.dimValue -2);\n          }\n          ctx.restore();\n        }\n        if(label.type == 'Native') {\n          ctx.save();\n          ctx.fillStyle = ctx.strokeStyle = label.color;\n          ctx.font = label.style + ' ' + label.size + 'px ' + label.family;\n          ctx.textBaseline = 'middle';\n          if(aggregates(node.name, valAcum)) {\n            if(horz) {\n              ctx.textAlign = 'right';\n              ctx.fillText(valAcum, x + acum - config.labelOffset, y + height/2);\n            } else {\n              ctx.textAlign = 'center';\n              ctx.fillText(valAcum, x + width/2, y - height - label.size/2 - config.labelOffset);\n            }\n          }\n          if(showLabels(node.name, valAcum, node)) {\n            if(horz) {\n              ctx.textAlign = 'center';\n              ctx.translate(x - config.labelOffset - label.size/2, y + height/2);\n              ctx.rotate(Math.PI / 2);\n              ctx.fillText(node.name, 0, 0);\n            } else {\n              ctx.textAlign = 'center';\n              ctx.fillText(node.name, x + width/2, y + label.size/2 + config.labelOffset);\n            }\n          }\n          ctx.restore();\n        }\n      }\n    },\n    'contains': function(node, mpos) {\n      var pos = node.pos.getc(true),\n          width = node.getData('width'),\n          height = node.getData('height'),\n          algnPos = this.getAlignedPos(pos, width, height),\n          x = algnPos.x, y = algnPos.y,\n          dimArray = node.getData('dimArray'),\n          config = node.getData('config'),\n          rx = mpos.x - x,\n          horz = config.orientation == 'horizontal';\n      //bounding box check\n      if(horz) {\n        if(mpos.x < x || mpos.x > x + width\n            || mpos.y > y + height || mpos.y < y) {\n            return false;\n          }\n      } else {\n        if(mpos.x < x || mpos.x > x + width\n            || mpos.y > y || mpos.y < y - height) {\n            return false;\n          }\n      }\n      //deep check\n      for(var i=0, l=dimArray.length, acum=(horz? x:y); i<l; i++) {\n        var dimi = dimArray[i];\n        if(horz) {\n          acum += dimi;\n          var intersec = acum;\n          if(mpos.x <= intersec) {\n            return {\n              'name': node.getData('stringArray')[i],\n              'color': node.getData('colorArray')[i],\n              'value': node.getData('valueArray')[i]\n            };\n          }\n        } else {\n          acum -= dimi;\n          var intersec = acum;\n          if(mpos.y >= intersec) {\n            return {\n              'name': node.getData('stringArray')[i],\n              'color': node.getData('colorArray')[i],\n              'value': node.getData('valueArray')[i]\n            };\n          }\n        }\n      }\n      return false;\n    }\n  },\n  'barchart-grouped' : {\n    'render' : function(node, canvas) {\n      var pos = node.pos.getc(true),\n          width = node.getData('width'),\n          height = node.getData('height'),\n          algnPos = this.getAlignedPos(pos, width, height),\n          x = algnPos.x, y = algnPos.y,\n          dimArray = node.getData('dimArray'),\n          valueArray = node.getData('valueArray'),\n          valueLength = valueArray.length,\n          colorArray = node.getData('colorArray'),\n          colorLength = colorArray.length,\n          stringArray = node.getData('stringArray');\n\n      var ctx = canvas.getCtx(),\n          opt = {},\n          border = node.getData('border'),\n          gradient = node.getData('gradient'),\n          config = node.getData('config'),\n          horz = config.orientation == 'horizontal',\n          aggregates = config.showAggregates,\n          showLabels = config.showLabels,\n          label = config.Label,\n          fixedDim = (horz? height : width) / valueLength;\n\n      if (colorArray && dimArray && stringArray) {\n        for (var i=0, l=valueLength, acum=0, valAcum=0; i<l; i++) {\n          ctx.fillStyle = ctx.strokeStyle = colorArray[i % colorLength];\n          if(gradient) {\n            var linear;\n            if(horz) {\n              linear = ctx.createLinearGradient(x + dimArray[i]/2, y + fixedDim * i,\n                  x + dimArray[i]/2, y + fixedDim * (i + 1));\n            } else {\n              linear = ctx.createLinearGradient(x + fixedDim * i, y - dimArray[i]/2,\n                  x + fixedDim * (i + 1), y - dimArray[i]/2);\n            }\n            var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)),\n                function(v) { return (v * 0.5) >> 0; }));\n            linear.addColorStop(0, color);\n            linear.addColorStop(0.5, colorArray[i % colorLength]);\n            linear.addColorStop(1, color);\n            ctx.fillStyle = linear;\n          }\n          if(horz) {\n            ctx.fillRect(x, y + fixedDim * i, dimArray[i], fixedDim);\n          } else {\n            ctx.fillRect(x + fixedDim * i, y - dimArray[i], fixedDim, dimArray[i]);\n          }\n          if(border && border.name == stringArray[i]) {\n            opt.acum = fixedDim * i;\n            opt.dimValue = dimArray[i];\n          }\n          acum += (dimArray[i] || 0);\n          valAcum += (valueArray[i] || 0);\n        }\n        if(border) {\n          ctx.save();\n          ctx.lineWidth = 2;\n          ctx.strokeStyle = border.color;\n          if(horz) {\n            ctx.strokeRect(x + 1, y + opt.acum + 1, opt.dimValue -2, fixedDim - 2);\n          } else {\n            ctx.strokeRect(x + opt.acum + 1, y - opt.dimValue + 1, fixedDim -2, opt.dimValue -2);\n          }\n          ctx.restore();\n        }\n        if(label.type == 'Native') {\n          ctx.save();\n          ctx.fillStyle = ctx.strokeStyle = label.color;\n          ctx.font = label.style + ' ' + label.size + 'px ' + label.family;\n          ctx.textBaseline = 'middle';\n          if(aggregates(node.name, valAcum)) {\n            if(horz) {\n              ctx.textAlign = 'right';\n              ctx.fillText(valAcum, x + Math.max.apply(null, dimArray) - config.labelOffset, y + height/2);\n            } else {\n              ctx.textAlign = 'center';\n              ctx.fillText(valAcum, x + width/2, y - Math.max.apply(null, dimArray) - label.size/2 - config.labelOffset);\n            }\n          }\n          if(showLabels(node.name, valAcum, node)) {\n            if(horz) {\n              ctx.textAlign = 'center';\n              ctx.translate(x - config.labelOffset - label.size/2, y + height/2);\n              ctx.rotate(Math.PI / 2);\n              ctx.fillText(node.name, 0, 0);\n            } else {\n              ctx.textAlign = 'center';\n              ctx.fillText(node.name, x + width/2, y + label.size/2 + config.labelOffset);\n            }\n          }\n          ctx.restore();\n        }\n      }\n    },\n    'contains': function(node, mpos) {\n      var pos = node.pos.getc(true),\n          width = node.getData('width'),\n          height = node.getData('height'),\n          algnPos = this.getAlignedPos(pos, width, height),\n          x = algnPos.x, y = algnPos.y,\n          dimArray = node.getData('dimArray'),\n          len = dimArray.length,\n          config = node.getData('config'),\n          rx = mpos.x - x,\n          horz = config.orientation == 'horizontal',\n          fixedDim = (horz? height : width) / len;\n      //bounding box check\n      if(horz) {\n        if(mpos.x < x || mpos.x > x + width\n            || mpos.y > y + height || mpos.y < y) {\n            return false;\n          }\n      } else {\n        if(mpos.x < x || mpos.x > x + width\n            || mpos.y > y || mpos.y < y - height) {\n            return false;\n          }\n      }\n      //deep check\n      for(var i=0, l=dimArray.length; i<l; i++) {\n        var dimi = dimArray[i];\n        if(horz) {\n          var limit = y + fixedDim * i;\n          if(mpos.x <= x+ dimi && mpos.y >= limit && mpos.y <= limit + fixedDim) {\n            return {\n              'name': node.getData('stringArray')[i],\n              'color': node.getData('colorArray')[i],\n              'value': node.getData('valueArray')[i]\n            };\n          }\n        } else {\n          var limit = x + fixedDim * i;\n          if(mpos.x >= limit && mpos.x <= limit + fixedDim && mpos.y >= y - dimi) {\n            return {\n              'name': node.getData('stringArray')[i],\n              'color': node.getData('colorArray')[i],\n              'value': node.getData('valueArray')[i]\n            };\n          }\n        }\n      }\n      return false;\n    }\n  }\n});\n\n/*\n  Class: BarChart\n\n  A visualization that displays stacked bar charts.\n\n  Constructor Options:\n\n  See <Options.BarChart>.\n\n*/\n$jit.BarChart = new Class({\n  st: null,\n  colors: [\"#416D9C\", \"#70A35E\", \"#EBB056\", \"#C74243\", \"#83548B\", \"#909291\", \"#557EAA\"],\n  selected: {},\n  busy: false,\n\n  initialize: function(opt) {\n    this.controller = this.config =\n      $.merge(Options(\"Canvas\", \"Label\", \"BarChart\"), {\n        Label: { type: 'Native' }\n      }, opt);\n    //set functions for showLabels and showAggregates\n    var showLabels = this.config.showLabels,\n        typeLabels = $.type(showLabels),\n        showAggregates = this.config.showAggregates,\n        typeAggregates = $.type(showAggregates);\n    this.config.showLabels = typeLabels == 'function'? showLabels : $.lambda(showLabels);\n    this.config.showAggregates = typeAggregates == 'function'? showAggregates : $.lambda(showAggregates);\n\n    this.initializeViz();\n  },\n\n  initializeViz: function() {\n    var config = this.config, that = this;\n    var nodeType = config.type.split(\":\")[0],\n        horz = config.orientation == 'horizontal',\n        nodeLabels = {};\n\n    var st = new $jit.ST({\n      injectInto: config.injectInto,\n      orientation: horz? 'left' : 'bottom',\n      levelDistance: 0,\n      siblingOffset: config.barsOffset,\n      subtreeOffset: 0,\n      withLabels: config.Label.type != 'Native',\n      useCanvas: config.useCanvas,\n      Label: {\n        type: config.Label.type\n      },\n      Node: {\n        overridable: true,\n        type: 'barchart-' + nodeType,\n        align: 'left',\n        width: 1,\n        height: 1\n      },\n      Edge: {\n        type: 'none'\n      },\n      Tips: {\n        enable: config.Tips.enable,\n        type: 'Native',\n        force: true,\n        onShow: function(tip, node, contains) {\n          var elem = contains;\n          config.Tips.onShow(tip, elem, node);\n        }\n      },\n      Events: {\n        enable: true,\n        type: 'Native',\n        onClick: function(node, eventInfo, evt) {\n          if(!config.Events.enable) return;\n          var elem = eventInfo.getContains();\n          config.Events.onClick(elem, eventInfo, evt);\n        },\n        onMouseMove: function(node, eventInfo, evt) {\n          if(!config.hoveredColor) return;\n          if(node) {\n            var elem = eventInfo.getContains();\n            that.select(node.id, elem.name, elem.index);\n          } else {\n            that.select(false, false, false);\n          }\n        }\n      },\n      onCreateLabel: function(domElement, node) {\n        var labelConf = config.Label,\n            valueArray = node.getData('valueArray'),\n            acum = $.reduce(valueArray, function(x, y) { return x + y; }, 0);\n        var nlbs = {\n          wrapper: document.createElement('div'),\n          aggregate: document.createElement('div'),\n          label: document.createElement('div')\n        };\n        var wrapper = nlbs.wrapper,\n            label = nlbs.label,\n            aggregate = nlbs.aggregate,\n            wrapperStyle = wrapper.style,\n            labelStyle = label.style,\n            aggregateStyle = aggregate.style;\n        //store node labels\n        nodeLabels[node.id] = nlbs;\n        //append labels\n        wrapper.appendChild(label);\n        wrapper.appendChild(aggregate);\n        if(!config.showLabels(node.name, acum, node)) {\n          labelStyle.display = 'none';\n        }\n        if(!config.showAggregates(node.name, acum, node)) {\n          aggregateStyle.display = 'none';\n        }\n        wrapperStyle.position = 'relative';\n        wrapperStyle.overflow = 'visible';\n        wrapperStyle.fontSize = labelConf.size + 'px';\n        wrapperStyle.fontFamily = labelConf.family;\n        wrapperStyle.color = labelConf.color;\n        wrapperStyle.textAlign = 'center';\n        aggregateStyle.position = labelStyle.position = 'absolute';\n\n        domElement.style.width = node.getData('width') + 'px';\n        domElement.style.height = node.getData('height') + 'px';\n        aggregateStyle.left = labelStyle.left =  '0px';\n\n        label.innerHTML = node.name;\n\n        domElement.appendChild(wrapper);\n      },\n      onPlaceLabel: function(domElement, node) {\n        if(!nodeLabels[node.id]) return;\n        var labels = nodeLabels[node.id],\n            wrapperStyle = labels.wrapper.style,\n            labelStyle = labels.label.style,\n            aggregateStyle = labels.aggregate.style,\n            grouped = config.type.split(':')[0] == 'grouped',\n            horz = config.orientation == 'horizontal',\n            dimArray = node.getData('dimArray'),\n            valArray = node.getData('valueArray'),\n            width = (grouped && horz)? Math.max.apply(null, dimArray) : node.getData('width'),\n            height = (grouped && !horz)? Math.max.apply(null, dimArray) : node.getData('height'),\n            font = parseInt(wrapperStyle.fontSize, 10),\n            domStyle = domElement.style;\n\n\n        if(dimArray && valArray) {\n          wrapperStyle.width = aggregateStyle.width = labelStyle.width = domElement.style.width = width + 'px';\n          for(var i=0, l=valArray.length, acum=0; i<l; i++) {\n            if(dimArray[i] > 0) {\n              acum+= valArray[i];\n            }\n          }\n          if(config.showLabels(node.name, acum, node)) {\n            labelStyle.display = '';\n          } else {\n            labelStyle.display = 'none';\n          }\n          if(config.showAggregates(node.name, acum, node)) {\n            aggregateStyle.display = '';\n          } else {\n            aggregateStyle.display = 'none';\n          }\n          if(config.orientation == 'horizontal') {\n            aggregateStyle.textAlign = 'right';\n            labelStyle.textAlign = 'left';\n            labelStyle.textIndex = aggregateStyle.textIndent = config.labelOffset + 'px';\n            aggregateStyle.top = labelStyle.top = (height-font)/2 + 'px';\n            domElement.style.height = wrapperStyle.height = height + 'px';\n          } else {\n            aggregateStyle.top = (-font - config.labelOffset) + 'px';\n            labelStyle.top = (config.labelOffset + height) + 'px';\n            domElement.style.top = parseInt(domElement.style.top, 10) - height + 'px';\n            domElement.style.height = wrapperStyle.height = height + 'px';\n          }\n          labels.aggregate.innerHTML = acum;\n        }\n      }\n    });\n\n    var size = st.canvas.getSize();\n    if(horz) {\n      st.config.offsetX = + size.width/2 - config.offset\n        - (config.showLabels && (config.labelOffset + config.Label.size));\n    } else {\n      st.config.offsetY = -size.height/2 + config.offset\n        + (config.showLabels && (config.labelOffset + config.Label.size));\n    }\n    this.st = st;\n    this.canvas = this.st.canvas;\n  },\n\n  /*\n    Method: loadJSON\n\n    Loads JSON data into the visualization.\n\n    Parameters:\n\n    json - The JSON data format. This format is described in <http://blog.thejit.org/2010/04/24/new-javascript-infovis-toolkit-visualizations/#json-data-format>.\n\n    Example:\n    (start code js)\n    var barChart = new $jit.BarChart(options);\n    barChart.loadJSON(json);\n    (end code)\n */\n  loadJSON: function(json) {\n    if(this.busy) return;\n    this.busy = true;\n\n    var prefix = $.time(),\n        ch = [],\n        st = this.st,\n        name = $.splat(json.label),\n        color = $.splat(json.color || this.colors),\n        config = this.config,\n        gradient = !!config.type.split(\":\")[1],\n        animate = config.animate,\n        horz = config.orientation == 'horizontal',\n        that = this;\n\n    for(var i=0, values=json.values, l=values.length; i<l; i++) {\n      var val = values[i]\n      var valArray = $.splat(values[i].values);\n      var acum = 0;\n      ch.push({\n        'id': prefix + val.label,\n        'name': val.label,\n        'data': {\n          'value': valArray,\n          '$valueArray': valArray,\n          '$colorArray': color,\n          '$stringArray': name,\n          '$gradient': gradient,\n          '$config': config\n        },\n        'children': []\n      });\n    }\n    var root = {\n      'id': prefix + '$root',\n      'name': '',\n      'data': {\n        '$type': 'none',\n        '$width': 1,\n        '$height': 1\n      },\n      'children': ch\n    };\n    st.loadJSON(root);\n\n    this.normalizeDims();\n    st.compute();\n    st.select(st.root);\n    if(animate) {\n      if(horz) {\n        st.fx.animate({\n          modes: ['node-property:width:dimArray'],\n          duration:1500,\n          onComplete: function() {\n            that.busy = false;\n          }\n        });\n      } else {\n        st.fx.animate({\n          modes: ['node-property:height:dimArray'],\n          duration:1500,\n          onComplete: function() {\n            that.busy = false;\n          }\n        });\n      }\n    } else {\n      this.busy = false;\n    }\n  },\n\n  /*\n    Method: updateJSON\n\n    Use this method when updating values for the current JSON data. If the items specified by the JSON data already exist in the graph then their values will be updated.\n\n    Parameters:\n\n    json - (object) JSON data to be updated. The JSON format corresponds to the one described in <BarChart.loadJSON>.\n    onComplete - (object) A callback object to be called when the animation transition when updating the data end.\n\n    Example:\n\n    (start code js)\n    barChart.updateJSON(json, {\n      onComplete: function() {\n        alert('update complete!');\n      }\n    });\n    (end code)\n */\n  updateJSON: function(json, onComplete) {\n    if(this.busy) return;\n    this.busy = true;\n\n    var st = this.st;\n    var graph = st.graph;\n    var values = json.values;\n    var animate = this.config.animate;\n    var that = this;\n    var horz = this.config.orientation == 'horizontal';\n    $.each(values, function(v) {\n      var n = graph.getByName(v.label);\n      if(n) {\n        n.setData('valueArray', $.splat(v.values));\n        if(json.label) {\n          n.setData('stringArray', $.splat(json.label));\n        }\n      }\n    });\n    this.normalizeDims();\n    st.compute();\n    st.select(st.root);\n    if(animate) {\n      if(horz) {\n        st.fx.animate({\n          modes: ['node-property:width:dimArray'],\n          duration:1500,\n          onComplete: function() {\n            that.busy = false;\n            onComplete && onComplete.onComplete();\n          }\n        });\n      } else {\n        st.fx.animate({\n          modes: ['node-property:height:dimArray'],\n          duration:1500,\n          onComplete: function() {\n            that.busy = false;\n            onComplete && onComplete.onComplete();\n          }\n        });\n      }\n    }\n  },\n\n  //adds the little brown bar when hovering the node\n  select: function(id, name) {\n    if(!this.config.hoveredColor) return;\n    var s = this.selected;\n    if(s.id != id || s.name != name) {\n      s.id = id;\n      s.name = name;\n      s.color = this.config.hoveredColor;\n      this.st.graph.eachNode(function(n) {\n        if(id == n.id) {\n          n.setData('border', s);\n        } else {\n          n.setData('border', false);\n        }\n      });\n      this.st.plot();\n    }\n  },\n\n  /*\n    Method: getLegend\n\n    Returns an object containing as keys the legend names and as values hex strings with color values.\n\n    Example:\n\n    (start code js)\n    var legend = barChart.getLegend();\n    (end code)\n  */\n  getLegend: function() {\n    var legend = {};\n    var n;\n    this.st.graph.getNode(this.st.root).eachAdjacency(function(adj) {\n      n = adj.nodeTo;\n    });\n    var colors = n.getData('colorArray'),\n        len = colors.length;\n    $.each(n.getData('stringArray'), function(s, i) {\n      legend[s] = colors[i % len];\n    });\n    return legend;\n  },\n\n  /*\n    Method: getMaxValue\n\n    Returns the maximum accumulated value for the stacks. This method is used for normalizing the graph heights according to the canvas height.\n\n    Example:\n\n    (start code js)\n    var ans = barChart.getMaxValue();\n    (end code)\n\n    In some cases it could be useful to override this method to normalize heights for a group of BarCharts, like when doing small multiples.\n\n    Example:\n\n    (start code js)\n    //will return 100 for all BarChart instances,\n    //displaying all of them with the same scale\n    $jit.BarChart.implement({\n      'getMaxValue': function() {\n        return 100;\n      }\n    });\n    (end code)\n\n  */\n  getMaxValue: function() {\n    var maxValue = 0, stacked = this.config.type.split(':')[0] == 'stacked';\n    this.st.graph.eachNode(function(n) {\n      var valArray = n.getData('valueArray'),\n          acum = 0;\n      if(!valArray) return;\n      if(stacked) {\n        $.each(valArray, function(v) {\n          acum += +v;\n        });\n      } else {\n        acum = Math.max.apply(null, valArray);\n      }\n      maxValue = maxValue>acum? maxValue:acum;\n    });\n    return maxValue;\n  },\n\n  setBarType: function(type) {\n    this.config.type = type;\n    this.st.config.Node.type = 'barchart-' + type.split(':')[0];\n  },\n\n  normalizeDims: function() {\n    //number of elements\n    var root = this.st.graph.getNode(this.st.root), l=0;\n    root.eachAdjacency(function() {\n      l++;\n    });\n    var maxValue = this.getMaxValue(),\n        size = this.st.canvas.getSize(),\n        config = this.config,\n        offset = config.offset,\n        horz = config.orientation == 'horizontal',\n        fixedDim = (size[horz? 'height':'width'] - 2 * offset - (l -1) * config.barsOffset) / l,\n        animate = config.animate,\n        height = size[horz? 'width':'height'] - 2 * offset\n          - (!horz && config.showAggregates && (config.Label.size + config.labelOffset))\n          - (config.showLabels && (config.Label.size + config.labelOffset)),\n        dim1 = horz? 'height':'width',\n        dim2 = horz? 'width':'height';\n    this.st.graph.eachNode(function(n) {\n      var acum = 0, animateValue = [];\n      $.each(n.getData('valueArray'), function(v) {\n        acum += +v;\n        animateValue.push(0);\n      });\n      n.setData(dim1, fixedDim);\n      if(animate) {\n        n.setData(dim2, acum * height / maxValue, 'end');\n        n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {\n          return n * height / maxValue;\n        }), 'end');\n        var dimArray = n.getData('dimArray');\n        if(!dimArray) {\n          n.setData('dimArray', animateValue);\n        }\n      } else {\n        n.setData(dim2, acum * height / maxValue);\n        n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {\n          return n * height / maxValue;\n        }));\n      }\n    });\n  }\n});\n\n/*\n * File: Options.PieChart.js\n *\n*/\n/*\n  Object: Options.PieChart\n\n  <PieChart> options.\n  Other options included in the PieChart are <Options.Canvas>, <Options.Label>, <Options.Tips> and <Options.Events>.\n\n  Syntax:\n\n  (start code js)\n\n  Options.PieChart = {\n    animate: true,\n    offset: 25,\n    sliceOffset:0,\n    labelOffset: 3,\n    type: 'stacked',\n    hoveredColor: '#9fd4ff',\n    showLabels: true,\n    resizeLabels: false,\n    updateHeights: false\n  };\n\n  (end code)\n\n  Example:\n\n  (start code js)\n\n  var pie = new $jit.PieChart({\n    animate: true,\n    sliceOffset: 5,\n    type: 'stacked:gradient'\n  });\n\n  (end code)\n\n  Parameters:\n\n  animate - (boolean) Default's *true*. Whether to add animated transitions when plotting/updating the visualization.\n  offset - (number) Default's *25*. Adds margin between the visualization and the canvas.\n  sliceOffset - (number) Default's *0*. Separation between the center of the canvas and each pie slice.\n  labelOffset - (number) Default's *3*. Adds margin between the label and the default place where it should be drawn.\n  type - (string) Default's *'stacked'*. Stack style. Posible values are 'stacked', 'stacked:gradient' to add gradients.\n  hoveredColor - (boolean|string) Default's *'#9fd4ff'*. Sets the selected color for a hovered pie stack.\n  showLabels - (boolean) Default's *true*. Display the name of the slots.\n  resizeLabels - (boolean|number) Default's *false*. Resize the pie labels according to their stacked values. Set a number for *resizeLabels* to set a font size minimum.\n  updateHeights - (boolean) Default's *false*. Only for mono-valued (most common) pie charts. Resize the height of the pie slices according to their current values.\n\n*/\nOptions.PieChart = {\n  $extend: true,\n\n  animate: true,\n  offset: 25, // page offset\n  sliceOffset:0,\n  labelOffset: 3, // label offset\n  type: 'stacked', // gradient\n  hoveredColor: '#9fd4ff',\n  Events: {\n    enable: false,\n    onClick: $.empty\n  },\n  Tips: {\n    enable: false,\n    onShow: $.empty,\n    onHide: $.empty\n  },\n  showLabels: true,\n  resizeLabels: false,\n\n  //only valid for mono-valued datasets\n  updateHeights: false\n};\n\n/*\n * File: Sunburst.js\n */\n\n/*\n   Class: Sunburst\n\n   A radial space filling tree visualization.\n\n   Inspired by:\n\n   Sunburst <http://www.cc.gatech.edu/gvu/ii/sunburst/>.\n\n   Note:\n\n   This visualization was built and engineered from scratch, taking only the paper as inspiration, and only shares some features with the visualization described in the paper.\n\n  Implements:\n\n  All <Loader> methods\n\n   Constructor Options:\n\n   Inherits options from\n\n   - <Options.Canvas>\n   - <Options.Controller>\n   - <Options.Node>\n   - <Options.Edge>\n   - <Options.Label>\n   - <Options.Events>\n   - <Options.Tips>\n   - <Options.NodeStyles>\n   - <Options.Navigation>\n\n   Additionally, there are other parameters and some default values changed\n\n   interpolation - (string) Default's *linear*. Describes the way nodes are interpolated. Possible values are 'linear' and 'polar'.\n   levelDistance - (number) Default's *100*. The distance between levels of the tree.\n   Node.type - Described in <Options.Node>. Default's to *multipie*.\n   Node.height - Described in <Options.Node>. Default's *0*.\n   Edge.type - Described in <Options.Edge>. Default's *none*.\n   Label.textAlign - Described in <Options.Label>. Default's *start*.\n   Label.textBaseline - Described in <Options.Label>. Default's *middle*.\n\n   Instance Properties:\n\n   canvas - Access a <Canvas> instance.\n   graph - Access a <Graph> instance.\n   op - Access a <Sunburst.Op> instance.\n   fx - Access a <Sunburst.Plot> instance.\n   labels - Access a <Sunburst.Label> interface implementation.\n\n*/\n\n$jit.Sunburst = new Class({\n\n  Implements: [ Loader, Extras, Layouts.Radial ],\n\n  initialize: function(controller) {\n    var $Sunburst = $jit.Sunburst;\n\n    var config = {\n      interpolation: 'linear',\n      levelDistance: 100,\n      Node: {\n        'type': 'multipie',\n        'height':0\n      },\n      Edge: {\n        'type': 'none'\n      },\n      Label: {\n        textAlign: 'start',\n        textBaseline: 'middle'\n      }\n    };\n\n    this.controller = this.config = $.merge(Options(\"Canvas\", \"Node\", \"Edge\",\n        \"Fx\", \"Tips\", \"NodeStyles\", \"Events\", \"Navigation\", \"Controller\", \"Label\"), config, controller);\n\n    var canvasConfig = this.config;\n    if(canvasConfig.useCanvas) {\n      this.canvas = canvasConfig.useCanvas;\n      this.config.labelContainer = this.canvas.id + '-label';\n    } else {\n      if(canvasConfig.background) {\n        canvasConfig.background = $.merge({\n          type: 'Circles'\n        }, canvasConfig.background);\n      }\n      this.canvas = new Canvas(this, canvasConfig);\n      this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';\n    }\n\n    this.graphOptions = {\n      'complex': false,\n      'Node': {\n        'selected': false,\n        'exist': true,\n        'drawn': true\n      }\n    };\n    this.graph = new Graph(this.graphOptions, this.config.Node,\n        this.config.Edge);\n    this.labels = new $Sunburst.Label[canvasConfig.Label.type](this);\n    this.fx = new $Sunburst.Plot(this);\n    this.op = new $Sunburst.Op(this);\n    this.json = null;\n    this.root = null;\n    this.rotated = null;\n    this.busy = false;\n    // initialize extras\n    this.initializeExtras();\n  },\n\n  /*\n\n    createLevelDistanceFunc\n\n    Returns the levelDistance function used for calculating a node distance\n    to its origin. This function returns a function that is computed\n    per level and not per node, such that all nodes with the same depth will have the\n    same distance to the origin. The resulting function gets the\n    parent node as parameter and returns a float.\n\n   */\n  createLevelDistanceFunc: function() {\n    var ld = this.config.levelDistance;\n    return function(elem) {\n      return (elem._depth + 1) * ld;\n    };\n  },\n\n  /*\n     Method: refresh\n\n     Computes positions and plots the tree.\n\n   */\n  refresh: function() {\n    this.compute();\n    this.plot();\n  },\n\n  /*\n   reposition\n\n   An alias for computing new positions to _endPos_\n\n   See also:\n\n   <Sunburst.compute>\n\n  */\n  reposition: function() {\n    this.compute('end');\n  },\n\n  /*\n  Method: rotate\n\n  Rotates the graph so that the selected node is horizontal on the right.\n\n  Parameters:\n\n  node - (object) A <Graph.Node>.\n  method - (string) Whether to perform an animation or just replot the graph. Possible values are \"replot\" or \"animate\".\n  opt - (object) Configuration options merged with this visualization configuration options.\n\n  See also:\n\n  <Sunburst.rotateAngle>\n\n  */\n  rotate: function(node, method, opt) {\n    var theta = node.getPos(opt.property || 'current').getp(true).theta;\n    this.rotated = node;\n    this.rotateAngle(-theta, method, opt);\n  },\n\n  /*\n  Method: rotateAngle\n\n  Rotates the graph of an angle theta.\n\n   Parameters:\n\n   node - (object) A <Graph.Node>.\n   method - (string) Whether to perform an animation or just replot the graph. Possible values are \"replot\" or \"animate\".\n   opt - (object) Configuration options merged with this visualization configuration options.\n\n   See also:\n\n   <Sunburst.rotate>\n\n  */\n  rotateAngle: function(theta, method, opt) {\n    var that = this;\n    var options = $.merge(this.config, opt || {}, {\n      modes: [ 'polar' ]\n    });\n    var prop = opt.property || (method === \"animate\" ? 'end' : 'current');\n    if(method === 'animate') {\n      this.fx.animation.pause();\n    }\n    this.graph.eachNode(function(n) {\n      var p = n.getPos(prop);\n      p.theta += theta;\n      if (p.theta < 0) {\n        p.theta += Math.PI * 2;\n      }\n    });\n    if (method == 'animate') {\n      this.fx.animate(options);\n    } else if (method == 'replot') {\n      this.fx.plot();\n      this.busy = false;\n    }\n  },\n\n  /*\n   Method: plot\n\n   Plots the Sunburst. This is a shortcut to *fx.plot*.\n  */\n  plot: function() {\n    this.fx.plot();\n  }\n});\n\n$jit.Sunburst.$extend = true;\n\n(function(Sunburst) {\n\n  /*\n     Class: Sunburst.Op\n\n     Custom extension of <Graph.Op>.\n\n     Extends:\n\n     All <Graph.Op> methods\n\n     See also:\n\n     <Graph.Op>\n\n  */\n  Sunburst.Op = new Class( {\n\n    Implements: Graph.Op,\n\n    initialize: function(viz) {\n      this.viz = viz;\n    }\n  });\n\n  /*\n     Class: Sunburst.Plot\n\n    Custom extension of <Graph.Plot>.\n\n    Extends:\n\n    All <Graph.Plot> methods\n\n    See also:\n\n    <Graph.Plot>\n\n  */\n  Sunburst.Plot = new Class( {\n\n    Implements: Graph.Plot,\n\n    initialize: function(viz) {\n      this.viz = viz;\n      this.config = viz.config;\n      this.node = viz.config.Node;\n      this.edge = viz.config.Edge;\n      this.animation = new Animation;\n      this.nodeTypes = new Sunburst.Plot.NodeTypes;\n      this.edgeTypes = new Sunburst.Plot.EdgeTypes;\n      this.labels = viz.labels;\n    }\n  });\n\n  /*\n    Class: Sunburst.Label\n\n    Custom extension of <Graph.Label>.\n    Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.\n\n    Extends:\n\n    All <Graph.Label> methods and subclasses.\n\n    See also:\n\n    <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.\n\n   */\n  Sunburst.Label = {};\n\n  /*\n     Sunburst.Label.Native\n\n     Custom extension of <Graph.Label.Native>.\n\n     Extends:\n\n     All <Graph.Label.Native> methods\n\n     See also:\n\n     <Graph.Label.Native>\n  */\n  Sunburst.Label.Native = new Class( {\n    Implements: Graph.Label.Native,\n\n    initialize: function(viz) {\n      this.viz = viz;\n      this.label = viz.config.Label;\n      this.config = viz.config;\n    },\n\n    renderLabel: function(canvas, node, controller) {\n      var span = node.getData('span');\n      if(span < Math.PI /2 && Math.tan(span) *\n          this.config.levelDistance * node._depth < 10) {\n        return;\n      }\n      var ctx = canvas.getCtx();\n      var measure = ctx.measureText(node.name);\n      if (node.id == this.viz.root) {\n        var x = -measure.width / 2, y = 0, thetap = 0;\n        var ld = 0;\n      } else {\n        var indent = 5;\n        var ld = controller.levelDistance - indent;\n        var clone = node.pos.clone();\n        clone.rho += indent;\n        var p = clone.getp(true);\n        var ct = clone.getc(true);\n        var x = ct.x, y = ct.y;\n        // get angle in degrees\n        var pi = Math.PI;\n        var cond = (p.theta > pi / 2 && p.theta < 3 * pi / 2);\n        var thetap = cond ? p.theta + pi : p.theta;\n        if (cond) {\n          x -= Math.abs(Math.cos(p.theta) * measure.width);\n          y += Math.sin(p.theta) * measure.width;\n        } else if (node.id == this.viz.root) {\n          x -= measure.width / 2;\n        }\n      }\n      ctx.save();\n      ctx.translate(x, y);\n      ctx.rotate(thetap);\n      ctx.fillText(node.name, 0, 0);\n      ctx.restore();\n    }\n  });\n\n  /*\n     Sunburst.Label.SVG\n\n    Custom extension of <Graph.Label.SVG>.\n\n    Extends:\n\n    All <Graph.Label.SVG> methods\n\n    See also:\n\n    <Graph.Label.SVG>\n\n  */\n  Sunburst.Label.SVG = new Class( {\n    Implements: Graph.Label.SVG,\n\n    initialize: function(viz) {\n      this.viz = viz;\n    },\n\n    /*\n       placeLabel\n\n       Overrides abstract method placeLabel in <Graph.Plot>.\n\n       Parameters:\n\n       tag - A DOM label element.\n       node - A <Graph.Node>.\n       controller - A configuration/controller object passed to the visualization.\n\n     */\n    placeLabel: function(tag, node, controller) {\n      var pos = node.pos.getc(true), viz = this.viz, canvas = this.viz.canvas;\n      var radius = canvas.getSize();\n      var labelPos = {\n        x: Math.round(pos.x + radius.width / 2),\n        y: Math.round(pos.y + radius.height / 2)\n      };\n      tag.setAttribute('x', labelPos.x);\n      tag.setAttribute('y', labelPos.y);\n\n      var bb = tag.getBBox();\n      if (bb) {\n        // center the label\n    var x = tag.getAttribute('x');\n    var y = tag.getAttribute('y');\n    // get polar coordinates\n    var p = node.pos.getp(true);\n    // get angle in degrees\n    var pi = Math.PI;\n    var cond = (p.theta > pi / 2 && p.theta < 3 * pi / 2);\n    if (cond) {\n      tag.setAttribute('x', x - bb.width);\n      tag.setAttribute('y', y - bb.height);\n    } else if (node.id == viz.root) {\n      tag.setAttribute('x', x - bb.width / 2);\n    }\n\n    var thetap = cond ? p.theta + pi : p.theta;\n    if(node._depth)\n      tag.setAttribute('transform', 'rotate(' + thetap * 360 / (2 * pi) + ' ' + x\n          + ' ' + y + ')');\n  }\n\n  controller.onPlaceLabel(tag, node);\n}\n  });\n\n  /*\n     Sunburst.Label.HTML\n\n     Custom extension of <Graph.Label.HTML>.\n\n     Extends:\n\n     All <Graph.Label.HTML> methods.\n\n     See also:\n\n     <Graph.Label.HTML>\n\n  */\n  Sunburst.Label.HTML = new Class( {\n    Implements: Graph.Label.HTML,\n\n    initialize: function(viz) {\n      this.viz = viz;\n    },\n    /*\n       placeLabel\n\n       Overrides abstract method placeLabel in <Graph.Plot>.\n\n       Parameters:\n\n       tag - A DOM label element.\n       node - A <Graph.Node>.\n       controller - A configuration/controller object passed to the visualization.\n\n     */\n    placeLabel: function(tag, node, controller) {\n      var pos = node.pos.clone(),\n          canvas = this.viz.canvas,\n          height = node.getData('height'),\n          ldist = ((height || node._depth == 0)? height : this.viz.config.levelDistance) /2,\n          radius = canvas.getSize();\n      pos.rho += ldist;\n      pos = pos.getc(true);\n\n      var labelPos = {\n        x: Math.round(pos.x + radius.width / 2),\n        y: Math.round(pos.y + radius.height / 2)\n      };\n\n      var style = tag.style;\n      style.left = labelPos.x + 'px';\n      style.top = labelPos.y + 'px';\n      style.display = this.fitsInCanvas(labelPos, canvas) ? '' : 'none';\n\n      controller.onPlaceLabel(tag, node);\n    }\n  });\n\n  /*\n    Class: Sunburst.Plot.NodeTypes\n\n    This class contains a list of <Graph.Node> built-in types.\n    Node types implemented are 'none', 'pie', 'multipie', 'gradient-pie' and 'gradient-multipie'.\n\n    You can add your custom node types, customizing your visualization to the extreme.\n\n    Example:\n\n    (start code js)\n      Sunburst.Plot.NodeTypes.implement({\n        'mySpecialType': {\n          'render': function(node, canvas) {\n            //print your custom node to canvas\n          },\n          //optional\n          'contains': function(node, pos) {\n            //return true if pos is inside the node or false otherwise\n          }\n        }\n      });\n    (end code)\n\n  */\n  Sunburst.Plot.NodeTypes = new Class( {\n    'none': {\n      'render': $.empty,\n      'contains': $.lambda(false),\n      'anglecontains': function(node, pos) {\n        var span = node.getData('span') / 2, theta = node.pos.theta;\n        var begin = theta - span, end = theta + span;\n        if (begin < 0)\n          begin += Math.PI * 2;\n        var atan = Math.atan2(pos.y, pos.x);\n        if (atan < 0)\n          atan += Math.PI * 2;\n        if (begin > end) {\n          return (atan > begin && atan <= Math.PI * 2) || atan < end;\n        } else {\n          return atan > begin && atan < end;\n        }\n      }\n    },\n\n    'pie': {\n      'render': function(node, canvas) {\n        var span = node.getData('span') / 2, theta = node.pos.theta;\n        var begin = theta - span, end = theta + span;\n        var polarNode = node.pos.getp(true);\n        var polar = new Polar(polarNode.rho, begin);\n        var p1coord = polar.getc(true);\n        polar.theta = end;\n        var p2coord = polar.getc(true);\n\n        var ctx = canvas.getCtx();\n        ctx.beginPath();\n        ctx.moveTo(0, 0);\n        ctx.lineTo(p1coord.x, p1coord.y);\n        ctx.moveTo(0, 0);\n        ctx.lineTo(p2coord.x, p2coord.y);\n        ctx.moveTo(0, 0);\n        ctx.arc(0, 0, polarNode.rho * node.getData('dim-quotient'), begin, end,\n            false);\n        ctx.fill();\n      },\n      'contains': function(node, pos) {\n        if (this.nodeTypes['none'].anglecontains.call(this, node, pos)) {\n          var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y);\n          var ld = this.config.levelDistance, d = node._depth;\n          return (rho <= ld * d);\n        }\n        return false;\n      }\n    },\n    'multipie': {\n      'render': function(node, canvas) {\n        var height = node.getData('height');\n        var ldist = height? height : this.config.levelDistance;\n        var span = node.getData('span') / 2, theta = node.pos.theta;\n        var begin = theta - span, end = theta + span;\n        var polarNode = node.pos.getp(true);\n\n        var polar = new Polar(polarNode.rho, begin);\n        var p1coord = polar.getc(true);\n\n        polar.theta = end;\n        var p2coord = polar.getc(true);\n\n        polar.rho += ldist;\n        var p3coord = polar.getc(true);\n\n        polar.theta = begin;\n        var p4coord = polar.getc(true);\n\n        var ctx = canvas.getCtx();\n        ctx.moveTo(0, 0);\n        ctx.beginPath();\n        ctx.arc(0, 0, polarNode.rho, begin, end, false);\n        ctx.arc(0, 0, polarNode.rho + ldist, end, begin, true);\n        ctx.moveTo(p1coord.x, p1coord.y);\n        ctx.lineTo(p4coord.x, p4coord.y);\n        ctx.moveTo(p2coord.x, p2coord.y);\n        ctx.lineTo(p3coord.x, p3coord.y);\n        ctx.fill();\n\n        if (node.collapsed) {\n          ctx.save();\n          ctx.lineWidth = 2;\n          ctx.moveTo(0, 0);\n          ctx.beginPath();\n          ctx.arc(0, 0, polarNode.rho + ldist + 5, end - 0.01, begin + 0.01,\n              true);\n          ctx.stroke();\n          ctx.restore();\n        }\n      },\n      'contains': function(node, pos) {\n        if (this.nodeTypes['none'].anglecontains.call(this, node, pos)) {\n          var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y);\n          var height = node.getData('height');\n          var ldist = height? height : this.config.levelDistance;\n          var ld = this.config.levelDistance, d = node._depth;\n          return (rho >= ld * d) && (rho <= (ld * d + ldist));\n        }\n        return false;\n      }\n    },\n\n    'gradient-multipie': {\n      'render': function(node, canvas) {\n        var ctx = canvas.getCtx();\n        var height = node.getData('height');\n        var ldist = height? height : this.config.levelDistance;\n        var radialGradient = ctx.createRadialGradient(0, 0, node.getPos().rho,\n            0, 0, node.getPos().rho + ldist);\n\n        var colorArray = $.hexToRgb(node.getData('color')), ans = [];\n        $.each(colorArray, function(i) {\n          ans.push(parseInt(i * 0.5, 10));\n        });\n        var endColor = $.rgbToHex(ans);\n        radialGradient.addColorStop(0, endColor);\n        radialGradient.addColorStop(1, node.getData('color'));\n        ctx.fillStyle = radialGradient;\n        this.nodeTypes['multipie'].render.call(this, node, canvas);\n      },\n      'contains': function(node, pos) {\n        return this.nodeTypes['multipie'].contains.call(this, node, pos);\n      }\n    },\n\n    'gradient-pie': {\n      'render': function(node, canvas) {\n        var ctx = canvas.getCtx();\n        var radialGradient = ctx.createRadialGradient(0, 0, 0, 0, 0, node\n            .getPos().rho);\n\n        var colorArray = $.hexToRgb(node.getData('color')), ans = [];\n        $.each(colorArray, function(i) {\n          ans.push(parseInt(i * 0.5, 10));\n        });\n        var endColor = $.rgbToHex(ans);\n        radialGradient.addColorStop(1, endColor);\n        radialGradient.addColorStop(0, node.getData('color'));\n        ctx.fillStyle = radialGradient;\n        this.nodeTypes['pie'].render.call(this, node, canvas);\n      },\n      'contains': function(node, pos) {\n        return this.nodeTypes['pie'].contains.call(this, node, pos);\n      }\n    }\n  });\n\n  /*\n    Class: Sunburst.Plot.EdgeTypes\n\n    This class contains a list of <Graph.Adjacence> built-in types.\n    Edge types implemented are 'none', 'line' and 'arrow'.\n\n    You can add your custom edge types, customizing your visualization to the extreme.\n\n    Example:\n\n    (start code js)\n      Sunburst.Plot.EdgeTypes.implement({\n        'mySpecialType': function(adj, canvas) {\n          //print your custom edge to canvas\n        }\n      });\n    (end code)\n\n  */\n  Sunburst.Plot.EdgeTypes = new Class({\n    'none': $.empty,\n    'line': function(adj, canvas) {\n      var from = adj.nodeFrom.pos.getc(true),\n          to = adj.nodeTo.pos.getc(true);\n      this.edgeHelper.line(from, to, canvas);\n    },\n    'arrow': function(adj, canvas) {\n      var from = adj.nodeFrom.pos.getc(true),\n          to = adj.nodeTo.pos.getc(true),\n          dim = adj.getData('dim'),\n          direction = adj.data.$direction,\n          inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id);\n      this.edgeHelper.arrow(from, to, dim, inv, canvas);\n    },\n    'hyperline': function(adj, canvas) {\n      var from = adj.nodeFrom.pos.getc(),\n          to = adj.nodeTo.pos.getc(),\n          dim = Math.max(from.norm(), to.norm());\n      this.edgeHelper.hyperline(from.$scale(1/dim), to.$scale(1/dim), dim, canvas);\n    }\n  });\n\n})($jit.Sunburst);\n\n\n/*\n * File: PieChart.js\n *\n*/\n\n$jit.Sunburst.Plot.NodeTypes.implement({\n  'piechart-stacked' : {\n    'render' : function(node, canvas) {\n      var pos = node.pos.getp(true),\n          dimArray = node.getData('dimArray'),\n          valueArray = node.getData('valueArray'),\n          colorArray = node.getData('colorArray'),\n          colorLength = colorArray.length,\n          stringArray = node.getData('stringArray'),\n          span = node.getData('span') / 2,\n          theta = node.pos.theta,\n          begin = theta - span,\n          end = theta + span,\n          polar = new Polar;\n\n      var ctx = canvas.getCtx(),\n          opt = {},\n          gradient = node.getData('gradient'),\n          border = node.getData('border'),\n          config = node.getData('config'),\n          showLabels = config.showLabels,\n          resizeLabels = config.resizeLabels,\n          label = config.Label;\n\n      var xpos = config.sliceOffset * Math.cos((begin + end) /2);\n      var ypos = config.sliceOffset * Math.sin((begin + end) /2);\n\n      if (colorArray && dimArray && stringArray) {\n        for (var i=0, l=dimArray.length, acum=0, valAcum=0; i<l; i++) {\n          var dimi = dimArray[i], colori = colorArray[i % colorLength];\n          if(dimi <= 0) continue;\n          ctx.fillStyle = ctx.strokeStyle = colori;\n          if(gradient && dimi) {\n            var radialGradient = ctx.createRadialGradient(xpos, ypos, acum + config.sliceOffset,\n                xpos, ypos, acum + dimi + config.sliceOffset);\n            var colorRgb = $.hexToRgb(colori),\n                ans = $.map(colorRgb, function(i) { return (i * 0.8) >> 0; }),\n                endColor = $.rgbToHex(ans);\n\n            radialGradient.addColorStop(0, colori);\n            radialGradient.addColorStop(0.5, colori);\n            radialGradient.addColorStop(1, endColor);\n            ctx.fillStyle = radialGradient;\n          }\n\n          polar.rho = acum + config.sliceOffset;\n          polar.theta = begin;\n          var p1coord = polar.getc(true);\n          polar.theta = end;\n          var p2coord = polar.getc(true);\n          polar.rho += dimi;\n          var p3coord = polar.getc(true);\n          polar.theta = begin;\n          var p4coord = polar.getc(true);\n\n          ctx.beginPath();\n          //fixing FF arc method + fill\n          ctx.arc(xpos, ypos, acum + .01, begin, end, false);\n          ctx.arc(xpos, ypos, acum + dimi + .01, end, begin, true);\n          ctx.fill();\n          if(border && border.name == stringArray[i]) {\n            opt.acum = acum;\n            opt.dimValue = dimArray[i];\n            opt.begin = begin;\n            opt.end = end;\n          }\n          acum += (dimi || 0);\n          valAcum += (valueArray[i] || 0);\n        }\n        if(border) {\n          ctx.save();\n          ctx.globalCompositeOperation = \"source-over\";\n          ctx.lineWidth = 2;\n          ctx.strokeStyle = border.color;\n          var s = begin < end? 1 : -1;\n          ctx.beginPath();\n          //fixing FF arc method + fill\n          ctx.arc(xpos, ypos, opt.acum + .01 + 1, opt.begin, opt.end, false);\n          ctx.arc(xpos, ypos, opt.acum + opt.dimValue + .01 - 1, opt.end, opt.begin, true);\n          ctx.closePath();\n          ctx.stroke();\n          ctx.restore();\n        }\n        if(showLabels && label.type == 'Native') {\n          ctx.save();\n          ctx.fillStyle = ctx.strokeStyle = label.color;\n          var scale = resizeLabels? node.getData('normalizedDim') : 1,\n              fontSize = (label.size * scale) >> 0;\n          fontSize = fontSize < +resizeLabels? +resizeLabels : fontSize;\n\n          ctx.font = label.style + ' ' + fontSize + 'px ' + label.family;\n          ctx.textBaseline = 'middle';\n          ctx.textAlign = 'center';\n\n          polar.rho = acum + config.labelOffset + config.sliceOffset;\n          polar.theta = node.pos.theta;\n          var cart = polar.getc(true);\n\n          ctx.fillText(node.name, cart.x, cart.y);\n          ctx.restore();\n        }\n      }\n    },\n    'contains': function(node, pos) {\n      if (this.nodeTypes['none'].anglecontains.call(this, node, pos)) {\n        var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y);\n        var ld = this.config.levelDistance, d = node._depth;\n        var config = node.getData('config');\n        if(rho <=ld * d + config.sliceOffset) {\n          var dimArray = node.getData('dimArray');\n          for(var i=0,l=dimArray.length,acum=config.sliceOffset; i<l; i++) {\n            var dimi = dimArray[i];\n            if(rho >= acum && rho <= acum + dimi) {\n              return {\n                name: node.getData('stringArray')[i],\n                color: node.getData('colorArray')[i],\n                value: node.getData('valueArray')[i],\n                label: node.name\n              };\n            }\n            acum += dimi;\n          }\n        }\n        return false;\n\n      }\n      return false;\n    }\n  }\n});\n\n/*\n  Class: PieChart\n\n  A visualization that displays stacked bar charts.\n\n  Constructor Options:\n\n  See <Options.PieChart>.\n\n*/\n$jit.PieChart = new Class({\n  sb: null,\n  colors: [\"#416D9C\", \"#70A35E\", \"#EBB056\", \"#C74243\", \"#83548B\", \"#909291\", \"#557EAA\"],\n  selected: {},\n  busy: false,\n\n  initialize: function(opt) {\n    this.controller = this.config =\n      $.merge(Options(\"Canvas\", \"PieChart\", \"Label\"), {\n        Label: { type: 'Native' }\n      }, opt);\n    this.initializeViz();\n  },\n\n  initializeViz: function() {\n    var config = this.config, that = this;\n    var nodeType = config.type.split(\":\")[0];\n    var sb = new $jit.Sunburst({\n      injectInto: config.injectInto,\n      useCanvas: config.useCanvas,\n      withLabels: config.Label.type != 'Native',\n      Label: {\n        type: config.Label.type\n      },\n      Node: {\n        overridable: true,\n        type: 'piechart-' + nodeType,\n        width: 1,\n        height: 1\n      },\n      Edge: {\n        type: 'none'\n      },\n      Tips: {\n        enable: config.Tips.enable,\n        type: 'Native',\n        force: true,\n        onShow: function(tip, node, contains) {\n          var elem = contains;\n          config.Tips.onShow(tip, elem, node);\n        }\n      },\n      Events: {\n        enable: true,\n        type: 'Native',\n        onClick: function(node, eventInfo, evt) {\n          if(!config.Events.enable) return;\n          var elem = eventInfo.getContains();\n          config.Events.onClick(elem, eventInfo, evt);\n        },\n        onMouseMove: function(node, eventInfo, evt) {\n          if(!config.hoveredColor) return;\n          if(node) {\n            var elem = eventInfo.getContains();\n            that.select(node.id, elem.name, elem.index);\n          } else {\n            that.select(false, false, false);\n          }\n        }\n      },\n      onCreateLabel: function(domElement, node) {\n        var labelConf = config.Label;\n        if(config.showLabels) {\n          var style = domElement.style;\n          style.fontSize = labelConf.size + 'px';\n          style.fontFamily = labelConf.family;\n          style.color = labelConf.color;\n          style.textAlign = 'center';\n          domElement.innerHTML = node.name;\n        }\n      },\n      onPlaceLabel: function(domElement, node) {\n        if(!config.showLabels) return;\n        var pos = node.pos.getp(true),\n            dimArray = node.getData('dimArray'),\n            span = node.getData('span') / 2,\n            theta = node.pos.theta,\n            begin = theta - span,\n            end = theta + span,\n            polar = new Polar;\n\n        var showLabels = config.showLabels,\n            resizeLabels = config.resizeLabels,\n            label = config.Label;\n\n        if (dimArray) {\n          for (var i=0, l=dimArray.length, acum=0; i<l; i++) {\n            acum += dimArray[i];\n          }\n          var scale = resizeLabels? node.getData('normalizedDim') : 1,\n              fontSize = (label.size * scale) >> 0;\n          fontSize = fontSize < +resizeLabels? +resizeLabels : fontSize;\n          domElement.style.fontSize = fontSize + 'px';\n          polar.rho = acum + config.labelOffset + config.sliceOffset;\n          polar.theta = (begin + end) / 2;\n          var pos = polar.getc(true);\n          var radius = that.canvas.getSize();\n          var labelPos = {\n            x: Math.round(pos.x + radius.width / 2),\n            y: Math.round(pos.y + radius.height / 2)\n          };\n          domElement.style.left = labelPos.x + 'px';\n          domElement.style.top = labelPos.y + 'px';\n        }\n      }\n    });\n\n    var size = sb.canvas.getSize(),\n        min = Math.min;\n    sb.config.levelDistance = min(size.width, size.height)/2\n      - config.offset - config.sliceOffset;\n    this.sb = sb;\n    this.canvas = this.sb.canvas;\n    this.canvas.getCtx().globalCompositeOperation = 'lighter';\n  },\n\n  /*\n    Method: loadJSON\n\n    Loads JSON data into the visualization.\n\n    Parameters:\n\n    json - The JSON data format. This format is described in <http://blog.thejit.org/2010/04/24/new-javascript-infovis-toolkit-visualizations/#json-data-format>.\n\n    Example:\n    (start code js)\n    var pieChart = new $jit.PieChart(options);\n    pieChart.loadJSON(json);\n    (end code)\n  */\n  loadJSON: function(json) {\n    var prefix = $.time(),\n        ch = [],\n        sb = this.sb,\n        name = $.splat(json.label),\n        nameLength = name.length,\n        color = $.splat(json.color || this.colors),\n        colorLength = color.length,\n        config = this.config,\n        gradient = !!config.type.split(\":\")[1],\n        animate = config.animate,\n        mono = nameLength == 1;\n\n    for(var i=0, values=json.values, l=values.length; i<l; i++) {\n      var val = values[i];\n      var valArray = $.splat(val.values);\n      ch.push({\n        'id': prefix + val.label,\n        'name': val.label,\n        'data': {\n          'value': valArray,\n          '$valueArray': valArray,\n          '$colorArray': mono? $.splat(color[i % colorLength]) : color,\n          '$stringArray': name,\n          '$gradient': gradient,\n          '$config': config,\n          '$angularWidth': $.reduce(valArray, function(x,y){return x+y;})\n        },\n        'children': []\n      });\n    }\n    var root = {\n      'id': prefix + '$root',\n      'name': '',\n      'data': {\n        '$type': 'none',\n        '$width': 1,\n        '$height': 1\n      },\n      'children': ch\n    };\n    sb.loadJSON(root);\n\n    this.normalizeDims();\n    sb.refresh();\n    if(animate) {\n      sb.fx.animate({\n        modes: ['node-property:dimArray'],\n        duration:1500\n      });\n    }\n  },\n\n  /*\n    Method: updateJSON\n\n    Use this method when updating values for the current JSON data. If the items specified by the JSON data already exist in the graph then their values will be updated.\n\n    Parameters:\n\n    json - (object) JSON data to be updated. The JSON format corresponds to the one described in <PieChart.loadJSON>.\n    onComplete - (object) A callback object to be called when the animation transition when updating the data end.\n\n    Example:\n\n    (start code js)\n    pieChart.updateJSON(json, {\n      onComplete: function() {\n        alert('update complete!');\n      }\n    });\n    (end code)\n  */\n  updateJSON: function(json, onComplete) {\n    if(this.busy) return;\n    this.busy = true;\n\n    var sb = this.sb;\n    var graph = sb.graph;\n    var values = json.values;\n    var animate = this.config.animate;\n    var that = this;\n    $.each(values, function(v) {\n      var n = graph.getByName(v.label),\n          vals = $.splat(v.values);\n      if(n) {\n        n.setData('valueArray', vals);\n        n.setData('angularWidth', $.reduce(vals, function(x,y){return x+y;}));\n        if(json.label) {\n          n.setData('stringArray', $.splat(json.label));\n        }\n      }\n    });\n    this.normalizeDims();\n    if(animate) {\n      sb.compute('end');\n      sb.fx.animate({\n        modes: ['node-property:dimArray:span', 'linear'],\n        duration:1500,\n        onComplete: function() {\n          that.busy = false;\n          onComplete && onComplete.onComplete();\n        }\n      });\n    } else {\n      sb.refresh();\n    }\n  },\n\n  //adds the little brown bar when hovering the node\n  select: function(id, name) {\n    if(!this.config.hoveredColor) return;\n    var s = this.selected;\n    if(s.id != id || s.name != name) {\n      s.id = id;\n      s.name = name;\n      s.color = this.config.hoveredColor;\n      this.sb.graph.eachNode(function(n) {\n        if(id == n.id) {\n          n.setData('border', s);\n        } else {\n          n.setData('border', false);\n        }\n      });\n      this.sb.plot();\n    }\n  },\n\n  /*\n    Method: getLegend\n\n    Returns an object containing as keys the legend names and as values hex strings with color values.\n\n    Example:\n\n    (start code js)\n    var legend = pieChart.getLegend();\n    (end code)\n  */\n  getLegend: function() {\n    var legend = {};\n    var n;\n    this.sb.graph.getNode(this.sb.root).eachAdjacency(function(adj) {\n      n = adj.nodeTo;\n    });\n    var colors = n.getData('colorArray'),\n        len = colors.length;\n    $.each(n.getData('stringArray'), function(s, i) {\n      legend[s] = colors[i % len];\n    });\n    return legend;\n  },\n\n  /*\n    Method: getMaxValue\n\n    Returns the maximum accumulated value for the stacks. This method is used for normalizing the graph heights according to the canvas height.\n\n    Example:\n\n    (start code js)\n    var ans = pieChart.getMaxValue();\n    (end code)\n\n    In some cases it could be useful to override this method to normalize heights for a group of PieCharts, like when doing small multiples.\n\n    Example:\n\n    (start code js)\n    //will return 100 for all PieChart instances,\n    //displaying all of them with the same scale\n    $jit.PieChart.implement({\n      'getMaxValue': function() {\n        return 100;\n      }\n    });\n    (end code)\n\n  */\n  getMaxValue: function() {\n    var maxValue = 0;\n    this.sb.graph.eachNode(function(n) {\n      var valArray = n.getData('valueArray'),\n          acum = 0;\n      $.each(valArray, function(v) {\n        acum += +v;\n      });\n      maxValue = maxValue>acum? maxValue:acum;\n    });\n    return maxValue;\n  },\n\n  normalizeDims: function() {\n    //number of elements\n    var root = this.sb.graph.getNode(this.sb.root), l=0;\n    root.eachAdjacency(function() {\n      l++;\n    });\n    var maxValue = this.getMaxValue(),\n        config = this.config,\n        animate = config.animate,\n        rho = this.sb.config.levelDistance;\n    this.sb.graph.eachNode(function(n) {\n      var acum = 0, animateValue = [];\n      $.each(n.getData('valueArray'), function(v) {\n        acum += +v;\n        animateValue.push(1);\n      });\n      var stat = (animateValue.length == 1) && !config.updateHeights;\n      if(animate) {\n        n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {\n          return stat? rho: (n * rho / maxValue);\n        }), 'end');\n        var dimArray = n.getData('dimArray');\n        if(!dimArray) {\n          n.setData('dimArray', animateValue);\n        }\n      } else {\n        n.setData('dimArray', $.map(n.getData('valueArray'), function(n) {\n          return stat? rho : (n * rho / maxValue);\n        }));\n      }\n      n.setData('normalizedDim', acum / maxValue);\n    });\n  }\n});\n\n\n\n })();\n"
  },
  {
    "path": "public/javascripts/jquery-ui.js",
    "content": "/*!\n * jQuery UI 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI\n */\n(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,\"visibility\")===\"hidden\"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:\"1.8.8\",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,\nNUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a===\"number\"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css(\"position\"))||/absolute/.test(this.css(\"position\"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,\n\"position\",1))&&/(auto|scroll)/.test(c.curCSS(this,\"overflow\",1)+c.curCSS(this,\"overflow-y\",1)+c.curCSS(this,\"overflow-x\",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,\"overflow\",1)+c.curCSS(this,\"overflow-y\",1)+c.curCSS(this,\"overflow-x\",1))}).eq(0);return/fixed/.test(this.css(\"position\"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css(\"zIndex\",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css(\"position\");\nif(b===\"absolute\"||b===\"relative\"||b===\"fixed\"){b=parseInt(a.css(\"zIndex\"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?\"selectstart\":\"mousedown\")+\".ui-disableSelection\",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(\".ui-disableSelection\")}});c.each([\"Width\",\"Height\"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,\"padding\"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f,\n\"border\"+this+\"Width\",true))||0;if(m)g-=parseFloat(c.curCSS(f,\"margin\"+this,true))||0});return g}var e=b===\"Width\"?[\"Left\",\"Right\"]:[\"Top\",\"Bottom\"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn[\"inner\"+b]=function(f){if(f===j)return i[\"inner\"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+\"px\")})};c.fn[\"outer\"+b]=function(f,g){if(typeof f!==\"number\")return i[\"outer\"+b].call(this,f);return this.each(function(){c(this).css(h,\nd(this,f,true,g)+\"px\")})}});c.extend(c.expr[\":\"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,\"tabindex\");if(\"area\"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!==\"map\")return false;a=c(\"img[usemap=#\"+d+\"]\")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:\"a\"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,\"tabindex\");return(isNaN(b)||b>=0)&&c(a).is(\":focusable\")}});\nc(function(){var a=document.body,b=a.appendChild(b=document.createElement(\"div\"));c.extend(b.style,{minHeight:\"100px\",height:\"auto\",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart=\"onselectstart\"in b;a.removeChild(b).style.display=\"none\"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&\nb[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css(\"overflow\")===\"hidden\")return false;b=b&&b===\"left\"?\"scrollLeft\":\"scrollTop\";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery);\n;/*!\n * jQuery UI Widget 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Widget\n */\n(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler(\"remove\");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b(\"*\",this).add([this]).each(function(){b(this).triggerHandler(\"remove\")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(\".\")[0],f;a=a.split(\".\")[1];f=e+\"-\"+a;if(!d){d=c;c=b.Widget}b.expr[\":\"][f]=function(h){return!!b.data(h,\na)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d===\"string\",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.charAt(0)===\"_\")return h;\ne?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:\"widget\",widgetEventPrefix:\"\",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,\nthis._getCreateOptions(),a);var d=this;this.element.bind(\"remove.\"+this.widgetName,function(){d.destroy()});this._create();this._trigger(\"create\");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind(\".\"+this.widgetName).removeData(this.widgetName);this.widget().unbind(\".\"+this.widgetName).removeAttr(\"aria-disabled\").removeClass(this.widgetBaseClass+\"-disabled ui-state-disabled\")},\nwidget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a===\"string\"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a===\"disabled\")this.widget()[c?\"addClass\":\"removeClass\"](this.widgetBaseClass+\"-disabled ui-state-disabled\").attr(\"aria-disabled\",c);return this},\nenable:function(){return this._setOption(\"disabled\",false)},disable:function(){return this._setOption(\"disabled\",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);\n;/*!\n * jQuery UI Mouse 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Mouse\n *\n * Depends:\n *  jquery.ui.widget.js\n */\n(function(c){c.widget(\"ui.mouse\",{options:{cancel:\":input,option\",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind(\"mousedown.\"+this.widgetName,function(b){return a._mouseDown(b)}).bind(\"click.\"+this.widgetName,function(b){if(true===c.data(b.target,a.widgetName+\".preventClickEvent\")){c.removeData(b.target,a.widgetName+\".preventClickEvent\");b.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind(\".\"+this.widgetName)},_mouseDown:function(a){a.originalEvent=\na.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var b=this,e=a.which==1,f=typeof this.options.cancel==\"string\"?c(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){b.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=\nthis._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();return true}}this._mouseMoveDelegate=function(d){return b._mouseMove(d)};this._mouseUpDelegate=function(d){return b._mouseUp(d)};c(document).bind(\"mousemove.\"+this.widgetName,this._mouseMoveDelegate).bind(\"mouseup.\"+this.widgetName,this._mouseUpDelegate);a.preventDefault();return a.originalEvent.mouseHandled=true}},_mouseMove:function(a){if(c.browser.msie&&!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);\nreturn a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind(\"mousemove.\"+this.widgetName,this._mouseMoveDelegate).unbind(\"mouseup.\"+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;a.target==this._mouseDownEvent.target&&c.data(a.target,this.widgetName+\".preventClickEvent\",\ntrue);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);\n;/*\n * jQuery UI Position 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Position\n */\n(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||\"flip\").split(\" \"),e=b.offset?b.offset.split(\" \"):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at=\"left top\";h=k=0;j={top:b.of.pageY,\nleft:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each([\"my\",\"at\"],function(){var f=(b[this]||\"\").split(\" \");if(f.length===1)f=n.test(f[0])?f.concat([\"center\"]):o.test(f[0])?[\"center\"].concat(f):[\"center\",\"center\"];f[0]=n.test(f[0])?f[0]:\"center\";f[1]=o.test(f[1])?f[1]:\"center\";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]===\"right\")j.left+=h;else if(b.at[0]===\"center\")j.left+=h/2;if(b.at[1]===\"bottom\")j.top+=\nk;else if(b.at[1]===\"center\")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,\"marginLeft\",true))||0,q=parseInt(c.curCSS(this,\"marginTop\",true))||0,v=l+p+(parseInt(c.curCSS(this,\"marginRight\",true))||0),w=m+q+(parseInt(c.curCSS(this,\"marginBottom\",true))||0),i=c.extend({},j),r;if(b.my[0]===\"right\")i.left-=l;else if(b.my[0]===\"center\")i.left-=l/2;if(b.my[1]===\"bottom\")i.top-=m;else if(b.my[1]===\"center\")i.top-=\nm/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each([\"left\",\"top\"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left=\nd>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!==\"center\"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]===\"left\"?-a.elemWidth:a.my[0]===\"right\"?a.elemWidth:0,e=a.at[0]===\"left\"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+=\na.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!==\"center\"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]===\"top\"?-a.elemHeight:a.my[1]===\"bottom\"?a.elemHeight:0,e=a.at[1]===\"top\"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,\"position\")))b.style.position=\"relative\";var d=c(b),\ng=d.offset(),e=parseInt(c.curCSS(b,\"top\",true),10)||0,h=parseInt(c.curCSS(b,\"left\",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};\"using\"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);\n;/*\n * jQuery UI Draggable 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Draggables\n *\n * Depends:\n *  jquery.ui.core.js\n *  jquery.ui.mouse.js\n *  jquery.ui.widget.js\n */\n(function(d){d.widget(\"ui.draggable\",d.ui.mouse,{widgetEventPrefix:\"drag\",options:{addClasses:true,appendTo:\"parent\",axis:false,connectToSortable:false,containment:false,cursor:\"auto\",cursorAt:false,grid:false,handle:false,helper:\"original\",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:\"default\",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:\"both\",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper==\n\"original\"&&!/^(?:r|a|f)/.test(this.element.css(\"position\")))this.element[0].style.position=\"relative\";this.options.addClasses&&this.element.addClass(\"ui-draggable\");this.options.disabled&&this.element.addClass(\"ui-draggable-disabled\");this._mouseInit()},destroy:function(){if(this.element.data(\"draggable\")){this.element.removeData(\"draggable\").unbind(\".draggable\").removeClass(\"ui-draggable ui-draggable-dragging ui-draggable-disabled\");this._mouseDestroy();return this}},_mouseCapture:function(a){var b=\nthis.options;if(this.helper||b.disabled||d(a.target).is(\".ui-resizable-handle\"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;return true},_mouseStart:function(a){var b=this.options;this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css(\"position\");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-\nthis.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger(\"start\",a)===false){this._clear();return false}this._cacheHelperProportions();\nd.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass(\"ui-draggable-dragging\");this._mouseDrag(a,true);return true},_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo(\"absolute\");if(!b){b=this._uiHash();if(this._trigger(\"drag\",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!=\"y\")this.helper[0].style.left=this.position.left+\"px\";if(!this.options.axis||\nthis.options.axis!=\"x\")this.helper[0].style.top=this.position.top+\"px\";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if(!this.element[0]||!this.element[0].parentNode)return false;if(this.options.revert==\"invalid\"&&!b||this.options.revert==\"valid\"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,\nb)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){c._trigger(\"stop\",a)!==false&&c._clear()})}else this._trigger(\"stop\",a)!==false&&this._clear();return false},cancel:function(){this.helper.is(\".ui-draggable-dragging\")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find(\"*\").andSelf().each(function(){if(this==\na.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper==\"clone\"?this.element.clone():this.element;a.parents(\"body\").length||a.appendTo(b.appendTo==\"parent\"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css(\"position\"))&&a.css(\"position\",\"absolute\");return a},_adjustOffsetFromHelper:function(a){if(typeof a==\"string\")a=a.split(\" \");if(d.isArray(a))a={left:+a[0],top:+a[1]||\n0};if(\"left\"in a)this.offset.click.left=a.left+this.margins.left;if(\"right\"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if(\"top\"in a)this.offset.click.top=a.top+this.margins.top;if(\"bottom\"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition==\"absolute\"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],\nthis.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()==\"html\"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css(\"borderTopWidth\"),10)||0),left:a.left+(parseInt(this.offsetParent.css(\"borderLeftWidth\"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition==\"relative\"){var a=this.element.position();return{top:a.top-\n(parseInt(this.helper.css(\"top\"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css(\"left\"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css(\"marginLeft\"),10)||0,top:parseInt(this.element.css(\"marginTop\"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment==\n\"parent\")a.containment=this.helper[0].parentNode;if(a.containment==\"document\"||a.containment==\"window\")this.containment=[(a.containment==\"document\"?0:d(window).scrollLeft())-this.offset.relative.left-this.offset.parent.left,(a.containment==\"document\"?0:d(window).scrollTop())-this.offset.relative.top-this.offset.parent.top,(a.containment==\"document\"?0:d(window).scrollLeft())+d(a.containment==\"document\"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment==\"document\"?\n0:d(window).scrollTop())+(d(a.containment==\"document\"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){var b=d(a.containment)[0];if(b){a=d(a.containment).offset();var c=d(b).css(\"overflow\")!=\"hidden\";this.containment=[a.left+(parseInt(d(b).css(\"borderLeftWidth\"),10)||0)+(parseInt(d(b).css(\"paddingLeft\"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css(\"borderTopWidth\"),\n10)||0)+(parseInt(d(b).css(\"paddingTop\"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css(\"borderLeftWidth\"),10)||0)-(parseInt(d(b).css(\"paddingRight\"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css(\"borderTopWidth\"),10)||0)-(parseInt(d(b).css(\"paddingBottom\"),10)||0)-this.helperProportions.height-this.margins.top]}}else if(a.containment.constructor==\nArray)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a==\"absolute\"?1:-1;var c=this.cssPosition==\"absolute\"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollTop():\nf?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition==\"absolute\"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,g=a.pageY;\nif(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])e=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/\nb.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;e=this.originalPageX+Math.round((e-this.originalPageX)/b.grid[0])*b.grid[0];e=this.containment?!(e-this.offset.click.left<this.containment[0]||e-this.offset.click.left>this.containment[2])?e:!(e-this.offset.click.left<this.containment[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:g-this.offset.click.top-\nthis.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition==\"fixed\"?0:this.cssPosition==\"fixed\"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<526&&this.cssPosition==\"fixed\"?0:this.cssPosition==\"fixed\"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass(\"ui-draggable-dragging\");this.helper[0]!=\nthis.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a==\"drag\")this.positionAbs=this._convertPositionTo(\"absolute\");return d.Widget.prototype._trigger.call(this,a,b,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:\"1.8.8\"});\nd.ui.plugin.add(\"draggable\",\"connectToSortable\",{start:function(a,b){var c=d(this).data(\"draggable\"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var g=d.data(this,\"sortable\");if(g&&!g.options.disabled){c.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger(\"activate\",a,e)}})},stop:function(a,b){var c=d(this).data(\"draggable\"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=\n0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;c.options.helper==\"original\"&&this.instance.currentItem.css({top:\"auto\",left:\"auto\"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger(\"deactivate\",a,f)}})},drag:function(a,b){var c=d(this).data(\"draggable\"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=\nc.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=d(f).clone().appendTo(this.instance.element).data(\"sortable-item\",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,\ntrue);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;c._trigger(\"toSortable\",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=\n0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger(\"out\",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&this.instance.placeholder.remove();c._trigger(\"fromSortable\",a);c.dropped=false}})}});d.ui.plugin.add(\"draggable\",\"cursor\",{start:function(){var a=d(\"body\"),b=d(this).data(\"draggable\").options;if(a.css(\"cursor\"))b._cursor=\na.css(\"cursor\");a.css(\"cursor\",b.cursor)},stop:function(){var a=d(this).data(\"draggable\").options;a._cursor&&d(\"body\").css(\"cursor\",a._cursor)}});d.ui.plugin.add(\"draggable\",\"iframeFix\",{start:function(){var a=d(this).data(\"draggable\").options;d(a.iframeFix===true?\"iframe\":a.iframeFix).each(function(){d('<div class=\"ui-draggable-iframeFix\" style=\"background: #fff;\"></div>').css({width:this.offsetWidth+\"px\",height:this.offsetHeight+\"px\",position:\"absolute\",opacity:\"0.001\",zIndex:1E3}).css(d(this).offset()).appendTo(\"body\")})},\nstop:function(){d(\"div.ui-draggable-iframeFix\").each(function(){this.parentNode.removeChild(this)})}});d.ui.plugin.add(\"draggable\",\"opacity\",{start:function(a,b){a=d(b.helper);b=d(this).data(\"draggable\").options;if(a.css(\"opacity\"))b._opacity=a.css(\"opacity\");a.css(\"opacity\",b.opacity)},stop:function(a,b){a=d(this).data(\"draggable\").options;a._opacity&&d(b.helper).css(\"opacity\",a._opacity)}});d.ui.plugin.add(\"draggable\",\"scroll\",{start:function(){var a=d(this).data(\"draggable\");if(a.scrollParent[0]!=\ndocument&&a.scrollParent[0].tagName!=\"HTML\")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data(\"draggable\"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!=\"HTML\"){if(!c.axis||c.axis!=\"x\")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-\nc.scrollSpeed;if(!c.axis||c.axis!=\"y\")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-b.overflowOffset.left<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!=\"x\")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-\n(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!=\"y\")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add(\"draggable\",\n\"snap\",{start:function(){var a=d(this).data(\"draggable\"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||\":data(draggable)\":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data(\"draggable\"),f=c.options,e=f.snapTolerance,g=b.offset.left,n=g+c.helperProportions.width,m=b.offset.top,o=m+c.helperProportions.height,h=\nc.snapElements.length-1;h>=0;h--){var i=c.snapElements[h].left,k=i+c.snapElements[h].width,j=c.snapElements[h].top,l=j+c.snapElements[h].height;if(i-e<g&&g<k+e&&j-e<m&&m<l+e||i-e<g&&g<k+e&&j-e<o&&o<l+e||i-e<n&&n<k+e&&j-e<m&&m<l+e||i-e<n&&n<k+e&&j-e<o&&o<l+e){if(f.snapMode!=\"inner\"){var p=Math.abs(j-o)<=e,q=Math.abs(l-m)<=e,r=Math.abs(i-n)<=e,s=Math.abs(k-g)<=e;if(p)b.position.top=c._convertPositionTo(\"relative\",{top:j-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo(\"relative\",\n{top:l,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo(\"relative\",{top:0,left:i-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo(\"relative\",{top:0,left:k}).left-c.margins.left}var t=p||q||r||s;if(f.snapMode!=\"outer\"){p=Math.abs(j-m)<=e;q=Math.abs(l-o)<=e;r=Math.abs(i-g)<=e;s=Math.abs(k-n)<=e;if(p)b.position.top=c._convertPositionTo(\"relative\",{top:j,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo(\"relative\",{top:l-c.helperProportions.height,\nleft:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo(\"relative\",{top:0,left:i}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo(\"relative\",{top:0,left:k-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[h].snapping&&(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=p||q||r||s||t}else{c.snapElements[h].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,\na,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=false}}}});d.ui.plugin.add(\"draggable\",\"stack\",{start:function(){var a=d(this).data(\"draggable\").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css(\"zIndex\"),10)||0)-(parseInt(d(f).css(\"zIndex\"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add(\"draggable\",\"zIndex\",{start:function(a,\nb){a=d(b.helper);b=d(this).data(\"draggable\").options;if(a.css(\"zIndex\"))b._zIndex=a.css(\"zIndex\");a.css(\"zIndex\",b.zIndex)},stop:function(a,b){a=d(this).data(\"draggable\").options;a._zIndex&&d(b.helper).css(\"zIndex\",a._zIndex)}})})(jQuery);\n;/*\n * jQuery UI Droppable 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Droppables\n *\n * Depends:\n *  jquery.ui.core.js\n *  jquery.ui.widget.js\n *  jquery.ui.mouse.js\n *  jquery.ui.draggable.js\n */\n(function(d){d.widget(\"ui.droppable\",{widgetEventPrefix:\"drop\",options:{accept:\"*\",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:\"default\",tolerance:\"intersect\"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this);\na.addClasses&&this.element.addClass(\"ui-droppable\")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass(\"ui-droppable ui-droppable-disabled\").removeData(\"droppable\").unbind(\".droppable\");return this},_setOption:function(a,b){if(a==\"accept\")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&\nthis.element.addClass(this.options.activeClass);b&&this._trigger(\"activate\",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger(\"deactivate\",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);\nthis._trigger(\"over\",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger(\"out\",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(\":data(droppable)\").not(\".ui-draggable-dragging\").each(function(){var g=\nd.data(this,\"droppable\");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger(\"drop\",\na,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:\"1.8.8\"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height;\nswitch(c){case \"fit\":return i<=e&&g<=k&&j<=f&&h<=l;case \"intersect\":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case \"pointer\":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case \"touch\":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>=\ni&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{\"default\":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(\":data(droppable)\").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css(\"display\")!=\n\"none\";if(c[f].visible){c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight};e==\"mousedown\"&&c[f]._activate.call(c[f],b)}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem||\na.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);if(c=!c&&this.isover==1?\"isout\":c&&this.isover==0?\"isover\":null){var e;if(this.options.greedy){var g=this.element.parents(\":data(droppable):eq(0)\");if(g.length){e=\nd.data(g[0],\"droppable\");e.greedyChild=c==\"isover\"?1:0}}if(e&&c==\"isover\"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c==\"isout\"?\"isover\":\"isout\"]=0;this[c==\"isover\"?\"_over\":\"_out\"].call(this,b);if(e&&c==\"isout\"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})}}})(jQuery);\n;/*\n * jQuery UI Resizable 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Resizables\n *\n * Depends:\n *  jquery.ui.core.js\n *  jquery.ui.mouse.js\n *  jquery.ui.widget.js\n */\n(function(e){e.widget(\"ui.resizable\",e.ui.mouse,{widgetEventPrefix:\"resize\",options:{alsoResize:false,animate:false,animateDuration:\"slow\",animateEasing:\"swing\",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:\"e,s,se\",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass(\"ui-resizable\");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,\n_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||\"ui-resizable-helper\":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css(\"position\"))&&e.browser.opera&&this.element.css({position:\"relative\",top:\"auto\",left:\"auto\"});this.element.wrap(e('<div class=\"ui-wrapper\" style=\"overflow: hidden;\"></div>').css({position:this.element.css(\"position\"),width:this.element.outerWidth(),height:this.element.outerHeight(),\ntop:this.element.css(\"top\"),left:this.element.css(\"left\")}));this.element=this.element.parent().data(\"resizable\",this.element.data(\"resizable\"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css(\"marginLeft\"),marginTop:this.originalElement.css(\"marginTop\"),marginRight:this.originalElement.css(\"marginRight\"),marginBottom:this.originalElement.css(\"marginBottom\")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=\nthis.originalElement.css(\"resize\");this.originalElement.css(\"resize\",\"none\");this._proportionallyResizeElements.push(this.originalElement.css({position:\"static\",zoom:1,display:\"block\"}));this.originalElement.css({margin:this.originalElement.css(\"margin\")});this._proportionallyResize()}this.handles=a.handles||(!e(\".ui-resizable-handle\",this.element).length?\"e,s,se\":{n:\".ui-resizable-n\",e:\".ui-resizable-e\",s:\".ui-resizable-s\",w:\".ui-resizable-w\",se:\".ui-resizable-se\",sw:\".ui-resizable-sw\",ne:\".ui-resizable-ne\",\nnw:\".ui-resizable-nw\"});if(this.handles.constructor==String){if(this.handles==\"all\")this.handles=\"n,e,s,w,se,sw,ne,nw\";var c=this.handles.split(\",\");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class=\"ui-resizable-handle '+(\"ui-resizable-\"+f)+'\"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});\"se\"==f&&g.addClass(\"ui-icon ui-icon-gripsmall-diagonal-se\");this.handles[f]=\".ui-resizable-\"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==\nString)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=[\"padding\",/ne|nw|n/.test(i)?\"Top\":/se|sw|s/.test(i)?\"Bottom\":/^e$/.test(i)?\"Right\":\"Left\"].join(\"\");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(\".ui-resizable-handle\",this.element).disableSelection();\nthis._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:\"se\"}});if(a.autoHide){this._handles.hide();e(this.element).addClass(\"ui-resizable-autohide\").hover(function(){e(this).removeClass(\"ui-resizable-autohide\");b._handles.show()},function(){if(!b.resizing){e(this).addClass(\"ui-resizable-autohide\");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass(\"ui-resizable ui-resizable-disabled ui-resizable-resizing\").removeData(\"resizable\").unbind(\".resizable\").find(\".ui-resizable-handle\").remove()};\nif(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css(\"position\"),width:a.outerWidth(),height:a.outerHeight(),top:a.css(\"top\"),left:a.css(\"left\")})).remove()}this.originalElement.css(\"resize\",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),\nd=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(\".ui-draggable\")||/absolute/.test(d.css(\"position\")))d.css({position:\"absolute\",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css(\"position\"))&&d.css({position:\"relative\",top:\"auto\",left:\"auto\"});this._renderProxy();c=m(this.helper.css(\"left\"));var f=m(this.helper.css(\"top\"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=\nthis.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio==\"number\"?a.aspectRatio:\nthis.originalSize.width/this.originalSize.height||1;a=e(\".ui-resizable-\"+this.axis).css(\"cursor\");e(\"body\").css(\"cursor\",a==\"auto\"?this.axis+\"-resize\":a);d.addClass(\"ui-resizable-resizing\");this._propagate(\"start\",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate(\"resize\",\nb);a.css({top:this.position.top+\"px\",left:this.position.left+\"px\",width:this.size.width+\"px\",height:this.size.height+\"px\"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger(\"resize\",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],\"left\")?0:c.sizeDiff.height;\nf={width:c.size.width-(f?0:c.sizeDiff.width),height:c.size.height-d};d=parseInt(c.element.css(\"left\"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css(\"top\"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e(\"body\").css(\"cursor\",\"auto\");this.element.removeClass(\"ui-resizable-resizing\");this._propagate(\"stop\",\nb);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d==\"sw\"){b.left=a.left+(c.width-b.width);b.top=null}if(d==\"nw\"){b.top=\na.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=l(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=l(b.width)&&a.minWidth&&a.minWidth>b.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,\nk=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css(\"borderTopWidth\"),\nc.css(\"borderRightWidth\"),c.css(\"borderBottomWidth\"),c.css(\"borderLeftWidth\")],f=[c.css(\"paddingTop\"),c.css(\"paddingRight\"),c.css(\"paddingBottom\"),c.css(\"paddingLeft\")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)||0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(\":hidden\")||e(b).parents(\":hidden\").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=\nthis.element.offset();if(this._helper){this.helper=this.helper||e('<div style=\"overflow:hidden;\"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:\"absolute\",left:this.elementOffset.left-c+\"px\",top:this.elementOffset.top-c+\"px\",zIndex:++b.zIndex});this.helper.appendTo(\"body\").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+\na}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,\narguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!=\"resize\"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,\n{version:\"1.8.8\"});e.ui.plugin.add(\"resizable\",\"alsoResize\",{start:function(){var b=e(this).data(\"resizable\").options,a=function(c){e(c).each(function(){var d=e(this);d.data(\"resizable-alsoresize\",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css(\"left\"),10),top:parseInt(d.css(\"top\"),10),position:d.css(\"position\")})})};if(typeof b.alsoResize==\"object\"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,\nfunction(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data(\"resizable\");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data(\"resizable-alsoresize\"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?[\"width\",\"height\"]:[\"width\",\"height\",\"top\",\"left\"];e.each(r,function(n,o){if((n=\n(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css(\"position\"))){c._revertToRelativePosition=true;k.css({position:\"absolute\",top:\"auto\",left:\"auto\"})}k.css(p)})};typeof b.alsoResize==\"object\"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data(\"resizable\"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data(\"resizable-alsoresize\").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=\nfalse;typeof a.alsoResize==\"object\"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData(\"resizable-alsoresize\")}});e.ui.plugin.add(\"resizable\",\"animate\",{stop:function(b){var a=e(this).data(\"resizable\"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],\"left\")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css(\"left\"),10)+(a.position.left-\na.originalPosition.left)||null;var h=parseInt(a.element.css(\"top\"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css(\"width\"),10),height:parseInt(a.element.css(\"height\"),10),top:parseInt(a.element.css(\"top\"),10),left:parseInt(a.element.css(\"left\"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate(\"resize\",\nb)}})}});e.ui.plugin.add(\"resizable\",\"containment\",{start:function(){var b=e(this).data(\"resizable\"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e([\"Top\",\n\"Right\",\"Left\",\"Bottom\"]).each(function(i,j){f[i]=m(d.css(\"padding\"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,\"left\")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data(\"resizable\"),c=a.options,d=a.containerOffset,\nf=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css(\"position\")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=\na.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css(\"position\"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+\na.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data(\"resizable\"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css(\"position\"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css(\"position\"))&&\ne(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add(\"resizable\",\"ghost\",{start:function(){var b=e(this).data(\"resizable\"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:\"block\",position:\"relative\",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass(\"ui-resizable-ghost\").addClass(typeof a.ghost==\"string\"?a.ghost:\"\");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data(\"resizable\");b.ghost&&b.ghost.css({position:\"relative\",\nheight:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data(\"resizable\");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add(\"resizable\",\"grid\",{resize:function(){var b=e(this).data(\"resizable\"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid==\"number\"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=\nd.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery);\n;/*\n * jQuery UI Selectable 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Selectables\n *\n * Depends:\n *  jquery.ui.core.js\n *  jquery.ui.mouse.js\n *  jquery.ui.widget.js\n */\n(function(e){e.widget(\"ui.selectable\",e.ui.mouse,{options:{appendTo:\"body\",autoRefresh:true,distance:0,filter:\"*\",tolerance:\"touch\"},_create:function(){var c=this;this.element.addClass(\"ui-selectable\");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,\"selectable-item\",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass(\"ui-selected\"),\nselecting:d.hasClass(\"ui-selecting\"),unselecting:d.hasClass(\"ui-unselecting\")})})};this.refresh();this.selectees=f.addClass(\"ui-selectee\");this._mouseInit();this.helper=e(\"<div class='ui-selectable-helper'></div>\")},destroy:function(){this.selectees.removeClass(\"ui-selectee\").removeData(\"selectable-item\");this.element.removeClass(\"ui-selectable ui-selectable-disabled\").removeData(\"selectable\").unbind(\".selectable\");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX,\nc.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger(\"start\",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(\".ui-selected\").each(function(){var b=e.data(this,\"selectable-item\");b.startselected=true;if(!c.metaKey){b.$element.removeClass(\"ui-selected\");b.selected=false;b.$element.addClass(\"ui-unselecting\");b.unselecting=true;f._trigger(\"unselecting\",\nc,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,\"selectable-item\");if(b){var g=!c.metaKey||!b.$element.hasClass(\"ui-selected\");b.$element.removeClass(g?\"ui-unselecting\":\"ui-selected\").addClass(g?\"ui-selecting\":\"ui-unselecting\");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger(\"selecting\",c,{selecting:b.element}):f._trigger(\"unselecting\",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d=\nthis.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,\"selectable-item\");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance==\"touch\")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(d.tolerance==\"fit\")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass(\"ui-selected\");a.selected=false}if(a.unselecting){a.$element.removeClass(\"ui-unselecting\");\na.unselecting=false}if(!a.selecting){a.$element.addClass(\"ui-selecting\");a.selecting=true;f._trigger(\"selecting\",c,{selecting:a.element})}}else{if(a.selecting)if(c.metaKey&&a.startselected){a.$element.removeClass(\"ui-selecting\");a.selecting=false;a.$element.addClass(\"ui-selected\");a.selected=true}else{a.$element.removeClass(\"ui-selecting\");a.selecting=false;if(a.startselected){a.$element.addClass(\"ui-unselecting\");a.unselecting=true}f._trigger(\"unselecting\",c,{unselecting:a.element})}if(a.selected)if(!c.metaKey&&\n!a.startselected){a.$element.removeClass(\"ui-selected\");a.selected=false;a.$element.addClass(\"ui-unselecting\");a.unselecting=true;f._trigger(\"unselecting\",c,{unselecting:a.element})}}}});return false}},_mouseStop:function(c){var f=this;this.dragged=false;e(\".ui-unselecting\",this.element[0]).each(function(){var d=e.data(this,\"selectable-item\");d.$element.removeClass(\"ui-unselecting\");d.unselecting=false;d.startselected=false;f._trigger(\"unselected\",c,{unselected:d.element})});e(\".ui-selecting\",this.element[0]).each(function(){var d=\ne.data(this,\"selectable-item\");d.$element.removeClass(\"ui-selecting\").addClass(\"ui-selected\");d.selecting=false;d.selected=true;d.startselected=true;f._trigger(\"selected\",c,{selected:d.element})});this._trigger(\"stop\",c);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:\"1.8.8\"})})(jQuery);\n;/*\n * jQuery UI Sortable 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Sortables\n *\n * Depends:\n *  jquery.ui.core.js\n *  jquery.ui.mouse.js\n *  jquery.ui.widget.js\n */\n(function(d){d.widget(\"ui.sortable\",d.ui.mouse,{widgetEventPrefix:\"sort\",options:{appendTo:\"parent\",axis:false,connectWith:false,containment:false,cursor:\"auto\",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:\"original\",items:\"> *\",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:\"default\",tolerance:\"intersect\",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass(\"ui-sortable\");\nthis.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css(\"float\")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass(\"ui-sortable ui-sortable-disabled\").removeData(\"sortable\").unbind(\".sortable\");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData(\"sortable-item\");return this},_setOption:function(a,b){if(a===\"disabled\"){this.options[a]=b;this.widget()[b?\"addClass\":\"removeClass\"](\"ui-sortable-disabled\")}else d.Widget.prototype._setOption.apply(this,\narguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type==\"static\")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,\"sortable-item\")==e){c=d(this);return false}});if(d.data(a.target,\"sortable-item\")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&!b){var f=false;d(this.options.handle,c).find(\"*\").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=\nc;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css(\"position\",\"absolute\");this.cssPosition=this.helper.css(\"position\");d.extend(this.offset,\n{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();\nif(b.cursor){if(d(\"body\").css(\"cursor\"))this._storedCursor=d(\"body\").css(\"cursor\");d(\"body\").css(\"cursor\",b.cursor)}if(b.opacity){if(this.helper.css(\"opacity\"))this._storedOpacity=this.helper.css(\"opacity\");this.helper.css(\"opacity\",b.opacity)}if(b.zIndex){if(this.helper.css(\"zIndex\"))this._storedZIndex=this.helper.css(\"zIndex\");this.helper.css(\"zIndex\",b.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!=\"HTML\")this.overflowOffset=this.scrollParent.offset();this._trigger(\"start\",\na,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger(\"activate\",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass(\"ui-sortable-helper\");this._mouseDrag(a);return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo(\"absolute\");\nif(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!=\"HTML\"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+\nthis.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()-b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+\nb.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a)}this.positionAbs=this._convertPositionTo(\"absolute\");if(!this.options.axis||this.options.axis!=\"y\")this.helper[0].style.left=this.position.left+\n\"px\";if(!this.options.axis||this.options.axis!=\"x\")this.helper[0].style.top=this.position.top+\"px\";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?\"next\":\"prev\"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type==\"semi-dynamic\"?!d.ui.contains(this.element[0],e):true)){this.direction=f==1?\"down\":\"up\";if(this.options.tolerance==\"pointer\"||this._intersectsWithSides(c))this._rearrange(a,\nc);else break;this._trigger(\"change\",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger(\"sort\",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==\ndocument.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp();this.options.helper==\"original\"?this.currentItem.css(this._storedCSS).removeClass(\"ui-sortable-helper\"):this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger(\"deactivate\",\nnull,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger(\"out\",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!=\"original\"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):\nd(this.domPosition.parent).prepend(this.currentItem);return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||\"id\")||\"\").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+\"[]\")+\"=\"+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+\"=\");return c.join(\"&\")},toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||\n\"id\")||\"\")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance==\"pointer\"||this.options.forcePointerForContainers||this.options.tolerance!=\"pointer\"&&this.helperProportions[this.floating?\"width\":\"height\"]>a[this.floating?\"width\":\"height\"]?j:g<b+\nthis.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection();var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?c&&c==\"right\"||a==\"down\"?2:1:a&&(a==\"down\"?\n2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e==\"right\"&&a||e==\"left\"&&!a:c&&(c==\"down\"&&b||c==\"up\"&&!b)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?\"down\":\"up\")},\n_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?\"right\":\"left\")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],\"sortable\");if(h&&h!=\nthis&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(\".ui-sortable-helper\").not(\".ui-sortable-placeholder\"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(\".ui-sortable-helper\").not(\".ui-sortable-placeholder\"),this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=\nthis.currentItem.find(\":data(sortable-item)\"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element),this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],\"sortable\");\nif(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data(\"sortable-item\",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&&this.helper)this.offset.parent=this._getParentOffset();for(var b=this.items.length-1;b>=\n0;b--){var c=this.items[b],e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=\nthis.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+\" ui-sortable-placeholder\").removeClass(\"ui-sortable-helper\")[0];if(!e)f.style.visibility=\"hidden\";return f},\nupdate:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css(\"paddingTop\")||0,10)-parseInt(b.currentItem.css(\"paddingBottom\")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css(\"paddingLeft\")||0,10)-parseInt(b.currentItem.css(\"paddingRight\")||0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=\nnull,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger(\"out\",a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger(\"over\",a,this._uiHash(this));\nthis.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?\"left\":\"top\"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?\"left\":\"top\"];if(Math.abs(h-f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,\nnull,this.containers[c].element,true);this._trigger(\"change\",a,this._uiHash());this.containers[c]._trigger(\"change\",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger(\"over\",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):b.helper==\"clone\"?this.currentItem.clone():this.currentItem;a.parents(\"body\").length||\nd(b.appendTo!=\"parent\"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css(\"position\"),top:this.currentItem.css(\"top\"),left:this.currentItem.css(\"left\")};if(a[0].style.width==\"\"||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==\"\"||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a==\n\"string\")a=a.split(\" \");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if(\"left\"in a)this.offset.click.left=a.left+this.margins.left;if(\"right\"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if(\"top\"in a)this.offset.click.top=a.top+this.margins.top;if(\"bottom\"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition==\n\"absolute\"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()==\"html\"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css(\"borderTopWidth\"),10)||0),left:a.left+(parseInt(this.offsetParent.css(\"borderLeftWidth\"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition==\n\"relative\"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css(\"top\"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css(\"left\"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css(\"marginLeft\"),10)||0,top:parseInt(this.currentItem.css(\"marginTop\"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},\n_setContainment:function(){var a=this.options;if(a.containment==\"parent\")a.containment=this.helper[0].parentNode;if(a.containment==\"document\"||a.containment==\"window\")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment==\"document\"?document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment==\"document\"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-\nthis.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css(\"overflow\")!=\"hidden\";this.containment=[a.left+(parseInt(d(b).css(\"borderLeftWidth\"),10)||0)+(parseInt(d(b).css(\"paddingLeft\"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css(\"borderTopWidth\"),10)||0)+(parseInt(d(b).css(\"paddingTop\"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css(\"borderLeftWidth\"),\n10)||0)-(parseInt(d(b).css(\"paddingRight\"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css(\"borderTopWidth\"),10)||0)-(parseInt(d(b).css(\"paddingBottom\"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a==\"absolute\"?1:-1;var c=this.cssPosition==\"absolute\"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?\nthis.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=\nthis.options,c=this.cssPosition==\"absolute\"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition==\"relative\"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])f=this.containment[0]+\nthis.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?\ng:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&this.cssPosition==\"fixed\"?0:this.cssPosition==\"fixed\"?-this.scrollParent.scrollTop():\ne?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition==\"fixed\"?0:this.cssPosition==\"fixed\"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction==\"down\"?b.item[0]:b.item[0].nextSibling);this.counter=this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==\nf.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem[0].parentNode&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]==\"auto\"||this._storedCSS[e]==\"static\")this._storedCSS[e]=\"\";this.currentItem.css(this._storedCSS).removeClass(\"ui-sortable-helper\")}else this.currentItem.show();this.fromOutside&&!b&&c.push(function(f){this._trigger(\"receive\",\nf,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(\".ui-sortable-helper\")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger(\"update\",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger(\"remove\",f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger(\"receive\",\ng,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger(\"update\",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger(\"deactivate\",g,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger(\"out\",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=\n0}}this._storedCursor&&d(\"body\").css(\"cursor\",this._storedCursor);this._storedOpacity&&this.helper.css(\"opacity\",this._storedOpacity);if(this._storedZIndex)this.helper.css(\"zIndex\",this._storedZIndex==\"auto\"?\"\":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger(\"beforeStop\",a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger(\"stop\",a,this._uiHash())}return false}b||this._trigger(\"beforeStop\",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);\nthis.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger(\"stop\",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()},_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});\nd.extend(d.ui.sortable,{version:\"1.8.8\"})})(jQuery);\n;/*\n * jQuery UI Accordion 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Accordion\n *\n * Depends:\n *  jquery.ui.core.js\n *  jquery.ui.widget.js\n */\n(function(c){c.widget(\"ui.accordion\",{options:{active:0,animated:\"slide\",autoHeight:true,clearStyle:false,collapsible:false,event:\"click\",fillSpace:false,header:\"> li > :first-child,> :not(li):even\",icons:{header:\"ui-icon-triangle-1-e\",headerSelected:\"ui-icon-triangle-1-s\"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass(\"ui-accordion ui-widget ui-helper-reset\").children(\"li\").addClass(\"ui-accordion-li-fix\");\na.headers=a.element.find(b.header).addClass(\"ui-accordion-header ui-helper-reset ui-state-default ui-corner-all\").bind(\"mouseenter.accordion\",function(){b.disabled||c(this).addClass(\"ui-state-hover\")}).bind(\"mouseleave.accordion\",function(){b.disabled||c(this).removeClass(\"ui-state-hover\")}).bind(\"focus.accordion\",function(){b.disabled||c(this).addClass(\"ui-state-focus\")}).bind(\"blur.accordion\",function(){b.disabled||c(this).removeClass(\"ui-state-focus\")});a.headers.next().addClass(\"ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom\");\nif(b.navigation){var d=a.element.find(\"a\").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(\".ui-accordion-header\");a.active=h.length?h:d.closest(\".ui-accordion-content\").prev()}}a.active=a._findActive(a.active||b.active).addClass(\"ui-state-default ui-state-active\").toggleClass(\"ui-corner-all\").toggleClass(\"ui-corner-top\");a.active.next().addClass(\"ui-accordion-content-active\");a._createIcons();a.resize();a.element.attr(\"role\",\"tablist\");a.headers.attr(\"role\",\"tab\").bind(\"keydown.accordion\",\nfunction(f){return a._keydown(f)}).next().attr(\"role\",\"tabpanel\");a.headers.not(a.active||\"\").attr({\"aria-expanded\":\"false\",tabIndex:-1}).next().hide();a.active.length?a.active.attr({\"aria-expanded\":\"true\",tabIndex:0}):a.headers.eq(0).attr(\"tabIndex\",0);c.browser.safari||a.headers.find(\"a\").attr(\"tabIndex\",-1);b.event&&a.headers.bind(b.event.split(\" \").join(\".accordion \")+\".accordion\",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a=this.options;if(a.icons){c(\"<span></span>\").addClass(\"ui-icon \"+\na.icons.header).prependTo(this.headers);this.active.children(\".ui-icon\").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass(\"ui-accordion-icons\")}},_destroyIcons:function(){this.headers.children(\".ui-icon\").remove();this.element.removeClass(\"ui-accordion-icons\")},destroy:function(){var a=this.options;this.element.removeClass(\"ui-accordion ui-widget ui-helper-reset\").removeAttr(\"role\");this.headers.unbind(\".accordion\").removeClass(\"ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top\").removeAttr(\"role\").removeAttr(\"aria-expanded\").removeAttr(\"tabIndex\");\nthis.headers.find(\"a\").removeAttr(\"tabIndex\");this._destroyIcons();var b=this.headers.next().css(\"display\",\"\").removeAttr(\"role\").removeClass(\"ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled\");if(a.autoHeight||a.fillHeight)b.css(\"height\",\"\");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a==\"active\"&&this.activate(b);if(a==\"icons\"){this._destroyIcons();\nb&&this._createIcons()}if(a==\"disabled\")this.headers.add(this.headers.next())[b?\"addClass\":\"removeClass\"](\"ui-accordion-disabled ui-state-disabled\")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target);\na.preventDefault()}if(f){c(a.target).attr(\"tabIndex\",-1);c(f).attr(\"tabIndex\",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css(\"overflow\");this.element.parent().css(\"overflow\",\"hidden\")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css(\"overflow\",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+\nc(this).height()))}).css(\"overflow\",\"auto\")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height(\"\").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a===\"number\"?this.headers.filter(\":eq(\"+a+\")\"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(\":eq(0)\")},_clickHandler:function(a,b){var d=this.options;\nif(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass(\"ui-state-active ui-corner-top\").addClass(\"ui-state-default ui-corner-all\").children(\".ui-icon\").removeClass(d.icons.headerSelected).addClass(d.icons.header);\nif(!b){a.removeClass(\"ui-state-default ui-corner-all\").addClass(\"ui-state-active ui-corner-top\").children(\".ui-icon\").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass(\"ui-accordion-content-active\")}}}else if(d.collapsible){this.active.removeClass(\"ui-state-active ui-corner-top\").addClass(\"ui-state-default ui-corner-all\").children(\".ui-icon\").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass(\"ui-accordion-content-active\");var g=this.active.next(),\ne={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger(\"changestart\",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight||\ne.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k=\"slide\";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({\"aria-expanded\":\"false\",\ntabIndex:-1}).blur();a.prev().attr({\"aria-expanded\":\"true\",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:\"\",overflow:\"\"});this.toHide.removeClass(\"ui-accordion-content-active\");this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger(\"change\",null,this.data)}}});c.extend(c.ui.accordion,{version:\"1.8.8\",animations:{slide:function(a,b){a=c.extend({easing:\"swing\",\nduration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css(\"overflow\"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css(\"paddingLeft\"),10)-parseInt(b.css(\"paddingRight\"),10)-(parseInt(b.css(\"borderLeftWidth\"),10)||0)-(parseInt(b.css(\"borderRightWidth\"),10)||0));c.each([\"height\",\"paddingTop\",\"paddingBottom\"],function(j,i){g[i]=\"hide\";j=(\"\"+c.css(a.toShow[0],i)).match(/^([\\d+-.]+)(.*)$/);f[i]={value:j[1],unit:j[2]||\"px\"}});a.toShow.css({height:0,\noverflow:\"hidden\"}).show();a.toHide.filter(\":hidden\").each(a.complete).end().filter(\":visible\").animate(g,{step:function(j,i){if(i.prop==\"height\")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css(\"height\",\"\");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:\"hide\",paddingTop:\"hide\",paddingBottom:\"hide\"},a);else a.toShow.animate({height:\"show\",\npaddingTop:\"show\",paddingBottom:\"show\"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?\"easeOutBounce\":\"swing\",duration:a.down?1E3:200})}}})})(jQuery);\n;/*\n * jQuery UI Autocomplete 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Autocomplete\n *\n * Depends:\n *  jquery.ui.core.js\n *  jquery.ui.widget.js\n *  jquery.ui.position.js\n */\n(function(d){d.widget(\"ui.autocomplete\",{options:{appendTo:\"body\",delay:300,minLength:1,position:{my:\"left top\",at:\"left bottom\",collision:\"none\"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,f;this.element.addClass(\"ui-autocomplete-input\").attr(\"autocomplete\",\"off\").attr({role:\"textbox\",\"aria-autocomplete\":\"list\",\"aria-haspopup\":\"true\"}).bind(\"keydown.autocomplete\",function(c){if(!(a.options.disabled||a.element.attr(\"readonly\"))){f=false;var e=d.ui.keyCode;\nswitch(c.keyCode){case e.PAGE_UP:a._move(\"previousPage\",c);break;case e.PAGE_DOWN:a._move(\"nextPage\",c);break;case e.LEFT:if($(\".ui-autocomplete\").is(\":visible\")){a._move(\"previous\",c);c.preventDefault();}break;case e.RIGHT:if($(\".ui-autocomplete\").is(\":visible\")){a._move(\"next\",c);c.preventDefault();}break;case e.UP:if($(\".ui-autocomplete\").is(\":visible\")){a._move(\"previous\",c);c.preventDefault();}break;case e.DOWN:if($(\".ui-autocomplete\").is(\":visible\")){a._move(\"next\",c);c.preventDefault();}break;case e.ENTER:case e.NUMPAD_ENTER:if(a.menu.active){f=true;c.preventDefault()}case e.TAB:if(!a.menu.active)return;a.menu.select(c);break;case e.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=a.element.val()){a.selectedItem=\nnull;a.search(null,c)}},a.options.delay);break}}}).bind(\"keypress.autocomplete\",function(c){if(f){f=false;c.preventDefault()}}).bind(\"focus.autocomplete\",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind(\"blur.autocomplete\",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};this.menu=d(\"<ul></ul>\").addClass(\"ui-autocomplete\").appendTo(d(this.options.appendTo||\n\"body\",b)[0]).mousedown(function(c){var e=a.menu.element[0];d(c.target).closest(\".ui-menu-item\").length||setTimeout(function(){d(document).one(\"mousedown\",function(g){g.target!==a.element[0]&&g.target!==e&&!d.ui.contains(e,g.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,e){e=e.item.data(\"item.autocomplete\");false!==a._trigger(\"focus\",c,{item:e})&&/^key/.test(c.originalEvent.type)&&a.element.val(e.value)},selected:function(c,e){var g=e.item.data(\"item.autocomplete\"),\nh=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=h;setTimeout(function(){a.previous=h;a.selectedItem=g},1)}false!==a._trigger(\"select\",c,{item:g})&&a.element.val(g.value);a.term=a.element.val();a.close(c);a.selectedItem=g},blur:function(){a.menu.element.is(\":visible\")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data(\"menu\");d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass(\"ui-autocomplete-input\").removeAttr(\"autocomplete\").removeAttr(\"role\").removeAttr(\"aria-autocomplete\").removeAttr(\"aria-haspopup\");\nthis.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a===\"source\"&&this._initSource();if(a===\"appendTo\")this.menu.element.appendTo(d(b||\"body\",this.element[0].ownerDocument)[0]);a===\"disabled\"&&b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,f;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,e){e(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source===\n\"string\"){f=this.options.source;this.source=function(c,e){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:f,data:c,dataType:\"json\",success:function(g,h,i){i===a.xhr&&e(g);a.xhr=null},error:function(g){g===a.xhr&&e([]);a.xhr=null}})}}else this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger(\"search\",b)!==false)return this._search(a)},_search:function(a){this.pending++;\nthis.element.addClass(\"ui-autocomplete-loading\");this.source({term:a},this.response)},_response:function(a){if(!this.options.disabled&&a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger(\"open\")}else this.close();this.pending--;this.pending||this.element.removeClass(\"ui-autocomplete-loading\")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(\":visible\")){this.menu.element.hide();this.menu.deactivate();this._trigger(\"close\",a)}},_change:function(a){this.previous!==\nthis.element.val()&&this._trigger(\"change\",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b===\"string\")return{label:b,value:b};return d.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position))},\n_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width(\"\").outerWidth(),this.element.outerWidth()))},_renderMenu:function(a,b){var f=this;d.each(b,function(c,e){f._renderItem(a,e)})},_renderItem:function(a,b){return d(\"<li></li>\").data(\"item.autocomplete\",b).append(d(\"<a></a>\").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(\":visible\"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);\nelse this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g,\"\\\\$&\")},filter:function(a,b){var f=new RegExp(d.ui.autocomplete.escapeRegex(b),\"i\");return d.grep(a,function(c){return f.test(c.label||c.value||c)})}})})(jQuery);\n(function(d){d.widget(\"ui.menu\",{_create:function(){var a=this;this.element.addClass(\"ui-menu ui-widget ui-widget-content ui-corner-all\").attr({role:\"listbox\",\"aria-activedescendant\":\"ui-active-menuitem\"}).click(function(b){if(d(b.target).closest(\".ui-menu-item a\").length){b.preventDefault();a.select(b)}});this.refresh()},refresh:function(){var a=this;this.element.children(\"li:not(.ui-menu-item):has(a)\").addClass(\"ui-menu-item\").attr(\"role\",\"menuitem\").children(\"a\").addClass(\"ui-corner-all\").attr(\"tabindex\",\n-1).mouseenter(function(b){a.activate(b,d(this).parent())}).mouseleave(function(){a.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var f=b.offset().top-this.element.offset().top,c=this.element.attr(\"scrollTop\"),e=this.element.height();if(f<0)this.element.attr(\"scrollTop\",c+f);else f>=e&&this.element.attr(\"scrollTop\",c+f-e+b.height())}this.active=b.eq(0).children(\"a\").addClass(\"ui-state-hover\").attr(\"id\",\"ui-active-menuitem\").end();this._trigger(\"focus\",a,{item:b})},\ndeactivate:function(){if(this.active){this.active.children(\"a\").removeClass(\"ui-state-hover\").removeAttr(\"id\");this._trigger(\"blur\");this.active=null}},next:function(a){this.move(\"next\",\".ui-menu-item:first\",a)},previous:function(a){this.move(\"prev\",\".ui-menu-item:last\",a)},first:function(){return this.active&&!this.active.prevAll(\".ui-menu-item\").length},last:function(){return this.active&&!this.active.nextAll(\".ui-menu-item\").length},move:function(a,b,f){if(this.active){a=this.active[a+\"All\"](\".ui-menu-item\").eq(0);\na.length?this.activate(f,a):this.activate(f,this.element.children(b))}else this.activate(f,this.element.children(b))},nextPage:function(a){if(this.hasScroll())if(!this.active||this.last())this.activate(a,this.element.children(\".ui-menu-item:first\"));else{var b=this.active.offset().top,f=this.element.height(),c=this.element.children(\".ui-menu-item\").filter(function(){var e=d(this).offset().top-b-f+d(this).height();return e<10&&e>-10});c.length||(c=this.element.children(\".ui-menu-item:last\"));this.activate(a,\nc)}else this.activate(a,this.element.children(\".ui-menu-item\").filter(!this.active||this.last()?\":first\":\":last\"))},previousPage:function(a){if(this.hasScroll())if(!this.active||this.first())this.activate(a,this.element.children(\".ui-menu-item:last\"));else{var b=this.active.offset().top,f=this.element.height();result=this.element.children(\".ui-menu-item\").filter(function(){var c=d(this).offset().top-b+f-d(this).height();return c<10&&c>-10});result.length||(result=this.element.children(\".ui-menu-item:first\"));\nthis.activate(a,result)}else this.activate(a,this.element.children(\".ui-menu-item\").filter(!this.active||this.first()?\":last\":\":first\"))},hasScroll:function(){return this.element.height()<this.element.attr(\"scrollHeight\")},select:function(a){this._trigger(\"selected\",a,{item:this.active})}})})(jQuery);\n;/*\n * jQuery UI Button 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Button\n *\n * Depends:\n *  jquery.ui.core.js\n *  jquery.ui.widget.js\n */\n(function(a){var g,i=function(b){a(\":ui-button\",b.target.form).each(function(){var c=a(this).data(\"button\");setTimeout(function(){c.refresh()},1)})},h=function(b){var c=b.name,d=b.form,e=a([]);if(c)e=d?a(d).find(\"[name='\"+c+\"']\"):a(\"[name='\"+c+\"']\",b.ownerDocument).filter(function(){return!this.form});return e};a.widget(\"ui.button\",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest(\"form\").unbind(\"reset.button\").bind(\"reset.button\",\ni);if(typeof this.options.disabled!==\"boolean\")this.options.disabled=this.element.attr(\"disabled\");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr(\"title\");var b=this,c=this.options,d=this.type===\"checkbox\"||this.type===\"radio\",e=\"ui-state-hover\"+(!d?\" ui-state-active\":\"\");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(\":disabled\"))c.disabled=true;this.buttonElement.addClass(\"ui-button ui-widget ui-state-default ui-corner-all\").attr(\"role\",\"button\").bind(\"mouseenter.button\",\nfunction(){if(!c.disabled){a(this).addClass(\"ui-state-hover\");this===g&&a(this).addClass(\"ui-state-active\")}}).bind(\"mouseleave.button\",function(){c.disabled||a(this).removeClass(e)}).bind(\"focus.button\",function(){a(this).addClass(\"ui-state-focus\")}).bind(\"blur.button\",function(){a(this).removeClass(\"ui-state-focus\")});d&&this.element.bind(\"change.button\",function(){b.refresh()});if(this.type===\"checkbox\")this.buttonElement.bind(\"click.button\",function(){if(c.disabled)return false;a(this).toggleClass(\"ui-state-active\");\nb.buttonElement.attr(\"aria-pressed\",b.element[0].checked)});else if(this.type===\"radio\")this.buttonElement.bind(\"click.button\",function(){if(c.disabled)return false;a(this).addClass(\"ui-state-active\");b.buttonElement.attr(\"aria-pressed\",true);var f=b.element[0];h(f).not(f).map(function(){return a(this).button(\"widget\")[0]}).removeClass(\"ui-state-active\").attr(\"aria-pressed\",false)});else{this.buttonElement.bind(\"mousedown.button\",function(){if(c.disabled)return false;a(this).addClass(\"ui-state-active\");\ng=this;a(document).one(\"mouseup\",function(){g=null})}).bind(\"mouseup.button\",function(){if(c.disabled)return false;a(this).removeClass(\"ui-state-active\")}).bind(\"keydown.button\",function(f){if(c.disabled)return false;if(f.keyCode==a.ui.keyCode.SPACE||f.keyCode==a.ui.keyCode.ENTER)a(this).addClass(\"ui-state-active\")}).bind(\"keyup.button\",function(){a(this).removeClass(\"ui-state-active\")});this.buttonElement.is(\"a\")&&this.buttonElement.keyup(function(f){f.keyCode===a.ui.keyCode.SPACE&&a(this).click()})}this._setOption(\"disabled\",\nc.disabled)},_determineButtonType:function(){this.type=this.element.is(\":checkbox\")?\"checkbox\":this.element.is(\":radio\")?\"radio\":this.element.is(\"input\")?\"input\":\"button\";if(this.type===\"checkbox\"||this.type===\"radio\"){this.buttonElement=this.element.parents().last().find(\"label[for=\"+this.element.attr(\"id\")+\"]\");this.element.addClass(\"ui-helper-hidden-accessible\");var b=this.element.is(\":checked\");b&&this.buttonElement.addClass(\"ui-state-active\");this.buttonElement.attr(\"aria-pressed\",b)}else this.buttonElement=\nthis.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass(\"ui-helper-hidden-accessible\");this.buttonElement.removeClass(\"ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active  ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only\").removeAttr(\"role\").removeAttr(\"aria-pressed\").html(this.buttonElement.find(\".ui-button-text\").html());this.hasTitle||\nthis.buttonElement.removeAttr(\"title\");a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b===\"disabled\")c?this.element.attr(\"disabled\",true):this.element.removeAttr(\"disabled\");this._resetButton()},refresh:function(){var b=this.element.is(\":disabled\");b!==this.options.disabled&&this._setOption(\"disabled\",b);if(this.type===\"radio\")h(this.element[0]).each(function(){a(this).is(\":checked\")?a(this).button(\"widget\").addClass(\"ui-state-active\").attr(\"aria-pressed\",\ntrue):a(this).button(\"widget\").removeClass(\"ui-state-active\").attr(\"aria-pressed\",false)});else if(this.type===\"checkbox\")this.element.is(\":checked\")?this.buttonElement.addClass(\"ui-state-active\").attr(\"aria-pressed\",true):this.buttonElement.removeClass(\"ui-state-active\").attr(\"aria-pressed\",false)},_resetButton:function(){if(this.type===\"input\")this.options.label&&this.element.val(this.options.label);else{var b=this.buttonElement.removeClass(\"ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only\"),\nc=a(\"<span></span>\").addClass(\"ui-button-text\").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary;if(d.primary||d.secondary){b.addClass(\"ui-button-text-icon\"+(e?\"s\":d.primary?\"-primary\":\"-secondary\"));d.primary&&b.prepend(\"<span class='ui-button-icon-primary ui-icon \"+d.primary+\"'></span>\");d.secondary&&b.append(\"<span class='ui-button-icon-secondary ui-icon \"+d.secondary+\"'></span>\");if(!this.options.text){b.addClass(e?\"ui-button-icons-only\":\"ui-button-icon-only\").removeClass(\"ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary\");\nthis.hasTitle||b.attr(\"title\",c)}}else b.addClass(\"ui-button-text-only\")}}});a.widget(\"ui.buttonset\",{options:{items:\":button, :submit, :reset, :checkbox, :radio, a, :data(button)\"},_create:function(){this.element.addClass(\"ui-buttonset\")},_init:function(){this.refresh()},_setOption:function(b,c){b===\"disabled\"&&this.buttons.button(\"option\",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(this.options.items).filter(\":ui-button\").button(\"refresh\").end().not(\":ui-button\").button().end().map(function(){return a(this).button(\"widget\")[0]}).removeClass(\"ui-corner-all ui-corner-left ui-corner-right\").filter(\":first\").addClass(\"ui-corner-left\").end().filter(\":last\").addClass(\"ui-corner-right\").end().end()},\ndestroy:function(){this.element.removeClass(\"ui-buttonset\");this.buttons.map(function(){return a(this).button(\"widget\")[0]}).removeClass(\"ui-corner-left ui-corner-right\").end().button(\"destroy\");a.Widget.prototype.destroy.call(this)}})})(jQuery);\n;/*\n * jQuery UI Dialog 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Dialog\n *\n * Depends:\n *  jquery.ui.core.js\n *  jquery.ui.widget.js\n *  jquery.ui.button.js\n *  jquery.ui.draggable.js\n *  jquery.ui.mouse.js\n *  jquery.ui.position.js\n *  jquery.ui.resizable.js\n */\n(function(c,j){var k={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},l={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true};c.widget(\"ui.dialog\",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:\"close\",dialogClass:\"\",draggable:true,hide:null,height:\"auto\",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:\"center\",at:\"center\",collision:\"fit\",using:function(a){var b=c(this).css(a).offset().top;b<0&&\nc(this).css(\"top\",a.top-b)}},resizable:true,show:null,stack:true,title:\"\",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr(\"title\");if(typeof this.originalTitle!==\"string\")this.originalTitle=\"\";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||\"&#160;\",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c(\"<div></div>\")).appendTo(document.body).hide().addClass(\"ui-dialog ui-widget ui-widget-content ui-corner-all \"+b.dialogClass).css({zIndex:b.zIndex}).attr(\"tabIndex\",\n-1).css(\"outline\",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:\"dialog\",\"aria-labelledby\":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr(\"title\").addClass(\"ui-dialog-content ui-widget-content\").appendTo(g);var f=(a.uiDialogTitlebar=c(\"<div></div>\")).addClass(\"ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix\").prependTo(g),h=c('<a href=\"#\"></a>').addClass(\"ui-dialog-titlebar-close ui-corner-all\").attr(\"role\",\n\"button\").hover(function(){h.addClass(\"ui-state-hover\")},function(){h.removeClass(\"ui-state-hover\")}).focus(function(){h.addClass(\"ui-state-focus\")}).blur(function(){h.removeClass(\"ui-state-focus\")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c(\"<span></span>\")).addClass(\"ui-icon ui-icon-closethick\").text(b.closeText).appendTo(h);c(\"<span></span>\").addClass(\"ui-dialog-title\").attr(\"id\",e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=\nb.beforeclose;f.find(\"*\").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(\".dialog\").removeData(\"dialog\").removeClass(\"ui-dialog-content ui-widget-content\").hide().appendTo(\"body\");a.uiDialog.remove();a.originalTitle&&\na.element.attr(\"title\",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger(\"beforeClose\",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind(\"keypress.ui-dialog\");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger(\"close\",a)});else{b.uiDialog.hide();b._trigger(\"close\",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(\".ui-dialog\").each(function(){if(this!==b.uiDialog[0]){e=c(this).css(\"z-index\");\nisNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger(\"focus\",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css(\"z-index\",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr(\"scrollTop\"),scrollLeft:d.element.attr(\"scrollLeft\")};c.ui.dialog.maxZ+=1;d.uiDialog.css(\"z-index\",c.ui.dialog.maxZ);\nd.element.attr(a);d._trigger(\"focus\",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind(\"keypress.ui-dialog\",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(\":tabbable\",this),f=g.filter(\":first\");g=g.filter(\":last\");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target===f[0]&&e.shiftKey){g.focus(1);return false}}});\nc(a.element.find(\":tabbable\").get().concat(d.find(\".ui-dialog-buttonpane :tabbable\").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger(\"open\");return a}},_createButtons:function(a){var b=this,d=false,e=c(\"<div></div>\").addClass(\"ui-dialog-buttonpane ui-widget-content ui-helper-clearfix\"),g=c(\"<div></div>\").addClass(\"ui-dialog-buttonset\").appendTo(e);b.uiDialog.find(\".ui-dialog-buttonpane\").remove();typeof a===\"object\"&&a!==null&&c.each(a,function(){return!(d=true)});if(d){c.each(a,function(f,\nh){h=c.isFunction(h)?{click:h,text:f}:h;f=c('<button type=\"button\"></button>').attr(h,true).unbind(\"click\").click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.fn.button&&f.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:\".ui-dialog-content, .ui-dialog-titlebar-close\",handle:\".ui-dialog-titlebar\",containment:\"document\",start:function(f,h){g=\nd.height===\"auto\"?\"auto\":c(this).height();c(this).height(c(this).height()).addClass(\"ui-dialog-dragging\");b._trigger(\"dragStart\",f,a(h))},drag:function(f,h){b._trigger(\"drag\",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass(\"ui-dialog-dragging\").height(g);b._trigger(\"dragStop\",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition,originalSize:f.originalSize,\nposition:f.position,size:f.size}}a=a===j?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css(\"position\");a=typeof a===\"string\"?a:\"n,e,s,w,se,sw,ne,nw\";d.uiDialog.resizable({cancel:\".ui-dialog-content\",containment:\"document\",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass(\"ui-dialog-resizing\");d._trigger(\"resizeStart\",f,b(h))},resize:function(f,h){d._trigger(\"resize\",f,b(h))},stop:function(f,\nh){c(this).removeClass(\"ui-dialog-resizing\");e.height=c(this).height();e.width=c(this).width();d._trigger(\"resizeStop\",f,b(h));c.ui.dialog.overlay.resize()}}).css(\"position\",g).find(\".ui-resizable-se\").addClass(\"ui-icon ui-icon-grip-diagonal-se\")},_minHeight:function(){var a=this.options;return a.height===\"auto\"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a===\"string\"||typeof a===\"object\"&&\"0\"in a){b=a.split?a.split(\" \"):[a[0],a[1]];if(b.length===\n1)b[1]=b[0];c.each([\"left\",\"top\"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(\" \"),at:b.join(\" \"),offset:d.join(\" \")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(\":visible\"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f);if(g in k)e=true;if(g in\nl)d[g]=f});e&&this._size();this.uiDialog.is(\":data(resizable)\")&&this.uiDialog.resizable(\"option\",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case \"beforeclose\":a=\"beforeClose\";break;case \"buttons\":d._createButtons(b);break;case \"closeText\":d.uiDialogTitlebarCloseText.text(\"\"+b);break;case \"dialogClass\":e.removeClass(d.options.dialogClass).addClass(\"ui-dialog ui-widget ui-widget-content ui-corner-all \"+b);break;case \"disabled\":b?e.addClass(\"ui-dialog-disabled\"):e.removeClass(\"ui-dialog-disabled\");\nbreak;case \"draggable\":var g=e.is(\":data(draggable)\");g&&!b&&e.draggable(\"destroy\");!g&&b&&d._makeDraggable();break;case \"position\":d._position(b);break;case \"resizable\":(g=e.is(\":data(resizable)\"))&&!b&&e.resizable(\"destroy\");g&&typeof b===\"string\"&&e.resizable(\"option\",\"handles\",b);!g&&b!==false&&d._makeResizable(b);break;case \"title\":c(\".ui-dialog-title\",d.uiDialogTitlebar).html(\"\"+(b||\"&#160;\"));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a=this.options,b,d,e=\nthis.uiDialog.is(\":visible\");this.element.show().css({width:\"auto\",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:\"auto\",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height===\"auto\")if(c.support.minHeight)this.element.css({minHeight:d,height:\"auto\"});else{this.uiDialog.show();a=this.element.css(\"height\",\"auto\").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height-b,0));this.uiDialog.is(\":data(resizable)\")&&\nthis.uiDialog.resizable(\"option\",\"minHeight\",this._minHeight())}});c.extend(c.ui.dialog,{version:\"1.8.8\",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr(\"id\");if(!a){this.uuid+=1;a=this.uuid}return\"ui-dialog-title-\"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map(\"focus,mousedown,mouseup,keydown,keypress,click\".split(\",\"),function(a){return a+\".dialog-overlay\"}).join(\" \"),create:function(a){if(this.instances.length===\n0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind(\"keydown.dialog-overlay\",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind(\"resize.dialog-overlay\",c.ui.dialog.overlay.resize)}var b=(this.oldInstances.pop()||c(\"<div></div>\").addClass(\"ui-widget-overlay\")).appendTo(document.body).css({width:this.width(),\nheight:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(\".dialog-overlay\");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css(\"z-index\"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);\nb=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+\"px\":a+\"px\"}else return c(document).height()+\"px\"},width:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<b?c(window).width()+\"px\":a+\"px\"}else return c(document).width()+\"px\"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,\nfunction(){a=a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);\n;/*\n * jQuery UI Slider 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Slider\n *\n * Depends:\n *  jquery.ui.core.js\n *  jquery.ui.mouse.js\n *  jquery.ui.widget.js\n */\n(function(d){d.widget(\"ui.slider\",d.ui.mouse,{widgetEventPrefix:\"slide\",options:{animate:false,distance:0,max:100,min:0,orientation:\"horizontal\",range:false,step:1,value:0,values:null},_create:function(){var b=this,a=this.options;this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass(\"ui-slider ui-slider-\"+this.orientation+\" ui-widget ui-widget-content ui-corner-all\");a.disabled&&this.element.addClass(\"ui-slider-disabled ui-disabled\");\nthis.range=d([]);if(a.range){if(a.range===true){this.range=d(\"<div></div>\");if(!a.values)a.values=[this._valueMin(),this._valueMin()];if(a.values.length&&a.values.length!==2)a.values=[a.values[0],a.values[0]]}else this.range=d(\"<div></div>\");this.range.appendTo(this.element).addClass(\"ui-slider-range\");if(a.range===\"min\"||a.range===\"max\")this.range.addClass(\"ui-slider-range-\"+a.range);this.range.addClass(\"ui-widget-header\")}d(\".ui-slider-handle\",this.element).length===0&&d(\"<a href='#'></a>\").appendTo(this.element).addClass(\"ui-slider-handle\");\nif(a.values&&a.values.length)for(;d(\".ui-slider-handle\",this.element).length<a.values.length;)d(\"<a href='#'></a>\").appendTo(this.element).addClass(\"ui-slider-handle\");this.handles=d(\".ui-slider-handle\",this.element).addClass(\"ui-state-default ui-corner-all\");this.handle=this.handles.eq(0);this.handles.add(this.range).filter(\"a\").click(function(c){c.preventDefault()}).hover(function(){a.disabled||d(this).addClass(\"ui-state-hover\")},function(){d(this).removeClass(\"ui-state-hover\")}).focus(function(){if(a.disabled)d(this).blur();\nelse{d(\".ui-slider .ui-state-focus\").removeClass(\"ui-state-focus\");d(this).addClass(\"ui-state-focus\")}}).blur(function(){d(this).removeClass(\"ui-state-focus\")});this.handles.each(function(c){d(this).data(\"index.ui-slider-handle\",c)});this.handles.keydown(function(c){var e=true,f=d(this).data(\"index.ui-slider-handle\"),h,g,i;if(!b.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e=\nfalse;if(!b._keySliding){b._keySliding=true;d(this).addClass(\"ui-state-active\");h=b._start(c,f);if(h===false)return}break}i=b.options.step;h=b.options.values&&b.options.values.length?(g=b.values(f)):(g=b.value());switch(c.keyCode){case d.ui.keyCode.HOME:g=b._valueMin();break;case d.ui.keyCode.END:g=b._valueMax();break;case d.ui.keyCode.PAGE_UP:g=b._trimAlignValue(h+(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:g=b._trimAlignValue(h-(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(h===\nb._valueMax())return;g=b._trimAlignValue(h+i);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(h===b._valueMin())return;g=b._trimAlignValue(h-i);break}b._slide(c,f,g);return e}}).keyup(function(c){var e=d(this).data(\"index.ui-slider-handle\");if(b._keySliding){b._keySliding=false;b._stop(c,e);b._change(c,e);d(this).removeClass(\"ui-state-active\")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass(\"ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all\").removeData(\"slider\").unbind(\".slider\");\nthis._mouseDestroy();return this},_mouseCapture:function(b){var a=this.options,c,e,f,h,g;if(a.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:b.pageX,y:b.pageY});e=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(i){var j=Math.abs(c-h.values(i));if(e>j){e=j;f=d(this);g=i}});if(a.range===true&&this.values(1)===a.min){g+=1;f=d(this.handles[g])}if(this._start(b,\ng)===false)return false;this._mouseSliding=true;h._handleIndex=g;f.addClass(\"ui-state-active\").focus();a=f.offset();this._clickOffset=!d(b.target).parents().andSelf().is(\".ui-slider-handle\")?{left:0,top:0}:{left:b.pageX-a.left-f.width()/2,top:b.pageY-a.top-f.height()/2-(parseInt(f.css(\"borderTopWidth\"),10)||0)-(parseInt(f.css(\"borderBottomWidth\"),10)||0)+(parseInt(f.css(\"marginTop\"),10)||0)};this.handles.hasClass(\"ui-state-hover\")||this._slide(b,g,c);return this._animateOff=true},_mouseStart:function(){return true},\n_mouseDrag:function(b){var a=this._normValueFromMouse({x:b.pageX,y:b.pageY});this._slide(b,this._handleIndex,a);return false},_mouseStop:function(b){this.handles.removeClass(\"ui-state-active\");this._mouseSliding=false;this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation===\"vertical\"?\"vertical\":\"horizontal\"},_normValueFromMouse:function(b){var a;\nif(this.orientation===\"horizontal\"){a=this.elementSize.width;b=b.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{a=this.elementSize.height;b=b.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}a=b/a;if(a>1)a=1;if(a<0)a=0;if(this.orientation===\"vertical\")a=1-a;b=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+a*b)},_start:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=\nthis.values(a);c.values=this.values()}return this._trigger(\"start\",b,c)},_slide:function(b,a,c){var e;if(this.options.values&&this.options.values.length){e=this.values(a?0:1);if(this.options.values.length===2&&this.options.range===true&&(a===0&&c>e||a===1&&c<e))c=e;if(c!==this.values(a)){e=this.values();e[a]=c;b=this._trigger(\"slide\",b,{handle:this.handles[a],value:c,values:e});this.values(a?0:1);b!==false&&this.values(a,c,true)}}else if(c!==this.value()){b=this._trigger(\"slide\",b,{handle:this.handles[a],\nvalue:c});b!==false&&this.value(c)}},_stop:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger(\"stop\",b,c)},_change:function(b,a){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger(\"change\",b,c)}},value:function(b){if(arguments.length){this.options.value=\nthis._trimAlignValue(b);this._refreshValue();this._change(null,0)}return this._value()},values:function(b,a){var c,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(a);this._refreshValue();this._change(null,b)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f<c.length;f+=1){c[f]=this._trimAlignValue(e[f]);this._change(null,f)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(b):this.value();\nelse return this._values()},_setOption:function(b,a){var c,e=0;if(d.isArray(this.options.values))e=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(b){case \"disabled\":if(a){this.handles.filter(\".ui-state-focus\").blur();this.handles.removeClass(\"ui-state-hover\");this.handles.attr(\"disabled\",\"disabled\");this.element.addClass(\"ui-disabled\")}else{this.handles.removeAttr(\"disabled\");this.element.removeClass(\"ui-disabled\")}break;case \"orientation\":this._detectOrientation();\nthis.element.removeClass(\"ui-slider-horizontal ui-slider-vertical\").addClass(\"ui-slider-\"+this.orientation);this._refreshValue();break;case \"value\":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case \"values\":this._animateOff=true;this._refreshValue();for(c=0;c<e;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var b=this.options.value;return b=this._trimAlignValue(b)},_values:function(b){var a,c;if(arguments.length){a=this.options.values[b];\nreturn a=this._trimAlignValue(a)}else{a=this.options.values.slice();for(c=0;c<a.length;c+=1)a[c]=this._trimAlignValue(a[c]);return a}},_trimAlignValue:function(b){if(b<=this._valueMin())return this._valueMin();if(b>=this._valueMax())return this._valueMax();var a=this.options.step>0?this.options.step:1,c=(b-this._valueMin())%a;alignValue=b-c;if(Math.abs(c)*2>=a)alignValue+=c>0?a:-a;return parseFloat(alignValue.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},\n_refreshValue:function(){var b=this.options.range,a=this.options,c=this,e=!this._animateOff?a.animate:false,f,h={},g,i,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(k){f=(c.values(k)-c._valueMin())/(c._valueMax()-c._valueMin())*100;h[c.orientation===\"horizontal\"?\"left\":\"bottom\"]=f+\"%\";d(this).stop(1,1)[e?\"animate\":\"css\"](h,a.animate);if(c.options.range===true)if(c.orientation===\"horizontal\"){if(k===0)c.range.stop(1,1)[e?\"animate\":\"css\"]({left:f+\"%\"},a.animate);\nif(k===1)c.range[e?\"animate\":\"css\"]({width:f-g+\"%\"},{queue:false,duration:a.animate})}else{if(k===0)c.range.stop(1,1)[e?\"animate\":\"css\"]({bottom:f+\"%\"},a.animate);if(k===1)c.range[e?\"animate\":\"css\"]({height:f-g+\"%\"},{queue:false,duration:a.animate})}g=f});else{i=this.value();j=this._valueMin();l=this._valueMax();f=l!==j?(i-j)/(l-j)*100:0;h[c.orientation===\"horizontal\"?\"left\":\"bottom\"]=f+\"%\";this.handle.stop(1,1)[e?\"animate\":\"css\"](h,a.animate);if(b===\"min\"&&this.orientation===\"horizontal\")this.range.stop(1,\n1)[e?\"animate\":\"css\"]({width:f+\"%\"},a.animate);if(b===\"max\"&&this.orientation===\"horizontal\")this.range[e?\"animate\":\"css\"]({width:100-f+\"%\"},{queue:false,duration:a.animate});if(b===\"min\"&&this.orientation===\"vertical\")this.range.stop(1,1)[e?\"animate\":\"css\"]({height:f+\"%\"},a.animate);if(b===\"max\"&&this.orientation===\"vertical\")this.range[e?\"animate\":\"css\"]({height:100-f+\"%\"},{queue:false,duration:a.animate})}}});d.extend(d.ui.slider,{version:\"1.8.8\"})})(jQuery);\n;/*\n * jQuery UI Tabs 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Tabs\n *\n * Depends:\n *  jquery.ui.core.js\n *  jquery.ui.widget.js\n */\n(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget(\"ui.tabs\",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:\"click\",fx:null,idPrefix:\"ui-tabs-\",load:null,panelTemplate:\"<div></div>\",remove:null,select:null,show:null,spinner:\"<em>Loading&#8230;</em>\",tabTemplate:\"<li><a href='#{href}'><span>#{label}</span></a></li>\"},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b==\"selected\")this.options.collapsible&&\ne==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\\s/g,\"_\").replace(/[^\\w\\u00c0-\\uFFFF-]/g,\"\")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,\"\\\\:\")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||\"ui-tabs-\"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(\".ui-state-processing\").removeClass(\"ui-state-processing\").find(\"span:data(label.tabs)\").each(function(){var b=\nd(this);b.html(b.data(\"label.tabs\")).removeData(\"label.tabs\")})},_tabify:function(b){function e(g,f){g.css(\"display\",\"\");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute(\"filter\")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find(\"ol,ul\").eq(0);this.lis=d(\" > li:has(a[href])\",this.list);this.anchors=this.lis.map(function(){return d(\"a\",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr(\"href\"),l=i.split(\"#\")[0],q;if(l&&(l===location.toString().split(\"#\")[0]||\n(q=d(\"base\")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!==\"#\"){d.data(f,\"href.tabs\",i);d.data(f,\"load.tabs\",i.replace(/#.*$/,\"\"));i=a._tabId(f);f.href=\"#\"+i;f=a.element.find(\"#\"+i);if(!f.length){f=d(c.panelTemplate).attr(\"id\",i).addClass(\"ui-tabs-panel ui-widget-content ui-corner-bottom\").insertAfter(a.panels[g-1]||a.list);f.data(\"destroy.tabs\",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass(\"ui-tabs ui-widget ui-widget-content ui-corner-all\");\nthis.list.addClass(\"ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all\");this.lis.addClass(\"ui-state-default ui-corner-top\");this.panels.addClass(\"ui-tabs-panel ui-widget-content ui-corner-bottom\");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!==\"number\"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!==\"number\"&&this.lis.filter(\".ui-tabs-selected\").length)c.selected=\nthis.lis.index(this.lis.filter(\".ui-tabs-selected\"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(\".ui-state-disabled\"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass(\"ui-tabs-hide\");this.lis.removeClass(\"ui-tabs-selected ui-state-active\");\nif(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass(\"ui-tabs-hide\");this.lis.eq(c.selected).addClass(\"ui-tabs-selected ui-state-active\");a.element.queue(\"tabs\",function(){a._trigger(\"show\",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))))});this.load(c.selected)}d(window).bind(\"unload\",function(){a.lis.add(a.anchors).unbind(\".tabs\");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(\".ui-tabs-selected\"));\nthis.element[c.collapsible?\"addClass\":\"removeClass\"](\"ui-tabs-collapsible\");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass(\"ui-tabs-selected\")?\"addClass\":\"removeClass\"](\"ui-state-disabled\");c.cache===false&&this.anchors.removeData(\"cache.tabs\");this.lis.add(this.anchors).unbind(\".tabs\");if(c.event!==\"mouseover\"){var k=function(g,f){f.is(\":not(.ui-state-disabled)\")&&f.addClass(\"ui-state-\"+g)},n=function(g,f){f.removeClass(\"ui-state-\"+\ng)};this.lis.bind(\"mouseover.tabs\",function(){k(\"hover\",d(this))});this.lis.bind(\"mouseout.tabs\",function(){n(\"hover\",d(this))});this.anchors.bind(\"focus.tabs\",function(){k(\"focus\",d(this).closest(\"li\"))});this.anchors.bind(\"blur.tabs\",function(){n(\"focus\",d(this).closest(\"li\"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest(\"li\").addClass(\"ui-tabs-selected ui-state-active\");f.hide().removeClass(\"ui-tabs-hide\").animate(o,o.duration||\"normal\",\nfunction(){e(f,o);a._trigger(\"show\",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest(\"li\").addClass(\"ui-tabs-selected ui-state-active\");f.removeClass(\"ui-tabs-hide\");a._trigger(\"show\",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||\"normal\",function(){a.lis.removeClass(\"ui-tabs-selected ui-state-active\");f.addClass(\"ui-tabs-hide\");e(f,m);a.element.dequeue(\"tabs\")})}:function(g,f){a.lis.removeClass(\"ui-tabs-selected ui-state-active\");f.addClass(\"ui-tabs-hide\");a.element.dequeue(\"tabs\")};\nthis.anchors.bind(c.event+\".tabs\",function(){var g=this,f=d(g).closest(\"li\"),i=a.panels.filter(\":not(.ui-tabs-hide)\"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass(\"ui-tabs-selected\")&&!c.collapsible||f.hasClass(\"ui-state-disabled\")||f.hasClass(\"ui-state-processing\")||a.panels.filter(\":animated\").length||a._trigger(\"select\",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass(\"ui-tabs-selected\")){c.selected=\n-1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue(\"tabs\",function(){s(g,i)}).dequeue(\"tabs\");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue(\"tabs\",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue(\"tabs\",function(){s(g,i)});a.element.queue(\"tabs\",function(){r(g,l)});a.load(a.anchors.index(this))}else throw\"jQuery UI Tabs: Mismatching fragment identifier.\";\nd.browser.msie&&this.blur()});this.anchors.bind(\"click.tabs\",function(){return false})},_getIndex:function(b){if(typeof b==\"string\")b=this.anchors.index(this.anchors.filter(\"[href$=\"+b+\"]\"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(\".tabs\").removeClass(\"ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible\").removeData(\"tabs\");this.list.removeClass(\"ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all\");this.anchors.each(function(){var e=\nd.data(this,\"href.tabs\");if(e)this.href=e;var a=d(this).unbind(\".tabs\");d.each([\"href\",\"load\",\"cache\"],function(c,h){a.removeData(h+\".tabs\")})});this.lis.unbind(\".tabs\").add(this.panels).each(function(){d.data(this,\"destroy.tabs\")?d(this).remove():d(this).removeClass(\"ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide\")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b,\ne,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\\{href\\}/g,b).replace(/#\\{label\\}/g,e));b=!b.indexOf(\"#\")?b.replace(\"#\",\"\"):this._tabId(d(\"a\",e)[0]);e.addClass(\"ui-state-default ui-corner-top\").data(\"destroy.tabs\",true);var j=c.element.find(\"#\"+b);j.length||(j=d(h.panelTemplate).attr(\"id\",b).data(\"destroy.tabs\",true));j.addClass(\"ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide\");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]);\nj.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass(\"ui-tabs-selected ui-state-active\");j.removeClass(\"ui-tabs-hide\");this.element.queue(\"tabs\",function(){c._trigger(\"show\",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger(\"add\",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();\nif(a.hasClass(\"ui-tabs-selected\")&&this.anchors.length>1)this.select(b+(b+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=b}),function(h){return h>=b?--h:h});this._tabify();this._trigger(\"remove\",null,this._ui(a.find(\"a\")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass(\"ui-state-disabled\");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger(\"enable\",null,\nthis._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass(\"ui-state-disabled\");e.disabled.push(b);e.disabled.sort();this._trigger(\"disable\",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+\".tabs\");return this},\nload:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,\"load.tabs\");this.abort();if(!h||this.element.queue(\"tabs\").length!==0&&d.data(c,\"cache.tabs\"))this.element.dequeue(\"tabs\");else{this.lis.eq(b).addClass(\"ui-state-processing\");if(a.spinner){var j=d(\"span\",c);j.data(\"label.tabs\",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c,\n\"cache.tabs\",true);e._trigger(\"load\",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger(\"load\",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue(\"tabs\");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue(\"tabs\",this.element.queue(\"tabs\").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},\nurl:function(b,e){this.anchors.eq(b).removeData(\"cache.tabs\").data(\"load.tabs\",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:\"1.8.8\"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k<a.anchors.length?k:0)},b);j&&j.stopPropagation()});e=a._unrotate||(a._unrotate=!e?function(j){j.clientX&&\na.rotate(null)}:function(){t=c.selected;h()});if(b){this.element.bind(\"tabsshow\",h);this.anchors.bind(c.event+\".tabs\",e);h()}else{clearTimeout(a.rotation);this.element.unbind(\"tabsshow\",h);this.anchors.unbind(c.event+\".tabs\",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery);\n;/*\n * jQuery UI Datepicker 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Datepicker\n *\n * Depends:\n *  jquery.ui.core.js\n */\n(function(d,G){function K(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId=\"ui-datepicker-div\";this._inlineClass=\"ui-datepicker-inline\";this._appendClass=\"ui-datepicker-append\";this._triggerClass=\"ui-datepicker-trigger\";this._dialogClass=\"ui-datepicker-dialog\";this._disableClass=\"ui-datepicker-disabled\";this._unselectableClass=\"ui-datepicker-unselectable\";this._currentClass=\"ui-datepicker-current-day\";this._dayOverClass=\n\"ui-datepicker-days-cell-over\";this.regional=[];this.regional[\"\"]={closeText:\"Done\",prevText:\"Prev\",nextText:\"Next\",currentText:\"Today\",monthNames:[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"],monthNamesShort:[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"],dayNames:[\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"],dayNamesShort:[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"],dayNamesMin:[\"Su\",\n\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\",\"Sa\"],weekHeader:\"Wk\",dateFormat:\"mm/dd/yy\",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:\"\"};this._defaults={showOn:\"focus\",showAnim:\"fadeIn\",showOptions:{},defaultDate:null,appendText:\"\",buttonText:\"...\",buttonImage:\"\",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:\"c-10:c+10\",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:\"+10\",\nminDate:null,maxDate:null,duration:\"fast\",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:\"\",altFormat:\"\",constrainInput:true,showButtonPanel:false,autoSize:false};d.extend(this._defaults,this.regional[\"\"]);this.dpDiv=d('<div id=\"'+this._mainDivId+'\" class=\"ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all\"></div>')}function E(a,b){d.extend(a,b);for(var c in b)if(b[c]==\nnull||b[c]==G)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:\"1.8.8\"}});var y=(new Date).getTime();d.extend(K.prototype,{markerClassName:\"hasDatepicker\",log:function(){this.debug&&console.log.apply(\"\",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){E(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute(\"date:\"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();\nf=e==\"div\"||e==\"span\";if(!a.id){this.uuid+=1;a.id=\"dp\"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e==\"input\")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g,\"\\\\\\\\$1\"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:d('<div class=\"'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all\"></div>')}},\n_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind(\"setData.datepicker\",function(e,f,h){b.settings[f]=h}).bind(\"getData.datepicker\",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,\"datepicker\",b)}},_attachments:function(a,b){var c=this._get(b,\"appendText\"),e=this._get(b,\"isRTL\");b.append&&\nb.append.remove();if(c){b.append=d('<span class=\"'+this._appendClass+'\">'+c+\"</span>\");a[e?\"before\":\"after\"](b.append)}a.unbind(\"focus\",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,\"showOn\");if(c==\"focus\"||c==\"both\")a.focus(this._showDatepicker);if(c==\"button\"||c==\"both\"){c=this._get(b,\"buttonText\");var f=this._get(b,\"buttonImage\");b.trigger=d(this._get(b,\"buttonImageOnly\")?d(\"<img/>\").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type=\"button\"></button>').addClass(this._triggerClass).html(f==\n\"\"?c:d(\"<img/>\").attr({src:f,alt:c,title:c})));a[e?\"before\":\"after\"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,\"autoSize\")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,\"dateFormat\");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,\nc.match(/MM/)?\"monthNames\":\"monthNamesShort\")));b.setDate(e(this._get(a,c.match(/DD/)?\"dayNames\":\"dayNamesShort\"))+20-b.getDay())}a.input.attr(\"size\",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind(\"setData.datepicker\",function(e,f,h){b.settings[f]=h}).bind(\"getData.datepicker\",function(e,f){return this._get(b,f)});d.data(a,\"datepicker\",b);this._setDate(b,this._getDefaultDate(b),\ntrue);this._updateDatepicker(b);this._updateAlternate(b);b.dpDiv.show()}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=1;this._dialogInput=d('<input type=\"text\" id=\"'+(\"dp\"+this.uuid)+'\" style=\"position: absolute; top: -100px; width: 0px; z-index: -10;\"/>');this._dialogInput.keydown(this._doKeyDown);d(\"body\").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],\"datepicker\",a)}E(a.settings,e||{});\nb=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css(\"left\",this._pos[0]+20+\"px\").css(\"top\",this._pos[1]+\"px\");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);\nthis._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],\"datepicker\",a);return this},_destroyDatepicker:function(a){var b=d(a),c=d.data(a,\"datepicker\");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,\"datepicker\");if(e==\"input\"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind(\"focus\",this._showDatepicker).unbind(\"keydown\",this._doKeyDown).unbind(\"keypress\",this._doKeyPress).unbind(\"keyup\",\nthis._doKeyUp)}else if(e==\"div\"||e==\"span\")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,\"datepicker\");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e==\"input\"){a.disabled=false;c.trigger.filter(\"button\").each(function(){this.disabled=false}).end().filter(\"img\").css({opacity:\"1.0\",cursor:\"\"})}else if(e==\"div\"||e==\"span\")b.children(\".\"+this._inlineClass).children().removeClass(\"ui-state-disabled\");this._disabledInputs=d.map(this._disabledInputs,\nfunction(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a,\"datepicker\");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e==\"input\"){a.disabled=true;c.trigger.filter(\"button\").each(function(){this.disabled=true}).end().filter(\"img\").css({opacity:\"0.5\",cursor:\"default\"})}else if(e==\"div\"||e==\"span\")b.children(\".\"+this._inlineClass).children().addClass(\"ui-state-disabled\");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:\nf});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,\"datepicker\")}catch(b){throw\"Missing instance data for this datepicker\";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b==\"string\")return b==\"defaults\"?d.extend({},d.datepicker._defaults):e?b==\"all\"?d.extend({},\ne.settings):this._get(e,b):null;var f=b||{};if(typeof b==\"string\"){f={};f[b]=c}if(e){this._curInst==e&&this._hideDatepicker();var h=this._getDateDatepicker(a,true);E(e.settings,f);this._attachments(d(a),e);this._autoSize(e);this._setDateDatepicker(a,h);this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);\nthis._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(\".ui-datepicker-rtl\");b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d(\"td.\"+d.datepicker._dayOverClass+\":not(.\"+d.datepicker._currentClass+\")\",b.dpDiv);c[0]?\nd.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]):d.datepicker._hideDatepicker();return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,\"stepBigMonths\"):-d.datepicker._get(b,\"stepMonths\"),\"M\");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,\"stepBigMonths\"):+d.datepicker._get(b,\"stepMonths\"),\"M\");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||\na.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,\"D\");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,\"stepBigMonths\"):-d.datepicker._get(b,\"stepMonths\"),\"M\");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,\"D\");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,\ne?-1:+1,\"D\");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,\"stepBigMonths\"):+d.datepicker._get(b,\"stepMonths\"),\"M\");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,\"D\");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,\n\"constrainInput\")){b=d.datepicker._possibleChars(d.datepicker._get(b,\"dateFormat\"));var c=String.fromCharCode(a.charCode==G?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||c<\" \"||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,\"dateFormat\"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},\n_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!=\"input\")a=d(\"input\",a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);d.datepicker._curInst&&d.datepicker._curInst!=b&&d.datepicker._curInst.dpDiv.stop(true,true);var c=d.datepicker._get(b,\"beforeShow\");E(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value=\"\";if(!d.datepicker._pos){d.datepicker._pos=\nd.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css(\"position\")==\"fixed\";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:\"absolute\",display:\"block\",top:\"-1000px\"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b,\nc,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?\"static\":e?\"fixed\":\"absolute\",display:\"none\",left:c.left+\"px\",top:c.top+\"px\"});if(!b.inline){c=d.datepicker._get(b,\"showAnim\");var f=d.datepicker._get(b,\"duration\"),h=function(){d.datepicker._datepickerShowing=true;var i=b.dpDiv.find(\"iframe.ui-datepicker-cover\");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.effects&&\nd.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,\"showOptions\"),f,h):b.dpDiv[c||\"show\"](c?f:null,h);if(!c||!f)h();b.input.is(\":visible\")&&!b.input.is(\":disabled\")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this,c=d.datepicker._getBorders(a.dpDiv);a.dpDiv.empty().append(this._generateHTML(a));var e=a.dpDiv.find(\"iframe.ui-datepicker-cover\");e.length&&e.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()});a.dpDiv.find(\"button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a\").bind(\"mouseout\",\nfunction(){d(this).removeClass(\"ui-state-hover\");this.className.indexOf(\"ui-datepicker-prev\")!=-1&&d(this).removeClass(\"ui-datepicker-prev-hover\");this.className.indexOf(\"ui-datepicker-next\")!=-1&&d(this).removeClass(\"ui-datepicker-next-hover\")}).bind(\"mouseover\",function(){if(!b._isDisabledDatepicker(a.inline?a.dpDiv.parent()[0]:a.input[0])){d(this).parents(\".ui-datepicker-calendar\").find(\"a\").removeClass(\"ui-state-hover\");d(this).addClass(\"ui-state-hover\");this.className.indexOf(\"ui-datepicker-prev\")!=\n-1&&d(this).addClass(\"ui-datepicker-prev-hover\");this.className.indexOf(\"ui-datepicker-next\")!=-1&&d(this).addClass(\"ui-datepicker-next-hover\")}}).end().find(\".\"+this._dayOverClass+\" a\").trigger(\"mouseover\").end();c=this._getNumberOfMonths(a);e=c[1];e>1?a.dpDiv.addClass(\"ui-datepicker-multi-\"+e).css(\"width\",17*e+\"em\"):a.dpDiv.removeClass(\"ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4\").width(\"\");a.dpDiv[(c[0]!=1||c[1]!=1?\"add\":\"remove\")+\"Class\"](\"ui-datepicker-multi\");a.dpDiv[(this._get(a,\n\"isRTL\")?\"add\":\"remove\")+\"Class\"](\"ui-datepicker-rtl\");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(\":visible\")&&!a.input.is(\":disabled\")&&a.input.focus();if(a.yearshtml){var f=a.yearshtml;setTimeout(function(){f===a.yearshtml&&a.dpDiv.find(\"select.ui-datepicker-year:first\").replaceWith(a.yearshtml);f=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css(\"border-left-width\"))),parseFloat(b(a.css(\"border-top-width\")))]},\n_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,\"isRTL\")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-\ng):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),\"isRTL\");a&&(a.type==\"hidden\"||a.nodeType!=1);)a=a[b?\"previousSibling\":\"nextSibling\"];a=d(a).offset();return[a.left,a.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,\"datepicker\")))if(this._datepickerShowing){a=this._get(b,\"showAnim\");var c=this._get(b,\"duration\"),e=function(){d.datepicker._tidyDialog(b);this._curInst=null};d.effects&&d.effects[a]?\nb.dpDiv.hide(a,d.datepicker._get(b,\"showOptions\"),c,e):b.dpDiv[a==\"slideDown\"?\"slideUp\":a==\"fadeIn\"?\"fadeOut\":\"hide\"](a?c:null,e);a||e();if(a=this._get(b,\"onClose\"))a.apply(b.input?b.input[0]:null,[b.input?b.input.val():\"\",b]);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:\"absolute\",left:\"0\",top:\"-100px\"});if(d.blockUI){d.unblockUI();d(\"body\").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(\".ui-datepicker-calendar\")},\n_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents(\"#\"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c==\"M\"?this._get(e,\"showCurrentAtPos\"):\n0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,\"gotoCurrent\")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e._selectingMonthYear=\nfalse;e[\"selected\"+(c==\"M\"?\"Month\":\"Year\")]=e[\"draw\"+(c==\"M\"?\"Month\":\"Year\")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_clickMonthYear:function(a){var b=this._getInst(d(a)[0]);b.input&&b._selectingMonthYear&&setTimeout(function(){b.input.focus()},0);b._selectingMonthYear=!b._selectingMonthYear},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=\nd(\"a\",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a);this._getInst(a[0]);this._selectDate(a,\"\")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,\"onSelect\");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger(\"change\");if(a.inline)this._updateDatepicker(a);\nelse{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!=\"object\"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,\"altField\");if(b){var c=this._get(a,\"altFormat\")||this._get(a,\"dateFormat\"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,\"\"]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=\na.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw\"Invalid arguments\";b=typeof b==\"object\"?b.toString():b+\"\";if(b==\"\")return null;for(var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff,f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,\nj=c=-1,l=-1,u=-1,k=false,o=function(p){(p=z+1<a.length&&a.charAt(z+1)==p)&&z++;return p},m=function(p){var v=o(p);p=new RegExp(\"^\\\\d{1,\"+(p==\"@\"?14:p==\"!\"?20:p==\"y\"&&v?4:p==\"o\"?3:2)+\"}\");p=b.substring(s).match(p);if(!p)throw\"Missing number at position \"+s;s+=p[0].length;return parseInt(p[0],10)},n=function(p,v,H){p=o(p)?H:v;for(v=0;v<p.length;v++)if(b.substr(s,p[v].length).toLowerCase()==p[v].toLowerCase()){s+=p[v].length;return v+1}throw\"Unknown name at position \"+s;},r=function(){if(b.charAt(s)!=\na.charAt(z))throw\"Unexpected literal at position \"+s;s++},s=0,z=0;z<a.length;z++)if(k)if(a.charAt(z)==\"'\"&&!o(\"'\"))k=false;else r();else switch(a.charAt(z)){case \"d\":l=m(\"d\");break;case \"D\":n(\"D\",f,h);break;case \"o\":u=m(\"o\");break;case \"m\":j=m(\"m\");break;case \"M\":j=n(\"M\",i,g);break;case \"y\":c=m(\"y\");break;case \"@\":var w=new Date(m(\"@\"));c=w.getFullYear();j=w.getMonth()+1;l=w.getDate();break;case \"!\":w=new Date((m(\"!\")-this._ticksTo1970)/1E4);c=w.getFullYear();j=w.getMonth()+1;l=w.getDate();break;\ncase \"'\":if(o(\"'\"))r();else k=true;break;default:r()}if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}w=this._daylightSavingAdjust(new Date(c,j-1,l));if(w.getFullYear()!=c||w.getMonth()+1!=j||w.getDate()!=l)throw\"Invalid date\";return w},ATOM:\"yy-mm-dd\",COOKIE:\"D, dd M yy\",ISO_8601:\"yy-mm-dd\",RFC_822:\"D, d M y\",RFC_850:\"DD, dd-M-y\",RFC_1036:\"D, d M y\",\nRFC_1123:\"D, d M yy\",RFC_2822:\"D, d M yy\",RSS:\"D, d M y\",TICKS:\"!\",TIMESTAMP:\"@\",W3C:\"yy-mm-dd\",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return\"\";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=k+1<a.length&&a.charAt(k+1)==o)&&k++;\nreturn o},g=function(o,m,n){m=\"\"+m;if(i(o))for(;m.length<n;)m=\"0\"+m;return m},j=function(o,m,n,r){return i(o)?r[m]:n[m]},l=\"\",u=false;if(b)for(var k=0;k<a.length;k++)if(u)if(a.charAt(k)==\"'\"&&!i(\"'\"))u=false;else l+=a.charAt(k);else switch(a.charAt(k)){case \"d\":l+=g(\"d\",b.getDate(),2);break;case \"D\":l+=j(\"D\",b.getDay(),e,f);break;case \"o\":l+=g(\"o\",(b.getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864E5,3);break;case \"m\":l+=g(\"m\",b.getMonth()+1,2);break;case \"M\":l+=j(\"M\",b.getMonth(),h,c);break;\ncase \"y\":l+=i(\"y\")?b.getFullYear():(b.getYear()%100<10?\"0\":\"\")+b.getYear()%100;break;case \"@\":l+=b.getTime();break;case \"!\":l+=b.getTime()*1E4+this._ticksTo1970;break;case \"'\":if(i(\"'\"))l+=\"'\";else u=true;break;default:l+=a.charAt(k)}return l},_possibleChars:function(a){for(var b=\"\",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=0;f<a.length;f++)if(c)if(a.charAt(f)==\"'\"&&!e(\"'\"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case \"d\":case \"m\":case \"y\":case \"@\":b+=\n\"0123456789\";break;case \"D\":case \"M\":return null;case \"'\":if(e(\"'\"))b+=\"'\";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==G?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,\"dateFormat\"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?\"\":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=\nf.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,\"defaultDate\"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date;i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,\"dateFormat\"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=\n(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,j=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\\s*(d|D|w|W|m|M|y|Y)?/g,k=u.exec(h);k;){switch(k[2]||\"d\"){case \"d\":case \"D\":g+=parseInt(k[1],10);break;case \"w\":case \"W\":g+=parseInt(k[1],10)*7;break;case \"m\":case \"M\":l+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break;case \"y\":case \"Y\":j+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break}k=u.exec(h)}return new Date(j,\nl,g)};if(b=(b=b==null||b===\"\"?c:typeof b==\"string\"?f(b):typeof b==\"number\"?isNaN(b)?c:e(b):new Date(b.getTime()))&&b.toString()==\"Invalid Date\"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=\na.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?\"\":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==\"\"?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),\nb.getMonth(),b.getDate()));var c=this._get(a,\"isRTL\"),e=this._get(a,\"showButtonPanel\"),f=this._get(a,\"hideIfNoPrevNext\"),h=this._get(a,\"navigationAsDateFormat\"),i=this._getNumberOfMonths(a),g=this._get(a,\"showCurrentAtPos\"),j=this._get(a,\"stepMonths\"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,\"min\"),o=this._getMinMaxDate(a,\"max\");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=\nthis._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&n<k?k:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,\"prevText\");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a));n=this._canAdjustMonth(a,-1,m,g)?'<a class=\"ui-datepicker-prev ui-corner-all\" onclick=\"DP_jQuery_'+y+\".datepicker._adjustDate('#\"+a.id+\"', -\"+j+\", 'M');\\\" title=\\\"\"+n+'\"><span class=\"ui-icon ui-icon-circle-triangle-'+\n(c?\"e\":\"w\")+'\">'+n+\"</span></a>\":f?\"\":'<a class=\"ui-datepicker-prev ui-corner-all ui-state-disabled\" title=\"'+n+'\"><span class=\"ui-icon ui-icon-circle-triangle-'+(c?\"e\":\"w\")+'\">'+n+\"</span></a>\";var r=this._get(a,\"nextText\");r=!h?r:this.formatDate(r,this._daylightSavingAdjust(new Date(m,g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class=\"ui-datepicker-next ui-corner-all\" onclick=\"DP_jQuery_'+y+\".datepicker._adjustDate('#\"+a.id+\"', +\"+j+\", 'M');\\\" title=\\\"\"+r+'\"><span class=\"ui-icon ui-icon-circle-triangle-'+\n(c?\"w\":\"e\")+'\">'+r+\"</span></a>\":f?\"\":'<a class=\"ui-datepicker-next ui-corner-all ui-state-disabled\" title=\"'+r+'\"><span class=\"ui-icon ui-icon-circle-triangle-'+(c?\"w\":\"e\")+'\">'+r+\"</span></a>\";j=this._get(a,\"currentText\");r=this._get(a,\"gotoCurrent\")&&a.currentDay?u:b;j=!h?j:this.formatDate(j,r,this._getFormatConfig(a));h=!a.inline?'<button type=\"button\" class=\"ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all\" onclick=\"DP_jQuery_'+y+'.datepicker._hideDatepicker();\">'+this._get(a,\n\"closeText\")+\"</button>\":\"\";e=e?'<div class=\"ui-datepicker-buttonpane ui-widget-content\">'+(c?h:\"\")+(this._isInRange(a,r)?'<button type=\"button\" class=\"ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all\" onclick=\"DP_jQuery_'+y+\".datepicker._gotoToday('#\"+a.id+\"');\\\">\"+j+\"</button>\":\"\")+(c?\"\":h)+\"</div>\":\"\";h=parseInt(this._get(a,\"firstDay\"),10);h=isNaN(h)?0:h;j=this._get(a,\"showWeek\");r=this._get(a,\"dayNames\");this._get(a,\"dayNamesShort\");var s=this._get(a,\"dayNamesMin\"),z=\nthis._get(a,\"monthNames\"),w=this._get(a,\"monthNamesShort\"),p=this._get(a,\"beforeShowDay\"),v=this._get(a,\"showOtherMonths\"),H=this._get(a,\"selectOtherMonths\");this._get(a,\"calculateWeek\");for(var L=this._getDefaultDate(a),I=\"\",C=0;C<i[0];C++){for(var M=\"\",D=0;D<i[1];D++){var N=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=\" ui-corner-all\",x=\"\";if(l){x+='<div class=\"ui-datepicker-group';if(i[1]>1)switch(D){case 0:x+=\" ui-datepicker-group-first\";t=\" ui-corner-\"+(c?\"right\":\"left\");break;case i[1]-\n1:x+=\" ui-datepicker-group-last\";t=\" ui-corner-\"+(c?\"left\":\"right\");break;default:x+=\" ui-datepicker-group-middle\";t=\"\";break}x+='\">'}x+='<div class=\"ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'\">'+(/all|left/.test(t)&&C==0?c?f:n:\"\")+(/all|right/.test(t)&&C==0?c?n:f:\"\")+this._generateMonthYearHeader(a,g,m,k,o,C>0||D>0,z,w)+'</div><table class=\"ui-datepicker-calendar\"><thead><tr>';var A=j?'<th class=\"ui-datepicker-week-col\">'+this._get(a,\"weekHeader\")+\"</th>\":\"\";for(t=0;t<7;t++){var q=\n(t+h)%7;A+=\"<th\"+((t+h+6)%7>=5?' class=\"ui-datepicker-week-end\"':\"\")+'><span title=\"'+r[q]+'\">'+s[q]+\"</span></th>\"}x+=A+\"</tr></thead><tbody>\";A=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,A);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;A=l?6:Math.ceil((t+A)/7);q=this._daylightSavingAdjust(new Date(m,g,1-t));for(var O=0;O<A;O++){x+=\"<tr>\";var P=!j?\"\":'<td class=\"ui-datepicker-week-col\">'+this._get(a,\"calculateWeek\")(q)+\"</td>\";for(t=0;t<7;t++){var F=\np?p.apply(a.input?a.input[0]:null,[q]):[true,\"\"],B=q.getMonth()!=g,J=B&&!H||!F[0]||k&&q<k||o&&q>o;P+='<td class=\"'+((t+h+6)%7>=5?\" ui-datepicker-week-end\":\"\")+(B?\" ui-datepicker-other-month\":\"\")+(q.getTime()==N.getTime()&&g==a.selectedMonth&&a._keyEvent||L.getTime()==q.getTime()&&L.getTime()==N.getTime()?\" \"+this._dayOverClass:\"\")+(J?\" \"+this._unselectableClass+\" ui-state-disabled\":\"\")+(B&&!v?\"\":\" \"+F[1]+(q.getTime()==u.getTime()?\" \"+this._currentClass:\"\")+(q.getTime()==b.getTime()?\" ui-datepicker-today\":\n\"\"))+'\"'+((!B||v)&&F[2]?' title=\"'+F[2]+'\"':\"\")+(J?\"\":' onclick=\"DP_jQuery_'+y+\".datepicker._selectDay('#\"+a.id+\"',\"+q.getMonth()+\",\"+q.getFullYear()+', this);return false;\"')+\">\"+(B&&!v?\"&#xa0;\":J?'<span class=\"ui-state-default\">'+q.getDate()+\"</span>\":'<a class=\"ui-state-default'+(q.getTime()==b.getTime()?\" ui-state-highlight\":\"\")+(q.getTime()==u.getTime()?\" ui-state-active\":\"\")+(B?\" ui-priority-secondary\":\"\")+'\" href=\"#\">'+q.getDate()+\"</a>\")+\"</td>\";q.setDate(q.getDate()+1);q=this._daylightSavingAdjust(q)}x+=\nP+\"</tr>\"}g++;if(g>11){g=0;m++}x+=\"</tbody></table>\"+(l?\"</div>\"+(i[0]>0&&D==i[1]-1?'<div class=\"ui-datepicker-row-break\"></div>':\"\"):\"\");M+=x}I+=M}I+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src=\"javascript:false;\" class=\"ui-datepicker-cover\" frameborder=\"0\"></iframe>':\"\");a._keyEvent=false;return I},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,\"changeMonth\"),l=this._get(a,\"changeYear\"),u=this._get(a,\"showMonthAfterYear\"),k='<div class=\"ui-datepicker-title\">',\no=\"\";if(h||!j)o+='<span class=\"ui-datepicker-month\">'+i[b]+\"</span>\";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class=\"ui-datepicker-month\" onchange=\"DP_jQuery_'+y+\".datepicker._selectMonthYear('#\"+a.id+\"', this, 'M');\\\" onclick=\\\"DP_jQuery_\"+y+\".datepicker._clickMonthYear('#\"+a.id+\"');\\\">\";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&(!m||n<=f.getMonth()))o+='<option value=\"'+n+'\"'+(n==b?' selected=\"selected\"':\"\")+\">\"+g[n]+\"</option>\";o+=\"</select>\"}u||(k+=o+(h||!(j&&\nl)?\"&#xa0;\":\"\"));a.yearshtml=\"\";if(h||!l)k+='<span class=\"ui-datepicker-year\">'+c+\"</span>\";else{g=this._get(a,\"yearRange\").split(\":\");var r=(new Date).getFullYear();i=function(s){s=s.match(/c[+-].*/)?c+parseInt(s.substring(1),10):s.match(/[+-].*/)?r+parseInt(s,10):parseInt(s,10);return isNaN(s)?r:s};b=i(g[0]);g=Math.max(b,i(g[1]||\"\"));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='<select class=\"ui-datepicker-year\" onchange=\"DP_jQuery_'+y+\".datepicker._selectMonthYear('#\"+\na.id+\"', this, 'Y');\\\" onclick=\\\"DP_jQuery_\"+y+\".datepicker._clickMonthYear('#\"+a.id+\"');\\\">\";b<=g;b++)a.yearshtml+='<option value=\"'+b+'\"'+(b==c?' selected=\"selected\"':\"\")+\">\"+b+\"</option>\";a.yearshtml+=\"</select>\";if(d.browser.mozilla)k+='<select class=\"ui-datepicker-year\"><option value=\"'+c+'\" selected=\"selected\">'+c+\"</option></select>\";else{k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,\"yearSuffix\");if(u)k+=(h||!(j&&l)?\"&#xa0;\":\"\")+o;k+=\"</div>\";return k},_adjustInstDate:function(a,b,c){var e=\na.drawYear+(c==\"Y\"?b:0),f=a.drawMonth+(c==\"M\"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c==\"D\"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c==\"M\"||c==\"Y\")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,\"min\");a=this._getMinMaxDate(a,\"max\");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,\n\"onChangeMonthYear\");if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,\"numberOfMonths\");return a==null?[1,1]:typeof a==\"number\"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+\"Date\"),null)},_getDaysInMonth:function(a,b){return 32-(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);\nc=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,\"min\");a=this._getMinMaxDate(a,\"max\");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,\"shortYearCutoff\");b=typeof b!=\"string\"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,\n\"dayNamesShort\"),dayNames:this._get(a,\"dayNames\"),monthNamesShort:this._get(a,\"monthNamesShort\"),monthNames:this._get(a,\"monthNames\")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b==\"object\"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,\"dateFormat\"),b,this._getFormatConfig(a))}});d.fn.datepicker=\nfunction(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find(\"body\").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a==\"string\"&&(a==\"isDisabled\"||a==\"getDate\"||a==\"widget\"))return d.datepicker[\"_\"+a+\"Datepicker\"].apply(d.datepicker,[this[0]].concat(b));if(a==\"option\"&&arguments.length==2&&typeof arguments[1]==\"string\")return d.datepicker[\"_\"+a+\"Datepicker\"].apply(d.datepicker,[this[0]].concat(b));\nreturn this.each(function(){typeof a==\"string\"?d.datepicker[\"_\"+a+\"Datepicker\"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new K;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version=\"1.8.8\";window[\"DP_jQuery_\"+y]=d})(jQuery);\n;/*\n * jQuery UI Progressbar 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Progressbar\n *\n * Depends:\n *   jquery.ui.core.js\n *   jquery.ui.widget.js\n */\n(function(b,d){b.widget(\"ui.progressbar\",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass(\"ui-progressbar ui-widget ui-widget-content ui-corner-all\").attr({role:\"progressbar\",\"aria-valuemin\":this.min,\"aria-valuemax\":this.options.max,\"aria-valuenow\":this._value()});this.valueDiv=b(\"<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>\").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass(\"ui-progressbar ui-widget ui-widget-content ui-corner-all\").removeAttr(\"role\").removeAttr(\"aria-valuemin\").removeAttr(\"aria-valuemax\").removeAttr(\"aria-valuenow\");\nthis.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption(\"value\",a);return this},_setOption:function(a,c){if(a===\"value\"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger(\"complete\")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!==\"number\")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*\nthis._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger(\"change\")}this.valueDiv.toggleClass(\"ui-corner-right\",a===this.options.max).width(c.toFixed(0)+\"%\");this.element.attr(\"aria-valuenow\",a)}});b.extend(b.ui.progressbar,{version:\"1.8.8\"})})(jQuery);\n;/*\n * jQuery UI Effects 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/\n */\njQuery.effects||function(f,j){function n(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*\\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*\\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],\n16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\\(0, 0, 0, 0\\)/.exec(c))return o.transparent;return o[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=\"\"&&b!=\"transparent\"||f.nodeName(c,\"body\"))break;a=\"backgroundColor\"}while(c=c.parentNode);return n(b)}function p(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,\na={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]==\"string\"){d=b.replace(/\\-(\\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]===\"string\")a[b]=c[b];return a}function q(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c==\"object\"){d=\na;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a==\"number\"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b==\"number\"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function m(c){if(!c||typeof c===\"number\"||f.fx.speeds[c])return true;if(typeof c===\"string\"&&!f.effects[c])return true;return false}f.effects={};f.each([\"backgroundColor\",\"borderBottomColor\",\"borderLeftColor\",\"borderRightColor\",\n\"borderTopColor\",\"borderColor\",\"color\",\"outlineColor\"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=n(b.end);b.colorInit=true}b.elem.style[a]=\"rgb(\"+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+\",\"+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+\",\"+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+\")\"}});var o={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,\n0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,\n211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},r=[\"add\",\"remove\",\"toggle\"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,\nd){if(f.isFunction(b)){d=b;b=null}return this.queue(\"fx\",function(){var e=f(this),g=e.attr(\"style\")||\" \",h=q(p.call(this)),l,v=e.attr(\"className\");f.each(r,function(w,i){c[i]&&e[i+\"Class\"](c[i])});l=q(p.call(this));e.attr(\"className\",v);e.animate(u(h,l),a,b,function(){f.each(r,function(w,i){c[i]&&e[i+\"Class\"](c[i])});if(typeof e.attr(\"style\")==\"object\"){e.attr(\"style\").cssText=\"\";e.attr(\"style\").cssText=g}else e.attr(\"style\",g);d&&d.apply(this,arguments)});h=f.queue(this);l=h.splice(h.length-1,1)[0];\nh.splice(1,0,l);f.dequeue(this)})};f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a==\"boolean\"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,\na):f.effects.animateClass.apply(this,[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:\"1.8.8\",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.data(\"ec.storage.\"+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data(\"ec.storage.\"+a[b]))},setMode:function(c,a){if(a==\"toggle\")a=c.is(\":hidden\")?\"show\":\"hide\";return a},getBaseline:function(c,\na){var b;switch(c[0]){case \"top\":b=0;break;case \"middle\":b=0.5;break;case \"bottom\":b=1;break;default:b=c[0]/a.height}switch(c[1]){case \"left\":c=0;break;case \"center\":c=0.5;break;case \"right\":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(\".ui-effects-wrapper\"))return c.parent();var a={width:c.outerWidth(true),height:c.outerHeight(true),\"float\":c.css(\"float\")},b=f(\"<div></div>\").addClass(\"ui-effects-wrapper\").css({fontSize:\"100%\",background:\"transparent\",\nborder:\"none\",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css(\"position\")==\"static\"){b.css({position:\"relative\"});c.css({position:\"relative\"})}else{f.extend(a,{position:c.css(\"position\"),zIndex:c.css(\"z-index\")});f.each([\"top\",\"left\",\"bottom\",\"right\"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]=\"auto\"});c.css({position:\"relative\",top:0,left:0,right:\"auto\",bottom:\"auto\"})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(\".ui-effects-wrapper\"))return c.parent().replaceWith(c);\nreturn c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});return d.call(this,b)},_show:f.fn.show,show:function(c){if(m(c))return this._show.apply(this,arguments);\nelse{var a=k.apply(this,arguments);a[1].mode=\"show\";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(m(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode=\"hide\";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(m(c)||typeof c===\"boolean\"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode=\"toggle\";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),\nb=[];f.each([\"em\",\"px\",\"%\",\"pt\"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:\"easeOutQuad\",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,\na,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,\na,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==\ne)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=\ng/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/\nh);if(a<1)return-0.5*h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,\na,b,d,e){return d-f.easing.easeOutBounce(c,e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery);\n;/*\n * jQuery UI Effects Blind 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Blind\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=[\"position\",\"top\",\"bottom\",\"left\",\"right\"],f=b.effects.setMode(a,c.options.mode||\"hide\"),d=c.options.direction||\"vertical\";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:\"hidden\"}),h=d==\"vertical\"?\"height\":\"width\";d=d==\"vertical\"?e.height():e.width();f==\"show\"&&e.css(h,0);var i={};i[h]=f==\"show\"?d:0;e.animate(i,c.duration,c.options.easing,function(){f==\"hide\"&&a.hide();b.effects.restore(a,\ng);b.effects.removeWrapper(a);c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery);\n;/*\n * jQuery UI Effects Bounce 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Bounce\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=[\"position\",\"top\",\"bottom\",\"left\",\"right\"],h=e.effects.setMode(a,b.options.mode||\"effect\"),d=b.options.direction||\"up\",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push(\"opacity\");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d==\"up\"||d==\"down\"?\"top\":\"left\";d=d==\"up\"||d==\"left\"?\"pos\":\"neg\";c=b.options.distance||(f==\"top\"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/\n3);if(h==\"show\")a.css(\"opacity\",0).css(f,d==\"pos\"?-c:c);if(h==\"hide\")c/=m*2;h!=\"hide\"&&m--;if(h==\"show\"){var g={opacity:1};g[f]=(d==\"pos\"?\"+=\":\"-=\")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d==\"pos\"?\"-=\":\"+=\")+c;k[f]=(d==\"pos\"?\"+=\":\"-=\")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h==\"hide\"?c*2:c/2}if(h==\"hide\"){g={opacity:0};g[f]=(d==\"pos\"?\"-=\":\"+=\")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a);\nb.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d==\"pos\"?\"-=\":\"+=\")+c;k[f]=(d==\"pos\"?\"+=\":\"-=\")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue(\"fx\",function(){a.dequeue()});a.dequeue()})}})(jQuery);\n;/*\n * jQuery UI Effects Clip 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Clip\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=[\"position\",\"top\",\"bottom\",\"left\",\"right\",\"height\",\"width\"],f=b.effects.setMode(a,e.options.mode||\"hide\"),c=e.options.direction||\"vertical\";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:\"hidden\"});d=a[0].tagName==\"IMG\"?d:a;var g={size:c==\"vertical\"?\"height\":\"width\",position:c==\"vertical\"?\"top\":\"left\"};c=c==\"vertical\"?d.height():d.width();if(f==\"show\"){d.css(g.size,0);d.css(g.position,\nc/2)}var h={};h[g.size]=f==\"show\"?c:0;h[g.position]=f==\"show\"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f==\"hide\"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery);\n;/*\n * jQuery UI Effects Drop 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Drop\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=[\"position\",\"top\",\"bottom\",\"left\",\"right\",\"opacity\"],e=c.effects.setMode(a,d.options.mode||\"hide\"),b=d.options.direction||\"left\";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b==\"up\"||b==\"down\"?\"top\":\"left\";b=b==\"up\"||b==\"left\"?\"pos\":\"neg\";var g=d.options.distance||(f==\"top\"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e==\"show\")a.css(\"opacity\",0).css(f,b==\"pos\"?-g:g);var i={opacity:e==\n\"show\"?1:0};i[f]=(e==\"show\"?b==\"pos\"?\"+=\":\"-=\":b==\"pos\"?\"-=\":\"+=\")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e==\"hide\"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);\n;/*\n * jQuery UI Effects Explode 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Explode\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode==\"toggle\"?j(this).is(\":visible\")?\"hide\":\"show\":a.options.mode;var b=j(this).show().css(\"visibility\",\"hidden\"),g=b.offset();g.top-=parseInt(b.css(\"marginTop\"),10)||0;g.left-=parseInt(b.css(\"marginLeft\"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f=\n0;f<d;f++)b.clone().appendTo(\"body\").wrap(\"<div></div>\").css({position:\"absolute\",visibility:\"visible\",left:-f*(h/d),top:-e*(i/c)}).parent().addClass(\"ui-effects-explode\").css({position:\"absolute\",overflow:\"hidden\",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode==\"show\"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode==\"show\"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode==\"show\"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode==\"show\"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+\ne*(i/c)+(a.options.mode==\"show\"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode==\"show\"?1:0},a.duration||500);setTimeout(function(){a.options.mode==\"show\"?b.css({visibility:\"visible\"}):b.css({visibility:\"visible\"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j(\"div.ui-effects-explode\").remove()},a.duration||500)})}})(jQuery);\n;/*\n * jQuery UI Effects Fade 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Fade\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||\"hide\");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery);\n;/*\n * jQuery UI Effects Fold 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Fold\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=[\"position\",\"top\",\"bottom\",\"left\",\"right\"],d=c.effects.setMode(b,a.options.mode||\"hide\"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:\"hidden\"}),f=d==\"show\"!=h,l=f?[\"width\",\"height\"]:[\"height\",\"width\"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1],\n10)/100*f[d==\"hide\"?0:1];if(d==\"show\")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d==\"show\"?f[0]:g;i[l[1]]=d==\"show\"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d==\"hide\"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery);\n;/*\n * jQuery UI Effects Highlight 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Highlight\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=[\"backgroundImage\",\"backgroundColor\",\"opacity\"],d=b.effects.setMode(a,c.options.mode||\"show\"),f={backgroundColor:a.css(\"backgroundColor\")};if(d==\"hide\")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:\"none\",backgroundColor:c.options.color||\"#ffff99\"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d==\"hide\"&&a.hide();b.effects.restore(a,e);d==\"show\"&&!b.support.opacity&&\nthis.style.removeAttribute(\"filter\");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);\n;/*\n * jQuery UI Effects Pulsate 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Pulsate\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||\"show\");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(\":visible\");animateTo=0;if(!isVisible){b.css(\"opacity\",0).show();animateTo=1}if(c==\"hide\"&&isVisible||c==\"show\"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration,\na.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue(\"fx\",function(){b.dequeue()}).dequeue()})}})(jQuery);\n;/*\n * jQuery UI Effects Scale 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Scale\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||\"hide\"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e==\"hide\"?g:100,from:e==\"hide\"?i:{height:i.height*h,width:i.width*h}});a.effect(\"scale\",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a,\nb.options.mode||\"effect\"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g==\"hide\"?0:100),i=b.options.direction||\"both\",f=b.options.origin;if(g!=\"effect\"){e.origin=f||[\"middle\",\"center\"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g==\"show\"?{height:0,width:0}:f);h={y:i!=\"horizontal\"?h/100:1,x:i!=\"vertical\"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g==\"show\"){a.from.opacity=0;a.to.opacity=1}if(g==\"hide\"){a.from.opacity=\n1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect(\"size\",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=[\"position\",\"top\",\"bottom\",\"left\",\"right\",\"width\",\"height\",\"overflow\",\"opacity\"],g=[\"position\",\"top\",\"bottom\",\"left\",\"right\",\"overflow\",\"opacity\"],h=[\"width\",\"height\",\"overflow\"],i=[\"fontSize\"],f=[\"borderTopWidth\",\"borderBottomWidth\",\"paddingTop\",\"paddingBottom\"],k=[\"borderLeftWidth\",\"borderRightWidth\",\"paddingLeft\",\"paddingRight\"],\np=c.effects.setMode(a,b.options.mode||\"effect\"),n=b.options.restore||false,m=b.options.scale||\"both\",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}};\nif(m==\"box\"||m==\"both\"){if(d.from.y!=d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m==\"content\"||m==\"both\")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a);\na.css(\"overflow\",\"hidden\").css(a.from);if(m==\"content\"||m==\"both\"){f=f.concat([\"marginTop\",\"marginBottom\"]).concat(i);k=k.concat([\"marginLeft\",\"marginRight\"]);h=e.concat(f).concat(k);a.find(\"*[width]\").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from);\nchild.to=c.effects.setTransition(child,f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css(\"opacity\",a.from.opacity);p==\"hide\"&&a.hide();c.effects.restore(a,\nn?e:g);c.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);\n;/*\n * jQuery UI Effects Shake 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Shake\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=[\"position\",\"top\",\"bottom\",\"left\",\"right\"];d.effects.setMode(b,a.options.mode||\"effect\");var c=a.options.direction||\"left\",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c==\"up\"||c==\"down\"?\"top\":\"left\",h=c==\"up\"||c==\"left\"?\"pos\":\"neg\";c={};var i={},k={};c[g]=(h==\"pos\"?\"-=\":\"+=\")+e;i[g]=(h==\"pos\"?\"+=\":\"-=\")+e*2;k[g]=\n(h==\"pos\"?\"-=\":\"+=\")+e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue(\"fx\",function(){b.dequeue()});b.dequeue()})}})(jQuery);\n;/*\n * jQuery UI Effects Slide 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Slide\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=[\"position\",\"top\",\"bottom\",\"left\",\"right\"],f=c.effects.setMode(a,d.options.mode||\"show\"),b=d.options.direction||\"left\";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:\"hidden\"});var g=b==\"up\"||b==\"down\"?\"top\":\"left\";b=b==\"up\"||b==\"left\"?\"pos\":\"neg\";var e=d.options.distance||(g==\"top\"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(f==\"show\")a.css(g,b==\"pos\"?isNaN(e)?\"-\"+e:-e:e);\nvar i={};i[g]=(f==\"show\"?b==\"pos\"?\"+=\":\"-=\":b==\"pos\"?\"-=\":\"+=\")+e;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){f==\"hide\"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);\n;/*\n * jQuery UI Effects Transfer 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Effects/Transfer\n *\n * Depends:\n *  jquery.effects.core.js\n */\n(function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class=\"ui-effects-transfer\"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:\"absolute\"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments);\nb.dequeue()})})}})(jQuery);\n;\n"
  },
  {
    "path": "public/javascripts/jquery.autocomplete.js",
    "content": "/*\n * jQuery Autocomplete plugin 1.1\n *\n * Copyright (c) 2009 Jörn Zaefferer\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n *\n * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $\n */\n\n;(function($) {\n\n$.fn.extend({\n  autocomplete: function(urlOrData, options) {\n    var isUrl = typeof urlOrData == \"string\";\n    options = $.extend({}, $.Autocompleter.defaults, {\n      url: isUrl ? urlOrData : null,\n      data: isUrl ? null : urlOrData,\n      delay: isUrl ? $.Autocompleter.defaults.delay : 10,\n      max: options && !options.scroll ? 10 : 150\n    }, options);\n\n    // if highlight is set to false, replace it with a do-nothing function\n    options.highlight = options.highlight || function(value) { return value; };\n\n    // if the formatMatch option is not specified, then use formatItem for backwards compatibility\n    options.formatMatch = options.formatMatch || options.formatItem;\n\n    return this.each(function() {\n      new $.Autocompleter(this, options);\n    });\n  },\n  result: function(handler) {\n    return this.bind(\"result\", handler);\n  },\n  search: function(handler) {\n    return this.trigger(\"search\", [handler]);\n  },\n  flushCache: function() {\n    return this.trigger(\"flushCache\");\n  },\n  setOptions: function(options){\n    return this.trigger(\"setOptions\", [options]);\n  },\n  unautocomplete: function() {\n    return this.trigger(\"unautocomplete\");\n  }\n});\n\n$.Autocompleter = function(input, options) {\n\n  var KEY = {\n    UP: 38,\n    DOWN: 40,\n    DEL: 46,\n    TAB: 9,\n    RETURN: 13,\n    ESC: 27,\n    COMMA: 188,\n    PAGEUP: 33,\n    PAGEDOWN: 34,\n    BACKSPACE: 8\n  };\n\n  // Create $ object for input element\n  var $input = $(input).attr(\"autocomplete\", \"off\").addClass(options.inputClass);\n\n  var timeout;\n  var previousValue = \"\";\n  var cache = $.Autocompleter.Cache(options);\n  var hasFocus = 0;\n  var lastKeyPressCode;\n  var config = {\n    mouseDownOnSelect: false\n  };\n  var select = $.Autocompleter.Select(options, input, selectCurrent, config);\n\n  var blockSubmit;\n\n  // prevent form submit in opera when selecting with return key\n  $.browser.opera && $(input.form).bind(\"submit.autocomplete\", function() {\n    if (blockSubmit) {\n      blockSubmit = false;\n      return false;\n    }\n  });\n\n  // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all\n  $input.bind(($.browser.opera ? \"keypress\" : \"keydown\") + \".autocomplete\", function(event) {\n    // a keypress means the input has focus\n    // avoids issue where input had focus before the autocomplete was applied\n    hasFocus = 1;\n    // track last key pressed\n    lastKeyPressCode = event.keyCode;\n    switch(event.keyCode) {\n\n      case KEY.UP:\n        event.preventDefault();\n        if ( select.visible() ) {\n          select.prev();\n        } else {\n          onChange(0, true);\n        }\n        break;\n\n      case KEY.DOWN:\n        event.preventDefault();\n        if ( select.visible() ) {\n          select.next();\n        } else {\n          onChange(0, true);\n        }\n        break;\n\n      case KEY.PAGEUP:\n        event.preventDefault();\n        if ( select.visible() ) {\n          select.pageUp();\n        } else {\n          onChange(0, true);\n        }\n        break;\n\n      case KEY.PAGEDOWN:\n        event.preventDefault();\n        if ( select.visible() ) {\n          select.pageDown();\n        } else {\n          onChange(0, true);\n        }\n        break;\n\n      // matches also semicolon\n      case options.multiple && $.trim(options.multipleSeparator) == \",\" && KEY.COMMA:\n      case KEY.TAB:\n      case KEY.RETURN:\n        if( selectCurrent() ) {\n          // stop default to prevent a form submit, Opera needs special handling\n          event.preventDefault();\n          blockSubmit = true;\n          return false;\n        }\n        break;\n\n      case KEY.ESC:\n        select.hide();\n        break;\n\n      default:\n        clearTimeout(timeout);\n        timeout = setTimeout(onChange, options.delay);\n        break;\n    }\n  }).focus(function(){\n    // track whether the field has focus, we shouldn't process any\n    // results if the field no longer has focus\n    hasFocus++;\n  }).blur(function() {\n    hasFocus = 0;\n    if (!config.mouseDownOnSelect) {\n      hideResults();\n    }\n  }).click(function() {\n    // show select when clicking in a focused field\n    if ( hasFocus++ > 1 && !select.visible() ) {\n      onChange(0, true);\n    }\n  }).bind(\"search\", function() {\n    // TODO why not just specifying both arguments?\n    var fn = (arguments.length > 1) ? arguments[1] : null;\n    function findValueCallback(q, data) {\n      var result;\n      if( data && data.length ) {\n        for (var i=0; i < data.length; i++) {\n          if( data[i].result.toLowerCase() == q.toLowerCase() ) {\n            result = data[i];\n            break;\n          }\n        }\n      }\n      if( typeof fn == \"function\" ) fn(result);\n      else $input.trigger(\"result\", result && [result.data, result.value]);\n    }\n    $.each(trimWords($input.val()), function(i, value) {\n      request(value, findValueCallback, findValueCallback);\n    });\n  }).bind(\"flushCache\", function() {\n    cache.flush();\n  }).bind(\"setOptions\", function() {\n    $.extend(options, arguments[1]);\n    // if we've updated the data, repopulate\n    if ( \"data\" in arguments[1] )\n      cache.populate();\n  }).bind(\"unautocomplete\", function() {\n    select.unbind();\n    $input.unbind();\n    $(input.form).unbind(\".autocomplete\");\n  });\n\n\n  function selectCurrent() {\n    var selected = select.selected();\n    if( !selected )\n      return false;\n\n    var v = selected.result;\n    previousValue = v;\n\n    if ( options.multiple ) {\n      var words = trimWords($input.val());\n      if ( words.length > 1 ) {\n        var seperator = options.multipleSeparator.length;\n        var cursorAt = $(input).selection().start;\n        var wordAt, progress = 0;\n        $.each(words, function(i, word) {\n          progress += word.length;\n          if (cursorAt <= progress) {\n            wordAt = i;\n            return false;\n          }\n          progress += seperator;\n        });\n        words[wordAt] = v;\n        // TODO this should set the cursor to the right position, but it gets overriden somewhere\n        //$.Autocompleter.Selection(input, progress + seperator, progress + seperator);\n        v = words.join( options.multipleSeparator );\n      }\n      v += options.multipleSeparator;\n    }\n\n    $input.val(v);\n    hideResultsNow();\n    $input.trigger(\"result\", [selected.data, selected.value]);\n    return true;\n  }\n\n  function onChange(crap, skipPrevCheck) {\n    if( lastKeyPressCode == KEY.DEL ) {\n      select.hide();\n      return;\n    }\n\n    var currentValue = $input.val();\n\n    if ( !skipPrevCheck && currentValue == previousValue )\n      return;\n\n    previousValue = currentValue;\n\n    currentValue = lastWord(currentValue);\n    if ( currentValue.length >= options.minChars) {\n      $input.addClass(options.loadingClass);\n      if (!options.matchCase)\n        currentValue = currentValue.toLowerCase();\n      request(currentValue, receiveData, hideResultsNow);\n    } else {\n      stopLoading();\n      select.hide();\n    }\n  };\n\n  function trimWords(value) {\n    if (!value)\n      return [\"\"];\n    if (!options.multiple)\n      return [$.trim(value)];\n    return $.map(value.split(options.multipleSeparator), function(word) {\n      return $.trim(value).length ? $.trim(word) : null;\n    });\n  }\n\n  function lastWord(value) {\n    if ( !options.multiple )\n      return value;\n    var words = trimWords(value);\n    if (words.length == 1)\n      return words[0];\n    var cursorAt = $(input).selection().start;\n    if (cursorAt == value.length) {\n      words = trimWords(value)\n    } else {\n      words = trimWords(value.replace(value.substring(cursorAt), \"\"));\n    }\n    return words[words.length - 1];\n  }\n\n  // fills in the input box w/the first match (assumed to be the best match)\n  // q: the term entered\n  // sValue: the first matching result\n  function autoFill(q, sValue){\n    // autofill in the complete box w/the first match as long as the user hasn't entered in more data\n    // if the last user key pressed was backspace, don't autofill\n    if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {\n      // fill in the value (keep the case the user has typed)\n      $input.val($input.val() + sValue.substring(lastWord(previousValue).length));\n      // select the portion of the value not typed by the user (so the next character will erase)\n      $(input).selection(previousValue.length, previousValue.length + sValue.length);\n    }\n  };\n\n  function hideResults() {\n    clearTimeout(timeout);\n    timeout = setTimeout(hideResultsNow, 200);\n  };\n\n  function hideResultsNow() {\n    var wasVisible = select.visible();\n    select.hide();\n    clearTimeout(timeout);\n    stopLoading();\n    if (options.mustMatch) {\n      // call search and run callback\n      $input.search(\n        function (result){\n          // if no value found, clear the input box\n          if( !result ) {\n            if (options.multiple) {\n              var words = trimWords($input.val()).slice(0, -1);\n              $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : \"\") );\n            }\n            else {\n              $input.val( \"\" );\n              $input.trigger(\"result\", null);\n            }\n          }\n        }\n      );\n    }\n  };\n\n  function receiveData(q, data) {\n    if ( data && data.length && hasFocus ) {\n      stopLoading();\n      select.display(data, q);\n      autoFill(q, data[0].value);\n      select.show();\n    } else {\n      hideResultsNow();\n    }\n  };\n\n  function request(term, success, failure) {\n    if (!options.matchCase)\n      term = term.toLowerCase();\n    var data = cache.load(term);\n    // recieve the cached data\n    if (data && data.length) {\n      success(term, data);\n    // if an AJAX url has been supplied, try loading the data now\n    } else if( (typeof options.url == \"string\") && (options.url.length > 0) ){\n\n      var extraParams = {\n        timestamp: +new Date()\n      };\n      $.each(options.extraParams, function(key, param) {\n        extraParams[key] = typeof param == \"function\" ? param() : param;\n      });\n\n      $.ajax({\n        // try to leverage ajaxQueue plugin to abort previous requests\n        mode: \"abort\",\n        // limit abortion to this input\n        port: \"autocomplete\" + input.name,\n        dataType: options.dataType,\n        url: options.url,\n        data: $.extend({\n          q: lastWord(term),\n          limit: options.max\n        }, extraParams),\n        success: function(data) {\n          var parsed = options.parse && options.parse(data) || parse(data);\n          cache.add(term, parsed);\n          success(term, parsed);\n        }\n      });\n    } else {\n      // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match\n      select.emptyList();\n      failure(term);\n    }\n  };\n\n  function parse(data) {\n    var parsed = [];\n    var rows = data.split(\"\\n\");\n    for (var i=0; i < rows.length; i++) {\n      var row = $.trim(rows[i]);\n      if (row) {\n        row = row.split(\"|\");\n        parsed[parsed.length] = {\n          data: row,\n          value: row[0],\n          result: options.formatResult && options.formatResult(row, row[0]) || row[0]\n        };\n      }\n    }\n    return parsed;\n  };\n\n  function stopLoading() {\n    $input.removeClass(options.loadingClass);\n  };\n\n};\n\n$.Autocompleter.defaults = {\n  inputClass: \"ac_input\",\n  resultsClass: \"ac_results\",\n  loadingClass: \"ac_loading\",\n  minChars: 1,\n  delay: 400,\n  matchCase: false,\n  matchSubset: true,\n  matchContains: false,\n  cacheLength: 10,\n  max: 100,\n  mustMatch: false,\n  extraParams: {},\n  selectFirst: true,\n  formatItem: function(row) { return row[0]; },\n  formatMatch: null,\n  autoFill: false,\n  width: 0,\n  multiple: false,\n  multipleSeparator: \", \",\n  highlight: function(value, term) {\n    return value.replace(new RegExp(\"(?![^&;]+;)(?!<[^<>]*)(\" + term.replace(/([\\^\\$\\(\\)\\[\\]\\{\\}\\*\\.\\+\\?\\|\\\\])/gi, \"\\\\$1\") + \")(?![^<>]*>)(?![^&;]+;)\", \"gi\"), \"<strong>$1</strong>\");\n  },\n    scroll: true,\n    scrollHeight: 180\n};\n\n$.Autocompleter.Cache = function(options) {\n\n  var data = {};\n  var length = 0;\n\n  function matchSubset(s, sub) {\n    if (!options.matchCase)\n      s = s.toLowerCase();\n    var i = s.indexOf(sub);\n    if (options.matchContains == \"word\"){\n      i = s.toLowerCase().search(\"\\\\b\" + sub.toLowerCase());\n    }\n    if (i == -1) return false;\n    return i == 0 || options.matchContains;\n  };\n\n  function add(q, value) {\n    if (length > options.cacheLength){\n      flush();\n    }\n    if (!data[q]){\n      length++;\n    }\n    data[q] = value;\n  }\n\n  function populate(){\n    if( !options.data ) return false;\n    // track the matches\n    var stMatchSets = {},\n      nullData = 0;\n\n    // no url was specified, we need to adjust the cache length to make sure it fits the local data store\n    if( !options.url ) options.cacheLength = 1;\n\n    // track all options for minChars = 0\n    stMatchSets[\"\"] = [];\n\n    // loop through the array and create a lookup structure\n    for ( var i = 0, ol = options.data.length; i < ol; i++ ) {\n      var rawValue = options.data[i];\n      // if rawValue is a string, make an array otherwise just reference the array\n      rawValue = (typeof rawValue == \"string\") ? [rawValue] : rawValue;\n\n      var value = options.formatMatch(rawValue, i+1, options.data.length);\n      if ( value === false )\n        continue;\n\n      var firstChar = value.charAt(0).toLowerCase();\n      // if no lookup array for this character exists, look it up now\n      if( !stMatchSets[firstChar] )\n        stMatchSets[firstChar] = [];\n\n      // if the match is a string\n      var row = {\n        value: value,\n        data: rawValue,\n        result: options.formatResult && options.formatResult(rawValue) || value\n      };\n\n      // push the current match into the set list\n      stMatchSets[firstChar].push(row);\n\n      // keep track of minChars zero items\n      if ( nullData++ < options.max ) {\n        stMatchSets[\"\"].push(row);\n      }\n    };\n\n    // add the data items to the cache\n    $.each(stMatchSets, function(i, value) {\n      // increase the cache size\n      options.cacheLength++;\n      // add to the cache\n      add(i, value);\n    });\n  }\n\n  // populate any existing data\n  setTimeout(populate, 25);\n\n  function flush(){\n    data = {};\n    length = 0;\n  }\n\n  return {\n    flush: flush,\n    add: add,\n    populate: populate,\n    load: function(q) {\n      if (!options.cacheLength || !length)\n        return null;\n      /*\n       * if dealing w/local data and matchContains than we must make sure\n       * to loop through all the data collections looking for matches\n       */\n      if( !options.url && options.matchContains ){\n        // track all matches\n        var csub = [];\n        // loop through all the data grids for matches\n        for( var k in data ){\n          // don't search through the stMatchSets[\"\"] (minChars: 0) cache\n          // this prevents duplicates\n          if( k.length > 0 ){\n            var c = data[k];\n            $.each(c, function(i, x) {\n              // if we've got a match, add it to the array\n              if (matchSubset(x.value, q)) {\n                csub.push(x);\n              }\n            });\n          }\n        }\n        return csub;\n      } else\n      // if the exact item exists, use it\n      if (data[q]){\n        return data[q];\n      } else\n      if (options.matchSubset) {\n        for (var i = q.length - 1; i >= options.minChars; i--) {\n          var c = data[q.substr(0, i)];\n          if (c) {\n            var csub = [];\n            $.each(c, function(i, x) {\n              if (matchSubset(x.value, q)) {\n                csub[csub.length] = x;\n              }\n            });\n            return csub;\n          }\n        }\n      }\n      return null;\n    }\n  };\n};\n\n$.Autocompleter.Select = function (options, input, select, config) {\n  var CLASSES = {\n    ACTIVE: \"ac_over\"\n  };\n\n  var listItems,\n    active = -1,\n    data,\n    term = \"\",\n    needsInit = true,\n    element,\n    list;\n\n  // Create results\n  function init() {\n    if (!needsInit)\n      return;\n    element = $(\"<div/>\")\n    .hide()\n    .addClass(options.resultsClass)\n    .css(\"position\", \"absolute\")\n    .appendTo(document.body);\n\n    list = $(\"<ul/>\").appendTo(element).mouseover( function(event) {\n      if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {\n              active = $(\"li\", list).removeClass(CLASSES.ACTIVE).index(target(event));\n          $(target(event)).addClass(CLASSES.ACTIVE);\n          }\n    }).click(function(event) {\n      $(target(event)).addClass(CLASSES.ACTIVE);\n      select();\n      // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus\n      input.focus();\n      return false;\n    }).mousedown(function() {\n      config.mouseDownOnSelect = true;\n    }).mouseup(function() {\n      config.mouseDownOnSelect = false;\n    });\n\n    if( options.width > 0 )\n      element.css(\"width\", options.width);\n\n    needsInit = false;\n  }\n\n  function target(event) {\n    var element = event.target;\n    while(element && element.tagName != \"LI\")\n      element = element.parentNode;\n    // more fun with IE, sometimes event.target is empty, just ignore it then\n    if(!element)\n      return [];\n    return element;\n  }\n\n  function moveSelect(step) {\n    listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);\n    movePosition(step);\n        var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);\n        if(options.scroll) {\n            var offset = 0;\n            listItems.slice(0, active).each(function() {\n        offset += this.offsetHeight;\n      });\n            if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {\n                list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());\n            } else if(offset < list.scrollTop()) {\n                list.scrollTop(offset);\n            }\n        }\n  };\n\n  function movePosition(step) {\n    active += step;\n    if (active < 0) {\n      active = listItems.size() - 1;\n    } else if (active >= listItems.size()) {\n      active = 0;\n    }\n  }\n\n  function limitNumberOfItems(available) {\n    return options.max && options.max < available\n      ? options.max\n      : available;\n  }\n\n  function fillList() {\n    list.empty();\n    var max = limitNumberOfItems(data.length);\n    for (var i=0; i < max; i++) {\n      if (!data[i])\n        continue;\n      var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);\n      if ( formatted === false )\n        continue;\n      var li = $(\"<li/>\").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? \"ac_even\" : \"ac_odd\").appendTo(list)[0];\n      $.data(li, \"ac_data\", data[i]);\n    }\n    listItems = list.find(\"li\");\n    if ( options.selectFirst ) {\n      listItems.slice(0, 1).addClass(CLASSES.ACTIVE);\n      active = 0;\n    }\n    // apply bgiframe if available\n    if ( $.fn.bgiframe )\n      list.bgiframe();\n  }\n\n  return {\n    display: function(d, q) {\n      init();\n      data = d;\n      term = q;\n      fillList();\n    },\n    next: function() {\n      moveSelect(1);\n    },\n    prev: function() {\n      moveSelect(-1);\n    },\n    pageUp: function() {\n      if (active != 0 && active - 8 < 0) {\n        moveSelect( -active );\n      } else {\n        moveSelect(-8);\n      }\n    },\n    pageDown: function() {\n      if (active != listItems.size() - 1 && active + 8 > listItems.size()) {\n        moveSelect( listItems.size() - 1 - active );\n      } else {\n        moveSelect(8);\n      }\n    },\n    hide: function() {\n      element && element.hide();\n      listItems && listItems.removeClass(CLASSES.ACTIVE);\n      active = -1;\n    },\n    visible : function() {\n      return element && element.is(\":visible\");\n    },\n    current: function() {\n      return this.visible() && (listItems.filter(\".\" + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);\n    },\n    show: function() {\n      var offset = $(input).offset();\n      element.css({\n        width: typeof options.width == \"string\" || options.width > 0 ? options.width : $(input).width(),\n        top: offset.top + input.offsetHeight,\n        left: offset.left\n      }).show();\n            if(options.scroll) {\n                list.scrollTop(0);\n                list.css({\n          maxHeight: options.scrollHeight,\n          overflow: 'auto'\n        });\n\n                if($.browser.msie && typeof document.body.style.maxHeight === \"undefined\") {\n          var listHeight = 0;\n          listItems.each(function() {\n            listHeight += this.offsetHeight;\n          });\n          var scrollbarsVisible = listHeight > options.scrollHeight;\n                    list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );\n          if (!scrollbarsVisible) {\n            // IE doesn't recalculate width when scrollbar disappears\n            listItems.width( list.width() - parseInt(listItems.css(\"padding-left\")) - parseInt(listItems.css(\"padding-right\")) );\n          }\n                }\n\n            }\n    },\n    selected: function() {\n      var selected = listItems && listItems.filter(\".\" + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);\n      return selected && selected.length && $.data(selected[0], \"ac_data\");\n    },\n    emptyList: function (){\n      list && list.empty();\n    },\n    unbind: function() {\n      element && element.remove();\n    }\n  };\n};\n\n$.fn.selection = function(start, end) {\n  if (start !== undefined) {\n    return this.each(function() {\n      if( this.createTextRange ){\n        var selRange = this.createTextRange();\n        if (end === undefined || start == end) {\n          selRange.move(\"character\", start);\n          selRange.select();\n        } else {\n          selRange.collapse(true);\n          selRange.moveStart(\"character\", start);\n          selRange.moveEnd(\"character\", end);\n          selRange.select();\n        }\n      } else if( this.setSelectionRange ){\n        this.setSelectionRange(start, end);\n      } else if( this.selectionStart ){\n        this.selectionStart = start;\n        this.selectionEnd = end;\n      }\n    });\n  }\n  var field = this[0];\n  if ( field.createTextRange ) {\n    var range = document.selection.createRange(),\n      orig = field.value,\n      teststring = \"<->\",\n      textLength = range.text.length;\n    range.text = teststring;\n    var caretAt = field.value.indexOf(teststring);\n    field.value = orig;\n    this.selection(caretAt, caretAt + textLength);\n    return {\n      start: caretAt,\n      end: caretAt + textLength\n    }\n  } else if( field.selectionStart !== undefined ){\n    return {\n      start: field.selectionStart,\n      end: field.selectionEnd\n    }\n  }\n};\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.autocomplete.pack.js",
    "content": "/*\n * jQuery Autocomplete plugin 1.1\n *\n * Copyright (c) 2009 Jörn Zaefferer\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n *\n * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $\n */\neval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}(';(3($){$.2e.1u({19:3(b,d){5 c=W b==\"1B\";d=$.1u({},$.M.1T,{Y:c?b:P,y:c?P:b,1J:c?$.M.1T.1J:10,X:d&&!d.1D?10:48},d);d.1y=d.1y||3(a){6 a};d.1v=d.1v||d.1R;6 A.I(3(){1M $.M(A,d)})},L:3(a){6 A.11(\"L\",a)},1k:3(a){6 A.14(\"1k\",[a])},2b:3(){6 A.14(\"2b\")},28:3(a){6 A.14(\"28\",[a])},24:3(){6 A.14(\"24\")}});$.M=3(o,r){5 t={2Y:38,2S:40,2N:46,2I:9,2E:13,2B:27,2x:3I,2v:33,2p:34,2n:8};5 u=$(o).3r(\"19\",\"3o\").Q(r.2Q);5 p;5 m=\"\";5 n=$.M.3c(r);5 s=0;5 k;5 h={1F:C};5 l=$.M.32(r,o,1Z,h);5 j;$.1Y.2X&&$(o.2U).11(\"45.19\",3(){4(j){j=C;6 C}});u.11(($.1Y.2X?\"43\":\"42\")+\".19\",3(a){s=1;k=a.2M;3V(a.2M){O t.2Y:a.1d();4(l.N()){l.30()}w{12(0,D)}R;O t.2S:a.1d();4(l.N()){l.2D()}w{12(0,D)}R;O t.2v:a.1d();4(l.N()){l.2C()}w{12(0,D)}R;O t.2p:a.1d();4(l.N()){l.2A()}w{12(0,D)}R;O r.17&&$.1c(r.S)==\",\"&&t.2x:O t.2I:O t.2E:4(1Z()){a.1d();j=D;6 C}R;O t.2B:l.Z();R;3J:1P(p);p=1O(12,r.1J);R}}).2t(3(){s++}).3E(3(){s=0;4(!h.1F){2r()}}).2q(3(){4(s++>1&&!l.N()){12(0,D)}}).11(\"1k\",3(){5 c=(1r.7>1)?1r[1]:P;3 1N(q,a){5 b;4(a&&a.7){16(5 i=0;i<a.7;i++){4(a[i].L.J()==q.J()){b=a[i];R}}}4(W c==\"3\")c(b);w u.14(\"L\",b&&[b.y,b.F])}$.I(15(u.K()),3(i,a){21(a,1N,1N)})}).11(\"2b\",3(){n.1o()}).11(\"28\",3(){$.1u(r,1r[1]);4(\"y\"2h 1r[1])n.1e()}).11(\"24\",3(){l.1p();u.1p();$(o.2U).1p(\".19\")});3 1Z(){5 e=l.2g();4(!e)6 C;5 v=e.L;m=v;4(r.17){5 b=15(u.K());4(b.7>1){5 f=r.S.7;5 c=$(o).18().1I;5 d,1H=0;$.I(b,3(i,a){1H+=a.7;4(c<=1H){d=i;6 C}1H+=f});b[d]=v;v=b.3f(r.S)}v+=r.S}u.K(v);1l();u.14(\"L\",[e.y,e.F]);6 D}3 12(b,c){4(k==t.2N){l.Z();6}5 a=u.K();4(!c&&a==m)6;m=a;a=1m(a);4(a.7>=r.29){u.Q(r.26);4(!r.1s)a=a.J();21(a,3a,1l)}w{1q();l.Z()}};3 15(b){4(!b)6[\"\"];4(!r.17)6[$.1c(b)];6 $.4h(b.23(r.S),3(a){6 $.1c(b).7?$.1c(a):P})}3 1m(a){4(!r.17)6 a;5 c=15(a);4(c.7==1)6 c[0];5 b=$(o).18().1I;4(b==a.7){c=15(a)}w{c=15(a.22(a.37(b),\"\"))}6 c[c.7-1]}3 1G(q,a){4(r.1G&&(1m(u.K()).J()==q.J())&&k!=t.2n){u.K(u.K()+a.37(1m(m).7));$(o).18(m.7,m.7+a.7)}};3 2r(){1P(p);p=1O(1l,4g)};3 1l(){5 c=l.N();l.Z();1P(p);1q();4(r.36){u.1k(3(a){4(!a){4(r.17){5 b=15(u.K()).1n(0,-1);u.K(b.3f(r.S)+(b.7?r.S:\"\"))}w{u.K(\"\");u.14(\"L\",P)}}})}};3 3a(q,a){4(a&&a.7&&s){1q();l.35(a,q);1G(q,a[0].F);l.20()}w{1l()}};3 21(f,d,g){4(!r.1s)f=f.J();5 e=n.31(f);4(e&&e.7){d(f,e)}w 4((W r.Y==\"1B\")&&(r.Y.7>0)){5 c={4f:+1M 4e()};$.I(r.2Z,3(a,b){c[a]=W b==\"3\"?b():b});$.4d({4c:\"4b\",4a:\"19\"+o.49,2V:r.2V,Y:r.Y,y:$.1u({q:1m(f),47:r.X},c),44:3(a){5 b=r.1A&&r.1A(a)||1A(a);n.1i(f,b);d(f,b)}})}w{l.2T();g(f)}};3 1A(c){5 d=[];5 b=c.23(\"\\\\n\");16(5 i=0;i<b.7;i++){5 a=$.1c(b[i]);4(a){a=a.23(\"|\");d[d.7]={y:a,F:a[0],L:r.1z&&r.1z(a,a[0])||a[0]}}}6 d};3 1q(){u.1h(r.26)}};$.M.1T={2Q:\"41\",2P:\"3Z\",26:\"3Y\",29:1,1J:3W,1s:C,1f:D,1w:C,1g:10,X:3U,36:C,2Z:{},1X:D,1R:3(a){6 a[0]},1v:P,1G:C,E:0,17:C,S:\", \",1y:3(b,a){6 b.22(1M 3T(\"(?![^&;]+;)(?!<[^<>]*)(\"+a.22(/([\\\\^\\\\$\\\\(\\\\)\\\\[\\\\]\\\\{\\\\}\\\\*\\\\.\\\\+\\\\?\\\\|\\\\\\\\])/2K,\"\\\\\\\\$1\")+\")(?![^<>]*>)(?![^&;]+;)\",\"2K\"),\"<2J>$1</2J>\")},1D:D,1E:3S};$.M.3c=3(g){5 h={};5 j=0;3 1f(s,a){4(!g.1s)s=s.J();5 i=s.2H(a);4(g.1w==\"3R\"){i=s.J().1k(\"\\\\\\\\b\"+a.J())}4(i==-1)6 C;6 i==0||g.1w};3 1i(q,a){4(j>g.1g){1o()}4(!h[q]){j++}h[q]=a}3 1e(){4(!g.y)6 C;5 f={},2G=0;4(!g.Y)g.1g=1;f[\"\"]=[];16(5 i=0,2F=g.y.7;i<2F;i++){5 c=g.y[i];c=(W c==\"1B\")?[c]:c;5 d=g.1v(c,i+1,g.y.7);4(d===C)1V;5 e=d.3Q(0).J();4(!f[e])f[e]=[];5 b={F:d,y:c,L:g.1z&&g.1z(c)||d};f[e].1U(b);4(2G++<g.X){f[\"\"].1U(b)}};$.I(f,3(i,a){g.1g++;1i(i,a)})}1O(1e,25);3 1o(){h={};j=0}6{1o:1o,1i:1i,1e:1e,31:3(q){4(!g.1g||!j)6 P;4(!g.Y&&g.1w){5 a=[];16(5 k 2h h){4(k.7>0){5 c=h[k];$.I(c,3(i,x){4(1f(x.F,q)){a.1U(x)}})}}6 a}w 4(h[q]){6 h[q]}w 4(g.1f){16(5 i=q.7-1;i>=g.29;i--){5 c=h[q.3O(0,i)];4(c){5 a=[];$.I(c,3(i,x){4(1f(x.F,q)){a[a.7]=x}});6 a}}}6 P}}};$.M.32=3(e,g,f,k){5 h={H:\"3N\"};5 j,z=-1,y,1t=\"\",1S=D,G,B;3 2y(){4(!1S)6;G=$(\"<3M/>\").Z().Q(e.2P).T(\"3L\",\"3K\").1Q(1K.2w);B=$(\"<3H/>\").1Q(G).3G(3(a){4(U(a).2u&&U(a).2u.3F()==\\'2s\\'){z=$(\"1L\",B).1h(h.H).3D(U(a));$(U(a)).Q(h.H)}}).2q(3(a){$(U(a)).Q(h.H);f();g.2t();6 C}).3C(3(){k.1F=D}).3B(3(){k.1F=C});4(e.E>0)G.T(\"E\",e.E);1S=C}3 U(a){5 b=a.U;3A(b&&b.3z!=\"2s\")b=b.3y;4(!b)6[];6 b}3 V(b){j.1n(z,z+1).1h(h.H);2o(b);5 a=j.1n(z,z+1).Q(h.H);4(e.1D){5 c=0;j.1n(0,z).I(3(){c+=A.1a});4((c+a[0].1a-B.1b())>B[0].3x){B.1b(c+a[0].1a-B.3w())}w 4(c<B.1b()){B.1b(c)}}};3 2o(a){z+=a;4(z<0){z=j.1j()-1}w 4(z>=j.1j()){z=0}}3 2m(a){6 e.X&&e.X<a?e.X:a}3 2l(){B.2z();5 b=2m(y.7);16(5 i=0;i<b;i++){4(!y[i])1V;5 a=e.1R(y[i].y,i+1,b,y[i].F,1t);4(a===C)1V;5 c=$(\"<1L/>\").3v(e.1y(a,1t)).Q(i%2==0?\"3u\":\"3P\").1Q(B)[0];$.y(c,\"2k\",y[i])}j=B.3t(\"1L\");4(e.1X){j.1n(0,1).Q(h.H);z=0}4($.2e.2W)B.2W()}6{35:3(d,q){2y();y=d;1t=q;2l()},2D:3(){V(1)},30:3(){V(-1)},2C:3(){4(z!=0&&z-8<0){V(-z)}w{V(-8)}},2A:3(){4(z!=j.1j()-1&&z+8>j.1j()){V(j.1j()-1-z)}w{V(8)}},Z:3(){G&&G.Z();j&&j.1h(h.H);z=-1},N:3(){6 G&&G.3s(\":N\")},3q:3(){6 A.N()&&(j.2j(\".\"+h.H)[0]||e.1X&&j[0])},20:3(){5 a=$(g).3p();G.T({E:W e.E==\"1B\"||e.E>0?e.E:$(g).E(),2i:a.2i+g.1a,1W:a.1W}).20();4(e.1D){B.1b(0);B.T({2L:e.1E,3n:\\'3X\\'});4($.1Y.3m&&W 1K.2w.3l.2L===\"1x\"){5 c=0;j.I(3(){c+=A.1a});5 b=c>e.1E;B.T(\\'3k\\',b?e.1E:c);4(!b){j.E(B.E()-2R(j.T(\"2O-1W\"))-2R(j.T(\"2O-3j\")))}}}},2g:3(){5 a=j&&j.2j(\".\"+h.H).1h(h.H);6 a&&a.7&&$.y(a[0],\"2k\")},2T:3(){B&&B.2z()},1p:3(){G&&G.3i()}}};$.2e.18=3(b,f){4(b!==1x){6 A.I(3(){4(A.2d){5 a=A.2d();4(f===1x||b==f){a.4n(\"2c\",b);a.3h()}w{a.4m(D);a.4l(\"2c\",b);a.4k(\"2c\",f);a.3h()}}w 4(A.3g){A.3g(b,f)}w 4(A.1C){A.1C=b;A.3e=f}})}5 c=A[0];4(c.2d){5 e=1K.18.4j(),3d=c.F,2a=\"<->\",2f=e.3b.7;e.3b=2a;5 d=c.F.2H(2a);c.F=3d;A.18(d,d+2f);6{1I:d,39:d+2f}}w 4(c.1C!==1x){6{1I:c.1C,39:c.3e}}}})(4i);',62,272,'|||function|if|var|return|length|||||||||||||||||||||||||else||data|active|this|list|false|true|width|value|element|ACTIVE|each|toLowerCase|val|result|Autocompleter|visible|case|null|addClass|break|multipleSeparator|css|target|moveSelect|typeof|max|url|hide||bind|onChange||trigger|trimWords|for|multiple|selection|autocomplete|offsetHeight|scrollTop|trim|preventDefault|populate|matchSubset|cacheLength|removeClass|add|size|search|hideResultsNow|lastWord|slice|flush|unbind|stopLoading|arguments|matchCase|term|extend|formatMatch|matchContains|undefined|highlight|formatResult|parse|string|selectionStart|scroll|scrollHeight|mouseDownOnSelect|autoFill|progress|start|delay|document|li|new|findValueCallback|setTimeout|clearTimeout|appendTo|formatItem|needsInit|defaults|push|continue|left|selectFirst|browser|selectCurrent|show|request|replace|split|unautocomplete||loadingClass||setOptions|minChars|teststring|flushCache|character|createTextRange|fn|textLength|selected|in|top|filter|ac_data|fillList|limitNumberOfItems|BACKSPACE|movePosition|PAGEDOWN|click|hideResults|LI|focus|nodeName|PAGEUP|body|COMMA|init|empty|pageDown|ESC|pageUp|next|RETURN|ol|nullData|indexOf|TAB|strong|gi|maxHeight|keyCode|DEL|padding|resultsClass|inputClass|parseInt|DOWN|emptyList|form|dataType|bgiframe|opera|UP|extraParams|prev|load|Select|||display|mustMatch|substring||end|receiveData|text|Cache|orig|selectionEnd|join|setSelectionRange|select|remove|right|height|style|msie|overflow|off|offset|current|attr|is|find|ac_even|html|innerHeight|clientHeight|parentNode|tagName|while|mouseup|mousedown|index|blur|toUpperCase|mouseover|ul|188|default|absolute|position|div|ac_over|substr|ac_odd|charAt|word|180|RegExp|100|switch|400|auto|ac_loading|ac_results||ac_input|keydown|keypress|success|submit||limit|150|name|port|abort|mode|ajax|Date|timestamp|200|map|jQuery|createRange|moveEnd|moveStart|collapse|move'.split('|'),0,{}))\n"
  },
  {
    "path": "public/javascripts/jquery.easing-1.3.pack.js",
    "content": "/*\n * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/\n *\n * Uses the built in easing capabilities added In jQuery 1.1\n * to offer multiple easing options\n *\n * TERMS OF USE - jQuery Easing\n *\n * Open source under the BSD License.\n *\n * Copyright © 2008 George McGinley Smith\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * Redistributions of source code must retain the above copyright notice, this list of\n * conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, this list\n * of conditions and the following disclaimer in the documentation and/or other materials\n * provided with the distribution.\n *\n * Neither the name of the author nor the names of contributors may be used to endorse\n * or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n*/\n\n// t: current time, b: begInnIng value, c: change In value, d: duration\neval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('h.i[\\'1a\\']=h.i[\\'z\\'];h.O(h.i,{y:\\'D\\',z:9(x,t,b,c,d){6 h.i[h.i.y](x,t,b,c,d)},17:9(x,t,b,c,d){6 c*(t/=d)*t+b},D:9(x,t,b,c,d){6-c*(t/=d)*(t-2)+b},13:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t+b;6-c/2*((--t)*(t-2)-1)+b},X:9(x,t,b,c,d){6 c*(t/=d)*t*t+b},U:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t+1)+b},R:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t+b;6 c/2*((t-=2)*t*t+2)+b},N:9(x,t,b,c,d){6 c*(t/=d)*t*t*t+b},M:9(x,t,b,c,d){6-c*((t=t/d-1)*t*t*t-1)+b},L:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t+b;6-c/2*((t-=2)*t*t*t-2)+b},K:9(x,t,b,c,d){6 c*(t/=d)*t*t*t*t+b},J:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t*t*t+1)+b},I:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t*t+b;6 c/2*((t-=2)*t*t*t*t+2)+b},G:9(x,t,b,c,d){6-c*8.C(t/d*(8.g/2))+c+b},15:9(x,t,b,c,d){6 c*8.n(t/d*(8.g/2))+b},12:9(x,t,b,c,d){6-c/2*(8.C(8.g*t/d)-1)+b},Z:9(x,t,b,c,d){6(t==0)?b:c*8.j(2,10*(t/d-1))+b},Y:9(x,t,b,c,d){6(t==d)?b+c:c*(-8.j(2,-10*t/d)+1)+b},W:9(x,t,b,c,d){e(t==0)6 b;e(t==d)6 b+c;e((t/=d/2)<1)6 c/2*8.j(2,10*(t-1))+b;6 c/2*(-8.j(2,-10*--t)+2)+b},V:9(x,t,b,c,d){6-c*(8.o(1-(t/=d)*t)-1)+b},S:9(x,t,b,c,d){6 c*8.o(1-(t=t/d-1)*t)+b},Q:9(x,t,b,c,d){e((t/=d/2)<1)6-c/2*(8.o(1-t*t)-1)+b;6 c/2*(8.o(1-(t-=2)*t)+1)+b},P:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6-(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b},H:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6 a*8.j(2,-10*t)*8.n((t*d-s)*(2*8.g)/p)+c+b},T:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d/2)==2)6 b+c;e(!p)p=d*(.3*1.5);e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);e(t<1)6-.5*(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b;6 a*8.j(2,-10*(t-=1))*8.n((t*d-s)*(2*8.g)/p)*.5+c+b},F:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*(t/=d)*t*((s+1)*t-s)+b},E:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*((t=t/d-1)*t*((s+1)*t+s)+1)+b},16:9(x,t,b,c,d,s){e(s==u)s=1.l;e((t/=d/2)<1)6 c/2*(t*t*(((s*=(1.B))+1)*t-s))+b;6 c/2*((t-=2)*t*(((s*=(1.B))+1)*t+s)+2)+b},A:9(x,t,b,c,d){6 c-h.i.v(x,d-t,0,c,d)+b},v:9(x,t,b,c,d){e((t/=d)<(1/2.k)){6 c*(7.q*t*t)+b}m e(t<(2/2.k)){6 c*(7.q*(t-=(1.5/2.k))*t+.k)+b}m e(t<(2.5/2.k)){6 c*(7.q*(t-=(2.14/2.k))*t+.11)+b}m{6 c*(7.q*(t-=(2.18/2.k))*t+.19)+b}},1b:9(x,t,b,c,d){e(t<d/2)6 h.i.A(x,t*2,0,c,d)*.5+b;6 h.i.v(x,t*2-d,0,c,d)*.5+c*.5+b}});',62,74,'||||||return||Math|function|||||if|var|PI|jQuery|easing|pow|75|70158|else|sin|sqrt||5625|asin|||undefined|easeOutBounce|abs||def|swing|easeInBounce|525|cos|easeOutQuad|easeOutBack|easeInBack|easeInSine|easeOutElastic|easeInOutQuint|easeOutQuint|easeInQuint|easeInOutQuart|easeOutQuart|easeInQuart|extend|easeInElastic|easeInOutCirc|easeInOutCubic|easeOutCirc|easeInOutElastic|easeOutCubic|easeInCirc|easeInOutExpo|easeInCubic|easeOutExpo|easeInExpo||9375|easeInOutSine|easeInOutQuad|25|easeOutSine|easeInOutBack|easeInQuad|625|984375|jswing|easeInOutBounce'.split('|'),0,{}))\n\n/*\n *\n * TERMS OF USE - EASING EQUATIONS\n *\n * Open source under the BSD License.\n *\n * Copyright © 2001 Robert Penner\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * Redistributions of source code must retain the above copyright notice, this list of\n * conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, this list\n * of conditions and the following disclaimer in the documentation and/or other materials\n * provided with the distribution.\n *\n * Neither the name of the author nor the names of contributors may be used to endorse\n * or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n"
  },
  {
    "path": "public/javascripts/jquery.em.js",
    "content": "/**\n * @projectDescription Monitor Font Size Changes with jQuery\n *\n * @version 1.0\n * @author Dave Cardwell\n *\n * jQuery-Em - $Revision: 24 $ ($Date: 2007-08-19 11:24:56 +0100 (Sun, 19 Aug 2007) $)\n * http://davecardwell.co.uk/javascript/jquery/plugins/jquery-em/\n *\n * Copyright ©2007 Dave Cardwell <http://davecardwell.co.uk/>\n *\n * Released under the MIT licence:\n * http://www.opensource.org/licenses/mit-license.php\n */\n\n// Upon $(document).ready()…\njQuery(function($) {\n    // Configuration…\n    var eventName = 'emchange';\n\n\n    // Set up default options.\n    $.em = $.extend({\n        /**\n         * The jQuery-Em version string.\n         *\n         * @example $.em.version;\n         * @desc '1.0a'\n         *\n         * @property\n         * @name version\n         * @type String\n         * @cat Plugins/Em\n         */\n        version: '1.0',\n\n        /**\n         * The number of milliseconds to wait when polling for changes to the\n         * font size.\n         *\n         * @example $.em.delay = 400;\n         * @desc Defaults to 200.\n         *\n         * @property\n         * @name delay\n         * @type Number\n         * @cat Plugins/Em\n         */\n        delay: 200,\n\n        /**\n         * The element used to detect changes to the font size.\n         *\n         * @example $.em.element = $('<div />')[0];\n         * @desc Default is an empty, absolutely positioned, 100em-wide <div>.\n         *\n         * @private\n         * @property\n         * @name element\n         * @type Element\n         * @cat Plugins/Em\n         */\n        element: $('<div />').css({ left:     '-100em',\n                                    position: 'absolute',\n                                    width:    '100em' })\n                             .prependTo('body')[0],\n\n        /**\n         * The action to perform when a change in the font size is detected.\n         *\n         * @example $.em.action = function() { ... }\n         * @desc The default action is to trigger a global “emchange” event.\n         * You probably shouldn’t change this behaviour as other plugins may\n         * rely on it, but the option is here for completion.\n         *\n         * @example $(document).bind('emchange', function(e, cur, prev) {...})\n         * @desc Any functions triggered on this event are passed the current\n         * font size, and last known font size as additional parameters.\n         *\n         * @private\n         * @property\n         * @name action\n         * @type Function\n         * @cat Plugins/Em\n         * @see current\n         * @see previous\n         */\n        action: function() {\n            var currentWidth = $.em.element.offsetWidth / 100;\n\n            // If the font size has changed since we last checked…\n            if ( currentWidth != $.em.current ) {\n                /**\n                 * The previous pixel value of the user agent’s font size. See\n                 * $.em.current for caveats. Will initially be undefined until\n                 * the “emchange” event is triggered.\n                 *\n                 * @example $.em.previous;\n                 * @result 16\n                 *\n                 * @property\n                 * @name previous\n                 * @type Number\n                 * @cat Plugins/Em\n                 * @see current\n                 */\n                $.em.previous = $.em.current;\n\n                /**\n                 * The current pixel value of the user agent’s font size. As\n                 * with $.em.previous, this value *may* be subject to minor\n                 * browser rounding errors that mean you might not want to\n                 * rely upon it as an absolute value.\n                 *\n                 * @example $.em.current;\n                 * @result 14\n                 *\n                 * @property\n                 * @name current\n                 * @type Number\n                 * @cat Plugins/Em\n                 * @see previous\n                 */\n                $.em.current = currentWidth;\n\n                $.event.trigger(eventName, [$.em.current, $.em.previous]);\n            }\n        }\n    }, $.em );\n\n\n    /**\n     * Bind a function to the emchange event of each matched element.\n     *\n     * @example $(\"p\").emchange( function() { alert(\"Hello\"); } );\n     *\n     * @name emchange\n     * @type jQuery\n     * @param Function fn A function to bind to the emchange event.\n     * @cat Plugins/Em\n     */\n\n    /**\n     * Trigger the emchange event of each matched element.\n     *\n     * @example $(\"p\").emchange()\n     *\n     * @name emchange\n     * @type jQuery\n     * @cat Plugins/Em\n     */\n    $.fn[eventName] = function(fn) { return fn ? this.bind(eventName, fn)\n                                               : this.trigger(eventName); };\n\n\n    // Store the initial pixel value of the user agent’s font size.\n    $.em.current = $.em.element.offsetWidth / 100;\n\n    /**\n     * While polling for font-size changes, $.em.iid stores the intervalID in\n     * case you should want to cancel with clearInterval().\n     *\n     * @example window.clearInterval( $.em.iid );\n     *\n     * @property\n     * @name iid\n     * @type Number\n     * @cat Plugins/Em\n     */\n    $.em.iid = setInterval( $.em.action, $.em.delay );\n});\n"
  },
  {
    "path": "public/javascripts/jquery.fancybox-1.3.0.js",
    "content": "/*\n * FancyBox - jQuery Plugin\n * Simple and fancy lightbox alternative\n *\n * Copyright (c) 20010 Janis Skarnelis\n * Examples and documentation at: http://fancybox.net\n *\n * Version: 1.3.0 (02/02/2010)\n * Requires: jQuery v1.3+\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n */\n\n;(function($) {\n\n  var tmp, loading, overlay, wrap, outer, inner, content, close, nav_left, nav_right;\n\n  var selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [];\n\n  var ajaxLoader = null, imgPreloader = new Image, imageRegExp = /\\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\\.]\\.(swf)\\s*$/i;\n\n  var loadingTimer, loadingFrame = 1;\n\n  var start_pos, final_pos, busy = false, shadow = 20, fx = $.extend($('<div/>')[0], { prop: 0 }), titleh = 0, isIE6 = !$.support.opacity && !window.XMLHttpRequest;\n\n  $.fn.fixPNG = function() {\n    return this.each(function () {\n      var image = $(this).css('backgroundImage');\n\n      if (image.match(/^url\\([\"']?(.*\\.png)[\"']?\\)$/i)) {\n        image = RegExp.$1;\n        $(this).css({\n          'backgroundImage': 'none',\n          'filter': \"progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=\" + ($(this).css('backgroundRepeat') == 'no-repeat' ? 'crop' : 'scale') + \", src='\" + image + \"')\"\n        }).each(function () {\n          var position = $(this).css('position');\n          if (position != 'absolute' && position != 'relative')\n            $(this).css('position', 'relative');\n        }).css('zoom', 1);\n      }\n    });\n  };\n\n  $.fn.fancybox = function(options) {\n    $(this).data('fancybox', $.extend({}, options));\n\n    $(this).unbind('click.fb').bind('click.fb', function(e) {\n      e.preventDefault();\n\n      if (busy) return;\n\n      busy = true;\n\n      $(this).blur();\n\n      selectedArray  = [];\n      selectedIndex  = 0;\n\n      var rel = $(this).attr('rel') || '';\n\n      if (!rel || rel == '' || rel === 'nofollow') {\n        selectedArray.push(this);\n\n      } else {\n        selectedArray  = $(\"a[rel=\" + rel + \"], area[rel=\" + rel + \"]\");\n        selectedIndex  = selectedArray.index( this );\n      }\n\n      fancybox_start();\n\n      return false;\n    });\n\n    return this;\n  };\n\n  /*\n\n  Public Methods\n\n  */\n\n  $.fancybox = function(obj, opts) {\n    if (busy) return;\n\n    busy = true;\n\n    selectedArray  = [];\n    selectedIndex  = 0;\n\n    if ($.isArray(obj)) {\n      for (var i = 0, j = obj.length; i < j; i++) {\n        if (typeof obj[i] == 'object') {\n          $(obj[i]).data('fancybox', $.extend({}, opts, obj[i]));\n        } else {\n          obj[i] = $({}).data('fancybox', $.extend({content : obj[i]}, opts));\n        }\n      }\n\n      selectedArray = jQuery.merge(selectedArray, obj);\n\n    } else {\n      if (typeof obj == 'object') {\n        $(obj).data('fancybox', $.extend({}, opts, obj));\n      } else {\n        obj = $({}).data('fancybox', $.extend({content : obj}, opts));\n      }\n\n      selectedArray.push(obj);\n    }\n\n    fancybox_start();\n  };\n\n  $.fancybox.showActivity = function() {\n    clearInterval(loadingTimer);\n\n    loading.show();\n    loadingTimer = setInterval(fancybox_animate_loading, 66);\n  };\n\n  $.fancybox.hideActivity = function() {\n    loading.hide();\n  };\n\n  $.fancybox.next = function() {\n    return $.fancybox.pos( currentIndex + 1);\n  };\n\n  $.fancybox.prev = function() {\n    return $.fancybox.pos( currentIndex - 1);\n  };\n\n  $.fancybox.pos = function(pos) {\n    if (busy) return;\n\n    pos = parseInt(pos);\n\n    if (pos > -1 && currentArray.length > pos) {\n      selectedIndex = pos;\n      fancybox_start();\n    }\n\n    if (currentOpts.cyclic && currentArray.length > 1 && pos < 0) {\n      selectedIndex = currentArray.length - 1;\n      fancybox_start();\n    }\n\n    if (currentOpts.cyclic && currentArray.length > 1 && pos >= currentArray.length) {\n      selectedIndex = 0;\n      fancybox_start();\n    }\n\n    return;\n  };\n\n  $.fancybox.cancel = function() {\n    if (busy) return;\n\n    busy = true;\n\n    $.event.trigger('fancybox-cancel');\n\n    fancybox_abort();\n\n    if (selectedOpts && $.isFunction(selectedOpts.onCancel)) {\n      selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts);\n    };\n\n    busy = false;\n  };\n\n  // Note: within an iframe use - parent.$.fancybox.close();\n  $.fancybox.close = function() {\n    if (busy || wrap.is(':hidden')) return;\n\n    busy = true;\n\n    if (currentOpts && $.isFunction(currentOpts.onCleanup)) {\n      if (currentOpts.onCleanup(currentArray, currentIndex, currentOpts) === false) {\n        busy = false;\n        return;\n      }\n    };\n\n    fancybox_abort();\n\n    $(close.add( nav_left ).add( nav_right )).hide();\n\n    $('#fancybox-title').remove();\n\n    wrap.add(inner).add(overlay).unbind();\n\n    $(window).unbind(\"resize.fb scroll.fb\");\n    $(document).unbind('keydown.fb');\n\n    function _cleanup() {\n      overlay.fadeOut('fast');\n\n      wrap.hide();\n\n      $.event.trigger('fancybox-cleanup');\n\n      inner.empty();\n\n      if ($.isFunction(currentOpts.onClosed)) {\n        currentOpts.onClosed(currentArray, currentIndex, currentOpts);\n      }\n\n      currentArray  = selectedOpts  = [];\n      currentIndex  = selectedIndex  = 0;\n      currentOpts    = selectedOpts  = {};\n\n      busy = false;\n    }\n\n    inner.css('overflow', 'hidden');\n\n    if (currentOpts.transitionOut == 'elastic') {\n      start_pos = fancybox_get_zoom_from();\n\n      var pos = wrap.position();\n\n      final_pos = {\n        top    :  pos.top ,\n        left  :  pos.left,\n        width  :  wrap.width(),\n        height  :  wrap.height()\n      };\n\n      if (currentOpts.opacity) {\n        final_pos.opacity = 1;\n      }\n\n      fx.prop = 1;\n\n      $(fx).animate({ prop: 0 }, {\n         duration  : currentOpts.speedOut,\n         easing    : currentOpts.easingOut,\n         step    : fancybox_draw,\n         complete  : _cleanup\n      });\n\n    } else {\n      wrap.fadeOut( currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup);\n    }\n  };\n\n  $.fancybox.resize = function() {\n    if (busy || wrap.is(':hidden')) return;\n\n    busy = true;\n\n    var c = inner.wrapInner(\"<div style='overflow:auto'></div>\").children();\n    var h = c.height();\n\n    wrap.css({height:  h + (currentOpts.padding * 2) + titleh});\n    inner.css({height:  h});\n\n    c.replaceWith(c.children());\n\n    $.fancybox.center();\n  };\n\n  $.fancybox.center = function() {\n    busy = true;\n\n    var view  = fancybox_get_viewport();\n    var margin  = currentOpts.margin;\n    var to    = {};\n\n    to.top  = view[3] + ((view[1] - ((wrap.height() - titleh) + (shadow * 2 ))) * 0.5);\n    to.left  = view[2] + ((view[0] - (wrap.width() + (shadow * 2 ))) * 0.5);\n\n    to.top  = Math.max(view[3] + margin, to.top);\n    to.left  = Math.max(view[2] + margin, to.left);\n\n    wrap.css(to);\n\n    busy = false;\n  };\n\n  /*\n\n  Inner Methods\n\n  */\n\n  function fancybox_abort() {\n    loading.hide();\n\n    imgPreloader.onerror = imgPreloader.onload = null;\n\n    if (ajaxLoader) ajaxLoader.abort();\n\n    tmp.empty();\n  };\n\n  function fancybox_error() {\n    $.fancybox('<p id=\"fancybox_error\">The requested content cannot be loaded.<br />Please try again later.</p>', {\n      'scrolling'    : 'no',\n      'padding'    : 20,\n      'transitionIn'  : 'none',\n      'transitionOut'  : 'none'\n    });\n  };\n\n  function fancybox_start() {\n    fancybox_abort();\n\n    var obj  = selectedArray[ selectedIndex ];\n\n    selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox')));\n\n    var href, type, title = obj.title || $(obj).title || selectedOpts.title || '';\n\n    if (obj.nodeName && !selectedOpts.orig) {\n      selectedOpts.orig = $(obj).children(\"img:first\").length ? $(obj).children(\"img:first\") : $(obj);\n    }\n\n    if (title == '' && selectedOpts.orig) title = selectedOpts.orig.attr('alt');\n\n    if (obj.nodeName && (/^(?:javascript|#)/i).test(obj.href)) {\n      href = selectedOpts.href || null;\n    } else {\n      href = selectedOpts.href || obj.href || null;\n    }\n\n    if (selectedOpts.type) {\n      type = selectedOpts.type;\n\n      if (!href) href = selectedOpts.content;\n\n    } else if (selectedOpts.content) {\n      type  = 'html';\n\n    } else if (href) {\n      if (href.match(imageRegExp)) {\n        type = 'image';\n\n      } else if (href.match(swfRegExp)) {\n        type = 'swf';\n\n      } else if ($(obj).hasClass(\"iframe\")) {\n        type = 'iframe';\n\n      } else if (href.match(/#/)) {\n        obj = href.substr(href.indexOf(\"#\"));\n\n        type = $(obj).length > 0 ? 'inline' : 'ajax';\n      } else {\n        type = 'ajax';\n      }\n    } else {\n      type = 'inline';\n    }\n\n    selectedOpts.type  = type;\n    selectedOpts.href  = href;\n    selectedOpts.title  = title;\n\n    if (selectedOpts.autoDimensions && selectedOpts.type !== 'iframe' && selectedOpts.type !== 'swf') {\n      selectedOpts.width    = 'auto';\n      selectedOpts.height    = 'auto';\n    }\n\n    if (selectedOpts.modal) {\n      selectedOpts.overlayShow    = true;\n      selectedOpts.hideOnOverlayClick  = false;\n      selectedOpts.hideOnContentClick  = false;\n      selectedOpts.enableEscapeButton  = false;\n      selectedOpts.showCloseButton  = false;\n    }\n\n    if ($.isFunction(selectedOpts.onStart)) {\n      if (selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts) === false) {\n        busy = false;\n        return;\n      }\n    };\n\n    tmp.css('padding', (shadow + selectedOpts.padding + selectedOpts.margin));\n\n    $('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function() {\n      $(this).replaceWith(inner.children());\n    });\n\n    switch (type) {\n      case 'html' :\n        tmp.html( selectedOpts.content );\n\n        fancybox_process_inline();\n      break;\n\n      case 'inline' :\n        $('<div class=\"fancybox-inline-tmp\" />').hide().insertBefore( $(obj) ).bind('fancybox-cleanup', function() {\n          $(this).replaceWith(inner.children());\n        }).bind('fancybox-cancel', function() {\n          $(this).replaceWith(tmp.children());\n        });\n\n        $(obj).appendTo(tmp);\n\n        fancybox_process_inline();\n      break;\n\n      case 'image':\n        busy = false;\n\n        $.fancybox.showActivity();\n\n        imgPreloader = new Image;\n\n        imgPreloader.onerror = function() {\n          fancybox_error();\n        }\n\n        imgPreloader.onload = function() {\n          imgPreloader.onerror = null;\n          imgPreloader.onload = null;\n          fancybox_process_image();\n        }\n\n        imgPreloader.src = href;\n\n      break;\n\n      case 'swf':\n        var str = '';\n        var emb = '';\n\n        str += '<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\"' + selectedOpts.width + '\" height=\"' + selectedOpts.height + '\"><param name=\"movie\" value=\"' + href + '\"></param>';\n\n        $.each(selectedOpts.swf, function(name, val) {\n          str += '<param name=\"' + name + '\" value=\"' + val + '\"></param>';\n          emb += ' ' + name + '=\"' + val + '\"';\n        });\n\n        str += '<embed src=\"' + href + '\" type=\"application/x-shockwave-flash\" width=\"' + selectedOpts.width + '\" height=\"' + selectedOpts.height + '\"' + emb + '></embed></object>';\n\n        tmp.html(str);\n\n        fancybox_process_inline();\n      break;\n\n      case 'ajax':\n        var selector  = href.split('#', 2);\n        var data    = selectedOpts.ajax.data || {};\n\n        if (selector.length > 1) {\n          href = selector[0];\n\n          typeof data == \"string\" ? data += '&selector=' + selector[1] : data['selector'] = selector[1];\n        }\n\n        busy = false;\n        $.fancybox.showActivity();\n\n        ajaxLoader = $.ajax($.extend(selectedOpts.ajax, {\n          url    : href,\n          data  : data,\n          error  : fancybox_error,\n          success : function(data, textStatus, XMLHttpRequest) {\n            if (ajaxLoader.status == 200) {\n              tmp.html( data );\n              fancybox_process_inline();\n            }\n          }\n        }));\n\n      break;\n\n      case 'iframe' :\n        $('<iframe id=\"fancybox-frame\" name=\"fancybox-frame' + new Date().getTime() + '\" frameborder=\"0\" hspace=\"0\" scrolling=\"' + selectedOpts.scrolling + '\" src=\"' + selectedOpts.href + '\"></iframe>').appendTo(tmp);\n\n        fancybox_show();\n      break;\n    }\n  };\n\n  function fancybox_process_image() {\n    busy = true;\n\n    selectedOpts.width  = imgPreloader.width;\n    selectedOpts.height  = imgPreloader.height;\n\n    $(\"<img />\").attr({\n      'id'  : 'fancybox-img',\n      'src'  : imgPreloader.src,\n      'alt'  : selectedOpts.title\n    }).appendTo( tmp );\n\n    fancybox_show();\n  };\n\n  function fancybox_process_inline() {\n    tmp.width(  selectedOpts.width );\n    tmp.height(  selectedOpts.height );\n\n    if (selectedOpts.width  == 'auto') selectedOpts.width  = tmp.width();\n    if (selectedOpts.height  == 'auto') selectedOpts.height  = tmp.height();\n\n    fancybox_show();\n  };\n\n  function fancybox_show() {\n    loading.hide();\n\n    if (wrap.is(\":visible\") && $.isFunction(currentOpts.onCleanup)) {\n      if (currentOpts.onCleanup(currentArray, currentIndex, currentOpts) === false) {\n        $.event.trigger('fancybox-cancel');\n\n        busy = false;\n        return;\n      }\n    };\n\n    currentArray  = selectedArray;\n    currentIndex  = selectedIndex;\n    currentOpts    = selectedOpts;\n\n    inner.get(0).scrollTop  = 0;\n    inner.get(0).scrollLeft  = 0;\n\n    if (currentOpts.overlayShow) {\n      if (isIE6) {\n        $('select:not(#fancybox-tmp select)').filter(function() {\n          return this.style.visibility !== 'hidden';\n        }).css({'visibility':'hidden'}).one('fancybox-cleanup', function() {\n          this.style.visibility = 'inherit';\n        });\n      }\n\n      overlay.css({\n        'background-color'  : currentOpts.overlayColor,\n        'opacity'      : currentOpts.overlayOpacity\n      }).unbind().show();\n    }\n\n    final_pos = fancybox_get_zoom_to();\n\n    fancybox_process_title();\n\n    if (wrap.is(\":visible\")) {\n      $( close.add( nav_left ).add( nav_right ) ).hide();\n\n      var pos = wrap.position();\n\n      start_pos = {\n        top    :  pos.top ,\n        left  :  pos.left,\n        width  :  wrap.width(),\n        height  :  wrap.height()\n      };\n\n      var equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height);\n\n      inner.fadeOut(currentOpts.changeFade, function() {\n        $.event.trigger('fancybox-change');\n\n        inner.css({\n            top      : currentOpts.padding,\n            left    : currentOpts.padding,\n            width    : Math.max(start_pos.width  - (currentOpts.padding * 2), 1),\n            height    : Math.max(start_pos.height  - (currentOpts.padding * 2), 1)\n          })\n          .empty()\n          .css('overflow', 'hidden');\n\n        function finish_resizing() {\n          inner.html( tmp.contents() ).fadeIn(currentOpts.changeFade, _finish);\n        }\n\n        fx.prop = 0;\n\n        $(fx).animate({ prop: 1 }, {\n           duration  : equal ? 0 : currentOpts.changeSpeed,\n           easing    : currentOpts.easingChange,\n           step    : fancybox_draw,\n           complete  : finish_resizing\n        });\n      });\n\n      return;\n    }\n\n    wrap.css('opacity', 1);\n\n    if (currentOpts.transitionIn == 'elastic') {\n      start_pos = fancybox_get_zoom_from();\n\n      inner.css({\n          top      : currentOpts.padding,\n          left    : currentOpts.padding,\n          width    : Math.max(start_pos.width  - (currentOpts.padding * 2), 1),\n          height    : Math.max(start_pos.height  - (currentOpts.padding * 2), 1)\n        })\n        .html( tmp.contents() );\n\n      wrap.css(start_pos).show();\n\n      if (currentOpts.opacity) final_pos.opacity = 0;\n\n      fx.prop = 0;\n\n      $(fx).animate({ prop: 1 }, {\n         duration  : currentOpts.speedIn,\n         easing    : currentOpts.easingIn,\n         step    : fancybox_draw,\n         complete  : _finish\n      });\n\n    } else {\n      inner.css({\n          top      : currentOpts.padding,\n          left    : currentOpts.padding,\n          width    : Math.max(final_pos.width  - (currentOpts.padding * 2), 1),\n          height    : Math.max(final_pos.height  - (currentOpts.padding * 2) - titleh, 1)\n        })\n        .html( tmp.contents() );\n\n      wrap.css( final_pos ).fadeIn( currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish );\n    }\n  };\n\n  function fancybox_draw(pos) {\n    var width  = Math.round(start_pos.width  + (final_pos.width  - start_pos.width)  * pos);\n    var height  = Math.round(start_pos.height  + (final_pos.height  - start_pos.height)  * pos);\n\n    var top    = Math.round(start_pos.top  + (final_pos.top  - start_pos.top)  * pos);\n    var left  = Math.round(start_pos.left  + (final_pos.left  - start_pos.left)  * pos);\n\n    wrap.css({\n      'width'    : width    + 'px',\n      'height'  : height  + 'px',\n      'top'    : top    + 'px',\n      'left'    : left    + 'px'\n    });\n\n    width  = Math.max(width - currentOpts.padding * 2, 0);\n    height  = Math.max(height - (currentOpts.padding * 2 + (titleh * pos)), 0);\n\n    inner.css({\n      'width'    : width    + 'px',\n      'height'  : height  + 'px'\n    });\n\n    if (typeof final_pos.opacity !== 'undefined') wrap.css('opacity', (pos < 0.5 ? 0.5 : pos));\n  };\n\n  function _finish() {\n    inner.css('overflow', overflow = (currentOpts.scrolling == 'auto' ? (currentOpts.type == 'image' || currentOpts.type == 'iframe' || currentOpts.type == 'swf' ? 'hidden' : 'auto') : (currentOpts.scrolling == 'yes' ? 'auto' : 'visible')));\n\n    if (!$.support.opacity) {\n      inner.get(0).style.removeAttribute('filter');\n      wrap.get(0).style.removeAttribute('filter');\n    }\n\n    $('#fancybox-title').show();\n\n    if (currentOpts.hideOnContentClick)  inner.one('click',    $.fancybox.close);\n    if (currentOpts.hideOnOverlayClick)  overlay.one('click',  $.fancybox.close);\n\n    if (currentOpts.showCloseButton) close.show();\n\n    fancybox_set_navigation();\n\n    $(window).bind(\"resize.fb\", $.fancybox.center);\n\n    currentOpts.centerOnScroll ? $(window).bind(\"scroll.fb\", $.fancybox.center) : $(window).unbind(\"scroll.fb\");\n\n    if ($.isFunction(currentOpts.onComplete)) currentOpts.onComplete(currentArray, currentIndex, currentOpts);\n\n    busy = false;\n\n    fancybox_preload_images();\n  };\n\n  function fancybox_get_zoom_to() {\n    var view  = fancybox_get_viewport();\n    var to    = {};\n\n    var margin = currentOpts.margin;\n    var resize = currentOpts.autoScale;\n\n    var horizontal_space  = (shadow + margin) * 2 ;\n    var vertical_space    = (shadow + margin) * 2 ;\n    var double_padding    = (currentOpts.padding * 2);\n\n    if (currentOpts.width.toString().indexOf('%') > -1) {\n      to.width = ((view[0] * parseFloat(currentOpts.width)) / 100) - (shadow * 2) ;\n      resize = false;\n\n    } else {\n      to.width = currentOpts.width + double_padding;\n    }\n\n    if (currentOpts.height.toString().indexOf('%') > -1) {\n      to.height = ((view[1] * parseFloat(currentOpts.height)) / 100) - (shadow * 2);\n      resize = false;\n\n    } else {\n      to.height = currentOpts.height + double_padding;\n    }\n\n    if (resize && (to.width > (view[0] - horizontal_space) || to.height > (view[1] - vertical_space))) {\n      if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') {\n        horizontal_space  += double_padding;\n        vertical_space    += double_padding;\n\n        var ratio = Math.min(Math.min( view[0] - horizontal_space, currentOpts.width) / currentOpts.width, Math.min( view[1] - vertical_space, currentOpts.height) / currentOpts.height);\n\n        to.width  = Math.round(ratio * (to.width  - double_padding)) + double_padding;\n        to.height  = Math.round(ratio * (to.height  - double_padding)) + double_padding;\n\n      } else {\n        to.width  = Math.min(to.width,  (view[0] - horizontal_space));\n        to.height  = Math.min(to.height,  (view[1] - vertical_space));\n      }\n    }\n\n    to.top  = view[3] + ((view[1] - (to.height  + (shadow * 2 ))) * 0.5);\n    to.left  = view[2] + ((view[0] - (to.width  + (shadow * 2 ))) * 0.5);\n\n    if (currentOpts.autoScale == false) {\n      to.top  = Math.max(view[3] + margin, to.top);\n      to.left  = Math.max(view[2] + margin, to.left);\n    }\n\n    return to;\n  };\n\n  function fancybox_get_zoom_from() {\n    var orig  = selectedOpts.orig ? $(selectedOpts.orig) : false;\n    var from   = {};\n\n    if (orig && orig.length) {\n      var pos = fancybox_get_obj_pos(orig);\n\n      from = {\n        width  : (pos.width  + (currentOpts.padding * 2)),\n        height  : (pos.height  + (currentOpts.padding * 2)),\n        top    : (pos.top    - currentOpts.padding - shadow),\n        left  : (pos.left    - currentOpts.padding - shadow)\n      };\n\n    } else {\n      var view = fancybox_get_viewport();\n\n      from = {\n        width  : 1,\n        height  : 1,\n        top    : view[3] + view[1] * 0.5,\n        left  : view[2] + view[0] * 0.5\n      };\n    }\n\n    return from;\n  };\n\n  function fancybox_set_navigation() {\n    $(document).unbind('keydown.fb').bind('keydown.fb', function(e) {\n      if (e.keyCode == 27 && currentOpts.enableEscapeButton) {\n        e.preventDefault();\n        $.fancybox.close();\n\n      } else if (e.keyCode == 37) {\n        e.preventDefault();\n        $.fancybox.prev();\n\n      } else if (e.keyCode == 39) {\n        e.preventDefault();\n        $.fancybox.next();\n      }\n    });\n\n    if ($.fn.mousewheel) {\n      wrap.unbind('mousewheel.fb');\n\n      if (currentArray.length > 1) {\n        wrap.bind('mousewheel.fb', function(e, delta) {\n          e.preventDefault();\n\n          if (busy || delta == 0) return;\n\n          delta > 0 ? $.fancybox.prev() : $.fancybox.next();\n        });\n      }\n    }\n\n    if (!currentOpts.showNavArrows) return;\n\n    if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != 0) {\n      nav_left.show();\n    }\n\n    if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length -1)) {\n      nav_right.show();\n    }\n  };\n\n  function fancybox_preload_images() {\n    if ((currentArray.length -1) > currentIndex) {\n      var href = currentArray[ currentIndex + 1 ].href;\n\n      if (typeof href !== 'undefined' && href.match(imageRegExp)) {\n        var objNext = new Image();\n        objNext.src = href;\n      }\n    }\n\n    if (currentIndex > 0) {\n      var href = currentArray[ currentIndex - 1 ].href;\n\n      if (typeof href !== 'undefined' && href.match(imageRegExp)) {\n        var objNext = new Image();\n        objNext.src = href;\n      }\n    }\n  };\n\n  function fancybox_animate_loading() {\n    if (!loading.is(':visible')){\n      clearInterval(loadingTimer);\n      return;\n    }\n\n    $('div', loading).css('top', (loadingFrame * -40) + 'px');\n\n    loadingFrame = (loadingFrame + 1) % 12;\n  };\n\n  function fancybox_get_viewport() {\n    return [ $(window).width(), $(window).height(), $(document).scrollLeft(), $(document).scrollTop() ];\n  };\n\n  function fancybox_get_obj_pos(obj) {\n    var pos    = obj.offset();\n\n    pos.top    += parseFloat( obj.css('paddingTop') )  || 0;\n    pos.left  += parseFloat( obj.css('paddingLeft') )  || 0;\n\n    pos.top    += parseFloat( obj.css('border-top-width') )  || 0;\n    pos.left  += parseFloat( obj.css('border-left-width') )  || 0;\n\n    pos.width  = obj.width();\n    pos.height  = obj.height();\n\n    return pos;\n  };\n\n  function fancybox_process_title() {\n    $('#fancybox-title').remove();\n\n    titleh = 0;\n\n    if (currentOpts.titleShow == false) return;\n\n    var obj    = currentArray[ currentIndex ];\n    var title  = currentOpts.title;\n\n    title = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(title, currentArray, currentIndex, currentOpts) : fancybox_format_title(title);\n\n    if (!title || title == '') return;\n\n    var width  = final_pos.width - (currentOpts.padding * 2);\n    var titlec  = 'fancybox-title-' + currentOpts.titlePosition;\n\n    $('<div id=\"fancybox-title\" class=\"' + titlec + '\" />').css({\n      'width'      : width,\n      'paddingLeft'  : currentOpts.padding,\n      'paddingRight'  : currentOpts.padding\n    }).html(title).appendTo('body');\n\n    switch (currentOpts.titlePosition) {\n      case 'inside':\n        titleh = $(\"#fancybox-title\").outerHeight(true) - currentOpts.padding;\n        final_pos.height += titleh;\n      break;\n\n      case 'over':\n        $('#fancybox-title').css('bottom', currentOpts.padding);\n      break;\n\n      default:\n        $('#fancybox-title').css('bottom', $(\"#fancybox-title\").outerHeight(true) * -1);\n      break;\n    }\n\n    $('#fancybox-title').appendTo( outer ).hide();\n\n    if (isIE6) {\n      $('#fancybox-title span').fixPNG();\n    }\n  };\n\n  function fancybox_format_title(title) {\n    if (title && title.length) {\n      switch (currentOpts.titlePosition) {\n        case 'inside':\n          return title;\n        break;\n\n        case 'over':\n          return '<span id=\"fancybox-title-over\">' + title + '</span>';\n        break;\n\n        default:\n          return '<span id=\"fancybox-title-wrap\"><span id=\"fancybox-title-left\"></span><span id=\"fancybox-title-main\">' + title + '</span><span id=\"fancybox-title-right\"></span></span>';\n        break;\n      }\n    }\n\n    return false;\n  };\n\n  function fancybox_init() {\n    if ($(\"#fancybox-wrap\").length) return;\n\n    $('body').append(\n      tmp      = $('<div id=\"fancybox-tmp\"></div>'),\n      loading    = $('<div id=\"fancybox-loading\"><div></div></div>'),\n      overlay    = $('<div id=\"fancybox-overlay\"></div>'),\n      wrap    = $('<div id=\"fancybox-wrap\"></div>')\n    );\n\n    outer = $('<div id=\"fancybox-outer\"></div>')\n      .append('<div class=\"fancy-bg\" id=\"fancy-bg-n\"></div><div class=\"fancy-bg\" id=\"fancy-bg-ne\"></div><div class=\"fancy-bg\" id=\"fancy-bg-e\"></div><div class=\"fancy-bg\" id=\"fancy-bg-se\"></div><div class=\"fancy-bg\" id=\"fancy-bg-s\"></div><div class=\"fancy-bg\" id=\"fancy-bg-sw\"></div><div class=\"fancy-bg\" id=\"fancy-bg-w\"></div><div class=\"fancy-bg\" id=\"fancy-bg-nw\"></div>')\n      .appendTo( wrap );\n\n    outer.append(\n      inner    = $('<div id=\"fancybox-inner\"></div>'),\n      close    = $('<a id=\"fancybox-close\"></a>'),\n\n      nav_left  = $('<a href=\"javascript:;\" id=\"fancybox-left\"><span class=\"fancy-ico\" id=\"fancybox-left-ico\"></span></a>'),\n      nav_right  = $('<a href=\"javascript:;\" id=\"fancybox-right\"><span class=\"fancy-ico\" id=\"fancybox-right-ico\"></span></a>')\n    );\n\n    close.click($.fancybox.close);\n    loading.click($.fancybox.cancel);\n\n    nav_left.click(function(e) {\n      e.preventDefault();\n      $.fancybox.prev();\n    });\n\n    nav_right.click(function(e) {\n      e.preventDefault();\n      $.fancybox.next();\n    });\n\n    if (!$.support.opacity) {\n      outer.find('.fancy-bg').fixPNG();\n    }\n\n    if (isIE6) {\n      $(close.add('.fancy-ico').add('div', loading)).fixPNG();\n\n      overlay.get(0).style.setExpression('height',  \"document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'\");\n      loading.get(0).style.setExpression('top',    \"(-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px'\");\n\n      outer.prepend('<iframe id=\"fancybox-hide-sel-frame\" src=\"javascript:\\'\\';\" scrolling=\"no\" frameborder=\"0\" ></iframe>');\n    }\n  };\n\n  $.fn.fancybox.defaults = {\n    padding        :  10,\n    margin        :  20,\n    opacity        :  false,\n    modal        :  false,\n    cyclic        :  false,\n    scrolling      :  'auto',  // 'auto', 'yes' or 'no'\n\n    width        :  560,\n    height        :  340,\n\n    autoScale      :  true,\n    autoDimensions    :  true,\n    centerOnScroll    :  false,\n\n    ajax        :  {},\n    swf          :  { wmode: 'transparent' },\n\n    hideOnOverlayClick  :  true,\n    hideOnContentClick  :  false,\n\n    overlayShow      :  true,\n    overlayOpacity    :  0.3,\n    overlayColor    :  '#666',\n\n    titleShow      :  true,\n    titlePosition    :  'outside',  // 'outside', 'inside' or 'over'\n    titleFormat      :  null,\n\n    transitionIn    :  'fade',  // 'elastic', 'fade' or 'none'\n    transitionOut    :  'fade',  // 'elastic', 'fade' or 'none'\n\n    speedIn        :  300,\n    speedOut      :  300,\n\n    changeSpeed      :  300,\n    changeFade      :  'fast',\n\n    easingIn      :  'swing',\n    easingOut      :  'swing',\n\n    showCloseButton    :  true,\n    showNavArrows    :  true,\n    enableEscapeButton  :  true,\n\n    onStart        :  null,\n    onCancel      :  null,\n    onComplete      :  null,\n    onCleanup      :  null,\n    onClosed      :  null\n  };\n\n  $(document).ready(function() {\n    fancybox_init();\n  });\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.fancybox-1.3.0.pack.js",
    "content": "/*\n * FancyBox - jQuery Plugin\n * Simple and fancy lightbox alternative\n *\n * Copyright (c) 20010 Janis Skarnelis\n * Examples and documentation at: http://fancybox.net\n *\n * Version: 1.3.0 (02/02/2010)\n * Requires: jQuery v1.3+\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n */\n\n;(function(b){function H(){v.hide();r.onerror=r.onload=null;F&&F.abort();l.empty()}function Q(){b.fancybox('<p id=\"fancybox_error\">The requested content cannot be loaded.<br />Please try again later.</p>',{scrolling:\"no\",padding:20,transitionIn:\"none\",transitionOut:\"none\"})}function B(){H();var a=q[s];e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data(\"fancybox\")==\"undefined\"?e:b(a).data(\"fancybox\"));var d,f,o=a.title||b(a).title||e.title||\"\";if(a.nodeName&&!e.orig)e.orig=b(a).children(\"img:first\").length?\nb(a).children(\"img:first\"):b(a);if(o==\"\"&&e.orig)o=e.orig.attr(\"alt\");d=a.nodeName&&/^(?:javascript|#)/i.test(a.href)?e.href||null:e.href||a.href||null;if(e.type){f=e.type;if(!d)d=e.content}else if(e.content)f=\"html\";else if(d)if(d.match(I))f=\"image\";else if(d.match(T))f=\"swf\";else if(b(a).hasClass(\"iframe\"))f=\"iframe\";else if(d.match(/#/)){a=d.substr(d.indexOf(\"#\"));f=b(a).length>0?\"inline\":\"ajax\"}else f=\"ajax\";else f=\"inline\";e.type=f;e.href=d;e.title=o;if(e.autoDimensions&&e.type!==\"iframe\"&&e.type!==\n\"swf\"){e.width=\"auto\";e.height=\"auto\"}if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=false;e.enableEscapeButton=false;e.showCloseButton=false}if(b.isFunction(e.onStart))if(e.onStart(q,s,e)===false){h=false;return}l.css(\"padding\",t+e.padding+e.margin);b(\".fancybox-inline-tmp\").unbind(\"fancybox-cancel\").bind(\"fancybox-change\",function(){b(this).replaceWith(i.children())});switch(f){case \"html\":l.html(e.content);G();break;case \"inline\":b('<div class=\"fancybox-inline-tmp\" />').hide().insertBefore(b(a)).bind(\"fancybox-cleanup\",\nfunction(){b(this).replaceWith(i.children())}).bind(\"fancybox-cancel\",function(){b(this).replaceWith(l.children())});b(a).appendTo(l);G();break;case \"image\":h=false;b.fancybox.showActivity();r=new Image;r.onerror=function(){Q()};r.onload=function(){r.onerror=null;r.onload=null;U()};r.src=d;break;case \"swf\":var u=\"\",w=\"\";u+='<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\"'+e.width+'\" height=\"'+e.height+'\"><param name=\"movie\" value=\"'+d+'\"></param>';b.each(e.swf,function(p,R){u+=\n'<param name=\"'+p+'\" value=\"'+R+'\"></param>';w+=\" \"+p+'=\"'+R+'\"'});u+='<embed src=\"'+d+'\" type=\"application/x-shockwave-flash\" width=\"'+e.width+'\" height=\"'+e.height+'\"'+w+\"></embed></object>\";l.html(u);G();break;case \"ajax\":a=d.split(\"#\",2);f=e.ajax.data||{};if(a.length>1){d=a[0];typeof f==\"string\"?(f+=\"&selector=\"+a[1]):(f.selector=a[1])}h=false;b.fancybox.showActivity();F=b.ajax(b.extend(e.ajax,{url:d,data:f,error:Q,success:function(p){if(F.status==200){l.html(p);G()}}}));break;case \"iframe\":b('<iframe id=\"fancybox-frame\" name=\"fancybox-frame'+\n(new Date).getTime()+'\" frameborder=\"0\" hspace=\"0\" scrolling=\"'+e.scrolling+'\" src=\"'+e.href+'\"></iframe>').appendTo(l);J();break}}function U(){h=true;e.width=r.width;e.height=r.height;b(\"<img />\").attr({id:\"fancybox-img\",src:r.src,alt:e.title}).appendTo(l);J()}function G(){l.width(e.width);l.height(e.height);if(e.width==\"auto\")e.width=l.width();if(e.height==\"auto\")e.height=l.height();J()}function J(){v.hide();if(g.is(\":visible\")&&b.isFunction(c.onCleanup))if(c.onCleanup(j,n,c)===false){b.event.trigger(\"fancybox-cancel\");\nh=false;return}j=q;n=s;c=e;i.get(0).scrollTop=0;i.get(0).scrollLeft=0;if(c.overlayShow){K&&b(\"select:not(#fancybox-tmp select)\").filter(function(){return this.style.visibility!==\"hidden\"}).css({visibility:\"hidden\"}).one(\"fancybox-cleanup\",function(){this.style.visibility=\"inherit\"});y.css({\"background-color\":c.overlayColor,opacity:c.overlayOpacity}).unbind().show()}m=V();W();if(g.is(\":visible\")){b(z.add(C).add(D)).hide();var a=g.position();k={top:a.top,left:a.left,width:g.width(),height:g.height()};\nvar d=k.width==m.width&&k.height==m.height;i.fadeOut(c.changeFade,function(){function f(){i.html(l.contents()).fadeIn(c.changeFade,L)}b.event.trigger(\"fancybox-change\");i.css({top:c.padding,left:c.padding,width:Math.max(k.width-c.padding*2,1),height:Math.max(k.height-c.padding*2,1)}).empty().css(\"overflow\",\"hidden\");A.prop=0;b(A).animate({prop:1},{duration:d?0:c.changeSpeed,easing:c.easingChange,step:M,complete:f})})}else{g.css(\"opacity\",1);if(c.transitionIn==\"elastic\"){k=S();i.css({top:c.padding,\nleft:c.padding,width:Math.max(k.width-c.padding*2,1),height:Math.max(k.height-c.padding*2,1)}).html(l.contents());g.css(k).show();if(c.opacity)m.opacity=0;A.prop=0;b(A).animate({prop:1},{duration:c.speedIn,easing:c.easingIn,step:M,complete:L})}else{i.css({top:c.padding,left:c.padding,width:Math.max(m.width-c.padding*2,1),height:Math.max(m.height-c.padding*2-x,1)}).html(l.contents());g.css(m).fadeIn(c.transitionIn==\"none\"?0:c.speedIn,L)}}}function M(a){var d=Math.round(k.width+(m.width-k.width)*a),\nf=Math.round(k.height+(m.height-k.height)*a),o=Math.round(k.top+(m.top-k.top)*a),u=Math.round(k.left+(m.left-k.left)*a);g.css({width:d+\"px\",height:f+\"px\",top:o+\"px\",left:u+\"px\"});d=Math.max(d-c.padding*2,0);f=Math.max(f-(c.padding*2+x*a),0);i.css({width:d+\"px\",height:f+\"px\"});if(typeof m.opacity!==\"undefined\")g.css(\"opacity\",a<0.5?0.5:a)}function L(){i.css(\"overflow\",overflow=c.scrolling==\"auto\"?c.type==\"image\"||c.type==\"iframe\"||c.type==\"swf\"?\"hidden\":\"auto\":c.scrolling==\"yes\"?\"auto\":\"visible\");\nif(!b.support.opacity){i.get(0).style.removeAttribute(\"filter\");g.get(0).style.removeAttribute(\"filter\")}b(\"#fancybox-title\").show();c.hideOnContentClick&&i.one(\"click\",b.fancybox.close);c.hideOnOverlayClick&&y.one(\"click\",b.fancybox.close);c.showCloseButton&&z.show();X();b(window).bind(\"resize.fb\",b.fancybox.center);c.centerOnScroll?b(window).bind(\"scroll.fb\",b.fancybox.center):b(window).unbind(\"scroll.fb\");b.isFunction(c.onComplete)&&c.onComplete(j,n,c);h=false;Y()}function V(){var a=N(),d={},f=\nc.margin,o=c.autoScale,u=(t+f)*2,w=(t+f)*2,p=c.padding*2;if(c.width.toString().indexOf(\"%\")>-1){d.width=a[0]*parseFloat(c.width)/100-t*2;o=false}else d.width=c.width+p;if(c.height.toString().indexOf(\"%\")>-1){d.height=a[1]*parseFloat(c.height)/100-t*2;o=false}else d.height=c.height+p;if(o&&(d.width>a[0]-u||d.height>a[1]-w))if(e.type==\"image\"||e.type==\"swf\"){u+=p;w+=p;o=Math.min(Math.min(a[0]-u,c.width)/c.width,Math.min(a[1]-w,c.height)/c.height);d.width=Math.round(o*(d.width-p))+p;d.height=Math.round(o*\n(d.height-p))+p}else{d.width=Math.min(d.width,a[0]-u);d.height=Math.min(d.height,a[1]-w)}d.top=a[3]+(a[1]-(d.height+t*2))*0.5;d.left=a[2]+(a[0]-(d.width+t*2))*0.5;if(c.autoScale==false){d.top=Math.max(a[3]+f,d.top);d.left=Math.max(a[2]+f,d.left)}return d}function S(){var a=e.orig?b(e.orig):false,d={};if(a&&a.length){a=Z(a);d={width:a.width+c.padding*2,height:a.height+c.padding*2,top:a.top-c.padding-t,left:a.left-c.padding-t}}else{a=N();d={width:1,height:1,top:a[3]+a[1]*0.5,left:a[2]+a[0]*0.5}}return d}\nfunction X(){b(document).unbind(\"keydown.fb\").bind(\"keydown.fb\",function(a){if(a.keyCode==27&&c.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if(a.keyCode==37){a.preventDefault();b.fancybox.prev()}else if(a.keyCode==39){a.preventDefault();b.fancybox.next()}});if(b.fn.mousewheel){g.unbind(\"mousewheel.fb\");j.length>1&&g.bind(\"mousewheel.fb\",function(a,d){a.preventDefault();h||d==0||(d>0?b.fancybox.prev():b.fancybox.next())})}if(c.showNavArrows){if(c.cyclic&&j.length>1||n!=0)C.show();\nif(c.cyclic&&j.length>1||n!=j.length-1)D.show()}}function Y(){if(j.length-1>n){var a=j[n+1].href;if(typeof a!==\"undefined\"&&a.match(I)){var d=new Image;d.src=a}}if(n>0){a=j[n-1].href;if(typeof a!==\"undefined\"&&a.match(I)){d=new Image;d.src=a}}}function $(){if(v.is(\":visible\")){b(\"div\",v).css(\"top\",O*-40+\"px\");O=(O+1)%12}else clearInterval(P)}function N(){return[b(window).width(),b(window).height(),b(document).scrollLeft(),b(document).scrollTop()]}function Z(a){var d=a.offset();d.top+=parseFloat(a.css(\"paddingTop\"))||\n0;d.left+=parseFloat(a.css(\"paddingLeft\"))||0;d.top+=parseFloat(a.css(\"border-top-width\"))||0;d.left+=parseFloat(a.css(\"border-left-width\"))||0;d.width=a.width();d.height=a.height();return d}function W(){b(\"#fancybox-title\").remove();x=0;if(c.titleShow!=false){var a=c.title;a=b.isFunction(c.titleFormat)?c.titleFormat(a,j,n,c):aa(a);if(!(!a||a==\"\")){var d=m.width-c.padding*2;b('<div id=\"fancybox-title\" class=\"'+(\"fancybox-title-\"+c.titlePosition)+'\" />').css({width:d,paddingLeft:c.padding,paddingRight:c.padding}).html(a).appendTo(\"body\");\nswitch(c.titlePosition){case \"inside\":x=b(\"#fancybox-title\").outerHeight(true)-c.padding;m.height+=x;break;case \"over\":b(\"#fancybox-title\").css(\"bottom\",c.padding);break;default:b(\"#fancybox-title\").css(\"bottom\",b(\"#fancybox-title\").outerHeight(true)*-1);break}b(\"#fancybox-title\").appendTo(E).hide();K&&b(\"#fancybox-title span\").fixPNG()}}}function aa(a){if(a&&a.length)switch(c.titlePosition){case \"inside\":return a;case \"over\":return'<span id=\"fancybox-title-over\">'+a+\"</span>\";default:return'<span id=\"fancybox-title-wrap\"><span id=\"fancybox-title-left\"></span><span id=\"fancybox-title-main\">'+\na+'</span><span id=\"fancybox-title-right\"></span></span>'}return false}function ba(){if(!b(\"#fancybox-wrap\").length){b(\"body\").append(l=b('<div id=\"fancybox-tmp\"></div>'),v=b('<div id=\"fancybox-loading\"><div></div></div>'),y=b('<div id=\"fancybox-overlay\"></div>'),g=b('<div id=\"fancybox-wrap\"></div>'));E=b('<div id=\"fancybox-outer\"></div>').append('<div class=\"fancy-bg\" id=\"fancy-bg-n\"></div><div class=\"fancy-bg\" id=\"fancy-bg-ne\"></div><div class=\"fancy-bg\" id=\"fancy-bg-e\"></div><div class=\"fancy-bg\" id=\"fancy-bg-se\"></div><div class=\"fancy-bg\" id=\"fancy-bg-s\"></div><div class=\"fancy-bg\" id=\"fancy-bg-sw\"></div><div class=\"fancy-bg\" id=\"fancy-bg-w\"></div><div class=\"fancy-bg\" id=\"fancy-bg-nw\"></div>').appendTo(g);\nE.append(i=b('<div id=\"fancybox-inner\"></div>'),z=b('<a id=\"fancybox-close\"></a>'),C=b('<a href=\"javascript:;\" id=\"fancybox-left\"><span class=\"fancy-ico\" id=\"fancybox-left-ico\"></span></a>'),D=b('<a href=\"javascript:;\" id=\"fancybox-right\"><span class=\"fancy-ico\" id=\"fancybox-right-ico\"></span></a>'));z.click(b.fancybox.close);v.click(b.fancybox.cancel);C.click(function(a){a.preventDefault();b.fancybox.prev()});D.click(function(a){a.preventDefault();b.fancybox.next()});b.support.opacity||E.find(\".fancy-bg\").fixPNG();\nif(K){b(z.add(\".fancy-ico\").add(\"div\",v)).fixPNG();y.get(0).style.setExpression(\"height\",\"document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'\");v.get(0).style.setExpression(\"top\",\"(-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px'\");E.prepend('<iframe id=\"fancybox-hide-sel-frame\" src=\"javascript:\\'\\';\" scrolling=\"no\" frameborder=\"0\" ></iframe>')}}}\nvar l,v,y,g,E,i,z,C,D,s=0,e={},q=[],n=0,c={},j=[],F=null,r=new Image,I=/\\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,T=/[^\\.]\\.(swf)\\s*$/i,P,O=1,k,m,h=false,t=20,A=b.extend(b(\"<div/>\")[0],{prop:0}),x=0,K=!b.support.opacity&&!window.XMLHttpRequest;b.fn.fixPNG=function(){return this.each(function(){var a=b(this).css(\"backgroundImage\");if(a.match(/^url\\([\"']?(.*\\.png)[\"']?\\)$/i)){a=RegExp.$1;b(this).css({backgroundImage:\"none\",filter:\"progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=\"+\n(b(this).css(\"backgroundRepeat\")==\"no-repeat\"?\"crop\":\"scale\")+\", src='\"+a+\"')\"}).each(function(){var d=b(this).css(\"position\");d!=\"absolute\"&&d!=\"relative\"&&b(this).css(\"position\",\"relative\")}).css(\"zoom\",1)}})};b.fn.fancybox=function(a){b(this).data(\"fancybox\",b.extend({},a));b(this).unbind(\"click.fb\").bind(\"click.fb\",function(d){d.preventDefault();if(!h){h=true;b(this).blur();q=[];s=0;d=b(this).attr(\"rel\")||\"\";if(!d||d==\"\"||d===\"nofollow\")q.push(this);else{q=b(\"a[rel=\"+d+\"], area[rel=\"+d+\"]\");s=\nq.index(this)}B();return false}});return this};b.fancybox=function(a,d){if(!h){h=true;q=[];s=0;if(b.isArray(a)){for(var f=0,o=a.length;f<o;f++)if(typeof a[f]==\"object\")b(a[f]).data(\"fancybox\",b.extend({},d,a[f]));else a[f]=b({}).data(\"fancybox\",b.extend({content:a[f]},d));q=jQuery.merge(q,a)}else{if(typeof a==\"object\")b(a).data(\"fancybox\",b.extend({},d,a));else a=b({}).data(\"fancybox\",b.extend({content:a},d));q.push(a)}B()}};b.fancybox.showActivity=function(){clearInterval(P);v.show();P=setInterval($,\n66)};b.fancybox.hideActivity=function(){v.hide()};b.fancybox.next=function(){return b.fancybox.pos(n+1)};b.fancybox.prev=function(){return b.fancybox.pos(n-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);if(a>-1&&j.length>a){s=a;B()}if(c.cyclic&&j.length>1&&a<0){s=j.length-1;B()}if(c.cyclic&&j.length>1&&a>=j.length){s=0;B()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger(\"fancybox-cancel\");H();e&&b.isFunction(e.onCancel)&&e.onCancel(q,s,e);h=false}};b.fancybox.close=function(){function a(){y.fadeOut(\"fast\");\ng.hide();b.event.trigger(\"fancybox-cleanup\");i.empty();b.isFunction(c.onClosed)&&c.onClosed(j,n,c);j=e=[];n=s=0;c=e={};h=false}if(!(h||g.is(\":hidden\"))){h=true;if(c&&b.isFunction(c.onCleanup))if(c.onCleanup(j,n,c)===false){h=false;return}H();b(z.add(C).add(D)).hide();b(\"#fancybox-title\").remove();g.add(i).add(y).unbind();b(window).unbind(\"resize.fb scroll.fb\");b(document).unbind(\"keydown.fb\");i.css(\"overflow\",\"hidden\");if(c.transitionOut==\"elastic\"){k=S();var d=g.position();m={top:d.top,left:d.left,\nwidth:g.width(),height:g.height()};if(c.opacity)m.opacity=1;A.prop=1;b(A).animate({prop:0},{duration:c.speedOut,easing:c.easingOut,step:M,complete:a})}else g.fadeOut(c.transitionOut==\"none\"?0:c.speedOut,a)}};b.fancybox.resize=function(){if(!(h||g.is(\":hidden\"))){h=true;var a=i.wrapInner(\"<div style='overflow:auto'></div>\").children(),d=a.height();g.css({height:d+c.padding*2+x});i.css({height:d});a.replaceWith(a.children());b.fancybox.center()}};b.fancybox.center=function(){h=true;var a=N(),d=c.margin,\nf={};f.top=a[3]+(a[1]-(g.height()-x+t*2))*0.5;f.left=a[2]+(a[0]-(g.width()+t*2))*0.5;f.top=Math.max(a[3]+d,f.top);f.left=Math.max(a[2]+d,f.left);g.css(f);h=false};b.fn.fancybox.defaults={padding:10,margin:20,opacity:false,modal:false,cyclic:false,scrolling:\"auto\",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:\"transparent\"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.3,overlayColor:\"#666\",titleShow:true,titlePosition:\"outside\",\ntitleFormat:null,transitionIn:\"fade\",transitionOut:\"fade\",speedIn:300,speedOut:300,changeSpeed:300,changeFade:\"fast\",easingIn:\"swing\",easingOut:\"swing\",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,onStart:null,onCancel:null,onComplete:null,onCleanup:null,onClosed:null};b(document).ready(function(){ba()})})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.fancybox-1.3.4.js",
    "content": "/*\n * FancyBox - jQuery Plugin\n * Simple and fancy lightbox alternative\n *\n * Examples and documentation at: http://fancybox.net\n *\n * Copyright (c) 2008 - 2010 Janis Skarnelis\n * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.\n *\n * Version: 1.3.4 (11/11/2010)\n * Requires: jQuery v1.3+\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n */\n\n;(function($) {\n  var tmp, loading, overlay, wrap, outer, content, close, title, nav_left, nav_right,\n\n    selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [],\n\n    ajaxLoader = null, imgPreloader = new Image(), imgRegExp = /\\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\\.]\\.(swf)\\s*$/i,\n\n    loadingTimer, loadingFrame = 1,\n\n    titleHeight = 0, titleStr = '', start_pos, final_pos, busy = false, fx = $.extend($('<div/>')[0], { prop: 0 }),\n\n    isIE6 = $.browser.msie && $.browser.version < 7 && !window.XMLHttpRequest,\n\n    /*\n     * Private methods\n     */\n\n    _abort = function() {\n      loading.hide();\n\n      imgPreloader.onerror = imgPreloader.onload = null;\n\n      if (ajaxLoader) {\n        ajaxLoader.abort();\n      }\n\n      tmp.empty();\n    },\n\n    _error = function() {\n      if (false === selectedOpts.onError(selectedArray, selectedIndex, selectedOpts)) {\n        loading.hide();\n        busy = false;\n        return;\n      }\n\n      selectedOpts.titleShow = false;\n\n      selectedOpts.width = 'auto';\n      selectedOpts.height = 'auto';\n\n      tmp.html( '<p id=\"fancybox-error\">The requested content cannot be loaded.<br />Please try again later.</p>' );\n\n      _process_inline();\n    },\n\n    _start = function() {\n      var obj = selectedArray[ selectedIndex ],\n        href,\n        type,\n        title,\n        str,\n        emb,\n        ret;\n\n      _abort();\n\n      selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox')));\n\n      ret = selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts);\n\n      if (ret === false) {\n        busy = false;\n        return;\n      } else if (typeof ret == 'object') {\n        selectedOpts = $.extend(selectedOpts, ret);\n      }\n\n      title = selectedOpts.title || (obj.nodeName ? $(obj).attr('title') : obj.title) || '';\n\n      if (obj.nodeName && !selectedOpts.orig) {\n        selectedOpts.orig = $(obj).children(\"img:first\").length ? $(obj).children(\"img:first\") : $(obj);\n      }\n\n      if (title === '' && selectedOpts.orig && selectedOpts.titleFromAlt) {\n        title = selectedOpts.orig.attr('alt');\n      }\n\n      href = selectedOpts.href || (obj.nodeName ? $(obj).attr('href') : obj.href) || null;\n\n      if ((/^(?:javascript)/i).test(href) || href == '#') {\n        href = null;\n      }\n\n      if (selectedOpts.type) {\n        type = selectedOpts.type;\n\n        if (!href) {\n          href = selectedOpts.content;\n        }\n\n      } else if (selectedOpts.content) {\n        type = 'html';\n\n      } else if (href) {\n        if (href.match(imgRegExp)) {\n          type = 'image';\n\n        } else if (href.match(swfRegExp)) {\n          type = 'swf';\n\n        } else if ($(obj).hasClass(\"iframe\")) {\n          type = 'iframe';\n\n        } else if (href.indexOf(\"#\") === 0) {\n          type = 'inline';\n\n        } else {\n          type = 'ajax';\n        }\n      }\n\n      if (!type) {\n        _error();\n        return;\n      }\n\n      if (type == 'inline') {\n        obj  = href.substr(href.indexOf(\"#\"));\n        type = $(obj).length > 0 ? 'inline' : 'ajax';\n      }\n\n      selectedOpts.type = type;\n      selectedOpts.href = href;\n      selectedOpts.title = title;\n\n      if (selectedOpts.autoDimensions) {\n        if (selectedOpts.type == 'html' || selectedOpts.type == 'inline' || selectedOpts.type == 'ajax') {\n          selectedOpts.width = 'auto';\n          selectedOpts.height = 'auto';\n        } else {\n          selectedOpts.autoDimensions = false;\n        }\n      }\n\n      if (selectedOpts.modal) {\n        selectedOpts.overlayShow = true;\n        selectedOpts.hideOnOverlayClick = false;\n        selectedOpts.hideOnContentClick = false;\n        selectedOpts.enableEscapeButton = false;\n        selectedOpts.showCloseButton = false;\n      }\n\n      selectedOpts.padding = parseInt(selectedOpts.padding, 10);\n      selectedOpts.margin = parseInt(selectedOpts.margin, 10);\n\n      tmp.css('padding', (selectedOpts.padding + selectedOpts.margin));\n\n      $('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function() {\n        $(this).replaceWith(content.children());\n      });\n\n      switch (type) {\n        case 'html' :\n          tmp.html( selectedOpts.content );\n          _process_inline();\n        break;\n\n        case 'inline' :\n          if ( $(obj).parent().is('#fancybox-content') === true) {\n            busy = false;\n            return;\n          }\n\n          $('<div class=\"fancybox-inline-tmp\" />')\n            .hide()\n            .insertBefore( $(obj) )\n            .bind('fancybox-cleanup', function() {\n              $(this).replaceWith(content.children());\n            }).bind('fancybox-cancel', function() {\n              $(this).replaceWith(tmp.children());\n            });\n\n          $(obj).appendTo(tmp);\n\n          _process_inline();\n        break;\n\n        case 'image':\n          busy = false;\n\n          $.fancybox.showActivity();\n\n          imgPreloader = new Image();\n\n          imgPreloader.onerror = function() {\n            _error();\n          };\n\n          imgPreloader.onload = function() {\n            busy = true;\n\n            imgPreloader.onerror = imgPreloader.onload = null;\n\n            _process_image();\n          };\n\n          imgPreloader.src = href;\n        break;\n\n        case 'swf':\n          selectedOpts.scrolling = 'no';\n\n          str = '<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\"' + selectedOpts.width + '\" height=\"' + selectedOpts.height + '\"><param name=\"movie\" value=\"' + href + '\"></param>';\n          emb = '';\n\n          $.each(selectedOpts.swf, function(name, val) {\n            str += '<param name=\"' + name + '\" value=\"' + val + '\"></param>';\n            emb += ' ' + name + '=\"' + val + '\"';\n          });\n\n          str += '<embed src=\"' + href + '\" type=\"application/x-shockwave-flash\" width=\"' + selectedOpts.width + '\" height=\"' + selectedOpts.height + '\"' + emb + '></embed></object>';\n\n          tmp.html(str);\n\n          _process_inline();\n        break;\n\n        case 'ajax':\n          busy = false;\n\n          $.fancybox.showActivity();\n\n          selectedOpts.ajax.win = selectedOpts.ajax.success;\n\n          ajaxLoader = $.ajax($.extend({}, selectedOpts.ajax, {\n            url  : href,\n            data : selectedOpts.ajax.data || {},\n            error : function(XMLHttpRequest, textStatus, errorThrown) {\n              if ( XMLHttpRequest.status > 0 ) {\n                _error();\n              }\n            },\n            success : function(data, textStatus, XMLHttpRequest) {\n              var o = typeof XMLHttpRequest == 'object' ? XMLHttpRequest : ajaxLoader;\n              if (o.status == 200) {\n                if ( typeof selectedOpts.ajax.win == 'function' ) {\n                  ret = selectedOpts.ajax.win(href, data, textStatus, XMLHttpRequest);\n\n                  if (ret === false) {\n                    loading.hide();\n                    return;\n                  } else if (typeof ret == 'string' || typeof ret == 'object') {\n                    data = ret;\n                  }\n                }\n\n                tmp.html( data );\n                _process_inline();\n              }\n            }\n          }));\n\n        break;\n\n        case 'iframe':\n          _show();\n        break;\n      }\n    },\n\n    _process_inline = function() {\n      var\n        w = selectedOpts.width,\n        h = selectedOpts.height;\n\n      if (w.toString().indexOf('%') > -1) {\n        w = parseInt( ($(window).width() - (selectedOpts.margin * 2)) * parseFloat(w) / 100, 10) + 'px';\n\n      } else {\n        w = w == 'auto' ? 'auto' : w + 'px';\n      }\n\n      if (h.toString().indexOf('%') > -1) {\n        h = parseInt( ($(window).height() - (selectedOpts.margin * 2)) * parseFloat(h) / 100, 10) + 'px';\n\n      } else {\n        h = h == 'auto' ? 'auto' : h + 'px';\n      }\n\n      tmp.wrapInner('<div style=\"width:' + w + ';height:' + h + ';overflow: ' + (selectedOpts.scrolling == 'auto' ? 'auto' : (selectedOpts.scrolling == 'yes' ? 'scroll' : 'hidden')) + ';position:relative;\"></div>');\n\n      selectedOpts.width = tmp.width();\n      selectedOpts.height = tmp.height();\n\n      _show();\n    },\n\n    _process_image = function() {\n      selectedOpts.width = imgPreloader.width;\n      selectedOpts.height = imgPreloader.height;\n\n      $(\"<img />\").attr({\n        'id' : 'fancybox-img',\n        'src' : imgPreloader.src,\n        'alt' : selectedOpts.title\n      }).appendTo( tmp );\n\n      _show();\n    },\n\n    _show = function() {\n      var pos, equal;\n\n      loading.hide();\n\n      if (wrap.is(\":visible\") && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {\n        $.event.trigger('fancybox-cancel');\n\n        busy = false;\n        return;\n      }\n\n      busy = true;\n\n      $(content.add( overlay )).unbind();\n\n      $(window).unbind(\"resize.fb scroll.fb\");\n      $(document).unbind('keydown.fb');\n\n      if (wrap.is(\":visible\") && currentOpts.titlePosition !== 'outside') {\n        wrap.css('height', wrap.height());\n      }\n\n      currentArray = selectedArray;\n      currentIndex = selectedIndex;\n      currentOpts = selectedOpts;\n\n      if (currentOpts.overlayShow) {\n        overlay.css({\n          'background-color' : currentOpts.overlayColor,\n          'opacity' : currentOpts.overlayOpacity,\n          'cursor' : currentOpts.hideOnOverlayClick ? 'pointer' : 'auto',\n          'height' : $(document).height()\n        });\n\n        if (!overlay.is(':visible')) {\n          if (isIE6) {\n            $('select:not(#fancybox-tmp select)').filter(function() {\n              return this.style.visibility !== 'hidden';\n            }).css({'visibility' : 'hidden'}).one('fancybox-cleanup', function() {\n              this.style.visibility = 'inherit';\n            });\n          }\n\n          overlay.show();\n        }\n      } else {\n        overlay.hide();\n      }\n\n      final_pos = _get_zoom_to();\n\n      _process_title();\n\n      if (wrap.is(\":visible\")) {\n        $( close.add( nav_left ).add( nav_right ) ).hide();\n\n        pos = wrap.position(),\n\n        start_pos = {\n          top   : pos.top,\n          left : pos.left,\n          width : wrap.width(),\n          height : wrap.height()\n        };\n\n        equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height);\n\n        content.fadeTo(currentOpts.changeFade, 0.3, function() {\n          var finish_resizing = function() {\n            content.html( tmp.contents() ).fadeTo(currentOpts.changeFade, 1, _finish);\n          };\n\n          $.event.trigger('fancybox-change');\n\n          content\n            .empty()\n            .removeAttr('filter')\n            .css({\n              'border-width' : currentOpts.padding,\n              'width'  : final_pos.width - currentOpts.padding * 2,\n              'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2\n            });\n\n          if (equal) {\n            finish_resizing();\n\n          } else {\n            fx.prop = 0;\n\n            $(fx).animate({prop: 1}, {\n               duration : currentOpts.changeSpeed,\n               easing : currentOpts.easingChange,\n               step : _draw,\n               complete : finish_resizing\n            });\n          }\n        });\n\n        return;\n      }\n\n      wrap.removeAttr(\"style\");\n\n      content.css('border-width', currentOpts.padding);\n\n      if (currentOpts.transitionIn == 'elastic') {\n        start_pos = _get_zoom_from();\n\n        content.html( tmp.contents() );\n\n        wrap.show();\n\n        if (currentOpts.opacity) {\n          final_pos.opacity = 0;\n        }\n\n        fx.prop = 0;\n\n        $(fx).animate({prop: 1}, {\n           duration : currentOpts.speedIn,\n           easing : currentOpts.easingIn,\n           step : _draw,\n           complete : _finish\n        });\n\n        return;\n      }\n\n      if (currentOpts.titlePosition == 'inside' && titleHeight > 0) {\n        title.show();\n      }\n\n      content\n        .css({\n          'width' : final_pos.width - currentOpts.padding * 2,\n          'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2\n        })\n        .html( tmp.contents() );\n\n      wrap\n        .css(final_pos)\n        .fadeIn( currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish );\n    },\n\n    _format_title = function(title) {\n      if (title && title.length) {\n        if (currentOpts.titlePosition == 'float') {\n          return '<table id=\"fancybox-title-float-wrap\" cellpadding=\"0\" cellspacing=\"0\"><tr><td id=\"fancybox-title-float-left\"></td><td id=\"fancybox-title-float-main\">' + title + '</td><td id=\"fancybox-title-float-right\"></td></tr></table>';\n        }\n\n        return '<div id=\"fancybox-title-' + currentOpts.titlePosition + '\">' + title + '</div>';\n      }\n\n      return false;\n    },\n\n    _process_title = function() {\n      titleStr = currentOpts.title || '';\n      titleHeight = 0;\n\n      title\n        .empty()\n        .removeAttr('style')\n        .removeClass();\n\n      if (currentOpts.titleShow === false) {\n        title.hide();\n        return;\n      }\n\n      titleStr = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(titleStr, currentArray, currentIndex, currentOpts) : _format_title(titleStr);\n\n      if (!titleStr || titleStr === '') {\n        title.hide();\n        return;\n      }\n\n      title\n        .addClass('fancybox-title-' + currentOpts.titlePosition)\n        .html( titleStr )\n        .appendTo( 'body' )\n        .show();\n\n      switch (currentOpts.titlePosition) {\n        case 'inside':\n          title\n            .css({\n              'width' : final_pos.width - (currentOpts.padding * 2),\n              'marginLeft' : currentOpts.padding,\n              'marginRight' : currentOpts.padding\n            });\n\n          titleHeight = title.outerHeight(true);\n\n          title.appendTo( outer );\n\n          final_pos.height += titleHeight;\n        break;\n\n        case 'over':\n          title\n            .css({\n              'marginLeft' : currentOpts.padding,\n              'width'  : final_pos.width - (currentOpts.padding * 2),\n              'bottom' : currentOpts.padding\n            })\n            .appendTo( outer );\n        break;\n\n        case 'float':\n          title\n            .css('left', parseInt((title.width() - final_pos.width - 40)/ 2, 10) * -1)\n            .appendTo( wrap );\n        break;\n\n        default:\n          title\n            .css({\n              'width' : final_pos.width - (currentOpts.padding * 2),\n              'paddingLeft' : currentOpts.padding,\n              'paddingRight' : currentOpts.padding\n            })\n            .appendTo( wrap );\n        break;\n      }\n\n      title.hide();\n    },\n\n    _set_navigation = function() {\n      if (currentOpts.enableEscapeButton || currentOpts.enableKeyboardNav) {\n        $(document).bind('keydown.fb', function(e) {\n          if (e.keyCode == 27 && currentOpts.enableEscapeButton) {\n            e.preventDefault();\n            $.fancybox.close();\n\n          } else if ((e.keyCode == 37 || e.keyCode == 39) && currentOpts.enableKeyboardNav && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'SELECT') {\n            e.preventDefault();\n            $.fancybox[ e.keyCode == 37 ? 'prev' : 'next']();\n          }\n        });\n      }\n\n      if (!currentOpts.showNavArrows) {\n        nav_left.hide();\n        nav_right.hide();\n        return;\n      }\n\n      if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex !== 0) {\n        nav_left.show();\n      }\n\n      if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length -1)) {\n        nav_right.show();\n      }\n    },\n\n    _finish = function () {\n      if (!$.support.opacity) {\n        content.get(0).style.removeAttribute('filter');\n        wrap.get(0).style.removeAttribute('filter');\n      }\n\n      if (selectedOpts.autoDimensions) {\n        content.css('height', 'auto');\n      }\n\n      wrap.css('height', 'auto');\n\n      if (titleStr && titleStr.length) {\n        title.show();\n      }\n\n      if (currentOpts.showCloseButton) {\n        close.show();\n      }\n\n      _set_navigation();\n\n      if (currentOpts.hideOnContentClick)  {\n        content.bind('click', $.fancybox.close);\n      }\n\n      if (currentOpts.hideOnOverlayClick)  {\n        overlay.bind('click', $.fancybox.close);\n      }\n\n      $(window).bind(\"resize.fb\", $.fancybox.resize);\n\n      if (currentOpts.centerOnScroll) {\n        $(window).bind(\"scroll.fb\", $.fancybox.center);\n      }\n\n      if (currentOpts.type == 'iframe') {\n        $('<iframe id=\"fancybox-frame\" name=\"fancybox-frame' + new Date().getTime() + '\" frameborder=\"0\" hspace=\"0\" ' + ($.browser.msie ? 'allowtransparency=\"true\"\"' : '') + ' scrolling=\"' + selectedOpts.scrolling + '\" src=\"' + currentOpts.href + '\"></iframe>').appendTo(content);\n      }\n\n      wrap.show();\n\n      busy = false;\n\n      $.fancybox.center();\n\n      currentOpts.onComplete(currentArray, currentIndex, currentOpts);\n\n      _preload_images();\n    },\n\n    _preload_images = function() {\n      var href,\n        objNext;\n\n      if ((currentArray.length -1) > currentIndex) {\n        href = currentArray[ currentIndex + 1 ].href;\n\n        if (typeof href !== 'undefined' && href.match(imgRegExp)) {\n          objNext = new Image();\n          objNext.src = href;\n        }\n      }\n\n      if (currentIndex > 0) {\n        href = currentArray[ currentIndex - 1 ].href;\n\n        if (typeof href !== 'undefined' && href.match(imgRegExp)) {\n          objNext = new Image();\n          objNext.src = href;\n        }\n      }\n    },\n\n    _draw = function(pos) {\n      var dim = {\n        width : parseInt(start_pos.width + (final_pos.width - start_pos.width) * pos, 10),\n        height : parseInt(start_pos.height + (final_pos.height - start_pos.height) * pos, 10),\n\n        top : parseInt(start_pos.top + (final_pos.top - start_pos.top) * pos, 10),\n        left : parseInt(start_pos.left + (final_pos.left - start_pos.left) * pos, 10)\n      };\n\n      if (typeof final_pos.opacity !== 'undefined') {\n        dim.opacity = pos < 0.5 ? 0.5 : pos;\n      }\n\n      wrap.css(dim);\n\n      content.css({\n        'width' : dim.width - currentOpts.padding * 2,\n        'height' : dim.height - (titleHeight * pos) - currentOpts.padding * 2\n      });\n    },\n\n    _get_viewport = function() {\n      return [\n        $(window).width() - (currentOpts.margin * 2),\n        $(window).height() - (currentOpts.margin * 2),\n        $(document).scrollLeft() + currentOpts.margin,\n        $(document).scrollTop() + currentOpts.margin\n      ];\n    },\n\n    _get_zoom_to = function () {\n      var view = _get_viewport(),\n        to = {},\n        resize = currentOpts.autoScale,\n        double_padding = currentOpts.padding * 2,\n        ratio;\n\n      if (currentOpts.width.toString().indexOf('%') > -1) {\n        to.width = parseInt((view[0] * parseFloat(currentOpts.width)) / 100, 10);\n      } else {\n        to.width = currentOpts.width + double_padding;\n      }\n\n      if (currentOpts.height.toString().indexOf('%') > -1) {\n        to.height = parseInt((view[1] * parseFloat(currentOpts.height)) / 100, 10);\n      } else {\n        to.height = currentOpts.height + double_padding;\n      }\n\n      if (resize && (to.width > view[0] || to.height > view[1])) {\n        if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') {\n          ratio = (currentOpts.width ) / (currentOpts.height );\n\n          if ((to.width ) > view[0]) {\n            to.width = view[0];\n            to.height = parseInt(((to.width - double_padding) / ratio) + double_padding, 10);\n          }\n\n          if ((to.height) > view[1]) {\n            to.height = view[1];\n            to.width = parseInt(((to.height - double_padding) * ratio) + double_padding, 10);\n          }\n\n        } else {\n          to.width = Math.min(to.width, view[0]);\n          to.height = Math.min(to.height, view[1]);\n        }\n      }\n\n      to.top = parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - to.height - 40) * 0.5)), 10);\n      to.left = parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - to.width - 40) * 0.5)), 10);\n\n      return to;\n    },\n\n    _get_obj_pos = function(obj) {\n      var pos = obj.offset();\n\n      pos.top += parseInt( obj.css('paddingTop'), 10 ) || 0;\n      pos.left += parseInt( obj.css('paddingLeft'), 10 ) || 0;\n\n      pos.top += parseInt( obj.css('border-top-width'), 10 ) || 0;\n      pos.left += parseInt( obj.css('border-left-width'), 10 ) || 0;\n\n      pos.width = obj.width();\n      pos.height = obj.height();\n\n      return pos;\n    },\n\n    _get_zoom_from = function() {\n      var orig = selectedOpts.orig ? $(selectedOpts.orig) : false,\n        from = {},\n        pos,\n        view;\n\n      if (orig && orig.length) {\n        pos = _get_obj_pos(orig);\n\n        from = {\n          width : pos.width + (currentOpts.padding * 2),\n          height : pos.height + (currentOpts.padding * 2),\n          top  : pos.top - currentOpts.padding - 20,\n          left : pos.left - currentOpts.padding - 20\n        };\n\n      } else {\n        view = _get_viewport();\n\n        from = {\n          width : currentOpts.padding * 2,\n          height : currentOpts.padding * 2,\n          top  : parseInt(view[3] + view[1] * 0.5, 10),\n          left : parseInt(view[2] + view[0] * 0.5, 10)\n        };\n      }\n\n      return from;\n    },\n\n    _animate_loading = function() {\n      if (!loading.is(':visible')){\n        clearInterval(loadingTimer);\n        return;\n      }\n\n      $('div', loading).css('top', (loadingFrame * -40) + 'px');\n\n      loadingFrame = (loadingFrame + 1) % 12;\n    };\n\n  /*\n   * Public methods\n   */\n\n  $.fn.fancybox = function(options) {\n    if (!$(this).length) {\n      return this;\n    }\n\n    $(this)\n      .data('fancybox', $.extend({}, options, ($.metadata ? $(this).metadata() : {})))\n      .unbind('click.fb')\n      .bind('click.fb', function(e) {\n        e.preventDefault();\n\n        if (busy) {\n          return;\n        }\n\n        busy = true;\n\n        $(this).blur();\n\n        selectedArray = [];\n        selectedIndex = 0;\n\n        var rel = $(this).attr('rel') || '';\n\n        if (!rel || rel == '' || rel === 'nofollow') {\n          selectedArray.push(this);\n\n        } else {\n          selectedArray = $(\"a[rel=\" + rel + \"], area[rel=\" + rel + \"]\");\n          selectedIndex = selectedArray.index( this );\n        }\n\n        _start();\n\n        return;\n      });\n\n    return this;\n  };\n\n  $.fancybox = function(obj) {\n    var opts;\n\n    if (busy) {\n      return;\n    }\n\n    busy = true;\n    opts = typeof arguments[1] !== 'undefined' ? arguments[1] : {};\n\n    selectedArray = [];\n    selectedIndex = parseInt(opts.index, 10) || 0;\n\n    if ($.isArray(obj)) {\n      for (var i = 0, j = obj.length; i < j; i++) {\n        if (typeof obj[i] == 'object') {\n          $(obj[i]).data('fancybox', $.extend({}, opts, obj[i]));\n        } else {\n          obj[i] = $({}).data('fancybox', $.extend({content : obj[i]}, opts));\n        }\n      }\n\n      selectedArray = jQuery.merge(selectedArray, obj);\n\n    } else {\n      if (typeof obj == 'object') {\n        $(obj).data('fancybox', $.extend({}, opts, obj));\n      } else {\n        obj = $({}).data('fancybox', $.extend({content : obj}, opts));\n      }\n\n      selectedArray.push(obj);\n    }\n\n    if (selectedIndex > selectedArray.length || selectedIndex < 0) {\n      selectedIndex = 0;\n    }\n\n    _start();\n  };\n\n  $.fancybox.showActivity = function() {\n    clearInterval(loadingTimer);\n\n    loading.show();\n    loadingTimer = setInterval(_animate_loading, 66);\n  };\n\n  $.fancybox.hideActivity = function() {\n    loading.hide();\n  };\n\n  $.fancybox.next = function() {\n    return $.fancybox.pos( currentIndex + 1);\n  };\n\n  $.fancybox.prev = function() {\n    return $.fancybox.pos( currentIndex - 1);\n  };\n\n  $.fancybox.pos = function(pos) {\n    if (busy) {\n      return;\n    }\n\n    pos = parseInt(pos);\n\n    selectedArray = currentArray;\n\n    if (pos > -1 && pos < currentArray.length) {\n      selectedIndex = pos;\n      _start();\n\n    } else if (currentOpts.cyclic && currentArray.length > 1) {\n      selectedIndex = pos >= currentArray.length ? 0 : currentArray.length - 1;\n      _start();\n    }\n\n    return;\n  };\n\n  $.fancybox.cancel = function() {\n    if (busy) {\n      return;\n    }\n\n    busy = true;\n\n    $.event.trigger('fancybox-cancel');\n\n    _abort();\n\n    selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts);\n\n    busy = false;\n  };\n\n  // Note: within an iframe use - parent.$.fancybox.close();\n  $.fancybox.close = function() {\n    if (busy || wrap.is(':hidden')) {\n      return;\n    }\n\n    busy = true;\n\n    if (currentOpts && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {\n      busy = false;\n      return;\n    }\n\n    _abort();\n\n    $(close.add( nav_left ).add( nav_right )).hide();\n\n    $(content.add( overlay )).unbind();\n\n    $(window).unbind(\"resize.fb scroll.fb\");\n    $(document).unbind('keydown.fb');\n\n    content.find('iframe').attr('src', isIE6 && /^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank');\n\n    if (currentOpts.titlePosition !== 'inside') {\n      title.empty();\n    }\n\n    wrap.stop();\n\n    function _cleanup() {\n      overlay.fadeOut('fast');\n\n      title.empty().hide();\n      wrap.hide();\n\n      $.event.trigger('fancybox-cleanup');\n\n      content.empty();\n\n      currentOpts.onClosed(currentArray, currentIndex, currentOpts);\n\n      currentArray = selectedOpts  = [];\n      currentIndex = selectedIndex = 0;\n      currentOpts = selectedOpts  = {};\n\n      busy = false;\n    }\n\n    if (currentOpts.transitionOut == 'elastic') {\n      start_pos = _get_zoom_from();\n\n      var pos = wrap.position();\n\n      final_pos = {\n        top   : pos.top ,\n        left : pos.left,\n        width :  wrap.width(),\n        height : wrap.height()\n      };\n\n      if (currentOpts.opacity) {\n        final_pos.opacity = 1;\n      }\n\n      title.empty().hide();\n\n      fx.prop = 1;\n\n      $(fx).animate({ prop: 0 }, {\n         duration : currentOpts.speedOut,\n         easing : currentOpts.easingOut,\n         step : _draw,\n         complete : _cleanup\n      });\n\n    } else {\n      wrap.fadeOut( currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup);\n    }\n  };\n\n  $.fancybox.resize = function() {\n    if (overlay.is(':visible')) {\n      overlay.css('height', $(document).height());\n    }\n\n    $.fancybox.center(true);\n  };\n\n  $.fancybox.center = function() {\n    var view, align;\n\n    if (busy) {\n      return;\n    }\n\n    align = arguments[0] === true ? 1 : 0;\n    view = _get_viewport();\n\n    if (!align && (wrap.width() > view[0] || wrap.height() > view[1])) {\n      return;\n    }\n\n    wrap\n      .stop()\n      .animate({\n        'top' : parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - content.height() - 40) * 0.5) - currentOpts.padding)),\n        'left' : parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - content.width() - 40) * 0.5) - currentOpts.padding))\n      }, typeof arguments[0] == 'number' ? arguments[0] : 200);\n  };\n\n  $.fancybox.init = function() {\n    if ($(\"#fancybox-wrap\").length) {\n      return;\n    }\n\n    $('body').append(\n      tmp  = $('<div id=\"fancybox-tmp\"></div>'),\n      loading  = $('<div id=\"fancybox-loading\"><div></div></div>'),\n      overlay  = $('<div id=\"fancybox-overlay\"></div>'),\n      wrap = $('<div id=\"fancybox-wrap\"></div>')\n    );\n\n    outer = $('<div id=\"fancybox-outer\"></div>')\n      .append('<div class=\"fancybox-bg\" id=\"fancybox-bg-n\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-ne\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-e\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-se\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-s\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-sw\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-w\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-nw\"></div>')\n      .appendTo( wrap );\n\n    outer.append(\n      content = $('<div id=\"fancybox-content\"></div>'),\n      close = $('<a id=\"fancybox-close\"></a>'),\n      title = $('<div id=\"fancybox-title\"></div>'),\n\n      nav_left = $('<a href=\"javascript:;\" id=\"fancybox-left\"><span class=\"fancy-ico\" id=\"fancybox-left-ico\"></span></a>'),\n      nav_right = $('<a href=\"javascript:;\" id=\"fancybox-right\"><span class=\"fancy-ico\" id=\"fancybox-right-ico\"></span></a>')\n    );\n\n    close.click($.fancybox.close);\n    loading.click($.fancybox.cancel);\n\n    nav_left.click(function(e) {\n      e.preventDefault();\n      $.fancybox.prev();\n    });\n\n    nav_right.click(function(e) {\n      e.preventDefault();\n      $.fancybox.next();\n    });\n\n    if ($.fn.mousewheel) {\n      wrap.bind('mousewheel.fb', function(e, delta) {\n        if (busy) {\n          e.preventDefault();\n\n        } else if ($(e.target).get(0).clientHeight == 0 || $(e.target).get(0).scrollHeight === $(e.target).get(0).clientHeight) {\n          e.preventDefault();\n          $.fancybox[ delta > 0 ? 'prev' : 'next']();\n        }\n      });\n    }\n\n    if (!$.support.opacity) {\n      wrap.addClass('fancybox-ie');\n    }\n\n    if (isIE6) {\n      loading.addClass('fancybox-ie6');\n      wrap.addClass('fancybox-ie6');\n\n      $('<iframe id=\"fancybox-hide-sel-frame\" src=\"' + (/^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank' ) + '\" scrolling=\"no\" border=\"0\" frameborder=\"0\" tabindex=\"-1\"></iframe>').prependTo(outer);\n    }\n  };\n\n  $.fn.fancybox.defaults = {\n    padding : 10,\n    margin : 40,\n    opacity : false,\n    modal : false,\n    cyclic : false,\n    scrolling : 'auto',  // 'auto', 'yes' or 'no'\n\n    width : 560,\n    height : 340,\n\n    autoScale : true,\n    autoDimensions : true,\n    centerOnScroll : false,\n\n    ajax : {},\n    swf : { wmode: 'transparent' },\n\n    hideOnOverlayClick : true,\n    hideOnContentClick : false,\n\n    overlayShow : true,\n    overlayOpacity : 0.7,\n    overlayColor : '#777',\n\n    titleShow : true,\n    titlePosition : 'float', // 'float', 'outside', 'inside' or 'over'\n    titleFormat : null,\n    titleFromAlt : false,\n\n    transitionIn : 'fade', // 'elastic', 'fade' or 'none'\n    transitionOut : 'fade', // 'elastic', 'fade' or 'none'\n\n    speedIn : 300,\n    speedOut : 300,\n\n    changeSpeed : 300,\n    changeFade : 'fast',\n\n    easingIn : 'swing',\n    easingOut : 'swing',\n\n    showCloseButton   : true,\n    showNavArrows : true,\n    enableEscapeButton : true,\n    enableKeyboardNav : true,\n\n    onStart : function(){},\n    onCancel : function(){},\n    onComplete : function(){},\n    onCleanup : function(){},\n    onClosed : function(){},\n    onError : function(){}\n  };\n\n  $(document).ready(function() {\n    $.fancybox.init();\n  });\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.fancybox-1.3.4.pack.js",
    "content": "/*\n * FancyBox - jQuery Plugin\n * Simple and fancy lightbox alternative\n *\n * Examples and documentation at: http://fancybox.net\n *\n * Copyright (c) 2008 - 2010 Janis Skarnelis\n * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.\n *\n * Version: 1.3.4 (11/11/2010)\n * Requires: jQuery v1.3+\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n */\n\n;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\\.]\\.(swf)\\s*$/i,K,L=1,y=0,s=\"\",r,i,h=false,B=b.extend(b(\"<div/>\")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width=\"auto\";e.height=\"auto\";m.html('<p id=\"fancybox-error\">The requested content cannot be loaded.<br />Please try again later.</p>');\nF()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data(\"fancybox\")==\"undefined\"?e:b(a).data(\"fancybox\"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w==\"object\")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr(\"title\"):a.title)||\"\";if(a.nodeName&&!e.orig)e.orig=b(a).children(\"img:first\").length?b(a).children(\"img:first\"):b(a);if(k===\"\"&&e.orig&&e.titleFromAlt)k=e.orig.attr(\"alt\");c=e.href||(a.nodeName?b(a).attr(\"href\"):a.href)||null;if(/^(?:javascript)/i.test(c)||\nc==\"#\")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g=\"html\";else if(c)g=c.match(J)?\"image\":c.match(W)?\"swf\":b(a).hasClass(\"iframe\")?\"iframe\":c.indexOf(\"#\")===0?\"inline\":\"ajax\";if(g){if(g==\"inline\"){a=c.substr(c.indexOf(\"#\"));g=b(a).length>0?\"inline\":\"ajax\"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type==\"html\"||e.type==\"inline\"||e.type==\"ajax\"){e.width=\"auto\";e.height=\"auto\"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=\nfalse;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css(\"padding\",e.padding+e.margin);b(\".fancybox-inline-tmp\").unbind(\"fancybox-cancel\").bind(\"fancybox-change\",function(){b(this).replaceWith(j.children())});switch(g){case \"html\":m.html(e.content);F();break;case \"inline\":if(b(a).parent().is(\"#fancybox-content\")===true){h=false;break}b('<div class=\"fancybox-inline-tmp\" />').hide().insertBefore(b(a)).bind(\"fancybox-cleanup\",function(){b(this).replaceWith(j.children())}).bind(\"fancybox-cancel\",\nfunction(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case \"image\":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b(\"<img />\").attr({id:\"fancybox-img\",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case \"swf\":e.scrolling=\"no\";C='<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\"'+e.width+'\" height=\"'+e.height+'\"><param name=\"movie\" value=\"'+c+\n'\"></param>';P=\"\";b.each(e.swf,function(x,H){C+='<param name=\"'+x+'\" value=\"'+H+'\"></param>';P+=\" \"+x+'=\"'+H+'\"'});C+='<embed src=\"'+c+'\" type=\"application/x-shockwave-flash\" width=\"'+e.width+'\" height=\"'+e.height+'\"'+P+\"></embed></object>\";m.html(C);F();break;case \"ajax\":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R==\"object\"?R:G).status==200){if(typeof e.ajax.win==\n\"function\"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w==\"string\"||typeof w==\"object\")x=w}m.html(x);F()}}}));break;case \"iframe\":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf(\"%\")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+\"px\":a==\"auto\"?\"auto\":a+\"px\";c=c.toString().indexOf(\"%\")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+\"px\":c==\"auto\"?\"auto\":c+\"px\";m.wrapInner('<div style=\"width:'+a+\";height:\"+c+\n\";overflow: \"+(e.scrolling==\"auto\"?\"auto\":e.scrolling==\"yes\"?\"scroll\":\"hidden\")+';position:relative;\"></div>');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(\":visible\")&&false===d.onCleanup(l,p,d)){b.event.trigger(\"fancybox-cancel\");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind(\"resize.fb scroll.fb\");b(document).unbind(\"keydown.fb\");f.is(\":visible\")&&d.titlePosition!==\"outside\"&&f.css(\"height\",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({\"background-color\":d.overlayColor,\nopacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?\"pointer\":\"auto\",height:b(document).height()});if(!u.is(\":visible\")){M&&b(\"select:not(#fancybox-tmp select)\").filter(function(){return this.style.visibility!==\"hidden\"}).css({visibility:\"hidden\"}).one(\"fancybox-cleanup\",function(){this.style.visibility=\"inherit\"});u.show()}}else u.hide();i=X();s=d.title||\"\";y=0;n.empty().removeAttr(\"style\").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length?\nd.titlePosition==\"float\"?'<table id=\"fancybox-title-float-wrap\" cellpadding=\"0\" cellspacing=\"0\"><tr><td id=\"fancybox-title-float-left\"></td><td id=\"fancybox-title-float-main\">'+s+'</td><td id=\"fancybox-title-float-right\"></td></tr></table>':'<div id=\"fancybox-title-'+d.titlePosition+'\">'+s+\"</div>\":false;s=a;if(!(!s||s===\"\")){n.addClass(\"fancybox-title-\"+d.titlePosition).html(s).appendTo(\"body\").show();switch(d.titlePosition){case \"inside\":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding});\ny=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case \"over\":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case \"float\":n.css(\"left\",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(\":visible\")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height==\ni.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger(\"fancybox-change\");j.empty().removeAttr(\"filter\").css({\"border-width\":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?\"auto\":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr(\"style\");j.css(\"border-width\",d.padding);if(d.transitionIn==\"elastic\"){r=V();j.html(m.contents());\nf.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition==\"inside\"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?\"auto\":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn==\"none\"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind(\"keydown.fb\",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode==\n37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!==\"INPUT\"&&a.target.tagName!==\"TEXTAREA\"&&a.target.tagName!==\"SELECT\"){a.preventDefault();b.fancybox[a.keyCode==37?\"prev\":\"next\"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute(\"filter\");f.get(0).style.removeAttribute(\"filter\")}e.autoDimensions&&j.css(\"height\",\"auto\");f.css(\"height\",\"auto\");\ns&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind(\"click\",b.fancybox.close);d.hideOnOverlayClick&&u.bind(\"click\",b.fancybox.close);b(window).bind(\"resize.fb\",b.fancybox.resize);d.centerOnScroll&&b(window).bind(\"scroll.fb\",b.fancybox.center);if(d.type==\"iframe\")b('<iframe id=\"fancybox-frame\" name=\"fancybox-frame'+(new Date).getTime()+'\" frameborder=\"0\" hspace=\"0\" '+(b.browser.msie?'allowtransparency=\"true\"\"':\"\")+' scrolling=\"'+e.scrolling+'\" src=\"'+d.href+'\"></iframe>').appendTo(j);\nf.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!==\"undefined\"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!==\"undefined\"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!==\"undefined\")c.opacity=a<0.5?0.5:a;f.css(c);\nj.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf(\"%\")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf(\"%\")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type==\n\"image\"||e.type==\"swf\"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css(\"paddingTop\"),\n10)||0;c.left+=parseInt(a.css(\"paddingLeft\"),10)||0;c.top+=parseInt(a.css(\"border-top-width\"),10)||0;c.left+=parseInt(a.css(\"border-left-width\"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(\":visible\")){b(\"div\",t).css(\"top\",L*-40+\"px\");L=(L+1)%12}else clearInterval(K)};\nb.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data(\"fancybox\",b.extend({},a,b.metadata?b(this).metadata():{})).unbind(\"click.fb\").bind(\"click.fb\",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr(\"rel\")||\"\";if(!c||c==\"\"||c===\"nofollow\")o.push(this);else{o=b(\"a[rel=\"+c+\"], area[rel=\"+c+\"]\");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!==\"undefined\"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k=\n0,C=a.length;k<C;k++)if(typeof a[k]==\"object\")b(a[k]).data(\"fancybox\",b.extend({},g,a[k]));else a[k]=b({}).data(\"fancybox\",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a==\"object\")b(a).data(\"fancybox\",b.extend({},g,a));else a=b({}).data(\"fancybox\",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+\n1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger(\"fancybox-cancel\");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut(\"fast\");n.empty().hide();f.hide();b.event.trigger(\"fancybox-cleanup\");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(\":hidden\"))){h=\ntrue;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind(\"resize.fb scroll.fb\");b(document).unbind(\"keydown.fb\");j.find(\"iframe\").attr(\"src\",M&&/^https/i.test(window.location.href||\"\")?\"javascript:void(false)\":\"about:blank\");d.titlePosition!==\"inside\"&&n.empty();f.stop();if(d.transitionOut==\"elastic\"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;\nb(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut==\"none\"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(\":visible\")&&u.css(\"height\",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5-\nd.padding))},typeof a==\"number\"?a:200)}};b.fancybox.init=function(){if(!b(\"#fancybox-wrap\").length){b(\"body\").append(m=b('<div id=\"fancybox-tmp\"></div>'),t=b('<div id=\"fancybox-loading\"><div></div></div>'),u=b('<div id=\"fancybox-overlay\"></div>'),f=b('<div id=\"fancybox-wrap\"></div>'));D=b('<div id=\"fancybox-outer\"></div>').append('<div class=\"fancybox-bg\" id=\"fancybox-bg-n\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-ne\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-e\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-se\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-s\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-sw\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-w\"></div><div class=\"fancybox-bg\" id=\"fancybox-bg-nw\"></div>').appendTo(f);\nD.append(j=b('<div id=\"fancybox-content\"></div>'),E=b('<a id=\"fancybox-close\"></a>'),n=b('<div id=\"fancybox-title\"></div>'),z=b('<a href=\"javascript:;\" id=\"fancybox-left\"><span class=\"fancy-ico\" id=\"fancybox-left-ico\"></span></a>'),A=b('<a href=\"javascript:;\" id=\"fancybox-right\"><span class=\"fancy-ico\" id=\"fancybox-right-ico\"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()});\nb.fn.mousewheel&&f.bind(\"mousewheel.fb\",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?\"prev\":\"next\"]()}});b.support.opacity||f.addClass(\"fancybox-ie\");if(M){t.addClass(\"fancybox-ie6\");f.addClass(\"fancybox-ie6\");b('<iframe id=\"fancybox-hide-sel-frame\" src=\"'+(/^https/i.test(window.location.href||\"\")?\"javascript:void(false)\":\"about:blank\")+'\" scrolling=\"no\" border=\"0\" frameborder=\"0\" tabindex=\"-1\"></iframe>').prependTo(D)}}};\nb.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:\"auto\",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:\"transparent\"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:\"#777\",titleShow:true,titlePosition:\"float\",titleFormat:null,titleFromAlt:false,transitionIn:\"fade\",transitionOut:\"fade\",speedIn:300,speedOut:300,changeSpeed:300,changeFade:\"fast\",easingIn:\"swing\",\neasingOut:\"swing\",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.fileupload-ui.js",
    "content": "/*\n * jQuery File Upload User Interface Plugin 3.6\n *\n * Copyright 2010, Sebastian Tschan, AQUANTUM\n * Licensed under the MIT license:\n * http://creativecommons.org/licenses/MIT/\n *\n * https://blueimp.net\n * http://www.aquantum.de\n */\n\n/*jslint browser: true */\n/*global jQuery, FileReader, URL */\n\n(function ($) {\n\n    var undef = 'undefined',\n        func = 'function',\n        UploadHandler,\n        methods,\n\n        LocalImage = function (file, imageTypes) {\n            var img,\n                fileReader;\n            if (!imageTypes.test(file.type)) {\n                return null;\n            }\n            img = document.createElement('img');\n            if (typeof URL !== undef && typeof URL.createObjectURL === func) {\n                img.src = URL.createObjectURL(file);\n                img.onload = function () {\n                    URL.revokeObjectURL(this.src);\n                };\n                return img;\n            }\n            if (typeof FileReader !== undef) {\n                fileReader = new FileReader();\n                if (typeof fileReader.readAsDataURL === func) {\n                    fileReader.onload = function (e) {\n                        img.src = e.target.result;\n                    };\n                    fileReader.readAsDataURL(file);\n                    return img;\n                }\n            }\n            return null;\n        };\n\n    UploadHandler = function (container, options) {\n        var uploadHandler = this,\n            dragOverTimeout,\n            isDropZoneEnlarged;\n\n        this.dropZone = container;\n        this.imageTypes = /^image\\/(gif|jpeg|png)$/;\n        this.previewSelector = '.file_upload_preview';\n        this.progressSelector = '.file_upload_progress div';\n        this.cancelSelector = '.file_upload_cancel button';\n        this.cssClassSmall = 'file_upload_small';\n        this.cssClassLarge = 'file_upload_large';\n        this.cssClassHighlight = 'file_upload_highlight';\n        this.dropEffect = 'highlight';\n        this.uploadTable = this.downloadTable = null;\n\n        this.buildUploadRow = this.buildDownloadRow = function () {\n            return null;\n        };\n\n        this.addNode = function (parentNode, node, callBack) {\n            if (node) {\n                node.css('display', 'none').appendTo(parentNode).fadeIn(function () {\n                    if (typeof callBack === func) {\n                        try {\n                            callBack();\n                        } catch (e) {\n                            // Fix endless exception loop:\n                            $(this).stop();\n                            throw e;\n                        }\n                    }\n                });\n            } else if (typeof callBack === func) {\n                callBack();\n            }\n        };\n\n        this.removeNode = function (node, callBack) {\n            if (node) {\n                node.fadeOut(function () {\n                    $(this).remove();\n                    if (typeof callBack === func) {\n                        try {\n                            callBack();\n                        } catch (e) {\n                            // Fix endless exception loop:\n                            $(this).stop();\n                            throw e;\n                        }\n                    }\n                });\n            } else if (typeof callBack === func) {\n                callBack();\n            }\n        };\n\n        this.onAbort = function (event, files, index, xhr, handler) {\n            handler.removeNode(handler.uploadRow);\n        };\n\n        this.cancelUpload = function (event, files, index, xhr, handler) {\n            var readyState = xhr.readyState;\n            xhr.abort();\n            // If readyState is below 2, abort() has no effect:\n            if (isNaN(readyState) || readyState < 2) {\n                handler.onAbort(event, files, index, xhr, handler);\n            }\n        };\n\n        this.initProgressBar = function (node, value) {\n            if (typeof node.progressbar === func) {\n                return node.progressbar({\n                    value: value\n                });\n            } else {\n                var progressbar = $('<progress value=\"' + value + '\" max=\"100\"/>').appendTo(node);\n                progressbar.progressbar = function (key, value) {\n                    progressbar.attr('value', value);\n                };\n                return progressbar;\n            }\n        };\n\n        this.initUploadRow = function (event, files, index, xhr, handler, callBack) {\n            var uploadRow = handler.uploadRow = handler.buildUploadRow(files, index, handler);\n            if (uploadRow) {\n                handler.progressbar = handler.initProgressBar(\n                    uploadRow.find(handler.progressSelector),\n                    (xhr.upload ? 0 : 100)\n                );\n                uploadRow.find(handler.cancelSelector).click(function (e) {\n                    handler.cancelUpload(e, files, index, xhr, handler);\n                });\n                uploadRow.find(handler.previewSelector).each(function () {\n                    $(this).append(new LocalImage(files[index], handler.imageTypes));\n                });\n            }\n            handler.addNode(\n                (typeof handler.uploadTable === func ? handler.uploadTable(handler) : handler.uploadTable),\n                uploadRow,\n                callBack\n            );\n        };\n\n        this.initUpload = function (event, files, index, xhr, handler, callBack) {\n            handler.initUploadRow(event, files, index, xhr, handler, function () {\n                if (typeof handler.beforeSend === func) {\n                    handler.beforeSend(event, files, index, xhr, handler, callBack);\n                } else {\n                    callBack();\n                }\n            });\n        };\n\n        this.onProgress = function (event, files, index, xhr, handler) {\n            if (handler.progressbar) {\n                handler.progressbar.progressbar(\n                    'value',\n                    parseInt(event.loaded / event.total * 100, 10)\n                );\n            }\n        };\n\n        this.parseResponse = function (xhr) {\n            if (typeof xhr.responseText !== undef) {\n                return $.parseJSON(xhr.responseText);\n            } else {\n                // Instead of an XHR object, an iframe is used for legacy browsers:\n                return $.parseJSON(xhr.contents().text());\n            }\n        };\n\n        this.initDownloadRow = function (event, files, index, xhr, handler, callBack) {\n            var json, downloadRow;\n            try {\n                json = handler.response = handler.parseResponse(xhr);\n                downloadRow = handler.downloadRow = handler.buildDownloadRow(json, handler);\n                handler.addNode(\n                    (typeof handler.downloadTable === func ? handler.downloadTable(handler) : handler.downloadTable),\n                    downloadRow,\n                    callBack\n                );\n            } catch (e) {\n                if (typeof handler.onError === func) {\n                    handler.originalEvent = event;\n                    handler.onError(e, files, index, xhr, handler);\n                } else {\n                    throw e;\n                }\n            }\n        };\n\n        this.onLoad = function (event, files, index, xhr, handler) {\n            handler.removeNode(handler.uploadRow, function () {\n                handler.initDownloadRow(event, files, index, xhr, handler, function () {\n                    if (typeof handler.onComplete === func) {\n                        handler.onComplete(event, files, index, xhr, handler);\n                    }\n                });\n            });\n        };\n\n        this.dropZoneEnlarge = function () {\n            if (!isDropZoneEnlarged) {\n                if (typeof uploadHandler.dropZone.switchClass === func) {\n                    uploadHandler.dropZone.switchClass(\n                        uploadHandler.cssClassSmall,\n                        uploadHandler.cssClassLarge\n                    );\n                } else {\n                    uploadHandler.dropZone.addClass(uploadHandler.cssClassLarge);\n                    uploadHandler.dropZone.removeClass(uploadHandler.cssClassSmall);\n                }\n                isDropZoneEnlarged = true;\n            }\n        };\n\n        this.dropZoneReduce = function () {\n            if (typeof uploadHandler.dropZone.switchClass === func) {\n                uploadHandler.dropZone.switchClass(\n                    uploadHandler.cssClassLarge,\n                    uploadHandler.cssClassSmall\n                );\n            } else {\n                uploadHandler.dropZone.addClass(uploadHandler.cssClassSmall);\n                uploadHandler.dropZone.removeClass(uploadHandler.cssClassLarge);\n            }\n            isDropZoneEnlarged = false;\n        };\n\n        this.onDocumentDragEnter = function (event) {\n            uploadHandler.dropZoneEnlarge();\n        };\n\n        this.onDocumentDragOver = function (event) {\n            if (dragOverTimeout) {\n                clearTimeout(dragOverTimeout);\n            }\n            dragOverTimeout = setTimeout(function () {\n                uploadHandler.dropZoneReduce();\n            }, 200);\n        };\n\n        this.onDragEnter = this.onDragLeave = function (event) {\n            uploadHandler.dropZone.toggleClass(uploadHandler.cssClassHighlight);\n        };\n\n        this.onDrop = function (event) {\n            if (dragOverTimeout) {\n                clearTimeout(dragOverTimeout);\n            }\n            if (uploadHandler.dropEffect && typeof uploadHandler.dropZone.effect === func) {\n                uploadHandler.dropZone.effect(uploadHandler.dropEffect, function () {\n                    uploadHandler.dropZone.removeClass(uploadHandler.cssClassHighlight);\n                    uploadHandler.dropZoneReduce();\n                });\n            } else {\n                uploadHandler.dropZone.removeClass(uploadHandler.cssClassHighlight);\n                uploadHandler.dropZoneReduce();\n            }\n        };\n\n        $.extend(this, options);\n    };\n\n    methods = {\n        init : function (options) {\n            return this.each(function () {\n                $(this).fileUpload(new UploadHandler($(this), options));\n            });\n        },\n\n        option: function (option, value, namespace) {\n            if (typeof option === undef || (typeof option === 'string' && typeof value === undef)) {\n                return $(this).fileUpload('option', option, value, namespace);\n            }\n            return this.each(function () {\n                $(this).fileUpload('option', option, value, namespace);\n            });\n        },\n\n        destroy : function (namespace) {\n            return this.each(function () {\n                $(this).fileUpload('destroy', namespace);\n            });\n        }\n    };\n\n    $.fn.fileUploadUI = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.fileUploadUI');\n        }\n    };\n\n}(jQuery));\n"
  },
  {
    "path": "public/javascripts/jquery.fileupload.js",
    "content": "/*\n * jQuery File Upload Plugin 3.7.1\n *\n * Copyright 2010, Sebastian Tschan, AQUANTUM\n * Licensed under the MIT license:\n * http://creativecommons.org/licenses/MIT/\n *\n * https://blueimp.net\n * http://www.aquantum.de\n */\n\n/*jslint browser: true */\n/*global File, FileReader, FormData, unescape, jQuery */\n\n(function ($) {\n\n    var defaultNamespace = 'file_upload',\n        undef = 'undefined',\n        func = 'function',\n        num = 'number',\n        FileUpload,\n        methods,\n\n        MultiLoader = function (callBack, numberComplete) {\n            var loaded = 0;\n            this.complete = function () {\n                loaded += 1;\n                if (loaded === numberComplete) {\n                    callBack();\n                }\n            };\n        };\n\n    FileUpload = function (container) {\n        var fileUpload = this,\n            uploadForm,\n            fileInput,\n            settings = {\n                namespace: defaultNamespace,\n                uploadFormFilter: function (index) {\n                    return true;\n                },\n                fileInputFilter: function (index) {\n                    return true;\n                },\n                cssClass: defaultNamespace,\n                dragDropSupport: true,\n                dropZone: container,\n                url: function (form) {\n                    return form.attr('action');\n                },\n                method: function (form) {\n                    return form.attr('method');\n                },\n                fieldName: function (input) {\n                    return input.attr('name');\n                },\n                formData: function (form) {\n                    return form.serializeArray();\n                },\n                multipart: true,\n                multiFileRequest: false,\n                withCredentials: false,\n                forceIframeUpload: false\n            },\n            documentListeners = {},\n            dropZoneListeners = {},\n            protocolRegExp = /^http(s)?:\\/\\//,\n            optionsReference,\n\n            isXHRUploadCapable = function () {\n                return typeof XMLHttpRequest !== undef && typeof File !== undef && (\n                    !settings.multipart || typeof FormData !== undef || typeof FileReader !== undef\n                );\n            },\n\n            initEventHandlers = function () {\n                if (settings.dragDropSupport) {\n                    if (typeof settings.onDocumentDragEnter === func) {\n                        documentListeners['dragenter.' + settings.namespace] = function (e) {\n                            settings.onDocumentDragEnter(e);\n                        };\n                    }\n                    if (typeof settings.onDocumentDragLeave === func) {\n                        documentListeners['dragleave.' + settings.namespace] = function (e) {\n                            settings.onDocumentDragLeave(e);\n                        };\n                    }\n                    documentListeners['dragover.'   + settings.namespace] = fileUpload.onDocumentDragOver;\n                    documentListeners['drop.'       + settings.namespace] = fileUpload.onDocumentDrop;\n                    $(document).bind(documentListeners);\n                    if (typeof settings.onDragEnter === func) {\n                        dropZoneListeners['dragenter.' + settings.namespace] = function (e) {\n                            settings.onDragEnter(e);\n                        };\n                    }\n                    if (typeof settings.onDragLeave === func) {\n                        dropZoneListeners['dragleave.' + settings.namespace] = function (e) {\n                            settings.onDragLeave(e);\n                        };\n                    }\n                    dropZoneListeners['dragover.'   + settings.namespace] = fileUpload.onDragOver;\n                    dropZoneListeners['drop.'       + settings.namespace] = fileUpload.onDrop;\n                    settings.dropZone.bind(dropZoneListeners);\n                }\n                fileInput.bind('change.' + settings.namespace, fileUpload.onChange);\n            },\n\n            removeEventHandlers = function () {\n                $.each(documentListeners, function (key, value) {\n                    $(document).unbind(key, value);\n                });\n                $.each(dropZoneListeners, function (key, value) {\n                    settings.dropZone.unbind(key, value);\n                });\n                fileInput.unbind('change.' + settings.namespace);\n            },\n\n            initUploadEventHandlers = function (files, index, xhr, settings) {\n                if (typeof settings.onProgress === func) {\n                    xhr.upload.onprogress = function (e) {\n                        settings.onProgress(e, files, index, xhr, settings);\n                    };\n                }\n                if (typeof settings.onLoad === func) {\n                    xhr.onload = function (e) {\n                        settings.onLoad(e, files, index, xhr, settings);\n                    };\n                }\n                if (typeof settings.onAbort === func) {\n                    xhr.onabort = function (e) {\n                        settings.onAbort(e, files, index, xhr, settings);\n                    };\n                }\n                if (typeof settings.onError === func) {\n                    xhr.onerror = function (e) {\n                        settings.onError(e, files, index, xhr, settings);\n                    };\n                }\n            },\n\n            getUrl = function (settings) {\n                if (typeof settings.url === func) {\n                    return settings.url(settings.uploadForm || uploadForm);\n                }\n                return settings.url;\n            },\n\n            getMethod = function (settings) {\n                if (typeof settings.method === func) {\n                    return settings.method(settings.uploadForm || uploadForm);\n                }\n                return settings.method;\n            },\n\n            getFieldName = function (settings) {\n                if (typeof settings.fieldName === func) {\n                    return settings.fieldName(settings.fileInput || fileInput);\n                }\n                return settings.fieldName;\n            },\n\n            getFormData = function (settings) {\n                var formData;\n                if (typeof settings.formData === func) {\n                    return settings.formData(settings.uploadForm || uploadForm);\n                } else if ($.isArray(settings.formData)) {\n                    return settings.formData;\n                } else if (settings.formData) {\n                    formData = [];\n                    $.each(settings.formData, function (name, value) {\n                        formData.push({name: name, value: value});\n                    });\n                    return formData;\n                }\n                return [];\n            },\n\n            isSameDomain = function (url) {\n                if (protocolRegExp.test(url)) {\n                    var host = location.host,\n                        indexStart = location.protocol.length + 2,\n                        index = url.indexOf(host, indexStart),\n                        pathIndex = index + host.length;\n                    if ((index === indexStart || index === url.indexOf('@', indexStart) + 1) &&\n                            (url.length === pathIndex || $.inArray(url.charAt(pathIndex), ['/', '?', '#']) !== -1)) {\n                        return true;\n                    }\n                    return false;\n                }\n                return true;\n            },\n\n            nonMultipartUpload = function (file, xhr, sameDomain) {\n                if (sameDomain) {\n                    xhr.setRequestHeader('X-File-Name', unescape(encodeURIComponent(file.name)));\n                }\n                xhr.setRequestHeader('Content-Type', file.type);\n                xhr.send(file);\n            },\n\n            formDataUpload = function (files, xhr, settings) {\n                var formData = new FormData(),\n                    i;\n                $.each(getFormData(settings), function (index, field) {\n                    formData.append(field.name, field.value);\n                });\n                for (i = 0; i < files.length; i += 1) {\n                    formData.append(getFieldName(settings), files[i]);\n                }\n                xhr.send(formData);\n            },\n\n            loadFileContent = function (file, callBack) {\n                var fileReader = new FileReader();\n                fileReader.onload = function (e) {\n                    file.content = e.target.result;\n                    callBack();\n                };\n                fileReader.readAsBinaryString(file);\n            },\n\n            buildMultiPartFormData = function (boundary, files, filesFieldName, fields) {\n                var doubleDash = '--',\n                    crlf     = '\\r\\n',\n                    formData = '';\n                $.each(fields, function (index, field) {\n                    formData += doubleDash + boundary + crlf +\n                        'Content-Disposition: form-data; name=\"' +\n                        unescape(encodeURIComponent(field.name)) +\n                        '\"' + crlf + crlf +\n                        unescape(encodeURIComponent(field.value)) + crlf;\n                });\n                $.each(files, function (index, file) {\n                    formData += doubleDash + boundary + crlf +\n                        'Content-Disposition: form-data; name=\"' +\n                        unescape(encodeURIComponent(filesFieldName)) +\n                        '\"; filename=\"' + unescape(encodeURIComponent(file.name)) + '\"' + crlf +\n                        'Content-Type: ' + file.type + crlf + crlf +\n                        file.content + crlf;\n                });\n                formData += doubleDash + boundary + doubleDash + crlf;\n                return formData;\n            },\n\n            fileReaderUpload = function (files, xhr, settings) {\n                var boundary = '----MultiPartFormBoundary' + (new Date()).getTime(),\n                    loader,\n                    i;\n                xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);\n                loader = new MultiLoader(function () {\n                    xhr.sendAsBinary(buildMultiPartFormData(\n                        boundary,\n                        files,\n                        getFieldName(settings),\n                        getFormData(settings)\n                    ));\n                }, files.length);\n                for (i = 0; i < files.length; i += 1) {\n                    loadFileContent(files[i], loader.complete);\n                }\n            },\n\n            upload = function (files, index, xhr, settings) {\n                var url = getUrl(settings),\n                    sameDomain = isSameDomain(url),\n                    filesToUpload;\n                initUploadEventHandlers(files, index, xhr, settings);\n                xhr.open(getMethod(settings), url, true);\n                if (sameDomain) {\n                    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n                } else if (settings.withCredentials) {\n                    xhr.withCredentials = true;\n                }\n                if (!settings.multipart) {\n                    nonMultipartUpload(files[index], xhr, sameDomain);\n                } else {\n                    if (typeof index === num) {\n                        filesToUpload = [files[index]];\n                    } else {\n                        filesToUpload = files;\n                    }\n                    if (typeof FormData !== undef) {\n                        formDataUpload(filesToUpload, xhr, settings);\n                    } else if (typeof FileReader !== undef) {\n                        fileReaderUpload(filesToUpload, xhr, settings);\n                    } else {\n                        $.error('Browser does neither support FormData nor FileReader interface');\n                    }\n                }\n            },\n\n            handleUpload = function (event, files, input, form, index) {\n                var xhr = new XMLHttpRequest(),\n                    uploadSettings = $.extend({}, settings);\n                uploadSettings.fileInput = input;\n                uploadSettings.uploadForm = form;\n                if (typeof uploadSettings.initUpload === func) {\n                    uploadSettings.initUpload(\n                        event,\n                        files,\n                        index,\n                        xhr,\n                        uploadSettings,\n                        function () {\n                            upload(files, index, xhr, uploadSettings);\n                        }\n                    );\n                } else {\n                    upload(files, index, xhr, uploadSettings);\n                }\n            },\n\n            handleFiles = function (event, files, input, form) {\n                var i;\n                if (settings.multiFileRequest) {\n                    handleUpload(event, files, input, form);\n                } else {\n                    for (i = 0; i < files.length; i += 1) {\n                        handleUpload(event, files, input, form, i);\n                    }\n                }\n            },\n\n            legacyUploadFormDataInit = function (input, form, settings) {\n                var formData = getFormData(settings);\n                form.find(':input').not(':disabled')\n                    .attr('disabled', true)\n                    .addClass(settings.namespace + '_disabled');\n                $.each(formData, function (index, field) {\n                    $('<input type=\"hidden\"/>')\n                        .attr('name', field.name)\n                        .val(field.value)\n                        .addClass(settings.namespace + '_form_data')\n                        .appendTo(form);\n                });\n                input\n                    .attr('name', getFieldName(settings))\n                    .appendTo(form);\n            },\n\n            legacyUploadFormDataReset = function (input, form, settings) {\n                input.detach();\n                form.find('.' + settings.namespace + '_disabled')\n                    .removeAttr('disabled')\n                    .removeClass(settings.namespace + '_disabled');\n                form.find('.' + settings.namespace + '_form_data').remove();\n            },\n\n            legacyUpload = function (input, form, iframe, settings) {\n                var originalAction = form.attr('action'),\n                    originalMethod = form.attr('method'),\n                    originalTarget = form.attr('target');\n                iframe\n                    .unbind('abort')\n                    .bind('abort', function (e) {\n                        iframe.readyState = 0;\n                        // javascript:false as iframe src prevents warning popups on HTTPS in IE6\n                        // concat is used here to prevent the \"Script URL\" JSLint error:\n                        iframe.unbind('load').attr('src', 'javascript'.concat(':false;'));\n                        if (typeof settings.onAbort === func) {\n                            settings.onAbort(e, [{name: input.val(), type: null, size: null}], 0, iframe, settings);\n                        }\n                    })\n                    .unbind('load')\n                    .bind('load', function (e) {\n                        iframe.readyState = 4;\n                        if (typeof settings.onLoad === func) {\n                            settings.onLoad(e, [{name: input.val(), type: null, size: null}], 0, iframe, settings);\n                        }\n                        // Fix for IE endless progress bar activity bug (happens on form submits to iframe targets):\n                        $('<iframe src=\"javascript:false;\" style=\"display:none\"></iframe>').appendTo(form).remove();\n                    });\n                form\n                    .attr('action', getUrl(settings))\n                    .attr('method', getMethod(settings))\n                    .attr('target', iframe.attr('name'));\n                legacyUploadFormDataInit(input, form, settings);\n                iframe.readyState = 2;\n                form.get(0).submit();\n                legacyUploadFormDataReset(input, form, settings);\n                form\n                    .attr('action', originalAction)\n                    .attr('method', originalMethod)\n                    .attr('target', originalTarget);\n            },\n\n            handleLegacyUpload = function (event, input, form) {\n                // javascript:false as iframe src prevents warning popups on HTTPS in IE6:\n                var iframe = $('<iframe src=\"javascript:false;\" style=\"display:none\" name=\"iframe_' +\n                    settings.namespace + '_' + (new Date()).getTime() + '\"></iframe>'),\n                    uploadSettings = $.extend({}, settings);\n                uploadSettings.fileInput = input;\n                uploadSettings.uploadForm = form;\n                iframe.readyState = 0;\n                iframe.abort = function () {\n                    iframe.trigger('abort');\n                };\n                iframe.bind('load', function () {\n                    iframe.unbind('load');\n                    if (typeof uploadSettings.initUpload === func) {\n                        uploadSettings.initUpload(\n                            event,\n                            [{name: input.val(), type: null, size: null}],\n                            0,\n                            iframe,\n                            uploadSettings,\n                            function () {\n                                legacyUpload(input, form, iframe, uploadSettings);\n                            }\n                        );\n                    } else {\n                        legacyUpload(input, form, iframe, uploadSettings);\n                    }\n                }).appendTo(form);\n            },\n\n            initUploadForm = function () {\n                uploadForm = (container.is('form') ? container : container.find('form'))\n                    .filter(settings.uploadFormFilter);\n            },\n\n            initFileInput = function () {\n                fileInput = uploadForm.find('input:file')\n                    .filter(settings.fileInputFilter);\n            },\n\n            replaceFileInput = function (input) {\n                var inputClone = input.clone(true);\n                $('<form/>').append(inputClone).get(0).reset();\n                input.after(inputClone).detach();\n                initFileInput();\n            };\n\n        this.onDocumentDragOver = function (e) {\n            if (typeof settings.onDocumentDragOver === func &&\n                    settings.onDocumentDragOver(e) === false) {\n                return false;\n            }\n            e.preventDefault();\n        };\n\n        this.onDocumentDrop = function (e) {\n            if (typeof settings.onDocumentDrop === func &&\n                    settings.onDocumentDrop(e) === false) {\n                return false;\n            }\n            e.preventDefault();\n        };\n\n        this.onDragOver = function (e) {\n            if (typeof settings.onDragOver === func &&\n                    settings.onDragOver(e) === false) {\n                return false;\n            }\n            var dataTransfer = e.originalEvent.dataTransfer;\n            if (dataTransfer) {\n                dataTransfer.dropEffect = dataTransfer.effectAllowed = 'copy';\n            }\n            e.preventDefault();\n        };\n\n        this.onDrop = function (e) {\n            if (typeof settings.onDrop === func &&\n                    settings.onDrop(e) === false) {\n                return false;\n            }\n            var dataTransfer = e.originalEvent.dataTransfer;\n            if (dataTransfer && dataTransfer.files && isXHRUploadCapable()) {\n                handleFiles(e, dataTransfer.files);\n            }\n            e.preventDefault();\n        };\n\n        this.onChange = function (e) {\n            if (typeof settings.onChange === func &&\n                    settings.onChange(e) === false) {\n                return false;\n            }\n            var input = $(e.target),\n                form = $(e.target.form);\n            if (form.length === 1) {\n                input.data(defaultNamespace + '_form', form);\n                replaceFileInput(input);\n            } else {\n                form = input.data(defaultNamespace + '_form');\n            }\n            if (!settings.forceIframeUpload && e.target.files && isXHRUploadCapable()) {\n                handleFiles(e, e.target.files, input, form);\n            } else {\n                handleLegacyUpload(e, input, form);\n            }\n        };\n\n        this.init = function (options) {\n            if (options) {\n                $.extend(settings, options);\n                optionsReference = options;\n            }\n            initUploadForm();\n            initFileInput();\n            if (container.data(settings.namespace)) {\n                $.error('FileUpload with namespace \"' + settings.namespace + '\" already assigned to this element');\n                return;\n            }\n            container\n                .data(settings.namespace, fileUpload)\n                .addClass(settings.cssClass);\n            settings.dropZone.not(container).addClass(settings.cssClass);\n            initEventHandlers();\n        };\n\n        this.options = function (options) {\n            var oldCssClass,\n                oldDropZone,\n                uploadFormFilterUpdate,\n                fileInputFilterUpdate;\n            if (typeof options === undef) {\n                return $.extend({}, settings);\n            }\n            if (optionsReference) {\n                $.extend(optionsReference, options);\n            }\n            removeEventHandlers();\n            $.each(options, function (name, value) {\n                switch (name) {\n                case 'namespace':\n                    $.error('The FileUpload namespace cannot be updated.');\n                    return;\n                case 'uploadFormFilter':\n                    uploadFormFilterUpdate = true;\n                    fileInputFilterUpdate = true;\n                    break;\n                case 'fileInputFilter':\n                    fileInputFilterUpdate = true;\n                    break;\n                case 'cssClass':\n                    oldCssClass = settings.cssClass;\n                    break;\n                case 'dropZone':\n                    oldDropZone = settings.dropZone;\n                    break;\n                }\n                settings[name] = value;\n            });\n            if (uploadFormFilterUpdate) {\n                initUploadForm();\n            }\n            if (fileInputFilterUpdate) {\n                initFileInput();\n            }\n            if (typeof oldCssClass !== undef) {\n                container\n                    .removeClass(oldCssClass)\n                    .addClass(settings.cssClass);\n                (oldDropZone ? oldDropZone : settings.dropZone).not(container)\n                    .removeClass(oldCssClass);\n                settings.dropZone.not(container).addClass(settings.cssClass);\n            } else if (oldDropZone) {\n                oldDropZone.not(container).removeClass(settings.cssClass);\n                settings.dropZone.not(container).addClass(settings.cssClass);\n            }\n            initEventHandlers();\n        };\n\n        this.option = function (name, value) {\n            var options;\n            if (typeof value === undef) {\n                return settings[name];\n            }\n            options = {};\n            options[name] = value;\n            fileUpload.options(options);\n        };\n\n        this.destroy = function () {\n            removeEventHandlers();\n            container\n                .removeData(settings.namespace)\n                .removeClass(settings.cssClass);\n            settings.dropZone.not(container).removeClass(settings.cssClass);\n        };\n    };\n\n    methods = {\n        init : function (options) {\n            return this.each(function () {\n                (new FileUpload($(this))).init(options);\n            });\n        },\n\n        option: function (option, value, namespace) {\n            namespace = namespace ? namespace : defaultNamespace;\n            var fileUpload = $(this).data(namespace);\n            if (fileUpload) {\n                if (typeof option === 'string') {\n                    return fileUpload.option(option, value);\n                }\n                return fileUpload.options(option);\n            } else {\n                $.error('No FileUpload with namespace \"' + namespace + '\" assigned to this element');\n            }\n        },\n\n        destroy : function (namespace) {\n            namespace = namespace ? namespace : defaultNamespace;\n            return this.each(function () {\n                var fileUpload = $(this).data(namespace);\n                if (fileUpload) {\n                    fileUpload.destroy();\n                } else {\n                    $.error('No FileUpload with namespace \"' + namespace + '\" assigned to this element');\n                }\n            });\n\n        }\n    };\n\n    $.fn.fileUpload = function (method) {\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        } else {\n            $.error('Method ' + method + ' does not exist on jQuery.fileUpload');\n        }\n    };\n\n}(jQuery));\n"
  },
  {
    "path": "public/javascripts/jquery.jgrowl_minimized.js",
    "content": "(function($){$.jGrowl=function(m,o){if($('#jGrowl').size()==0)\n$('<div id=\"jGrowl\"></div>').addClass($.jGrowl.defaults.position).appendTo('body');$('#jGrowl').jGrowl(m,o);};$.fn.jGrowl=function(m,o){if($.isFunction(this.each)){var args=arguments;return this.each(function(){var self=this;if($(this).data('jGrowl.instance')==undefined){$(this).data('jGrowl.instance',$.extend(new $.fn.jGrowl(),{notifications:[],element:null,interval:null}));$(this).data('jGrowl.instance').startup(this);}\nif($.isFunction($(this).data('jGrowl.instance')[m])){$(this).data('jGrowl.instance')[m].apply($(this).data('jGrowl.instance'),$.makeArray(args).slice(1));}else{$(this).data('jGrowl.instance').create(m,o);}});};};$.extend($.fn.jGrowl.prototype,{defaults:{pool:0,header:'',group:'',sticky:false,position:'top-right',glue:'after',theme:'default',corners:'10px',check:250,life:3000,speed:'normal',easing:'swing',closer:true,closeTemplate:'&times;',closerTemplate:'<div>[ close all ]</div>',log:function(e,m,o){},beforeOpen:function(e,m,o){},open:function(e,m,o){},beforeClose:function(e,m,o){},close:function(e,m,o){},animateOpen:{opacity:'show'},animateClose:{opacity:'hide'}},notifications:[],element:null,interval:null,create:function(message,o){var o=$.extend({},this.defaults,o);this.notifications.push({message:message,options:o});o.log.apply(this.element,[this.element,message,o]);},render:function(notification){var self=this;var message=notification.message;var o=notification.options;var notification=$('<div class=\"jGrowl-notification ui-state-highlight ui-corner-all'+\n((o.group!=undefined&&o.group!='')?' '+o.group:'')+'\">'+'<div class=\"close\">'+o.closeTemplate+'</div>'+'<div class=\"header\">'+o.header+'</div>'+'<div class=\"message\">'+message+'</div></div>').data(\"jGrowl\",o).addClass(o.theme).children('div.close').bind(\"click.jGrowl\",function(){$(this).parent().trigger('jGrowl.close');}).parent();$(notification).bind(\"mouseover.jGrowl\",function(){$('div.jGrowl-notification',self.element).data(\"jGrowl.pause\",true);}).bind(\"mouseout.jGrowl\",function(){$('div.jGrowl-notification',self.element).data(\"jGrowl.pause\",false);}).bind('jGrowl.beforeOpen',function(){if(o.beforeOpen.apply(notification,[notification,message,o,self.element])!=false){$(this).trigger('jGrowl.open');}}).bind('jGrowl.open',function(){if(o.open.apply(notification,[notification,message,o,self.element])!=false){if(o.glue=='after'){$('div.jGrowl-notification:last',self.element).after(notification);}else{$('div.jGrowl-notification:first',self.element).before(notification);}\n$(this).animate(o.animateOpen,o.speed,o.easing,function(){if($.browser.msie&&(parseInt($(this).css('opacity'),10)===1||parseInt($(this).css('opacity'),10)===0))\nthis.style.removeAttribute('filter');$(this).data(\"jGrowl\").created=new Date();});}}).bind('jGrowl.beforeClose',function(){if(o.beforeClose.apply(notification,[notification,message,o,self.element])!=false)\n$(this).trigger('jGrowl.close');}).bind('jGrowl.close',function(){$(this).data('jGrowl.pause',true);$(this).animate(o.animateClose,o.speed,o.easing,function(){$(this).remove();var close=o.close.apply(notification,[notification,message,o,self.element]);if($.isFunction(close))\nclose.apply(notification,[notification,message,o,self.element]);});}).trigger('jGrowl.beforeOpen');if($.fn.corner!=undefined)$(notification).corner(o.corners);if($('div.jGrowl-notification:parent',self.element).size()>1&&$('div.jGrowl-closer',self.element).size()==0&&this.defaults.closer!=false){$(this.defaults.closerTemplate).addClass('jGrowl-closer ui-state-highlight ui-corner-all').addClass(this.defaults.theme).appendTo(self.element).animate(this.defaults.animateOpen,this.defaults.speed,this.defaults.easing).bind(\"click.jGrowl\",function(){$(this).siblings().children('div.close').trigger(\"click.jGrowl\");if($.isFunction(self.defaults.closer)){self.defaults.closer.apply($(this).parent()[0],[$(this).parent()[0]]);}});};},update:function(){$(this.element).find('div.jGrowl-notification:parent').each(function(){if($(this).data(\"jGrowl\")!=undefined&&$(this).data(\"jGrowl\").created!=undefined&&($(this).data(\"jGrowl\").created.getTime()+$(this).data(\"jGrowl\").life)<(new Date()).getTime()&&$(this).data(\"jGrowl\").sticky!=true&&($(this).data(\"jGrowl.pause\")==undefined||$(this).data(\"jGrowl.pause\")!=true)){$(this).trigger('jGrowl.beforeClose');}});if(this.notifications.length>0&&(this.defaults.pool==0||$(this.element).find('div.jGrowl-notification:parent').size()<this.defaults.pool))\nthis.render(this.notifications.shift());if($(this.element).find('div.jGrowl-notification:parent').size()<2){$(this.element).find('div.jGrowl-closer').animate(this.defaults.animateClose,this.defaults.speed,this.defaults.easing,function(){$(this).remove();});}},startup:function(e){this.element=$(e).addClass('jGrowl').append('<div class=\"jGrowl-notification\"></div>');this.interval=setInterval(function(){$(e).data('jGrowl.instance').update();},this.defaults.check);if($.browser.msie&&parseInt($.browser.version)<7&&!window[\"XMLHttpRequest\"]){$(this.element).addClass('ie6');}},shutdown:function(){$(this.element).removeClass('jGrowl').find('div.jGrowl-notification').remove();clearInterval(this.interval);},close:function(){$(this.element).find('div.jGrowl-notification').each(function(){$(this).trigger('jGrowl.beforeClose');});}});$.jGrowl.defaults=$.fn.jGrowl.prototype.defaults;})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.js",
    "content": "/*!\n * jQuery JavaScript Library v1.4.4\n * http://jquery.com/\n *\n * Copyright 2010, John Resig\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n * Copyright 2010, The Dojo Foundation\n * Released under the MIT, BSD, and GPL Licenses.\n *\n * Date: Thu Nov 11 19:04:53 2010 -0500\n */\n(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute(\"data-\"+b);if(typeof d===\"string\"){try{d=d===\"true\"?true:d===\"false\"?false:d===\"null\"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?\"events\":\"__events__\");if(typeof h===\"function\")h=\nh.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type===\"click\")){if(a.namespace)A=RegExp(\"(^|\\\\.)\"+a.namespace.split(\".\").join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,\"\")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType===\"mouseenter\"||\nh.preType===\"mouseleave\"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!==\"*\"?a+\".\":\"\")+b.replace(La,\n\"`\").replace(Ma,\"&\")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b===\"string\"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,\ne);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:\"script\"}):c.globalEval(b.text||b.textContent||b.innerHTML||\"\");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b===\"width\"?a.offsetWidth:a.offsetHeight;if(d===\"border\")return e;c.each(b===\"width\"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,\"padding\"+this))||0);if(d===\"margin\")e+=parseFloat(c.css(a,\n\"margin\"+this))||0;else e-=parseFloat(c.css(a,\"border\"+this+\"Width\"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+\"[\"+(typeof h===\"object\"||c.isArray(h)?f:\"\")+\"]\",h,d,e)});else if(!d&&b!=null&&typeof b===\"object\")c.isEmptyObject(b)?e(a,\"\"):c.each(b,function(f,h){da(a+\"[\"+f+\"]\",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c(\"<\"+\na+\">\").appendTo(\"body\"),d=b.css(\"display\");b.remove();if(d===\"none\"||d===\"\")d=\"block\";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll(\"left\")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\\w\\W]+>)[^>]*$|#([\\w\\-]+)$)/,l=/\\S/,k=/^\\s+/,o=/\\s+$/,x=/\\W/,r=/\\d/,A=/^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,\nC=/^[\\],:{}\\s]*$/,J=/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g,I=/(?:^|:|,)(?:\\s*\\[)+/g,L=/(webkit)[ \\/]([\\w.]+)/,g=/(opera)(?:.*version)?[ \\/]([\\w.]+)/,i=/(msie) ([\\w.]+)/,n=/(mozilla)(?:.*? rv:([\\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j,\ns){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j===\"body\"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector=\"body\";this.length=1;return this}if(typeof j===\"string\")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,\nj)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:\"\",jquery:\"1.4.4\",length:0,size:function(){return this.length},\ntoArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s===\"find\")z.selector=this.selector+(this.selector?\" \":\"\")+v;else if(s)z.selector=this.selector+\".\"+s+\"(\"+v+\")\";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j===\n-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),\"slice\",N.call(arguments).join(\",\"))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false;\nif(typeof G===\"boolean\"){ga=G;G=arguments[1]||{};K=2}if(typeof G!==\"object\"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--;\nif(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger(\"ready\").unbind(\"ready\")}}},bindReady:function(){if(!p){p=true;if(t.readyState===\"complete\")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener(\"DOMContentLoaded\",u,false);E.addEventListener(\"load\",b.ready,false)}else if(t.attachEvent){t.attachEvent(\"onreadystatechange\",u);E.attachEvent(\"onload\",\nb.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)===\"function\"},isArray:Array.isArray||function(j){return b.type(j)===\"array\"},isWindow:function(j){return j&&typeof j===\"object\"&&\"setInterval\"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||\"object\"},isPlainObject:function(j){if(!j||b.type(j)!==\"object\"||j.nodeType||b.isWindow(j))return false;if(j.constructor&&\n!F.call(j,\"constructor\")&&!F.call(j.constructor.prototype,\"isPrototypeOf\"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!==\"string\"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,\"@\").replace(w,\"]\").replace(I,\"\")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function(\"return \"+j))();else b.error(\"Invalid JSON: \"+j)},noop:function(){},globalEval:function(j){if(j&&\nl.test(j)){var s=t.getElementsByTagName(\"head\")[0]||t.documentElement,v=t.createElement(\"script\");v.type=\"text/javascript\";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z],\nz,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?\"\":O.call(j)}:function(j){return j==null?\"\":j.toString().replace(k,\"\").replace(o,\"\")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z===\"string\"||z===\"function\"||z===\"regexp\"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j,\ns){var v=j.length,z=0;if(typeof s.length===\"number\")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s===\"string\"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v=\ns;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s===\"object\"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf(\"compatible\")<0&&n.exec(j)||\n[];return{browser:j[1]||\"\",version:j[2]||\"0\"}},browser:{}});b.each(\"Boolean Number String Function Array Date RegExp Object\".split(\" \"),function(j,s){R[\"[object \"+s+\"]\"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\\s/.test(\"\\u00a0\")){k=/^[\\s\\xA0]+/;o=/[\\s\\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener(\"DOMContentLoaded\",u,\nfalse);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState===\"complete\"){t.detachEvent(\"onreadystatechange\",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement(\"script\"),d=t.createElement(\"div\"),e=\"script\"+c.now();d.style.display=\"none\";d.innerHTML=\"   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>\";var f=d.getElementsByTagName(\"*\"),h=d.getElementsByTagName(\"a\")[0],l=t.createElement(\"select\"),\nk=l.appendChild(t.createElement(\"option\"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName(\"tbody\").length,htmlSerialize:!!d.getElementsByTagName(\"link\").length,style:/red/.test(h.getAttribute(\"style\")),hrefNormalized:h.getAttribute(\"href\")===\"/a\",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName(\"input\")[0].value===\"on\",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false,\nscriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type=\"text/javascript\";try{b.appendChild(t.createTextNode(\"window.\"+e+\"=1;\"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent(\"onclick\",function r(){c.support.noCloneEvent=\nfalse;d.detachEvent(\"onclick\",r)});d.cloneNode(true).fireEvent(\"onclick\")}d=t.createElement(\"div\");d.innerHTML=\"<input type='radio' name='radiotest' checked='checked'/>\";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement(\"div\");r.style.width=r.style.paddingLeft=\"1px\";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if(\"zoom\"in r.style){r.style.display=\"inline\";r.style.zoom=\n1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display=\"\";r.innerHTML=\"<div style='width:4px;'></div>\";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML=\"<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>\";var A=r.getElementsByTagName(\"td\");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display=\"\";A[1].style.display=\"none\";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML=\"\";t.body.removeChild(r).style.display=\n\"none\"});a=function(r){var A=t.createElement(\"div\");r=\"on\"+r;var C=r in A;if(!C){A.setAttribute(r,\"return;\");C=typeof A[r]===\"function\"}return C};c.support.submitBubbles=a(\"submit\");c.support.changeBubbles=a(\"change\");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\\{.*\\}|\\[.*\\])$/;c.extend({cache:{},uuid:0,expando:\"jQuery\"+c.now(),noData:{embed:true,object:\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h=\nc.cache;if(!(e&&!f&&typeof b===\"string\"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b===\"object\")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b===\"string\"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);\nelse if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute(\"classid\")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a===\"undefined\"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf(\"data-\")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a===\"object\")return this.each(function(){c.data(this,\na)});var k=a.split(\".\");k[1]=k[1]?\".\"+k[1]:\"\";if(b===B){d=this.triggerHandler(\"getData\"+k[1]+\"!\",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler(\"setData\"+k[1]+\"!\",x);c.data(this,a,b);o.triggerHandler(\"changeData\"+k[1]+\"!\",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||\"fx\")+\"queue\";var e=\nc.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||\"fx\";var d=c.queue(a,b),e=d.shift();if(e===\"inprogress\")e=d.shift();if(e){b===\"fx\"&&d.unshift(\"inprogress\");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!==\"string\"){b=a;a=\"fx\"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a===\"fx\"&&d[0]!==\"inprogress\"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,\na)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||\"fx\";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||\"fx\",[])}});var sa=/[\\n\\t]/g,ha=/\\s+/,Sa=/\\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={\"for\":\"htmlFor\",\"class\":\"className\",readonly:\"readOnly\",maxlength:\"maxLength\",cellspacing:\"cellSpacing\",rowspan:\"rowSpan\",\ncolspan:\"colSpan\",tabindex:\"tabIndex\",usemap:\"useMap\",frameborder:\"frameBorder\"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,\"\");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr(\"class\")))});if(a&&typeof a===\"string\")for(var b=(a||\"\").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===\n1)if(f.className){for(var h=\" \"+f.className+\" \",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(\" \"+b[k]+\" \")<0)l+=\" \"+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr(\"class\")))});if(a&&typeof a===\"string\"||a===B)for(var b=(a||\"\").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(\" \"+f.className+\" \").replace(sa,\" \"),\nl=0,k=b.length;l<k;l++)h=h.replace(\" \"+b[l]+\" \",\" \");f.className=c.trim(h)}else f.className=\"\"}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b===\"boolean\";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr(\"class\"),b),b)});return this.each(function(){if(d===\"string\")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?\"addClass\":\"removeClass\"](f)}else if(d===\"undefined\"||d===\"boolean\"){this.className&&c.data(this,\n\"__className__\",this.className);this.className=this.className||a===false?\"\":c.data(this,\"__className__\")||\"\"}})},hasClass:function(a){a=\" \"+a+\" \";for(var b=0,d=this.length;b<d;b++)if((\" \"+this[b].className+\" \").replace(sa,\" \").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,\"option\")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,\"select\")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type===\"select-one\";\nif(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute(\"disabled\")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,\"optgroup\"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute(\"value\")===null?\"on\":b.value;return(b.value||\"\").replace(Sa,\"\")}return B}var k=c.isFunction(a);return this.each(function(o){var x=c(this),r=a;if(this.nodeType===1){if(k)r=\na.call(this,o,x.val());if(r==null)r=\"\";else if(typeof r===\"number\")r+=\"\";else if(c.isArray(r))r=c.map(r,function(C){return C==null?\"\":C+\"\"});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,\"select\")){var A=c.makeArray(r);c(\"option\",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},\nattr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b===\"type\"&&Ua.test(a.nodeName)&&a.parentNode&&c.error(\"type property can't be changed\");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,\"form\")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b===\"tabIndex\")return(b=a.getAttributeNode(\"tabIndex\"))&&\nb.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b===\"style\"){if(f)a.style.cssText=\"\"+d;return a.style.cssText}f&&a.setAttribute(b,\"\"+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\\./g,Ma=/ /g,Xa=/[^\\w\\s.|`]/g,Ya=function(a){return a.replace(Xa,\"\\\\$&\")},ua={focusin:0,focusout:0};\nc.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?\"events\":\"__events__\",k=h[l],o=h.handle;if(typeof k===\"function\"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!==\"undefined\"&&!c.event.triggered?c.event.handle.apply(o.elem,\narguments):B};o.elem=a;b=b.split(\" \");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(\".\")>-1){r=l.split(\".\");l=r.shift();h.namespace=r.slice(0).sort().join(\".\")}else{r=[];h.namespace=\"\"}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent(\"on\"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid=\nd.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?\"events\":\"__events__\",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I===\"function\"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b===\"string\"&&b.charAt(0)===\".\"){b=b||\"\";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(\" \");f=b[l++];){r=f;k=f.indexOf(\".\")<0;o=[];if(!k){o=f.split(\".\");f=o.shift();x=RegExp(\"(^|\\\\.)\"+\nc.map(o.slice(0).sort(),Ya).join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b=\nw.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w===\"function\")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a===\"object\"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf(\"!\")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===\n8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,\"handle\"):(c.data(d,\"__events__\")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d[\"on\"+f]&&d[\"on\"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,\"\"),o=c.nodeName(e,\"a\")&&k===\n\"click\",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e[\"on\"+k])e[\"on\"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e[\"on\"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(\".\")<0&&!a.exclusive;if(!b){e=a.type.split(\".\");a.type=e.shift();d=e.slice(0).sort();e=RegExp(\"(^|\\\\.)\"+\nd.join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\")}a.namespace=a.namespace||d.join(\".\");f=c.data(this,this.nodeType?\"events\":\"__events__\");if(typeof f===\"function\")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:\"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which\".split(\" \"),\nfix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||\nd&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,\nY(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent(\"on\"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=\nc.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};\nvar va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!==\n\"form\"){c.event.add(this,\"click.specialSubmit\",function(a){var b=a.target,d=b.type;if((d===\"submit\"||d===\"image\")&&c(b).closest(\"form\").length){a.liveFired=B;return la(\"submit\",this,arguments)}});c.event.add(this,\"keypress.specialSubmit\",function(a){var b=a.target,d=b.type;if((d===\"text\"||d===\"password\")&&c(b).closest(\"form\").length&&a.keyCode===13){a.liveFired=B;return la(\"submit\",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,\".specialSubmit\")}};if(!c.support.changeBubbles){var V,\nxa=function(a){var b=a.type,d=a.value;if(b===\"radio\"||b===\"checkbox\")d=a.checked;else if(b===\"select-multiple\")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join(\"-\"):\"\";else if(a.nodeName.toLowerCase()===\"select\")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,\"_change_data\");f=xa(d);if(a.type!==\"focusout\"||d.type!==\"radio\")c.data(d,\"_change_data\",f);if(!(e===B||f===e))if(e!=null||f){a.type=\"change\";a.liveFired=\nB;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d===\"radio\"||d===\"checkbox\"||b.nodeName.toLowerCase()===\"select\")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!==\"textarea\"||a.keyCode===32&&(d===\"checkbox\"||d===\"radio\")||d===\"select-multiple\")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,\"_change_data\",xa(a))}},setup:function(){if(this.type===\n\"file\")return false;for(var a in V)c.event.add(this,a+\".specialChange\",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,\".specialChange\");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:\"focusin\",blur:\"focusout\"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]===\n0&&t.removeEventListener(a,d,true)}}});c.each([\"bind\",\"one\"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d===\"object\"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b===\"one\"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d===\"unload\"&&b!==\"one\")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a===\"object\"&&!a.preventDefault)for(var d in a)this.unbind(d,\na[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind(\"live\"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=\n1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,\"lastToggle\"+a.guid)||0)%d;c.data(this,\"lastToggle\"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:\"focusin\",blur:\"focusout\",mouseenter:\"mouseover\",mouseleave:\"mouseout\"};c.each([\"live\",\"die\"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d===\n\"object\"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=e;e=B}for(d=(d||\"\").split(\" \");(l=d[k++])!=null;){o=X.exec(l);x=\"\";if(o){x=o[0];l=l.replace(X,\"\")}if(l===\"hover\")d.push(\"mouseenter\"+x,\"mouseleave\"+x);else{o=l;if(l===\"focus\"||l===\"blur\"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b===\"live\"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],\"live.\"+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind(\"live.\"+Y(l,r),f)}}return this}});\nc.each(\"blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error\".split(\" \"),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind(\"unload\",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});\n(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!==\"string\"){if(y===i){F=true;break}}else if(k.filter(i,\n[y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^\\[\\]]*\\]|['\"][^'\"]*['\"]|[^\\[\\]'\"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!==\"string\")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec(\"\");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3];\nbreak}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]===\"~\"||D[0]===\"+\")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr,\nq.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M=\"\";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)===\"[object Array]\")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h=\nl;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!==\"\\\\\"){u[1]=(u[1]||\"\").replace(/\\\\/g,\"\");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],\"\");break}}}}m||(m=i.getElementsByTagName(\"*\"));\nreturn{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!==\"\\\\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!==\nB){n||(F=y);g=g.replace(o.match[N],\"\");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw\"Syntax error, unrecognized expression: \"+g;};var o=k.selectors={order:[\"ID\",\"NAME\",\"TAG\"],match:{ID:/#((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,CLASS:/\\.((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,NAME:/\\[name=['\"]*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)['\"]*\\]/,ATTR:/\\[\\s*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)\\s*(?:(\\S?=)\\s*(['\"]*)(.*?)\\3|)\\s*\\]/,TAG:/^((?:[\\w\\u00c0-\\uFFFF\\*\\-]|\\\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\\((even|odd|[\\dn+\\-]*)\\))?/,\nPOS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^\\-]|$)/,PSEUDO:/:((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)(?:\\((['\"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/},leftMatch:{},attrMap:{\"class\":\"className\",\"for\":\"htmlFor\"},attrHandle:{href:function(g){return g.getAttribute(\"href\")}},relative:{\"+\":function(g,i){var n=typeof i===\"string\",m=n&&!/\\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()===\ni?q||false:q===i}n&&k.filter(i,g,true)},\">\":function(g,i){var n,m=typeof i===\"string\",p=0,q=g.length;if(m&&!/\\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},\"\":function(g,i,n){var m,p=e++,q=b;if(typeof i===\"string\"&&!/\\W/.test(i)){m=i=i.toLowerCase();q=a}q(\"parentNode\",i,p,g,m,n)},\"~\":function(g,i,n){var m,p=e++,q=b;if(typeof i===\"string\"&&!/\\W/.test(i)){m=\ni=i.toLowerCase();q=a}q(\"previousSibling\",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!==\"undefined\"&&!n)return(g=i.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!==\"undefined\"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute(\"name\")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=\" \"+g[1].replace(/\\\\/g,\n\"\")+\" \";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(\" \"+u.className+\" \").replace(/[\\t\\n]/g,\" \").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\\\/g,\"\")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]===\"nth\"){var i=/(-?)(\\d*)n((?:\\+|-)?\\d*)/.exec(g[2]===\"even\"&&\"2n\"||g[2]===\"odd\"&&\"2n+1\"||!/\\D/.test(g[2])&&\"0n+\"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n,\nm,p,q){i=g[1].replace(/\\\\/g,\"\");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]===\"~=\")g[4]=\" \"+g[4]+\" \";return g},PSEUDO:function(g,i,n,m,p){if(g[1]===\"not\")if((d.exec(g[3])||\"\").length>1||/^\\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!==\"hidden\"},disabled:function(g){return g.disabled===\ntrue},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\\d/i.test(g.nodeName)},text:function(g){return\"text\"===g.type},radio:function(g){return\"radio\"===g.type},checkbox:function(g){return\"checkbox\"===g.type},file:function(g){return\"file\"===g.type},password:function(g){return\"password\"===g.type},submit:function(g){return\"submit\"===\ng.type},image:function(g){return\"image\"===g.type},reset:function(g){return\"reset\"===g.type},button:function(g){return\"button\"===g.type||g.nodeName.toLowerCase()===\"button\"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]-\n0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p===\"contains\")return(g.textContent||g.innerText||k.getText([g])||\"\").indexOf(i[3])>=0;else if(p===\"not\"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error(\"Syntax error, unrecognized expression: \"+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case \"only\":case \"first\":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n===\n\"first\")return true;m=g;case \"last\":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case \"nth\":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute(\"id\")===i},TAG:function(g,i){return i===\"*\"&&g.nodeType===1||g.nodeName.toLowerCase()===\ni},CLASS:function(g,i){return(\" \"+(g.className||g.getAttribute(\"class\"))+\" \").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+\"\",p=i[2],q=i[4];return n==null?p===\"!=\":p===\"=\"?m===q:p===\"*=\"?m.indexOf(q)>=0:p===\"~=\"?(\" \"+m+\" \").indexOf(q)>=0:!q?m&&n!==false:p===\"!=\"?m!==q:p===\"^=\"?m.indexOf(q)===0:p===\"$=\"?m.substr(m.length-q.length)===q:p===\"|=\"?m===q||m.substr(0,q.length+1)===q+\"-\":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]];\nif(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return\"\\\\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\\[]*\\])(?![^\\(]*\\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\\r|\\n)*?)/.source+o.match[A].source.replace(/\\\\(\\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)===\"[object Array]\")Array.prototype.push.apply(m,\ng);else if(typeof g.length===\"number\")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1;\nfor(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i=\"\",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement(\"div\"),\ni=\"script\"+(new Date).getTime(),n=t.documentElement;g.innerHTML=\"<a name='\"+i+\"'/>\";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!==\"undefined\"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!==\"undefined\"&&p.getAttributeNode(\"id\").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!==\"undefined\"&&m.getAttributeNode(\"id\");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g);\nn=g=null})();(function(){var g=t.createElement(\"div\");g.appendChild(t.createComment(\"\"));if(g.getElementsByTagName(\"*\").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]===\"*\"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML=\"<a href='#'></a>\";if(g.firstChild&&typeof g.firstChild.getAttribute!==\"undefined\"&&g.firstChild.getAttribute(\"href\")!==\"#\")o.attrHandle.href=function(i){return i.getAttribute(\"href\",2)};g=null})();t.querySelectorAll&&\nfunction(){var g=k,i=t.createElement(\"div\");i.innerHTML=\"<p class='TEST'></p>\";if(!(i.querySelectorAll&&i.querySelectorAll(\".TEST\").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g,\"='$1']\");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!==\"object\"){var F=p.getAttribute(\"id\"),M=F||\"__sizzle__\";F||p.setAttribute(\"id\",M);try{return C(p.querySelectorAll(\"#\"+M+\" \"+m),q)}catch(N){}finally{F||\np.removeAttribute(\"id\")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,\"[test!='']:sizzle\")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g,\"='$1']\");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g=\nt.createElement(\"div\");g.innerHTML=\"<div class='test e'></div><div class='test'></div>\";if(!(!g.getElementsByClassName||g.getElementsByClassName(\"e\").length===0)){g.lastChild.className=\"e\";if(g.getElementsByClassName(\"e\").length!==1){o.order.splice(1,0,\"CLASS\");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!==\"undefined\"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition?\nfunction(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!==\"HTML\":false};var L=function(g,i){for(var n,m=[],p=\"\",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,\"\")}g=o.relative[g]?g+\"*\":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[\":\"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML;\nc.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\\[\\.,]*$/,bb=Array.prototype.slice,cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack(\"\",\"find\",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},\nnot:function(a){return this.pushStack(ma(this,a,false),\"not\",a)},filter:function(a){return this.pushStack(ma(this,a,true),\"filter\",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h=\nh.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,\"closest\",a)},index:function(a){if(!a||typeof a===\"string\")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a===\"string\"?c(a,b||this.context):\nc.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,\"parentNode\")},parentsUntil:function(a,b,d){return c.dir(a,\"parentNode\",d)},next:function(a){return c.nth(a,2,\"nextSibling\")},prev:function(a){return c.nth(a,\n2,\"previousSibling\")},nextAll:function(a){return c.dir(a,\"nextSibling\")},prevAll:function(a){return c.dir(a,\"previousSibling\")},nextUntil:function(a,b,d){return c.dir(a,\"nextSibling\",d)},prevUntil:function(a,b,d){return c.dir(a,\"previousSibling\",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,\"iframe\")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,\nb){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e===\"string\")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(\",\"))}});c.extend({filter:function(a,b,d){if(d)a=\":not(\"+a+\")\";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&\ne.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\\d+=\"(?:\\d+|null)\"/g,$=/^\\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/ig,Ba=/<([\\w:]+)/,db=/<tbody/i,eb=/<|&#?\\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\\s*(?:[^=]|=\\s*.checked.)/i,fb=/\\=([^=\"'>\\s]+\\/)>/g,P={option:[1,\n\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],area:[1,\"<map>\",\"</map>\"],_default:[0,\"\",\"\"]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,\"div<div>\",\"</div>\"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=\nc(this);d.text(a.call(this,b,d.text()))});if(typeof a!==\"object\"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},\nwrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,\"body\")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},\nprepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,\"before\",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,\nthis.nextSibling)});else if(arguments.length){var a=this.pushStack(this,\"after\",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName(\"*\"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName(\"*\"));b.firstChild;)b.removeChild(b.firstChild);\nreturn this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement(\"div\");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,\"\").replace(fb,'=\"$1\">').replace($,\"\")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find(\"*\"),b.find(\"*\"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,\"\"):null;\nelse if(typeof a===\"string\"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||[\"\",\"\"])[1].toLowerCase()]){a=a.replace(Aa,\"<$1></$2>\");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName(\"*\"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=\nc(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!==\"string\")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),\"replaceWith\",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l===\"string\"&&Da.test(l))return this.each(function(){c(this).domManip(a,\nb,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,\"tr\");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],\"table\")?this[f].getElementsByTagName(\"tbody\")[0]||this[f].appendChild(this[f].ownerDocument.createElement(\"tbody\")):\nthis[f]:this[f],f>0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]===\"string\"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:\"append\",\nprependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement===\"undefined\")b=b.ownerDocument||\nb[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l===\"number\")l+=\"\";if(l){if(typeof l===\"string\"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l===\"string\"){l=l.replace(Aa,\"<$1></$2>\");var k=(Ba.exec(l)||[\"\",\"\"])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement(\"div\");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k===\"table\"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]===\"<table>\"&&!x?r.childNodes:[];for(o=k.length-\n1;o>=0;--o)c.nodeName(k[o],\"tbody\")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],\"script\")&&(!f[h].type||f[h].type.toLowerCase()===\"text/javascript\"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName(\"script\"))));\nd.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\\([^)]*\\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\\d+(?:px)?$/i,\njb=/^-?\\d/,kb={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Pa=[\"Left\",\"Right\"],Qa=[\"Top\",\"Bottom\"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,\"opacity\",\"opacity\");return d===\"\"?\"1\":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,\nzoom:true,lineHeight:true},cssProps:{\"float\":c.support.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d===\"number\"&&isNaN(d)||d==null)){if(typeof d===\"number\"&&!c.cssNumber[h])d+=\"px\";if(!k||!(\"set\"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&\"get\"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),\nh=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&\"get\"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each([\"height\",\"width\"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h===\"0px\"&&aa)h=aa(d,b,b);\nif(h!=null)return h===\"\"||h===\"auto\"?\"0px\":h}if(h<0||h==null){h=d.style[b];return h===\"\"||h===\"auto\"?\"0px\":h}return typeof h===\"string\"?h:h+\"px\"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+\"px\"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||\"\")?parseFloat(RegExp.$1)/100+\"\":b?\"1\":\"\"},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?\"\":\"alpha(opacity=\"+b*100+\")\",f=\nd.filter||\"\";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+\" \"+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,\"-$1\").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===\"\"&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left;\ne=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b===\"fontSize\"?\"1em\":f||0;f=h.pixelLeft+\"px\";h.left=d;a.runtimeStyle.left=e}return f===\"\"?\"auto\":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,\"display\"))===\"none\"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,\nob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\\[\\]$/,T=/\\=\\?(&|$)/,ja=/\\?/,rb=/([?&])_=[^&]*/,sb=/^(\\w+:)?\\/\\/([^\\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==\"string\"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(\" \");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e=\"GET\";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b===\n\"object\"){b=c.param(b,c.ajaxSettings.traditional);e=\"POST\"}var h=this;c.ajax({url:a,type:e,dataType:\"html\",data:b,complete:function(l,k){if(k===\"success\"||k===\"notmodified\")h.html(f?c(\"<div>\").append(l.responseText.replace(nb,\"\")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&\n!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each(\"ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend\".split(\" \"),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:\"GET\",url:a,data:b,success:d,dataType:e})},\ngetScript:function(a,b){return c.get(a,null,b,\"script\")},getJSON:function(a,b,d){return c.get(a,b,d,\"json\")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:\"POST\",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:\"GET\",contentType:\"application/x-www-form-urlencoded\",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:\"application/xml, text/xml\",html:\"text/html\",\nscript:\"text/javascript, application/javascript\",json:\"application/json, text/javascript\",text:\"text/plain\",_default:\"*/*\"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,\"\");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!==\"string\")b.data=c.param(b.data,b.traditional);if(b.dataType===\"jsonp\"){if(h===\"GET\")T.test(b.url)||(b.url+=(ja.test(b.url)?\"&\":\"?\")+(b.jsonp||\"callback\")+\"=?\");else if(!b.data||\n!T.test(b.data))b.data=(b.data?b.data+\"&\":\"\")+(b.jsonp||\"callback\")+\"=?\";b.dataType=\"json\"}if(b.dataType===\"json\"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||\"jsonp\"+mb++;if(b.data)b.data=(b.data+\"\").replace(T,\"=\"+d+\"$1\");b.url=b.url.replace(T,\"=\"+d+\"$1\");b.dataType=\"script\";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType===\"script\"&&b.cache===null)b.cache=\nfalse;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,\"$1_=\"+o);b.url=x+(x===b.url?(ja.test(b.url)?\"&\":\"?\")+\"_=\"+o:\"\")}if(b.data&&l)b.url+=(ja.test(b.url)?\"&\":\"?\")+b.data;b.global&&c.active++===0&&c.event.trigger(\"ajaxStart\");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType===\"script\"&&h===\"GET\"&&o){var r=t.getElementsByTagName(\"head\")[0]||t.documentElement,A=t.createElement(\"script\");if(b.scriptCharset)A.charset=b.scriptCharset;\nA.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState===\"loaded\"||this.readyState===\"complete\")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader(\"Content-Type\",\nb.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader(\"If-Modified-Since\",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader(\"If-None-Match\",c.etag[b.url])}o||w.setRequestHeader(\"X-Requested-With\",\"XMLHttpRequest\");w.setRequestHeader(\"Accept\",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+\", */*; q=0.01\":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger(\"ajaxStop\");w.abort();return false}b.global&&\nc.triggerGlobal(b,\"ajaxSend\",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m===\"abort\"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m===\"timeout\")){J=true;w.onreadystatechange=c.noop;e=m===\"timeout\"?\"timeout\":!c.httpSuccess(w)?\"error\":b.ifModified&&c.httpNotModified(w,b.url)?\"notmodified\":\"success\";var p;if(e===\"success\")try{f=c.httpData(w,b.dataType,b)}catch(q){e=\"parsererror\";p=q}if(e===\"success\"||e===\"notmodified\")d||\nc.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m===\"timeout\"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L(\"abort\")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L(\"timeout\")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]=\nencodeURIComponent(h)+\"=\"+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join(\"&\").replace(tb,\"+\")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,\"ajaxError\",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,\"ajaxSuccess\",\n[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,\"ajaxComplete\",[b,a]);a.global&&c.active--===1&&c.event.trigger(\"ajaxStop\")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol===\"file:\"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader(\"Last-Modified\"),\ne=a.getResponseHeader(\"Etag\");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader(\"content-type\")||\"\",f=b===\"xml\"||!b&&e.indexOf(\"xml\")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName===\"parsererror\"&&c.error(\"parsererror\");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a===\"string\")if(b===\"json\"||!b&&e.indexOf(\"json\")>=0)a=c.parseJSON(a);else if(b===\"script\"||!b&&e.indexOf(\"javascript\")>=0)c.globalEval(a);return a}});\nif(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!==\"file:\")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\\-]=)?([\\d+.\\-]+)(.*)$/,ba,pa=[[\"height\",\"marginTop\",\"marginBottom\",\"paddingTop\",\"paddingBottom\"],[\"width\",\"marginLeft\",\"marginRight\",\"paddingLeft\",\"paddingRight\"],[\"opacity\"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S(\"show\",\n3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,\"olddisplay\")&&b===\"none\")b=a.style.display=\"\";b===\"\"&&c.css(a,\"display\")===\"none\"&&c.data(a,\"olddisplay\",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===\"\"||b===\"none\")a.style.display=c.data(a,\"olddisplay\")||\"\"}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S(\"hide\",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],\"display\");d!==\"none\"&&c.data(this[a],\"olddisplay\",\nd)}for(a=0;a<b;a++)this[a].style.display=\"none\";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a===\"boolean\";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(\":hidden\");c(this)[f?\"show\":\"hide\"]()}):this.animate(S(\"toggle\",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(\":hidden\").css(\"opacity\",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,\nd,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?\"each\":\"queue\"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(\":hidden\"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]===\"hide\"&&o||a[l]===\"show\"&&!o)return h.complete.call(this);if(k&&(l===\"height\"||l===\"width\")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,\"display\")===\"inline\"&&c.css(this,\"float\")===\"none\")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)===\n\"inline\")this.style.display=\"inline-block\";else{this.style.display=\"inline\";this.style.zoom=1}else this.style.display=\"inline-block\"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow=\"hidden\";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C===\"toggle\"?o?\"show\":\"hide\":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||\"px\";if(g!==\"px\"){c.style(x,A,(L||1)+g);I=(L||\n1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]===\"-=\"?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,\"\")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S(\"show\",1),slideUp:S(\"hide\",1),slideToggle:S(\"toggle\",1),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,\nd,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a===\"object\"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration===\"number\"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*\nMath.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)}\nvar f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||\"px\";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop===\"width\"||this.prop===\"height\"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;\nthis.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each([\"\",\"X\",\"Y\"],function(k,o){f.style[\"overflow\"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||\nthis.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?\"swing\":\"linear\");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=\nc.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,\"opacity\",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop===\"width\"||a.prop===\"height\"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===\nb.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset=\"getBoundingClientRect\"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&\nh.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle;\nfor(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position===\"fixed\")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!==\"visible\"){k+=\nparseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position===\"relative\"||d.position===\"static\"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position===\"fixed\"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement(\"div\"),d,e,f,h=parseFloat(c.css(a,\"marginTop\"))||0;c.extend(b.style,{position:\"absolute\",top:0,left:0,margin:0,border:0,width:\"1px\",\nheight:\"1px\",visibility:\"hidden\"});b.innerHTML=\"<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>\";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=\nf.offsetTop===5;e.style.position=\"fixed\";e.style.top=\"20px\";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top=\"\";d.style.overflow=\"hidden\";d.style.position=\"relative\";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,\n\"marginTop\"))||0;d+=parseFloat(c.css(a,\"marginLeft\"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,\"position\");if(e===\"static\")a.style.position=\"relative\";var f=c(a),h=f.offset(),l=c.css(a,\"top\"),k=c.css(a,\"left\"),o=e===\"absolute\"&&c.inArray(\"auto\",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;\"using\"in b?b.using.call(a,\ne):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,\"marginTop\"))||0;d.left-=parseFloat(c.css(a,\"marginLeft\"))||0;e.top+=parseFloat(c.css(b[0],\"borderTopWidth\"))||0;e.left+=parseFloat(c.css(b[0],\"borderLeftWidth\"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&&\nc.css(a,\"position\")===\"static\";)a=a.offsetParent;return a})}});c.each([\"Left\",\"Top\"],function(a,b){var d=\"scroll\"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?\"pageXOffset\"in h?h[a?\"pageYOffset\":\"pageXOffset\"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each([\"Height\",\"Width\"],function(a,b){var d=b.toLowerCase();\nc.fn[\"inner\"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,\"padding\")):null};c.fn[\"outer\"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?\"margin\":\"border\")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode===\"CSS1Compat\"&&f.document.documentElement[\"client\"+b]||f.document.body[\"client\"+b];else if(f.nodeType===9)return Math.max(f.documentElement[\"client\"+\nb],f.body[\"scroll\"+b],f.documentElement[\"scroll\"+b],f.body[\"offset\"+b],f.documentElement[\"offset\"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e===\"string\"?e:e+\"px\")}})})(window);\n"
  },
  {
    "path": "public/javascripts/jquery.mousewheel-3.0.2.pack.js",
    "content": "/*! Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)\n * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)\n * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.\n * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.\n * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.\n *\n * Version: 3.0.2\n *\n * Requires: 1.2.2+\n */\n\n(function(b){function d(a){var f=[].slice.call(arguments,1),e=0;a=b.event.fix(a||window.event);a.type=\"mousewheel\";if(a.wheelDelta)e=a.wheelDelta/120;if(a.detail)e=-a.detail/3;f.unshift(a,e);return b.event.handle.apply(this,f)}var c=[\"DOMMouseScroll\",\"mousewheel\"];b.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=c.length;a;)this.addEventListener(c[--a],d,false);else this.onmousewheel=d},teardown:function(){if(this.removeEventListener)for(var a=c.length;a;)this.removeEventListener(c[--a],\nd,false);else this.onmousewheel=null}};b.fn.extend({mousewheel:function(a){return a?this.bind(\"mousewheel\",a):this.trigger(\"mousewheel\")},unmousewheel:function(a){return this.unbind(\"mousewheel\",a)}})})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.mousewheel-3.0.4.pack.js",
    "content": "/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)\n* Licensed under the MIT License (LICENSE.txt).\n*\n* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.\n* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.\n* Thanks to: Seamus Leahy for adding deltaX and deltaY\n*\n* Version: 3.0.4\n*\n* Requires: 1.2.2+\n*/\n\n(function(d){function g(a){var b=a||window.event,i=[].slice.call(arguments,1),c=0,h=0,e=0;a=d.event.fix(b);a.type=\"mousewheel\";if(a.wheelDelta)c=a.wheelDelta/120;if(a.detail)c=-a.detail/3;e=c;if(b.axis!==undefined&&b.axis===b.HORIZONTAL_AXIS){e=0;h=-1*c}if(b.wheelDeltaY!==undefined)e=b.wheelDeltaY/120;if(b.wheelDeltaX!==undefined)h=-1*b.wheelDeltaX/120;i.unshift(a,c,h,e);return d.event.handle.apply(this,i)}var f=[\"DOMMouseScroll\",\"mousewheel\"];d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=\nf.length;a;)this.addEventListener(f[--a],g,false);else this.onmousewheel=g},teardown:function(){if(this.removeEventListener)for(var a=f.length;a;)this.removeEventListener(f[--a],g,false);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind(\"mousewheel\",a):this.trigger(\"mousewheel\")},unmousewheel:function(a){return this.unbind(\"mousewheel\",a)}})})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.mousewheel.js",
    "content": "/* Copyright (c) 2006 Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)\n * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)\n * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.\n * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.\n * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.\n *\n * $LastChangedDate: 2007-12-20 09:02:08 -0600 (Thu, 20 Dec 2007) $\n * $Rev: 4265 $\n *\n * Version: 3.0\n *\n * Requires: $ 1.2.2+\n */\n\n(function($) {\n\n$.event.special.mousewheel = {\n  setup: function() {\n    var handler = $.event.special.mousewheel.handler;\n\n    // Fix pageX, pageY, clientX and clientY for mozilla\n    if ( $.browser.mozilla )\n      $(this).bind('mousemove.mousewheel', function(event) {\n        $.data(this, 'mwcursorposdata', {\n          pageX: event.pageX,\n          pageY: event.pageY,\n          clientX: event.clientX,\n          clientY: event.clientY\n        });\n      });\n\n    if ( this.addEventListener )\n      this.addEventListener( ($.browser.mozilla ? 'DOMMouseScroll' : 'mousewheel'), handler, false);\n    else\n      this.onmousewheel = handler;\n  },\n\n  teardown: function() {\n    var handler = $.event.special.mousewheel.handler;\n\n    $(this).unbind('mousemove.mousewheel');\n\n    if ( this.removeEventListener )\n      this.removeEventListener( ($.browser.mozilla ? 'DOMMouseScroll' : 'mousewheel'), handler, false);\n    else\n      this.onmousewheel = function(){};\n\n    $.removeData(this, 'mwcursorposdata');\n  },\n\n  handler: function(event) {\n    var args = Array.prototype.slice.call( arguments, 1 );\n\n    event = $.event.fix(event || window.event);\n    // Get correct pageX, pageY, clientX and clientY for mozilla\n    $.extend( event, $.data(this, 'mwcursorposdata') || {} );\n    var delta = 0, returnValue = true;\n\n    if ( event.wheelDelta ) delta = event.wheelDelta/120;\n    if ( event.detail     ) delta = -event.detail/3;\n//    if ( $.browser.opera  ) delta = -event.wheelDelta;\n\n    event.data  = event.data || {};\n    event.type  = \"mousewheel\";\n\n    // Add delta to the front of the arguments\n    args.unshift(delta);\n    // Add event to the front of the arguments\n    args.unshift(event);\n\n    return $.event.handle.apply(this, args);\n  }\n};\n\n$.fn.extend({\n  mousewheel: function(fn) {\n    return fn ? this.bind(\"mousewheel\", fn) : this.trigger(\"mousewheel\");\n  },\n\n  unmousewheel: function(fn) {\n    return this.unbind(\"mousewheel\", fn);\n  }\n});\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.scrollTo-min.js",
    "content": ";(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\\d+(\\.\\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.tagsinput.js",
    "content": "/*\n\n  jQuery Tags Input Plugin 1.2\n\n  Copyright (c) 2010 XOXCO, Inc\n\n  Documentation for this plugin lives here:\n  http://xoxco.com/clickable/jquery-tags-input\n\n  Licensed under the MIT license:\n  http://www.opensource.org/licenses/mit-license.php\n\n  ben@xoxco.com\n\n*/\n\n(function($) {\n\n  var delimiter = new Array();\n  var issue_id = null;\n  var cache = undefined;\n\n  jQuery.fn.addTag = function(value,options) {\n\n      var options = jQuery.extend({focus:false},options);\n\n      this.each(function() {\n        id = $(this).attr('id');\n\n        var tagslist = $(this).val().split(delimiter[id]);\n        if (tagslist[0] == '') {\n          tagslist = new Array();\n        }\n        value = jQuery.trim(value);\n        if (value !='') {\n\n          $('<span class=\"tag\">'+value + '&nbsp;&nbsp;<a href=\"#\" title=\"Remove tag\" onclick=\"return $(\\'#'+id + '\\').removeTag(\\'' + escape(value) + '\\');\">x</a></span>').insertBefore('#'+id+'_addTag');\n          tagslist.push(value);\n\n          $('#'+id+'_tag').val('');\n          if (options.focus) {\n            $('#'+id+'_tag').focus();\n          } else {\n            $('#'+id+'_tag').blur();\n          }\n        }\n        jQuery.fn.tagsInput.updateTagsField(this,tagslist);\n\n      });\n\n      if (options.send_to_server || (options.send_to_server != false && options.focus != false)){\n        update_issue_tags($(this).attr('value'));\n      }\n\n      return false;\n    };\n\n  jQuery.fn.removeTag = function(value) {\n\n      this.each(function() {\n        id = $(this).attr('id');\n\n        var old = $(this).val().split(delimiter[id]);\n\n\n        $('#'+id+'_tagsinput .tag').remove();\n        str = '';\n        for (i=0; i< old.length; i++) {\n          if (escape(old[i])!=value) {\n            str = str + delimiter[id] +old[i];\n          }\n        }\n\n        jQuery.fn.tagsInput.importTags(this,str);\n      });\n\n      update_issue_tags($(this).attr('value'));\n\n      return false;\n\n    };\n\n  function update_issue_tags(tags){\n    if (issue_id == null){return;}\n    var url = url_for({ controller: 'issues',\n                             action    : 'update_tags',\n                id    : issue_id\n                            });\n    var data = 'tags=' + tags;\n\n    $.ajax({\n       type: \"POST\",\n       dataType: \"json\",\n       url: url,\n       data: data\n     });\n  }\n\n  jQuery.fn.tagsInput = function(options) {\n\n    var settings = jQuery.extend({defaultText:'add a tag',width:'300px',height:'100px','hide':true,'delimiter':',',autocomplete:{selectFirst:false}},options);\n\n    issue_id = settings.issue_id;\n\n    this.each(function() {\n      if (settings.hide) {\n        $(this).hide();\n      }\n\n      id = $(this).attr('id')\n\n      data = jQuery.extend({\n        pid:id,\n        real_input: '#'+id,\n        holder: '#'+id+'_tagsinput',\n        input_wrapper: '#'+id+'_addTag',\n        fake_input: '#'+id+'_tag'\n      },settings);\n\n\n      delimiter[id] = data.delimiter;\n\n      $('<div id=\"'+id+'_tagsinput\" class=\"tagsinput\"><div id=\"'+id+'_addTag\"><input id=\"'+id+'_tag\" value=\"\" default=\"'+settings.defaultText+'\" /></div><div class=\"tags_clear\"></div></div>').insertAfter(this);\n\n      $(data.holder).css('width',settings.width);\n      $(data.holder).css('height',settings.height);\n\n\n      if ($(data.real_input).val()!='') {\n        jQuery.fn.tagsInput.importTags($(data.real_input),$(data.real_input).val());\n      } else {\n        $(data.fake_input).val($(data.fake_input).attr('default'));\n        $(data.fake_input).css('color','#666666');\n      }\n\n\n      $(data.holder).bind('click',data,function(event) {\n        $(event.data.fake_input).focus();\n      });\n\n      // if user types a comma, create a new tag\n      $(data.fake_input).bind('keypress',data,function(event) {\n        if (event.which==event.data.delimiter.charCodeAt(0) || event.which==13) {\n\n          $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true});\n          return false;\n        }\n      });\n\n\n      $(data.fake_input).bind('focus',data,function(event) {\n        if ($(event.data.fake_input).val()==$(event.data.fake_input).attr('default')) {\n          $(event.data.fake_input).val('');\n        }\n        $(event.data.fake_input).css('color','#000000');\n      });\n\n      if (settings.autocomplete_url != undefined) {\n        $(data.fake_input).autocomplete({\n              source: function( request, response ) {\n                var term = request.term;\n\n                   if (typeof cache != \"undefined\") {\n                     //map the data into a response that will be understood by the autocomplete widget\n                     response($.ui.autocomplete.filter(cache, term.substring(1, term.length)));\n                   }\n                   //get the data from the server\n                   else {\n                     $.ajax({\n                       url: settings.autocomplete_url,\n                       dataType: \"json\",\n                       success: function(data) {\n                         //cache the data for later\n                         cache = data;\n                         //map the data into a response that will be understood by the autocomplete widget\n                           response($.ui.autocomplete.filter(cache, term.substring(1, term.length)));\n                       }\n                     });\n                   }\n              },\n\n                    //   if ( term in cache ) {\n                    //     response($.ui.autocomplete.filter(cache, term.substring(1, term.length)));\n                    //     // response( cache[ term ] );\n                    //     return;\n                    //   }\n                    //\n                    //   lastXhr = $.getJSON( settings.autocomplete_url, request, function( data, status, xhr ) {\n                    //     cache[ term ] = data;\n                    //     if ( xhr === lastXhr ) {\n                    //       response( data );\n                    //     }\n                    //   });\n                    // },\n              minLength: 0,\n              data: data,\n              });\n\n        $(data.fake_input).bind( \"autocompleteselect\", data, function(event, ui) {\n                if (ui.item) {\n                  d = ui.item.value + \"\";\n                  $(event.data.real_input).addTag(d,{focus:true});\n                  event.preventDefault();\n                }\n              });\n\n\n        $(data.fake_input).bind('blur',data,function(event) {\n          if (($(event.data.fake_input).val() != $(event.data.fake_input).attr('default'))&&($(event.data.fake_input).val() != '')) {\n            $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:false, send_to_server:true});\n          }\n\n          $(event.data.fake_input).val($(event.data.fake_input).attr('default'));\n          $(event.data.fake_input).css('color','#666666');\n          return false;\n        });\n\n\n      } else {\n\n          // if a user tabs out of the field, create a new tag\n          // this is only available if autocomplete is not used.\n          $(data.fake_input).bind('blur',data,function(event) {\n            var d = $(this).attr('default');\n            if ($(event.data.fake_input).val()!='' && $(event.data.fake_input).val()!=d) {\n              event.preventDefault();\n              $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true});\n            } else {\n              $(event.data.fake_input).val($(event.data.fake_input).attr('default'));\n              $(event.data.fake_input).css('color','#666666');\n            }\n            return false;\n          });\n\n      }\n\n      $(data.fake_input).blur();\n    });\n\n    return this;\n\n  };\n\n\n  jQuery.fn.tagsInput.updateTagsField = function(obj,tagslist) {\n\n      id = $(obj).attr('id');\n      $(obj).val(tagslist.join(delimiter[id]));\n    };\n\n\n\n  jQuery.fn.tagsInput.importTags = function(obj,val) {\n\n      $(obj).val('');\n      id = $(obj).attr('id');\n      var tags = val.split(delimiter[id]);\n      for (i=0; i<tags.length; i++) {\n        $(obj).addTag(tags[i],{focus:false, send_to_server:false});\n      }\n    };\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.ui.autocomplete.ext.js",
    "content": "/*\n * jQuery UI Autocomplete\n * version: 1.0 (1/2/2008)\n * @requires: jQuery v1.2 or later, dimensions plugin\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n *\n * Copyright 2007 Yehuda Katz, Rein Henrichs\n */\n\n(function($) {\n  $.ui = $.ui || {};\n  $.ui.autocomplete = $.ui.autocomplete || {};\n  $.ui.autocomplete.ext = $.ui.autocomplete.ext || {};\n\n  $.ui.autocomplete.ext.ajax = function(opt) {\n    var ajax = opt.ajax;\n    return { getList: function(input) {\n      $.getJSON(ajax, \"val=\" + input.val(), function(json) { input.trigger(\"updateList\", [json]); });\n    } };\n  };\n\n  $.ui.autocomplete.ext.templateText = function(opt) {\n    var template = $.makeTemplate(opt.templateText, \"<%\", \"%>\");\n    return { template: function(obj) { return template(obj); } };\n  };\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.ui.autocomplete.js",
    "content": "/* jQuery Autocomplete\n * Version 1.0\n * Written by Yehuda Katz (wycats@gmail.com) and Rein Henrichs (reinh@reinh.com)\n * @requires jQuery v1.2, jQuery dimensions plugin\n *\n * Copyright 2007 Yehuda Katz, Rein Henrichs\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n *\n */\n\n/*\n * @description Form autocomplete plugin using preloaded or Ajax JSON data source\n *\n * @example $('input#user-name').autocomplete({list: [\"quentin\", \"adam\", \"admin\"]})\n * @desc Simple autocomplete with basic JSON data source\n *\n * @example $('input#user-name').autocomplete({ajax: \"/usernames.js\"})\n * @desc Simple autocomplete with Ajax loaded JSON data source\n *\n */\n\n\n(function($) {\n\n  $.ui = $.ui || {}; $.ui.autocomplete = $.ui.autocomplete || {}; var active;\n\n  $.fn.autocompleteMode = function(container, input, size, opt) {\n    var original = input.val(); var selected = -1; var self = this;\n\n    $.data(document.body, \"autocompleteMode\", true);\n\n    $(\"body\").one(\"cancel.autocomplete\", function() {\n      input.trigger(\"cancel.autocomplete\"); $(\"body\").trigger(\"off.autocomplete\"); input.val(original);\n    });\n\n    $(\"body\").one(\"activate.autocomplete\", function() {\n      input.trigger(\"activate.autocomplete\", [$.data(active[0], \"originalObject\")]); $(\"body\").trigger(\"off.autocomplete\");\n    });\n\n    $(\"body\").one(\"off.autocomplete\", function(e, reset) {\n      container.remove();\n      $.data(document.body, \"autocompleteMode\", false);\n      input.unbind(\"keydown.autocomplete\");\n      $(\"body\").add(window).unbind(\"click.autocomplete\").unbind(\"cancel.autocomplete\").unbind(\"activate.autocomplete\");\n    });\n\n    // If a click bubbles all the way up to the window, close the autocomplete\n    $(window).bind(\"click.autocomplete\", function() { $(\"body\").trigger(\"cancel.autocomplete\"); });\n\n    var select = function() {\n      active = $(\"> *\", container).removeClass(\"active\").slice(selected, selected + 1).addClass(\"active\");\n      input.trigger(\"itemSelected.autocomplete\", [$.data(active[0], \"originalObject\")]);\n      input.val(opt.insertText($.data(active[0], \"originalObject\")));\n    };\n\n    container.mouseover(function(e) {\n      // If you hover over the container, but not its children, return\n      if(e.target == container[0]) return;\n      // Set the selected item to the item hovered over and make it active\n      selected = $(\"> *\", container).index($(e.target).is('li') ? $(e.target)[0] : $(e.target).parents('li')[0]); select();\n    }).bind(\"click.autocomplete\", function(e) {\n      $(\"body\").trigger(\"activate.autocomplete\"); $.data(document.body, \"suppressKey\", false);\n    });\n\n    input\n      .bind(\"keydown.autocomplete\", function(e) {\n        if(e.which == 27) { $(\"body\").trigger(\"cancel.autocomplete\"); }\n        else if(e.which == 13) { $(\"body\").trigger(\"activate.autocomplete\"); }\n        else if(e.which == 40 || e.which == 9 || e.which == 38) {\n          switch(e.which) {\n            case 40:\n            case 9:\n              selected = selected >= size - 1 ? 0 : selected + 1; break;\n            case 38:\n              selected = selected <= 0 ? size - 1 : selected - 1; break;\n            default: break;\n          }\n          select();\n        } else { return true; }\n        $.data(document.body, \"suppressKey\", true);\n      });\n  };\n\n  $.fn.autocomplete = function(opt) {\n\n    opt = $.extend({}, {\n      timeout: 1000,\n      getList: function(input) { input.trigger(\"updateList\", [opt.list]); },\n      template: function(str) { return \"<li>\" + opt.insertText(str) + \"</li>\"; },\n      insertText: function(str) { return str; },\n      match: function(typed) { return this.match(new RegExp(typed)); },\n      wrapper: \"<ul class='jq-ui-autocomplete'></ul>\"\n    }, opt);\n\n    if($.ui.autocomplete.ext) {\n      for(var ext in $.ui.autocomplete.ext) {\n        if(opt[ext]) {\n          opt = $.extend(opt, $.ui.autocomplete.ext[ext](opt));\n          delete opt[ext];\n        }\n    } }\n\n    return this.each(function() {\n\n      $(this)\n        .keypress(function(e) {\n          var typingTimeout = $.data(this, \"typingTimeout\");\n          if(typingTimeout) window.clearInterval(typingTimeout);\n\n          if($.data(document.body, \"suppressKey\"))\n            return $.data(document.body, \"suppressKey\", false);\n          else if($.data(document.body, \"autocompleteMode\") && e.charCode < 32 && e.keyCode != 8 && e.keyCode != 46) return false;\n          else {\n            $.data(this, \"typingTimeout\", window.setTimeout(function() {\n              $(e.target).trigger(\"autocomplete\");\n            }, opt.timeout));\n          }\n        })\n        .bind(\"autocomplete\", function() {\n          var self = $(this);\n\n          self.one(\"updateList\", function(e, list) {\n            list = $(list)\n              .filter(function() { return opt.match.call(this, self.val()); })\n              .map(function() {\n                var node = $(opt.template(this))[0];\n                $.data(node, \"originalObject\", this);\n                return node;\n              });\n\n            $(\"body\").trigger(\"off.autocomplete\");\n\n            if(!list.length) return false;\n\n            var container = list.wrapAll(opt.wrapper).parents(\":last\").children();\n\n            var offset = self.offset();\n\n            opt.container = container\n              .css({top: offset.top + self.outerHeight(), left: offset.left, width: self.width()})\n              .appendTo(\"body\");\n\n            $(\"body\").autocompleteMode(container, self, list.length, opt);\n          });\n\n          opt.getList(self);\n        });\n\n    });\n  };\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jquery.ui.position.js",
    "content": "/*\n * jQuery UI Position @VERSION\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Position\n */\n(function($) {\n\n$.ui = $.ui || {};\n\nvar horizontalPositions = /left|center|right/,\n  horizontalDefault = 'center',\n  verticalPositions = /top|center|bottom/,\n  verticalDefault = 'center',\n  _position = $.fn.position;\n\n$.fn.position = function(options) {\n  if (!options || !options.of) {\n    return _position.apply(this, arguments);\n  }\n\n  // make a copy, we don't want to modify arguments\n  options = $.extend({}, options);\n\n  var target = $(options.of),\n    collision = (options.collision || 'flip').split(' '),\n    offset = options.offset ? options.offset.split(' ') : [0, 0],\n    targetWidth,\n    targetHeight,\n    basePosition;\n\n  if (options.of.nodeType === 9) {\n    targetWidth = target.width();\n    targetHeight = target.height();\n    basePosition = { top: 0, left: 0 };\n  } else if (options.of.scrollTo && options.of.document) {\n    targetWidth = target.width();\n    targetHeight = target.height();\n    basePosition = { top: target.scrollTop(), left: target.scrollLeft() };\n  } else if (options.of.preventDefault) {\n    // force left top to allow flipping\n    options.at = 'left top';\n    targetWidth = targetHeight = 0;\n    basePosition = { top: options.of.pageY, left: options.of.pageX };\n  } else {\n    targetWidth = target.outerWidth();\n    targetHeight = target.outerHeight();\n    basePosition = target.offset();\n  }\n\n  // force my and at to have valid horizontal and veritcal positions\n  // if a value is missing or invalid, it will be converted to center\n  $.each(['my', 'at'], function() {\n    var pos = (options[this] || '').split(' ');\n    pos = pos.length == 1\n      ? horizontalPositions.test(pos[0])\n        ? pos.concat([verticalDefault])\n        : verticalPositions.test(pos[0])\n          ? [horizontalDefault].concat(pos)\n          : [horizontalDefault, verticalDefault]\n      : pos;\n    pos[0] = horizontalPositions.test(pos[0]) ? pos[0] : horizontalDefault;\n    pos[1] = verticalPositions.test(pos[1]) ? pos[1] : verticalDefault;\n    options[this] = pos;\n  });\n\n  // normalize collision option\n  if (collision.length == 1) {\n    collision[1] = collision[0];\n  }\n\n  // normalize offset option\n  offset[0] = parseInt(offset[0], 10) || 0;\n  if (offset.length == 1) {\n    offset[1] = offset[0];\n  }\n  offset[1] = parseInt(offset[1], 10) || 0;\n\n  switch (options.at[0]) {\n    case 'right':\n      basePosition.left += targetWidth;\n      break;\n    case horizontalDefault:\n      basePosition.left += targetWidth / 2;\n      break;\n  }\n\n  switch (options.at[1]) {\n    case 'bottom':\n      basePosition.top += targetHeight;\n      break;\n    case verticalDefault:\n      basePosition.top += targetHeight / 2;\n      break;\n  }\n\n  basePosition.left += offset[0];\n  basePosition.top += offset[1];\n\n  return this.each(function() {\n    var elem = $(this),\n      elemWidth = elem.outerWidth(),\n      elemHeight = elem.outerHeight(),\n      position = $.extend({}, basePosition),\n      over,\n      myOffset,\n      atOffset;\n\n    switch (options.my[0]) {\n      case 'right':\n        position.left -= elemWidth;\n        break;\n      case horizontalDefault:\n        position.left -= elemWidth / 2;\n        break;\n    }\n\n    switch (options.my[1]) {\n      case 'bottom':\n        position.top -= elemHeight;\n        break;\n      case verticalDefault:\n        position.top -= elemHeight / 2;\n        break;\n    }\n\n    $.each(['left', 'top'], function(i, dir) {\n      ($.ui.position[collision[i]] &&\n        $.ui.position[collision[i]][dir](position, {\n          targetWidth: targetWidth,\n          targetHeight: targetHeight,\n          elemWidth: elemWidth,\n          elemHeight: elemHeight,\n          offset: offset,\n          my: options.my,\n          at: options.at\n        }));\n    });\n\n    (options.stackfix !== false && $.fn.stackfix && elem.stackfix());\n    elem.offset($.extend(position, { using: options.using }));\n  });\n};\n\n$.ui.position = {\n  fit: {\n    left: function(position, data) {\n      var over = position.left + data.elemWidth - $(window).width() - $(window).scrollLeft();\n      position.left = over > 0 ? position.left - over : Math.max(0, position.left);\n    },\n    top: function(position, data) {\n      var over = position.top + data.elemHeight - $(window).height() - $(window).scrollTop();\n      position.top = over > 0 ? position.top - over : Math.max(0, position.top);\n    }\n  },\n\n  flip: {\n    left: function(position, data) {\n      if (data.at[0] == 'center')\n        return;\n      var over = position.left + data.elemWidth - $(window).width() - $(window).scrollLeft(),\n        myOffset = data.my[0] == 'left' ? -data.elemWidth : data.my[0] == 'right' ? data.elemWidth : 0,\n        offset = -2 * data.offset[0];\n      position.left += position.left < 0 ? myOffset + data.targetWidth + offset : over > 0 ? myOffset - data.targetWidth + offset : 0;\n    },\n    top: function(position, data) {\n      if (data.at[1] == 'center')\n        return;\n      var over = position.top + data.elemHeight - $(window).height() - $(window).scrollTop(),\n        myOffset = data.my[1] == 'top' ? -data.elemHeight : data.my[1] == 'bottom' ? data.elemHeight : 0,\n        atOffset = data.at[1] == 'top' ? data.targetHeight : -data.targetHeight,\n        offset = -2 * data.offset[1];\n      position.top += position.top < 0 ? myOffset + data.targetHeight + offset : over > 0 ? myOffset + atOffset + offset : 0;\n    }\n  }\n};\n\n// offset setter from jQuery 1.4\nif (!$.offset.setOffset) {\n  $.offset.setOffset = function( elem, options ) {\n    // set position first, in-case top/left are set even on static elem\n    if ( /static/.test( jQuery.curCSS( elem, 'position' ) ) ) {\n      elem.style.position = 'relative';\n    }\n    var curElem   = jQuery( elem ),\n      curOffset = curElem.offset(),\n      curTop    = parseInt( jQuery.curCSS( elem, 'top',  true ), 10 ) || 0,\n      curLeft   = parseInt( jQuery.curCSS( elem, 'left', true ), 10)  || 0,\n      props     = {\n        top:  (options.top  - curOffset.top)  + curTop,\n        left: (options.left - curOffset.left) + curLeft\n      };\n\n    if ( 'using' in options ) {\n      options.using.call( elem, props );\n    } else {\n      curElem.css( props );\n    }\n  };\n\n  var _offset = $.fn.offset;\n  $.fn.offset = function( options ) {\n    var elem = this[0];\n    if ( !elem || !elem.ownerDocument ) { return null; }\n    if ( options ) {\n      return this.each(function() {\n        $.offset.setOffset( this, options );\n      });\n    }\n    return _offset.call(this);\n  };\n}\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/jrails.js",
    "content": "(function($){$.ajaxSettings.accepts._default=\"text/javascript, text/html, application/xml, text/xml, */*\"})(jQuery);(function($){$.fn.reset=function(){return this.each(function(){if(typeof this.reset==\"function\"||(typeof this.reset==\"object\"&&!this.reset.nodeType)){this.reset()}})};$.fn.enable=function(){return this.each(function(){this.disabled=false})};$.fn.disable=function(){return this.each(function(){this.disabled=true})}})(jQuery);(function($){$.extend({fieldEvent:function(el,obs){var field=el[0]||el,e=\"change\";if(field.type==\"radio\"||field.type==\"checkbox\"){e=\"click\"}else{if(obs&&(field.type==\"text\"||field.type==\"textarea\"||field.type==\"password\")){e=\"keyup\"}}return e}});$.fn.extend({delayedObserver:function(delay,callback){var el=$(this);if(typeof window.delayedObserverStack==\"undefined\"){window.delayedObserverStack=[]}if(typeof window.delayedObserverCallback==\"undefined\"){window.delayedObserverCallback=function(stackPos){var observed=window.delayedObserverStack[stackPos];if(observed.timer){clearTimeout(observed.timer)}observed.timer=setTimeout(function(){observed.timer=null;observed.callback(observed.obj,observed.obj.formVal())},observed.delay*1000);observed.oldVal=observed.obj.formVal()}}window.delayedObserverStack.push({obj:el,timer:null,delay:delay,oldVal:el.formVal(),callback:callback});var stackPos=window.delayedObserverStack.length-1;if(el[0].tagName==\"FORM\"){$(\":input\",el).each(function(){var field=$(this);field.bind($.fieldEvent(field,delay),function(){var observed=window.delayedObserverStack[stackPos];if(observed.obj.formVal()==observed.oldVal){return}else{window.delayedObserverCallback(stackPos)}})})}else{el.bind($.fieldEvent(el,delay),function(){var observed=window.delayedObserverStack[stackPos];if(observed.obj.formVal()==observed.oldVal){return}else{window.delayedObserverCallback(stackPos)}})}},formVal:function(){var el=this[0];if(el.tagName==\"FORM\"){return this.serialize()}if(el.type==\"checkbox\"||el.type==\"radio\"){return this.filter(\"input:checked\").val()||\"\"}else{return this.val()}}})})(jQuery);(function($){$.fn.extend({visualEffect:function(o,options){if(options){speed=options.duration*1000}else{speed=null}e=o.replace(/\\_(.)/g,function(m,l){return l.toUpperCase()});return eval(\"$(this).\"+e+\"(\"+speed+\")\")},appear:function(speed,callback){return this.fadeIn(speed,callback)},blindDown:function(speed,callback){return this.show(\"blind\",{direction:\"vertical\"},speed,callback)},blindUp:function(speed,callback){return this.hide(\"blind\",{direction:\"vertical\"},speed,callback)},blindRight:function(speed,callback){return this.show(\"blind\",{direction:\"horizontal\"},speed,callback)},blindLeft:function(speed,callback){this.hide(\"blind\",{direction:\"horizontal\"},speed,callback);return this},dropOut:function(speed,callback){return this.hide(\"drop\",{direction:\"down\"},speed,callback)},dropIn:function(speed,callback){return this.show(\"drop\",{direction:\"up\"},speed,callback)},fade:function(speed,callback){return this.fadeOut(speed,callback)},fadeToggle:function(speed,callback){return this.animate({opacity:\"toggle\"},speed,callback)},fold:function(speed,callback){return this.hide(\"fold\",{},speed,callback)},foldOut:function(speed,callback){return this.show(\"fold\",{},speed,callback)},grow:function(speed,callback){return this.show(\"scale\",{},speed,callback)},highlight:function(speed,callback){return this.show(\"highlight\",{},speed,callback)},puff:function(speed,callback){return this.hide(\"puff\",{},speed,callback)},pulsate:function(speed,callback){return this.show(\"pulsate\",{},speed,callback)},shake:function(speed,callback){return this.show(\"shake\",{},speed,callback)},shrink:function(speed,callback){return this.hide(\"scale\",{},speed,callback)},squish:function(speed,callback){return this.hide(\"scale\",{origin:[\"top\",\"left\"]},speed,callback)},slideUp:function(speed,callback){return this.hide(\"slide\",{direction:\"up\"},speed,callback)},slideDown:function(speed,callback){return this.show(\"slide\",{direction:\"up\"},speed,callback)},switchOff:function(speed,callback){return this.hide(\"clip\",{},speed,callback)},switchOn:function(speed,callback){return this.show(\"clip\",{},speed,callback)}})})(jQuery);\n"
  },
  {
    "path": "public/javascripts/json2.js",
    "content": "/*\n    http://www.JSON.org/json2.js\n    2010-08-25\n\n    Public Domain.\n\n    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.\n\n    See http://www.JSON.org/js.html\n\n\n    This code should be minified before deployment.\n    See http://javascript.crockford.com/jsmin.html\n\n    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO\n    NOT CONTROL.\n\n\n    This file creates a global JSON object containing two methods: stringify\n    and parse.\n\n        JSON.stringify(value, replacer, space)\n            value       any JavaScript value, usually an object or array.\n\n            replacer    an optional parameter that determines how object\n                        values are stringified for objects. It can be a\n                        function or an array of strings.\n\n            space       an optional parameter that specifies the indentation\n                        of nested structures. If it is omitted, the text will\n                        be packed without extra whitespace. If it is a number,\n                        it will specify the number of spaces to indent at each\n                        level. If it is a string (such as '\\t' or '&nbsp;'),\n                        it contains the characters used to indent at each level.\n\n            This method produces a JSON text from a JavaScript value.\n\n            When an object value is found, if the object contains a toJSON\n            method, its toJSON method will be called and the result will be\n            stringified. A toJSON method does not serialize: it returns the\n            value represented by the name/value pair that should be serialized,\n            or undefined if nothing should be serialized. The toJSON method\n            will be passed the key associated with the value, and this will be\n            bound to the value\n\n            For example, this would serialize Dates as ISO strings.\n\n                Date.prototype.toJSON = function (key) {\n                    function f(n) {\n                        // Format integers to have at least two digits.\n                        return n < 10 ? '0' + n : n;\n                    }\n\n                    return this.getUTCFullYear()   + '-' +\n                         f(this.getUTCMonth() + 1) + '-' +\n                         f(this.getUTCDate())      + 'T' +\n                         f(this.getUTCHours())     + ':' +\n                         f(this.getUTCMinutes())   + ':' +\n                         f(this.getUTCSeconds())   + 'Z';\n                };\n\n            You can provide an optional replacer method. It will be passed the\n            key and value of each member, with this bound to the containing\n            object. The value that is returned from your method will be\n            serialized. If your method returns undefined, then the member will\n            be excluded from the serialization.\n\n            If the replacer parameter is an array of strings, then it will be\n            used to select the members to be serialized. It filters the results\n            such that only members with keys listed in the replacer array are\n            stringified.\n\n            Values that do not have JSON representations, such as undefined or\n            functions, will not be serialized. Such values in objects will be\n            dropped; in arrays they will be replaced with null. You can use\n            a replacer function to replace those with JSON values.\n            JSON.stringify(undefined) returns undefined.\n\n            The optional space parameter produces a stringification of the\n            value that is filled with line breaks and indentation to make it\n            easier to read.\n\n            If the space parameter is a non-empty string, then that string will\n            be used for indentation. If the space parameter is a number, then\n            the indentation will be that many spaces.\n\n            Example:\n\n            text = JSON.stringify(['e', {pluribus: 'unum'}]);\n            // text is '[\"e\",{\"pluribus\":\"unum\"}]'\n\n\n            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\\t');\n            // text is '[\\n\\t\"e\",\\n\\t{\\n\\t\\t\"pluribus\": \"unum\"\\n\\t}\\n]'\n\n            text = JSON.stringify([new Date()], function (key, value) {\n                return this[key] instanceof Date ?\n                    'Date(' + this[key] + ')' : value;\n            });\n            // text is '[\"Date(---current time---)\"]'\n\n\n        JSON.parse(text, reviver)\n            This method parses a JSON text to produce an object or array.\n            It can throw a SyntaxError exception.\n\n            The optional reviver parameter is a function that can filter and\n            transform the results. It receives each of the keys and values,\n            and its return value is used instead of the original value.\n            If it returns what it received, then the structure is not modified.\n            If it returns undefined then the member is deleted.\n\n            Example:\n\n            // Parse the text. Values that look like ISO date strings will\n            // be converted to Date objects.\n\n            myData = JSON.parse(text, function (key, value) {\n                var a;\n                if (typeof value === 'string') {\n                    a =\n/^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2}(?:\\.\\d*)?)Z$/.exec(value);\n                    if (a) {\n                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],\n                            +a[5], +a[6]));\n                    }\n                }\n                return value;\n            });\n\n            myData = JSON.parse('[\"Date(09/09/2001)\"]', function (key, value) {\n                var d;\n                if (typeof value === 'string' &&\n                        value.slice(0, 5) === 'Date(' &&\n                        value.slice(-1) === ')') {\n                    d = new Date(value.slice(5, -1));\n                    if (d) {\n                        return d;\n                    }\n                }\n                return value;\n            });\n\n\n    This is a reference implementation. You are free to copy, modify, or\n    redistribute.\n*/\n\n/*jslint evil: true, strict: false */\n\n/*members \"\", \"\\b\", \"\\t\", \"\\n\", \"\\f\", \"\\r\", \"\\\"\", JSON, \"\\\\\", apply,\n    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,\n    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,\n    lastIndex, length, parse, prototype, push, replace, slice, stringify,\n    test, toJSON, toString, valueOf\n*/\n\n\n// Create a JSON object only if one does not already exist. We create the\n// methods in a closure to avoid creating global variables.\n\nif (!this.JSON) {\n    this.JSON = {};\n}\n\n(function () {\n\n    function f(n) {\n        // Format integers to have at least two digits.\n        return n < 10 ? '0' + n : n;\n    }\n\n    if (typeof Date.prototype.toJSON !== 'function') {\n\n        Date.prototype.toJSON = function (key) {\n\n            return isFinite(this.valueOf()) ?\n                   this.getUTCFullYear()   + '-' +\n                 f(this.getUTCMonth() + 1) + '-' +\n                 f(this.getUTCDate())      + 'T' +\n                 f(this.getUTCHours())     + ':' +\n                 f(this.getUTCMinutes())   + ':' +\n                 f(this.getUTCSeconds())   + 'Z' : null;\n        };\n\n        String.prototype.toJSON =\n        Number.prototype.toJSON =\n        Boolean.prototype.toJSON = function (key) {\n            return this.valueOf();\n        };\n    }\n\n    var cx = /[\\u0000\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g,\n        escapable = /[\\\\\\\"\\x00-\\x1f\\x7f-\\x9f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g,\n        gap,\n        indent,\n        meta = {    // table of character substitutions\n            '\\b': '\\\\b',\n            '\\t': '\\\\t',\n            '\\n': '\\\\n',\n            '\\f': '\\\\f',\n            '\\r': '\\\\r',\n            '\"' : '\\\\\"',\n            '\\\\': '\\\\\\\\'\n        },\n        rep;\n\n\n    function quote(string) {\n\n// If the string contains no control characters, no quote characters, and no\n// backslash characters, then we can safely slap some quotes around it.\n// Otherwise we must also replace the offending characters with safe escape\n// sequences.\n\n        escapable.lastIndex = 0;\n        return escapable.test(string) ?\n            '\"' + string.replace(escapable, function (a) {\n                var c = meta[a];\n                return typeof c === 'string' ? c :\n                    '\\\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);\n            }) + '\"' :\n            '\"' + string + '\"';\n    }\n\n\n    function str(key, holder) {\n\n// Produce a string from holder[key].\n\n        var i,          // The loop counter.\n            k,          // The member key.\n            v,          // The member value.\n            length,\n            mind = gap,\n            partial,\n            value = holder[key];\n\n// If the value has a toJSON method, call it to obtain a replacement value.\n\n        if (value && typeof value === 'object' &&\n                typeof value.toJSON === 'function') {\n            value = value.toJSON(key);\n        }\n\n// If we were called with a replacer function, then call the replacer to\n// obtain a replacement value.\n\n        if (typeof rep === 'function') {\n            value = rep.call(holder, key, value);\n        }\n\n// What happens next depends on the value's type.\n\n        switch (typeof value) {\n        case 'string':\n            return quote(value);\n\n        case 'number':\n\n// JSON numbers must be finite. Encode non-finite numbers as null.\n\n            return isFinite(value) ? String(value) : 'null';\n\n        case 'boolean':\n        case 'null':\n\n// If the value is a boolean or null, convert it to a string. Note:\n// typeof null does not produce 'null'. The case is included here in\n// the remote chance that this gets fixed someday.\n\n            return String(value);\n\n// If the type is 'object', we might be dealing with an object or an array or\n// null.\n\n        case 'object':\n\n// Due to a specification blunder in ECMAScript, typeof null is 'object',\n// so watch out for that case.\n\n            if (!value) {\n                return 'null';\n            }\n\n// Make an array to hold the partial results of stringifying this object value.\n\n            gap += indent;\n            partial = [];\n\n// Is the value an array?\n\n            if (Object.prototype.toString.apply(value) === '[object Array]') {\n\n// The value is an array. Stringify every element. Use null as a placeholder\n// for non-JSON values.\n\n                length = value.length;\n                for (i = 0; i < length; i += 1) {\n                    partial[i] = str(i, value) || 'null';\n                }\n\n// Join all of the elements together, separated with commas, and wrap them in\n// brackets.\n\n                v = partial.length === 0 ? '[]' :\n                    gap ? '[\\n' + gap +\n                            partial.join(',\\n' + gap) + '\\n' +\n                                mind + ']' :\n                          '[' + partial.join(',') + ']';\n                gap = mind;\n                return v;\n            }\n\n// If the replacer is an array, use it to select the members to be stringified.\n\n            if (rep && typeof rep === 'object') {\n                length = rep.length;\n                for (i = 0; i < length; i += 1) {\n                    k = rep[i];\n                    if (typeof k === 'string') {\n                        v = str(k, value);\n                        if (v) {\n                            partial.push(quote(k) + (gap ? ': ' : ':') + v);\n                        }\n                    }\n                }\n            } else {\n\n// Otherwise, iterate through all of the keys in the object.\n\n                for (k in value) {\n                    if (Object.hasOwnProperty.call(value, k)) {\n                        v = str(k, value);\n                        if (v) {\n                            partial.push(quote(k) + (gap ? ': ' : ':') + v);\n                        }\n                    }\n                }\n            }\n\n// Join all of the member texts together, separated with commas,\n// and wrap them in braces.\n\n            v = partial.length === 0 ? '{}' :\n                gap ? '{\\n' + gap + partial.join(',\\n' + gap) + '\\n' +\n                        mind + '}' : '{' + partial.join(',') + '}';\n            gap = mind;\n            return v;\n        }\n    }\n\n// If the JSON object does not yet have a stringify method, give it one.\n\n    if (typeof JSON.stringify !== 'function') {\n        JSON.stringify = function (value, replacer, space) {\n\n// The stringify method takes a value and an optional replacer, and an optional\n// space parameter, and returns a JSON text. The replacer can be a function\n// that can replace values, or an array of strings that will select the keys.\n// A default replacer method can be provided. Use of the space parameter can\n// produce text that is more easily readable.\n\n            var i;\n            gap = '';\n            indent = '';\n\n// If the space parameter is a number, make an indent string containing that\n// many spaces.\n\n            if (typeof space === 'number') {\n                for (i = 0; i < space; i += 1) {\n                    indent += ' ';\n                }\n\n// If the space parameter is a string, it will be used as the indent string.\n\n            } else if (typeof space === 'string') {\n                indent = space;\n            }\n\n// If there is a replacer, it must be a function or an array.\n// Otherwise, throw an error.\n\n            rep = replacer;\n            if (replacer && typeof replacer !== 'function' &&\n                    (typeof replacer !== 'object' ||\n                     typeof replacer.length !== 'number')) {\n                throw new Error('JSON.stringify');\n            }\n\n// Make a fake root object containing our value under the key of ''.\n// Return the result of stringifying the value.\n\n            return str('', {'': value});\n        };\n    }\n\n\n// If the JSON object does not yet have a parse method, give it one.\n\n    if (typeof JSON.parse !== 'function') {\n        JSON.parse = function (text, reviver) {\n\n// The parse method takes a text and an optional reviver function, and returns\n// a JavaScript value if the text is a valid JSON text.\n\n            var j;\n\n            function walk(holder, key) {\n\n// The walk method is used to recursively walk the resulting structure so\n// that modifications can be made.\n\n                var k, v, value = holder[key];\n                if (value && typeof value === 'object') {\n                    for (k in value) {\n                        if (Object.hasOwnProperty.call(value, k)) {\n                            v = walk(value, k);\n                            if (v !== undefined) {\n                                value[k] = v;\n                            } else {\n                                delete value[k];\n                            }\n                        }\n                    }\n                }\n                return reviver.call(holder, key, value);\n            }\n\n\n// Parsing happens in four stages. In the first stage, we replace certain\n// Unicode characters with escape sequences. JavaScript handles many characters\n// incorrectly, either silently deleting them, or treating them as line endings.\n\n            text = String(text);\n            cx.lastIndex = 0;\n            if (cx.test(text)) {\n                text = text.replace(cx, function (a) {\n                    return '\\\\u' +\n                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);\n                });\n            }\n\n// In the second stage, we run the text against regular expressions that look\n// for non-JSON patterns. We are especially concerned with '()' and 'new'\n// because they can cause invocation, and '=' because it can cause mutation.\n// But just to be safe, we want to reject all unexpected forms.\n\n// We split the second stage into 4 regexp operations in order to work around\n// crippling inefficiencies in IE's and Safari's regexp engines. First we\n// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we\n// replace all simple value tokens with ']' characters. Third, we delete all\n// open brackets that follow a colon or comma or that begin the text. Finally,\n// we look to see that the remaining characters are only whitespace or ']' or\n// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.\n\n            if (/^[\\],:{}\\s]*$/\n.test(text.replace(/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')\n.replace(/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g, ']')\n.replace(/(?:^|:|,)(?:\\s*\\[)+/g, ''))) {\n\n// In the third stage we use the eval function to compile the text into a\n// JavaScript structure. The '{' operator is subject to a syntactic ambiguity\n// in JavaScript: it can begin a block or an object literal. We wrap the text\n// in parens to eliminate the ambiguity.\n\n                j = eval('(' + text + ')');\n\n// In the optional fourth stage, we recursively walk the new structure, passing\n// each name/value pair to a reviver function for possible transformation.\n\n                return typeof reviver === 'function' ?\n                    walk({'': j}, '') : j;\n            }\n\n// If the text is not JSON parseable, then a SyntaxError is thrown.\n\n            throw new SyntaxError('JSON.parse');\n        };\n    }\n}());\n"
  },
  {
    "path": "public/javascripts/jstoolbar/jstoolbar.js",
    "content": "/* ***** BEGIN LICENSE BLOCK *****\n * This file is part of DotClear.\n * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All\n * rights reserved.\n *\n * DotClear is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * DotClear is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with DotClear; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n *\n * ***** END LICENSE BLOCK *****\n*/\n\n/* Modified by JP LANG for textile formatting */\n\nfunction jsToolBar(textarea) {\n  if (!document.createElement) { return; }\n\n  if (!textarea) { return; }\n\n  if ((typeof(document[\"selection\"]) == \"undefined\")\n  && (typeof(textarea[\"setSelectionRange\"]) == \"undefined\")) {\n    return;\n  }\n\n  this.textarea = textarea;\n\n  this.editor = document.createElement('div');\n  this.editor.className = 'jstEditor';\n\n  this.textarea.parentNode.insertBefore(this.editor,this.textarea);\n  this.editor.appendChild(this.textarea);\n\n  this.toolbar = document.createElement(\"div\");\n  this.toolbar.className = 'jstElements';\n  this.editor.parentNode.insertBefore(this.toolbar,this.editor);\n\n  // Dragable resizing (only for gecko)\n  if (this.editor.addEventListener)\n  {\n    this.handle = document.createElement('div');\n    this.handle.className = 'jstHandle';\n    var dragStart = this.resizeDragStart;\n    var This = this;\n    this.handle.addEventListener('mousedown',function(event) { dragStart.call(This,event); },false);\n    // fix memory leak in Firefox (bug #241518)\n    window.addEventListener('unload',function() {\n        var del = This.handle.parentNode.removeChild(This.handle);\n        delete(This.handle);\n    },false);\n\n    this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling);\n  }\n\n  this.context = null;\n  this.toolNodes = {}; // lorsque la toolbar est dessinée , cet objet est garni\n          // de raccourcis vers les éléments DOM correspondants aux outils.\n}\n\nfunction jsButton(title, fn, scope, className) {\n    if(typeof jsToolBar.strings == 'undefined') {\n      this.title = title || null;\n    } else {\n      this.title = jsToolBar.strings[title] || title || null;\n    }\n  this.fn = fn || function(){};\n  this.scope = scope || null;\n  this.className = className || null;\n}\njsButton.prototype.draw = function() {\n  if (!this.scope) return null;\n\n  var button = document.createElement('button');\n  button.setAttribute('type','button');\n  button.tabIndex = 200;\n  if (this.className) button.className = this.className;\n  button.title = this.title;\n  var span = document.createElement('span');\n  span.appendChild(document.createTextNode(this.title));\n  button.appendChild(span);\n\n  if (this.icon != undefined) {\n    button.style.backgroundImage = 'url('+this.icon+')';\n  }\n  if (typeof(this.fn) == 'function') {\n    var This = this;\n    button.onclick = function() { try { This.fn.apply(This.scope, arguments) } catch (e) {} return false; };\n  }\n  return button;\n}\n\nfunction jsSpace(id) {\n  this.id = id || null;\n  this.width = null;\n}\njsSpace.prototype.draw = function() {\n  var span = document.createElement('span');\n  if (this.id) span.id = this.id;\n  span.appendChild(document.createTextNode(String.fromCharCode(160)));\n  span.className = 'jstSpacer';\n  if (this.width) span.style.marginRight = this.width+'px';\n\n  return span;\n}\n\nfunction jsCombo(title, options, scope, fn, className) {\n  this.title = title || null;\n  this.options = options || null;\n  this.scope = scope || null;\n  this.fn = fn || function(){};\n  this.className = className || null;\n}\njsCombo.prototype.draw = function() {\n  if (!this.scope || !this.options) return null;\n\n  var select = document.createElement('select');\n  if (this.className) select.className = className;\n  select.title = this.title;\n\n  for (var o in this.options) {\n    //var opt = this.options[o];\n    var option = document.createElement('option');\n    option.value = o;\n    option.appendChild(document.createTextNode(this.options[o]));\n    select.appendChild(option);\n  }\n\n  var This = this;\n  select.onchange = function() {\n    try {\n      This.fn.call(This.scope, this.value);\n    } catch (e) { alert(e); }\n\n    return false;\n  }\n\n  return select;\n}\n\n\njsToolBar.prototype = {\n  base_url: '',\n  mode: 'wiki',\n  elements: {},\n  help_link: '',\n\n  getMode: function() {\n    return this.mode;\n  },\n\n  setMode: function(mode) {\n    this.mode = mode || 'wiki';\n  },\n\n  switchMode: function(mode) {\n    mode = mode || 'wiki';\n    this.draw(mode);\n  },\n\n  setHelpLink: function(link) {\n    this.help_link = link;\n  },\n\n  button: function(toolName) {\n    var tool = this.elements[toolName];\n    if (typeof tool.fn[this.mode] != 'function') return null;\n    var b = new jsButton(tool.title, tool.fn[this.mode], this, 'jstb_'+toolName);\n    if (tool.icon != undefined) b.icon = tool.icon;\n    return b;\n  },\n  space: function(toolName) {\n    var tool = new jsSpace(toolName)\n    if (this.elements[toolName].width !== undefined)\n      tool.width = this.elements[toolName].width;\n    return tool;\n  },\n  combo: function(toolName) {\n    var tool = this.elements[toolName];\n    var length = tool[this.mode].list.length;\n\n    if (typeof tool[this.mode].fn != 'function' || length == 0) {\n      return null;\n    } else {\n      var options = {};\n      for (var i=0; i < length; i++) {\n        var opt = tool[this.mode].list[i];\n        options[opt] = tool.options[opt];\n      }\n      return new jsCombo(tool.title, options, this, tool[this.mode].fn);\n    }\n  },\n  draw: function(mode) {\n    this.setMode(mode);\n\n    // Empty toolbar\n    while (this.toolbar.hasChildNodes()) {\n      this.toolbar.removeChild(this.toolbar.firstChild)\n    }\n    this.toolNodes = {}; // vide les raccourcis DOM/**/\n\n    var h = document.createElement('div');\n    h.className = 'help'\n    h.innerHTML = this.help_link;\n    '<a href=\"/help/wiki_syntax.html\" onclick=\"window.open(\\'/help/wiki_syntax.html\\', \\'\\', \\'resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes\\'); return false;\">Aide</a>';\n    this.toolbar.appendChild(h);\n\n    // Draw toolbar elements\n    var b, tool, newTool;\n\n    for (var i in this.elements) {\n      b = this.elements[i];\n\n      var disabled =\n      b.type == undefined || b.type == ''\n      || (b.disabled != undefined && b.disabled)\n      || (b.context != undefined && b.context != null && b.context != this.context);\n\n      if (!disabled && typeof this[b.type] == 'function') {\n        tool = this[b.type](i);\n        if (tool) newTool = tool.draw();\n        if (newTool) {\n          this.toolNodes[i] = newTool; //mémorise l'accès DOM pour usage éventuel ultérieur\n          this.toolbar.appendChild(newTool);\n        }\n      }\n    }\n  },\n\n  singleTag: function(stag,etag) {\n    stag = stag || null;\n    etag = etag || stag;\n\n    if (!stag || !etag) { return; }\n\n    this.encloseSelection(stag,etag);\n  },\n\n  encloseLineSelection: function(prefix, suffix, fn) {\n    this.textarea.focus();\n\n    prefix = prefix || '';\n    suffix = suffix || '';\n\n    var start, end, sel, scrollPos, subst, res;\n\n    if (typeof(document[\"selection\"]) != \"undefined\") {\n      sel = document.selection.createRange().text;\n    } else if (typeof(this.textarea[\"setSelectionRange\"]) != \"undefined\") {\n      start = this.textarea.selectionStart;\n      end = this.textarea.selectionEnd;\n      scrollPos = this.textarea.scrollTop;\n      // go to the start of the line\n      start = this.textarea.value.substring(0, start).replace(/[^\\r\\n]*$/g,'').length;\n      // go to the end of the line\n            end = this.textarea.value.length - this.textarea.value.substring(end, this.textarea.value.length).replace(/^[^\\r\\n]*/, '').length;\n      sel = this.textarea.value.substring(start, end);\n    }\n\n    if (sel.match(/ $/)) { // exclude ending space char, if any\n      sel = sel.substring(0, sel.length - 1);\n      suffix = suffix + \" \";\n    }\n\n    if (typeof(fn) == 'function') {\n      res = (sel) ? fn.call(this,sel) : fn('');\n    } else {\n      res = (sel) ? sel : '';\n    }\n\n    subst = prefix + res + suffix;\n\n    if (typeof(document[\"selection\"]) != \"undefined\") {\n      document.selection.createRange().text = subst;\n      var range = this.textarea.createTextRange();\n      range.collapse(false);\n      range.move('character', -suffix.length);\n      range.select();\n    } else if (typeof(this.textarea[\"setSelectionRange\"]) != \"undefined\") {\n      this.textarea.value = this.textarea.value.substring(0, start) + subst +\n      this.textarea.value.substring(end);\n      if (sel) {\n        this.textarea.setSelectionRange(start + subst.length, start + subst.length);\n      } else {\n        this.textarea.setSelectionRange(start + prefix.length, start + prefix.length);\n      }\n      this.textarea.scrollTop = scrollPos;\n    }\n  },\n\n  encloseSelection: function(prefix, suffix, fn) {\n    this.textarea.focus();\n\n    prefix = prefix || '';\n    suffix = suffix || '';\n\n    var start, end, sel, scrollPos, subst, res;\n\n    if (typeof(document[\"selection\"]) != \"undefined\") {\n      sel = document.selection.createRange().text;\n    } else if (typeof(this.textarea[\"setSelectionRange\"]) != \"undefined\") {\n      start = this.textarea.selectionStart;\n      end = this.textarea.selectionEnd;\n      scrollPos = this.textarea.scrollTop;\n      sel = this.textarea.value.substring(start, end);\n    }\n\n    if (sel.match(/ $/)) { // exclude ending space char, if any\n      sel = sel.substring(0, sel.length - 1);\n      suffix = suffix + \" \";\n    }\n\n    if (typeof(fn) == 'function') {\n      res = (sel) ? fn.call(this,sel) : fn('');\n    } else {\n      res = (sel) ? sel : '';\n    }\n\n    subst = prefix + res + suffix;\n\n    if (typeof(document[\"selection\"]) != \"undefined\") {\n      document.selection.createRange().text = subst;\n      var range = this.textarea.createTextRange();\n      range.collapse(false);\n      range.move('character', -suffix.length);\n      range.select();\n//      this.textarea.caretPos -= suffix.length;\n    } else if (typeof(this.textarea[\"setSelectionRange\"]) != \"undefined\") {\n      this.textarea.value = this.textarea.value.substring(0, start) + subst +\n      this.textarea.value.substring(end);\n      if (sel) {\n        this.textarea.setSelectionRange(start + subst.length, start + subst.length);\n      } else {\n        this.textarea.setSelectionRange(start + prefix.length, start + prefix.length);\n      }\n      this.textarea.scrollTop = scrollPos;\n    }\n  },\n\n  stripBaseURL: function(url) {\n    if (this.base_url != '') {\n      var pos = url.indexOf(this.base_url);\n      if (pos == 0) {\n        url = url.substr(this.base_url.length);\n      }\n    }\n\n    return url;\n  }\n};\n\n/** Resizer\n-------------------------------------------------------- */\njsToolBar.prototype.resizeSetStartH = function() {\n  this.dragStartH = this.textarea.offsetHeight + 0;\n};\njsToolBar.prototype.resizeDragStart = function(event) {\n  var This = this;\n  this.dragStartY = event.clientY;\n  this.resizeSetStartH();\n  document.addEventListener('mousemove', this.dragMoveHdlr=function(event){This.resizeDragMove(event);}, false);\n  document.addEventListener('mouseup', this.dragStopHdlr=function(event){This.resizeDragStop(event);}, false);\n};\n\njsToolBar.prototype.resizeDragMove = function(event) {\n  this.textarea.style.height = (this.dragStartH+event.clientY-this.dragStartY)+'px';\n};\n\njsToolBar.prototype.resizeDragStop = function(event) {\n  document.removeEventListener('mousemove', this.dragMoveHdlr, false);\n  document.removeEventListener('mouseup', this.dragStopHdlr, false);\n};\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-bg.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Strong';\njsToolBar.strings['Italic'] = 'Italic';\njsToolBar.strings['Underline'] = 'Underline';\njsToolBar.strings['Deleted'] = 'Deleted';\njsToolBar.strings['Code'] = 'Inline Code';\njsToolBar.strings['Heading 1'] = 'Heading 1';\njsToolBar.strings['Heading 2'] = 'Heading 2';\njsToolBar.strings['Heading 3'] = 'Heading 3';\njsToolBar.strings['Unordered list'] = 'Unordered list';\njsToolBar.strings['Ordered list'] = 'Ordered list';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'Preformatted text';\njsToolBar.strings['Wiki link'] = 'Link to a Wiki page';\njsToolBar.strings['Image'] = 'Image';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-bs.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Strong';\njsToolBar.strings['Italic'] = 'Italic';\njsToolBar.strings['Underline'] = 'Underline';\njsToolBar.strings['Deleted'] = 'Deleted';\njsToolBar.strings['Code'] = 'Inline Code';\njsToolBar.strings['Heading 1'] = 'Heading 1';\njsToolBar.strings['Heading 2'] = 'Heading 2';\njsToolBar.strings['Heading 3'] = 'Heading 3';\njsToolBar.strings['Unordered list'] = 'Unordered list';\njsToolBar.strings['Ordered list'] = 'Ordered list';\njsToolBar.strings['Preformatted text'] = 'Preformatted text';\njsToolBar.strings['Wiki link'] = 'Link na Wiki stranicu';\njsToolBar.strings['Image'] = 'Slika';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-ca.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Negreta';\njsToolBar.strings['Italic'] = 'Cursiva';\njsToolBar.strings['Underline'] = 'Subratllat';\njsToolBar.strings['Deleted'] = 'Barrat';\njsToolBar.strings['Code'] = 'Codi en línia';\njsToolBar.strings['Heading 1'] = 'Encapçalament 1';\njsToolBar.strings['Heading 2'] = 'Encapçalament 2';\njsToolBar.strings['Heading 3'] = 'Encapçalament 3';\njsToolBar.strings['Unordered list'] = 'Llista sense ordre';\njsToolBar.strings['Ordered list'] = 'Llista ordenada';\njsToolBar.strings['Quote'] = 'Cometes';\njsToolBar.strings['Unquote'] = 'Sense cometes';\njsToolBar.strings['Preformatted text'] = 'Text formatat';\njsToolBar.strings['Wiki link'] = 'Enllaça a una pàgina Wiki';\njsToolBar.strings['Image'] = 'Imatge';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-cs.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Tučné';\njsToolBar.strings['Italic'] = 'Kurzíva';\njsToolBar.strings['Underline'] = 'Podtržené';\njsToolBar.strings['Deleted'] = 'Přeškrtnuté ';\njsToolBar.strings['Code'] = 'Zobrazení kódu';\njsToolBar.strings['Heading 1'] = 'Záhlaví 1';\njsToolBar.strings['Heading 2'] = 'Záhlaví 2';\njsToolBar.strings['Heading 3'] = 'Záhlaví 3';\njsToolBar.strings['Unordered list'] = 'Seznam';\njsToolBar.strings['Ordered list'] = 'Uspořádaný seznam';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'Předformátovaný text';\njsToolBar.strings['Wiki link'] = 'Vložit odkaz na Wiki stránku';\njsToolBar.strings['Image'] = 'Vložit obrázek';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-da.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Fed';\njsToolBar.strings['Italic'] = 'Kursiv';\njsToolBar.strings['Underline'] = 'Understreget';\njsToolBar.strings['Deleted'] = 'Slettet';\njsToolBar.strings['Code'] = 'Inline-kode';\njsToolBar.strings['Heading 1'] = 'Overskrift 1';\njsToolBar.strings['Heading 2'] = 'Overskrift 2';\njsToolBar.strings['Heading 3'] = 'Overskrift 3';\njsToolBar.strings['Unordered list'] = 'Unummereret liste';\njsToolBar.strings['Ordered list'] = 'Nummereret liste';\njsToolBar.strings['Quote'] = 'Citér';\njsToolBar.strings['Unquote'] = 'Fjern citér';\njsToolBar.strings['Preformatted text'] = 'Præformateret tekst';\njsToolBar.strings['Wiki link'] = 'Link til en wiki-side';\njsToolBar.strings['Image'] = 'Billede';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-de.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Fett';\njsToolBar.strings['Italic'] = 'Kursiv';\njsToolBar.strings['Underline'] = 'Unterstrichen';\njsToolBar.strings['Deleted'] = 'Durchgestrichen';\njsToolBar.strings['Code'] = 'Quelltext';\njsToolBar.strings['Heading 1'] = 'Überschrift 1. Ordnung';\njsToolBar.strings['Heading 2'] = 'Überschrift 2. Ordnung';\njsToolBar.strings['Heading 3'] = 'Überschrift 3. Ordnung';\njsToolBar.strings['Unordered list'] = 'Aufzählungsliste';\njsToolBar.strings['Ordered list'] = 'Nummerierte Liste';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'Präformatierter Text';\njsToolBar.strings['Wiki link'] = 'Verweis (Link) zu einer Wiki-Seite';\njsToolBar.strings['Image'] = 'Grafik';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-en.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Strong';\njsToolBar.strings['Italic'] = 'Italic';\njsToolBar.strings['Underline'] = 'Underline';\njsToolBar.strings['Deleted'] = 'Deleted';\njsToolBar.strings['Code'] = 'Inline Code';\njsToolBar.strings['Heading 1'] = 'Heading 1';\njsToolBar.strings['Heading 2'] = 'Heading 2';\njsToolBar.strings['Heading 3'] = 'Heading 3';\njsToolBar.strings['Unordered list'] = 'Unordered list';\njsToolBar.strings['Ordered list'] = 'Ordered list';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'Preformatted text';\njsToolBar.strings['Wiki link'] = 'Link to a Wiki page';\njsToolBar.strings['Image'] = 'Image';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-es.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Negrita';\njsToolBar.strings['Italic'] = 'Itálica';\njsToolBar.strings['Underline'] = 'Subrayado';\njsToolBar.strings['Deleted'] = 'Tachado';\njsToolBar.strings['Code'] = 'Código fuente';\njsToolBar.strings['Heading 1'] = 'Encabezado 1';\njsToolBar.strings['Heading 2'] = 'Encabezado 2';\njsToolBar.strings['Heading 3'] = 'Encabezado 3';\njsToolBar.strings['Unordered list'] = 'Lista sin ordenar';\njsToolBar.strings['Ordered list'] = 'Lista ordenada';\njsToolBar.strings['Quote'] = 'Citar';\njsToolBar.strings['Unquote'] = 'Quitar cita';\njsToolBar.strings['Preformatted text'] = 'Texto con formato';\njsToolBar.strings['Wiki link'] = 'Enlace a página Wiki';\njsToolBar.strings['Image'] = 'Imagen';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-fi.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Lihavoitu';\njsToolBar.strings['Italic'] = 'Kursivoitu';\njsToolBar.strings['Underline'] = 'Alleviivattu';\njsToolBar.strings['Deleted'] = 'Yliviivattu';\njsToolBar.strings['Code'] = 'Koodi näkymä';\njsToolBar.strings['Heading 1'] = 'Otsikko 1';\njsToolBar.strings['Heading 2'] = 'Otsikko 2';\njsToolBar.strings['Heading 3'] = 'Otsikko 3';\njsToolBar.strings['Unordered list'] = 'Järjestämätön lista';\njsToolBar.strings['Ordered list'] = 'Järjestetty lista';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'Ennaltamuotoiltu teksti';\njsToolBar.strings['Wiki link'] = 'Linkki Wiki sivulle';\njsToolBar.strings['Image'] = 'Kuva';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-fr.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Gras';\njsToolBar.strings['Italic'] = 'Italique';\njsToolBar.strings['Underline'] = 'Souligné';\njsToolBar.strings['Deleted'] = 'Rayé';\njsToolBar.strings['Code'] = 'Code en ligne';\njsToolBar.strings['Heading 1'] = 'Titre niveau 1';\njsToolBar.strings['Heading 2'] = 'Titre niveau 2';\njsToolBar.strings['Heading 3'] = 'Titre niveau 3';\njsToolBar.strings['Unordered list'] = 'Liste à puces';\njsToolBar.strings['Ordered list'] = 'Liste numérotée';\njsToolBar.strings['Quote'] = 'Citer';\njsToolBar.strings['Unquote'] = 'Supprimer citation';\njsToolBar.strings['Preformatted text'] = 'Texte préformaté';\njsToolBar.strings['Wiki link'] = 'Lien vers une page Wiki';\njsToolBar.strings['Image'] = 'Image';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-gl.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Negriña';\njsToolBar.strings['Italic'] = 'Itálica';\njsToolBar.strings['Underline'] = 'Suliñado';\njsToolBar.strings['Deleted'] = 'Tachado';\njsToolBar.strings['Code'] = 'Código fonte';\njsToolBar.strings['Heading 1'] = 'Encabezado 1';\njsToolBar.strings['Heading 2'] = 'Encabezado 2';\njsToolBar.strings['Heading 3'] = 'Encabezado 3';\njsToolBar.strings['Unordered list'] = 'Lista sen ordenar';\njsToolBar.strings['Ordered list'] = 'Lista ordenada';\njsToolBar.strings['Quote'] = 'Citar';\njsToolBar.strings['Unquote'] = 'Quitar cita';\njsToolBar.strings['Preformatted text'] = 'Texto con formato';\njsToolBar.strings['Wiki link'] = 'Enlace a páxina Wiki';\njsToolBar.strings['Image'] = 'Imaxe';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-he.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Strong';\njsToolBar.strings['Italic'] = 'Italic';\njsToolBar.strings['Underline'] = 'Underline';\njsToolBar.strings['Deleted'] = 'Deleted';\njsToolBar.strings['Code'] = 'Inline Code';\njsToolBar.strings['Heading 1'] = 'Heading 1';\njsToolBar.strings['Heading 2'] = 'Heading 2';\njsToolBar.strings['Heading 3'] = 'Heading 3';\njsToolBar.strings['Unordered list'] = 'Unordered list';\njsToolBar.strings['Ordered list'] = 'Ordered list';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'Preformatted text';\njsToolBar.strings['Wiki link'] = 'Link to a Wiki page';\njsToolBar.strings['Image'] = 'Image';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-hu.js",
    "content": "﻿jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Félkövér';\njsToolBar.strings['Italic'] = 'Dőlt';\njsToolBar.strings['Underline'] = 'Aláhúzott';\njsToolBar.strings['Deleted'] = 'Törölt';\njsToolBar.strings['Code'] = 'Kód sorok';\njsToolBar.strings['Heading 1'] = 'Fejléc 1';\njsToolBar.strings['Heading 2'] = 'Fejléc 2';\njsToolBar.strings['Heading 3'] = 'Fejléc 3';\njsToolBar.strings['Unordered list'] = 'Felsorolás';\njsToolBar.strings['Ordered list'] = 'Számozott lista';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'Előreformázott szöveg';\njsToolBar.strings['Wiki link'] = 'Link egy Wiki oldalra';\njsToolBar.strings['Image'] = 'Kép';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-id.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Tebal';\njsToolBar.strings['Italic'] = 'Miring';\njsToolBar.strings['Underline'] = 'Garis bawah';\njsToolBar.strings['Deleted'] = 'Dihapus';\njsToolBar.strings['Code'] = 'Inline Code';\njsToolBar.strings['Heading 1'] = 'Judul 1';\njsToolBar.strings['Heading 2'] = 'Judul 2';\njsToolBar.strings['Heading 3'] = 'Judul 3';\njsToolBar.strings['Unordered list'] = 'Daftar tak terurut';\njsToolBar.strings['Ordered list'] = 'Daftar terurut';\njsToolBar.strings['Quote'] = 'Kutipan';\njsToolBar.strings['Unquote'] = 'Hapus kutipan';\njsToolBar.strings['Preformatted text'] = 'Teks terformat';\njsToolBar.strings['Wiki link'] = 'Tautkan ke halaman wiki';\njsToolBar.strings['Image'] = 'Gambar';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-it.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Grassetto';\njsToolBar.strings['Italic'] = 'Corsivo';\njsToolBar.strings['Underline'] = 'Sottolineato';\njsToolBar.strings['Deleted'] = 'Barrato';\njsToolBar.strings['Code'] = 'Codice sorgente';\njsToolBar.strings['Heading 1'] = 'Titolo 1';\njsToolBar.strings['Heading 2'] = 'Titolo 2';\njsToolBar.strings['Heading 3'] = 'Titolo 3';\njsToolBar.strings['Unordered list'] = 'Elenco puntato';\njsToolBar.strings['Ordered list'] = 'Numerazione';\njsToolBar.strings['Quote'] = 'Aumenta rientro';\njsToolBar.strings['Unquote'] = 'Riduci rientro';\njsToolBar.strings['Preformatted text'] = 'Testo preformattato';\njsToolBar.strings['Wiki link'] = 'Collegamento a pagina Wiki';\njsToolBar.strings['Image'] = 'Immagine';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-ja.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = '強調';\njsToolBar.strings['Italic'] = '斜体';\njsToolBar.strings['Underline'] = '下線';\njsToolBar.strings['Deleted'] = '取り消し線';\njsToolBar.strings['Code'] = 'コード';\njsToolBar.strings['Heading 1'] = '見出し 1';\njsToolBar.strings['Heading 2'] = '見出し 2';\njsToolBar.strings['Heading 3'] = '見出し 3';\njsToolBar.strings['Unordered list'] = '順不同リスト';\njsToolBar.strings['Ordered list'] = '番号つきリスト';\njsToolBar.strings['Quote'] = '引用';\njsToolBar.strings['Unquote'] = '引用解除';\njsToolBar.strings['Preformatted text'] = '整形済みテキスト';\njsToolBar.strings['Wiki link'] = 'Wikiページへのリンク';\njsToolBar.strings['Image'] = '画像';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-ko.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = '굵게';\njsToolBar.strings['Italic'] = '기울임';\njsToolBar.strings['Underline'] = '밑줄';\njsToolBar.strings['Deleted'] = '취소선';\njsToolBar.strings['Code'] = '코드';\njsToolBar.strings['Heading 1'] = '제목 1';\njsToolBar.strings['Heading 2'] = '제목 2';\njsToolBar.strings['Heading 3'] = '제목 3';\njsToolBar.strings['Unordered list'] = '글머리 기호';\njsToolBar.strings['Ordered list'] = '번호 매기기';\njsToolBar.strings['Quote'] = '인용';\njsToolBar.strings['Unquote'] = '인용 취소';\njsToolBar.strings['Preformatted text'] = '있는 그대로 표현 (Preformatted text)';\njsToolBar.strings['Wiki link'] = 'Wiki 페이지에 연결';\njsToolBar.strings['Image'] = '그림';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-lt.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Pastorinti';\njsToolBar.strings['Italic'] = 'Italic';\njsToolBar.strings['Underline'] = 'Pabraukti';\njsToolBar.strings['Deleted'] = 'Užbraukti';\njsToolBar.strings['Code'] = 'Kodas';\njsToolBar.strings['Heading 1'] = 'Heading 1';\njsToolBar.strings['Heading 2'] = 'Heading 2';\njsToolBar.strings['Heading 3'] = 'Heading 3';\njsToolBar.strings['Unordered list'] = 'Nenumeruotas sąrašas';\njsToolBar.strings['Ordered list'] = 'Numeruotas sąrašas';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'Preformatuotas tekstas';\njsToolBar.strings['Wiki link'] = 'Nuoroda į Wiki puslapį';\njsToolBar.strings['Image'] = 'Paveikslas';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-mk.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Strong';\njsToolBar.strings['Italic'] = 'Italic';\njsToolBar.strings['Underline'] = 'Underline';\njsToolBar.strings['Deleted'] = 'Deleted';\njsToolBar.strings['Code'] = 'Inline Code';\njsToolBar.strings['Heading 1'] = 'Heading 1';\njsToolBar.strings['Heading 2'] = 'Heading 2';\njsToolBar.strings['Heading 3'] = 'Heading 3';\njsToolBar.strings['Unordered list'] = 'Unordered list';\njsToolBar.strings['Ordered list'] = 'Подредена листа';\njsToolBar.strings['Quote'] = 'Цитат';\njsToolBar.strings['Unquote'] = 'Отстрани цитат';\njsToolBar.strings['Preformatted text'] = 'Preformatted text';\njsToolBar.strings['Wiki link'] = 'Линк до вики страна';\njsToolBar.strings['Image'] = 'Слика';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-nl.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Extra nadruk';\njsToolBar.strings['Italic'] = 'Cursief';\njsToolBar.strings['Underline'] = 'Onderstreept';\njsToolBar.strings['Deleted'] = 'Verwijderd';\njsToolBar.strings['Code'] = 'Computercode';\njsToolBar.strings['Heading 1'] = 'Kop 1';\njsToolBar.strings['Heading 2'] = 'Kop 2';\njsToolBar.strings['Heading 3'] = 'Kop 3';\njsToolBar.strings['Unordered list'] = 'Ongeordende lijst';\njsToolBar.strings['Ordered list'] = 'Geordende lijst';\njsToolBar.strings['Quote'] = 'Citaat';\njsToolBar.strings['Unquote'] = 'Verwijder citaat';\njsToolBar.strings['Preformatted text'] = 'Voor-geformateerde tekst';\njsToolBar.strings['Wiki link'] = 'Link naar een Wiki pagina';\njsToolBar.strings['Image'] = 'Afbeelding';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-no.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Fet';\njsToolBar.strings['Italic'] = 'Kursiv';\njsToolBar.strings['Underline'] = 'Understreking';\njsToolBar.strings['Deleted'] = 'Slettet';\njsToolBar.strings['Code'] = 'Kode';\njsToolBar.strings['Heading 1'] = 'Overskrift 1';\njsToolBar.strings['Heading 2'] = 'Overskrift 2';\njsToolBar.strings['Heading 3'] = 'Overskrift 3';\njsToolBar.strings['Unordered list'] = 'Punktliste';\njsToolBar.strings['Ordered list'] = 'Nummerert liste';\njsToolBar.strings['Quote'] = 'Sitat';\njsToolBar.strings['Unquote'] = 'Avslutt sitat';\njsToolBar.strings['Preformatted text'] = 'Preformatert tekst';\njsToolBar.strings['Wiki link'] = 'Lenke til Wiki-side';\njsToolBar.strings['Image'] = 'Bilde';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-pl.js",
    "content": "﻿// Keep this line in order to avoid problems with Windows Notepad UTF-8 EF-BB-BF idea...\njsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Pogrubienie';\njsToolBar.strings['Italic'] = 'Kursywa';\njsToolBar.strings['Underline'] = 'Podkreślenie';\njsToolBar.strings['Deleted'] = 'Usunięte';\njsToolBar.strings['Code'] = 'Wstawka kodu';\njsToolBar.strings['Heading 1'] = 'Nagłowek 1';\njsToolBar.strings['Heading 2'] = 'Nagłówek 2';\njsToolBar.strings['Heading 3'] = 'Nagłówek 3';\njsToolBar.strings['Unordered list'] = 'Nieposortowana lista';\njsToolBar.strings['Ordered list'] = 'Posortowana lista';\njsToolBar.strings['Quote'] = 'Cytat';\njsToolBar.strings['Unquote'] = 'Usuń cytat';\njsToolBar.strings['Preformatted text'] = 'Sformatowany tekst';\njsToolBar.strings['Wiki link'] = 'Odnośnik do strony Wiki';\njsToolBar.strings['Image'] = 'Obraz';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-pt-br.js",
    "content": "// Translated by: Alexandre da Silva <simpsomboy@gmail.com>\n\njsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Negrito';\njsToolBar.strings['Italic'] = 'Itálico';\njsToolBar.strings['Underline'] = 'Sublinhado';\njsToolBar.strings['Deleted'] = 'Excluído';\njsToolBar.strings['Code'] = 'Código Inline';\njsToolBar.strings['Heading 1'] = 'Cabeçalho 1';\njsToolBar.strings['Heading 2'] = 'Cabeçalho 2';\njsToolBar.strings['Heading 3'] = 'Cabeçalho 3';\njsToolBar.strings['Unordered list'] = 'Lista não ordenada';\njsToolBar.strings['Ordered list'] = 'Lista ordenada';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'Texto pré-formatado';\njsToolBar.strings['Wiki link'] = 'Link para uma página Wiki';\njsToolBar.strings['Image'] = 'Imagem';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-pt.js",
    "content": "// Translated by: Pedro Araújo <phcrva19@hotmail.com>\njsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Negrito';\njsToolBar.strings['Italic'] = 'Itálico';\njsToolBar.strings['Underline'] = 'Sublinhado';\njsToolBar.strings['Deleted'] = 'Apagado';\njsToolBar.strings['Code'] = 'Código Inline';\njsToolBar.strings['Heading 1'] = 'Cabeçalho 1';\njsToolBar.strings['Heading 2'] = 'Cabeçalho 2';\njsToolBar.strings['Heading 3'] = 'Cabeçalho 3';\njsToolBar.strings['Unordered list'] = 'Lista não ordenada';\njsToolBar.strings['Ordered list'] = 'Lista ordenada';\njsToolBar.strings['Quote'] = 'Citação';\njsToolBar.strings['Unquote'] = 'Remover citação';\njsToolBar.strings['Preformatted text'] = 'Texto pré-formatado';\njsToolBar.strings['Wiki link'] = 'Link para uma página da Wiki';\njsToolBar.strings['Image'] = 'Imagem';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-ro.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Bold';\njsToolBar.strings['Italic'] = 'Italic';\njsToolBar.strings['Underline'] = 'Subliniat';\njsToolBar.strings['Deleted'] = 'Șters';\njsToolBar.strings['Code'] = 'Fragment de cod';\njsToolBar.strings['Heading 1'] = 'Heading 1';\njsToolBar.strings['Heading 2'] = 'Heading 2';\njsToolBar.strings['Heading 3'] = 'Heading 3';\njsToolBar.strings['Unordered list'] = 'Listă pe puncte';\njsToolBar.strings['Ordered list'] = 'Listă ordonată';\njsToolBar.strings['Quote'] = 'Citează';\njsToolBar.strings['Unquote'] = 'Fără citat';\njsToolBar.strings['Preformatted text'] = 'Text preformatat';\njsToolBar.strings['Wiki link'] = 'Trimitere către o pagină wiki';\njsToolBar.strings['Image'] = 'Imagine';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-ru.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Жирный';\njsToolBar.strings['Italic'] = 'Курсив';\njsToolBar.strings['Underline'] = 'Подчеркнутый';\njsToolBar.strings['Deleted'] = 'Зачеркнутый';\njsToolBar.strings['Code'] = 'Вставка кода';\njsToolBar.strings['Heading 1'] = 'Заголовок 1';\njsToolBar.strings['Heading 2'] = 'Заголовок 2';\njsToolBar.strings['Heading 3'] = 'Заголовок 3';\njsToolBar.strings['Unordered list'] = 'Маркированный список';\njsToolBar.strings['Ordered list'] = 'Нумерованный список';\njsToolBar.strings['Quote'] = 'Цитата';\njsToolBar.strings['Unquote'] = 'Удалить цитату';\njsToolBar.strings['Preformatted text'] = 'Заранее форматированный текст';\njsToolBar.strings['Wiki link'] = 'Ссылка на страницу в Wiki';\njsToolBar.strings['Image'] = 'Вставка изображения';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-sk.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Tučné';\njsToolBar.strings['Italic'] = 'Kurzíva';\njsToolBar.strings['Underline'] = 'Podčiarknuté';\njsToolBar.strings['Deleted'] = 'Preškrtnuté';\njsToolBar.strings['Code'] = 'Zobrazenie kódu';\njsToolBar.strings['Heading 1'] = 'Záhlavie 1';\njsToolBar.strings['Heading 2'] = 'Záhlavie 2';\njsToolBar.strings['Heading 3'] = 'Záhlavie 3';\njsToolBar.strings['Unordered list'] = 'Zoznam';\njsToolBar.strings['Ordered list'] = 'Zoradený zoznam';\njsToolBar.strings['Quote'] = 'Citácia';\njsToolBar.strings['Unquote'] = 'Odstránenie citácie';\njsToolBar.strings['Preformatted text'] = 'Predformátovaný text';\njsToolBar.strings['Wiki link'] = 'Link na Wiki stránku';\njsToolBar.strings['Image'] = 'Obrázok';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-sl.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Krepko';\njsToolBar.strings['Italic'] = 'Poševno';\njsToolBar.strings['Underline'] = 'Podčrtano';\njsToolBar.strings['Deleted'] = 'Izbrisano';\njsToolBar.strings['Code'] = 'Koda med vrsticami';\njsToolBar.strings['Heading 1'] = 'Naslov 1';\njsToolBar.strings['Heading 2'] = 'Naslov 2';\njsToolBar.strings['Heading 3'] = 'Naslov 3';\njsToolBar.strings['Unordered list'] = 'Neurejen seznam';\njsToolBar.strings['Ordered list'] = 'Urejen seznam';\njsToolBar.strings['Quote'] = 'Citat';\njsToolBar.strings['Unquote'] = 'Odstrani citat';\njsToolBar.strings['Preformatted text'] = 'Predoblikovano besedilo';\njsToolBar.strings['Wiki link'] = 'Povezava na Wiki stran';\njsToolBar.strings['Image'] = 'Slika';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-sr.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Strong';\njsToolBar.strings['Italic'] = 'Italic';\njsToolBar.strings['Underline'] = 'Underline';\njsToolBar.strings['Deleted'] = 'Deleted';\njsToolBar.strings['Code'] = 'Inline Code';\njsToolBar.strings['Heading 1'] = 'Heading 1';\njsToolBar.strings['Heading 2'] = 'Heading 2';\njsToolBar.strings['Heading 3'] = 'Heading 3';\njsToolBar.strings['Unordered list'] = 'Unordered list';\njsToolBar.strings['Ordered list'] = 'Ordered list';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'Preformatted text';\njsToolBar.strings['Wiki link'] = 'Link to a Wiki page';\njsToolBar.strings['Image'] = 'Image';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-sv.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Fet';\njsToolBar.strings['Italic'] = 'Kursiv';\njsToolBar.strings['Underline'] = 'Understruken';\njsToolBar.strings['Deleted'] = 'Genomstruken';\njsToolBar.strings['Code'] = 'Kod';\njsToolBar.strings['Heading 1'] = 'Rubrik 1';\njsToolBar.strings['Heading 2'] = 'Rubrik 2';\njsToolBar.strings['Heading 3'] = 'Rubrik 3';\njsToolBar.strings['Unordered list'] = 'Osorterad lista';\njsToolBar.strings['Ordered list'] = 'Sorterad lista';\njsToolBar.strings['Quote'] = 'Citat';\njsToolBar.strings['Unquote'] = 'Ta bort citat';\njsToolBar.strings['Preformatted text'] = 'Förformaterad text';\njsToolBar.strings['Wiki link'] = 'Länk till en wikisida';\njsToolBar.strings['Image'] = 'Bild';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-th.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'หนา';\njsToolBar.strings['Italic'] = 'เอียง';\njsToolBar.strings['Underline'] = 'ขีดเส้นใต้';\njsToolBar.strings['Deleted'] = 'ขีดฆ่า';\njsToolBar.strings['Code'] = 'โค๊ดโปรแกรม';\njsToolBar.strings['Heading 1'] = 'หัวข้อ 1';\njsToolBar.strings['Heading 2'] = 'หัวข้อ 2';\njsToolBar.strings['Heading 3'] = 'หัวข้อ 3';\njsToolBar.strings['Unordered list'] = 'รายการ';\njsToolBar.strings['Ordered list'] = 'ลำดับเลข';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'รูปแบบข้อความคงที่';\njsToolBar.strings['Wiki link'] = 'เชื่อมโยงไปหน้า Wiki อื่น';\njsToolBar.strings['Image'] = 'รูปภาพ';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-tr.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Kalın';\njsToolBar.strings['Italic'] = 'İtalik';\njsToolBar.strings['Underline'] = 'Altı çizgili';\njsToolBar.strings['Deleted'] = 'Silinmiş';\njsToolBar.strings['Code'] = 'Satır içi kod';\njsToolBar.strings['Heading 1'] = 'Başlık 1';\njsToolBar.strings['Heading 2'] = 'Başlık 2';\njsToolBar.strings['Heading 3'] = 'Başlık 3';\njsToolBar.strings['Unordered list'] = 'Sırasız liste';\njsToolBar.strings['Ordered list'] = 'Sıralı liste';\njsToolBar.strings['Preformatted text'] = 'Preformatted text';\njsToolBar.strings['Wiki link'] = 'Wiki sayfasına bağlantı';\njsToolBar.strings['Image'] = 'Resim';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-uk.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Strong';\njsToolBar.strings['Italic'] = 'Italic';\njsToolBar.strings['Underline'] = 'Underline';\njsToolBar.strings['Deleted'] = 'Deleted';\njsToolBar.strings['Code'] = 'Inline Code';\njsToolBar.strings['Heading 1'] = 'Heading 1';\njsToolBar.strings['Heading 2'] = 'Heading 2';\njsToolBar.strings['Heading 3'] = 'Heading 3';\njsToolBar.strings['Unordered list'] = 'Unordered list';\njsToolBar.strings['Ordered list'] = 'Ordered list';\njsToolBar.strings['Quote'] = 'Quote';\njsToolBar.strings['Unquote'] = 'Remove Quote';\njsToolBar.strings['Preformatted text'] = 'Preformatted text';\njsToolBar.strings['Wiki link'] = 'Link to a Wiki page';\njsToolBar.strings['Image'] = 'Image';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-vi.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = 'Đậm';\njsToolBar.strings['Italic'] = 'Nghiêng';\njsToolBar.strings['Underline'] = 'Gạch chân';\njsToolBar.strings['Deleted'] = 'Xóa';\njsToolBar.strings['Code'] = 'Mã chung dòng';\njsToolBar.strings['Heading 1'] = 'Tiêu đề 1';\njsToolBar.strings['Heading 2'] = 'Tiêu đề 2';\njsToolBar.strings['Heading 3'] = 'Tiêu đề 3';\njsToolBar.strings['Unordered list'] = 'Danh sách không thứ tự';\njsToolBar.strings['Ordered list'] = 'Danh sách có thứ tự';\njsToolBar.strings['Quote'] = 'Trích dẫn';\njsToolBar.strings['Unquote'] = 'Bỏ trích dẫn';\njsToolBar.strings['Preformatted text'] = 'Mã nguồn';\njsToolBar.strings['Wiki link'] = 'Liên kết đến trang wiki';\njsToolBar.strings['Image'] = 'Ảnh';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-zh-tw.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = '粗體';\njsToolBar.strings['Italic'] = '斜體';\njsToolBar.strings['Underline'] = '底線';\njsToolBar.strings['Deleted'] = '刪除線';\njsToolBar.strings['Code'] = '程式碼';\njsToolBar.strings['Heading 1'] = '標題 1';\njsToolBar.strings['Heading 2'] = '標題 2';\njsToolBar.strings['Heading 3'] = '標題 3';\njsToolBar.strings['Unordered list'] = '項目清單';\njsToolBar.strings['Ordered list'] = '編號清單';\njsToolBar.strings['Quote'] = '引文';\njsToolBar.strings['Unquote'] = '取消引文';\njsToolBar.strings['Preformatted text'] = '已格式文字';\njsToolBar.strings['Wiki link'] = '連結至 Wiki 頁面';\njsToolBar.strings['Image'] = '圖片';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/lang/jstoolbar-zh.js",
    "content": "jsToolBar.strings = {};\njsToolBar.strings['Strong'] = '粗体';\njsToolBar.strings['Italic'] = '斜体';\njsToolBar.strings['Underline'] = '下划线';\njsToolBar.strings['Deleted'] = '删除线';\njsToolBar.strings['Code'] = '程序代码';\njsToolBar.strings['Heading 1'] = '标题 1';\njsToolBar.strings['Heading 2'] = '标题 2';\njsToolBar.strings['Heading 3'] = '标题 3';\njsToolBar.strings['Unordered list'] = '无序列表';\njsToolBar.strings['Ordered list'] = '排序列表';\njsToolBar.strings['Quote'] = '引用';\njsToolBar.strings['Unquote'] = '删除引用';\njsToolBar.strings['Preformatted text'] = '格式化文本';\njsToolBar.strings['Wiki link'] = '连接到 Wiki 页面';\njsToolBar.strings['Image'] = '图片';\n"
  },
  {
    "path": "public/javascripts/jstoolbar/textile.js",
    "content": "/* ***** BEGIN LICENSE BLOCK *****\n * This file is part of DotClear.\n * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All\n * rights reserved.\n *\n * DotClear is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * DotClear is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with DotClear; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n *\n * ***** END LICENSE BLOCK *****\n*/\n\n/* Modified by JP LANG for textile formatting */\n\n// strong\njsToolBar.prototype.elements.strong = {\n  type: 'button',\n  title: 'Strong',\n  fn: {\n    wiki: function() { this.singleTag('*') }\n  }\n}\n\n// em\njsToolBar.prototype.elements.em = {\n  type: 'button',\n  title: 'Italic',\n  fn: {\n    wiki: function() { this.singleTag(\"_\") }\n  }\n}\n\n// ins\njsToolBar.prototype.elements.ins = {\n  type: 'button',\n  title: 'Underline',\n  fn: {\n    wiki: function() { this.singleTag('+') }\n  }\n}\n\n// del\njsToolBar.prototype.elements.del = {\n  type: 'button',\n  title: 'Deleted',\n  fn: {\n    wiki: function() { this.singleTag('-') }\n  }\n}\n\n// code\njsToolBar.prototype.elements.code = {\n  type: 'button',\n  title: 'Code',\n  fn: {\n    wiki: function() { this.singleTag('@') }\n  }\n}\n\n// spacer\njsToolBar.prototype.elements.space1 = {type: 'space'}\n\n// headings\njsToolBar.prototype.elements.h1 = {\n  type: 'button',\n  title: 'Heading 1',\n  fn: {\n    wiki: function() {\n      this.encloseLineSelection('h1. ', '',function(str) {\n        str = str.replace(/^h\\d+\\.\\s+/, '')\n        return str;\n      });\n    }\n  }\n}\njsToolBar.prototype.elements.h2 = {\n  type: 'button',\n  title: 'Heading 2',\n  fn: {\n    wiki: function() {\n      this.encloseLineSelection('h2. ', '',function(str) {\n        str = str.replace(/^h\\d+\\.\\s+/, '')\n        return str;\n      });\n    }\n  }\n}\njsToolBar.prototype.elements.h3 = {\n  type: 'button',\n  title: 'Heading 3',\n  fn: {\n    wiki: function() {\n      this.encloseLineSelection('h3. ', '',function(str) {\n        str = str.replace(/^h\\d+\\.\\s+/, '')\n        return str;\n      });\n    }\n  }\n}\n\n// spacer\njsToolBar.prototype.elements.space2 = {type: 'space'}\n\n// ul\njsToolBar.prototype.elements.ul = {\n  type: 'button',\n  title: 'Unordered list',\n  fn: {\n    wiki: function() {\n      this.encloseLineSelection('','',function(str) {\n        str = str.replace(/\\r/g,'');\n        return str.replace(/(\\n|^)[#-]?\\s*/g,\"$1* \");\n      });\n    }\n  }\n}\n\n// ol\njsToolBar.prototype.elements.ol = {\n  type: 'button',\n  title: 'Ordered list',\n  fn: {\n    wiki: function() {\n      this.encloseLineSelection('','',function(str) {\n        str = str.replace(/\\r/g,'');\n        return str.replace(/(\\n|^)[*-]?\\s*/g,\"$1# \");\n      });\n    }\n  }\n}\n\n// spacer\njsToolBar.prototype.elements.space3 = {type: 'space'}\n\n// bq\njsToolBar.prototype.elements.bq = {\n  type: 'button',\n  title: 'Quote',\n  fn: {\n    wiki: function() {\n      this.encloseLineSelection('','',function(str) {\n        str = str.replace(/\\r/g,'');\n        return str.replace(/(\\n|^) *([^\\n]*)/g,\"$1> $2\");\n      });\n    }\n  }\n}\n\n// unbq\njsToolBar.prototype.elements.unbq = {\n  type: 'button',\n  title: 'Unquote',\n  fn: {\n    wiki: function() {\n      this.encloseLineSelection('','',function(str) {\n        str = str.replace(/\\r/g,'');\n        return str.replace(/(\\n|^) *[>]? *([^\\n]*)/g,\"$1$2\");\n      });\n    }\n  }\n}\n\n// pre\njsToolBar.prototype.elements.pre = {\n  type: 'button',\n  title: 'Preformatted text',\n  fn: {\n    wiki: function() { this.encloseLineSelection('<pre>\\n', '\\n</pre>') }\n  }\n}\n\n// spacer\njsToolBar.prototype.elements.space4 = {type: 'space'}\n\n// wiki page\njsToolBar.prototype.elements.link = {\n  type: 'button',\n  title: 'Wiki link',\n  fn: {\n    wiki: function() { this.encloseSelection(\"[[\", \"]]\") }\n  }\n}\n// image\njsToolBar.prototype.elements.img = {\n  type: 'button',\n  title: 'Image',\n  fn: {\n    wiki: function() { this.encloseSelection(\"!\", \"!\") }\n  }\n}\n"
  },
  {
    "path": "public/javascripts/lightbox.js",
    "content": "/*\nCreated By: Chris Campbell\nWebsite: http://particletree.com\nDate: 2/1/2006\n\nInspired by the lightbox implementation found at http://www.huddletogether.com/projects/lightbox/\n*/\n\n/*-------------------------------GLOBAL VARIABLES------------------------------------*/\n\nvar detect = navigator.userAgent.toLowerCase();\nvar OS,browser,version,total,thestring;\n\n/*-----------------------------------------------------------------------------------------------*/\n\n//Browser detect script origionally created by Peter Paul Koch at http://www.quirksmode.org/\n\nfunction getBrowserInfo() {\n  if (checkIt('konqueror')) {\n    browser = \"Konqueror\";\n    OS = \"Linux\";\n  }\n  else if (checkIt('safari')) browser   = \"Safari\"\n  else if (checkIt('omniweb')) browser   = \"OmniWeb\"\n  else if (checkIt('opera')) browser     = \"Opera\"\n  else if (checkIt('webtv')) browser     = \"WebTV\";\n  else if (checkIt('icab')) browser     = \"iCab\"\n  else if (checkIt('msie')) browser     = \"Internet Explorer\"\n  else if (!checkIt('compatible')) {\n    browser = \"Netscape Navigator\"\n    version = detect.charAt(8);\n  }\n  else browser = \"An unknown browser\";\n\n  if (!version) version = detect.charAt(place + thestring.length);\n\n  if (!OS) {\n    if (checkIt('linux')) OS     = \"Linux\";\n    else if (checkIt('x11')) OS   = \"Unix\";\n    else if (checkIt('mac')) OS   = \"Mac\"\n    else if (checkIt('win')) OS   = \"Windows\"\n    else OS                 = \"an unknown operating system\";\n  }\n}\n\nfunction checkIt(string) {\n  place = detect.indexOf(string) + 1;\n  thestring = string;\n  return place;\n}\n\n/*-----------------------------------------------------------------------------------------------*/\n\nEvent.observe(window, 'load', initialize, false);\nEvent.observe(window, 'load', getBrowserInfo, false);\nEvent.observe(window, 'unload', Event.unloadCache, false);\n\nvar lightbox = Class.create();\n\nlightbox.prototype = {\n\n  yPos : 0,\n  xPos : 0,\n\n  initialize: function(ctrl) {\n    this.content = ctrl.href;\n    Event.observe(ctrl, 'click', this.activate.bindAsEventListener(this), false);\n    ctrl.onclick = function(){return false;};\n  },\n\n  // Turn everything on - mainly the IE fixes\n  activate: function(){\n    if (browser == 'Internet Explorer'){\n      this.getScroll();\n      this.prepareIE('100%', 'hidden');\n      this.setScroll(0,0);\n      this.hideSelects('hidden');\n    }\n    this.displayLightbox(\"block\");\n  },\n\n  // Ie requires height to 100% and overflow hidden or else you can scroll down past the lightbox\n  prepareIE: function(height, overflow){\n    bod = document.getElementsByTagName('body')[0];\n    bod.style.height = height;\n    bod.style.overflow = overflow;\n\n    htm = document.getElementsByTagName('html')[0];\n    htm.style.height = height;\n    htm.style.overflow = overflow;\n  },\n\n  // In IE, select elements hover on top of the lightbox\n  hideSelects: function(visibility){\n    selects = document.getElementsByTagName('select');\n    for(i = 0; i < selects.length; i++) {\n      selects[i].style.visibility = visibility;\n    }\n  },\n\n  // Taken from lightbox implementation found at http://www.huddletogether.com/projects/lightbox/\n  getScroll: function(){\n    if (self.pageYOffset) {\n      this.yPos = self.pageYOffset;\n    } else if (document.documentElement && document.documentElement.scrollTop){\n      this.yPos = document.documentElement.scrollTop;\n    } else if (document.body) {\n      this.yPos = document.body.scrollTop;\n    }\n  },\n\n  setScroll: function(x, y){\n    window.scrollTo(x, y);\n  },\n\n  displayLightbox: function(display){\n    $('overlay').style.display = display;\n    $('lightbox').style.display = display;\n    if(display != 'none') this.loadInfo();\n  },\n\n  // Begin Ajax request based off of the href of the clicked linked\n  loadInfo: function() {\n    var myAjax = new Ajax.Request(\n        this.content,\n        {method: 'post', parameters: \"\", onComplete: this.processInfo.bindAsEventListener(this)}\n    );\n\n  },\n\n  // Display Ajax response\n  processInfo: function(response){\n    info = \"<div id='lbContent'>\" + response.responseText + \"</div>\";\n    new Insertion.Before($('lbLoadMessage'), info)\n    $('lightbox').className = \"done\";\n    this.actions();\n  },\n\n  // Search through new links within the lightbox, and attach click event\n  actions: function(){\n    lbActions = document.getElementsByClassName('lbAction');\n\n    for(i = 0; i < lbActions.length; i++) {\n      Event.observe(lbActions[i], 'click', this[lbActions[i].rel].bindAsEventListener(this), false);\n      lbActions[i].onclick = function(){return false;};\n    }\n\n  },\n\n  // Example of creating your own functionality once lightbox is initiated\n  insert: function(e){\n     link = Event.element(e).parentNode;\n     Element.remove($('lbContent'));\n\n     var myAjax = new Ajax.Request(\n        link.href,\n        {method: 'post', parameters: \"\", onComplete: this.processInfo.bindAsEventListener(this)}\n     );\n\n  },\n\n  // Example of creating your own functionality once lightbox is initiated\n  deactivate: function(){\n    Element.remove($('lbContent'));\n\n    if (browser == \"Internet Explorer\"){\n      this.setScroll(0,this.yPos);\n      this.prepareIE(\"auto\", \"auto\");\n      this.hideSelects(\"visible\");\n    }\n\n    this.displayLightbox(\"none\");\n  }\n}\n\n/*-----------------------------------------------------------------------------------------------*/\n\n// Onload, make all links that need to trigger a lightbox active\nfunction initialize(){\n  addLightboxMarkup();\n  lbox = document.getElementsByClassName('lbOn');\n  for(i = 0; i < lbox.length; i++) {\n    valid = new lightbox(lbox[i]);\n  }\n}\n\n// Add in markup necessary to make this work. Basically two divs:\n// Overlay holds the shadow\n// Lightbox is the centered square that the content is put into.\nfunction addLightboxMarkup() {\n  bod         = document.getElementsByTagName('body')[0];\n  overlay       = document.createElement('div');\n  overlay.id    = 'overlay';\n  lb          = document.createElement('div');\n  lb.id        = 'lightbox';\n  lb.className   = 'loading';\n  lb.innerHTML  = '<div id=\"lbLoadMessage\">' +\n              '<p>Loading</p>' +\n              '</div>';\n  bod.appendChild(overlay);\n  bod.appendChild(lb);\n}\n\n// Added from http://javathehutt.blogspot.com/2006/07/rails-realities-part-15-ajax-modal.html\n\nfunction add_lightbox(id) {\n  // dismiss();\n  try{\n  value = new lightbox($(id));\n  }\n  catch(err){}\n}\n\nfunction dismiss() {\n  try{\n  lightbox.prototype.deactivate();\n  if(browser == 'Internet Explorer') {\n    // this is here because lightbox doesn't scroll IE after dismissing after we post forms\n    window.scrollTo(0, lightbox.prototype.getYPos());\n  }\n}\ncatch(err){}\n}\n"
  },
  {
    "path": "public/javascripts/prototype.js",
    "content": "/*  Prototype JavaScript framework, version 1.6.0.3\n *  (c) 2005-2008 Sam Stephenson\n *\n *  Prototype is freely distributable under the terms of an MIT-style license.\n *  For details, see the Prototype web site: http://www.prototypejs.org/\n *\n *--------------------------------------------------------------------------*/\n\nvar Prototype = {\n  Version: '1.6.0.3',\n\n  Browser: {\n    IE:     !!(window.attachEvent &&\n      navigator.userAgent.indexOf('Opera') === -1),\n    Opera:  navigator.userAgent.indexOf('Opera') > -1,\n    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,\n    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 &&\n      navigator.userAgent.indexOf('KHTML') === -1,\n    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)\n  },\n\n  BrowserFeatures: {\n    XPath: !!document.evaluate,\n    SelectorsAPI: !!document.querySelector,\n    ElementExtensions: !!window.HTMLElement,\n    SpecificElementExtensions:\n      document.createElement('div')['__proto__'] &&\n      document.createElement('div')['__proto__'] !==\n        document.createElement('form')['__proto__']\n  },\n\n  ScriptFragment: '<script[^>]*>([\\\\S\\\\s]*?)<\\/script>',\n  JSONFilter: /^\\/\\*-secure-([\\s\\S]*)\\*\\/\\s*$/,\n\n  emptyFunction: function() { },\n  K: function(x) { return x }\n};\n\nif (Prototype.Browser.MobileSafari)\n  Prototype.BrowserFeatures.SpecificElementExtensions = false;\n\n\n/* Based on Alex Arnell's inheritance implementation. */\nvar Class = {\n  create: function() {\n    var parent = null, properties = $A(arguments);\n    if (Object.isFunction(properties[0]))\n      parent = properties.shift();\n\n    function klass() {\n      this.initialize.apply(this, arguments);\n    }\n\n    Object.extend(klass, Class.Methods);\n    klass.superclass = parent;\n    klass.subclasses = [];\n\n    if (parent) {\n      var subclass = function() { };\n      subclass.prototype = parent.prototype;\n      klass.prototype = new subclass;\n      parent.subclasses.push(klass);\n    }\n\n    for (var i = 0; i < properties.length; i++)\n      klass.addMethods(properties[i]);\n\n    if (!klass.prototype.initialize)\n      klass.prototype.initialize = Prototype.emptyFunction;\n\n    klass.prototype.constructor = klass;\n\n    return klass;\n  }\n};\n\nClass.Methods = {\n  addMethods: function(source) {\n    var ancestor   = this.superclass && this.superclass.prototype;\n    var properties = Object.keys(source);\n\n    if (!Object.keys({ toString: true }).length)\n      properties.push(\"toString\", \"valueOf\");\n\n    for (var i = 0, length = properties.length; i < length; i++) {\n      var property = properties[i], value = source[property];\n      if (ancestor && Object.isFunction(value) &&\n          value.argumentNames().first() == \"$super\") {\n        var method = value;\n        value = (function(m) {\n          return function() { return ancestor[m].apply(this, arguments) };\n        })(property).wrap(method);\n\n        value.valueOf = method.valueOf.bind(method);\n        value.toString = method.toString.bind(method);\n      }\n      this.prototype[property] = value;\n    }\n\n    return this;\n  }\n};\n\nvar Abstract = { };\n\nObject.extend = function(destination, source) {\n  for (var property in source)\n    destination[property] = source[property];\n  return destination;\n};\n\nObject.extend(Object, {\n  inspect: function(object) {\n    try {\n      if (Object.isUndefined(object)) return 'undefined';\n      if (object === null) return 'null';\n      return object.inspect ? object.inspect() : String(object);\n    } catch (e) {\n      if (e instanceof RangeError) return '...';\n      throw e;\n    }\n  },\n\n  toJSON: function(object) {\n    var type = typeof object;\n    switch (type) {\n      case 'undefined':\n      case 'function':\n      case 'unknown': return;\n      case 'boolean': return object.toString();\n    }\n\n    if (object === null) return 'null';\n    if (object.toJSON) return object.toJSON();\n    if (Object.isElement(object)) return;\n\n    var results = [];\n    for (var property in object) {\n      var value = Object.toJSON(object[property]);\n      if (!Object.isUndefined(value))\n        results.push(property.toJSON() + ': ' + value);\n    }\n\n    return '{' + results.join(', ') + '}';\n  },\n\n  toQueryString: function(object) {\n    return $H(object).toQueryString();\n  },\n\n  toHTML: function(object) {\n    return object && object.toHTML ? object.toHTML() : String.interpret(object);\n  },\n\n  keys: function(object) {\n    var keys = [];\n    for (var property in object)\n      keys.push(property);\n    return keys;\n  },\n\n  values: function(object) {\n    var values = [];\n    for (var property in object)\n      values.push(object[property]);\n    return values;\n  },\n\n  clone: function(object) {\n    return Object.extend({ }, object);\n  },\n\n  isElement: function(object) {\n    return !!(object && object.nodeType == 1);\n  },\n\n  isArray: function(object) {\n    return object != null && typeof object == \"object\" &&\n      'splice' in object && 'join' in object;\n  },\n\n  isHash: function(object) {\n    return object instanceof Hash;\n  },\n\n  isFunction: function(object) {\n    return typeof object == \"function\";\n  },\n\n  isString: function(object) {\n    return typeof object == \"string\";\n  },\n\n  isNumber: function(object) {\n    return typeof object == \"number\";\n  },\n\n  isUndefined: function(object) {\n    return typeof object == \"undefined\";\n  }\n});\n\nObject.extend(Function.prototype, {\n  argumentNames: function() {\n    var names = this.toString().match(/^[\\s\\(]*function[^(]*\\(([^\\)]*)\\)/)[1]\n      .replace(/\\s+/g, '').split(',');\n    return names.length == 1 && !names[0] ? [] : names;\n  },\n\n  bind: function() {\n    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;\n    var __method = this, args = $A(arguments), object = args.shift();\n    return function() {\n      return __method.apply(object, args.concat($A(arguments)));\n    }\n  },\n\n  bindAsEventListener: function() {\n    var __method = this, args = $A(arguments), object = args.shift();\n    return function(event) {\n      return __method.apply(object, [event || window.event].concat(args));\n    }\n  },\n\n  curry: function() {\n    if (!arguments.length) return this;\n    var __method = this, args = $A(arguments);\n    return function() {\n      return __method.apply(this, args.concat($A(arguments)));\n    }\n  },\n\n  delay: function() {\n    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;\n    return window.setTimeout(function() {\n      return __method.apply(__method, args);\n    }, timeout);\n  },\n\n  defer: function() {\n    var args = [0.01].concat($A(arguments));\n    return this.delay.apply(this, args);\n  },\n\n  wrap: function(wrapper) {\n    var __method = this;\n    return function() {\n      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));\n    }\n  },\n\n  methodize: function() {\n    if (this._methodized) return this._methodized;\n    var __method = this;\n    return this._methodized = function() {\n      return __method.apply(null, [this].concat($A(arguments)));\n    };\n  }\n});\n\nDate.prototype.toJSON = function() {\n  return '\"' + this.getUTCFullYear() + '-' +\n    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +\n    this.getUTCDate().toPaddedString(2) + 'T' +\n    this.getUTCHours().toPaddedString(2) + ':' +\n    this.getUTCMinutes().toPaddedString(2) + ':' +\n    this.getUTCSeconds().toPaddedString(2) + 'Z\"';\n};\n\nvar Try = {\n  these: function() {\n    var returnValue;\n\n    for (var i = 0, length = arguments.length; i < length; i++) {\n      var lambda = arguments[i];\n      try {\n        returnValue = lambda();\n        break;\n      } catch (e) { }\n    }\n\n    return returnValue;\n  }\n};\n\nRegExp.prototype.match = RegExp.prototype.test;\n\nRegExp.escape = function(str) {\n  return String(str).replace(/([.*+?^=!:${}()|[\\]\\/\\\\])/g, '\\\\$1');\n};\n\n/*--------------------------------------------------------------------------*/\n\nvar PeriodicalExecuter = Class.create({\n  initialize: function(callback, frequency) {\n    this.callback = callback;\n    this.frequency = frequency;\n    this.currentlyExecuting = false;\n\n    this.registerCallback();\n  },\n\n  registerCallback: function() {\n    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);\n  },\n\n  execute: function() {\n    this.callback(this);\n  },\n\n  stop: function() {\n    if (!this.timer) return;\n    clearInterval(this.timer);\n    this.timer = null;\n  },\n\n  onTimerEvent: function() {\n    if (!this.currentlyExecuting) {\n      try {\n        this.currentlyExecuting = true;\n        this.execute();\n      } finally {\n        this.currentlyExecuting = false;\n      }\n    }\n  }\n});\nObject.extend(String, {\n  interpret: function(value) {\n    return value == null ? '' : String(value);\n  },\n  specialChar: {\n    '\\b': '\\\\b',\n    '\\t': '\\\\t',\n    '\\n': '\\\\n',\n    '\\f': '\\\\f',\n    '\\r': '\\\\r',\n    '\\\\': '\\\\\\\\'\n  }\n});\n\nObject.extend(String.prototype, {\n  gsub: function(pattern, replacement) {\n    var result = '', source = this, match;\n    replacement = arguments.callee.prepareReplacement(replacement);\n\n    while (source.length > 0) {\n      if (match = source.match(pattern)) {\n        result += source.slice(0, match.index);\n        result += String.interpret(replacement(match));\n        source  = source.slice(match.index + match[0].length);\n      } else {\n        result += source, source = '';\n      }\n    }\n    return result;\n  },\n\n  sub: function(pattern, replacement, count) {\n    replacement = this.gsub.prepareReplacement(replacement);\n    count = Object.isUndefined(count) ? 1 : count;\n\n    return this.gsub(pattern, function(match) {\n      if (--count < 0) return match[0];\n      return replacement(match);\n    });\n  },\n\n  scan: function(pattern, iterator) {\n    this.gsub(pattern, iterator);\n    return String(this);\n  },\n\n  truncate: function(length, truncation) {\n    length = length || 30;\n    truncation = Object.isUndefined(truncation) ? '...' : truncation;\n    return this.length > length ?\n      this.slice(0, length - truncation.length) + truncation : String(this);\n  },\n\n  strip: function() {\n    return this.replace(/^\\s+/, '').replace(/\\s+$/, '');\n  },\n\n  stripTags: function() {\n    return this.replace(/<\\/?[^>]+>/gi, '');\n  },\n\n  stripScripts: function() {\n    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');\n  },\n\n  extractScripts: function() {\n    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');\n    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');\n    return (this.match(matchAll) || []).map(function(scriptTag) {\n      return (scriptTag.match(matchOne) || ['', ''])[1];\n    });\n  },\n\n  evalScripts: function() {\n    return this.extractScripts().map(function(script) { return eval(script) });\n  },\n\n  escapeHTML: function() {\n    var self = arguments.callee;\n    self.text.data = this;\n    return self.div.innerHTML;\n  },\n\n  unescapeHTML: function() {\n    var div = new Element('div');\n    div.innerHTML = this.stripTags();\n    return div.childNodes[0] ? (div.childNodes.length > 1 ?\n      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :\n      div.childNodes[0].nodeValue) : '';\n  },\n\n  toQueryParams: function(separator) {\n    var match = this.strip().match(/([^?#]*)(#.*)?$/);\n    if (!match) return { };\n\n    return match[1].split(separator || '&').inject({ }, function(hash, pair) {\n      if ((pair = pair.split('='))[0]) {\n        var key = decodeURIComponent(pair.shift());\n        var value = pair.length > 1 ? pair.join('=') : pair[0];\n        if (value != undefined) value = decodeURIComponent(value);\n\n        if (key in hash) {\n          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];\n          hash[key].push(value);\n        }\n        else hash[key] = value;\n      }\n      return hash;\n    });\n  },\n\n  toArray: function() {\n    return this.split('');\n  },\n\n  succ: function() {\n    return this.slice(0, this.length - 1) +\n      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);\n  },\n\n  times: function(count) {\n    return count < 1 ? '' : new Array(count + 1).join(this);\n  },\n\n  camelize: function() {\n    var parts = this.split('-'), len = parts.length;\n    if (len == 1) return parts[0];\n\n    var camelized = this.charAt(0) == '-'\n      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)\n      : parts[0];\n\n    for (var i = 1; i < len; i++)\n      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);\n\n    return camelized;\n  },\n\n  capitalize: function() {\n    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();\n  },\n\n  underscore: function() {\n    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();\n  },\n\n  dasherize: function() {\n    return this.gsub(/_/,'-');\n  },\n\n  inspect: function(useDoubleQuotes) {\n    var escapedString = this.gsub(/[\\x00-\\x1f\\\\]/, function(match) {\n      var character = String.specialChar[match[0]];\n      return character ? character : '\\\\u00' + match[0].charCodeAt().toPaddedString(2, 16);\n    });\n    if (useDoubleQuotes) return '\"' + escapedString.replace(/\"/g, '\\\\\"') + '\"';\n    return \"'\" + escapedString.replace(/'/g, '\\\\\\'') + \"'\";\n  },\n\n  toJSON: function() {\n    return this.inspect(true);\n  },\n\n  unfilterJSON: function(filter) {\n    return this.sub(filter || Prototype.JSONFilter, '#{1}');\n  },\n\n  isJSON: function() {\n    var str = this;\n    if (str.blank()) return false;\n    str = this.replace(/\\\\./g, '@').replace(/\"[^\"\\\\\\n\\r]*\"/g, '');\n    return (/^[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t]*$/).test(str);\n  },\n\n  evalJSON: function(sanitize) {\n    var json = this.unfilterJSON();\n    try {\n      if (!sanitize || json.isJSON()) return eval('(' + json + ')');\n    } catch (e) { }\n    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());\n  },\n\n  include: function(pattern) {\n    return this.indexOf(pattern) > -1;\n  },\n\n  startsWith: function(pattern) {\n    return this.indexOf(pattern) === 0;\n  },\n\n  endsWith: function(pattern) {\n    var d = this.length - pattern.length;\n    return d >= 0 && this.lastIndexOf(pattern) === d;\n  },\n\n  empty: function() {\n    return this == '';\n  },\n\n  blank: function() {\n    return /^\\s*$/.test(this);\n  },\n\n  interpolate: function(object, pattern) {\n    return new Template(this, pattern).evaluate(object);\n  }\n});\n\nif (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {\n  escapeHTML: function() {\n    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');\n  },\n  unescapeHTML: function() {\n    return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');\n  }\n});\n\nString.prototype.gsub.prepareReplacement = function(replacement) {\n  if (Object.isFunction(replacement)) return replacement;\n  var template = new Template(replacement);\n  return function(match) { return template.evaluate(match) };\n};\n\nString.prototype.parseQuery = String.prototype.toQueryParams;\n\nObject.extend(String.prototype.escapeHTML, {\n  div:  document.createElement('div'),\n  text: document.createTextNode('')\n});\n\nString.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);\n\nvar Template = Class.create({\n  initialize: function(template, pattern) {\n    this.template = template.toString();\n    this.pattern = pattern || Template.Pattern;\n  },\n\n  evaluate: function(object) {\n    if (Object.isFunction(object.toTemplateReplacements))\n      object = object.toTemplateReplacements();\n\n    return this.template.gsub(this.pattern, function(match) {\n      if (object == null) return '';\n\n      var before = match[1] || '';\n      if (before == '\\\\') return match[2];\n\n      var ctx = object, expr = match[3];\n      var pattern = /^([^.[]+|\\[((?:.*?[^\\\\])?)\\])(\\.|\\[|$)/;\n      match = pattern.exec(expr);\n      if (match == null) return before;\n\n      while (match != null) {\n        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\\\\\]', ']') : match[1];\n        ctx = ctx[comp];\n        if (null == ctx || '' == match[3]) break;\n        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);\n        match = pattern.exec(expr);\n      }\n\n      return before + String.interpret(ctx);\n    });\n  }\n});\nTemplate.Pattern = /(^|.|\\r|\\n)(#\\{(.*?)\\})/;\n\nvar $break = { };\n\nvar Enumerable = {\n  each: function(iterator, context) {\n    var index = 0;\n    try {\n      this._each(function(value) {\n        iterator.call(context, value, index++);\n      });\n    } catch (e) {\n      if (e != $break) throw e;\n    }\n    return this;\n  },\n\n  eachSlice: function(number, iterator, context) {\n    var index = -number, slices = [], array = this.toArray();\n    if (number < 1) return array;\n    while ((index += number) < array.length)\n      slices.push(array.slice(index, index+number));\n    return slices.collect(iterator, context);\n  },\n\n  all: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var result = true;\n    this.each(function(value, index) {\n      result = result && !!iterator.call(context, value, index);\n      if (!result) throw $break;\n    });\n    return result;\n  },\n\n  any: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var result = false;\n    this.each(function(value, index) {\n      if (result = !!iterator.call(context, value, index))\n        throw $break;\n    });\n    return result;\n  },\n\n  collect: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var results = [];\n    this.each(function(value, index) {\n      results.push(iterator.call(context, value, index));\n    });\n    return results;\n  },\n\n  detect: function(iterator, context) {\n    var result;\n    this.each(function(value, index) {\n      if (iterator.call(context, value, index)) {\n        result = value;\n        throw $break;\n      }\n    });\n    return result;\n  },\n\n  findAll: function(iterator, context) {\n    var results = [];\n    this.each(function(value, index) {\n      if (iterator.call(context, value, index))\n        results.push(value);\n    });\n    return results;\n  },\n\n  grep: function(filter, iterator, context) {\n    iterator = iterator || Prototype.K;\n    var results = [];\n\n    if (Object.isString(filter))\n      filter = new RegExp(filter);\n\n    this.each(function(value, index) {\n      if (filter.match(value))\n        results.push(iterator.call(context, value, index));\n    });\n    return results;\n  },\n\n  include: function(object) {\n    if (Object.isFunction(this.indexOf))\n      if (this.indexOf(object) != -1) return true;\n\n    var found = false;\n    this.each(function(value) {\n      if (value == object) {\n        found = true;\n        throw $break;\n      }\n    });\n    return found;\n  },\n\n  inGroupsOf: function(number, fillWith) {\n    fillWith = Object.isUndefined(fillWith) ? null : fillWith;\n    return this.eachSlice(number, function(slice) {\n      while(slice.length < number) slice.push(fillWith);\n      return slice;\n    });\n  },\n\n  inject: function(memo, iterator, context) {\n    this.each(function(value, index) {\n      memo = iterator.call(context, memo, value, index);\n    });\n    return memo;\n  },\n\n  invoke: function(method) {\n    var args = $A(arguments).slice(1);\n    return this.map(function(value) {\n      return value[method].apply(value, args);\n    });\n  },\n\n  max: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var result;\n    this.each(function(value, index) {\n      value = iterator.call(context, value, index);\n      if (result == null || value >= result)\n        result = value;\n    });\n    return result;\n  },\n\n  min: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var result;\n    this.each(function(value, index) {\n      value = iterator.call(context, value, index);\n      if (result == null || value < result)\n        result = value;\n    });\n    return result;\n  },\n\n  partition: function(iterator, context) {\n    iterator = iterator || Prototype.K;\n    var trues = [], falses = [];\n    this.each(function(value, index) {\n      (iterator.call(context, value, index) ?\n        trues : falses).push(value);\n    });\n    return [trues, falses];\n  },\n\n  pluck: function(property) {\n    var results = [];\n    this.each(function(value) {\n      results.push(value[property]);\n    });\n    return results;\n  },\n\n  reject: function(iterator, context) {\n    var results = [];\n    this.each(function(value, index) {\n      if (!iterator.call(context, value, index))\n        results.push(value);\n    });\n    return results;\n  },\n\n  sortBy: function(iterator, context) {\n    return this.map(function(value, index) {\n      return {\n        value: value,\n        criteria: iterator.call(context, value, index)\n      };\n    }).sort(function(left, right) {\n      var a = left.criteria, b = right.criteria;\n      return a < b ? -1 : a > b ? 1 : 0;\n    }).pluck('value');\n  },\n\n  toArray: function() {\n    return this.map();\n  },\n\n  zip: function() {\n    var iterator = Prototype.K, args = $A(arguments);\n    if (Object.isFunction(args.last()))\n      iterator = args.pop();\n\n    var collections = [this].concat(args).map($A);\n    return this.map(function(value, index) {\n      return iterator(collections.pluck(index));\n    });\n  },\n\n  size: function() {\n    return this.toArray().length;\n  },\n\n  inspect: function() {\n    return '#<Enumerable:' + this.toArray().inspect() + '>';\n  }\n};\n\nObject.extend(Enumerable, {\n  map:     Enumerable.collect,\n  find:    Enumerable.detect,\n  select:  Enumerable.findAll,\n  filter:  Enumerable.findAll,\n  member:  Enumerable.include,\n  entries: Enumerable.toArray,\n  every:   Enumerable.all,\n  some:    Enumerable.any\n});\nfunction $A(iterable) {\n  if (!iterable) return [];\n  if (iterable.toArray) return iterable.toArray();\n  var length = iterable.length || 0, results = new Array(length);\n  while (length--) results[length] = iterable[length];\n  return results;\n}\n\nif (Prototype.Browser.WebKit) {\n  $A = function(iterable) {\n    if (!iterable) return [];\n    // In Safari, only use the `toArray` method if it's not a NodeList.\n    // A NodeList is a function, has an function `item` property, and a numeric\n    // `length` property. Adapted from Google Doctype.\n    if (!(typeof iterable === 'function' && typeof iterable.length ===\n        'number' && typeof iterable.item === 'function') && iterable.toArray)\n      return iterable.toArray();\n    var length = iterable.length || 0, results = new Array(length);\n    while (length--) results[length] = iterable[length];\n    return results;\n  };\n}\n\nArray.from = $A;\n\nObject.extend(Array.prototype, Enumerable);\n\nif (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;\n\nObject.extend(Array.prototype, {\n  _each: function(iterator) {\n    for (var i = 0, length = this.length; i < length; i++)\n      iterator(this[i]);\n  },\n\n  clear: function() {\n    this.length = 0;\n    return this;\n  },\n\n  first: function() {\n    return this[0];\n  },\n\n  last: function() {\n    return this[this.length - 1];\n  },\n\n  compact: function() {\n    return this.select(function(value) {\n      return value != null;\n    });\n  },\n\n  flatten: function() {\n    return this.inject([], function(array, value) {\n      return array.concat(Object.isArray(value) ?\n        value.flatten() : [value]);\n    });\n  },\n\n  without: function() {\n    var values = $A(arguments);\n    return this.select(function(value) {\n      return !values.include(value);\n    });\n  },\n\n  reverse: function(inline) {\n    return (inline !== false ? this : this.toArray())._reverse();\n  },\n\n  reduce: function() {\n    return this.length > 1 ? this : this[0];\n  },\n\n  uniq: function(sorted) {\n    return this.inject([], function(array, value, index) {\n      if (0 == index || (sorted ? array.last() != value : !array.include(value)))\n        array.push(value);\n      return array;\n    });\n  },\n\n  intersect: function(array) {\n    return this.uniq().findAll(function(item) {\n      return array.detect(function(value) { return item === value });\n    });\n  },\n\n  clone: function() {\n    return [].concat(this);\n  },\n\n  size: function() {\n    return this.length;\n  },\n\n  inspect: function() {\n    return '[' + this.map(Object.inspect).join(', ') + ']';\n  },\n\n  toJSON: function() {\n    var results = [];\n    this.each(function(object) {\n      var value = Object.toJSON(object);\n      if (!Object.isUndefined(value)) results.push(value);\n    });\n    return '[' + results.join(', ') + ']';\n  }\n});\n\n// use native browser JS 1.6 implementation if available\nif (Object.isFunction(Array.prototype.forEach))\n  Array.prototype._each = Array.prototype.forEach;\n\nif (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {\n  i || (i = 0);\n  var length = this.length;\n  if (i < 0) i = length + i;\n  for (; i < length; i++)\n    if (this[i] === item) return i;\n  return -1;\n};\n\nif (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {\n  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;\n  var n = this.slice(0, i).reverse().indexOf(item);\n  return (n < 0) ? n : i - n - 1;\n};\n\nArray.prototype.toArray = Array.prototype.clone;\n\nfunction $w(string) {\n  if (!Object.isString(string)) return [];\n  string = string.strip();\n  return string ? string.split(/\\s+/) : [];\n}\n\nif (Prototype.Browser.Opera){\n  Array.prototype.concat = function() {\n    var array = [];\n    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);\n    for (var i = 0, length = arguments.length; i < length; i++) {\n      if (Object.isArray(arguments[i])) {\n        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)\n          array.push(arguments[i][j]);\n      } else {\n        array.push(arguments[i]);\n      }\n    }\n    return array;\n  };\n}\nObject.extend(Number.prototype, {\n  toColorPart: function() {\n    return this.toPaddedString(2, 16);\n  },\n\n  succ: function() {\n    return this + 1;\n  },\n\n  times: function(iterator, context) {\n    $R(0, this, true).each(iterator, context);\n    return this;\n  },\n\n  toPaddedString: function(length, radix) {\n    var string = this.toString(radix || 10);\n    return '0'.times(length - string.length) + string;\n  },\n\n  toJSON: function() {\n    return isFinite(this) ? this.toString() : 'null';\n  }\n});\n\n$w('abs round ceil floor').each(function(method){\n  Number.prototype[method] = Math[method].methodize();\n});\nfunction $H(object) {\n  return new Hash(object);\n};\n\nvar Hash = Class.create(Enumerable, (function() {\n\n  function toQueryPair(key, value) {\n    if (Object.isUndefined(value)) return key;\n    return key + '=' + encodeURIComponent(String.interpret(value));\n  }\n\n  return {\n    initialize: function(object) {\n      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);\n    },\n\n    _each: function(iterator) {\n      for (var key in this._object) {\n        var value = this._object[key], pair = [key, value];\n        pair.key = key;\n        pair.value = value;\n        iterator(pair);\n      }\n    },\n\n    set: function(key, value) {\n      return this._object[key] = value;\n    },\n\n    get: function(key) {\n      // simulating poorly supported hasOwnProperty\n      if (this._object[key] !== Object.prototype[key])\n        return this._object[key];\n    },\n\n    unset: function(key) {\n      var value = this._object[key];\n      delete this._object[key];\n      return value;\n    },\n\n    toObject: function() {\n      return Object.clone(this._object);\n    },\n\n    keys: function() {\n      return this.pluck('key');\n    },\n\n    values: function() {\n      return this.pluck('value');\n    },\n\n    index: function(value) {\n      var match = this.detect(function(pair) {\n        return pair.value === value;\n      });\n      return match && match.key;\n    },\n\n    merge: function(object) {\n      return this.clone().update(object);\n    },\n\n    update: function(object) {\n      return new Hash(object).inject(this, function(result, pair) {\n        result.set(pair.key, pair.value);\n        return result;\n      });\n    },\n\n    toQueryString: function() {\n      return this.inject([], function(results, pair) {\n        var key = encodeURIComponent(pair.key), values = pair.value;\n\n        if (values && typeof values == 'object') {\n          if (Object.isArray(values))\n            return results.concat(values.map(toQueryPair.curry(key)));\n        } else results.push(toQueryPair(key, values));\n        return results;\n      }).join('&');\n    },\n\n    inspect: function() {\n      return '#<Hash:{' + this.map(function(pair) {\n        return pair.map(Object.inspect).join(': ');\n      }).join(', ') + '}>';\n    },\n\n    toJSON: function() {\n      return Object.toJSON(this.toObject());\n    },\n\n    clone: function() {\n      return new Hash(this);\n    }\n  }\n})());\n\nHash.prototype.toTemplateReplacements = Hash.prototype.toObject;\nHash.from = $H;\nvar ObjectRange = Class.create(Enumerable, {\n  initialize: function(start, end, exclusive) {\n    this.start = start;\n    this.end = end;\n    this.exclusive = exclusive;\n  },\n\n  _each: function(iterator) {\n    var value = this.start;\n    while (this.include(value)) {\n      iterator(value);\n      value = value.succ();\n    }\n  },\n\n  include: function(value) {\n    if (value < this.start)\n      return false;\n    if (this.exclusive)\n      return value < this.end;\n    return value <= this.end;\n  }\n});\n\nvar $R = function(start, end, exclusive) {\n  return new ObjectRange(start, end, exclusive);\n};\n\nvar Ajax = {\n  getTransport: function() {\n    return Try.these(\n      function() {return new XMLHttpRequest()},\n      function() {return new ActiveXObject('Msxml2.XMLHTTP')},\n      function() {return new ActiveXObject('Microsoft.XMLHTTP')}\n    ) || false;\n  },\n\n  activeRequestCount: 0\n};\n\nAjax.Responders = {\n  responders: [],\n\n  _each: function(iterator) {\n    this.responders._each(iterator);\n  },\n\n  register: function(responder) {\n    if (!this.include(responder))\n      this.responders.push(responder);\n  },\n\n  unregister: function(responder) {\n    this.responders = this.responders.without(responder);\n  },\n\n  dispatch: function(callback, request, transport, json) {\n    this.each(function(responder) {\n      if (Object.isFunction(responder[callback])) {\n        try {\n          responder[callback].apply(responder, [request, transport, json]);\n        } catch (e) { }\n      }\n    });\n  }\n};\n\nObject.extend(Ajax.Responders, Enumerable);\n\nAjax.Responders.register({\n  onCreate:   function() { Ajax.activeRequestCount++ },\n  onComplete: function() { Ajax.activeRequestCount-- }\n});\n\nAjax.Base = Class.create({\n  initialize: function(options) {\n    this.options = {\n      method:       'post',\n      asynchronous: true,\n      contentType:  'application/x-www-form-urlencoded',\n      encoding:     'UTF-8',\n      parameters:   '',\n      evalJSON:     true,\n      evalJS:       true\n    };\n    Object.extend(this.options, options || { });\n\n    this.options.method = this.options.method.toLowerCase();\n\n    if (Object.isString(this.options.parameters))\n      this.options.parameters = this.options.parameters.toQueryParams();\n    else if (Object.isHash(this.options.parameters))\n      this.options.parameters = this.options.parameters.toObject();\n  }\n});\n\nAjax.Request = Class.create(Ajax.Base, {\n  _complete: false,\n\n  initialize: function($super, url, options) {\n    $super(options);\n    this.transport = Ajax.getTransport();\n    this.request(url);\n  },\n\n  request: function(url) {\n    this.url = url;\n    this.method = this.options.method;\n    var params = Object.clone(this.options.parameters);\n\n    if (!['get', 'post'].include(this.method)) {\n      // simulate other verbs over post\n      params['_method'] = this.method;\n      this.method = 'post';\n    }\n\n    this.parameters = params;\n\n    if (params = Object.toQueryString(params)) {\n      // when GET, append parameters to URL\n      if (this.method == 'get')\n        this.url += (this.url.include('?') ? '&' : '?') + params;\n      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))\n        params += '&_=';\n    }\n\n    try {\n      var response = new Ajax.Response(this);\n      if (this.options.onCreate) this.options.onCreate(response);\n      Ajax.Responders.dispatch('onCreate', this, response);\n\n      this.transport.open(this.method.toUpperCase(), this.url,\n        this.options.asynchronous);\n\n      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);\n\n      this.transport.onreadystatechange = this.onStateChange.bind(this);\n      this.setRequestHeaders();\n\n      this.body = this.method == 'post' ? (this.options.postBody || params) : null;\n      this.transport.send(this.body);\n\n      /* Force Firefox to handle ready state 4 for synchronous requests */\n      if (!this.options.asynchronous && this.transport.overrideMimeType)\n        this.onStateChange();\n\n    }\n    catch (e) {\n      this.dispatchException(e);\n    }\n  },\n\n  onStateChange: function() {\n    var readyState = this.transport.readyState;\n    if (readyState > 1 && !((readyState == 4) && this._complete))\n      this.respondToReadyState(this.transport.readyState);\n  },\n\n  setRequestHeaders: function() {\n    var headers = {\n      'X-Requested-With': 'XMLHttpRequest',\n      'X-Prototype-Version': Prototype.Version,\n      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'\n    };\n\n    if (this.method == 'post') {\n      headers['Content-type'] = this.options.contentType +\n        (this.options.encoding ? '; charset=' + this.options.encoding : '');\n\n      /* Force \"Connection: close\" for older Mozilla browsers to work\n       * around a bug where XMLHttpRequest sends an incorrect\n       * Content-length header. See Mozilla Bugzilla #246651.\n       */\n      if (this.transport.overrideMimeType &&\n          (navigator.userAgent.match(/Gecko\\/(\\d{4})/) || [0,2005])[1] < 2005)\n            headers['Connection'] = 'close';\n    }\n\n    // user-defined headers\n    if (typeof this.options.requestHeaders == 'object') {\n      var extras = this.options.requestHeaders;\n\n      if (Object.isFunction(extras.push))\n        for (var i = 0, length = extras.length; i < length; i += 2)\n          headers[extras[i]] = extras[i+1];\n      else\n        $H(extras).each(function(pair) { headers[pair.key] = pair.value });\n    }\n\n    for (var name in headers)\n      this.transport.setRequestHeader(name, headers[name]);\n  },\n\n  success: function() {\n    var status = this.getStatus();\n    return !status || (status >= 200 && status < 300);\n  },\n\n  getStatus: function() {\n    try {\n      return this.transport.status || 0;\n    } catch (e) { return 0 }\n  },\n\n  respondToReadyState: function(readyState) {\n    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);\n\n    if (state == 'Complete') {\n      try {\n        this._complete = true;\n        (this.options['on' + response.status]\n         || this.options['on' + (this.success() ? 'Success' : 'Failure')]\n         || Prototype.emptyFunction)(response, response.headerJSON);\n      } catch (e) {\n        this.dispatchException(e);\n      }\n\n      var contentType = response.getHeader('Content-type');\n      if (this.options.evalJS == 'force'\n          || (this.options.evalJS && this.isSameOrigin() && contentType\n          && contentType.match(/^\\s*(text|application)\\/(x-)?(java|ecma)script(;.*)?\\s*$/i)))\n        this.evalResponse();\n    }\n\n    try {\n      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);\n      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);\n    } catch (e) {\n      this.dispatchException(e);\n    }\n\n    if (state == 'Complete') {\n      // avoid memory leak in MSIE: clean up\n      this.transport.onreadystatechange = Prototype.emptyFunction;\n    }\n  },\n\n  isSameOrigin: function() {\n    var m = this.url.match(/^\\s*https?:\\/\\/[^\\/]*/);\n    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({\n      protocol: location.protocol,\n      domain: document.domain,\n      port: location.port ? ':' + location.port : ''\n    }));\n  },\n\n  getHeader: function(name) {\n    try {\n      return this.transport.getResponseHeader(name) || null;\n    } catch (e) { return null }\n  },\n\n  evalResponse: function() {\n    try {\n      return eval((this.transport.responseText || '').unfilterJSON());\n    } catch (e) {\n      this.dispatchException(e);\n    }\n  },\n\n  dispatchException: function(exception) {\n    (this.options.onException || Prototype.emptyFunction)(this, exception);\n    Ajax.Responders.dispatch('onException', this, exception);\n  }\n});\n\nAjax.Request.Events =\n  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];\n\nAjax.Response = Class.create({\n  initialize: function(request){\n    this.request = request;\n    var transport  = this.transport  = request.transport,\n        readyState = this.readyState = transport.readyState;\n\n    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {\n      this.status       = this.getStatus();\n      this.statusText   = this.getStatusText();\n      this.responseText = String.interpret(transport.responseText);\n      this.headerJSON   = this._getHeaderJSON();\n    }\n\n    if(readyState == 4) {\n      var xml = transport.responseXML;\n      this.responseXML  = Object.isUndefined(xml) ? null : xml;\n      this.responseJSON = this._getResponseJSON();\n    }\n  },\n\n  status:      0,\n  statusText: '',\n\n  getStatus: Ajax.Request.prototype.getStatus,\n\n  getStatusText: function() {\n    try {\n      return this.transport.statusText || '';\n    } catch (e) { return '' }\n  },\n\n  getHeader: Ajax.Request.prototype.getHeader,\n\n  getAllHeaders: function() {\n    try {\n      return this.getAllResponseHeaders();\n    } catch (e) { return null }\n  },\n\n  getResponseHeader: function(name) {\n    return this.transport.getResponseHeader(name);\n  },\n\n  getAllResponseHeaders: function() {\n    return this.transport.getAllResponseHeaders();\n  },\n\n  _getHeaderJSON: function() {\n    var json = this.getHeader('X-JSON');\n    if (!json) return null;\n    json = decodeURIComponent(escape(json));\n    try {\n      return json.evalJSON(this.request.options.sanitizeJSON ||\n        !this.request.isSameOrigin());\n    } catch (e) {\n      this.request.dispatchException(e);\n    }\n  },\n\n  _getResponseJSON: function() {\n    var options = this.request.options;\n    if (!options.evalJSON || (options.evalJSON != 'force' &&\n      !(this.getHeader('Content-type') || '').include('application/json')) ||\n        this.responseText.blank())\n          return null;\n    try {\n      return this.responseText.evalJSON(options.sanitizeJSON ||\n        !this.request.isSameOrigin());\n    } catch (e) {\n      this.request.dispatchException(e);\n    }\n  }\n});\n\nAjax.Updater = Class.create(Ajax.Request, {\n  initialize: function($super, container, url, options) {\n    this.container = {\n      success: (container.success || container),\n      failure: (container.failure || (container.success ? null : container))\n    };\n\n    options = Object.clone(options);\n    var onComplete = options.onComplete;\n    options.onComplete = (function(response, json) {\n      this.updateContent(response.responseText);\n      if (Object.isFunction(onComplete)) onComplete(response, json);\n    }).bind(this);\n\n    $super(url, options);\n  },\n\n  updateContent: function(responseText) {\n    var receiver = this.container[this.success() ? 'success' : 'failure'],\n        options = this.options;\n\n    if (!options.evalScripts) responseText = responseText.stripScripts();\n\n    if (receiver = $(receiver)) {\n      if (options.insertion) {\n        if (Object.isString(options.insertion)) {\n          var insertion = { }; insertion[options.insertion] = responseText;\n          receiver.insert(insertion);\n        }\n        else options.insertion(receiver, responseText);\n      }\n      else receiver.update(responseText);\n    }\n  }\n});\n\nAjax.PeriodicalUpdater = Class.create(Ajax.Base, {\n  initialize: function($super, container, url, options) {\n    $super(options);\n    this.onComplete = this.options.onComplete;\n\n    this.frequency = (this.options.frequency || 2);\n    this.decay = (this.options.decay || 1);\n\n    this.updater = { };\n    this.container = container;\n    this.url = url;\n\n    this.start();\n  },\n\n  start: function() {\n    this.options.onComplete = this.updateComplete.bind(this);\n    this.onTimerEvent();\n  },\n\n  stop: function() {\n    this.updater.options.onComplete = undefined;\n    clearTimeout(this.timer);\n    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);\n  },\n\n  updateComplete: function(response) {\n    if (this.options.decay) {\n      this.decay = (response.responseText == this.lastText ?\n        this.decay * this.options.decay : 1);\n\n      this.lastText = response.responseText;\n    }\n    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);\n  },\n\n  onTimerEvent: function() {\n    this.updater = new Ajax.Updater(this.container, this.url, this.options);\n  }\n});\nfunction $(element) {\n  if (arguments.length > 1) {\n    for (var i = 0, elements = [], length = arguments.length; i < length; i++)\n      elements.push($(arguments[i]));\n    return elements;\n  }\n  if (Object.isString(element))\n    element = document.getElementById(element);\n  return Element.extend(element);\n}\n\nif (Prototype.BrowserFeatures.XPath) {\n  document._getElementsByXPath = function(expression, parentElement) {\n    var results = [];\n    var query = document.evaluate(expression, $(parentElement) || document,\n      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n    for (var i = 0, length = query.snapshotLength; i < length; i++)\n      results.push(Element.extend(query.snapshotItem(i)));\n    return results;\n  };\n}\n\n/*--------------------------------------------------------------------------*/\n\nif (!window.Node) var Node = { };\n\nif (!Node.ELEMENT_NODE) {\n  // DOM level 2 ECMAScript Language Binding\n  Object.extend(Node, {\n    ELEMENT_NODE: 1,\n    ATTRIBUTE_NODE: 2,\n    TEXT_NODE: 3,\n    CDATA_SECTION_NODE: 4,\n    ENTITY_REFERENCE_NODE: 5,\n    ENTITY_NODE: 6,\n    PROCESSING_INSTRUCTION_NODE: 7,\n    COMMENT_NODE: 8,\n    DOCUMENT_NODE: 9,\n    DOCUMENT_TYPE_NODE: 10,\n    DOCUMENT_FRAGMENT_NODE: 11,\n    NOTATION_NODE: 12\n  });\n}\n\n(function() {\n  var element = this.Element;\n  this.Element = function(tagName, attributes) {\n    attributes = attributes || { };\n    tagName = tagName.toLowerCase();\n    var cache = Element.cache;\n    if (Prototype.Browser.IE && attributes.name) {\n      tagName = '<' + tagName + ' name=\"' + attributes.name + '\">';\n      delete attributes.name;\n      return Element.writeAttribute(document.createElement(tagName), attributes);\n    }\n    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));\n    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);\n  };\n  Object.extend(this.Element, element || { });\n  if (element) this.Element.prototype = element.prototype;\n}).call(window);\n\nElement.cache = { };\n\nElement.Methods = {\n  visible: function(element) {\n    return $(element).style.display != 'none';\n  },\n\n  toggle: function(element) {\n    element = $(element);\n    Element[Element.visible(element) ? 'hide' : 'show'](element);\n    return element;\n  },\n\n  hide: function(element) {\n    element = $(element);\n    element.style.display = 'none';\n    return element;\n  },\n\n  show: function(element) {\n    element = $(element);\n    element.style.display = '';\n    return element;\n  },\n\n  remove: function(element) {\n    element = $(element);\n    element.parentNode.removeChild(element);\n    return element;\n  },\n\n  update: function(element, content) {\n    element = $(element);\n    if (content && content.toElement) content = content.toElement();\n    if (Object.isElement(content)) return element.update().insert(content);\n    content = Object.toHTML(content);\n    element.innerHTML = content.stripScripts();\n    content.evalScripts.bind(content).defer();\n    return element;\n  },\n\n  replace: function(element, content) {\n    element = $(element);\n    if (content && content.toElement) content = content.toElement();\n    else if (!Object.isElement(content)) {\n      content = Object.toHTML(content);\n      var range = element.ownerDocument.createRange();\n      range.selectNode(element);\n      content.evalScripts.bind(content).defer();\n      content = range.createContextualFragment(content.stripScripts());\n    }\n    element.parentNode.replaceChild(content, element);\n    return element;\n  },\n\n  insert: function(element, insertions) {\n    element = $(element);\n\n    if (Object.isString(insertions) || Object.isNumber(insertions) ||\n        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))\n          insertions = {bottom:insertions};\n\n    var content, insert, tagName, childNodes;\n\n    for (var position in insertions) {\n      content  = insertions[position];\n      position = position.toLowerCase();\n      insert = Element._insertionTranslations[position];\n\n      if (content && content.toElement) content = content.toElement();\n      if (Object.isElement(content)) {\n        insert(element, content);\n        continue;\n      }\n\n      content = Object.toHTML(content);\n\n      tagName = ((position == 'before' || position == 'after')\n        ? element.parentNode : element).tagName.toUpperCase();\n\n      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());\n\n      if (position == 'top' || position == 'after') childNodes.reverse();\n      childNodes.each(insert.curry(element));\n\n      content.evalScripts.bind(content).defer();\n    }\n\n    return element;\n  },\n\n  wrap: function(element, wrapper, attributes) {\n    element = $(element);\n    if (Object.isElement(wrapper))\n      $(wrapper).writeAttribute(attributes || { });\n    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);\n    else wrapper = new Element('div', wrapper);\n    if (element.parentNode)\n      element.parentNode.replaceChild(wrapper, element);\n    wrapper.appendChild(element);\n    return wrapper;\n  },\n\n  inspect: function(element) {\n    element = $(element);\n    var result = '<' + element.tagName.toLowerCase();\n    $H({'id': 'id', 'className': 'class'}).each(function(pair) {\n      var property = pair.first(), attribute = pair.last();\n      var value = (element[property] || '').toString();\n      if (value) result += ' ' + attribute + '=' + value.inspect(true);\n    });\n    return result + '>';\n  },\n\n  recursivelyCollect: function(element, property) {\n    element = $(element);\n    var elements = [];\n    while (element = element[property])\n      if (element.nodeType == 1)\n        elements.push(Element.extend(element));\n    return elements;\n  },\n\n  ancestors: function(element) {\n    return $(element).recursivelyCollect('parentNode');\n  },\n\n  descendants: function(element) {\n    return $(element).select(\"*\");\n  },\n\n  firstDescendant: function(element) {\n    element = $(element).firstChild;\n    while (element && element.nodeType != 1) element = element.nextSibling;\n    return $(element);\n  },\n\n  immediateDescendants: function(element) {\n    if (!(element = $(element).firstChild)) return [];\n    while (element && element.nodeType != 1) element = element.nextSibling;\n    if (element) return [element].concat($(element).nextSiblings());\n    return [];\n  },\n\n  previousSiblings: function(element) {\n    return $(element).recursivelyCollect('previousSibling');\n  },\n\n  nextSiblings: function(element) {\n    return $(element).recursivelyCollect('nextSibling');\n  },\n\n  siblings: function(element) {\n    element = $(element);\n    return element.previousSiblings().reverse().concat(element.nextSiblings());\n  },\n\n  match: function(element, selector) {\n    if (Object.isString(selector))\n      selector = new Selector(selector);\n    return selector.match($(element));\n  },\n\n  up: function(element, expression, index) {\n    element = $(element);\n    if (arguments.length == 1) return $(element.parentNode);\n    var ancestors = element.ancestors();\n    return Object.isNumber(expression) ? ancestors[expression] :\n      Selector.findElement(ancestors, expression, index);\n  },\n\n  down: function(element, expression, index) {\n    element = $(element);\n    if (arguments.length == 1) return element.firstDescendant();\n    return Object.isNumber(expression) ? element.descendants()[expression] :\n      Element.select(element, expression)[index || 0];\n  },\n\n  previous: function(element, expression, index) {\n    element = $(element);\n    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));\n    var previousSiblings = element.previousSiblings();\n    return Object.isNumber(expression) ? previousSiblings[expression] :\n      Selector.findElement(previousSiblings, expression, index);\n  },\n\n  next: function(element, expression, index) {\n    element = $(element);\n    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));\n    var nextSiblings = element.nextSiblings();\n    return Object.isNumber(expression) ? nextSiblings[expression] :\n      Selector.findElement(nextSiblings, expression, index);\n  },\n\n  select: function() {\n    var args = $A(arguments), element = $(args.shift());\n    return Selector.findChildElements(element, args);\n  },\n\n  adjacent: function() {\n    var args = $A(arguments), element = $(args.shift());\n    return Selector.findChildElements(element.parentNode, args).without(element);\n  },\n\n  identify: function(element) {\n    element = $(element);\n    var id = element.readAttribute('id'), self = arguments.callee;\n    if (id) return id;\n    do { id = 'anonymous_element_' + self.counter++ } while ($(id));\n    element.writeAttribute('id', id);\n    return id;\n  },\n\n  readAttribute: function(element, name) {\n    element = $(element);\n    if (Prototype.Browser.IE) {\n      var t = Element._attributeTranslations.read;\n      if (t.values[name]) return t.values[name](element, name);\n      if (t.names[name]) name = t.names[name];\n      if (name.include(':')) {\n        return (!element.attributes || !element.attributes[name]) ? null :\n         element.attributes[name].value;\n      }\n    }\n    return element.getAttribute(name);\n  },\n\n  writeAttribute: function(element, name, value) {\n    element = $(element);\n    var attributes = { }, t = Element._attributeTranslations.write;\n\n    if (typeof name == 'object') attributes = name;\n    else attributes[name] = Object.isUndefined(value) ? true : value;\n\n    for (var attr in attributes) {\n      name = t.names[attr] || attr;\n      value = attributes[attr];\n      if (t.values[attr]) name = t.values[attr](element, value);\n      if (value === false || value === null)\n        element.removeAttribute(name);\n      else if (value === true)\n        element.setAttribute(name, name);\n      else element.setAttribute(name, value);\n    }\n    return element;\n  },\n\n  getHeight: function(element) {\n    return $(element).getDimensions().height;\n  },\n\n  getWidth: function(element) {\n    return $(element).getDimensions().width;\n  },\n\n  classNames: function(element) {\n    return new Element.ClassNames(element);\n  },\n\n  hasClassName: function(element, className) {\n    if (!(element = $(element))) return;\n    var elementClassName = element.className;\n    return (elementClassName.length > 0 && (elementClassName == className ||\n      new RegExp(\"(^|\\\\s)\" + className + \"(\\\\s|$)\").test(elementClassName)));\n  },\n\n  addClassName: function(element, className) {\n    if (!(element = $(element))) return;\n    if (!element.hasClassName(className))\n      element.className += (element.className ? ' ' : '') + className;\n    return element;\n  },\n\n  removeClassName: function(element, className) {\n    if (!(element = $(element))) return;\n    element.className = element.className.replace(\n      new RegExp(\"(^|\\\\s+)\" + className + \"(\\\\s+|$)\"), ' ').strip();\n    return element;\n  },\n\n  toggleClassName: function(element, className) {\n    if (!(element = $(element))) return;\n    return element[element.hasClassName(className) ?\n      'removeClassName' : 'addClassName'](className);\n  },\n\n  // removes whitespace-only text node children\n  cleanWhitespace: function(element) {\n    element = $(element);\n    var node = element.firstChild;\n    while (node) {\n      var nextNode = node.nextSibling;\n      if (node.nodeType == 3 && !/\\S/.test(node.nodeValue))\n        element.removeChild(node);\n      node = nextNode;\n    }\n    return element;\n  },\n\n  empty: function(element) {\n    return $(element).innerHTML.blank();\n  },\n\n  descendantOf: function(element, ancestor) {\n    element = $(element), ancestor = $(ancestor);\n\n    if (element.compareDocumentPosition)\n      return (element.compareDocumentPosition(ancestor) & 8) === 8;\n\n    if (ancestor.contains)\n      return ancestor.contains(element) && ancestor !== element;\n\n    while (element = element.parentNode)\n      if (element == ancestor) return true;\n\n    return false;\n  },\n\n  scrollTo: function(element) {\n    element = $(element);\n    var pos = element.cumulativeOffset();\n    window.scrollTo(pos[0], pos[1]);\n    return element;\n  },\n\n  getStyle: function(element, style) {\n    element = $(element);\n    style = style == 'float' ? 'cssFloat' : style.camelize();\n    var value = element.style[style];\n    if (!value || value == 'auto') {\n      var css = document.defaultView.getComputedStyle(element, null);\n      value = css ? css[style] : null;\n    }\n    if (style == 'opacity') return value ? parseFloat(value) : 1.0;\n    return value == 'auto' ? null : value;\n  },\n\n  getOpacity: function(element) {\n    return $(element).getStyle('opacity');\n  },\n\n  setStyle: function(element, styles) {\n    element = $(element);\n    var elementStyle = element.style, match;\n    if (Object.isString(styles)) {\n      element.style.cssText += ';' + styles;\n      return styles.include('opacity') ?\n        element.setOpacity(styles.match(/opacity:\\s*(\\d?\\.?\\d*)/)[1]) : element;\n    }\n    for (var property in styles)\n      if (property == 'opacity') element.setOpacity(styles[property]);\n      else\n        elementStyle[(property == 'float' || property == 'cssFloat') ?\n          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :\n            property] = styles[property];\n\n    return element;\n  },\n\n  setOpacity: function(element, value) {\n    element = $(element);\n    element.style.opacity = (value == 1 || value === '') ? '' :\n      (value < 0.00001) ? 0 : value;\n    return element;\n  },\n\n  getDimensions: function(element) {\n    element = $(element);\n    var display = element.getStyle('display');\n    if (display != 'none' && display != null) // Safari bug\n      return {width: element.offsetWidth, height: element.offsetHeight};\n\n    // All *Width and *Height properties give 0 on elements with display none,\n    // so enable the element temporarily\n    var els = element.style;\n    var originalVisibility = els.visibility;\n    var originalPosition = els.position;\n    var originalDisplay = els.display;\n    els.visibility = 'hidden';\n    els.position = 'absolute';\n    els.display = 'block';\n    var originalWidth = element.clientWidth;\n    var originalHeight = element.clientHeight;\n    els.display = originalDisplay;\n    els.position = originalPosition;\n    els.visibility = originalVisibility;\n    return {width: originalWidth, height: originalHeight};\n  },\n\n  makePositioned: function(element) {\n    element = $(element);\n    var pos = Element.getStyle(element, 'position');\n    if (pos == 'static' || !pos) {\n      element._madePositioned = true;\n      element.style.position = 'relative';\n      // Opera returns the offset relative to the positioning context, when an\n      // element is position relative but top and left have not been defined\n      if (Prototype.Browser.Opera) {\n        element.style.top = 0;\n        element.style.left = 0;\n      }\n    }\n    return element;\n  },\n\n  undoPositioned: function(element) {\n    element = $(element);\n    if (element._madePositioned) {\n      element._madePositioned = undefined;\n      element.style.position =\n        element.style.top =\n        element.style.left =\n        element.style.bottom =\n        element.style.right = '';\n    }\n    return element;\n  },\n\n  makeClipping: function(element) {\n    element = $(element);\n    if (element._overflow) return element;\n    element._overflow = Element.getStyle(element, 'overflow') || 'auto';\n    if (element._overflow !== 'hidden')\n      element.style.overflow = 'hidden';\n    return element;\n  },\n\n  undoClipping: function(element) {\n    element = $(element);\n    if (!element._overflow) return element;\n    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;\n    element._overflow = null;\n    return element;\n  },\n\n  cumulativeOffset: function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n      element = element.offsetParent;\n    } while (element);\n    return Element._returnOffset(valueL, valueT);\n  },\n\n  positionedOffset: function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n      element = element.offsetParent;\n      if (element) {\n        if (element.tagName.toUpperCase() == 'BODY') break;\n        var p = Element.getStyle(element, 'position');\n        if (p !== 'static') break;\n      }\n    } while (element);\n    return Element._returnOffset(valueL, valueT);\n  },\n\n  absolutize: function(element) {\n    element = $(element);\n    if (element.getStyle('position') == 'absolute') return element;\n    // Position.prepare(); // To be done manually by Scripty when it needs it.\n\n    var offsets = element.positionedOffset();\n    var top     = offsets[1];\n    var left    = offsets[0];\n    var width   = element.clientWidth;\n    var height  = element.clientHeight;\n\n    element._originalLeft   = left - parseFloat(element.style.left  || 0);\n    element._originalTop    = top  - parseFloat(element.style.top || 0);\n    element._originalWidth  = element.style.width;\n    element._originalHeight = element.style.height;\n\n    element.style.position = 'absolute';\n    element.style.top    = top + 'px';\n    element.style.left   = left + 'px';\n    element.style.width  = width + 'px';\n    element.style.height = height + 'px';\n    return element;\n  },\n\n  relativize: function(element) {\n    element = $(element);\n    if (element.getStyle('position') == 'relative') return element;\n    // Position.prepare(); // To be done manually by Scripty when it needs it.\n\n    element.style.position = 'relative';\n    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);\n    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);\n\n    element.style.top    = top + 'px';\n    element.style.left   = left + 'px';\n    element.style.height = element._originalHeight;\n    element.style.width  = element._originalWidth;\n    return element;\n  },\n\n  cumulativeScrollOffset: function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.scrollTop  || 0;\n      valueL += element.scrollLeft || 0;\n      element = element.parentNode;\n    } while (element);\n    return Element._returnOffset(valueL, valueT);\n  },\n\n  getOffsetParent: function(element) {\n    if (element.offsetParent) return $(element.offsetParent);\n    if (element == document.body) return $(element);\n\n    while ((element = element.parentNode) && element != document.body)\n      if (Element.getStyle(element, 'position') != 'static')\n        return $(element);\n\n    return $(document.body);\n  },\n\n  viewportOffset: function(forElement) {\n    var valueT = 0, valueL = 0;\n\n    var element = forElement;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n\n      // Safari fix\n      if (element.offsetParent == document.body &&\n        Element.getStyle(element, 'position') == 'absolute') break;\n\n    } while (element = element.offsetParent);\n\n    element = forElement;\n    do {\n      if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {\n        valueT -= element.scrollTop  || 0;\n        valueL -= element.scrollLeft || 0;\n      }\n    } while (element = element.parentNode);\n\n    return Element._returnOffset(valueL, valueT);\n  },\n\n  clonePosition: function(element, source) {\n    var options = Object.extend({\n      setLeft:    true,\n      setTop:     true,\n      setWidth:   true,\n      setHeight:  true,\n      offsetTop:  0,\n      offsetLeft: 0\n    }, arguments[2] || { });\n\n    // find page position of source\n    source = $(source);\n    var p = source.viewportOffset();\n\n    // find coordinate system to use\n    element = $(element);\n    var delta = [0, 0];\n    var parent = null;\n    // delta [0,0] will do fine with position: fixed elements,\n    // position:absolute needs offsetParent deltas\n    if (Element.getStyle(element, 'position') == 'absolute') {\n      parent = element.getOffsetParent();\n      delta = parent.viewportOffset();\n    }\n\n    // correct by body offsets (fixes Safari)\n    if (parent == document.body) {\n      delta[0] -= document.body.offsetLeft;\n      delta[1] -= document.body.offsetTop;\n    }\n\n    // set position\n    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';\n    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';\n    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';\n    if (options.setHeight) element.style.height = source.offsetHeight + 'px';\n    return element;\n  }\n};\n\nElement.Methods.identify.counter = 1;\n\nObject.extend(Element.Methods, {\n  getElementsBySelector: Element.Methods.select,\n  childElements: Element.Methods.immediateDescendants\n});\n\nElement._attributeTranslations = {\n  write: {\n    names: {\n      className: 'class',\n      htmlFor:   'for'\n    },\n    values: { }\n  }\n};\n\nif (Prototype.Browser.Opera) {\n  Element.Methods.getStyle = Element.Methods.getStyle.wrap(\n    function(proceed, element, style) {\n      switch (style) {\n        case 'left': case 'top': case 'right': case 'bottom':\n          if (proceed(element, 'position') === 'static') return null;\n        case 'height': case 'width':\n          // returns '0px' for hidden elements; we want it to return null\n          if (!Element.visible(element)) return null;\n\n          // returns the border-box dimensions rather than the content-box\n          // dimensions, so we subtract padding and borders from the value\n          var dim = parseInt(proceed(element, style), 10);\n\n          if (dim !== element['offset' + style.capitalize()])\n            return dim + 'px';\n\n          var properties;\n          if (style === 'height') {\n            properties = ['border-top-width', 'padding-top',\n             'padding-bottom', 'border-bottom-width'];\n          }\n          else {\n            properties = ['border-left-width', 'padding-left',\n             'padding-right', 'border-right-width'];\n          }\n          return properties.inject(dim, function(memo, property) {\n            var val = proceed(element, property);\n            return val === null ? memo : memo - parseInt(val, 10);\n          }) + 'px';\n        default: return proceed(element, style);\n      }\n    }\n  );\n\n  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(\n    function(proceed, element, attribute) {\n      if (attribute === 'title') return element.title;\n      return proceed(element, attribute);\n    }\n  );\n}\n\nelse if (Prototype.Browser.IE) {\n  // IE doesn't report offsets correctly for static elements, so we change them\n  // to \"relative\" to get the values, then change them back.\n  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(\n    function(proceed, element) {\n      element = $(element);\n      // IE throws an error if element is not in document\n      try { element.offsetParent }\n      catch(e) { return $(document.body) }\n      var position = element.getStyle('position');\n      if (position !== 'static') return proceed(element);\n      element.setStyle({ position: 'relative' });\n      var value = proceed(element);\n      element.setStyle({ position: position });\n      return value;\n    }\n  );\n\n  $w('positionedOffset viewportOffset').each(function(method) {\n    Element.Methods[method] = Element.Methods[method].wrap(\n      function(proceed, element) {\n        element = $(element);\n        try { element.offsetParent }\n        catch(e) { return Element._returnOffset(0,0) }\n        var position = element.getStyle('position');\n        if (position !== 'static') return proceed(element);\n        // Trigger hasLayout on the offset parent so that IE6 reports\n        // accurate offsetTop and offsetLeft values for position: fixed.\n        var offsetParent = element.getOffsetParent();\n        if (offsetParent && offsetParent.getStyle('position') === 'fixed')\n          offsetParent.setStyle({ zoom: 1 });\n        element.setStyle({ position: 'relative' });\n        var value = proceed(element);\n        element.setStyle({ position: position });\n        return value;\n      }\n    );\n  });\n\n  Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(\n    function(proceed, element) {\n      try { element.offsetParent }\n      catch(e) { return Element._returnOffset(0,0) }\n      return proceed(element);\n    }\n  );\n\n  Element.Methods.getStyle = function(element, style) {\n    element = $(element);\n    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();\n    var value = element.style[style];\n    if (!value && element.currentStyle) value = element.currentStyle[style];\n\n    if (style == 'opacity') {\n      if (value = (element.getStyle('filter') || '').match(/alpha\\(opacity=(.*)\\)/))\n        if (value[1]) return parseFloat(value[1]) / 100;\n      return 1.0;\n    }\n\n    if (value == 'auto') {\n      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))\n        return element['offset' + style.capitalize()] + 'px';\n      return null;\n    }\n    return value;\n  };\n\n  Element.Methods.setOpacity = function(element, value) {\n    function stripAlpha(filter){\n      return filter.replace(/alpha\\([^\\)]*\\)/gi,'');\n    }\n    element = $(element);\n    var currentStyle = element.currentStyle;\n    if ((currentStyle && !currentStyle.hasLayout) ||\n      (!currentStyle && element.style.zoom == 'normal'))\n        element.style.zoom = 1;\n\n    var filter = element.getStyle('filter'), style = element.style;\n    if (value == 1 || value === '') {\n      (filter = stripAlpha(filter)) ?\n        style.filter = filter : style.removeAttribute('filter');\n      return element;\n    } else if (value < 0.00001) value = 0;\n    style.filter = stripAlpha(filter) +\n      'alpha(opacity=' + (value * 100) + ')';\n    return element;\n  };\n\n  Element._attributeTranslations = {\n    read: {\n      names: {\n        'class': 'className',\n        'for':   'htmlFor'\n      },\n      values: {\n        _getAttr: function(element, attribute) {\n          return element.getAttribute(attribute, 2);\n        },\n        _getAttrNode: function(element, attribute) {\n          var node = element.getAttributeNode(attribute);\n          return node ? node.value : \"\";\n        },\n        _getEv: function(element, attribute) {\n          attribute = element.getAttribute(attribute);\n          return attribute ? attribute.toString().slice(23, -2) : null;\n        },\n        _flag: function(element, attribute) {\n          return $(element).hasAttribute(attribute) ? attribute : null;\n        },\n        style: function(element) {\n          return element.style.cssText.toLowerCase();\n        },\n        title: function(element) {\n          return element.title;\n        }\n      }\n    }\n  };\n\n  Element._attributeTranslations.write = {\n    names: Object.extend({\n      cellpadding: 'cellPadding',\n      cellspacing: 'cellSpacing'\n    }, Element._attributeTranslations.read.names),\n    values: {\n      checked: function(element, value) {\n        element.checked = !!value;\n      },\n\n      style: function(element, value) {\n        element.style.cssText = value ? value : '';\n      }\n    }\n  };\n\n  Element._attributeTranslations.has = {};\n\n  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +\n      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {\n    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;\n    Element._attributeTranslations.has[attr.toLowerCase()] = attr;\n  });\n\n  (function(v) {\n    Object.extend(v, {\n      href:        v._getAttr,\n      src:         v._getAttr,\n      type:        v._getAttr,\n      action:      v._getAttrNode,\n      disabled:    v._flag,\n      checked:     v._flag,\n      readonly:    v._flag,\n      multiple:    v._flag,\n      onload:      v._getEv,\n      onunload:    v._getEv,\n      onclick:     v._getEv,\n      ondblclick:  v._getEv,\n      onmousedown: v._getEv,\n      onmouseup:   v._getEv,\n      onmouseover: v._getEv,\n      onmousemove: v._getEv,\n      onmouseout:  v._getEv,\n      onfocus:     v._getEv,\n      onblur:      v._getEv,\n      onkeypress:  v._getEv,\n      onkeydown:   v._getEv,\n      onkeyup:     v._getEv,\n      onsubmit:    v._getEv,\n      onreset:     v._getEv,\n      onselect:    v._getEv,\n      onchange:    v._getEv\n    });\n  })(Element._attributeTranslations.read.values);\n}\n\nelse if (Prototype.Browser.Gecko && /rv:1\\.8\\.0/.test(navigator.userAgent)) {\n  Element.Methods.setOpacity = function(element, value) {\n    element = $(element);\n    element.style.opacity = (value == 1) ? 0.999999 :\n      (value === '') ? '' : (value < 0.00001) ? 0 : value;\n    return element;\n  };\n}\n\nelse if (Prototype.Browser.WebKit) {\n  Element.Methods.setOpacity = function(element, value) {\n    element = $(element);\n    element.style.opacity = (value == 1 || value === '') ? '' :\n      (value < 0.00001) ? 0 : value;\n\n    if (value == 1)\n      if(element.tagName.toUpperCase() == 'IMG' && element.width) {\n        element.width++; element.width--;\n      } else try {\n        var n = document.createTextNode(' ');\n        element.appendChild(n);\n        element.removeChild(n);\n      } catch (e) { }\n\n    return element;\n  };\n\n  // Safari returns margins on body which is incorrect if the child is absolutely\n  // positioned.  For performance reasons, redefine Element#cumulativeOffset for\n  // KHTML/WebKit only.\n  Element.Methods.cumulativeOffset = function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n      if (element.offsetParent == document.body)\n        if (Element.getStyle(element, 'position') == 'absolute') break;\n\n      element = element.offsetParent;\n    } while (element);\n\n    return Element._returnOffset(valueL, valueT);\n  };\n}\n\nif (Prototype.Browser.IE || Prototype.Browser.Opera) {\n  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements\n  Element.Methods.update = function(element, content) {\n    element = $(element);\n\n    if (content && content.toElement) content = content.toElement();\n    if (Object.isElement(content)) return element.update().insert(content);\n\n    content = Object.toHTML(content);\n    var tagName = element.tagName.toUpperCase();\n\n    if (tagName in Element._insertionTranslations.tags) {\n      $A(element.childNodes).each(function(node) { element.removeChild(node) });\n      Element._getContentFromAnonymousElement(tagName, content.stripScripts())\n        .each(function(node) { element.appendChild(node) });\n    }\n    else element.innerHTML = content.stripScripts();\n\n    content.evalScripts.bind(content).defer();\n    return element;\n  };\n}\n\nif ('outerHTML' in document.createElement('div')) {\n  Element.Methods.replace = function(element, content) {\n    element = $(element);\n\n    if (content && content.toElement) content = content.toElement();\n    if (Object.isElement(content)) {\n      element.parentNode.replaceChild(content, element);\n      return element;\n    }\n\n    content = Object.toHTML(content);\n    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();\n\n    if (Element._insertionTranslations.tags[tagName]) {\n      var nextSibling = element.next();\n      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());\n      parent.removeChild(element);\n      if (nextSibling)\n        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });\n      else\n        fragments.each(function(node) { parent.appendChild(node) });\n    }\n    else element.outerHTML = content.stripScripts();\n\n    content.evalScripts.bind(content).defer();\n    return element;\n  };\n}\n\nElement._returnOffset = function(l, t) {\n  var result = [l, t];\n  result.left = l;\n  result.top = t;\n  return result;\n};\n\nElement._getContentFromAnonymousElement = function(tagName, html) {\n  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];\n  if (t) {\n    div.innerHTML = t[0] + html + t[1];\n    t[2].times(function() { div = div.firstChild });\n  } else div.innerHTML = html;\n  return $A(div.childNodes);\n};\n\nElement._insertionTranslations = {\n  before: function(element, node) {\n    element.parentNode.insertBefore(node, element);\n  },\n  top: function(element, node) {\n    element.insertBefore(node, element.firstChild);\n  },\n  bottom: function(element, node) {\n    element.appendChild(node);\n  },\n  after: function(element, node) {\n    element.parentNode.insertBefore(node, element.nextSibling);\n  },\n  tags: {\n    TABLE:  ['<table>',                '</table>',                   1],\n    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],\n    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],\n    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],\n    SELECT: ['<select>',               '</select>',                  1]\n  }\n};\n\n(function() {\n  Object.extend(this.tags, {\n    THEAD: this.tags.TBODY,\n    TFOOT: this.tags.TBODY,\n    TH:    this.tags.TD\n  });\n}).call(Element._insertionTranslations);\n\nElement.Methods.Simulated = {\n  hasAttribute: function(element, attribute) {\n    attribute = Element._attributeTranslations.has[attribute] || attribute;\n    var node = $(element).getAttributeNode(attribute);\n    return !!(node && node.specified);\n  }\n};\n\nElement.Methods.ByTag = { };\n\nObject.extend(Element, Element.Methods);\n\nif (!Prototype.BrowserFeatures.ElementExtensions &&\n    document.createElement('div')['__proto__']) {\n  window.HTMLElement = { };\n  window.HTMLElement.prototype = document.createElement('div')['__proto__'];\n  Prototype.BrowserFeatures.ElementExtensions = true;\n}\n\nElement.extend = (function() {\n  if (Prototype.BrowserFeatures.SpecificElementExtensions)\n    return Prototype.K;\n\n  var Methods = { }, ByTag = Element.Methods.ByTag;\n\n  var extend = Object.extend(function(element) {\n    if (!element || element._extendedByPrototype ||\n        element.nodeType != 1 || element == window) return element;\n\n    var methods = Object.clone(Methods),\n      tagName = element.tagName.toUpperCase(), property, value;\n\n    // extend methods for specific tags\n    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);\n\n    for (property in methods) {\n      value = methods[property];\n      if (Object.isFunction(value) && !(property in element))\n        element[property] = value.methodize();\n    }\n\n    element._extendedByPrototype = Prototype.emptyFunction;\n    return element;\n\n  }, {\n    refresh: function() {\n      // extend methods for all tags (Safari doesn't need this)\n      if (!Prototype.BrowserFeatures.ElementExtensions) {\n        Object.extend(Methods, Element.Methods);\n        Object.extend(Methods, Element.Methods.Simulated);\n      }\n    }\n  });\n\n  extend.refresh();\n  return extend;\n})();\n\nElement.hasAttribute = function(element, attribute) {\n  if (element.hasAttribute) return element.hasAttribute(attribute);\n  return Element.Methods.Simulated.hasAttribute(element, attribute);\n};\n\nElement.addMethods = function(methods) {\n  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;\n\n  if (!methods) {\n    Object.extend(Form, Form.Methods);\n    Object.extend(Form.Element, Form.Element.Methods);\n    Object.extend(Element.Methods.ByTag, {\n      \"FORM\":     Object.clone(Form.Methods),\n      \"INPUT\":    Object.clone(Form.Element.Methods),\n      \"SELECT\":   Object.clone(Form.Element.Methods),\n      \"TEXTAREA\": Object.clone(Form.Element.Methods)\n    });\n  }\n\n  if (arguments.length == 2) {\n    var tagName = methods;\n    methods = arguments[1];\n  }\n\n  if (!tagName) Object.extend(Element.Methods, methods || { });\n  else {\n    if (Object.isArray(tagName)) tagName.each(extend);\n    else extend(tagName);\n  }\n\n  function extend(tagName) {\n    tagName = tagName.toUpperCase();\n    if (!Element.Methods.ByTag[tagName])\n      Element.Methods.ByTag[tagName] = { };\n    Object.extend(Element.Methods.ByTag[tagName], methods);\n  }\n\n  function copy(methods, destination, onlyIfAbsent) {\n    onlyIfAbsent = onlyIfAbsent || false;\n    for (var property in methods) {\n      var value = methods[property];\n      if (!Object.isFunction(value)) continue;\n      if (!onlyIfAbsent || !(property in destination))\n        destination[property] = value.methodize();\n    }\n  }\n\n  function findDOMClass(tagName) {\n    var klass;\n    var trans = {\n      \"OPTGROUP\": \"OptGroup\", \"TEXTAREA\": \"TextArea\", \"P\": \"Paragraph\",\n      \"FIELDSET\": \"FieldSet\", \"UL\": \"UList\", \"OL\": \"OList\", \"DL\": \"DList\",\n      \"DIR\": \"Directory\", \"H1\": \"Heading\", \"H2\": \"Heading\", \"H3\": \"Heading\",\n      \"H4\": \"Heading\", \"H5\": \"Heading\", \"H6\": \"Heading\", \"Q\": \"Quote\",\n      \"INS\": \"Mod\", \"DEL\": \"Mod\", \"A\": \"Anchor\", \"IMG\": \"Image\", \"CAPTION\":\n      \"TableCaption\", \"COL\": \"TableCol\", \"COLGROUP\": \"TableCol\", \"THEAD\":\n      \"TableSection\", \"TFOOT\": \"TableSection\", \"TBODY\": \"TableSection\", \"TR\":\n      \"TableRow\", \"TH\": \"TableCell\", \"TD\": \"TableCell\", \"FRAMESET\":\n      \"FrameSet\", \"IFRAME\": \"IFrame\"\n    };\n    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';\n    if (window[klass]) return window[klass];\n    klass = 'HTML' + tagName + 'Element';\n    if (window[klass]) return window[klass];\n    klass = 'HTML' + tagName.capitalize() + 'Element';\n    if (window[klass]) return window[klass];\n\n    window[klass] = { };\n    window[klass].prototype = document.createElement(tagName)['__proto__'];\n    return window[klass];\n  }\n\n  if (F.ElementExtensions) {\n    copy(Element.Methods, HTMLElement.prototype);\n    copy(Element.Methods.Simulated, HTMLElement.prototype, true);\n  }\n\n  if (F.SpecificElementExtensions) {\n    for (var tag in Element.Methods.ByTag) {\n      var klass = findDOMClass(tag);\n      if (Object.isUndefined(klass)) continue;\n      copy(T[tag], klass.prototype);\n    }\n  }\n\n  Object.extend(Element, Element.Methods);\n  delete Element.ByTag;\n\n  if (Element.extend.refresh) Element.extend.refresh();\n  Element.cache = { };\n};\n\ndocument.viewport = {\n  getDimensions: function() {\n    var dimensions = { }, B = Prototype.Browser;\n    $w('width height').each(function(d) {\n      var D = d.capitalize();\n      if (B.WebKit && !document.evaluate) {\n        // Safari <3.0 needs self.innerWidth/Height\n        dimensions[d] = self['inner' + D];\n      } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) {\n        // Opera <9.5 needs document.body.clientWidth/Height\n        dimensions[d] = document.body['client' + D]\n      } else {\n        dimensions[d] = document.documentElement['client' + D];\n      }\n    });\n    return dimensions;\n  },\n\n  getWidth: function() {\n    return this.getDimensions().width;\n  },\n\n  getHeight: function() {\n    return this.getDimensions().height;\n  },\n\n  getScrollOffsets: function() {\n    return Element._returnOffset(\n      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,\n      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);\n  }\n};\n/* Portions of the Selector class are derived from Jack Slocum's DomQuery,\n * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style\n * license.  Please see http://www.yui-ext.com/ for more information. */\n\nvar Selector = Class.create({\n  initialize: function(expression) {\n    this.expression = expression.strip();\n\n    if (this.shouldUseSelectorsAPI()) {\n      this.mode = 'selectorsAPI';\n    } else if (this.shouldUseXPath()) {\n      this.mode = 'xpath';\n      this.compileXPathMatcher();\n    } else {\n      this.mode = \"normal\";\n      this.compileMatcher();\n    }\n\n  },\n\n  shouldUseXPath: function() {\n    if (!Prototype.BrowserFeatures.XPath) return false;\n\n    var e = this.expression;\n\n    // Safari 3 chokes on :*-of-type and :empty\n    if (Prototype.Browser.WebKit &&\n     (e.include(\"-of-type\") || e.include(\":empty\")))\n      return false;\n\n    // XPath can't do namespaced attributes, nor can it read\n    // the \"checked\" property from DOM nodes\n    if ((/(\\[[\\w-]*?:|:checked)/).test(e))\n      return false;\n\n    return true;\n  },\n\n  shouldUseSelectorsAPI: function() {\n    if (!Prototype.BrowserFeatures.SelectorsAPI) return false;\n\n    if (!Selector._div) Selector._div = new Element('div');\n\n    // Make sure the browser treats the selector as valid. Test on an\n    // isolated element to minimize cost of this check.\n    try {\n      Selector._div.querySelector(this.expression);\n    } catch(e) {\n      return false;\n    }\n\n    return true;\n  },\n\n  compileMatcher: function() {\n    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,\n        c = Selector.criteria, le, p, m;\n\n    if (Selector._cache[e]) {\n      this.matcher = Selector._cache[e];\n      return;\n    }\n\n    this.matcher = [\"this.matcher = function(root) {\",\n                    \"var r = root, h = Selector.handlers, c = false, n;\"];\n\n    while (e && le != e && (/\\S/).test(e)) {\n      le = e;\n      for (var i in ps) {\n        p = ps[i];\n        if (m = e.match(p)) {\n          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :\n            new Template(c[i]).evaluate(m));\n          e = e.replace(m[0], '');\n          break;\n        }\n      }\n    }\n\n    this.matcher.push(\"return h.unique(n);\\n}\");\n    eval(this.matcher.join('\\n'));\n    Selector._cache[this.expression] = this.matcher;\n  },\n\n  compileXPathMatcher: function() {\n    var e = this.expression, ps = Selector.patterns,\n        x = Selector.xpath, le, m;\n\n    if (Selector._cache[e]) {\n      this.xpath = Selector._cache[e]; return;\n    }\n\n    this.matcher = ['.//*'];\n    while (e && le != e && (/\\S/).test(e)) {\n      le = e;\n      for (var i in ps) {\n        if (m = e.match(ps[i])) {\n          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :\n            new Template(x[i]).evaluate(m));\n          e = e.replace(m[0], '');\n          break;\n        }\n      }\n    }\n\n    this.xpath = this.matcher.join('');\n    Selector._cache[this.expression] = this.xpath;\n  },\n\n  findElements: function(root) {\n    root = root || document;\n    var e = this.expression, results;\n\n    switch (this.mode) {\n      case 'selectorsAPI':\n        // querySelectorAll queries document-wide, then filters to descendants\n        // of the context element. That's not what we want.\n        // Add an explicit context to the selector if necessary.\n        if (root !== document) {\n          var oldId = root.id, id = $(root).identify();\n          e = \"#\" + id + \" \" + e;\n        }\n\n        results = $A(root.querySelectorAll(e)).map(Element.extend);\n        root.id = oldId;\n\n        return results;\n      case 'xpath':\n        return document._getElementsByXPath(this.xpath, root);\n      default:\n       return this.matcher(root);\n    }\n  },\n\n  match: function(element) {\n    this.tokens = [];\n\n    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;\n    var le, p, m;\n\n    while (e && le !== e && (/\\S/).test(e)) {\n      le = e;\n      for (var i in ps) {\n        p = ps[i];\n        if (m = e.match(p)) {\n          // use the Selector.assertions methods unless the selector\n          // is too complex.\n          if (as[i]) {\n            this.tokens.push([i, Object.clone(m)]);\n            e = e.replace(m[0], '');\n          } else {\n            // reluctantly do a document-wide search\n            // and look for a match in the array\n            return this.findElements(document).include(element);\n          }\n        }\n      }\n    }\n\n    var match = true, name, matches;\n    for (var i = 0, token; token = this.tokens[i]; i++) {\n      name = token[0], matches = token[1];\n      if (!Selector.assertions[name](element, matches)) {\n        match = false; break;\n      }\n    }\n\n    return match;\n  },\n\n  toString: function() {\n    return this.expression;\n  },\n\n  inspect: function() {\n    return \"#<Selector:\" + this.expression.inspect() + \">\";\n  }\n});\n\nObject.extend(Selector, {\n  _cache: { },\n\n  xpath: {\n    descendant:   \"//*\",\n    child:        \"/*\",\n    adjacent:     \"/following-sibling::*[1]\",\n    laterSibling: '/following-sibling::*',\n    tagName:      function(m) {\n      if (m[1] == '*') return '';\n      return \"[local-name()='\" + m[1].toLowerCase() +\n             \"' or local-name()='\" + m[1].toUpperCase() + \"']\";\n    },\n    className:    \"[contains(concat(' ', @class, ' '), ' #{1} ')]\",\n    id:           \"[@id='#{1}']\",\n    attrPresence: function(m) {\n      m[1] = m[1].toLowerCase();\n      return new Template(\"[@#{1}]\").evaluate(m);\n    },\n    attr: function(m) {\n      m[1] = m[1].toLowerCase();\n      m[3] = m[5] || m[6];\n      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);\n    },\n    pseudo: function(m) {\n      var h = Selector.xpath.pseudos[m[1]];\n      if (!h) return '';\n      if (Object.isFunction(h)) return h(m);\n      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);\n    },\n    operators: {\n      '=':  \"[@#{1}='#{3}']\",\n      '!=': \"[@#{1}!='#{3}']\",\n      '^=': \"[starts-with(@#{1}, '#{3}')]\",\n      '$=': \"[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']\",\n      '*=': \"[contains(@#{1}, '#{3}')]\",\n      '~=': \"[contains(concat(' ', @#{1}, ' '), ' #{3} ')]\",\n      '|=': \"[contains(concat('-', @#{1}, '-'), '-#{3}-')]\"\n    },\n    pseudos: {\n      'first-child': '[not(preceding-sibling::*)]',\n      'last-child':  '[not(following-sibling::*)]',\n      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',\n      'empty':       \"[count(*) = 0 and (count(text()) = 0)]\",\n      'checked':     \"[@checked]\",\n      'disabled':    \"[(@disabled) and (@type!='hidden')]\",\n      'enabled':     \"[not(@disabled) and (@type!='hidden')]\",\n      'not': function(m) {\n        var e = m[6], p = Selector.patterns,\n            x = Selector.xpath, le, v;\n\n        var exclusion = [];\n        while (e && le != e && (/\\S/).test(e)) {\n          le = e;\n          for (var i in p) {\n            if (m = e.match(p[i])) {\n              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);\n              exclusion.push(\"(\" + v.substring(1, v.length - 1) + \")\");\n              e = e.replace(m[0], '');\n              break;\n            }\n          }\n        }\n        return \"[not(\" + exclusion.join(\" and \") + \")]\";\n      },\n      'nth-child':      function(m) {\n        return Selector.xpath.pseudos.nth(\"(count(./preceding-sibling::*) + 1) \", m);\n      },\n      'nth-last-child': function(m) {\n        return Selector.xpath.pseudos.nth(\"(count(./following-sibling::*) + 1) \", m);\n      },\n      'nth-of-type':    function(m) {\n        return Selector.xpath.pseudos.nth(\"position() \", m);\n      },\n      'nth-last-of-type': function(m) {\n        return Selector.xpath.pseudos.nth(\"(last() + 1 - position()) \", m);\n      },\n      'first-of-type':  function(m) {\n        m[6] = \"1\"; return Selector.xpath.pseudos['nth-of-type'](m);\n      },\n      'last-of-type':   function(m) {\n        m[6] = \"1\"; return Selector.xpath.pseudos['nth-last-of-type'](m);\n      },\n      'only-of-type':   function(m) {\n        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);\n      },\n      nth: function(fragment, m) {\n        var mm, formula = m[6], predicate;\n        if (formula == 'even') formula = '2n+0';\n        if (formula == 'odd')  formula = '2n+1';\n        if (mm = formula.match(/^(\\d+)$/)) // digit only\n          return '[' + fragment + \"= \" + mm[1] + ']';\n        if (mm = formula.match(/^(-?\\d*)?n(([+-])(\\d+))?/)) { // an+b\n          if (mm[1] == \"-\") mm[1] = -1;\n          var a = mm[1] ? Number(mm[1]) : 1;\n          var b = mm[2] ? Number(mm[2]) : 0;\n          predicate = \"[((#{fragment} - #{b}) mod #{a} = 0) and \" +\n          \"((#{fragment} - #{b}) div #{a} >= 0)]\";\n          return new Template(predicate).evaluate({\n            fragment: fragment, a: a, b: b });\n        }\n      }\n    }\n  },\n\n  criteria: {\n    tagName:      'n = h.tagName(n, r, \"#{1}\", c);      c = false;',\n    className:    'n = h.className(n, r, \"#{1}\", c);    c = false;',\n    id:           'n = h.id(n, r, \"#{1}\", c);           c = false;',\n    attrPresence: 'n = h.attrPresence(n, r, \"#{1}\", c); c = false;',\n    attr: function(m) {\n      m[3] = (m[5] || m[6]);\n      return new Template('n = h.attr(n, r, \"#{1}\", \"#{3}\", \"#{2}\", c); c = false;').evaluate(m);\n    },\n    pseudo: function(m) {\n      if (m[6]) m[6] = m[6].replace(/\"/g, '\\\\\"');\n      return new Template('n = h.pseudo(n, \"#{1}\", \"#{6}\", r, c); c = false;').evaluate(m);\n    },\n    descendant:   'c = \"descendant\";',\n    child:        'c = \"child\";',\n    adjacent:     'c = \"adjacent\";',\n    laterSibling: 'c = \"laterSibling\";'\n  },\n\n  patterns: {\n    // combinators must be listed first\n    // (and descendant needs to be last combinator)\n    laterSibling: /^\\s*~\\s*/,\n    child:        /^\\s*>\\s*/,\n    adjacent:     /^\\s*\\+\\s*/,\n    descendant:   /^\\s/,\n\n    // selectors follow\n    tagName:      /^\\s*(\\*|[\\w\\-]+)(\\b|$)?/,\n    id:           /^#([\\w\\-\\*]+)(\\b|$)/,\n    className:    /^\\.([\\w\\-\\*]+)(\\b|$)/,\n    pseudo:\n/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\\((.*?)\\))?(\\b|$|(?=\\s|[:+~>]))/,\n    attrPresence: /^\\[((?:[\\w]+:)?[\\w]+)\\]/,\n    attr:         /\\[((?:[\\w-]*:)?[\\w-]+)\\s*(?:([!^$*~|]?=)\\s*((['\"])([^\\4]*?)\\4|([^'\"][^\\]]*?)))?\\]/\n  },\n\n  // for Selector.match and Element#match\n  assertions: {\n    tagName: function(element, matches) {\n      return matches[1].toUpperCase() == element.tagName.toUpperCase();\n    },\n\n    className: function(element, matches) {\n      return Element.hasClassName(element, matches[1]);\n    },\n\n    id: function(element, matches) {\n      return element.id === matches[1];\n    },\n\n    attrPresence: function(element, matches) {\n      return Element.hasAttribute(element, matches[1]);\n    },\n\n    attr: function(element, matches) {\n      var nodeValue = Element.readAttribute(element, matches[1]);\n      return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);\n    }\n  },\n\n  handlers: {\n    // UTILITY FUNCTIONS\n    // joins two collections\n    concat: function(a, b) {\n      for (var i = 0, node; node = b[i]; i++)\n        a.push(node);\n      return a;\n    },\n\n    // marks an array of nodes for counting\n    mark: function(nodes) {\n      var _true = Prototype.emptyFunction;\n      for (var i = 0, node; node = nodes[i]; i++)\n        node._countedByPrototype = _true;\n      return nodes;\n    },\n\n    unmark: function(nodes) {\n      for (var i = 0, node; node = nodes[i]; i++)\n        node._countedByPrototype = undefined;\n      return nodes;\n    },\n\n    // mark each child node with its position (for nth calls)\n    // \"ofType\" flag indicates whether we're indexing for nth-of-type\n    // rather than nth-child\n    index: function(parentNode, reverse, ofType) {\n      parentNode._countedByPrototype = Prototype.emptyFunction;\n      if (reverse) {\n        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {\n          var node = nodes[i];\n          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;\n        }\n      } else {\n        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)\n          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;\n      }\n    },\n\n    // filters out duplicates and extends all nodes\n    unique: function(nodes) {\n      if (nodes.length == 0) return nodes;\n      var results = [], n;\n      for (var i = 0, l = nodes.length; i < l; i++)\n        if (!(n = nodes[i])._countedByPrototype) {\n          n._countedByPrototype = Prototype.emptyFunction;\n          results.push(Element.extend(n));\n        }\n      return Selector.handlers.unmark(results);\n    },\n\n    // COMBINATOR FUNCTIONS\n    descendant: function(nodes) {\n      var h = Selector.handlers;\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        h.concat(results, node.getElementsByTagName('*'));\n      return results;\n    },\n\n    child: function(nodes) {\n      var h = Selector.handlers;\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\n        for (var j = 0, child; child = node.childNodes[j]; j++)\n          if (child.nodeType == 1 && child.tagName != '!') results.push(child);\n      }\n      return results;\n    },\n\n    adjacent: function(nodes) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\n        var next = this.nextElementSibling(node);\n        if (next) results.push(next);\n      }\n      return results;\n    },\n\n    laterSibling: function(nodes) {\n      var h = Selector.handlers;\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        h.concat(results, Element.nextSiblings(node));\n      return results;\n    },\n\n    nextElementSibling: function(node) {\n      while (node = node.nextSibling)\n        if (node.nodeType == 1) return node;\n      return null;\n    },\n\n    previousElementSibling: function(node) {\n      while (node = node.previousSibling)\n        if (node.nodeType == 1) return node;\n      return null;\n    },\n\n    // TOKEN FUNCTIONS\n    tagName: function(nodes, root, tagName, combinator) {\n      var uTagName = tagName.toUpperCase();\n      var results = [], h = Selector.handlers;\n      if (nodes) {\n        if (combinator) {\n          // fastlane for ordinary descendant combinators\n          if (combinator == \"descendant\") {\n            for (var i = 0, node; node = nodes[i]; i++)\n              h.concat(results, node.getElementsByTagName(tagName));\n            return results;\n          } else nodes = this[combinator](nodes);\n          if (tagName == \"*\") return nodes;\n        }\n        for (var i = 0, node; node = nodes[i]; i++)\n          if (node.tagName.toUpperCase() === uTagName) results.push(node);\n        return results;\n      } else return root.getElementsByTagName(tagName);\n    },\n\n    id: function(nodes, root, id, combinator) {\n      var targetNode = $(id), h = Selector.handlers;\n      if (!targetNode) return [];\n      if (!nodes && root == document) return [targetNode];\n      if (nodes) {\n        if (combinator) {\n          if (combinator == 'child') {\n            for (var i = 0, node; node = nodes[i]; i++)\n              if (targetNode.parentNode == node) return [targetNode];\n          } else if (combinator == 'descendant') {\n            for (var i = 0, node; node = nodes[i]; i++)\n              if (Element.descendantOf(targetNode, node)) return [targetNode];\n          } else if (combinator == 'adjacent') {\n            for (var i = 0, node; node = nodes[i]; i++)\n              if (Selector.handlers.previousElementSibling(targetNode) == node)\n                return [targetNode];\n          } else nodes = h[combinator](nodes);\n        }\n        for (var i = 0, node; node = nodes[i]; i++)\n          if (node == targetNode) return [targetNode];\n        return [];\n      }\n      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];\n    },\n\n    className: function(nodes, root, className, combinator) {\n      if (nodes && combinator) nodes = this[combinator](nodes);\n      return Selector.handlers.byClassName(nodes, root, className);\n    },\n\n    byClassName: function(nodes, root, className) {\n      if (!nodes) nodes = Selector.handlers.descendant([root]);\n      var needle = ' ' + className + ' ';\n      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {\n        nodeClassName = node.className;\n        if (nodeClassName.length == 0) continue;\n        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))\n          results.push(node);\n      }\n      return results;\n    },\n\n    attrPresence: function(nodes, root, attr, combinator) {\n      if (!nodes) nodes = root.getElementsByTagName(\"*\");\n      if (nodes && combinator) nodes = this[combinator](nodes);\n      var results = [];\n      for (var i = 0, node; node = nodes[i]; i++)\n        if (Element.hasAttribute(node, attr)) results.push(node);\n      return results;\n    },\n\n    attr: function(nodes, root, attr, value, operator, combinator) {\n      if (!nodes) nodes = root.getElementsByTagName(\"*\");\n      if (nodes && combinator) nodes = this[combinator](nodes);\n      var handler = Selector.operators[operator], results = [];\n      for (var i = 0, node; node = nodes[i]; i++) {\n        var nodeValue = Element.readAttribute(node, attr);\n        if (nodeValue === null) continue;\n        if (handler(nodeValue, value)) results.push(node);\n      }\n      return results;\n    },\n\n    pseudo: function(nodes, name, value, root, combinator) {\n      if (nodes && combinator) nodes = this[combinator](nodes);\n      if (!nodes) nodes = root.getElementsByTagName(\"*\");\n      return Selector.pseudos[name](nodes, value, root);\n    }\n  },\n\n  pseudos: {\n    'first-child': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\n        if (Selector.handlers.previousElementSibling(node)) continue;\n          results.push(node);\n      }\n      return results;\n    },\n    'last-child': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\n        if (Selector.handlers.nextElementSibling(node)) continue;\n          results.push(node);\n      }\n      return results;\n    },\n    'only-child': function(nodes, value, root) {\n      var h = Selector.handlers;\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))\n          results.push(node);\n      return results;\n    },\n    'nth-child':        function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, formula, root);\n    },\n    'nth-last-child':   function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, formula, root, true);\n    },\n    'nth-of-type':      function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, formula, root, false, true);\n    },\n    'nth-last-of-type': function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, formula, root, true, true);\n    },\n    'first-of-type':    function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, \"1\", root, false, true);\n    },\n    'last-of-type':     function(nodes, formula, root) {\n      return Selector.pseudos.nth(nodes, \"1\", root, true, true);\n    },\n    'only-of-type':     function(nodes, formula, root) {\n      var p = Selector.pseudos;\n      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);\n    },\n\n    // handles the an+b logic\n    getIndices: function(a, b, total) {\n      if (a == 0) return b > 0 ? [b] : [];\n      return $R(1, total).inject([], function(memo, i) {\n        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);\n        return memo;\n      });\n    },\n\n    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type\n    nth: function(nodes, formula, root, reverse, ofType) {\n      if (nodes.length == 0) return [];\n      if (formula == 'even') formula = '2n+0';\n      if (formula == 'odd')  formula = '2n+1';\n      var h = Selector.handlers, results = [], indexed = [], m;\n      h.mark(nodes);\n      for (var i = 0, node; node = nodes[i]; i++) {\n        if (!node.parentNode._countedByPrototype) {\n          h.index(node.parentNode, reverse, ofType);\n          indexed.push(node.parentNode);\n        }\n      }\n      if (formula.match(/^\\d+$/)) { // just a number\n        formula = Number(formula);\n        for (var i = 0, node; node = nodes[i]; i++)\n          if (node.nodeIndex == formula) results.push(node);\n      } else if (m = formula.match(/^(-?\\d*)?n(([+-])(\\d+))?/)) { // an+b\n        if (m[1] == \"-\") m[1] = -1;\n        var a = m[1] ? Number(m[1]) : 1;\n        var b = m[2] ? Number(m[2]) : 0;\n        var indices = Selector.pseudos.getIndices(a, b, nodes.length);\n        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {\n          for (var j = 0; j < l; j++)\n            if (node.nodeIndex == indices[j]) results.push(node);\n        }\n      }\n      h.unmark(nodes);\n      h.unmark(indexed);\n      return results;\n    },\n\n    'empty': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++) {\n        // IE treats comments as element nodes\n        if (node.tagName == '!' || node.firstChild) continue;\n        results.push(node);\n      }\n      return results;\n    },\n\n    'not': function(nodes, selector, root) {\n      var h = Selector.handlers, selectorType, m;\n      var exclusions = new Selector(selector).findElements(root);\n      h.mark(exclusions);\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        if (!node._countedByPrototype) results.push(node);\n      h.unmark(exclusions);\n      return results;\n    },\n\n    'enabled': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        if (!node.disabled && (!node.type || node.type !== 'hidden'))\n          results.push(node);\n      return results;\n    },\n\n    'disabled': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        if (node.disabled) results.push(node);\n      return results;\n    },\n\n    'checked': function(nodes, value, root) {\n      for (var i = 0, results = [], node; node = nodes[i]; i++)\n        if (node.checked) results.push(node);\n      return results;\n    }\n  },\n\n  operators: {\n    '=':  function(nv, v) { return nv == v; },\n    '!=': function(nv, v) { return nv != v; },\n    '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },\n    '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },\n    '*=': function(nv, v) { return nv == v || nv && nv.include(v); },\n    '$=': function(nv, v) { return nv.endsWith(v); },\n    '*=': function(nv, v) { return nv.include(v); },\n    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },\n    '|=': function(nv, v) { return ('-' + (nv || \"\").toUpperCase() +\n     '-').include('-' + (v || \"\").toUpperCase() + '-'); }\n  },\n\n  split: function(expression) {\n    var expressions = [];\n    expression.scan(/(([\\w#:.~>+()\\s-]+|\\*|\\[.*?\\])+)\\s*(,|$)/, function(m) {\n      expressions.push(m[1].strip());\n    });\n    return expressions;\n  },\n\n  matchElements: function(elements, expression) {\n    var matches = $$(expression), h = Selector.handlers;\n    h.mark(matches);\n    for (var i = 0, results = [], element; element = elements[i]; i++)\n      if (element._countedByPrototype) results.push(element);\n    h.unmark(matches);\n    return results;\n  },\n\n  findElement: function(elements, expression, index) {\n    if (Object.isNumber(expression)) {\n      index = expression; expression = false;\n    }\n    return Selector.matchElements(elements, expression || '*')[index || 0];\n  },\n\n  findChildElements: function(element, expressions) {\n    expressions = Selector.split(expressions.join(','));\n    var results = [], h = Selector.handlers;\n    for (var i = 0, l = expressions.length, selector; i < l; i++) {\n      selector = new Selector(expressions[i].strip());\n      h.concat(results, selector.findElements(element));\n    }\n    return (l > 1) ? h.unique(results) : results;\n  }\n});\n\nif (Prototype.Browser.IE) {\n  Object.extend(Selector.handlers, {\n    // IE returns comment nodes on getElementsByTagName(\"*\").\n    // Filter them out.\n    concat: function(a, b) {\n      for (var i = 0, node; node = b[i]; i++)\n        if (node.tagName !== \"!\") a.push(node);\n      return a;\n    },\n\n    // IE improperly serializes _countedByPrototype in (inner|outer)HTML.\n    unmark: function(nodes) {\n      for (var i = 0, node; node = nodes[i]; i++)\n        node.removeAttribute('_countedByPrototype');\n      return nodes;\n    }\n  });\n}\n\nfunction $$() {\n  return Selector.findChildElements(document, $A(arguments));\n}\nvar Form = {\n  reset: function(form) {\n    $(form).reset();\n    return form;\n  },\n\n  serializeElements: function(elements, options) {\n    if (typeof options != 'object') options = { hash: !!options };\n    else if (Object.isUndefined(options.hash)) options.hash = true;\n    var key, value, submitted = false, submit = options.submit;\n\n    var data = elements.inject({ }, function(result, element) {\n      if (!element.disabled && element.name) {\n        key = element.name; value = $(element).getValue();\n        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&\n            submit !== false && (!submit || key == submit) && (submitted = true)))) {\n          if (key in result) {\n            // a key is already present; construct an array of values\n            if (!Object.isArray(result[key])) result[key] = [result[key]];\n            result[key].push(value);\n          }\n          else result[key] = value;\n        }\n      }\n      return result;\n    });\n\n    return options.hash ? data : Object.toQueryString(data);\n  }\n};\n\nForm.Methods = {\n  serialize: function(form, options) {\n    return Form.serializeElements(Form.getElements(form), options);\n  },\n\n  getElements: function(form) {\n    return $A($(form).getElementsByTagName('*')).inject([],\n      function(elements, child) {\n        if (Form.Element.Serializers[child.tagName.toLowerCase()])\n          elements.push(Element.extend(child));\n        return elements;\n      }\n    );\n  },\n\n  getInputs: function(form, typeName, name) {\n    form = $(form);\n    var inputs = form.getElementsByTagName('input');\n\n    if (!typeName && !name) return $A(inputs).map(Element.extend);\n\n    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {\n      var input = inputs[i];\n      if ((typeName && input.type != typeName) || (name && input.name != name))\n        continue;\n      matchingInputs.push(Element.extend(input));\n    }\n\n    return matchingInputs;\n  },\n\n  disable: function(form) {\n    form = $(form);\n    Form.getElements(form).invoke('disable');\n    return form;\n  },\n\n  enable: function(form) {\n    form = $(form);\n    Form.getElements(form).invoke('enable');\n    return form;\n  },\n\n  findFirstElement: function(form) {\n    var elements = $(form).getElements().findAll(function(element) {\n      return 'hidden' != element.type && !element.disabled;\n    });\n    var firstByIndex = elements.findAll(function(element) {\n      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;\n    }).sortBy(function(element) { return element.tabIndex }).first();\n\n    return firstByIndex ? firstByIndex : elements.find(function(element) {\n      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());\n    });\n  },\n\n  focusFirstElement: function(form) {\n    form = $(form);\n    form.findFirstElement().activate();\n    return form;\n  },\n\n  request: function(form, options) {\n    form = $(form), options = Object.clone(options || { });\n\n    var params = options.parameters, action = form.readAttribute('action') || '';\n    if (action.blank()) action = window.location.href;\n    options.parameters = form.serialize(true);\n\n    if (params) {\n      if (Object.isString(params)) params = params.toQueryParams();\n      Object.extend(options.parameters, params);\n    }\n\n    if (form.hasAttribute('method') && !options.method)\n      options.method = form.method;\n\n    return new Ajax.Request(action, options);\n  }\n};\n\n/*--------------------------------------------------------------------------*/\n\nForm.Element = {\n  focus: function(element) {\n    $(element).focus();\n    return element;\n  },\n\n  select: function(element) {\n    $(element).select();\n    return element;\n  }\n};\n\nForm.Element.Methods = {\n  serialize: function(element) {\n    element = $(element);\n    if (!element.disabled && element.name) {\n      var value = element.getValue();\n      if (value != undefined) {\n        var pair = { };\n        pair[element.name] = value;\n        return Object.toQueryString(pair);\n      }\n    }\n    return '';\n  },\n\n  getValue: function(element) {\n    element = $(element);\n    var method = element.tagName.toLowerCase();\n    return Form.Element.Serializers[method](element);\n  },\n\n  setValue: function(element, value) {\n    element = $(element);\n    var method = element.tagName.toLowerCase();\n    Form.Element.Serializers[method](element, value);\n    return element;\n  },\n\n  clear: function(element) {\n    $(element).value = '';\n    return element;\n  },\n\n  present: function(element) {\n    return $(element).value != '';\n  },\n\n  activate: function(element) {\n    element = $(element);\n    try {\n      element.focus();\n      if (element.select && (element.tagName.toLowerCase() != 'input' ||\n          !['button', 'reset', 'submit'].include(element.type)))\n        element.select();\n    } catch (e) { }\n    return element;\n  },\n\n  disable: function(element) {\n    element = $(element);\n    element.disabled = true;\n    return element;\n  },\n\n  enable: function(element) {\n    element = $(element);\n    element.disabled = false;\n    return element;\n  }\n};\n\n/*--------------------------------------------------------------------------*/\n\nvar Field = Form.Element;\nvar $F = Form.Element.Methods.getValue;\n\n/*--------------------------------------------------------------------------*/\n\nForm.Element.Serializers = {\n  input: function(element, value) {\n    switch (element.type.toLowerCase()) {\n      case 'checkbox':\n      case 'radio':\n        return Form.Element.Serializers.inputSelector(element, value);\n      default:\n        return Form.Element.Serializers.textarea(element, value);\n    }\n  },\n\n  inputSelector: function(element, value) {\n    if (Object.isUndefined(value)) return element.checked ? element.value : null;\n    else element.checked = !!value;\n  },\n\n  textarea: function(element, value) {\n    if (Object.isUndefined(value)) return element.value;\n    else element.value = value;\n  },\n\n  select: function(element, value) {\n    if (Object.isUndefined(value))\n      return this[element.type == 'select-one' ?\n        'selectOne' : 'selectMany'](element);\n    else {\n      var opt, currentValue, single = !Object.isArray(value);\n      for (var i = 0, length = element.length; i < length; i++) {\n        opt = element.options[i];\n        currentValue = this.optionValue(opt);\n        if (single) {\n          if (currentValue == value) {\n            opt.selected = true;\n            return;\n          }\n        }\n        else opt.selected = value.include(currentValue);\n      }\n    }\n  },\n\n  selectOne: function(element) {\n    var index = element.selectedIndex;\n    return index >= 0 ? this.optionValue(element.options[index]) : null;\n  },\n\n  selectMany: function(element) {\n    var values, length = element.length;\n    if (!length) return null;\n\n    for (var i = 0, values = []; i < length; i++) {\n      var opt = element.options[i];\n      if (opt.selected) values.push(this.optionValue(opt));\n    }\n    return values;\n  },\n\n  optionValue: function(opt) {\n    // extend element because hasAttribute may not be native\n    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;\n  }\n};\n\n/*--------------------------------------------------------------------------*/\n\nAbstract.TimedObserver = Class.create(PeriodicalExecuter, {\n  initialize: function($super, element, frequency, callback) {\n    $super(callback, frequency);\n    this.element   = $(element);\n    this.lastValue = this.getValue();\n  },\n\n  execute: function() {\n    var value = this.getValue();\n    if (Object.isString(this.lastValue) && Object.isString(value) ?\n        this.lastValue != value : String(this.lastValue) != String(value)) {\n      this.callback(this.element, value);\n      this.lastValue = value;\n    }\n  }\n});\n\nForm.Element.Observer = Class.create(Abstract.TimedObserver, {\n  getValue: function() {\n    return Form.Element.getValue(this.element);\n  }\n});\n\nForm.Observer = Class.create(Abstract.TimedObserver, {\n  getValue: function() {\n    return Form.serialize(this.element);\n  }\n});\n\n/*--------------------------------------------------------------------------*/\n\nAbstract.EventObserver = Class.create({\n  initialize: function(element, callback) {\n    this.element  = $(element);\n    this.callback = callback;\n\n    this.lastValue = this.getValue();\n    if (this.element.tagName.toLowerCase() == 'form')\n      this.registerFormCallbacks();\n    else\n      this.registerCallback(this.element);\n  },\n\n  onElementEvent: function() {\n    var value = this.getValue();\n    if (this.lastValue != value) {\n      this.callback(this.element, value);\n      this.lastValue = value;\n    }\n  },\n\n  registerFormCallbacks: function() {\n    Form.getElements(this.element).each(this.registerCallback, this);\n  },\n\n  registerCallback: function(element) {\n    if (element.type) {\n      switch (element.type.toLowerCase()) {\n        case 'checkbox':\n        case 'radio':\n          Event.observe(element, 'click', this.onElementEvent.bind(this));\n          break;\n        default:\n          Event.observe(element, 'change', this.onElementEvent.bind(this));\n          break;\n      }\n    }\n  }\n});\n\nForm.Element.EventObserver = Class.create(Abstract.EventObserver, {\n  getValue: function() {\n    return Form.Element.getValue(this.element);\n  }\n});\n\nForm.EventObserver = Class.create(Abstract.EventObserver, {\n  getValue: function() {\n    return Form.serialize(this.element);\n  }\n});\nif (!window.Event) var Event = { };\n\nObject.extend(Event, {\n  KEY_BACKSPACE: 8,\n  KEY_TAB:       9,\n  KEY_RETURN:   13,\n  KEY_ESC:      27,\n  KEY_LEFT:     37,\n  KEY_UP:       38,\n  KEY_RIGHT:    39,\n  KEY_DOWN:     40,\n  KEY_DELETE:   46,\n  KEY_HOME:     36,\n  KEY_END:      35,\n  KEY_PAGEUP:   33,\n  KEY_PAGEDOWN: 34,\n  KEY_INSERT:   45,\n\n  cache: { },\n\n  relatedTarget: function(event) {\n    var element;\n    switch(event.type) {\n      case 'mouseover': element = event.fromElement; break;\n      case 'mouseout':  element = event.toElement;   break;\n      default: return null;\n    }\n    return Element.extend(element);\n  }\n});\n\nEvent.Methods = (function() {\n  var isButton;\n\n  if (Prototype.Browser.IE) {\n    var buttonMap = { 0: 1, 1: 4, 2: 2 };\n    isButton = function(event, code) {\n      return event.button == buttonMap[code];\n    };\n\n  } else if (Prototype.Browser.WebKit) {\n    isButton = function(event, code) {\n      switch (code) {\n        case 0: return event.which == 1 && !event.metaKey;\n        case 1: return event.which == 1 && event.metaKey;\n        default: return false;\n      }\n    };\n\n  } else {\n    isButton = function(event, code) {\n      return event.which ? (event.which === code + 1) : (event.button === code);\n    };\n  }\n\n  return {\n    isLeftClick:   function(event) { return isButton(event, 0) },\n    isMiddleClick: function(event) { return isButton(event, 1) },\n    isRightClick:  function(event) { return isButton(event, 2) },\n\n    element: function(event) {\n      event = Event.extend(event);\n\n      var node          = event.target,\n          type          = event.type,\n          currentTarget = event.currentTarget;\n\n      if (currentTarget && currentTarget.tagName) {\n        // Firefox screws up the \"click\" event when moving between radio buttons\n        // via arrow keys. It also screws up the \"load\" and \"error\" events on images,\n        // reporting the document as the target instead of the original image.\n        if (type === 'load' || type === 'error' ||\n          (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'\n            && currentTarget.type === 'radio'))\n              node = currentTarget;\n      }\n      if (node.nodeType == Node.TEXT_NODE) node = node.parentNode;\n      return Element.extend(node);\n    },\n\n    findElement: function(event, expression) {\n      var element = Event.element(event);\n      if (!expression) return element;\n      var elements = [element].concat(element.ancestors());\n      return Selector.findElement(elements, expression, 0);\n    },\n\n    pointer: function(event) {\n      var docElement = document.documentElement,\n      body = document.body || { scrollLeft: 0, scrollTop: 0 };\n      return {\n        x: event.pageX || (event.clientX +\n          (docElement.scrollLeft || body.scrollLeft) -\n          (docElement.clientLeft || 0)),\n        y: event.pageY || (event.clientY +\n          (docElement.scrollTop || body.scrollTop) -\n          (docElement.clientTop || 0))\n      };\n    },\n\n    pointerX: function(event) { return Event.pointer(event).x },\n    pointerY: function(event) { return Event.pointer(event).y },\n\n    stop: function(event) {\n      Event.extend(event);\n      event.preventDefault();\n      event.stopPropagation();\n      event.stopped = true;\n    }\n  };\n})();\n\nEvent.extend = (function() {\n  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {\n    m[name] = Event.Methods[name].methodize();\n    return m;\n  });\n\n  if (Prototype.Browser.IE) {\n    Object.extend(methods, {\n      stopPropagation: function() { this.cancelBubble = true },\n      preventDefault:  function() { this.returnValue = false },\n      inspect: function() { return \"[object Event]\" }\n    });\n\n    return function(event) {\n      if (!event) return false;\n      if (event._extendedByPrototype) return event;\n\n      event._extendedByPrototype = Prototype.emptyFunction;\n      var pointer = Event.pointer(event);\n      Object.extend(event, {\n        target: event.srcElement,\n        relatedTarget: Event.relatedTarget(event),\n        pageX:  pointer.x,\n        pageY:  pointer.y\n      });\n      return Object.extend(event, methods);\n    };\n\n  } else {\n    Event.prototype = Event.prototype || document.createEvent(\"HTMLEvents\")['__proto__'];\n    Object.extend(Event.prototype, methods);\n    return Prototype.K;\n  }\n})();\n\nObject.extend(Event, (function() {\n  var cache = Event.cache;\n\n  function getEventID(element) {\n    if (element._prototypeEventID) return element._prototypeEventID[0];\n    arguments.callee.id = arguments.callee.id || 1;\n    return element._prototypeEventID = [++arguments.callee.id];\n  }\n\n  function getDOMEventName(eventName) {\n    if (eventName && eventName.include(':')) return \"dataavailable\";\n    return eventName;\n  }\n\n  function getCacheForID(id) {\n    return cache[id] = cache[id] || { };\n  }\n\n  function getWrappersForEventName(id, eventName) {\n    var c = getCacheForID(id);\n    return c[eventName] = c[eventName] || [];\n  }\n\n  function createWrapper(element, eventName, handler) {\n    var id = getEventID(element);\n    var c = getWrappersForEventName(id, eventName);\n    if (c.pluck(\"handler\").include(handler)) return false;\n\n    var wrapper = function(event) {\n      if (!Event || !Event.extend ||\n        (event.eventName && event.eventName != eventName))\n          return false;\n\n      Event.extend(event);\n      handler.call(element, event);\n    };\n\n    wrapper.handler = handler;\n    c.push(wrapper);\n    return wrapper;\n  }\n\n  function findWrapper(id, eventName, handler) {\n    var c = getWrappersForEventName(id, eventName);\n    return c.find(function(wrapper) { return wrapper.handler == handler });\n  }\n\n  function destroyWrapper(id, eventName, handler) {\n    var c = getCacheForID(id);\n    if (!c[eventName]) return false;\n    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));\n  }\n\n  function destroyCache() {\n    for (var id in cache)\n      for (var eventName in cache[id])\n        cache[id][eventName] = null;\n  }\n\n\n  // Internet Explorer needs to remove event handlers on page unload\n  // in order to avoid memory leaks.\n  if (window.attachEvent) {\n    window.attachEvent(\"onunload\", destroyCache);\n  }\n\n  // Safari has a dummy event handler on page unload so that it won't\n  // use its bfcache. Safari <= 3.1 has an issue with restoring the \"document\"\n  // object when page is returned to via the back button using its bfcache.\n  if (Prototype.Browser.WebKit) {\n    window.addEventListener('unload', Prototype.emptyFunction, false);\n  }\n\n  return {\n    observe: function(element, eventName, handler) {\n      element = $(element);\n      var name = getDOMEventName(eventName);\n\n      var wrapper = createWrapper(element, eventName, handler);\n      if (!wrapper) return element;\n\n      if (element.addEventListener) {\n        element.addEventListener(name, wrapper, false);\n      } else {\n        element.attachEvent(\"on\" + name, wrapper);\n      }\n\n      return element;\n    },\n\n    stopObserving: function(element, eventName, handler) {\n      element = $(element);\n      var id = getEventID(element), name = getDOMEventName(eventName);\n\n      if (!handler && eventName) {\n        getWrappersForEventName(id, eventName).each(function(wrapper) {\n          element.stopObserving(eventName, wrapper.handler);\n        });\n        return element;\n\n      } else if (!eventName) {\n        Object.keys(getCacheForID(id)).each(function(eventName) {\n          element.stopObserving(eventName);\n        });\n        return element;\n      }\n\n      var wrapper = findWrapper(id, eventName, handler);\n      if (!wrapper) return element;\n\n      if (element.removeEventListener) {\n        element.removeEventListener(name, wrapper, false);\n      } else {\n        element.detachEvent(\"on\" + name, wrapper);\n      }\n\n      destroyWrapper(id, eventName, handler);\n\n      return element;\n    },\n\n    fire: function(element, eventName, memo) {\n      element = $(element);\n      if (element == document && document.createEvent && !element.dispatchEvent)\n        element = document.documentElement;\n\n      var event;\n      if (document.createEvent) {\n        event = document.createEvent(\"HTMLEvents\");\n        event.initEvent(\"dataavailable\", true, true);\n      } else {\n        event = document.createEventObject();\n        event.eventType = \"ondataavailable\";\n      }\n\n      event.eventName = eventName;\n      event.memo = memo || { };\n\n      if (document.createEvent) {\n        element.dispatchEvent(event);\n      } else {\n        element.fireEvent(event.eventType, event);\n      }\n\n      return Event.extend(event);\n    }\n  };\n})());\n\nObject.extend(Event, Event.Methods);\n\nElement.addMethods({\n  fire:          Event.fire,\n  observe:       Event.observe,\n  stopObserving: Event.stopObserving\n});\n\nObject.extend(document, {\n  fire:          Element.Methods.fire.methodize(),\n  observe:       Element.Methods.observe.methodize(),\n  stopObserving: Element.Methods.stopObserving.methodize(),\n  loaded:        false\n});\n\n(function() {\n  /* Support for the DOMContentLoaded event is based on work by Dan Webb,\n     Matthias Miller, Dean Edwards and John Resig. */\n\n  var timer;\n\n  function fireContentLoadedEvent() {\n    if (document.loaded) return;\n    if (timer) window.clearInterval(timer);\n    document.fire(\"dom:loaded\");\n    document.loaded = true;\n  }\n\n  if (document.addEventListener) {\n    if (Prototype.Browser.WebKit) {\n      timer = window.setInterval(function() {\n        if (/loaded|complete/.test(document.readyState))\n          fireContentLoadedEvent();\n      }, 0);\n\n      Event.observe(window, \"load\", fireContentLoadedEvent);\n\n    } else {\n      document.addEventListener(\"DOMContentLoaded\",\n        fireContentLoadedEvent, false);\n    }\n\n  } else {\n    document.write(\"<script id=__onDOMContentLoaded defer src=//:><\\/script>\");\n    $(\"__onDOMContentLoaded\").onreadystatechange = function() {\n      if (this.readyState == \"complete\") {\n        this.onreadystatechange = null;\n        fireContentLoadedEvent();\n      }\n    };\n  }\n})();\n/*------------------------------- DEPRECATED -------------------------------*/\n\nHash.toQueryString = Object.toQueryString;\n\nvar Toggle = { display: Element.toggle };\n\nElement.Methods.childOf = Element.Methods.descendantOf;\n\nvar Insertion = {\n  Before: function(element, content) {\n    return Element.insert(element, {before:content});\n  },\n\n  Top: function(element, content) {\n    return Element.insert(element, {top:content});\n  },\n\n  Bottom: function(element, content) {\n    return Element.insert(element, {bottom:content});\n  },\n\n  After: function(element, content) {\n    return Element.insert(element, {after:content});\n  }\n};\n\nvar $continue = new Error('\"throw $continue\" is deprecated, use \"return\" instead');\n\n// This should be moved to script.aculo.us; notice the deprecated methods\n// further below, that map to the newer Element methods.\nvar Position = {\n  // set to true if needed, warning: firefox performance problems\n  // NOT neeeded for page scrolling, only if draggable contained in\n  // scrollable elements\n  includeScrollOffsets: false,\n\n  // must be called before calling withinIncludingScrolloffset, every time the\n  // page is scrolled\n  prepare: function() {\n    this.deltaX =  window.pageXOffset\n                || document.documentElement.scrollLeft\n                || document.body.scrollLeft\n                || 0;\n    this.deltaY =  window.pageYOffset\n                || document.documentElement.scrollTop\n                || document.body.scrollTop\n                || 0;\n  },\n\n  // caches x/y coordinate pair to use with overlap\n  within: function(element, x, y) {\n    if (this.includeScrollOffsets)\n      return this.withinIncludingScrolloffsets(element, x, y);\n    this.xcomp = x;\n    this.ycomp = y;\n    this.offset = Element.cumulativeOffset(element);\n\n    return (y >= this.offset[1] &&\n            y <  this.offset[1] + element.offsetHeight &&\n            x >= this.offset[0] &&\n            x <  this.offset[0] + element.offsetWidth);\n  },\n\n  withinIncludingScrolloffsets: function(element, x, y) {\n    var offsetcache = Element.cumulativeScrollOffset(element);\n\n    this.xcomp = x + offsetcache[0] - this.deltaX;\n    this.ycomp = y + offsetcache[1] - this.deltaY;\n    this.offset = Element.cumulativeOffset(element);\n\n    return (this.ycomp >= this.offset[1] &&\n            this.ycomp <  this.offset[1] + element.offsetHeight &&\n            this.xcomp >= this.offset[0] &&\n            this.xcomp <  this.offset[0] + element.offsetWidth);\n  },\n\n  // within must be called directly before\n  overlap: function(mode, element) {\n    if (!mode) return 0;\n    if (mode == 'vertical')\n      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /\n        element.offsetHeight;\n    if (mode == 'horizontal')\n      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /\n        element.offsetWidth;\n  },\n\n  // Deprecation layer -- use newer Element methods now (1.5.2).\n\n  cumulativeOffset: Element.Methods.cumulativeOffset,\n\n  positionedOffset: Element.Methods.positionedOffset,\n\n  absolutize: function(element) {\n    Position.prepare();\n    return Element.absolutize(element);\n  },\n\n  relativize: function(element) {\n    Position.prepare();\n    return Element.relativize(element);\n  },\n\n  realOffset: Element.Methods.cumulativeScrollOffset,\n\n  offsetParent: Element.Methods.getOffsetParent,\n\n  page: Element.Methods.viewportOffset,\n\n  clone: function(source, target, options) {\n    options = options || { };\n    return Element.clonePosition(target, source, options);\n  }\n};\n\n/*--------------------------------------------------------------------------*/\n\nif (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){\n  function iter(name) {\n    return name.blank() ? null : \"[contains(concat(' ', @class, ' '), ' \" + name + \" ')]\";\n  }\n\n  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?\n  function(element, className) {\n    className = className.toString().strip();\n    var cond = /\\s/.test(className) ? $w(className).map(iter).join('') : iter(className);\n    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];\n  } : function(element, className) {\n    className = className.toString().strip();\n    var elements = [], classNames = (/\\s/.test(className) ? $w(className) : null);\n    if (!classNames && !className) return elements;\n\n    var nodes = $(element).getElementsByTagName('*');\n    className = ' ' + className + ' ';\n\n    for (var i = 0, child, cn; child = nodes[i]; i++) {\n      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||\n          (classNames && classNames.all(function(name) {\n            return !name.toString().blank() && cn.include(' ' + name + ' ');\n          }))))\n        elements.push(Element.extend(child));\n    }\n    return elements;\n  };\n\n  return function(className, parentElement) {\n    return $(parentElement || document.body).getElementsByClassName(className);\n  };\n}(Element.Methods);\n\n/*--------------------------------------------------------------------------*/\n\nElement.ClassNames = Class.create();\nElement.ClassNames.prototype = {\n  initialize: function(element) {\n    this.element = $(element);\n  },\n\n  _each: function(iterator) {\n    this.element.className.split(/\\s+/).select(function(name) {\n      return name.length > 0;\n    })._each(iterator);\n  },\n\n  set: function(className) {\n    this.element.className = className;\n  },\n\n  add: function(classNameToAdd) {\n    if (this.include(classNameToAdd)) return;\n    this.set($A(this).concat(classNameToAdd).join(' '));\n  },\n\n  remove: function(classNameToRemove) {\n    if (!this.include(classNameToRemove)) return;\n    this.set($A(this).without(classNameToRemove).join(' '));\n  },\n\n  toString: function() {\n    return $A(this).join(' ');\n  }\n};\n\nObject.extend(Element.ClassNames.prototype, Enumerable);\n\n/*--------------------------------------------------------------------------*/\n\nElement.addMethods();\n"
  },
  {
    "path": "public/javascripts/repository_navigation.js",
    "content": "Event.observe(window,'load',function() {\n  /*\n  If we're viewing a tag or branch, don't display it in the\n  revision box\n  */\n  var branch_selected = $('branch') && $('rev').getValue() == $('branch').getValue();\n  var tag_selected = $('tag') && $('rev').getValue() == $('tag').getValue();\n  if (branch_selected || tag_selected) {\n    $('rev').setValue('');\n  }\n\n  /*\n  Copy the branch/tag value into the revision box, then disable\n  the dropdowns before submitting the form\n  */\n  $$('#branch,#tag').each(function(e) {\n    e.observe('change',function(e) {\n      $('rev').setValue(e.element().getValue());\n      $$('#branch,#tag').invoke('disable');\n      e.element().parentNode.submit();\n      $$('#branch,#tag').invoke('enable');\n    });\n  });\n\n  /*\n  Disable the branch/tag dropdowns before submitting the revision form\n  */\n  $('rev').observe('keydown', function(e) {\n    if (e.keyCode == 13) {\n      $$('#branch,#tag').invoke('disable');\n      e.element().parentNode.submit();\n      $$('#branch,#tag').invoke('enable');\n    }\n  });\n})\n"
  },
  {
    "path": "public/javascripts/retro.js",
    "content": "var confdescriptions = ['Wild guess','I\\'m probably wrong', 'Not sure', 'Confident', 'Pretty sure', 'Absolutely positive'];\n\n$('document').ready(function(){\n\n  if (retroStatus == 1){\n    $(\".closed\").hide();\n    $(\".open\").show();\n  }\n  else{\n    $(\".closed\").show();\n    $(\".open\").hide();\n  }\n\n  if (belongs){\n    $(\".private\").show();\n  }\n  else{\n    $(\".private\").hide();\n  }\n\n  calculate_sum();\n\n  $(\".slider-per\").slider({\n    range: \"min\",\n    value: 0,\n    min: 0,\n    max: 100,\n    step: 1,\n    slide: function(event, ui) {\n      var user_id = $(\"#\" + this.id).attr(\"user_id\");\n      $(\"#user_\" + user_id + \"_percentage\").html(ui.value + '%');\n      calculate_sum();\n    }\n  });\n\n  $(\".slider-per\").each(function(){\n     $(\"#\" + this.id).slider('value',parseInt($(\"#\" + this.id).attr(\"per\")));\n  });\n\n  $(\".slider-conf\").slider({\n    range: \"min\",\n    value: 0,\n    min: 0,\n    max: 100,\n    step: 20,\n    slide: function(event, ui) {\n      var user_id = $(\"#\" + this.id).attr(\"user_id\");\n      $(\"#user_\" + user_id + \"_percentage\").html(confdescriptions[ui.value/20] + ' (' + ui.value + ')%');\n      calculate_sum();\n    }\n  });\n\n  $(\".slider-conf\").each(function(){\n     $(\"#\" + this.id).slider('value',parseInt($(\"#\" + this.id).attr(\"per\")));\n  });\n\n  var confvalue = $('#slider_confidence').slider('value');\n  $(\"#user_0_percentage\").html(confdescriptions[confvalue/20] + ' (' + confvalue + ')%');\n\n\n});\n\nfunction calculate_sum(){\n  $('#success').hide();\n  $('#saving').hide();\n  var total = 0;\n  $(\".percentage_label\").each(function() {\n    total = total + parseInt($(\"#\" + this.id).html().replace('%',''));\n  });\n\n\n  $('#total').html(total + '%');\n  if ((total > 95)&&(total < 105)){\n    $('#change_retro_link_save').show();\n  }\n  else{\n    $('#change_retro_link_save').hide();\n  }\n}\n\n\nfunction save_retro(retroId){\n  $('#saving').show();\n\n  var data = \"commit=Create\";\n  var rater_id = currentUserId;\n  var confidence = $(\"#slider_confidence\").slider('value');\n  var i=0;\n  $('#change_retro_link_save').hide();\n\n  $(\".slider\").each(function() {\n    var ratee_id = $(\"#\" + this.id).attr(\"user_id\");\n    if (ratee_id != \"0\"){\n      var score = $(\"#\" + this.id).slider('value');\n      data = data + '&retro_ratings['+i+'][rater_id]=' + rater_id;\n      data = data + '&retro_ratings['+i+'][ratee_id]=' + ratee_id;\n      data = data + '&retro_ratings['+i+'][score]=' + score;\n      data = data + '&retro_ratings['+i+'][retro_id]=' + retroId;\n      data = data + '&retro_ratings['+i+'][confidence]=' + confidence;\n      i++;\n    }\n  });\n\n\n    var url = url_for({ controller: 'retro_ratings',\n                           action    : 'create'\n                          });\n\n  $.ajax({\n     type: \"POST\",\n     dataType: \"json\",\n     url: url,\n     data: data,\n     success:    function(html){\n      saved();\n    },\n     error:   function (XMLHttpRequest, textStatus, errorThrown) {\n    // typically only one of textStatus or errorThrown will have info\n    // possible valuees for textstatus \"timeout\", \"error\", \"notmodified\" and \"parsererror\n    $('#change_retro_link_save').show();\n    $.jGrowl(\"Sorry, couldn't save!\", { header: 'Error', position: 'bottom-right' });\n    },\n    timeout: 30000 //30 seconds\n   });\n}\n\nfunction saved(){\n  $('#saving').hide();\n  $('#success').show();\n}\n"
  },
  {
    "path": "public/javascripts/select_list_move.js",
    "content": "var NS4 = (navigator.appName == \"Netscape\" && parseInt(navigator.appVersion) < 5);\n\nfunction addOption(theSel, theText, theValue)\n{\n  var newOpt = new Option(theText, theValue);\n  var selLength = theSel.length;\n  theSel.options[selLength] = newOpt;\n}\n\nfunction swapOptions(theSel, index1, index2)\n{\n  var text, value;\n  text = theSel.options[index1].text;\n  value = theSel.options[index1].value;\n  theSel.options[index1].text = theSel.options[index2].text;\n  theSel.options[index1].value = theSel.options[index2].value;\n  theSel.options[index2].text = text;\n  theSel.options[index2].value = value;\n}\n\nfunction deleteOption(theSel, theIndex)\n{\n  var selLength = theSel.length;\n  if(selLength>0)\n  {\n    theSel.options[theIndex] = null;\n  }\n}\n\nfunction moveOptions(theSelFrom, theSelTo)\n{\n\n  var selLength = theSelFrom.length;\n  var selectedText = new Array();\n  var selectedValues = new Array();\n  var selectedCount = 0;\n\n  var i;\n\n  for(i=selLength-1; i>=0; i--)\n  {\n    if(theSelFrom.options[i].selected)\n    {\n      selectedText[selectedCount] = theSelFrom.options[i].text;\n      selectedValues[selectedCount] = theSelFrom.options[i].value;\n      deleteOption(theSelFrom, i);\n      selectedCount++;\n    }\n  }\n\n  for(i=selectedCount-1; i>=0; i--)\n  {\n    addOption(theSelTo, selectedText[i], selectedValues[i]);\n  }\n\n  if(NS4) history.go(0);\n}\n\nfunction moveOptionUp(theSel) {\n  var index = theSel.selectedIndex;\n  if (index > 0) {\n    swapOptions(theSel, index-1, index);\n    theSel.selectedIndex = index-1;\n  }\n}\n\nfunction moveOptionDown(theSel) {\n  var index = theSel.selectedIndex;\n  if (index < theSel.length - 1) {\n    swapOptions(theSel, index, index+1);\n    theSel.selectedIndex = index+1;\n  }\n}\n\nfunction selectAllOptions(id)\n{\n  var select = $(id);\n  for (var i=0; i<select.options.length; i++) {\n    select.options[i].selected = true;\n  }\n}\n\n"
  },
  {
    "path": "public/javascripts/static/Quicksand_Book_400.font.js",
    "content": "/*!\n * The following copyright notice may not be removed under any circumstances.\n *\n * Copyright:\n * Copyright (c) Andrew Paglinawan, 2008. All rights reserved.\n *\n * Trademark:\n * Dashling is a trademark of the Andrew Paglinawan.\n *\n * Full name:\n * QuicksandBook-Regular\n *\n * Manufacturer:\n * Andrew Paglinawan\n *\n * Designer:\n * Andrew Paglinawan\n */\nCufon.registerFont({\"w\":237,\"face\":{\"font-family\":\"Quicksand Book\",\"font-weight\":400,\"font-stretch\":\"normal\",\"units-per-em\":\"360\",\"panose-1\":\"2 7 3 3 0 0 0 6 0 0\",\"ascent\":\"288\",\"descent\":\"-72\",\"bbox\":\"-8.91478 -289 381.785 74\",\"underline-thickness\":\"18\",\"underline-position\":\"-18\",\"unicode-range\":\"U+0020-U+007E\"},\"glyphs\":{\" \":{\"w\":108},\"B\":{\"d\":\"37,-9r0,-234v6,-18,44,-7,65,-9v58,-5,85,80,39,112v28,10,49,36,49,68v0,40,-32,72,-72,72r-72,0v-5,0,-9,-4,-9,-9xm55,-18r63,0v30,0,54,-24,54,-54v0,-55,-58,-58,-117,-54r0,108xm55,-144v47,4,92,-2,92,-45v0,-43,-45,-49,-92,-45r0,90\",\"w\":213,\"k\":{\"?\":2,\"A\":7,\"y\":4,\"w\":4,\"v\":14,\"i\":14,\"Y\":11,\"X\":7,\"W\":5,\"V\":7,\"T\":7,\"I\":4,\"B\":25}},\"C\":{\"d\":\"26,-127v0,-105,132,-168,213,-101v9,7,-3,22,-11,15v-68,-58,-184,-6,-184,86v0,88,115,143,183,85v9,-7,22,7,12,15v-80,65,-213,3,-213,-100\",\"w\":277,\"k\":{\"-\":4,\"A\":5,\"y\":4,\"x\":4,\"w\":4,\"v\":4,\"q\":4,\"o\":4,\"l\":12,\"g\":4,\"e\":4,\"d\":4,\"c\":4,\"Y\":7,\"X\":4,\"Q\":7,\"O\":7,\"G\":7,\"C\":7}},\"D\":{\"d\":\"219,-126v0,86,-72,139,-174,126v-4,0,-8,-4,-8,-9r0,-234v4,-18,37,-9,56,-9v69,0,126,57,126,126xm55,-18v86,10,147,-34,147,-108v0,-73,-61,-118,-147,-108r0,216\",\"w\":258,\"k\":{\"}\":7,\"]\":7,\"\\\\\":14,\",\":14,\"\\/\":14,\"?\":7,\".\":14,\"A\":23,\")\":11,\"x\":4,\"w\":8,\"a\":32,\"Z\":16,\"Y\":23,\"X\":20,\"W\":13,\"V\":16,\"T\":20,\"S\":4,\"R\":7,\"O\":5,\"N\":22,\"J\":14,\"I\":18,\"H\":18,\"E\":18,\"D\":11}},\"E\":{\"d\":\"37,-9r0,-234v0,-5,4,-9,10,-9r129,0v5,0,8,4,8,9v0,5,-3,9,-8,9r-121,0r0,99r106,0v5,0,8,4,8,9v0,5,-3,9,-8,9r-106,0r0,99r121,0v5,0,8,4,8,9v0,5,-3,9,-8,9r-131,0v-4,0,-8,-4,-8,-9\",\"w\":213,\"k\":{\"y\":4,\"w\":4,\"v\":4,\"o\":4,\"e\":4,\"d\":4,\"c\":4,\"R\":-7}},\"F\":{\"d\":\"37,-9r0,-234v0,-5,4,-9,10,-9r129,0v5,0,9,4,9,9v0,5,-4,9,-9,9r-121,0r0,99r106,0v5,0,9,4,9,9v0,5,-4,9,-9,9r-106,0r0,108v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9\",\"w\":217,\"k\":{\",\":36,\"\\/\":25,\"?\":-4,\".\":36,\"A\":29,\"z\":5,\"y\":5,\"w\":4,\"v\":5,\"u\":26,\"s\":4,\"q\":4,\"o\":26,\"m\":26,\"g\":4,\"e\":5,\"d\":4,\"c\":5,\"a\":9,\"&\":11,\"Z\":4,\"Q\":7,\"O\":7,\"J\":40,\"G\":7,\"C\":7}},\"G\":{\"d\":\"242,-36v-13,29,-54,36,-85,36v-72,0,-131,-57,-131,-128v0,-103,133,-168,213,-99v8,6,-3,21,-11,14v-67,-58,-184,-4,-184,85v0,87,108,142,180,89r0,-74r-69,0v-5,0,-9,-4,-9,-9v0,-5,4,-9,9,-9r79,0v4,0,8,4,8,9r0,86\",\"w\":293,\"k\":{\"\\\\\":5,\"?\":4,\"y\":2,\"w\":19,\"v\":2,\"o\":7,\"a\":-4,\"Y\":11,\"X\":4,\"W\":5,\"V\":7,\"T\":7,\"L\":18,\"H\":16,\"F\":18}},\"H\":{\"d\":\"185,-9r0,-108r-130,0r0,108v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9r0,-234v0,-5,4,-9,9,-9v5,0,9,4,9,9r0,108r130,0r0,-108v0,-5,3,-9,8,-9v5,0,9,4,9,9r0,234v0,5,-4,9,-9,9v-5,0,-8,-4,-8,-9\",\"w\":255,\"k\":{\"A\":23,\"Y\":16,\"W\":18,\"O\":11,\"I\":18}},\"I\":{\"d\":\"40,-243v0,-5,4,-9,9,-9v5,0,9,4,9,9r0,234v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9r0,-234\",\"w\":109},\"J\":{\"d\":\"17,-59v-1,-5,0,-10,5,-11v5,-1,10,1,11,5v9,28,35,47,65,47v37,0,68,-30,68,-67r0,-158v0,-5,4,-9,9,-9v5,0,8,4,8,9r0,158v0,48,-38,85,-85,85v-38,0,-70,-25,-81,-59\",\"w\":213,\"k\":{\",\":5,\".\":5,\"A\":9,\"i\":-11,\"h\":-8,\"e\":-15,\"a\":-19,\"J\":7}},\"K\":{\"d\":\"37,-9r0,-233v0,-5,4,-9,9,-9v5,0,9,4,9,9r0,146r152,-153v9,-7,22,4,13,13r-97,96r99,126v5,5,-1,14,-7,14v-3,0,-5,0,-7,-3r-97,-124r-56,55r0,63v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9\",\"w\":257,\"k\":{\"-\":18,\"y\":18,\"w\":18,\"v\":22,\"u\":7,\"t\":9,\"q\":9,\"o\":11,\"g\":9,\"f\":7,\"e\":11,\"d\":9,\"c\":11,\"a\":4,\"&\":4,\"Y\":14,\"W\":11,\"V\":11,\"U\":5,\"T\":4,\"S\":4,\"Q\":18,\"O\":18,\"G\":18,\"C\":18,\"B\":16}},\"L\":{\"d\":\"176,0r-130,0v-5,0,-9,-4,-9,-9r0,-234v0,-5,4,-9,9,-9v5,0,9,4,9,9r0,225r121,0v5,0,9,4,9,9v0,5,-4,9,-9,9\",\"w\":202,\"k\":{\"\\\\\":43,\"*\":29,\"-\":14,\"?\":22,\"w\":18,\"v\":22,\"t\":7,\"q\":2,\"o\":4,\"g\":2,\"f\":7,\"e\":4,\"d\":2,\"c\":4,\"&\":4,\"Y\":47,\"W\":36,\"V\":41,\"U\":7,\"T\":36,\"Q\":14,\"O\":14,\"I\":-2,\"G\":14,\"C\":14}},\"M\":{\"d\":\"232,-9r0,-207r-81,112v-3,6,-11,6,-15,0r-81,-112r0,207v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9r0,-233v0,-8,12,-12,17,-5r90,124r89,-124v5,-7,17,-3,16,5r0,233v0,5,-4,9,-9,9v-5,0,-8,-4,-8,-9\",\"w\":303,\"k\":{\"A\":23,\"P\":18,\"O\":16,\"M\":12,\"E\":18}},\"N\":{\"d\":\"224,-9v1,9,-14,13,-17,4r-151,-210r0,206v0,5,-4,9,-9,9v-5,0,-8,-4,-8,-9r0,-231v-3,-8,10,-15,15,-7r153,211r0,-205v0,-5,3,-8,8,-8v5,0,9,3,9,8r0,232\",\"w\":277,\"k\":{\"Y\":16,\"U\":18,\"T\":4,\"O\":18,\"N\":12,\"I\":13,\"G\":18,\"E\":23,\"D\":18}},\"O\":{\"d\":\"26,-128v0,-71,54,-128,122,-128v67,0,121,57,121,128v0,71,-54,128,-121,128v-68,0,-122,-57,-122,-128xm44,-128v0,62,47,110,104,110v55,0,103,-48,103,-110v0,-62,-48,-110,-103,-110v-57,0,-104,48,-104,110\",\"w\":306,\"k\":{\"}\":7,\"]\":7,\"\\\\\":14,\",\":14,\"\\/\":14,\"?\":7,\".\":14,\"A\":14,\")\":11,\"x\":2,\"Z\":14,\"Y\":22,\"X\":18,\"W\":13,\"V\":14,\"U\":16,\"T\":20,\"S\":2,\"O\":4,\"N\":9,\"M\":14,\"L\":2,\"K\":11,\"J\":11,\"I\":18,\"H\":14,\"D\":11,\"C\":11,\"B\":13}},\"P\":{\"d\":\"37,-9r0,-234v0,-5,4,-9,10,-9r70,0v40,0,72,32,72,72v0,40,-32,72,-72,72r-62,0r0,99v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9xm55,-125r62,0v30,0,55,-25,55,-55v0,-54,-58,-58,-117,-54r0,109\",\"w\":209,\"k\":{\",\":36,\"\\/\":22,\".\":36,\"A\":25,\"y\":-4,\"w\":-4,\"v\":-4,\"u\":-2,\"t\":-5,\"o\":5,\"g\":8,\"f\":11,\"e\":4,\"d\":8,\"c\":2,\"&\":7,\"Z\":5,\"Y\":4,\"X\":11,\"W\":2,\"V\":4,\"J\":36}},\"Q\":{\"d\":\"155,8v43,13,79,46,122,8v4,-3,9,-2,12,2v3,4,3,10,-1,13v-20,15,-39,21,-57,21v-41,1,-86,-46,-127,-21v-6,4,-12,0,-13,-4v-2,-19,26,-18,38,-27v-60,-8,-105,-63,-105,-127v0,-70,54,-129,121,-129v67,0,121,59,121,129v0,71,-53,116,-111,135xm42,-127v0,61,47,110,103,110v56,0,103,-49,103,-110v0,-62,-47,-110,-103,-110v-56,0,-103,48,-103,110\",\"w\":303,\"k\":{\"?\":7,\")\":4,\"Y\":23,\"W\":13,\"V\":14,\"T\":20}},\"R\":{\"d\":\"191,-4v-25,0,-26,-21,-28,-53v-3,-51,-56,-55,-113,-51r0,99v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9r0,-234v0,-5,4,-10,10,-9r70,0v76,-4,97,111,31,137v18,10,37,28,37,58v0,28,4,32,17,41v1,5,-1,10,-6,12xm167,-180v0,-54,-58,-58,-117,-54r0,108v59,4,117,1,117,-54\",\"w\":225,\"k\":{\"t\":-4,\"q\":2,\"o\":4,\"g\":2,\"f\":-4,\"e\":4,\"d\":2,\"c\":4,\"Y\":9,\"W\":5,\"V\":7,\"U\":22,\"T\":7,\"O\":6,\"J\":2}},\"S\":{\"d\":\"68,-225v-47,36,1,79,53,85v44,5,92,24,92,70v0,43,-46,71,-93,70v-39,0,-72,-19,-93,-36v-3,-3,-4,-8,-1,-11v3,-4,8,-4,11,-1v36,40,155,48,160,-22v-10,-77,-165,-32,-165,-120v0,-40,43,-66,87,-66v33,0,58,17,78,30v4,3,5,7,2,11v-2,4,-7,5,-11,2v-29,-25,-86,-38,-120,-12\",\"w\":240,\"k\":{\"\\\\\":7,\"?\":4,\"A\":5,\"z\":2,\"y\":5,\"x\":5,\"w\":4,\"v\":5,\"t\":2,\"f\":2,\"Z\":4,\"Y\":11,\"X\":9,\"W\":9,\"V\":11,\"T\":5,\"S\":4}},\"T\":{\"d\":\"103,-9r0,-225r-76,0v-5,0,-9,-4,-9,-9v0,-5,4,-9,9,-9r169,0v5,0,8,4,8,9v0,5,-3,9,-8,9r-76,0r0,225v0,5,-4,9,-9,9v-5,0,-8,-4,-8,-9\",\"w\":233,\"k\":{\",\":36,\";\":18,\":\":18,\"\\/\":32,\"-\":32,\".\":36,\"A\":34,\"z\":40,\"y\":36,\"x\":36,\"w\":36,\"v\":36,\"u\":36,\"t\":18,\"s\":41,\"r\":36,\"q\":45,\"p\":36,\"o\":49,\"n\":36,\"m\":36,\"l\":5,\"j\":14,\"i\":14,\"h\":7,\"g\":45,\"f\":18,\"e\":49,\"d\":45,\"c\":49,\"a\":49,\"&\":25,\"Z\":7,\"S\":5,\"Q\":20,\"O\":20,\"J\":40,\"G\":20,\"D\":5,\"C\":20}},\"U\":{\"d\":\"38,-243v0,-5,3,-9,8,-9v5,0,9,4,9,9r0,141v0,46,38,84,84,84v47,0,85,-38,85,-84r0,-141v0,-5,4,-9,9,-9v5,0,9,4,9,9r0,141v0,56,-46,102,-103,102v-56,0,-101,-46,-101,-102r0,-141\",\"w\":293,\"k\":{\",\":5,\"\\/\":5,\".\":5,\"A\":18,\"x\":2,\"Z\":16,\"X\":4,\"W\":18,\"T\":11,\"R\":9,\"O\":14,\"N\":5,\"M\":18,\"L\":17,\"K\":18,\"J\":7,\"I\":18,\"H\":18,\"F\":18,\"E\":18,\"D\":11}},\"V\":{\"d\":\"137,-8v0,9,-16,11,-17,2r-98,-232v-4,-9,11,-19,16,-8r90,215r91,-215v1,-4,7,-6,11,-4v4,2,6,8,4,12\",\"w\":270,\"k\":{\",\":43,\";\":7,\":\":7,\"\\/\":43,\"-\":14,\".\":43,\"A\":49,\"z\":20,\"y\":14,\"x\":18,\"w\":13,\"v\":14,\"u\":14,\"t\":7,\"s\":22,\"r\":14,\"q\":23,\"p\":14,\"o\":25,\"n\":14,\"m\":14,\"l\":4,\"j\":7,\"i\":7,\"g\":23,\"f\":9,\"e\":25,\"d\":23,\"c\":25,\"a\":25,\"&\":20,\"Z\":4,\"Y\":7,\"X\":7,\"W\":4,\"V\":4,\"S\":9,\"Q\":14,\"O\":14,\"J\":43,\"I\":18,\"G\":14,\"E\":11,\"C\":14}},\"W\":{\"d\":\"283,-6v-2,8,-14,7,-17,0r-64,-152r-67,157v-5,3,-14,0,-14,-6r-97,-231v-5,-10,11,-18,16,-8r90,215r64,-152v4,-7,13,-6,17,0r64,152r90,-215v2,-4,7,-6,12,-4v4,2,6,8,4,12\",\"w\":396,\"k\":{\",\":36,\";\":5,\":\":5,\"\\/\":36,\"-\":13,\".\":36,\"A\":43,\"z\":20,\"y\":13,\"x\":14,\"w\":13,\"v\":13,\"u\":13,\"t\":9,\"s\":22,\"r\":13,\"q\":22,\"p\":13,\"o\":23,\"n\":13,\"m\":13,\"l\":4,\"j\":5,\"i\":5,\"g\":22,\"f\":11,\"e\":23,\"d\":22,\"c\":23,\"a\":25,\"&\":16,\"Z\":4,\"Y\":7,\"X\":5,\"W\":4,\"V\":4,\"S\":7,\"Q\":13,\"O\":13,\"J\":38,\"I\":18,\"G\":13,\"E\":7,\"C\":13}},\"X\":{\"d\":\"36,0v-6,0,-11,-8,-6,-14r81,-111r-81,-112v-3,-4,-3,-9,1,-12v4,-3,9,-2,12,2r78,107r78,-107v3,-4,9,-5,13,-2v4,3,4,8,1,12r-81,112r81,111v5,6,0,14,-6,14v-3,0,-6,-1,-8,-4r-78,-107r-78,107v-1,3,-4,4,-7,4\",\"w\":259,\"k\":{\"-\":18,\"?\":5,\"A\":18,\"y\":14,\"w\":14,\"v\":18,\"u\":7,\"t\":7,\"q\":14,\"o\":16,\"l\":4,\"j\":4,\"i\":4,\"g\":14,\"f\":7,\"e\":16,\"d\":14,\"c\":16,\"a\":4,\"&\":4,\"Y\":7,\"W\":5,\"V\":7,\"U\":18,\"S\":11,\"Q\":18,\"O\":18,\"J\":4,\"I\":18,\"G\":18,\"E\":16,\"C\":18}},\"Y\":{\"d\":\"107,-9r0,-112r-85,-116v-3,-4,-2,-9,2,-12v4,-3,9,-2,12,2r79,108r79,-108v3,-4,8,-5,12,-2v4,3,5,8,2,12r-84,115r0,113v0,5,-4,9,-9,9v-5,0,-8,-4,-8,-9\",\"w\":217,\"k\":{\",\":47,\";\":14,\":\":14,\"\\/\":40,\"-\":29,\".\":47,\"A\":17,\"z\":29,\"y\":22,\"x\":25,\"w\":20,\"v\":22,\"u\":27,\"t\":11,\"s\":36,\"r\":27,\"q\":38,\"p\":27,\"o\":40,\"n\":27,\"m\":27,\"l\":4,\"j\":7,\"i\":7,\"g\":38,\"f\":14,\"e\":40,\"d\":38,\"c\":40,\"a\":36,\"&\":25,\"Z\":4,\"X\":7,\"W\":7,\"V\":7,\"S\":13,\"R\":-11,\"Q\":22,\"O\":22,\"L\":-18,\"J\":47,\"I\":-18,\"G\":22,\"C\":22}},\"Z\":{\"d\":\"35,0v-8,1,-10,-10,-6,-15r159,-218r-153,0v-5,0,-8,-4,-8,-9v0,-5,3,-9,8,-9r177,4v3,3,3,7,0,10r-160,219r154,0v5,0,8,4,8,9v0,5,-3,9,-8,9r-171,0\",\"w\":240,\"k\":{\"-\":11,\"y\":5,\"w\":5,\"v\":7,\"q\":7,\"o\":9,\"g\":7,\"f\":4,\"e\":9,\"d\":7,\"c\":9,\"&\":5,\"Z\":4,\"T\":-13,\"S\":4,\"Q\":14,\"O\":14,\"G\":14,\"C\":14}},\"&\":{\"d\":\"202,-145v5,24,-5,40,-21,46v11,54,-31,97,-81,99v-78,3,-111,-111,-47,-150v-36,-36,-6,-102,45,-102v33,0,61,27,61,61v0,5,-4,8,-9,8v-5,0,-9,-3,-9,-8v0,-24,-19,-43,-43,-43v-24,0,-43,19,-43,43v-6,22,34,37,15,51v-57,25,-38,125,30,122v40,-2,73,-35,63,-79v-35,-4,-64,5,-57,36v1,6,-3,11,-8,12v-10,-2,-11,-5,-11,-19v0,-35,37,-52,84,-47v22,3,6,-30,21,-37v5,-1,9,3,10,7\",\"w\":250,\"k\":{\"Y\":25,\"W\":18,\"V\":22,\"T\":32,\"S\":4}},\"\\u00a0\":{\"w\":108},\"0\":{\"d\":\"111,0v-116,-5,-116,-247,0,-252v115,5,115,248,0,252xm159,-204v-51,-72,-118,1,-118,78v0,78,69,148,118,78v26,-37,26,-119,0,-156\",\"w\":255,\"k\":{\",\":7,\"\\/\":13,\".\":7,\"7\":11,\"3\":4,\"2\":4,\"1\":2}},\"1\":{\"d\":\"61,-9r0,-217v-16,5,-32,27,-48,18v-3,-5,0,-10,4,-12r48,-30v6,-3,13,2,13,10r0,231v0,5,-4,9,-9,9v-5,0,-8,-4,-8,-9\",\"w\":120},\"2\":{\"d\":\"26,-219v43,-62,150,-27,150,49v0,22,-9,44,-27,61r-101,91r119,0v5,0,9,4,9,9v0,5,-4,9,-9,9v-48,-2,-105,5,-148,-3v-3,-4,-4,-8,0,-12r118,-107v46,-37,13,-112,-43,-112v-22,0,-43,13,-56,27v-4,4,-9,4,-12,0v-4,-4,-4,-9,0,-12\",\"w\":212,\"k\":{\"7\":5,\"4\":11}},\"3\":{\"d\":\"157,-86v0,-34,-33,-68,-67,-67v-7,0,-16,-10,-8,-17r63,-64r-97,0v-5,0,-9,-4,-9,-9v0,-5,4,-9,9,-9r118,0v8,0,12,11,6,16r-65,67v36,6,68,44,68,83v0,70,-94,118,-146,61v-4,-3,-4,-9,0,-13v3,-4,9,-4,13,0v40,44,115,8,115,-48\",\"w\":219,\"k\":{\"\\/\":4,\"9\":2,\"7\":9,\"5\":2}},\"4\":{\"d\":\"173,0v-17,-3,-6,-35,-9,-52r-143,-2v-4,-3,-4,-8,-1,-12r146,-182v6,-7,16,-1,16,6r0,173v11,0,26,-3,26,9v0,11,-15,7,-26,8v-3,18,8,49,-9,52xm45,-69r119,0r0,-148\",\"w\":239,\"k\":{\"\\/\":7,\"9\":4,\"7\":14,\"1\":7}},\"5\":{\"d\":\"171,-85v0,70,-95,116,-146,60v-4,-4,-4,-9,0,-12v4,-4,9,-4,13,0v41,43,115,7,115,-48v0,-58,-75,-92,-115,-48v-7,7,-17,1,-15,-9r12,-101v0,-6,4,-9,10,-9r117,0v5,0,9,4,9,9v0,5,-4,9,-9,9r-110,0r-9,75v57,-36,128,14,128,74\",\"w\":217,\"k\":{\"\\/\":7,\"9\":2,\"7\":11,\"3\":2,\"2\":4}},\"6\":{\"d\":\"107,0v-51,-1,-86,-41,-84,-97v3,-73,35,-155,113,-155v5,0,9,4,9,9v0,5,-4,9,-9,9v-54,2,-81,47,-91,96v44,-56,145,-20,145,55v0,46,-37,83,-83,83xm107,-149v-38,1,-71,33,-65,74v4,32,32,57,65,57v37,0,66,-29,66,-65v0,-36,-29,-66,-66,-66\",\"w\":231,\"k\":{\"\\/\":4,\"9\":4,\"7\":9,\"3\":4,\"1\":7}},\"7\":{\"d\":\"165,-251v8,-1,14,8,9,14r-97,232v-5,11,-20,2,-17,-7r93,-221r-121,0v-5,0,-9,-4,-9,-9v0,-5,4,-9,9,-9r133,0\",\"w\":211,\"k\":{\",\":36,\"\\/\":50,\"-\":11,\".\":36,\"9\":5,\"8\":4,\"6\":7,\"5\":9,\"4\":31,\"3\":7,\"2\":5,\"1\":-4,\"0\":7}},\"8\":{\"d\":\"70,-157v-39,-26,-19,-95,32,-95v50,0,70,70,30,95v30,12,51,41,51,75v0,45,-36,82,-81,82v-45,0,-82,-37,-82,-82v0,-34,20,-63,50,-75xm37,-82v0,36,29,65,65,65v36,0,64,-29,64,-65v0,-35,-28,-64,-64,-64v-36,0,-65,29,-65,64xm67,-200v0,19,16,36,35,36v19,0,35,-17,35,-36v0,-19,-16,-35,-35,-35v-19,0,-35,16,-35,35\",\"w\":226,\"k\":{\"9\":2,\"7\":4}},\"9\":{\"d\":\"190,-179v8,88,-27,176,-112,179v-5,0,-9,-3,-9,-8v0,-5,4,-10,9,-10v55,-1,83,-46,92,-96v-44,55,-146,21,-146,-55v0,-46,37,-83,83,-83v43,0,79,32,83,73xm107,-104v37,0,66,-28,66,-65v0,-36,-29,-65,-66,-65v-36,0,-66,29,-66,65v0,37,30,65,66,65\",\"w\":231,\"k\":{\",\":4,\"\\/\":9,\".\":4,\"7\":9,\"5\":2,\"3\":4,\"2\":4}},\"a\":{\"d\":\"173,-176v5,0,8,3,8,8r0,159v0,5,-3,9,-8,9v-14,-1,-8,-22,-9,-35v-41,66,-150,29,-150,-53v0,-80,108,-120,150,-54v1,-13,-5,-34,9,-34xm98,-17v36,0,66,-31,66,-71v0,-40,-30,-71,-66,-71v-36,0,-66,31,-66,71v0,40,30,71,66,71\",\"w\":222,\"k\":{\"\\\\\":27,\"*\":5,\"?\":13,\"y\":-11,\"w\":7,\"v\":7,\"n\":4,\"l\":-5,\"j\":-43,\"g\":-13}},\"b\":{\"d\":\"33,-9r0,-234v0,-5,4,-9,9,-9v5,0,9,4,9,9r0,101v42,-64,153,-29,153,54v0,81,-110,119,-153,54v4,18,-6,49,-18,25xm119,-159v-37,0,-68,30,-68,71v0,39,31,70,68,70v37,0,67,-31,67,-70v0,-39,-30,-71,-67,-71\",\"k\":{\"}\":5,\"]\":7,\"\\\\\":25,\"*\":5,\",\":4,\"?\":13,\".\":4,\")\":11,\"z\":5,\"y\":9,\"x\":11,\"w\":7,\"v\":9}},\"c\":{\"d\":\"169,-31v3,24,-36,31,-57,31v-50,1,-90,-39,-91,-89v-2,-71,92,-113,147,-68v4,3,4,8,1,12v-19,6,-35,-19,-57,-14v-41,0,-73,31,-74,70v-2,58,74,94,119,56v4,-3,9,-1,12,2\",\"w\":205,\"k\":{\"\\\\\":14,\"?\":5,\")\":5,\"y\":2,\"x\":4,\"w\":2,\"v\":2,\"q\":4,\"o\":5,\"g\":4,\"e\":5,\"d\":4,\"c\":5}},\"d\":{\"d\":\"184,0v-14,0,-8,-21,-9,-34v-42,64,-153,28,-153,-54v0,-82,110,-119,153,-54r0,-101v0,-5,4,-9,9,-9v5,0,8,4,8,9r0,234v0,5,-3,9,-8,9xm107,-18v38,-1,70,-31,68,-73v-1,-38,-32,-68,-68,-68v-37,0,-68,32,-68,71v0,39,31,70,68,70\",\"k\":{\"e\":5}},\"e\":{\"d\":\"107,0v-48,0,-86,-40,-86,-88v0,-49,38,-88,86,-88v45,0,82,36,85,83v0,5,-4,8,-9,8r-145,0v0,67,94,93,125,36v6,-10,21,0,15,9v-15,24,-41,40,-71,40xm173,-102v-10,-74,-124,-73,-134,0r134,0\",\"w\":219,\"k\":{\"}\":4,\"]\":7,\"\\\\\":29,\"*\":7,\",\":4,\"?\":14,\".\":4,\")\":11,\"z\":5,\"y\":-11,\"x\":11,\"w\":9,\"v\":9,\"t\":14,\"r\":8}},\"f\":{\"d\":\"55,-179v-4,-43,9,-74,48,-73v5,0,8,4,8,9v0,5,-3,9,-8,9v-33,-2,-29,22,-30,55v18,-4,49,5,25,17r-25,0r0,154v0,5,-4,8,-9,8v-5,0,-9,-3,-9,-8r0,-154v-17,5,-46,-7,-23,-17r23,0\",\"w\":130,\"k\":{\"}\":-11,\"]\":-7,\"\\\\\":-11,\"*\":-11,\",\":16,\"\\/\":16,\"?\":-13,\".\":16,\")\":-11,\"z\":4,\"q\":4,\"o\":4,\"g\":4,\"e\":4,\"d\":4,\"c\":4,\"a\":5}},\"g\":{\"d\":\"188,-168r0,154v1,58,-64,102,-120,74v-4,-3,-6,-7,-4,-11v9,-13,24,6,40,2v45,-2,72,-36,66,-87v-41,65,-148,30,-148,-53v0,-81,106,-118,148,-53v-4,-18,4,-49,18,-26xm104,-18v36,0,66,-31,66,-71v0,-39,-30,-70,-66,-70v-36,0,-65,31,-65,70v0,40,29,71,65,71\",\"k\":{\"\\\\\":18}},\"h\":{\"d\":\"51,-6v-2,9,-19,7,-18,-3r0,-234v0,-5,4,-9,9,-9v5,0,9,4,9,9r0,93v36,-49,130,-24,130,43r0,98v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9r0,-98v0,-31,-25,-52,-56,-52v-31,0,-56,21,-56,52r0,101\",\"w\":220,\"k\":{\"\\\\\":27,\"*\":5,\"?\":11,\"y\":5,\"w\":5,\"v\":7,\"a\":-14}},\"i\":{\"d\":\"34,-168v0,-5,3,-8,8,-8v5,0,9,3,9,8r0,159v0,5,-4,9,-9,9v-5,0,-8,-4,-8,-9r0,-159xm34,-217v-5,-17,15,-23,17,-8v5,16,-16,24,-17,8\",\"w\":101,\"k\":{\"l\":8}},\"j\":{\"d\":\"30,-208v-13,0,-12,-27,0,-26v8,0,9,8,8,17v0,5,-3,9,-8,9xm-2,60v1,-13,22,-6,22,-22r0,-205v0,-5,4,-9,9,-9v5,0,8,4,8,9r0,205v3,20,-30,44,-39,22\",\"w\":89,\"k\":{\"a\":7}},\"k\":{\"d\":\"33,-9r0,-234v0,-5,4,-9,9,-9v5,0,9,4,9,9r0,169r105,-104v4,-4,8,-4,12,0v4,3,4,8,0,12r-68,68r68,84v5,5,0,14,-6,14v-3,0,-6,0,-7,-3r-68,-82r-36,36v-3,17,7,46,-9,49v-5,0,-9,-4,-9,-9\",\"w\":201,\"k\":{\"\\\\\":14,\"-\":7,\"y\":5,\"w\":7,\"v\":7,\"u\":4,\"t\":4,\"q\":9,\"o\":9,\"g\":9,\"e\":9,\"d\":9,\"c\":9,\"a\":4}},\"l\":{\"d\":\"36,-243v0,-5,4,-9,9,-9v5,0,9,4,9,9r0,234v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9r0,-234\",\"w\":89,\"k\":{\"y\":-23,\"e\":-16}},\"m\":{\"d\":\"50,-8v1,10,-15,10,-17,2r0,-162v0,-10,18,-11,17,0r0,17v29,-37,99,-30,118,12v30,-62,135,-39,135,35r0,96v0,4,-4,8,-9,8v-5,0,-8,-4,-8,-8r0,-96v-1,-30,-25,-55,-55,-55v-30,0,-54,25,-54,55r0,97v-2,8,-18,10,-18,-1r0,-96v0,-30,-24,-55,-54,-55v-30,0,-55,25,-55,55r0,96\",\"w\":342,\"k\":{\"\\\\\":27,\"*\":5,\"?\":11,\"y\":5,\"w\":5,\"v\":7}},\"n\":{\"d\":\"50,-9v3,11,-14,11,-16,4v-3,-49,0,-108,-1,-162v0,-5,4,-9,9,-9v11,0,7,15,8,26v37,-50,127,-20,127,46r0,95v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9r0,-95v0,-30,-24,-55,-54,-55v-30,0,-55,25,-55,55r0,95\",\"w\":220,\"k\":{\"\\\\\":27,\"*\":5,\"?\":11,\"y\":5,\"w\":5,\"v\":7,\"d\":7}},\"o\":{\"d\":\"25,-88v0,-48,38,-88,84,-88v46,0,83,40,83,88v0,48,-37,88,-83,88v-46,0,-84,-40,-84,-88xm42,-88v0,39,31,71,67,71v36,0,66,-32,66,-71v0,-39,-30,-71,-66,-71v-36,0,-67,32,-67,71\",\"w\":225,\"k\":{\"}\":5,\"]\":7,\"\\\\\":29,\"*\":7,\",\":7,\"?\":18,\".\":7,\")\":11,\"z\":7,\"y\":-16,\"x\":13,\"w\":14,\"v\":11,\"u\":6,\"t\":7,\"r\":7,\"f\":13}},\"p\":{\"d\":\"33,65r0,-233v0,-5,4,-8,9,-8v14,0,8,21,9,34v42,-64,152,-28,152,53v0,81,-110,120,-152,53r0,101v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9xm118,-159v-37,1,-67,30,-67,70v0,39,31,71,67,71v37,0,68,-32,68,-71v0,-39,-31,-70,-68,-70\",\"k\":{\"}\":5,\"]\":7,\"\\\\\":25,\"*\":5,\",\":4,\"?\":13,\".\":4,\")\":11,\"z\":5,\"y\":9,\"x\":11,\"w\":7,\"v\":9,\"l\":7,\"i\":11,\"e\":4}},\"q\":{\"d\":\"174,65r0,-101v-42,65,-152,30,-152,-53v0,-81,110,-118,152,-53v1,-13,-5,-34,9,-34v5,0,9,3,9,8r0,233v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9xm39,-89v0,39,30,71,67,71v37,0,68,-32,68,-71v0,-39,-31,-70,-68,-70v-37,0,-67,31,-67,70\",\"k\":{\"\\\\\":18}},\"r\":{\"d\":\"124,-159v-39,-3,-67,49,-73,73r0,77v0,11,-18,12,-18,0r0,-158v0,-5,4,-9,9,-9v16,2,7,31,9,47v13,-24,37,-46,73,-47v5,0,8,4,8,9v0,5,-3,8,-8,8\",\"w\":158,\"k\":{\"\\\\\":11,\"*\":-7,\",\":32,\"\\/\":27,\".\":32,\"z\":4,\"q\":9,\"o\":9,\"e\":18,\"d\":9,\"c\":9,\"a\":9}},\"s\":{\"d\":\"53,-150v-48,69,99,27,99,100v0,15,-9,26,-21,36v-30,25,-89,11,-109,-11v-4,-3,-4,-8,-1,-12v21,-8,37,25,66,20v33,1,66,-32,35,-54v-28,-20,-97,-12,-98,-59v0,-51,85,-57,115,-27v4,3,6,8,3,12v-18,10,-33,-20,-55,-15v-14,0,-26,4,-34,10\",\"w\":177,\"k\":{\"}\":4,\"]\":5,\"\\\\\":27,\"?\":13,\")\":7,\"z\":4,\"y\":-13,\"x\":9,\"w\":5,\"v\":7,\"t\":-5,\"s\":4}},\"t\":{\"d\":\"64,-176v12,1,30,-3,31,8v-1,12,-18,9,-31,9r0,128v1,17,20,9,22,22v0,4,-5,9,-9,9v-18,0,-31,-13,-31,-31r0,-128v-11,0,-34,3,-31,-9v-3,-11,21,-7,31,-8r0,-66v0,-4,4,-9,8,-9v5,0,10,5,10,9r0,66\",\"w\":144,\"k\":{\"\\\\\":14,\"t\":23,\"r\":25,\"q\":5,\"o\":5,\"h\":7,\"g\":5,\"e\":14,\"d\":5,\"c\":5,\"a\":11}},\"u\":{\"d\":\"30,-168v0,-5,4,-9,9,-9v5,0,8,4,8,9r0,96v0,30,24,55,54,55v30,0,55,-25,55,-55r0,-96v0,-11,18,-12,18,0r0,96v0,40,-33,72,-73,72v-40,0,-71,-32,-71,-72r0,-96\",\"w\":220,\"k\":{\"\\\\\":18,\"n\":9,\"l\":11}},\"v\":{\"d\":\"103,-7v0,7,-13,10,-16,2r-66,-158v-2,-4,0,-9,4,-11v4,-2,10,0,11,4r59,139r59,-139v1,-4,7,-6,11,-4v4,2,6,7,4,11\",\"w\":209,\"k\":{\"}\":4,\"]\":7,\"\\\\\":18,\",\":31,\"\\/\":25,\"-\":5,\"?\":4,\".\":31,\"z\":2,\"y\":5,\"x\":4,\"w\":5,\"v\":5,\"s\":7,\"q\":9,\"o\":11,\"g\":9,\"e\":11,\"d\":9,\"c\":11,\"a\":9}},\"w\":{\"d\":\"203,-6v-2,7,-15,9,-16,0r-41,-97r-41,98v-2,7,-14,6,-16,0r-66,-158v-2,-4,0,-9,4,-11v4,-2,10,0,11,4r59,139r41,-96v2,-7,13,-7,16,0r41,96r58,-139v5,-9,21,-3,16,7\",\"w\":309,\"k\":{\"}\":4,\"]\":7,\"\\\\\":18,\",\":25,\"\\/\":22,\"-\":4,\"?\":4,\".\":25,\"z\":2,\"y\":4,\"x\":4,\"w\":4,\"v\":5,\"s\":5,\"q\":7,\"o\":9,\"l\":21,\"i\":22,\"g\":7,\"e\":22,\"d\":7,\"c\":9,\"a\":7}},\"x\":{\"d\":\"33,0v-5,0,-11,-8,-6,-14r54,-73r-54,-75v-3,-4,-3,-9,1,-12v4,-3,9,-2,12,2r51,70r51,-70v3,-4,9,-5,12,-2v4,3,5,8,2,12r-54,75r54,73v5,6,-1,14,-7,14v-3,0,-6,-1,-7,-4r-51,-69r-51,69v-1,3,-4,4,-7,4\",\"w\":205,\"k\":{\"}\":4,\"]\":4,\"\\\\\":18,\"-\":11,\"?\":5,\"y\":4,\"w\":4,\"v\":4,\"s\":7,\"q\":11,\"o\":13,\"i\":16,\"g\":11,\"e\":13,\"d\":11,\"c\":13,\"a\":16}},\"y\":{\"d\":\"145,-168v-2,-9,14,-11,16,-4v3,49,0,104,1,158v1,58,-64,102,-120,74v-9,-5,-3,-18,7,-15v50,20,102,-14,96,-71v-37,49,-126,21,-126,-46r0,-96v0,-5,4,-8,8,-8v5,0,9,3,9,8r0,96v0,30,24,54,54,54v30,0,55,-24,55,-54r0,-96\",\"w\":211,\"k\":{\"}\":4,\"]\":7,\"\\\\\":18,\",\":31,\"\\/\":25,\"-\":5,\"?\":4,\".\":31,\"z\":2,\"y\":4,\"x\":4,\"w\":4,\"v\":5,\"s\":7,\"q\":9,\"o\":11,\"l\":11,\"g\":9,\"e\":11,\"d\":9,\"c\":11,\"a\":9}},\"z\":{\"d\":\"145,-175v9,-1,13,11,6,16r-104,142r99,0v5,0,8,3,8,8v0,5,-3,9,-8,9r-115,0v-8,1,-12,-11,-6,-15r104,-143r-98,0v-5,0,-9,-3,-9,-8v0,-5,4,-9,9,-9r114,0\",\"w\":199,\"k\":{\"\\\\\":16,\"q\":5,\"o\":5,\"g\":5,\"e\":5,\"d\":5,\"c\":5}},\"!\":{\"d\":\"33,-243v0,-5,4,-9,9,-9v5,0,9,4,9,9r0,180v0,5,-4,9,-9,9v-5,0,-9,-4,-9,-9r0,-180xm33,-9v-5,-17,16,-23,18,-8v5,17,-16,23,-18,8\",\"w\":90},\"(\":{\"d\":\"105,35v-92,-5,-93,-167,-62,-243v11,-27,32,-45,62,-45v5,0,10,5,10,10v0,5,-5,10,-10,10v-73,6,-69,155,-44,214v10,23,23,34,44,34v5,0,10,5,10,10v0,6,-5,10,-10,10\",\"w\":154,\"k\":{\"s\":5,\"q\":11,\"o\":11,\"j\":-11,\"g\":7,\"e\":11,\"d\":11,\"c\":11,\"Q\":11,\"O\":11,\"J\":5,\"G\":11,\"C\":11}},\")\":{\"d\":\"111,-109v0,71,-16,141,-80,144v-5,0,-9,-4,-9,-10v0,-5,4,-10,9,-10v49,-3,60,-65,60,-124v0,-60,-11,-120,-60,-124v-11,0,-12,-20,0,-20v64,3,80,74,80,144\",\"w\":154},\"+\":{\"d\":\"113,-36v-24,-6,-7,-53,-12,-78r-66,0v-7,0,-12,-5,-12,-12v6,-24,53,-7,78,-12v4,-26,-12,-71,12,-78v24,7,7,52,12,78v26,4,71,-12,78,12v-7,24,-52,7,-78,12r0,66v0,7,-5,12,-12,12\",\"w\":223},\"<\":{\"d\":\"25,-118v-5,-3,-2,-12,0,-15r114,-115v4,-4,11,-4,15,0v4,4,4,11,0,15r-108,108r108,108v7,7,0,18,-8,17v-3,0,-5,-1,-7,-3\",\"w\":223},\">\":{\"d\":\"43,0v-8,1,-14,-11,-7,-17r107,-108r-107,-108v-4,-4,-4,-11,0,-15v4,-4,10,-4,14,0r115,116v3,4,2,11,-1,14r-114,115v-2,2,-4,3,-7,3\",\"w\":223},\"A\":{\"d\":\"198,-6r-23,-59r-115,0r-22,59v-1,5,-5,6,-11,6v-4,-2,-7,-8,-5,-12r87,-234v2,-6,15,-7,17,0r88,234v2,4,-1,13,-8,12v-3,0,-7,-2,-8,-6xm118,-218r-51,135r102,0\",\"w\":232,\"k\":{\"\\\\\":43,\"*\":36,\"-\":14,\"?\":22,\"y\":4,\"w\":16,\"v\":22,\"u\":4,\"t\":11,\"q\":9,\"o\":9,\"g\":9,\"f\":7,\"e\":9,\"d\":9,\"c\":9,\"Z\":-13,\"Y\":27,\"W\":29,\"V\":32,\"U\":9,\"T\":36,\"S\":6,\"O\":14,\"H\":7,\"G\":12,\"C\":14}},\".\":{\"d\":\"30,-18v0,-10,8,-18,18,-18v10,0,18,8,18,18v0,10,-8,18,-18,18v-10,0,-18,-8,-18,-18\",\"w\":82,\"k\":{\"y\":22,\"w\":25,\"v\":31,\"t\":9,\"q\":4,\"o\":7,\"g\":4,\"f\":5,\"e\":7,\"d\":4,\"c\":7,\"7\":7,\"1\":18,\"0\":7,\"Y\":47,\"W\":36,\"V\":43,\"U\":5,\"T\":36,\"Q\":14,\"O\":14,\"G\":14,\"C\":14}},\"?\":{\"d\":\"83,-50v-16,-5,-5,-37,-8,-55v0,-5,4,-8,8,-8v34,0,61,-28,61,-61v0,-62,-90,-83,-114,-30v-2,4,-7,5,-11,2v-4,-3,-6,-7,-3,-11v31,-66,145,-40,145,39v0,40,-31,73,-70,77v-3,16,7,44,-8,47xm83,0v-7,0,-9,-8,-8,-16v0,-5,4,-9,8,-9v8,0,9,8,8,17v0,5,-3,8,-8,8\",\"w\":192},\"=\":{\"d\":\"39,-77v-6,0,-11,-4,-11,-10v0,-5,5,-10,11,-10r128,0v6,0,10,5,10,10v0,6,-4,10,-10,10r-128,0xm39,-155v-6,0,-11,-5,-11,-10v0,-6,5,-10,11,-10r128,0v6,0,10,4,10,10v0,5,-4,10,-10,10r-128,0\",\"w\":223},\"-\":{\"d\":\"31,-118v-4,0,-7,-3,-7,-7v0,-4,3,-7,7,-7r76,0v4,0,7,3,7,7v0,4,-3,7,-7,7r-76,0\",\"w\":146,\"k\":{\"A\":14,\"z\":4,\"y\":5,\"x\":11,\"w\":4,\"v\":5,\"7\":14,\"3\":4,\"1\":11,\"Z\":11,\"Y\":29,\"X\":18,\"W\":13,\"V\":14,\"T\":32}},\"\\u00ad\":{\"d\":\"31,-118v-4,0,-7,-3,-7,-7v0,-4,3,-7,7,-7r76,0v4,0,7,3,7,7v0,4,-3,7,-7,7r-76,0\",\"w\":146},\"\\/\":{\"d\":\"44,-5v-5,11,-20,2,-16,-7r98,-234v4,-10,22,-3,17,7\",\"w\":151,\"k\":{\"\\/\":61,\"A\":43,\"z\":22,\"y\":18,\"x\":18,\"w\":18,\"v\":18,\"u\":18,\"t\":7,\"s\":31,\"r\":18,\"q\":25,\"p\":18,\"o\":29,\"n\":18,\"m\":18,\"g\":25,\"f\":9,\"e\":29,\"d\":25,\"c\":29,\"a\":23,\"9\":7,\"8\":5,\"7\":4,\"6\":13,\"5\":7,\"4\":34,\"3\":4,\"2\":7,\"1\":-4,\"0\":13,\"Z\":7,\"S\":11,\"Q\":14,\"O\":14,\"J\":47,\"G\":14,\"C\":14}},\":\":{\"d\":\"31,-18v0,-10,8,-18,18,-18v10,0,18,8,18,18v0,10,-8,18,-18,18v-10,0,-18,-8,-18,-18xm31,-169v0,-10,8,-18,18,-18v10,0,18,8,18,18v0,10,-8,18,-18,18v-10,0,-18,-8,-18,-18\",\"w\":86,\"k\":{\"Y\":14,\"W\":5,\"V\":7,\"T\":18}},\";\":{\"d\":\"24,-169v0,-10,8,-18,18,-18v10,0,18,8,18,18v0,10,-8,18,-18,18v-10,0,-18,-8,-18,-18xm55,-20v3,34,-10,53,-28,58v-17,-10,24,-21,14,-38v-7,-1,-11,-9,-10,-20v0,-7,5,-12,12,-12v7,0,12,5,12,12\",\"w\":86,\"k\":{\"Y\":14,\"W\":5,\"V\":7,\"T\":18}},\"\\u037e\":{\"d\":\"24,-169v0,-10,8,-18,18,-18v10,0,18,8,18,18v0,10,-8,18,-18,18v-10,0,-18,-8,-18,-18xm55,-20v3,34,-10,53,-28,58v-17,-10,24,-21,14,-38v-7,-1,-11,-9,-10,-20v0,-7,5,-12,12,-12v7,0,12,5,12,12\",\"w\":86},\",\":{\"d\":\"53,-20v3,34,-9,53,-28,58v-17,-10,24,-21,14,-38v-12,-1,-14,-33,2,-32v7,0,12,5,12,12\",\"w\":82,\"k\":{\"y\":16,\"w\":25,\"v\":31,\"t\":9,\"q\":4,\"o\":7,\"j\":-5,\"g\":4,\"f\":5,\"e\":7,\"d\":4,\"c\":7,\"7\":7,\"1\":18,\"0\":7,\"Y\":47,\"W\":36,\"V\":43,\"U\":5,\"T\":36,\"Q\":14,\"O\":14,\"G\":14,\"C\":14}},\"'\":{\"d\":\"25,-166r11,-77v-1,-11,20,-15,23,-4r-23,81v-1,5,-3,7,-6,7v-3,0,-6,-2,-5,-7\",\"w\":82},\"\\\"\":{\"d\":\"90,-166r11,-77v-1,-11,20,-16,22,-4v-4,30,-15,54,-22,81v-1,5,-3,7,-6,7v-3,0,-6,-2,-5,-7xm25,-166r11,-77v-1,-11,20,-15,23,-4r-23,81v-1,5,-3,7,-6,7v-3,0,-6,-2,-5,-7\",\"w\":147},\"_\":{\"d\":\"-1,58v-12,0,-9,-16,0,-16r218,0v12,0,9,16,0,16r-218,0\",\"w\":216},\"*\":{\"d\":\"77,-145v-14,-5,-2,-32,-4,-47r-38,25v-8,0,-11,-11,-3,-15r37,-17v-13,-9,-34,-11,-42,-25v12,-18,32,13,46,17v1,-15,-10,-41,4,-47v16,4,3,32,5,47v13,-8,23,-19,38,-24v8,-1,9,13,2,14r-37,18v13,9,35,9,42,24v0,7,-8,10,-13,5r-32,-22v-1,16,11,42,-5,47\",\"w\":154,\"k\":{\"A\":36,\"t\":-4,\"s\":4,\"q\":5,\"o\":7,\"g\":5,\"e\":7,\"d\":5,\"c\":7,\"a\":4,\"J\":29}},\"@\":{\"d\":\"145,-18v13,3,35,-10,38,4v3,14,-24,14,-38,14v-70,0,-126,-56,-126,-126v0,-70,56,-126,126,-126v70,0,126,56,126,126v0,43,-6,74,-53,85v-22,-1,-27,-17,-26,-39v-35,45,-111,14,-111,-46v0,-37,28,-68,64,-68v59,0,68,62,65,125v1,6,2,12,11,11v27,-12,33,-37,33,-68v0,-59,-50,-109,-109,-109v-60,0,-108,50,-108,109v0,60,48,108,108,108xm100,-126v0,28,20,49,45,49v25,0,47,-21,47,-49v0,-27,-22,-50,-47,-50v-25,0,-45,23,-45,50\",\"w\":352},\"\\\\\":{\"d\":\"139,-13v2,6,-1,13,-9,12v-3,0,-7,-1,-8,-5r-98,-233v-2,-5,0,-10,5,-12v5,-2,9,1,11,5\",\"w\":161,\"k\":{\"y\":22,\"w\":22,\"v\":25,\"t\":11,\"j\":-11,\"f\":4,\"Y\":40,\"W\":36,\"V\":43,\"U\":5,\"T\":32,\"Q\":14,\"O\":14,\"G\":14,\"C\":14}},\"`\":{\"d\":\"108,-216v-21,8,-36,-24,-49,-36v1,-7,19,-12,25,-2\",\"w\":180},\"~\":{\"d\":\"60,-105v-12,-3,-12,16,-23,19v-5,0,-7,-5,-6,-11v10,-46,48,-18,75,-12v12,3,12,-17,23,-19v6,-1,7,6,5,11v-11,47,-47,18,-74,12\",\"w\":165},\"#\":{\"d\":\"51,-9r10,-58v-16,-2,-43,7,-45,-9v3,-15,32,-5,48,-8r15,-85v-16,-3,-45,8,-48,-8v2,-18,34,-6,51,-9r10,-60v1,-5,4,-7,9,-7v6,0,9,5,8,10r-10,57r75,0r10,-60v1,-5,4,-7,9,-7v6,0,9,5,8,10r-10,57v15,2,42,-7,44,8v-2,17,-31,6,-47,9r-15,85v16,3,44,-7,48,8v-3,17,-34,6,-51,9r-10,61v-1,5,-4,7,-9,7v-6,0,-9,-5,-8,-10r10,-58r-75,0r-10,61v-1,5,-4,7,-9,7v-6,0,-9,-5,-8,-10xm81,-84r75,0r15,-85r-75,0\",\"w\":252},\"$\":{\"d\":\"31,-52v24,16,46,34,77,35r0,-102v-54,-12,-77,-32,-77,-68v0,-36,32,-64,76,-65v-5,-16,11,-32,17,-14r0,15v28,3,55,12,69,33v0,5,-4,9,-9,9v-22,-9,-39,-26,-61,-26r0,101v55,12,78,32,78,67v0,38,-32,66,-77,67v4,18,-3,53,-17,28r0,-28v-31,-3,-56,-15,-81,-35v-7,-6,-4,-17,5,-17xm183,-65v0,-25,-13,-41,-60,-51r0,100v36,-1,60,-22,60,-49xm50,-188v0,24,12,39,58,50r0,-98v-35,1,-58,22,-58,48\",\"w\":227,\"k\":{\"7\":4}},\"[\":{\"d\":\"35,37r0,-280v0,-5,5,-9,10,-9r83,0v4,0,7,3,7,7v0,4,-3,7,-7,7r-76,0r0,271r76,0v4,0,7,3,7,7v0,4,-3,7,-7,7r-83,0v-5,0,-10,-5,-10,-10\",\"w\":154,\"k\":{\"y\":4,\"x\":4,\"w\":7,\"v\":7,\"s\":5,\"q\":7,\"o\":7,\"j\":-11,\"e\":7,\"d\":7,\"c\":7,\"a\":4,\"Q\":7,\"O\":7,\"J\":4,\"G\":7,\"C\":7}},\"]\":{\"d\":\"120,-243r0,280v0,5,-5,10,-10,10r-83,0v-4,0,-7,-3,-7,-7v0,-4,3,-7,7,-7r76,0r0,-271r-76,0v-4,0,-7,-3,-7,-7v0,-4,3,-7,7,-7r83,0v5,0,10,4,10,9\",\"w\":154},\"^\":{\"d\":\"90,-238r-44,57v-3,5,-15,8,-17,1v14,-25,33,-45,49,-68v6,-9,18,-9,24,0v16,23,35,43,49,68v-1,7,-16,4,-18,-1\",\"w\":180},\"{\":{\"d\":\"146,50v-74,-16,-73,-40,-72,-101v0,-28,-9,-45,-46,-45v-6,0,-8,-3,-8,-7v0,-4,2,-7,8,-7v49,0,47,-31,46,-74v0,-37,11,-61,72,-73v10,-2,10,10,3,12v-64,16,-58,34,-58,90v0,32,-14,45,-37,52v33,7,37,36,37,79v0,36,6,49,58,63v2,1,5,2,5,5v0,4,-4,7,-8,6\",\"w\":172,\"k\":{\"z\":4,\"y\":4,\"x\":4,\"w\":4,\"v\":4,\"s\":4,\"q\":5,\"o\":5,\"j\":-13,\"g\":4,\"e\":5,\"d\":5,\"c\":5,\"Q\":7,\"O\":7,\"J\":4,\"G\":7,\"C\":7}},\"}\":{\"d\":\"27,-257v73,16,73,40,72,101v0,28,8,46,45,46v6,0,9,3,9,7v0,4,-3,7,-9,7v-50,-1,-45,32,-45,74v0,37,-11,60,-72,72v-7,2,-11,-9,-4,-11v64,-16,58,-34,58,-90v0,-32,15,-45,38,-52v-33,-7,-38,-36,-38,-79v0,-36,-6,-49,-58,-63v-7,-2,-4,-14,4,-12\",\"w\":172},\"|\":{\"d\":\"44,40r0,-321v0,-4,3,-8,7,-8v4,0,8,4,8,8r0,321v0,11,-15,10,-15,0\",\"w\":102}}});\n"
  },
  {
    "path": "public/javascripts/static/css_browser_selector.js",
    "content": "/*\nCSS Browser Selector v0.3.4 (Sep 29, 2009)\nRafael Lima (http://rafael.adm.br)\nhttp://rafael.adm.br/css_browser_selector\nLicense: http://creativecommons.org/licenses/by/2.5/\nContributors: http://rafael.adm.br/css_browser_selector#contributors\n*/\nfunction css_browser_selector(u){var ua = u.toLowerCase(),is=function(t){return ua.indexOf(t)>-1;},g='gecko',w='webkit',s='safari',o='opera',h=document.getElementsByTagName('html')[0],b=[(!(/opera|webtv/i.test(ua))&&/msie\\s(\\d)/.test(ua))?('ie ie'+RegExp.$1):is('firefox/2')?g+' ff2':is('firefox/3.5')?g+' ff3 ff3_5':is('firefox/3')?g+' ff3':is('gecko/')?g:is('opera')?o+(/version\\/(\\d+)/.test(ua)?' '+o+RegExp.$1:(/opera(\\s|\\/)(\\d+)/.test(ua)?' '+o+RegExp.$2:'')):is('konqueror')?'konqueror':is('chrome')?w+' chrome':is('iron')?w+' iron':is('applewebkit/')?w+' '+s+(/version\\/(\\d+)/.test(ua)?' '+s+RegExp.$1:''):is('mozilla/')?g:'',is('j2me')?'mobile':is('iphone')?'iphone':is('ipod')?'ipod':is('mac')?'mac':is('darwin')?'mac':is('webtv')?'webtv':is('win')?'win':is('freebsd')?'freebsd':(is('x11')||is('linux'))?'linux':'','js']; c = b.join(' '); h.className += ' '+c; return c;}; css_browser_selector(navigator.userAgent);\n"
  },
  {
    "path": "public/javascripts/static/cufon-yui.js",
    "content": "/*\n * Copyright (c) 2009 Simo Kinnunen.\n * Licensed under the MIT license.\n *\n * @version 1.09\n */\nvar Cufon=(function(){var m=function(){return m.replace.apply(null,arguments)};var x=m.DOM={ready:(function(){var C=false,E={loaded:1,complete:1};var B=[],D=function(){if(C){return}C=true;for(var F;F=B.shift();F()){}};if(document.addEventListener){document.addEventListener(\"DOMContentLoaded\",D,false);window.addEventListener(\"pageshow\",D,false)}if(!window.opera&&document.readyState){(function(){E[document.readyState]?D():setTimeout(arguments.callee,10)})()}if(document.readyState&&document.createStyleSheet){(function(){try{document.body.doScroll(\"left\");D()}catch(F){setTimeout(arguments.callee,1)}})()}q(window,\"load\",D);return function(F){if(!arguments.length){D()}else{C?F():B.push(F)}}})(),root:function(){return document.documentElement||document.body}};var n=m.CSS={Size:function(C,B){this.value=parseFloat(C);this.unit=String(C).match(/[a-z%]*$/)[0]||\"px\";this.convert=function(D){return D/B*this.value};this.convertFrom=function(D){return D/this.value*B};this.toString=function(){return this.value+this.unit}},addClass:function(C,B){var D=C.className;C.className=D+(D&&\" \")+B;return C},color:j(function(C){var B={};B.color=C.replace(/^rgba\\((.*?),\\s*([\\d.]+)\\)/,function(E,D,F){B.opacity=parseFloat(F);return\"rgb(\"+D+\")\"});return B}),fontStretch:j(function(B){if(typeof B==\"number\"){return B}if(/%$/.test(B)){return parseFloat(B)/100}return{\"ultra-condensed\":0.5,\"extra-condensed\":0.625,condensed:0.75,\"semi-condensed\":0.875,\"semi-expanded\":1.125,expanded:1.25,\"extra-expanded\":1.5,\"ultra-expanded\":2}[B]||1}),getStyle:function(C){var B=document.defaultView;if(B&&B.getComputedStyle){return new a(B.getComputedStyle(C,null))}if(C.currentStyle){return new a(C.currentStyle)}return new a(C.style)},gradient:j(function(F){var G={id:F,type:F.match(/^-([a-z]+)-gradient\\(/)[1],stops:[]},C=F.substr(F.indexOf(\"(\")).match(/([\\d.]+=)?(#[a-f0-9]+|[a-z]+\\(.*?\\)|[a-z]+)/ig);for(var E=0,B=C.length,D;E<B;++E){D=C[E].split(\"=\",2).reverse();G.stops.push([D[1]||E/(B-1),D[0]])}return G}),quotedList:j(function(E){var D=[],C=/\\s*(([\"'])([\\s\\S]*?[^\\\\])\\2|[^,]+)\\s*/g,B;while(B=C.exec(E)){D.push(B[3]||B[1])}return D}),recognizesMedia:j(function(G){var E=document.createElement(\"style\"),D,C,B;E.type=\"text/css\";E.media=G;try{E.appendChild(document.createTextNode(\"/**/\"))}catch(F){}C=g(\"head\")[0];C.insertBefore(E,C.firstChild);D=(E.sheet||E.styleSheet);B=D&&!D.disabled;C.removeChild(E);return B}),removeClass:function(D,C){var B=RegExp(\"(?:^|\\\\s+)\"+C+\"(?=\\\\s|$)\",\"g\");D.className=D.className.replace(B,\"\");return D},supports:function(D,C){var B=document.createElement(\"span\").style;if(B[D]===undefined){return false}B[D]=C;return B[D]===C},textAlign:function(E,D,B,C){if(D.get(\"textAlign\")==\"right\"){if(B>0){E=\" \"+E}}else{if(B<C-1){E+=\" \"}}return E},textShadow:j(function(F){if(F==\"none\"){return null}var E=[],G={},B,C=0;var D=/(#[a-f0-9]+|[a-z]+\\(.*?\\)|[a-z]+)|(-?[\\d.]+[a-z%]*)|,/ig;while(B=D.exec(F)){if(B[0]==\",\"){E.push(G);G={};C=0}else{if(B[1]){G.color=B[1]}else{G[[\"offX\",\"offY\",\"blur\"][C++]]=B[2]}}}E.push(G);return E}),textTransform:(function(){var B={uppercase:function(C){return C.toUpperCase()},lowercase:function(C){return C.toLowerCase()},capitalize:function(C){return C.replace(/\\b./g,function(D){return D.toUpperCase()})}};return function(E,D){var C=B[D.get(\"textTransform\")];return C?C(E):E}})(),whiteSpace:(function(){var D={inline:1,\"inline-block\":1,\"run-in\":1};var C=/^\\s+/,B=/\\s+$/;return function(H,F,G,E){if(E){if(E.nodeName.toLowerCase()==\"br\"){H=H.replace(C,\"\")}}if(D[F.get(\"display\")]){return H}if(!G.previousSibling){H=H.replace(C,\"\")}if(!G.nextSibling){H=H.replace(B,\"\")}return H}})()};n.ready=(function(){var B=!n.recognizesMedia(\"all\"),E=false;var D=[],H=function(){B=true;for(var K;K=D.shift();K()){}};var I=g(\"link\"),J=g(\"style\");function C(K){return K.disabled||G(K.sheet,K.media||\"screen\")}function G(M,P){if(!n.recognizesMedia(P||\"all\")){return true}if(!M||M.disabled){return false}try{var Q=M.cssRules,O;if(Q){search:for(var L=0,K=Q.length;O=Q[L],L<K;++L){switch(O.type){case 2:break;case 3:if(!G(O.styleSheet,O.media.mediaText)){return false}break;default:break search}}}}catch(N){}return true}function F(){if(document.createStyleSheet){return true}var L,K;for(K=0;L=I[K];++K){if(L.rel.toLowerCase()==\"stylesheet\"&&!C(L)){return false}}for(K=0;L=J[K];++K){if(!C(L)){return false}}return true}x.ready(function(){if(!E){E=n.getStyle(document.body).isUsable()}if(B||(E&&F())){H()}else{setTimeout(arguments.callee,10)}});return function(K){if(B){K()}else{D.push(K)}}})();function s(D){var C=this.face=D.face,B={\"\\u0020\":1,\"\\u00a0\":1,\"\\u3000\":1};this.glyphs=D.glyphs;this.w=D.w;this.baseSize=parseInt(C[\"units-per-em\"],10);this.family=C[\"font-family\"].toLowerCase();this.weight=C[\"font-weight\"];this.style=C[\"font-style\"]||\"normal\";this.viewBox=(function(){var F=C.bbox.split(/\\s+/);var E={minX:parseInt(F[0],10),minY:parseInt(F[1],10),maxX:parseInt(F[2],10),maxY:parseInt(F[3],10)};E.width=E.maxX-E.minX;E.height=E.maxY-E.minY;E.toString=function(){return[this.minX,this.minY,this.width,this.height].join(\" \")};return E})();this.ascent=-parseInt(C.ascent,10);this.descent=-parseInt(C.descent,10);this.height=-this.ascent+this.descent;this.spacing=function(L,N,E){var O=this.glyphs,M,K,G,P=[],F=0,J=-1,I=-1,H;while(H=L[++J]){M=O[H]||this.missingGlyph;if(!M){continue}if(K){F-=G=K[H]||0;P[I]-=G}F+=P[++I]=~~(M.w||this.w)+N+(B[H]?E:0);K=M.k}P.total=F;return P}}function f(){var C={},B={oblique:\"italic\",italic:\"oblique\"};this.add=function(D){(C[D.style]||(C[D.style]={}))[D.weight]=D};this.get=function(H,I){var G=C[H]||C[B[H]]||C.normal||C.italic||C.oblique;if(!G){return null}I={normal:400,bold:700}[I]||parseInt(I,10);if(G[I]){return G[I]}var E={1:1,99:0}[I%100],K=[],F,D;if(E===undefined){E=I>400}if(I==500){I=400}for(var J in G){if(!k(G,J)){continue}J=parseInt(J,10);if(!F||J<F){F=J}if(!D||J>D){D=J}K.push(J)}if(I<F){I=F}if(I>D){I=D}K.sort(function(M,L){return(E?(M>=I&&L>=I)?M<L:M>L:(M<=I&&L<=I)?M>L:M<L)?-1:1});return G[K[0]]}}function r(){function D(F,G){if(F.contains){return F.contains(G)}return F.compareDocumentPosition(G)&16}function B(G){var F=G.relatedTarget;if(!F||D(this,F)){return}C(this,G.type==\"mouseover\")}function E(F){C(this,F.type==\"mouseenter\")}function C(F,G){setTimeout(function(){var H=d.get(F).options;m.replace(F,G?h(H,H.hover):H,true)},10)}this.attach=function(F){if(F.onmouseenter===undefined){q(F,\"mouseover\",B);q(F,\"mouseout\",B)}else{q(F,\"mouseenter\",E);q(F,\"mouseleave\",E)}}}function u(){var C=[],D={};function B(H){var E=[],G;for(var F=0;G=H[F];++F){E[F]=C[D[G]]}return E}this.add=function(F,E){D[F]=C.push(E)-1};this.repeat=function(){var E=arguments.length?B(arguments):C,F;for(var G=0;F=E[G++];){m.replace(F[0],F[1],true)}}}function A(){var D={},B=0;function C(E){return E.cufid||(E.cufid=++B)}this.get=function(E){var F=C(E);return D[F]||(D[F]={})}}function a(B){var D={},C={};this.extend=function(E){for(var F in E){if(k(E,F)){D[F]=E[F]}}return this};this.get=function(E){return D[E]!=undefined?D[E]:B[E]};this.getSize=function(F,E){return C[F]||(C[F]=new n.Size(this.get(F),E))};this.isUsable=function(){return !!B}}function q(C,B,D){if(C.addEventListener){C.addEventListener(B,D,false)}else{if(C.attachEvent){C.attachEvent(\"on\"+B,function(){return D.call(C,window.event)})}}}function v(C,B){var D=d.get(C);if(D.options){return C}if(B.hover&&B.hoverables[C.nodeName.toLowerCase()]){b.attach(C)}D.options=B;return C}function j(B){var C={};return function(D){if(!k(C,D)){C[D]=B.apply(null,arguments)}return C[D]}}function c(F,E){var B=n.quotedList(E.get(\"fontFamily\").toLowerCase()),D;for(var C=0;D=B[C];++C){if(i[D]){return i[D].get(E.get(\"fontStyle\"),E.get(\"fontWeight\"))}}return null}function g(B){return document.getElementsByTagName(B)}function k(C,B){return C.hasOwnProperty(B)}function h(){var C={},B,F;for(var E=0,D=arguments.length;B=arguments[E],E<D;++E){for(F in B){if(k(B,F)){C[F]=B[F]}}}return C}function o(E,M,C,N,F,D){var K=document.createDocumentFragment(),H;if(M===\"\"){return K}var L=N.separate;var I=M.split(p[L]),B=(L==\"words\");if(B&&t){if(/^\\s/.test(M)){I.unshift(\"\")}if(/\\s$/.test(M)){I.push(\"\")}}for(var J=0,G=I.length;J<G;++J){H=z[N.engine](E,B?n.textAlign(I[J],C,J,G):I[J],C,N,F,D,J<G-1);if(H){K.appendChild(H)}}return K}function l(D,M){var C=D.nodeName.toLowerCase();if(M.ignore[C]){return}var E=!M.textless[C];var B=n.getStyle(v(D,M)).extend(M);var F=c(D,B),G,K,I,H,L,J;if(!F){return}for(G=D.firstChild;G;G=I){K=G.nodeType;I=G.nextSibling;if(E&&K==3){if(H){H.appendData(G.data);D.removeChild(G)}else{H=G}if(I){continue}}if(H){D.replaceChild(o(F,n.whiteSpace(H.data,B,H,J),B,M,G,D),H);H=null}if(K==1){if(G.firstChild){if(G.nodeName.toLowerCase()==\"cufon\"){z[M.engine](F,null,B,M,G,D)}else{arguments.callee(G,M)}}J=G}}}var t=\" \".split(/\\s+/).length==0;var d=new A();var b=new r();var y=new u();var e=false;var z={},i={},w={autoDetect:false,engine:null,forceHitArea:false,hover:false,hoverables:{a:true},ignore:{applet:1,canvas:1,col:1,colgroup:1,head:1,iframe:1,map:1,optgroup:1,option:1,script:1,select:1,style:1,textarea:1,title:1,pre:1},printable:true,selector:(window.Sizzle||(window.jQuery&&function(B){return jQuery(B)})||(window.dojo&&dojo.query)||(window.Ext&&Ext.query)||(window.YAHOO&&YAHOO.util&&YAHOO.util.Selector&&YAHOO.util.Selector.query)||(window.$$&&function(B){return $$(B)})||(window.$&&function(B){return $(B)})||(document.querySelectorAll&&function(B){return document.querySelectorAll(B)})||g),separate:\"words\",textless:{dl:1,html:1,ol:1,table:1,tbody:1,thead:1,tfoot:1,tr:1,ul:1},textShadow:\"none\"};var p={words:/\\s/.test(\"\\u00a0\")?/[^\\S\\u00a0]+/:/\\s+/,characters:\"\",none:/^/};m.now=function(){x.ready();return m};m.refresh=function(){y.repeat.apply(y,arguments);return m};m.registerEngine=function(C,B){if(!B){return m}z[C]=B;return m.set(\"engine\",C)};m.registerFont=function(D){if(!D){return m}var B=new s(D),C=B.family;if(!i[C]){i[C]=new f()}i[C].add(B);return m.set(\"fontFamily\",'\"'+C+'\"')};m.replace=function(D,C,B){C=h(w,C);if(!C.engine){return m}if(!e){n.addClass(x.root(),\"cufon-active cufon-loading\");n.ready(function(){n.addClass(n.removeClass(x.root(),\"cufon-loading\"),\"cufon-ready\")});e=true}if(C.hover){C.forceHitArea=true}if(C.autoDetect){delete C.fontFamily}if(typeof C.textShadow==\"string\"){C.textShadow=n.textShadow(C.textShadow)}if(typeof C.color==\"string\"&&/^-/.test(C.color)){C.textGradient=n.gradient(C.color)}else{delete C.textGradient}if(!B){y.add(D,arguments)}if(D.nodeType||typeof D==\"string\"){D=[D]}n.ready(function(){for(var F=0,E=D.length;F<E;++F){var G=D[F];if(typeof G==\"string\"){m.replace(C.selector(G),C,true)}else{l(G,C)}}});return m};m.set=function(B,C){w[B]=C;return m};return m})();Cufon.registerEngine(\"canvas\",(function(){var b=document.createElement(\"canvas\");if(!b||!b.getContext||!b.getContext.apply){return}b=null;var a=Cufon.CSS.supports(\"display\",\"inline-block\");var e=!a&&(document.compatMode==\"BackCompat\"||/frameset|transitional/i.test(document.doctype.publicId));var f=document.createElement(\"style\");f.type=\"text/css\";f.appendChild(document.createTextNode((\"cufon{text-indent:0;}@media screen,projection{cufon{display:inline;display:inline-block;position:relative;vertical-align:middle;\"+(e?\"\":\"font-size:1px;line-height:1px;\")+\"}cufon cufontext{display:-moz-inline-box;display:inline-block;width:0;height:0;overflow:hidden;text-indent:-10000in;}\"+(a?\"cufon canvas{position:relative;}\":\"cufon canvas{position:absolute;}\")+\"}@media print{cufon{padding:0;}cufon canvas{display:none;}}\").replace(/;/g,\"!important;\")));document.getElementsByTagName(\"head\")[0].appendChild(f);function d(p,h){var n=0,m=0;var g=[],o=/([mrvxe])([^a-z]*)/g,k;generate:for(var j=0;k=o.exec(p);++j){var l=k[2].split(\",\");switch(k[1]){case\"v\":g[j]={m:\"bezierCurveTo\",a:[n+~~l[0],m+~~l[1],n+~~l[2],m+~~l[3],n+=~~l[4],m+=~~l[5]]};break;case\"r\":g[j]={m:\"lineTo\",a:[n+=~~l[0],m+=~~l[1]]};break;case\"m\":g[j]={m:\"moveTo\",a:[n=~~l[0],m=~~l[1]]};break;case\"x\":g[j]={m:\"closePath\"};break;case\"e\":break generate}h[g[j].m].apply(h,g[j].a)}return g}function c(m,k){for(var j=0,h=m.length;j<h;++j){var g=m[j];k[g.m].apply(k,g.a)}}return function(V,w,P,t,C,W){var k=(w===null);if(k){w=C.getAttribute(\"alt\")}var A=V.viewBox;var m=P.getSize(\"fontSize\",V.baseSize);var B=0,O=0,N=0,u=0;var z=t.textShadow,L=[];if(z){for(var U=z.length;U--;){var F=z[U];var K=m.convertFrom(parseFloat(F.offX));var I=m.convertFrom(parseFloat(F.offY));L[U]=[K,I];if(I<B){B=I}if(K>O){O=K}if(I>N){N=I}if(K<u){u=K}}}var Z=Cufon.CSS.textTransform(w,P).split(\"\");var E=V.spacing(Z,~~m.convertFrom(parseFloat(P.get(\"letterSpacing\"))||0),~~m.convertFrom(parseFloat(P.get(\"wordSpacing\"))||0));if(!E.length){return null}var h=E.total;O+=A.width-E[E.length-1];u+=A.minX;var s,n;if(k){s=C;n=C.firstChild}else{s=document.createElement(\"cufon\");s.className=\"cufon cufon-canvas\";s.setAttribute(\"alt\",w);n=document.createElement(\"canvas\");s.appendChild(n);if(t.printable){var S=document.createElement(\"cufontext\");S.appendChild(document.createTextNode(w));s.appendChild(S)}}var aa=s.style;var H=n.style;var j=m.convert(A.height);var Y=Math.ceil(j);var M=Y/j;var G=M*Cufon.CSS.fontStretch(P.get(\"fontStretch\"));var J=h*G;var Q=Math.ceil(m.convert(J+O-u));var o=Math.ceil(m.convert(A.height-B+N));n.width=Q;n.height=o;H.width=Q+\"px\";H.height=o+\"px\";B+=A.minY;H.top=Math.round(m.convert(B-V.ascent))+\"px\";H.left=Math.round(m.convert(u))+\"px\";var r=Math.max(Math.ceil(m.convert(J)),0)+\"px\";if(a){aa.width=r;aa.height=m.convert(V.height)+\"px\"}else{aa.paddingLeft=r;aa.paddingBottom=(m.convert(V.height)-1)+\"px\"}var X=n.getContext(\"2d\"),D=j/A.height;X.scale(D,D*M);X.translate(-u,-B);X.save();function T(){var x=V.glyphs,ab,l=-1,g=-1,y;X.scale(G,1);while(y=Z[++l]){var ab=x[Z[l]]||V.missingGlyph;if(!ab){continue}if(ab.d){X.beginPath();if(ab.code){c(ab.code,X)}else{ab.code=d(\"m\"+ab.d,X)}X.fill()}X.translate(E[++g],0)}X.restore()}if(z){for(var U=z.length;U--;){var F=z[U];X.save();X.fillStyle=F.color;X.translate.apply(X,L[U]);T()}}var q=t.textGradient;if(q){var v=q.stops,p=X.createLinearGradient(0,A.minY,0,A.maxY);for(var U=0,R=v.length;U<R;++U){p.addColorStop.apply(p,v[U])}X.fillStyle=p}else{X.fillStyle=P.get(\"color\")}T();return s}})());Cufon.registerEngine(\"vml\",(function(){var e=document.namespaces;if(!e){return}e.add(\"cvml\",\"urn:schemas-microsoft-com:vml\");e=null;var b=document.createElement(\"cvml:shape\");b.style.behavior=\"url(#default#VML)\";if(!b.coordsize){return}b=null;var h=(document.documentMode||0)<8;document.write(('<style type=\"text/css\">cufoncanvas{text-indent:0;}@media screen{cvml\\\\:shape,cvml\\\\:rect,cvml\\\\:fill,cvml\\\\:shadow{behavior:url(#default#VML);display:block;antialias:true;position:absolute;}cufoncanvas{position:absolute;text-align:left;}cufon{display:inline-block;position:relative;vertical-align:'+(h?\"middle\":\"text-bottom\")+\";}cufon cufontext{position:absolute;left:-10000in;font-size:1px;}a cufon{cursor:pointer}}@media print{cufon cufoncanvas{display:none;}}</style>\").replace(/;/g,\"!important;\"));function c(i,j){return a(i,/(?:em|ex|%)$|^[a-z-]+$/i.test(j)?\"1em\":j)}function a(l,m){if(m===\"0\"){return 0}if(/px$/i.test(m)){return parseFloat(m)}var k=l.style.left,j=l.runtimeStyle.left;l.runtimeStyle.left=l.currentStyle.left;l.style.left=m.replace(\"%\",\"em\");var i=l.style.pixelLeft;l.style.left=k;l.runtimeStyle.left=j;return i}function f(l,k,j,n){var i=\"computed\"+n,m=k[i];if(isNaN(m)){m=k.get(n);k[i]=m=(m==\"normal\")?0:~~j.convertFrom(a(l,m))}return m}var g={};function d(p){var q=p.id;if(!g[q]){var n=p.stops,o=document.createElement(\"cvml:fill\"),i=[];o.type=\"gradient\";o.angle=180;o.focus=\"0\";o.method=\"sigma\";o.color=n[0][1];for(var m=1,l=n.length-1;m<l;++m){i.push(n[m][0]*100+\"% \"+n[m][1])}o.colors=i.join(\",\");o.color2=n[l][1];g[q]=o}return g[q]}return function(ac,G,Y,C,K,ad,W){var n=(G===null);if(n){G=K.alt}var I=ac.viewBox;var p=Y.computedFontSize||(Y.computedFontSize=new Cufon.CSS.Size(c(ad,Y.get(\"fontSize\"))+\"px\",ac.baseSize));var y,q;if(n){y=K;q=K.firstChild}else{y=document.createElement(\"cufon\");y.className=\"cufon cufon-vml\";y.alt=G;q=document.createElement(\"cufoncanvas\");y.appendChild(q);if(C.printable){var Z=document.createElement(\"cufontext\");Z.appendChild(document.createTextNode(G));y.appendChild(Z)}if(!W){y.appendChild(document.createElement(\"cvml:shape\"))}}var ai=y.style;var R=q.style;var l=p.convert(I.height),af=Math.ceil(l);var V=af/l;var P=V*Cufon.CSS.fontStretch(Y.get(\"fontStretch\"));var U=I.minX,T=I.minY;R.height=af;R.top=Math.round(p.convert(T-ac.ascent));R.left=Math.round(p.convert(U));ai.height=p.convert(ac.height)+\"px\";var F=Y.get(\"color\");var ag=Cufon.CSS.textTransform(G,Y).split(\"\");var L=ac.spacing(ag,f(ad,Y,p,\"letterSpacing\"),f(ad,Y,p,\"wordSpacing\"));if(!L.length){return null}var k=L.total;var x=-U+k+(I.width-L[L.length-1]);var ah=p.convert(x*P),X=Math.round(ah);var O=x+\",\"+I.height,m;var J=\"r\"+O+\"ns\";var u=C.textGradient&&d(C.textGradient);var o=ac.glyphs,S=0;var H=C.textShadow;var ab=-1,aa=0,w;while(w=ag[++ab]){var D=o[ag[ab]]||ac.missingGlyph,v;if(!D){continue}if(n){v=q.childNodes[aa];while(v.firstChild){v.removeChild(v.firstChild)}}else{v=document.createElement(\"cvml:shape\");q.appendChild(v)}v.stroked=\"f\";v.coordsize=O;v.coordorigin=m=(U-S)+\",\"+T;v.path=(D.d?\"m\"+D.d+\"xe\":\"\")+\"m\"+m+J;v.fillcolor=F;if(u){v.appendChild(u.cloneNode(false))}var ae=v.style;ae.width=X;ae.height=af;if(H){var s=H[0],r=H[1];var B=Cufon.CSS.color(s.color),z;var N=document.createElement(\"cvml:shadow\");N.on=\"t\";N.color=B.color;N.offset=s.offX+\",\"+s.offY;if(r){z=Cufon.CSS.color(r.color);N.type=\"double\";N.color2=z.color;N.offset2=r.offX+\",\"+r.offY}N.opacity=B.opacity||(z&&z.opacity)||1;v.appendChild(N)}S+=L[aa++]}var M=v.nextSibling,t,A;if(C.forceHitArea){if(!M){M=document.createElement(\"cvml:rect\");M.stroked=\"f\";M.className=\"cufon-vml-cover\";t=document.createElement(\"cvml:fill\");t.opacity=0;M.appendChild(t);q.appendChild(M)}A=M.style;A.width=X;A.height=af}else{if(M){q.removeChild(M)}}ai.width=Math.max(Math.ceil(p.convert(k*P)),0);if(h){var Q=Y.computedYAdjust;if(Q===undefined){var E=Y.get(\"lineHeight\");if(E==\"normal\"){E=\"1em\"}else{if(!isNaN(E)){E+=\"em\"}}Y.computedYAdjust=Q=0.5*(a(ad,E)-parseFloat(ai.height))}if(Q){ai.marginTop=Math.ceil(Q)+\"px\";ai.marginBottom=Q+\"px\"}}return y}})());\n"
  },
  {
    "path": "public/javascripts/static/execute.js",
    "content": "$(document).ready(function() {\n    // Read More Buttons\n    $('a.readmore').append('<span class=\"hover\"></span>');\n           // span whose opacity will animate when mouse hovers.\n           $('a.readmore').hover(\n     function() {\n      $('.hover', this).stop().animate({ 'opacity': 0 }, 300,'easeOutSine')},\n     function() {\n           $('.hover', this).stop().animate({ 'opacity': 1 }, 300, 'easeOutQuad') });\n\n     // Pricing Buttons\n   $('a.pricing-buttom').prepend('<a class=\"phover\"></a>');\n           // span whose opacity will animate when mouse hovers.\n           $('a.pricing-buttom').hover(\n     function() {\n\n      $('.phover', this).stop().animate({'opacity': 0 }, 300,'easeOutSine')},\n     function() {\n           $('.phover', this).stop().animate({'opacity': 1}, 300, 'easeOutQuad')});\n\n\n    // The main menu\n     $('ul.sf-menu').superfish({\n            delay:       1000,                            // one second delay on mouseout\n            animation:   {opacity:'show',height:'show'},  // fade-in and slide-down animation\n            speed:       'slow',                          // faster animation speed\n            autoArrows:  false,                           // disable generation of arrow mark-up\n            dropShadows: false                            // disable drop shadows\n        });\n});\n"
  },
  {
    "path": "public/javascripts/static/hoverIntent.js",
    "content": "(function($){\n  /* hoverIntent by Brian Cherne */\n  $.fn.hoverIntent = function(f,g) {\n    // default configuration options\n    var cfg = {\n      sensitivity: 7,\n      interval: 100,\n      timeout: 0\n    };\n    // override configuration options with user supplied object\n    cfg = $.extend(cfg, g ? { over: f, out: g } : f );\n\n    // instantiate variables\n    // cX, cY = current X and Y position of mouse, updated by mousemove event\n    // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval\n    var cX, cY, pX, pY;\n\n    // A private function for getting mouse position\n    var track = function(ev) {\n      cX = ev.pageX;\n      cY = ev.pageY;\n    };\n\n    // A private function for comparing current and previous mouse position\n    var compare = function(ev,ob) {\n      ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);\n      // compare mouse positions to see if they've crossed the threshold\n      if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {\n        $(ob).unbind(\"mousemove\",track);\n        // set hoverIntent state to true (so mouseOut can be called)\n        ob.hoverIntent_s = 1;\n        return cfg.over.apply(ob,[ev]);\n      } else {\n        // set previous coordinates for next time\n        pX = cX; pY = cY;\n        // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)\n        ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );\n      }\n    };\n\n    // A private function for delaying the mouseOut function\n    var delay = function(ev,ob) {\n      ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);\n      ob.hoverIntent_s = 0;\n      return cfg.out.apply(ob,[ev]);\n    };\n\n    // A private function for handling mouse 'hovering'\n    var handleHover = function(e) {\n      // next three lines copied from jQuery.hover, ignore children onMouseOver/onMouseOut\n      var p = (e.type == \"mouseover\" ? e.fromElement : e.toElement) || e.relatedTarget;\n      while ( p && p != this ) { try { p = p.parentNode; } catch(e) { p = this; } }\n      if ( p == this ) { return false; }\n\n      // copy objects to be passed into t (required for event object to be passed in IE)\n      var ev = jQuery.extend({},e);\n      var ob = this;\n\n      // cancel hoverIntent timer if it exists\n      if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }\n\n      // else e.type == \"onmouseover\"\n      if (e.type == \"mouseover\") {\n        // set \"previous\" X and Y position based on initial entry point\n        pX = ev.pageX; pY = ev.pageY;\n        // update \"current\" X and Y position based on mousemove\n        $(ob).bind(\"mousemove\",track);\n        // start polling interval (self-calling timeout) to compare mouse coordinates over time\n        if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}\n\n      // else e.type == \"onmouseout\"\n      } else {\n        // unbind expensive mousemove event\n        $(ob).unbind(\"mousemove\",track);\n        // if hoverIntent state is true, then call the mouseOut function after the specified delay\n        if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}\n      }\n    };\n\n    // bind the function to the two event listeners\n    return this.mouseover(handleHover).mouseout(handleHover);\n  };\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/static/jquery-galleryview-1.1/jquery.galleryview-1.1.js",
    "content": "/*\n\n  GalleryView - jQuery Content Gallery Plugin\n  Author:     Jack Anderson\n  Version:    1.1 (April 5, 2009)\n  Documentation:   http://www.spaceforaname.com/jquery/galleryview/\n\n  Please use this development script if you intend to make changes to the\n  plugin code.  For production sites, please use jquery.galleryview-1.0.1-pack.js.\n\n*/\n(function($){\n  $.fn.galleryView = function(options) {\n    var opts = $.extend($.fn.galleryView.defaults,options);\n\n    var id;\n    var iterator = 0;\n    var gallery_width;\n    var gallery_height;\n    var frame_margin = 10;\n    var strip_width;\n    var wrapper_width;\n    var item_count = 0;\n    var slide_method;\n    var img_path;\n    var paused = false;\n    var frame_caption_size = 20;\n    var frame_margin_top = 5;\n    var pointer_width = 2;\n\n    //Define jQuery objects for reuse\n    var j_gallery;\n    var j_filmstrip;\n    var j_frames;\n    var j_panels;\n    var j_pointer;\n\n/************************************************/\n/*  Plugin Methods                */\n/************************************************/\n    function showItem(i) {\n      //Disable next/prev buttons until transition is complete\n      $('img.nav-next').unbind('click');\n      $('img.nav-prev').unbind('click');\n      j_frames.unbind('click');\n      if(has_panels) {\n        if(opts.fade_panels) {\n          //Fade out all panels and fade in target panel\n          j_panels.fadeOut(opts.transition_speed).eq(i%item_count).fadeIn(opts.transition_speed,function(){\n            if(!has_filmstrip) {\n              $('img.nav-prev').click(showPrevItem);\n              $('img.nav-next').click(showNextItem);\n            }\n          });\n        }\n      }\n\n      if(has_filmstrip) {\n        //Slide either pointer or filmstrip, depending on transition method\n        if(slide_method=='strip') {\n          //Stop filmstrip if it's currently in motion\n          j_filmstrip.stop();\n\n          //Determine distance between pointer (eventual destination) and target frame\n          var distance = getPos(j_frames[i]).left - (getPos(j_pointer[0]).left+2);\n          var leftstr = (distance>=0?'-=':'+=')+Math.abs(distance)+'px';\n\n          //Animate filmstrip and slide target frame under pointer\n          //If target frame is a duplicate, jump back to 'original' frame\n          j_filmstrip.animate({\n            'left':leftstr\n          },opts.transition_speed,opts.easing,function(){\n            //Always ensure that there are a sufficient number of hidden frames on either\n            //side of the filmstrip to avoid empty frames\n            if(i>item_count) {\n              i = i%item_count;\n              iterator = i;\n              j_filmstrip.css('left','-'+((opts.frame_width+frame_margin)*i)+'px');\n            } else if (i<=(item_count-strip_size)) {\n              i = (i%item_count)+item_count;\n              iterator = i;\n              j_filmstrip.css('left','-'+((opts.frame_width+frame_margin)*i)+'px');\n            }\n\n            if(!opts.fade_panels) {\n              j_panels.hide().eq(i%item_count).show();\n            }\n            $('img.nav-prev').click(showPrevItem);\n            $('img.nav-next').click(showNextItem);\n            enableFrameClicking();\n          });\n        } else if(slide_method=='pointer') {\n          //Stop pointer if it's currently in motion\n          j_pointer.stop();\n          //Get position of target frame\n          var pos = getPos(j_frames[i]);\n          //Slide the pointer over the target frame\n          j_pointer.animate({\n            'left':(pos.left-2+'px')\n          },opts.transition_speed,opts.easing,function(){\n            if(!opts.fade_panels) {\n              j_panels.hide().eq(i%item_count).show();\n            }\n            $('img.nav-prev').click(showPrevItem);\n            $('img.nav-next').click(showNextItem);\n            enableFrameClicking();\n          });\n        }\n\n        if($('a',j_frames[i])[0]) {\n          j_pointer.unbind('click').click(function(){\n            var a = $('a',j_frames[i]).eq(0);\n            if(a.attr('target')=='_blank') {window.open(a.attr('href'));}\n            else {location.href = a.attr('href');}\n          });\n        }\n      }\n    };\n    function showNextItem() {\n      $(document).stopTime(\"transition\");\n      if(++iterator==j_frames.length) {iterator=0;}\n      showItem(iterator);\n      $(document).everyTime(opts.transition_interval,\"transition\",function(){\n        showNextItem();\n      });\n    };\n    function showPrevItem() {\n      $(document).stopTime(\"transition\");\n      if(--iterator<0) {iterator = item_count-1;}\n      //alert(iterator);\n      showItem(iterator);\n      $(document).everyTime(opts.transition_interval,\"transition\",function(){\n        showNextItem();\n      });\n    };\n    function getPos(el) {\n      var left = 0, top = 0;\n      var el_id = el.id;\n      if(el.offsetParent) {\n        do {\n          left += el.offsetLeft;\n          top += el.offsetTop;\n        } while(el = el.offsetParent);\n      }\n      //If we want the position of the gallery itself, return it\n      if(el_id == id) {return {'left':left,'top':top};}\n      //Otherwise, get position of element relative to gallery\n      else {\n        var gPos = getPos(j_gallery[0]);\n        var gLeft = gPos.left;\n        var gTop = gPos.top;\n\n        return {'left':left-gLeft,'top':top-gTop};\n      }\n    };\n    function enableFrameClicking() {\n      j_frames.each(function(i){\n        //If there isn't a link in this frame, set up frame to slide on click\n        //Frames with links will handle themselves\n        if($('a',this).length==0) {\n          $(this).click(function(){\n            $(document).stopTime(\"transition\");\n            showItem(i);\n            iterator = i;\n            $(document).everyTime(opts.transition_interval,\"transition\",function(){\n              showNextItem();\n            });\n          });\n        }\n      });\n    };\n\n    function buildPanels() {\n      //If there are panel captions, add overlay divs\n      if($('.panel-overlay').length>0) {j_panels.append('<div class=\"overlay\"></div>');}\n\n      if(!has_filmstrip) {\n        //Add navigation buttons\n        $('<img />').addClass('nav-next').attr('src',img_path+opts.nav_theme+'/next.png').appendTo(j_gallery).css({\n          'position':'absolute',\n          'zIndex':'1100',\n          'cursor':'pointer',\n          'top':((opts.panel_height-22)/2)+'px',\n          'right':'10px',\n          'display':'none'\n        }).click(showNextItem);\n        $('<img />').addClass('nav-prev').attr('src',img_path+opts.nav_theme+'/prev.png').appendTo(j_gallery).css({\n          'position':'absolute',\n          'zIndex':'1100',\n          'cursor':'pointer',\n          'top':((opts.panel_height-22)/2)+'px',\n          'left':'10px',\n          'display':'none'\n        }).click(showPrevItem);\n\n        $('<img />').addClass('nav-overlay').attr('src',img_path+opts.nav_theme+'/panel-nav-next.png').appendTo(j_gallery).css({\n          'position':'absolute',\n          'zIndex':'1099',\n          'top':((opts.panel_height-22)/2)-10+'px',\n          'right':'0',\n          'display':'none'\n        });\n\n        $('<img />').addClass('nav-overlay').attr('src',img_path+opts.nav_theme+'/panel-nav-prev.png').appendTo(j_gallery).css({\n          'position':'absolute',\n          'zIndex':'1099',\n          'top':((opts.panel_height-22)/2)-10+'px',\n          'left':'0',\n          'display':'none'\n        });\n      }\n      j_panels.css({\n        'width':(opts.panel_width-parseInt(j_panels.css('paddingLeft').split('px')[0],10)-parseInt(j_panels.css('paddingRight').split('px')[0],10))+'px',\n        'height':(opts.panel_height-parseInt(j_panels.css('paddingTop').split('px')[0],10)-parseInt(j_panels.css('paddingBottom').split('px')[0],10))+'px',\n        'position':'absolute',\n        'top':(opts.filmstrip_position=='top'?(opts.frame_height+frame_margin_top+(opts.show_captions?frame_caption_size:frame_margin_top))+'px':'0px'),\n        'left':'0px',\n        'overflow':'hidden',\n        'background':'white',\n        'display':'none'\n      });\n      $('.panel-overlay',j_panels).css({\n        'position':'absolute',\n        'zIndex':'999',\n        'width':(opts.panel_width-20)+'px',\n        'height':opts.overlay_height+'px',\n        'top':(opts.overlay_position=='top'?'0':opts.panel_height-opts.overlay_height+'px'),\n        'left':'0',\n        'padding':'0 10px',\n        'color':opts.overlay_text_color,\n        'fontSize':opts.overlay_font_size\n      });\n      $('.panel-overlay a',j_panels).css({\n        'color':opts.overlay_text_color,\n        'textDecoration':'underline',\n        'fontWeight':'bold'\n      });\n      $('.overlay',j_panels).css({\n        'position':'absolute',\n        'zIndex':'998',\n        'width':opts.panel_width+'px',\n        'height':opts.overlay_height+'px',\n        'top':(opts.overlay_position=='top'?'0':opts.panel_height-opts.overlay_height+'px'),\n        'left':'0',\n        'background':opts.overlay_color,\n        'opacity':opts.overlay_opacity\n      });\n      $('.panel iframe',j_panels).css({\n        'width':opts.panel_width+'px',\n        'height':(opts.panel_height-opts.overlay_height)+'px',\n        'border':'0'\n      });\n    };\n\n    function buildFilmstrip() {\n      //Add wrapper to filmstrip to hide extra frames\n      j_filmstrip.wrap('<div class=\"strip_wrapper\"></div>');\n      if(slide_method=='strip') {\n        j_frames.clone().appendTo(j_filmstrip);\n        j_frames.clone().appendTo(j_filmstrip);\n        j_frames = $('li',j_filmstrip);\n      }\n      //If captions are enabled, add caption divs and fill with the image titles\n      if(opts.show_captions) {\n        j_frames.append('<div class=\"caption\"></div>').each(function(i){\n          $(this).find('.caption').html($(this).find('img').attr('title'));\n        });\n      }\n\n      j_filmstrip.css({\n        'listStyle':'none',\n        'margin':'0',\n        'padding':'0',\n        'width':strip_width+'px',\n        'position':'absolute',\n        'zIndex':'900',\n        'top':'0',\n        'left':'0',\n        'height':(opts.frame_height+10)+'px',\n        'background':opts.background_color\n      });\n      j_frames.css({\n        'float':'left',\n        'position':'relative',\n        'height':opts.frame_height+'px',\n        'zIndex':'901',\n        'marginTop':frame_margin_top+'px',\n        'marginBottom':'0px',\n        'marginRight':frame_margin+'px',\n        'padding':'0',\n        'cursor':'pointer'\n      });\n      $('img',j_frames).css({\n        'border':'none'\n      });\n      $('.strip_wrapper',j_gallery).css({\n        'position':'absolute',\n        'top':(opts.filmstrip_position=='top'?'0px':opts.panel_height+'px'),\n        'left':((gallery_width-wrapper_width)/2)+'px',\n        'width':wrapper_width+'px',\n        'height':(opts.frame_height+frame_margin_top+(opts.show_captions?frame_caption_size:frame_margin_top))+'px',\n        'overflow':'hidden'\n      });\n      $('.caption',j_gallery).css({\n        'position':'absolute',\n        'top':opts.frame_height+'px',\n        'left':'0',\n        'margin':'0',\n        'width':opts.frame_width+'px',\n        'padding':'0',\n        'color':opts.caption_text_color,\n        'textAlign':'center',\n        'fontSize':'10px',\n        'height':frame_caption_size+'px',\n\n        'lineHeight':frame_caption_size+'px'\n      });\n      var pointer = $('<div></div>');\n      pointer.attr('id','pointer').appendTo(j_gallery).css({\n         'position':'absolute',\n         'zIndex':'1000',\n         'cursor':'pointer',\n         'top':getPos(j_frames[0]).top-(pointer_width/2)+'px',\n         'left':getPos(j_frames[0]).left-(pointer_width/2)+'px',\n         'height':opts.frame_height-pointer_width+'px',\n         'width':opts.frame_width-pointer_width+'px',\n         'border':(has_panels?pointer_width+'px solid '+(opts.nav_theme=='dark'?'black':'white'):'none')\n      });\n      j_pointer = $('#pointer',j_gallery);\n      if(has_panels) {\n        var pointerArrow = $('<img />');\n        pointerArrow.attr('src',img_path+opts.nav_theme+'/pointer'+(opts.filmstrip_position=='top'?'-down':'')+'.png').appendTo($('#pointer')).css({\n          'position':'absolute',\n          'zIndex':'1001',\n          'top':(opts.filmstrip_position=='bottom'?'-'+(10+pointer_width)+'px':opts.frame_height+'px'),\n          'left':((opts.frame_width/2)-10)+'px'\n        });\n      }\n\n      //If the filmstrip is animating, move the strip to the middle third\n      if(slide_method=='strip') {\n        j_filmstrip.css('left','-'+((opts.frame_width+frame_margin)*item_count)+'px');\n        iterator = item_count;\n      }\n      //If there's a link under the pointer, enable clicking on the pointer\n      if($('a',j_frames[iterator])[0]) {\n        j_pointer.click(function(){\n          var a = $('a',j_frames[iterator]).eq(0);\n          if(a.attr('target')=='_blank') {window.open(a.attr('href'));}\n          else {location.href = a.attr('href');}\n        });\n      }\n\n      //Add navigation buttons\n      $('<img />').addClass('nav-next').attr('src',img_path+opts.nav_theme+'/next.png').appendTo(j_gallery).css({\n        'position':'absolute',\n        'cursor':'pointer',\n        'top':(opts.filmstrip_position=='top'?0:opts.panel_height)+frame_margin_top+((opts.frame_height-22)/2)+'px',\n        'right':(gallery_width/2)-(wrapper_width/2)-10-22+'px'\n      }).click(showNextItem);\n      $('<img />').addClass('nav-prev').attr('src',img_path+opts.nav_theme+'/prev.png').appendTo(j_gallery).css({\n        'position':'absolute',\n        'cursor':'pointer',\n        'top':(opts.filmstrip_position=='top'?0:opts.panel_height)+frame_margin_top+((opts.frame_height-22)/2)+'px',\n        'left':(gallery_width/2)-(wrapper_width/2)-10-22+'px'\n      }).click(showPrevItem);\n    };\n\n    //Check mouse to see if it is within the borders of the panel\n    //More reliable than 'mouseover' event when elements overlay the panel\n    function mouseIsOverPanels(x,y) {\n      var pos = getPos(j_gallery[0]);\n      var top = pos.top;\n      var left = pos.left;\n      return x > left && x < left+opts.panel_width && y > top && y < top+opts.panel_height;\n    };\n\n/************************************************/\n/*  Main Plugin Code              */\n/************************************************/\n    return this.each(function() {\n      j_gallery = $(this);\n      //Determine path between current page and filmstrip images\n      //Scan script tags and look for path to GalleryView plugin\n      $('script').each(function(i){\n        var s = $(this);\n        if(s.attr('src') && s.attr('src').match(/jquery\\.galleryview/)){\n          img_path = s.attr('src').split('jquery.galleryview')[0]+'themes/';\n        }\n      });\n\n      //Hide gallery to prevent Flash of Unstyled Content (FoUC) in IE\n      j_gallery.css('visibility','hidden');\n\n      //Assign elements to variables for reuse\n      j_filmstrip = $('.filmstrip',j_gallery);\n      j_frames = $('li',j_filmstrip);\n      j_panels = $('.panel',j_gallery);\n\n      id = j_gallery.attr('id');\n\n      has_panels = j_panels.length > 0;\n      has_filmstrip = j_frames.length > 0;\n\n      if(!has_panels) opts.panel_height = 0;\n\n      //Number of frames in filmstrip\n      item_count = has_panels?j_panels.length:j_frames.length;\n\n      //Number of frames that can display within the screen's width\n      //64 = width of block for navigation button * 2\n      //5 = minimum frame margin\n      strip_size = has_panels?Math.floor((opts.panel_width-64)/(opts.frame_width+frame_margin)):Math.min(item_count,opts.filmstrip_size);\n\n\n      /************************************************/\n      /*  Determine transition method for filmstrip  */\n      /************************************************/\n          //If more items than strip size, slide filmstrip\n          //Otherwise, slide pointer\n          if(strip_size >= item_count) {\n            slide_method = 'pointer';\n            strip_size = item_count;\n          }\n          else {slide_method = 'strip';}\n\n      /************************************************/\n      /*  Determine dimensions of various elements  */\n      /************************************************/\n\n          //Width of gallery block\n          gallery_width = has_panels?opts.panel_width:(strip_size*(opts.frame_width+frame_margin))-frame_margin+64;\n\n          //Height of gallery block = screen + filmstrip + captions (optional)\n          gallery_height = (has_panels?opts.panel_height:0)+(has_filmstrip?opts.frame_height+frame_margin_top+(opts.show_captions?frame_caption_size:frame_margin_top):0);\n\n          //Width of filmstrip\n          if(slide_method == 'pointer') {strip_width = (opts.frame_width*item_count)+(frame_margin*(item_count));}\n          else {strip_width = (opts.frame_width*item_count*3)+(frame_margin*(item_count*3));}\n\n          //Width of filmstrip wrapper (to hide overflow)\n          wrapper_width = ((strip_size*opts.frame_width)+((strip_size-1)*frame_margin));\n\n      /************************************************/\n      /*  Apply CSS Styles              */\n      /************************************************/\n          j_gallery.css({\n            'position':'relative',\n            'margin':'0',\n            'background':opts.background_color,\n            'border':opts.border,\n            'width':gallery_width+'px',\n            'height':gallery_height+'px'\n          });\n\n      /************************************************/\n      /*  Build filmstrip and/or panels        */\n      /************************************************/\n          if(has_filmstrip) {\n            buildFilmstrip();\n          }\n          if(has_panels) {\n            buildPanels();\n          }\n\n\n      /************************************************/\n      /*  Add events to various elements        */\n      /************************************************/\n          if(has_filmstrip) enableFrameClicking();\n\n\n\n            $().mousemove(function(e){\n              if(mouseIsOverPanels(e.pageX,e.pageY)) {\n                if(opts.pause_on_hover) {\n                  $(document).oneTime(500,\"animation_pause\",function(){\n                    $(document).stopTime(\"transition\");\n                    paused=true;\n                  });\n                }\n                if(has_panels && !has_filmstrip) {\n                  $('.nav-overlay').fadeIn('fast');\n                  $('.nav-next').fadeIn('fast');\n                  $('.nav-prev').fadeIn('fast');\n                }\n              } else {\n                if(opts.pause_on_hover) {\n                  $(document).stopTime(\"animation_pause\");\n                  if(paused) {\n                    $(document).everyTime(opts.transition_interval,\"transition\",function(){\n                      showNextItem();\n                    });\n                    paused = false;\n                  }\n                }\n                if(has_panels && !has_filmstrip) {\n                  $('.nav-overlay').fadeOut('fast');\n                  $('.nav-next').fadeOut('fast');\n                  $('.nav-prev').fadeOut('fast');\n                }\n              }\n            });\n\n\n      /************************************************/\n      /*  Initiate Automated Animation        */\n      /************************************************/\n          //Show the first panel\n          j_panels.eq(0).show();\n\n          //If we have more than one item, begin automated transitions\n          if(item_count > 1) {\n            $(document).everyTime(opts.transition_interval,\"transition\",function(){\n              showNextItem();\n            });\n          }\n\n          //Make gallery visible now that work is complete\n          j_gallery.css('visibility','visible');\n    });\n  };\n\n  $.fn.galleryView.defaults = {\n    panel_width: 400,\n    panel_height: 300,\n    frame_width: 80,\n    frame_height: 80,\n    filmstrip_size: 3,\n    overlay_height: 70,\n    overlay_font_size: '1em',\n    transition_speed: 400,\n    transition_interval: 6000,\n    overlay_opacity: 0.6,\n    overlay_color: 'black',\n    background_color: 'black',\n    overlay_text_color: 'white',\n    caption_text_color: 'white',\n    border: '1px solid black',\n    nav_theme: 'light',\n    easing: 'swing',\n    filmstrip_position: 'bottom',\n    overlay_position: 'bottom',\n    show_captions: false,\n    fade_panels: true,\n    pause_on_hover: false\n  };\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/static/jquery-galleryview-1.1/jquery.timers-1.1.2.js",
    "content": "﻿/**\n * jQuery.timers - Timer abstractions for jQuery\n * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)\n * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).\n * Date: 2009/02/08\n *\n * @author Blair Mitchelmore\n * @version 1.1.2\n *\n **/\n\njQuery.fn.extend({\n  everyTime: function(interval, label, fn, times, belay) {\n    return this.each(function() {\n      jQuery.timer.add(this, interval, label, fn, times, belay);\n    });\n  },\n  oneTime: function(interval, label, fn) {\n    return this.each(function() {\n      jQuery.timer.add(this, interval, label, fn, 1);\n    });\n  },\n  stopTime: function(label, fn) {\n    return this.each(function() {\n      jQuery.timer.remove(this, label, fn);\n    });\n  }\n});\n\njQuery.event.special\n\njQuery.extend({\n  timer: {\n    global: [],\n    guid: 1,\n    dataKey: \"jQuery.timer\",\n    regex: /^([0-9]+(?:\\.[0-9]*)?)\\s*(.*s)?$/,\n    powers: {\n      // Yeah this is major overkill...\n      'ms': 1,\n      'cs': 10,\n      'ds': 100,\n      's': 1000,\n      'das': 10000,\n      'hs': 100000,\n      'ks': 1000000\n    },\n    timeParse: function(value) {\n      if (value == undefined || value == null)\n        return null;\n      var result = this.regex.exec(jQuery.trim(value.toString()));\n      if (result[2]) {\n        var num = parseFloat(result[1]);\n        var mult = this.powers[result[2]] || 1;\n        return num * mult;\n      } else {\n        return value;\n      }\n    },\n    add: function(element, interval, label, fn, times, belay) {\n      var counter = 0;\n\n      if (jQuery.isFunction(label)) {\n        if (!times)\n          times = fn;\n        fn = label;\n        label = interval;\n      }\n\n      interval = jQuery.timer.timeParse(interval);\n\n      if (typeof interval != 'number' || isNaN(interval) || interval <= 0)\n        return;\n\n      if (times && times.constructor != Number) {\n        belay = !!times;\n        times = 0;\n      }\n\n      times = times || 0;\n      belay = belay || false;\n\n      var timers = jQuery.data(element, this.dataKey) || jQuery.data(element, this.dataKey, {});\n\n      if (!timers[label])\n        timers[label] = {};\n\n      fn.timerID = fn.timerID || this.guid++;\n\n      var handler = function() {\n        if (belay && this.inProgress)\n          return;\n        this.inProgress = true;\n        if ((++counter > times && times !== 0) || fn.call(element, counter) === false)\n          jQuery.timer.remove(element, label, fn);\n        this.inProgress = false;\n      };\n\n      handler.timerID = fn.timerID;\n\n      if (!timers[label][fn.timerID])\n        timers[label][fn.timerID] = window.setInterval(handler,interval);\n\n      this.global.push( element );\n\n    },\n    remove: function(element, label, fn) {\n      var timers = jQuery.data(element, this.dataKey), ret;\n\n      if ( timers ) {\n\n        if (!label) {\n          for ( label in timers )\n            this.remove(element, label, fn);\n        } else if ( timers[label] ) {\n          if ( fn ) {\n            if ( fn.timerID ) {\n              window.clearInterval(timers[label][fn.timerID]);\n              delete timers[label][fn.timerID];\n            }\n          } else {\n            for ( var fn in timers[label] ) {\n              window.clearInterval(timers[label][fn]);\n              delete timers[label][fn];\n            }\n          }\n\n          for ( ret in timers[label] ) break;\n          if ( !ret ) {\n            ret = null;\n            delete timers[label];\n          }\n        }\n\n        for ( ret in timers ) break;\n        if ( !ret )\n          jQuery.removeData(element, this.dataKey);\n      }\n    }\n  }\n});\n\njQuery(window).bind(\"unload\", function() {\n  jQuery.each(jQuery.timer.global, function(index, item) {\n    jQuery.timer.remove(item);\n  });\n});\n"
  },
  {
    "path": "public/javascripts/static/jquery.easing.1.3.js",
    "content": "/*\n * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/\n *\n * Uses the built in easing capabilities added In jQuery 1.1\n * to offer multiple easing options\n *\n * TERMS OF USE - jQuery Easing\n *\n * Open source under the BSD License.\n *\n * Copyright © 2008 George McGinley Smith\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * Redistributions of source code must retain the above copyright notice, this list of\n * conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, this list\n * of conditions and the following disclaimer in the documentation and/or other materials\n * provided with the distribution.\n *\n * Neither the name of the author nor the names of contributors may be used to endorse\n * or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n*/\n\n// t: current time, b: begInnIng value, c: change In value, d: duration\njQuery.easing['jswing'] = jQuery.easing['swing'];\n\njQuery.extend( jQuery.easing,\n{\n  def: 'easeOutQuad',\n  swing: function (x, t, b, c, d) {\n    //alert(jQuery.easing.default);\n    return jQuery.easing[jQuery.easing.def](x, t, b, c, d);\n  },\n  easeInQuad: function (x, t, b, c, d) {\n    return c*(t/=d)*t + b;\n  },\n  easeOutQuad: function (x, t, b, c, d) {\n    return -c *(t/=d)*(t-2) + b;\n  },\n  easeInOutQuad: function (x, t, b, c, d) {\n    if ((t/=d/2) < 1) return c/2*t*t + b;\n    return -c/2 * ((--t)*(t-2) - 1) + b;\n  },\n  easeInCubic: function (x, t, b, c, d) {\n    return c*(t/=d)*t*t + b;\n  },\n  easeOutCubic: function (x, t, b, c, d) {\n    return c*((t=t/d-1)*t*t + 1) + b;\n  },\n  easeInOutCubic: function (x, t, b, c, d) {\n    if ((t/=d/2) < 1) return c/2*t*t*t + b;\n    return c/2*((t-=2)*t*t + 2) + b;\n  },\n  easeInQuart: function (x, t, b, c, d) {\n    return c*(t/=d)*t*t*t + b;\n  },\n  easeOutQuart: function (x, t, b, c, d) {\n    return -c * ((t=t/d-1)*t*t*t - 1) + b;\n  },\n  easeInOutQuart: function (x, t, b, c, d) {\n    if ((t/=d/2) < 1) return c/2*t*t*t*t + b;\n    return -c/2 * ((t-=2)*t*t*t - 2) + b;\n  },\n  easeInQuint: function (x, t, b, c, d) {\n    return c*(t/=d)*t*t*t*t + b;\n  },\n  easeOutQuint: function (x, t, b, c, d) {\n    return c*((t=t/d-1)*t*t*t*t + 1) + b;\n  },\n  easeInOutQuint: function (x, t, b, c, d) {\n    if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;\n    return c/2*((t-=2)*t*t*t*t + 2) + b;\n  },\n  easeInSine: function (x, t, b, c, d) {\n    return -c * Math.cos(t/d * (Math.PI/2)) + c + b;\n  },\n  easeOutSine: function (x, t, b, c, d) {\n    return c * Math.sin(t/d * (Math.PI/2)) + b;\n  },\n  easeInOutSine: function (x, t, b, c, d) {\n    return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;\n  },\n  easeInExpo: function (x, t, b, c, d) {\n    return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;\n  },\n  easeOutExpo: function (x, t, b, c, d) {\n    return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;\n  },\n  easeInOutExpo: function (x, t, b, c, d) {\n    if (t==0) return b;\n    if (t==d) return b+c;\n    if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;\n    return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;\n  },\n  easeInCirc: function (x, t, b, c, d) {\n    return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;\n  },\n  easeOutCirc: function (x, t, b, c, d) {\n    return c * Math.sqrt(1 - (t=t/d-1)*t) + b;\n  },\n  easeInOutCirc: function (x, t, b, c, d) {\n    if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;\n    return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;\n  },\n  easeInElastic: function (x, t, b, c, d) {\n    var s=1.70158;var p=0;var a=c;\n    if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;\n    if (a < Math.abs(c)) { a=c; var s=p/4; }\n    else var s = p/(2*Math.PI) * Math.asin (c/a);\n    return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;\n  },\n  easeOutElastic: function (x, t, b, c, d) {\n    var s=1.70158;var p=0;var a=c;\n    if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;\n    if (a < Math.abs(c)) { a=c; var s=p/4; }\n    else var s = p/(2*Math.PI) * Math.asin (c/a);\n    return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;\n  },\n  easeInOutElastic: function (x, t, b, c, d) {\n    var s=1.70158;var p=0;var a=c;\n    if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);\n    if (a < Math.abs(c)) { a=c; var s=p/4; }\n    else var s = p/(2*Math.PI) * Math.asin (c/a);\n    if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;\n    return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;\n  },\n  easeInBack: function (x, t, b, c, d, s) {\n    if (s == undefined) s = 1.70158;\n    return c*(t/=d)*t*((s+1)*t - s) + b;\n  },\n  easeOutBack: function (x, t, b, c, d, s) {\n    if (s == undefined) s = 1.70158;\n    return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;\n  },\n  easeInOutBack: function (x, t, b, c, d, s) {\n    if (s == undefined) s = 1.70158;\n    if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;\n    return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;\n  },\n  easeInBounce: function (x, t, b, c, d) {\n    return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;\n  },\n  easeOutBounce: function (x, t, b, c, d) {\n    if ((t/=d) < (1/2.75)) {\n      return c*(7.5625*t*t) + b;\n    } else if (t < (2/2.75)) {\n      return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;\n    } else if (t < (2.5/2.75)) {\n      return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;\n    } else {\n      return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;\n    }\n  },\n  easeInOutBounce: function (x, t, b, c, d) {\n    if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;\n    return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;\n  }\n});\n\n/*\n *\n * TERMS OF USE - EASING EQUATIONS\n *\n * Open source under the BSD License.\n *\n * Copyright © 2001 Robert Penner\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * Redistributions of source code must retain the above copyright notice, this list of\n * conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice, this list\n * of conditions and the following disclaimer in the documentation and/or other materials\n * provided with the distribution.\n *\n * Neither the name of the author nor the names of contributors may be used to endorse\n * or promote products derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n */\n"
  },
  {
    "path": "public/javascripts/static/jquery.scroll.pack.js",
    "content": "/*-----------------------\n* jQuery Plugin: Scroll to Top\n* by Craig Wilson, Ph.Creative http://www.ph-creative.com\n*\n* Copyright (c) 2009 Ph.Creative Ltd.\n* Licensed under the MIT License http://www.opensource.org/licenses/mit-license.php\n*\n* Description: Adds an unobtrusive \"Scroll to Top\" link to your page with smooth scrolling.\n* For usage instructions and version updates to go http://blog.ph-creative.com/post/jquery-plugin-scroll-to-top-v3.aspx\n*\n* Version: 3.0, 29/10/2009\n-----------------------*/\n$(function(){$.fn.scrollToTop=function(options){if(options.speed){var speed=options.speed;}else{var speed=\"slow\";}if(options.ease){var ease=options.ease;}else{var ease=\"jswing\";}if(options.start){var start=options.start;}else{var start=\"0\";}var scrollDiv=$(this);$(this).hide().removeAttr(\"href\");if($(window).scrollTop()>start){$(this).fadeIn(\"slow\");}$(window).scroll(function(){if($(window).scrollTop()>start){$(scrollDiv).fadeIn(\"slow\");}else{$(scrollDiv).fadeOut(\"slow\");}});$(this).click(function(event){$(\"html, body\").animate({scrollTop:\"0px\"},speed,ease);});}});\n"
  },
  {
    "path": "public/javascripts/static/jquery.send.js",
    "content": "jQuery(document).ready(function(){\n\n  $('#contact-form').submit(function(){\n\n    var action = $(this).attr('action');\n\n    $(\"#message\").slideUp(750,function() {\n    $('#message').hide();\n\n     $('#contact-submit')\n      .after('<img src=\"/images/ajax-loader.gif\" class=\"loader\" />')\n      .attr('disabled','disabled');\n\n    $.post(action, {\n      name: $('#name').val(),\n      email: $('#email').val(),\n      website: $('#website').val(),\n      phone: $('#phone').val(),\n      subject: $('#subject').val(),\n      comments: $('#comments').val(),\n      verify: $('#verify').val()\n    },\n      function(data){\n        document.getElementById('message').innerHTML = data;\n        $('#message').slideDown('slow');\n        $('#contact-form img.loader').fadeOut('slow',function(){$(this).remove()});\n        $('#contact-form #contact-submit').attr('disabled','');\n        if(data.match('success') != null) $('#contact-form').slideUp('slow');\n\n      }\n    );\n\n    });\n\n    return false;\n\n  });\n\n});\n"
  },
  {
    "path": "public/javascripts/static/superfish.js",
    "content": "\n/*\n * Superfish v1.4.8 - jQuery menu widget\n * Copyright (c) 2008 Joel Birch\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n *\n * CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt\n */\n\n;(function($){\n  $.fn.superfish = function(op){\n\n    var sf = $.fn.superfish,\n      c = sf.c,\n      $arrow = $(['<span class=\"',c.arrowClass,'\"> &#187;</span>'].join('')),\n      over = function(){\n        var $$ = $(this), menu = getMenu($$);\n        clearTimeout(menu.sfTimer);\n        $$.showSuperfishUl().siblings().hideSuperfishUl();\n      },\n      out = function(){\n        var $$ = $(this), menu = getMenu($$), o = sf.op;\n        clearTimeout(menu.sfTimer);\n        menu.sfTimer=setTimeout(function(){\n          o.retainPath=($.inArray($$[0],o.$path)>-1);\n          $$.hideSuperfishUl();\n          if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length<1){over.call(o.$path);}\n        },o.delay);\n      },\n      getMenu = function($menu){\n        var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0];\n        sf.op = sf.o[menu.serial];\n        return menu;\n      },\n      addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); };\n\n    return this.each(function() {\n      var s = this.serial = sf.o.length;\n      var o = $.extend({},sf.defaults,op);\n      o.$path = $('li.'+o.pathClass,this).slice(0,o.pathLevels).each(function(){\n        $(this).addClass([o.hoverClass,c.bcClass].join(' '))\n          .filter('li:has(ul)').removeClass(o.pathClass);\n      });\n      sf.o[s] = sf.op = o;\n\n      $('li:has(ul)',this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).each(function() {\n        if (o.autoArrows) addArrow( $('>a:first-child',this) );\n      })\n      .not('.'+c.bcClass)\n        .hideSuperfishUl();\n\n      var $a = $('a',this);\n      $a.each(function(i){\n        var $li = $a.eq(i).parents('li');\n        $a.eq(i).focus(function(){over.call($li);}).blur(function(){out.call($li);});\n      });\n      o.onInit.call(this);\n\n    }).each(function() {\n      var menuClasses = [c.menuClass];\n      if (sf.op.dropShadows  && !($.browser.msie && $.browser.version < 7)) menuClasses.push(c.shadowClass);\n      $(this).addClass(menuClasses.join(' '));\n    });\n  };\n\n  var sf = $.fn.superfish;\n  sf.o = [];\n  sf.op = {};\n  sf.IE7fix = function(){\n    var o = sf.op;\n    if ($.browser.msie && $.browser.version > 6 && o.dropShadows && o.animation.opacity!=undefined)\n      this.toggleClass(sf.c.shadowClass+'-off');\n    };\n  sf.c = {\n    bcClass     : 'sf-breadcrumb',\n    menuClass   : 'sf-js-enabled',\n    anchorClass : 'sf-with-ul',\n    arrowClass  : 'sf-sub-indicator',\n    shadowClass : 'sf-shadow'\n  };\n  sf.defaults = {\n    hoverClass  : 'sfHover',\n    pathClass  : 'overideThisToUse',\n    pathLevels  : 1,\n    delay    : 800,\n    animation  : {opacity:'show'},\n    speed    : 'normal',\n    autoArrows  : true,\n    dropShadows : true,\n    disableHI  : false,    // true disables hoverIntent detection\n    onInit    : function(){}, // callback functions\n    onBeforeShow: function(){},\n    onShow    : function(){},\n    onHide    : function(){}\n  };\n  $.fn.extend({\n    hideSuperfishUl : function(){\n      var o = sf.op,\n        not = (o.retainPath===true) ? o.$path : '';\n      o.retainPath = false;\n      var $ul = $(['li.',o.hoverClass].join(''),this).add(this).not(not).removeClass(o.hoverClass)\n          .find('>ul').hide().css('visibility','hidden');\n      o.onHide.call($ul);\n      return this;\n    },\n    showSuperfishUl : function(){\n      var o = sf.op,\n        sh = sf.c.shadowClass+'-off',\n        $ul = this.addClass(o.hoverClass)\n          .find('>ul:hidden').css('visibility','visible');\n      sf.IE7fix.call($ul);\n      o.onBeforeShow.call($ul);\n      $ul.animate(o.animation,o.speed,function(){ sf.IE7fix.call($ul); o.onShow.call($ul); });\n      return this;\n    }\n  });\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/store.js",
    "content": "var store = (function(){\n  var api = {},\n    win = window,\n    doc = win.document,\n    localStorageName = 'localStorage',\n    globalStorageName = 'globalStorage',\n    storage\n\n  api.set = function(key, value) {}\n  api.get = function(key) {}\n  api.remove = function(key) {}\n  api.clear = function() {}\n\n  if (localStorageName in win && win[localStorageName]) {\n    storage = win[localStorageName]\n    api.set = function(key, val) { storage[key] = val }\n    api.get = function(key) { return storage[key] }\n    api.remove = function(key) { delete storage[key] }\n    api.clear = function() { storage.clear() }\n  } else if (globalStorageName in win && win[globalStorageName]) {\n    storage = win[globalStorageName][win.location.hostname]\n    api.set = function(key, val) { storage[key] = val }\n    api.get = function(key) { return storage[key] && storage[key].value }\n    api.remove = function(key) { delete storage[key] }\n    api.clear = function() { for (var key in storage ) { delete storage[key] } }\n  } else if (doc.documentElement.addBehavior) {\n    function createStorage() {\n      storage = doc.body.appendChild(doc.createElement('div'))\n      storage.style.display = 'none'\n      // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx\n      // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx\n      storage.addBehavior('#default#userData')\n      storage.load(localStorageName)\n    }\n    api.set = function(key, val) {\n      if (!storage) { createStorage() }\n      storage.setAttribute(key, val)\n      storage.save(localStorageName)\n    }\n    api.get = function(key) {\n      if (!storage) { createStorage() }\n      return storage.getAttribute(key)\n    }\n    api.remove = function(key) {\n      if (!storage) { createStorage() }\n      storage.removeAttribute(key)\n      storage.save(localStorageName)\n    }\n    api.clear = function() {\n      if (!storage) { createStorage() }\n      var attributes = storage.XMLDocument.documentElement.attributes;\n      storage.load(localStorageName)\n      for (var i=0, attr; attr = attributes[i]; i++) {\n        storage.removeAttribute(attr.name)\n      }\n      storage.save(localStorageName)\n    }\n  }\n\n  return api\n})()\n"
  },
  {
    "path": "public/javascripts/superfish.js",
    "content": "\n/*\n * Superfish v1.4.8 - jQuery menu widget\n * Copyright (c) 2008 Joel Birch\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n *\n * CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt\n */\n\n;(function($){\n  $.fn.superfish = function(op){\n\n    var sf = $.fn.superfish,\n      c = sf.c,\n      $arrow = $(['<span class=\"',c.arrowClass,'\"> &#187;</span>'].join('')),\n      over = function(){\n        var $$ = $(this), menu = getMenu($$);\n        clearTimeout(menu.sfTimer);\n        $$.showSuperfishUl().siblings().hideSuperfishUl();\n      },\n      out = function(){\n        var $$ = $(this), menu = getMenu($$), o = sf.op;\n        clearTimeout(menu.sfTimer);\n        menu.sfTimer=setTimeout(function(){\n          o.retainPath=($.inArray($$[0],o.$path)>-1);\n          $$.hideSuperfishUl();\n          if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length<1){over.call(o.$path);}\n        },o.delay);\n      },\n      getMenu = function($menu){\n        var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0];\n        sf.op = sf.o[menu.serial];\n        return menu;\n      },\n      addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); };\n\n    return this.each(function() {\n      var s = this.serial = sf.o.length;\n      var o = $.extend({},sf.defaults,op);\n      o.$path = $('li.'+o.pathClass,this).slice(0,o.pathLevels).each(function(){\n        $(this).addClass([o.hoverClass,c.bcClass].join(' '))\n          .filter('li:has(ul)').removeClass(o.pathClass);\n      });\n      sf.o[s] = sf.op = o;\n\n      $('li:has(ul)',this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).each(function() {\n        if (o.autoArrows) addArrow( $('>a:first-child',this) );\n      })\n      .not('.'+c.bcClass)\n        .hideSuperfishUl();\n\n      var $a = $('a',this);\n      $a.each(function(i){\n        var $li = $a.eq(i).parents('li');\n        $a.eq(i).focus(function(){over.call($li);}).blur(function(){out.call($li);});\n      });\n      o.onInit.call(this);\n\n    }).each(function() {\n      var menuClasses = [c.menuClass];\n      if (sf.op.dropShadows  && !($.browser.msie && $.browser.version < 7)) menuClasses.push(c.shadowClass);\n      $(this).addClass(menuClasses.join(' '));\n    });\n  };\n\n  var sf = $.fn.superfish;\n  sf.o = [];\n  sf.op = {};\n  sf.IE7fix = function(){\n    var o = sf.op;\n    if ($.browser.msie && $.browser.version > 6 && o.dropShadows && o.animation.opacity!=undefined)\n      this.toggleClass(sf.c.shadowClass+'-off');\n    };\n  sf.c = {\n    bcClass     : 'sf-breadcrumb',\n    menuClass   : 'sf-js-enabled',\n    anchorClass : 'sf-with-ul',\n    arrowClass  : 'sf-sub-indicator',\n    shadowClass : 'sf-shadow'\n  };\n  sf.defaults = {\n    hoverClass  : 'sfHover',\n    pathClass  : 'overideThisToUse',\n    pathLevels  : 1,\n    delay    : 800,\n    animation  : {opacity:'show'},\n    speed    : 'normal',\n    autoArrows  : true,\n    dropShadows : true,\n    disableHI  : false,    // true disables hoverIntent detection\n    onInit    : function(){}, // callback functions\n    onBeforeShow: function(){},\n    onShow    : function(){},\n    onHide    : function(){}\n  };\n  $.fn.extend({\n    hideSuperfishUl : function(){\n      var o = sf.op,\n        not = (o.retainPath===true) ? o.$path : '';\n      o.retainPath = false;\n      var $ul = $(['li.',o.hoverClass].join(''),this).add(this).not(not).removeClass(o.hoverClass)\n          .find('>ul').hide().css('visibility','hidden');\n      o.onHide.call($ul);\n      return this;\n    },\n    showSuperfishUl : function(){\n      var o = sf.op,\n        sh = sf.c.shadowClass+'-off',\n        $ul = this.addClass(o.hoverClass)\n          .find('>ul:hidden').css('visibility','visible');\n      sf.IE7fix.call($ul);\n      o.onBeforeShow.call($ul);\n      $ul.animate(o.animation,o.speed,function(){ sf.IE7fix.call($ul); o.onShow.call($ul); });\n      return this;\n    }\n  });\n\n})(jQuery);\n"
  },
  {
    "path": "public/javascripts/supersubs.js",
    "content": "\n/*\n * Supersubs v0.2b - jQuery plugin\n * Copyright (c) 2008 Joel Birch\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n *\n *\n * This plugin automatically adjusts submenu widths of suckerfish-style menus to that of\n * their longest list item children. If you use this, please expect bugs and report them\n * to the jQuery Google Group with the word 'Superfish' in the subject line.\n *\n */\n\n;(function($){ // $ will refer to jQuery within this closure\n\n  $.fn.supersubs = function(options){\n    var opts = $.extend({}, $.fn.supersubs.defaults, options);\n    // return original object to support chaining\n    return this.each(function() {\n      // cache selections\n      var $$ = $(this);\n      // support metadata\n      var o = $.meta ? $.extend({}, opts, $$.data()) : opts;\n      // get the font size of menu.\n      // .css('fontSize') returns various results cross-browser, so measure an em dash instead\n      var fontsize = $('<li id=\"menu-fontsize\">&#8212;</li>').css({\n        'padding' : 0,\n        'position' : 'absolute',\n        'top' : '-999em',\n        'width' : 'auto'\n      }).appendTo($$).width(); //clientWidth is faster, but was incorrect here\n      // remove em dash\n      $('#menu-fontsize').remove();\n      // cache all ul elements\n      $ULs = $$.find('ul');\n      // loop through each ul in menu\n      $ULs.each(function(i) {\n        // cache this ul\n        var $ul = $ULs.eq(i);\n        // get all (li) children of this ul\n        var $LIs = $ul.children();\n        // get all anchor grand-children\n        var $As = $LIs.children('a');\n        // force content to one line and save current float property\n        var liFloat = $LIs.css('white-space','nowrap').css('float');\n        // remove width restrictions and floats so elements remain vertically stacked\n        var emWidth = $ul.add($LIs).add($As).css({\n          'float' : 'none',\n          'width'  : 'auto'\n        })\n        // this ul will now be shrink-wrapped to longest li due to position:absolute\n        // so save its width as ems. Clientwidth is 2 times faster than .width() - thanks Dan Switzer\n        .end().end()[0].clientWidth / fontsize;\n        // add more width to ensure lines don't turn over at certain sizes in various browsers\n        emWidth += o.extraWidth;\n        // restrict to at least minWidth and at most maxWidth\n        if (emWidth > o.maxWidth)    { emWidth = o.maxWidth; }\n        else if (emWidth < o.minWidth)  { emWidth = o.minWidth; }\n        emWidth += 'em';\n        // set ul to width in ems\n        $ul.css('width',emWidth);\n        // restore li floats to avoid IE bugs\n        // set li width to full width of this ul\n        // revert white-space to normal\n        $LIs.css({\n          'float' : liFloat,\n          'width' : '100%',\n          'white-space' : 'normal'\n        })\n        // update offset position of descendant ul to reflect new width of parent\n        .each(function(){\n          var $childUl = $('>ul',this);\n          var offsetDirection = $childUl.css('left')!==undefined ? 'left' : 'right';\n          $childUl.css(offsetDirection,emWidth);\n        });\n      });\n\n    });\n  };\n  // expose defaults\n  $.fn.supersubs.defaults = {\n    minWidth    : 9,    // requires em unit.\n    maxWidth    : 25,    // requires em unit.\n    extraWidth    : 0      // extra width can ensure lines don't sometimes turn over due to slight browser differences in how they round-off values\n  };\n\n})(jQuery); // plugin code ends\n"
  },
  {
    "path": "public/javascripts/textile-editor-config.js",
    "content": "var teButtons = TextileEditor.buttons;\n\nteButtons.push(new TextileEditorButton('ed_strong',      'bold.png',          '*',   '*',  'b', 'Bold','s'));\nteButtons.push(new TextileEditorButton('ed_emphasis',    'italic.png',        '_',   '_',  'i', 'Italicize','s'));\nteButtons.push(new TextileEditorButton('ed_underline',  'underline.png',     '+',   '+',  'u', 'Underline','s'));\nteButtons.push(new TextileEditorButton('ed_strike',     'strikethrough.png', '-',   '-',  's', 'Strikethrough','s'));\nteButtons.push(new TextileEditorButton('ed_ol',          'list_numbers.png',  ' # ', '\\n', ',', 'Numbered List'));\nteButtons.push(new TextileEditorButton('ed_ul',          'list_bullets.png',  ' * ', '\\n', '.', 'Bulleted List'));\nteButtons.push(new TextileEditorButton('ed_p',          'paragraph.png',     'p',   '\\n', 'p', 'Paragraph'));\nteButtons.push(new TextileEditorButton('ed_h1',          'h1.png',            'h1',  '\\n', '1', 'Header 1'));\nteButtons.push(new TextileEditorButton('ed_h2',          'h2.png',            'h2',  '\\n', '2', 'Header 2'));\nteButtons.push(new TextileEditorButton('ed_h3',          'h3.png',            'h3',  '\\n', '3', 'Header 3'));\nteButtons.push(new TextileEditorButton('ed_h4',          'h4.png',            'h4',  '\\n', '4', 'Header 4'));\nteButtons.push(new TextileEditorButton('ed_block',       'blockquote.png',    'bq',  '\\n', 'q', 'Blockquote'));\nteButtons.push(new TextileEditorButton('ed_outdent',     'outdent.png',       ')',   '\\n', ']', 'Outdent'));\nteButtons.push(new TextileEditorButton('ed_indent',      'indent.png',        '(',   '\\n', '[', 'Indent'));\nteButtons.push(new TextileEditorButton('ed_justifyl',    'left.png',          '<',   '\\n', 'l', 'Left Justify'));\nteButtons.push(new TextileEditorButton('ed_justifyc',    'center.png',        '=',   '\\n', 'e', 'Center Text'));\nteButtons.push(new TextileEditorButton('ed_justifyr',    'right.png',         '>',   '\\n', 'r', 'Right Justify'));\nteButtons.push(new TextileEditorButton('ed_justify',     'justify.png',       '<>',  '\\n', 'j', 'Justify'));\nteButtons.push('&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"http://en.wikipedia.org/wiki/Textile_%28markup_language%29#Textile_syntax_examples\" target=\"_blank\">Help</a>');\n\n// teButtons.push(new TextileEditorButton('ed_code','code','@','@','c','Code'));\n"
  },
  {
    "path": "public/javascripts/textile-editor.js",
    "content": "/*\n\nTextile Editor v0.2\ncreated by: dave olsen, wvu web services\ncreated on: march 17, 2007\nproject page: slateinfo.blogs.wvu.edu\n\ninspired by:\n - Patrick Woods, http://www.hakjoon.com/code/38/textile-quicktags-redirect &\n - Alex King, http://alexking.org/projects/js-quicktags\n\nfeatures:\n - supports: IE7, FF2, Safari2\n - ability to use \"simple\" vs. \"extended\" editor\n - supports all block elements in textile except footnote\n - supports all block modifier elements in textile\n - supports simple ordered and unordered lists\n - supports most of the phrase modifiers, very easy to add the missing ones\n - supports multiple-paragraph modification\n - can have multiple \"editors\" on one page, access key use in this environment is flaky\n - access key support\n - select text to add and remove tags, selection stays highlighted\n - seamlessly change between tags and modifiers\n - doesn't need to be in the body onload tag\n - can supply your own, custom IDs for the editor to be drawn around\n\ntodo:\n - a clean way of providing image and link inserts\n - get the selection to properly show in IE\n\nmore on textile:\n - Textism, http://www.textism.com/tools/textile/index.php\n - Textile Reference, http://hobix.com/textile/\n\n*/\n\n// Define Button Object\nfunction TextileEditorButton(id, display, tagStart, tagEnd, access, title, sve, open) {\n  this.id = id;       // used to name the toolbar button\n  this.display = display;   // label on button\n  this.tagStart = tagStart;   // open tag\n  this.tagEnd = tagEnd;   // close tag\n  this.access = access;   // set to -1 if tag does not need to be closed\n  this.title = title;     // sets the title attribute of the button to give 'tool tips'\n  this.sve = sve;       // sve = simple vs. extended. add an 's' to make it show up in the simple toolbar\n  this.open = open;     // set to -1 if tag does not need to be closed\n  this.standard = true;  // this is a standard button\n  // this.framework = 'prototype'; // the JS framework used\n}\n\nfunction TextileEditorButtonSeparator(sve) {\n  this.separator = true;\n  this.sve = sve;\n}\n\nvar TextileEditor = function() {};\nTextileEditor.buttons = new Array();\nTextileEditor.Methods = {\n  // class methods\n\n  // create the toolbar (edToolbar)\n  initialize: function(canvas, view) {\n    var toolbar = document.createElement(\"div\");\n    toolbar.id = \"textile-toolbar-\" + canvas;\n    toolbar.className = 'textile-toolbar';\n    this.canvas = document.getElementById(canvas);\n    this.canvas.parentNode.insertBefore(toolbar, this.canvas);\n    this.openTags = new Array();\n\n    // Create the local Button array by assigning theButtons array to edButtons\n    var edButtons = new Array();\n    edButtons = this.buttons;\n\n    var standardButtons = new Array();\n    for(var i = 0; i < edButtons.length; i++) {\n      var thisButton = this.prepareButton(edButtons[i]);\n      if (view == 's') {\n        if (edButtons[i].sve == 's') {\n          toolbar.appendChild(thisButton);\n          standardButtons.push(thisButton);\n        }\n      } else {\n        if (typeof thisButton == 'string') {\n          toolbar.innerHTML += thisButton;\n        } else {\n          toolbar.appendChild(thisButton);\n          standardButtons.push(thisButton);\n        }\n      }\n    } // end for\n\n    var te = this;\n    var buttons = toolbar.getElementsByTagName('button');\n    for(var i = 0; i < buttons.length; i++) {\n    //$A(toolbar.getElementsByTagName('button')).each(function(button) {\n      if (!buttons[i].onclick) {\n        buttons[i].onclick = function() { te.insertTag(this); return false; }\n      } // end if\n\n      buttons[i].tagStart = buttons[i].getAttribute('tagStart');\n      buttons[i].tagEnd = buttons[i].getAttribute('tagEnd');\n      buttons[i].open = buttons[i].getAttribute('open');\n      buttons[i].textile_editor = te;\n      buttons[i].canvas = te.canvas;\n      // console.log(buttons[i].canvas);\n    //});\n    }\n  }, // end initialize\n\n  // draw individual buttons (edShowButton)\n  prepareButton: function(button) {\n    if (button.separator) {\n      var theButton = document.createElement('span');\n      theButton.className = 'ed_sep';\n      return theButton;\n    }\n\n    if (button.standard) {\n      var theButton = document.createElement(\"button\");\n      theButton.id = button.id;\n      theButton.setAttribute('class', 'standard');\n      theButton.setAttribute('tagStart', button.tagStart);\n      theButton.setAttribute('tagEnd', button.tagEnd);\n      theButton.setAttribute('open', button.open);\n\n      var img = document.createElement('img');\n      img.src = '/images/textile-editor/' + button.display;\n      theButton.appendChild(img);\n    } else {\n      return button;\n    } // end if !custom\n\n    theButton.accessKey = button.access;\n    theButton.title = button.title;\n    return theButton;\n  }, // end prepareButton\n\n  // if clicked, no selected text, tag not open highlight button\n  // (edAddTag)\n  addTag: function(button) {\n    if (button.tagEnd != '') {\n      this.openTags[this.openTags.length] = button;\n      //var el = document.getElementById(button.id);\n      //el.className = 'selected';\n      button.className = 'selected';\n    }\n  }, // end addTag\n\n  // if clicked, no selected text, tag open lowlight button\n  // (edRemoveTag)\n  removeTag: function(button) {\n    for (i = 0; i < this.openTags.length; i++) {\n      if (this.openTags[i] == button) {\n        this.openTags.splice(button, 1);\n        //var el = document.getElementById(button.id);\n        //el.className = 'unselected';\n        button.className = 'unselected';\n      }\n    }\n  }, // end removeTag\n\n  // see if there are open tags. for the remove tag bit...\n  // (edCheckOpenTags)\n  checkOpenTags: function(button) {\n    var tag = 0;\n    for (i = 0; i < this.openTags.length; i++) {\n      if (this.openTags[i] == button) {\n        tag++;\n      }\n    }\n    if (tag > 0) {\n      return true; // tag found\n    }\n    else {\n      return false; // tag not found\n    }\n  }, // end checkOpenTags\n\n  // insert the tag. this is the bulk of the code.\n  // (edInsertTag)\n  insertTag: function(button, tagStart, tagEnd) {\n    // console.log(button);\n    var myField = button.canvas;\n    myField.focus();\n\n    if (tagStart) {\n      button.tagStart = tagStart;\n      button.tagEnd = tagEnd ? tagEnd : '\\n';\n    }\n\n    var textSelected = false;\n    var finalText = '';\n    var FF = false;\n\n    // grab the text that's going to be manipulated, by browser\n    if (document.selection) { // IE support\n      sel = document.selection.createRange();\n\n      // set-up the text vars\n      var beginningText = '';\n      var followupText = '';\n      var selectedText = sel.text;\n\n      // check if text has been selected\n      if (sel.text.length > 0) {\n        textSelected = true;\n      }\n\n      // set-up newline regex's so we can swap tags across multiple paragraphs\n      var newlineReplaceRegexClean = /\\r\\n\\s\\n/g;\n      var newlineReplaceRegexDirty = '\\\\r\\\\n\\\\s\\\\n';\n      var newlineReplaceClean = '\\r\\n\\n';\n    }\n    else if (myField.selectionStart || myField.selectionStart == '0') { // MOZ/FF/NS/S support\n\n      // figure out cursor and selection positions\n      var startPos = myField.selectionStart;\n      var endPos = myField.selectionEnd;\n      var cursorPos = endPos;\n      var scrollTop = myField.scrollTop;\n      FF = true; // note that is is a FF/MOZ/NS/S browser\n\n      // set-up the text vars\n      var beginningText = myField.value.substring(0, startPos);\n      var followupText = myField.value.substring(endPos, myField.value.length);\n\n      // check if text has been selected\n      if (startPos != endPos) {\n        textSelected = true;\n        var selectedText = myField.value.substring(startPos, endPos);\n      }\n\n      // set-up newline regex's so we can swap tags across multiple paragraphs\n      var newlineReplaceRegexClean = /\\n\\n/g;\n      var newlineReplaceRegexDirty = '\\\\n\\\\n';\n      var newlineReplaceClean = '\\n\\n';\n    }\n\n\n    // if there is text that has been highlighted...\n    if (textSelected) {\n\n      // set-up some defaults for how to handle bad new line characters\n      var newlineStart = '';\n      var newlineStartPos = 0;\n      var newlineEnd = '';\n      var newlineEndPos = 0;\n      var newlineFollowup = '';\n\n      // set-up some defaults for how to handle placing the beginning and end of selection\n      var posDiffPos = 0;\n      var posDiffNeg = 0;\n      var mplier = 1;\n\n      // remove newline from the beginning of the selectedText.\n      if (selectedText.match(/^\\n/)) {\n        selectedText = selectedText.replace(/^\\n/,'');\n        newlineStart = '\\n';\n        newlineStartpos = 1;\n      }\n\n      // remove newline from the end of the selectedText.\n      if (selectedText.match(/\\n$/g)) {\n        selectedText = selectedText.replace(/\\n$/g,'');\n        newlineEnd = '\\n';\n        newlineEndPos = 1;\n      }\n\n      // remove space from the end of the selectedText.\n      // Fixes a bug that causes any browser running under Microsoft Internet Explorer\n      // to append an additional space before the closing element.\n      // *Bold text *here => *Bold text*\n      if (selectedText.match(/\\s$/g)) {\n        selectedText = selectedText.replace(/\\s$/g,'');\n        followupText = ' ';\n      }\n\n      // no clue, i'm sure it made sense at the time i wrote it\n      if (followupText.match(/^\\n/)) {\n        newlineFollowup = '';\n      }\n      else {\n        newlineFollowup = '\\n\\n';\n      }\n\n      // first off let's check if the user is trying to mess with lists\n      if ((button.tagStart == ' * ') || (button.tagStart == ' # ')) {\n\n        listItems = 0; // sets up a default to be able to properly manipulate final selection\n\n        // set-up all of the regex's\n        re_start = new RegExp('^ (\\\\*|\\\\#) ','g');\n        if (button.tagStart == ' # ') {\n          re_tag = new RegExp(' \\\\# ','g'); // because of JS regex stupidity i need an if/else to properly set it up, could have done it with a regex replace though\n        }\n        else {\n          re_tag = new RegExp(' \\\\* ','g');\n        }\n        re_replace = new RegExp(' (\\\\*|\\\\#) ','g');\n\n        // try to remove bullets in text copied from ms word **Mac Only!**\n        re_word_bullet_m_s = new RegExp('• ','g'); // mac/safari\n        re_word_bullet_m_f = new RegExp('∑ ','g'); // mac/firefox\n        selectedText = selectedText.replace(re_word_bullet_m_s,'').replace(re_word_bullet_m_f,'');\n\n        // if the selected text starts with one of the tags we're working with...\n        if (selectedText.match(re_start)) {\n\n          // if tag that begins the selection matches the one clicked, remove them all\n          if (selectedText.match(re_tag)) {\n            finalText = beginningText\n                    + newlineStart\n                    + selectedText.replace(re_replace,'')\n                    + newlineEnd\n                    + followupText;\n            if (matches = selectedText.match(/ (\\*|\\#) /g)) {\n              listItems = matches.length;\n            }\n            posDiffNeg = listItems*3; // how many list items were there because that's 3 spaces to remove from final selection\n          }\n\n          // else replace the current tag type with the selected tag type\n          else {\n            finalText = beginningText\n                    + newlineStart\n                    + selectedText.replace(re_replace,button.tagStart)\n                    + newlineEnd\n                    + followupText;\n          }\n        }\n\n        // else try to create the list type\n        // NOTE: the items in a list will only be replaced if a newline starts with some character, not a space\n        else {\n          finalText = beginningText\n                  + newlineStart\n                        + button.tagStart\n                  + selectedText.replace(newlineReplaceRegexClean,newlineReplaceClean + button.tagStart).replace(/\\n(\\S)/g,'\\n' + button.tagStart + '$1')\n                  + newlineEnd\n                  + followupText;\n          if (matches = selectedText.match(/\\n(\\S)/g)) {\n            listItems = matches.length;\n          }\n          posDiffPos = 3 + listItems*3;\n        }\n      }\n\n      // now lets look and see if the user is trying to muck with a block or block modifier\n      else if (button.tagStart.match(/^(h1|h2|h3|h4|h5|h6|bq|p|\\>|\\<\\>|\\<|\\=|\\(|\\))/g)) {\n\n        var insertTag = '';\n        var insertModifier = '';\n        var tagPartBlock = '';\n        var tagPartModifier = '';\n        var tagPartModifierOrig = ''; // ugly hack but it's late\n        var drawSwitch = '';\n        var captureIndentStart = false;\n        var captureListStart = false;\n        var periodAddition = '\\\\. ';\n        var periodAdditionClean = '. ';\n        var listItemsAddition = 0;\n\n        var re_list_items = new RegExp('(\\\\*+|\\\\#+)','g'); // need this regex later on when checking indentation of lists\n\n        var re_block_modifier = new RegExp('^(h1|h2|h3|h4|h5|h6|bq|p| [\\\\*]{1,} | [\\\\#]{1,} |)(\\\\>|\\\\<\\\\>|\\\\<|\\\\=|[\\\\(]{1,}|[\\\\)]{1,6}|)','g');\n        if (tagPartMatches = re_block_modifier.exec(selectedText)) {\n          tagPartBlock = tagPartMatches[1];\n          tagPartModifier = tagPartMatches[2];\n          tagPartModifierOrig = tagPartMatches[2];\n          tagPartModifierOrig = tagPartModifierOrig.replace(/\\(/g,\"\\\\(\");\n        }\n\n        // if tag already up is the same as the tag provided replace the whole tag\n        if (tagPartBlock == button.tagStart) {\n          insertTag  = tagPartBlock + tagPartModifierOrig; // use Orig because it's escaped for regex\n          drawSwitch = 0;\n        }\n        // else if let's check to add/remove block modifier\n        else if ((tagPartModifier == button.tagStart) || (newm = tagPartModifier.match(/[\\(]{2,}/g))) {\n          if ((button.tagStart == '(') || (button.tagStart == ')')) {\n            var indentLength = tagPartModifier.length;\n            if (button.tagStart == '(') {\n              indentLength = indentLength + 1;\n            }\n            else {\n              indentLength = indentLength - 1;\n            }\n            for (var i = 0; i < indentLength; i++) {\n              insertModifier = insertModifier + '(';\n            }\n            insertTag = tagPartBlock + insertModifier;\n          }\n          else {\n            if (button.tagStart == tagPartModifier) {\n              insertTag =  tagPartBlock;\n              } // going to rely on the default empty insertModifier\n            else {\n\n              if (button.tagStart.match(/(\\>|\\<\\>|\\<|\\=)/g)) {\n                insertTag = tagPartBlock + button.tagStart;\n              }\n              else {\n                insertTag = button.tagStart + tagPartModifier;\n              }\n            }\n\n          }\n          drawSwitch = 1;\n        }\n        // indentation of list items\n        else if (listPartMatches = re_list_items.exec(tagPartBlock)) {\n            var listTypeMatch = listPartMatches[1];\n            var indentLength = tagPartBlock.length - 2;\n            var listInsert = '';\n            if (button.tagStart == '(') {\n              indentLength = indentLength + 1;\n            }\n            else {\n              indentLength = indentLength - 1;\n            }\n            if (listTypeMatch.match(/[\\*]{1,}/g)) {\n              var listType = '*';\n              var listReplace = '\\\\*';\n            }\n            else {\n              var listType = '#';\n              var listReplace = '\\\\#';\n            }\n            for (var i = 0; i < indentLength; i++) {\n              listInsert = listInsert + listType;\n            }\n            if (listInsert != '') {\n              insertTag = ' ' + listInsert + ' ';\n            }\n            else {\n              insertTag = '';\n            }\n            tagPartBlock = tagPartBlock.replace(/(\\*|\\#)/g,listReplace);\n            drawSwitch = 1;\n            captureListStart = true;\n            periodAddition = '';\n            periodAdditionClean = '';\n            if (matches = selectedText.match(/\\n\\s/g)) {\n              listItemsAddition = matches.length;\n            }\n        }\n        // must be a block modification e.g. p>. to p<.\n        else {\n\n          // if this is a block modification/addition\n          if (button.tagStart.match(/(h1|h2|h3|h4|h5|h6|bq|p)/g)) {\n            if (tagPartBlock == '') {\n              drawSwitch = 2;\n            }\n            else {\n              drawSwitch = 1;\n            }\n\n            insertTag = button.tagStart + tagPartModifier;\n          }\n\n          // else this is a modifier modification/addition\n          else {\n            if ((tagPartModifier == '') && (tagPartBlock != '')) {\n              drawSwitch = 1;\n            }\n            else if (tagPartModifier == '') {\n              drawSwitch = 2;\n            }\n            else {\n              drawSwitch = 1;\n            }\n\n            // if no tag part block but a modifier we need at least the p tag\n            if (tagPartBlock == '') {\n              tagPartBlock = 'p';\n            }\n\n            //make sure to swap out outdent\n            if (button.tagStart == ')') {\n              tagPartModifier = '';\n            }\n            else {\n              tagPartModifier = button.tagStart;\n              captureIndentStart = true; // ugly hack to fix issue with proper selection handling\n            }\n\n            insertTag = tagPartBlock + tagPartModifier;\n          }\n        }\n\n        mplier = 0;\n        if (captureListStart || (tagPartModifier.match(/[\\(\\)]{1,}/g))) {\n          re_start = new RegExp(insertTag.escape + periodAddition,'g'); // for tags that mimic regex properties, parens + list tags\n        }\n        else {\n          re_start = new RegExp(insertTag + periodAddition,'g'); // for tags that don't, why i can't just escape everything i have no clue\n        }\n        re_old = new RegExp(tagPartBlock + tagPartModifierOrig + periodAddition,'g');\n        re_middle = new RegExp(newlineReplaceRegexDirty + insertTag.escape + periodAddition.escape,'g');\n        re_tag = new RegExp(insertTag.escape + periodAddition.escape,'g');\n\n        // *************************************************************************************************************************\n        // this is where everything gets swapped around or inserted, bullets and single options have their own if/else statements\n        // *************************************************************************************************************************\n        if ((drawSwitch == 0) || (drawSwitch == 1)) {\n          if (drawSwitch == 0) { // completely removing a tag\n            finalText = beginningText\n                    + newlineStart\n                    + selectedText.replace(re_start,'').replace(re_middle,newlineReplaceClean)\n                    + newlineEnd\n                    + followupText;\n            if (matches = selectedText.match(newlineReplaceRegexClean)) {\n              mplier = mplier + matches.length;\n            }\n            posDiffNeg = insertTag.length + 2 + (mplier*4);\n          }\n          else { // modifying a tag, though we do delete bullets here\n            finalText = beginningText\n                    + newlineStart\n                    + selectedText.replace(re_old,insertTag + periodAdditionClean)\n                    + newlineEnd\n                    + followupText;\n\n            if (matches = selectedText.match(newlineReplaceRegexClean)) {\n              mplier = mplier + matches.length;\n            }\n            // figure out the length of various elements to modify the selection position\n            if (captureIndentStart) { // need to double-check that this wasn't the first indent\n              tagPreviousLength = tagPartBlock.length;\n              tagCurrentLength = insertTag.length;\n            }\n            else if (captureListStart) { // if this is a list we're manipulating\n              if (button.tagStart == '(') { // if indenting\n                tagPreviousLength = listTypeMatch.length + 2;\n                tagCurrentLength = insertTag.length + listItemsAddition;\n              }\n              else if (insertTag.match(/(\\*|\\#)/g)) { // if removing but still has bullets\n                tagPreviousLength = insertTag.length + listItemsAddition;\n                tagCurrentLength = listTypeMatch.length;\n              }\n              else {  // if removing last bullet\n                tagPreviousLength = insertTag.length + listItemsAddition;\n                tagCurrentLength = listTypeMatch.length - (3*listItemsAddition) - 1;\n              }\n            }\n            else { // everything else\n              tagPreviousLength = tagPartBlock.length + tagPartModifier.length;\n              tagCurrentLength = insertTag.length;\n            }\n            if (tagCurrentLength > tagPreviousLength) {\n              posDiffPos = (tagCurrentLength - tagPreviousLength) + (mplier*(tagCurrentLength - tagPreviousLength));\n            }\n            else {\n              posDiffNeg = (tagPreviousLength - tagCurrentLength) + (mplier*(tagPreviousLength - tagCurrentLength));\n            }\n          }\n        }\n        else { // for adding tags other then bullets (have their own statement)\n          finalText = beginningText\n                  + newlineStart\n                        + insertTag + '. '\n                  + selectedText.replace(newlineReplaceRegexClean,button.tagEnd + '\\n' + insertTag + '. ')\n                  + newlineFollowup\n                  + newlineEnd\n                  + followupText;\n          if (matches = selectedText.match(newlineReplaceRegexClean)) {\n            mplier = mplier + matches.length;\n          }\n          posDiffPos = insertTag.length + 2 + (mplier*4);\n        }\n      }\n\n      // swap in and out the simple tags around a selection like bold\n      else {\n\n        mplier = 1; // the multiplier for the tag length\n        re_start = new RegExp('^\\\\' + button.tagStart,'g');\n        re_end =  new RegExp('\\\\' + button.tagEnd + '$','g');\n        re_middle = new RegExp('\\\\' + button.tagEnd + newlineReplaceRegexDirty + '\\\\' + button.tagStart,'g');\n        if (selectedText.match(re_start) && selectedText.match(re_end)) {\n          finalText = beginningText\n                  + newlineStart\n                  + selectedText.replace(re_start,'').replace(re_end,'').replace(re_middle,newlineReplaceClean)\n                  + newlineEnd\n                  + followupText;\n          if (matches = selectedText.match(newlineReplaceRegexClean)) {\n            mplier = mplier + matches.length;\n          }\n          posDiffNeg = button.tagStart.length*mplier + button.tagEnd.length*mplier;\n        }\n        else {\n          finalText = beginningText\n                  + newlineStart\n                        + button.tagStart\n                  + selectedText.replace(newlineReplaceRegexClean,button.tagEnd + newlineReplaceClean + button.tagStart)\n                  + button.tagEnd\n                  + newlineEnd\n                  + followupText;\n          if (matches = selectedText.match(newlineReplaceRegexClean)) {\n            mplier = mplier + matches.length;\n          }\n          posDiffPos = (button.tagStart.length*mplier) + (button.tagEnd.length*mplier);\n        }\n      }\n\n      cursorPos += button.tagStart.length + button.tagEnd.length;\n\n    }\n\n    // just swap in and out single values, e.g. someone clicks b they'll get a *\n    else {\n      var buttonStart = '';\n      var buttonEnd = '';\n      var re_p = new RegExp('(\\\\<|\\\\>|\\\\=|\\\\<\\\\>|\\\\(|\\\\))','g');\n      var re_h = new RegExp('^(h1|h2|h3|h4|h5|h6|p|bq)','g');\n      if (!this.checkOpenTags(button) || button.tagEnd == '') { // opening tag\n\n        if (button.tagStart.match(re_h)) {\n          buttonStart = button.tagStart + '. ';\n        }\n        else {\n          buttonStart = button.tagStart;\n        }\n        if (button.tagStart.match(re_p)) { // make sure that invoking block modifiers don't do anything\n          finalText = beginningText\n                     + followupText;\n          cursorPos = startPos;\n        }\n        else {\n          finalText = beginningText\n                      + buttonStart\n                      + followupText;\n          this.addTag(button);\n          cursorPos = startPos + buttonStart.length;\n        }\n\n      }\n      else {  // closing tag\n        if (button.tagStart.match(re_p)) {\n          buttonEnd = '\\n\\n';\n        }\n        else if (button.tagStart.match(re_h)) {\n          buttonEnd = '\\n\\n';\n        }\n        else {\n          buttonEnd = button.tagEnd\n        }\n        finalText = beginningText\n                    + button.tagEnd\n                    + followupText;\n        this.removeTag(button);\n        cursorPos = startPos + button.tagEnd.length;\n      }\n    }\n\n    // set the appropriate DOM value with the final text\n    if (FF == true) {\n      myField.value = finalText;\n      myField.scrollTop = scrollTop;\n    }\n    else {\n      sel.text = finalText;\n    }\n\n    // build up the selection capture, doesn't work in IE\n    if (textSelected) {\n      myField.selectionStart = startPos + newlineStartPos;\n      myField.selectionEnd = endPos + posDiffPos - posDiffNeg - newlineEndPos;\n      //alert('s: ' + myField.selectionStart + ' e: ' + myField.selectionEnd + ' sp: ' + startPos + ' ep: ' + endPos + ' pdp: ' + posDiffPos + ' pdn: ' + posDiffNeg)\n    }\n    else {\n      myField.selectionStart = cursorPos;\n      myField.selectionEnd = cursorPos;\n    }\n  } // end insertTag\n}; // end class\n\n// add class methods\n// Object.extend(TextileEditor, TextileEditor.Methods);\ndestination = TextileEditor\nsource = TextileEditor.Methods\nfor(var property in source) destination[property] = source[property];\n\ndocument.write('<script src=\"/javascripts/textile-editor-config.js\" type=\"text/javascript\"></script>');\n"
  },
  {
    "path": "public/maintenance/index.html",
    "content": "We are undergoing maintenance right now, please try again later.\n\nSorry!\n"
  },
  {
    "path": "public/stylesheets/bubbletip-IE.css",
    "content": "/*******************************/\n/******** bubbletip-IE *********/\n/*******************************/\n.bubbletip td.bt-topleft\n{\n  background-image: url(/images/bubbletip/bubbletip-TL-corner.png);\n  background-repeat: no-repeat;\n  background-position: 0px 0px;\n  background-attachment: scroll;\n}\n.bubbletip td.bt-top\n{\n  background: transparent url(/images/bubbletip/bubbletip-T.png) repeat-x scroll 0px 0px;\n}\n.bubbletip td.bt-topright\n{\n  background: transparent url(/images/bubbletip/bubbletip-TR-corner.png) no-repeat scroll 0px 0px;\n}\n.bubbletip td.bt-left-tail div.bt-left, .bubbletip td.bt-left\n{\n  background: transparent url(/images/bubbletip/bubbletip-L.png) repeat-y scroll 0px 0px;\n}\n.bubbletip td.bt-left-tail div.bt-left-tail\n{\n  background: transparent url(/images/bubbletip/bubbletip-L-tail.png) no-repeat scroll 0px 0px;\n}\n.bubbletip td.bt-right-tail div.bt-right, .bubbletip td.bt-right\n{\n  background: transparent url(/images/bubbletip/bubbletip-R.png) repeat-y scroll 0px 0px;\n}\n.bubbletip td.bt-right-tail div.bt-right-tail\n{\n  background: transparent url(/images/bubbletip/bubbletip-R-tail.png) no-repeat scroll 0px 0px;\n}\n.bubbletip td.bt-bottomleft\n{\n  background: transparent url(/images/bubbletip/bubbletip-BL-corner.png) no-repeat scroll 0px 0px;\n}\n.bubbletip td.bt-bottom\n{\n  background: transparent url(/images/bubbletip/bubbletip-B.png) repeat-x scroll 0px 0px;\n}\n.bubbletip td.bt-bottomright\n{\n  background: transparent url(/images/bubbletip/bubbletip-BR-corner.png) no-repeat scroll 0px 0px;\n}\n.bubbletip table.bt-top th\n{\n  background: transparent url(/images/bubbletip/bubbletip-T.png) repeat-x scroll 0px 0px;\n}\n.bubbletip table.bt-bottom th\n{\n  background: transparent url(/images/bubbletip/bubbletip-B.png) repeat-x scroll 0px 0px;\n}\n.bubbletip table.bt-top td div\n{\n  background: transparent url(/images/bubbletip/bubbletip-T-tail.png) no-repeat scroll 0px 0px;\n}\n.bubbletip table.bt-bottom td div\n{\n  background: transparent url(/images/bubbletip/bubbletip-B-tail.png) no-repeat scroll 0px 0px;\n}\n/*******************************/\n\n"
  },
  {
    "path": "public/stylesheets/bubbletip.css",
    "content": "/*******************************/\n/********* bubbletip ***********/\n/*******************************/\n\n.bubbletip\n{\n  position: absolute;\n  z-index: 50;\n  border-collapse: collapse;\n  width:auto;\n  height:auto;\n}\n\n.bubbletip td{\n  border:none;\n}\n\n.bubbletip td.bt-topleft\n{\n  background: transparent url(/images/bubbletip/bubbletip.png) no-repeat scroll 0px 0px;\n  height: 33px;\n  width: 33px;\n}\n.bubbletip td.bt-top\n{\n/*  background:url(/images/bg_gradient_comments_hover.gif) #FFF repeat-x scroll 10px 0px;  */\n  background: transparent url(/images/bubbletip/bubbletip-T-B.png) repeat-x scroll 0px 0px;\n  height: 33px;\n}\n.bubbletip td.bt-topright\n{\n  background: transparent url(/images/bubbletip/bubbletip.png) no-repeat scroll -73px 0px;\n  height: 33px;\n  width: 33px;\n}\n.bubbletip td.bt-left-tail div.bt-left, .bubbletip td.bt-left\n{\n  background: transparent url(/images/bubbletip/bubbletip-L-R.png) repeat-y scroll 0px 0px;\n  width: 33px;\n}\n.bubbletip td.bt-left-tail div.bt-left-tail\n{\n  background: transparent url(/images/bubbletip/bubbletip.png) no-repeat scroll 0px -33px;\n  width: 33px;\n  height: 40px;\n}\n.bubbletip td.bt-right-tail div.bt-right, .bubbletip td.bt-right\n{\n  background: transparent url(/images/bubbletip/bubbletip-L-R.png) repeat-y scroll -33px 0px;\n  width: 33px;\n}\n.bubbletip td.bt-right-tail div.bt-right-tail\n{\n  background: transparent url(/images/bubbletip/bubbletip.png) no-repeat scroll -73px -33px;\n  width: 33px;\n  height: 40px;\n}\n.bubbletip td.bt-bottomleft\n{\n  background: transparent url(/images/bubbletip/bubbletip.png) no-repeat scroll 0px -73px;\n  height: 33px;\n  width: 33px;\n}\n.bubbletip td.bt-bottom\n{\n  background: transparent url(/images/bubbletip/bubbletip-T-B.png) repeat-x scroll 0px -33px;\n  height: 33px;\n}\n.bubbletip td.bt-bottomright\n{\n  background: transparent url(/images/bubbletip/bubbletip.png) no-repeat scroll -73px -73px;\n  height: 33px;\n  width: 33px;\n}\n.bubbletip table.bt-top, .bubbletip table.bt-bottom\n{\n  width: 100%;\n}\n.bubbletip table.bt-top th\n{\n  width: 50%;\n  background: transparent url(/images/bubbletip/bubbletip-T-B.png) repeat-x scroll 0px 0px;\n}\n.bubbletip table.bt-bottom th\n{\n  width: 50%;\n  background: transparent url(/images/bubbletip/bubbletip-T-B.png) repeat-x scroll 0px -33px;\n}\n.bubbletip table.bt-top td div\n{\n  background: transparent url(/images/bubbletip/bubbletip.png) no-repeat scroll -33px 0px;\n  width: 40px;\n  height: 33px;\n}\n.bubbletip table.bt-bottom td div\n{\n  background: transparent url(/images/bubbletip/bubbletip.png) no-repeat scroll -33px -73px;\n  width: 40px;\n  height: 33px;\n}\n.bubbletip td.bt-content\n{\n  background-color: #fff;\n  vertical-align: middle;\n}\n/*******************************/\n\n.bubbletip tr, td {\nword-wrap: normal;\nborder-collapse:collapse;\nmargin:0px;\npadding:0px;\n}\n\n.bubbletip td {\npadding:0px;\nvertical-align:top;\n}\n\n.bubbletip table\n{\n  margin:0px;\n}\n\n"
  },
  {
    "path": "public/stylesheets/calendar.css",
    "content": "/* The main calendar widget.  DIV containing a table. */\n\nimg.calendar-trigger {\n    cursor: pointer;\n    vertical-align: middle;\n    margin-left: 4px;\n}\n\ndiv.calendar { position: relative; z-index: 30;}\n\n.calendar, .calendar table {\n  border: 1px solid #556;\n  font-size: 11px;\n  color: #000;\n  cursor: default;\n  background: #fafbfc;\n  font-family: tahoma,verdana,sans-serif;\n}\n\n/* Header part -- contains navigation buttons and day names. */\n\n.calendar .button { /* \"<<\", \"<\", \">\", \">>\" buttons have this class */\n  text-align: center;    /* They are the navigation buttons */\n  padding: 2px;          /* Make the buttons seem like they're pressing */\n}\n\n.calendar .nav {\n  background: #467aa7;\n}\n\n.calendar thead .title { /* This holds the current \"month, year\" */\n  font-weight: bold;      /* Pressing it will take you to the current date */\n  text-align: center;\n  background: #fff;\n  color: #000;\n  padding: 2px;\n}\n\n.calendar thead .headrow { /* Row <TR> containing navigation buttons */\n  background: #467aa7;\n  color: #fff;\n}\n\n.calendar thead .daynames { /* Row <TR> containing the day names */\n  background: #bdf;\n}\n\n.calendar thead .name { /* Cells <TD> containing the day names */\n  border-bottom: 1px solid #556;\n  padding: 2px;\n  text-align: center;\n  color: #000;\n}\n\n.calendar thead .weekend { /* How a weekend day name shows in header */\n  color: #a66;\n}\n\n.calendar thead .hilite { /* How do the buttons in header appear when hover */\n  background-color: #80b0da;\n  color: #000;\n  padding: 1px;\n}\n\n.calendar thead .active { /* Active (pressed) buttons in header */\n  background-color: #77c;\n  padding: 2px 0px 0px 2px;\n}\n\n/* The body part -- contains all the days in month. */\n\n.calendar tbody .day { /* Cells <TD> containing month days dates */\n  width: 2em;\n  color: #456;\n  text-align: right;\n  padding: 2px 4px 2px 2px;\n}\n.calendar tbody .day.othermonth {\n  font-size: 80%;\n  color: #bbb;\n}\n.calendar tbody .day.othermonth.oweekend {\n  color: #fbb;\n}\n\n.calendar table .wn {\n  padding: 2px 3px 2px 2px;\n  border-right: 1px solid #000;\n  background: #bdf;\n}\n\n.calendar tbody .rowhilite td {\n  background: #def;\n}\n\n.calendar tbody .rowhilite td.wn {\n  background: #80b0da;\n}\n\n.calendar tbody td.hilite { /* Hovered cells <TD> */\n  background: #80b0da;\n  padding: 1px 3px 1px 1px;\n  border: 1px solid #bbb;\n}\n\n.calendar tbody td.active { /* Active (pressed) cells <TD> */\n  background: #cde;\n  padding: 2px 2px 0px 2px;\n}\n\n.calendar tbody td.selected { /* Cell showing today date */\n  font-weight: bold;\n  border: 1px solid #000;\n  padding: 1px 3px 1px 1px;\n  background: #fff;\n  color: #000;\n}\n\n.calendar tbody td.weekend { /* Cells showing weekend days */\n  color: #a66;\n}\n\n.calendar tbody td.today { /* Cell showing selected date */\n  font-weight: bold;\n  color: #f00;\n}\n\n.calendar tbody .disabled { color: #999; }\n\n.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */\n  visibility: hidden;\n}\n\n.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */\n  display: none;\n}\n\n/* The footer part -- status bar and \"Close\" button */\n\n.calendar tfoot .footrow { /* The <TR> in footer (only one right now) */\n  text-align: center;\n  background: #556;\n  color: #fff;\n}\n\n.calendar tfoot .ttip { /* Tooltip (status bar) cell <TD> */\n  background: #fff;\n  color: #445;\n  border-top: 1px solid #556;\n  padding: 1px;\n}\n\n.calendar tfoot .hilite { /* Hover style for buttons in footer */\n  background: #aaf;\n  border: 1px solid #04f;\n  color: #000;\n  padding: 1px;\n}\n\n.calendar tfoot .active { /* Active (pressed) style for buttons in footer */\n  background: #77c;\n  padding: 2px 0px 0px 2px;\n}\n\n/* Combo boxes (menus that display months/years for direct selection) */\n\n.calendar .combo {\n  position: absolute;\n  display: none;\n  top: 0px;\n  left: 0px;\n  width: 4em;\n  cursor: default;\n  border: 1px solid #655;\n  background: #def;\n  color: #000;\n  font-size: 90%;\n  z-index: 100;\n}\n\n.calendar .combo .label,\n.calendar .combo .label-IEfix {\n  text-align: center;\n  padding: 1px;\n}\n\n.calendar .combo .label-IEfix {\n  width: 4em;\n}\n\n.calendar .combo .hilite {\n  background: #acf;\n}\n\n.calendar .combo .active {\n  border-top: 1px solid #46a;\n  border-bottom: 1px solid #46a;\n  background: #eef;\n  font-weight: bold;\n}\n\n.calendar td.time {\n  border-top: 1px solid #000;\n  padding: 1px 0px;\n  text-align: center;\n  background-color: #f4f0e8;\n}\n\n.calendar td.time .hour,\n.calendar td.time .minute,\n.calendar td.time .ampm {\n  padding: 0px 3px 0px 4px;\n  border: 1px solid #889;\n  font-weight: bold;\n  background-color: #fff;\n}\n\n.calendar td.time .ampm {\n  text-align: center;\n}\n\n.calendar td.time .colon {\n  padding: 0px 2px 0px 3px;\n  font-weight: bold;\n}\n\n.calendar td.time span.hilite {\n  border-color: #000;\n  background-color: #667;\n  color: #fff;\n}\n\n.calendar td.time span.active {\n  border-color: #f00;\n  background-color: #000;\n  color: #0f0;\n}\n"
  },
  {
    "path": "public/stylesheets/context_menu.css",
    "content": "#context-menu { position: absolute; z-index: 40; font-size: 0.9em;}\n\n#context-menu ul, #context-menu li, #context-menu a {\n  display:block;\n  margin:0;\n  padding:0;\n  border:0;\n}\n\n#context-menu ul {\n  width:150px;\n  border-top:1px solid #ddd;\n  border-left:1px solid #ddd;\n  border-bottom:1px solid #777;\n  border-right:1px solid #777;\n  background:white;\n  list-style:none;\n}\n\n#context-menu li {\n  position:relative;\n  padding:1px;\n  z-index:39;\n}\n#context-menu li.folder ul { position:absolute; left:168px; /* IE6 */ top:-2px; }\n#context-menu li.folder>ul { left:148px; }\n\n#context-menu.reverse-y li.folder>ul { top:auto; bottom:0; }\n#context-menu.reverse-x li.folder ul { left:auto; right:168px; /* IE6 */ }\n#context-menu.reverse-x li.folder>ul { right:148px; }\n\n#context-menu a {\n  border:1px solid white;\n  text-decoration:none !important;\n  background-repeat: no-repeat;\n  background-position: 1px 50%;\n  padding: 1px 0px 1px 20px;\n  width:100%; /* IE */\n}\n#context-menu li>a { width:auto; } /* others */\n#context-menu a.disabled, #context-menu a.disabled:hover {color: #ccc;}\n#context-menu li a.submenu { background:url(\"../images/sub.gif\") right no-repeat; }\n#context-menu a:hover { border-color:gray; background-color:#eee; color:#2A5685; }\n#context-menu li.folder a:hover { background-color:#eee; }\n#context-menu li.folder:hover { z-index:40; }\n#context-menu ul ul, #context-menu  li:hover ul ul { display:none; }\n#context-menu li:hover ul, #context-menu li:hover li:hover ul {  display:block; }\n\n/* selected element */\n.context-menu-selection { background-color:#507AAA !important; color:#f8f8f8 !important; }\n.context-menu-selection a, .context-menu-selection a:hover { color:#f8f8f8 !important; }\n.context-menu-selection:hover { background-color:#507AAA !important; color:#f8f8f8  !important; }\n"
  },
  {
    "path": "public/stylesheets/csshover.htc",
    "content": "<attach event=\"ondocumentready\" handler=\"parseStylesheets\" />\n<script>\n/**\n *\tWhatever:hover - V1.42.060206 - hover & active\n *\t------------------------------------------------------------\n *\t(c) 2005 - Peter Nederlof\n *\tPeterned - http://www.xs4all.nl/~peterned/\n *\tLicense  - http://creativecommons.org/licenses/LGPL/2.1/\n *\n *\tWhatever:hover is free software; you can redistribute it and/or\n *\tmodify it under the terms of the GNU Lesser General Public\n *\tLicense as published by the Free Software Foundation; either\n *\tversion 2.1 of the License, or (at your option) any later version.\n *\n *\tWhatever:hover is distributed in the hope that it will be useful,\n *\tbut WITHOUT ANY WARRANTY; without even the implied warranty of\n *\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n *\tLesser General Public License for more details.\n *\n *\tCredits and thanks to:\n *\tArnoud Berendsen, Martin Reurings, Robert Hanson\n *\n *\thowto: body { behavior:url(\"csshover.htc\"); }\n *\t------------------------------------------------------------\n */\n\nvar csshoverReg = /(^|\\s)(([^a]([^ ]+)?)|(a([^#.][^ ]+)+)):(hover|active)/i,\ncurrentSheet, doc = window.document, hoverEvents = [], activators = {\n\tonhover:{on:'onmouseover', off:'onmouseout'},\n\tonactive:{on:'onmousedown', off:'onmouseup'}\n}\n\nfunction parseStylesheets() {\n\tif(!/MSIE (5|6)/.test(navigator.userAgent)) return;\n\twindow.attachEvent('onunload', unhookHoverEvents);\n\tvar sheets = doc.styleSheets, l = sheets.length;\n\tfor(var i=0; i<l; i++) \n\t\tparseStylesheet(sheets[i]);\n}\n\tfunction parseStylesheet(sheet) {\n\t\tif(sheet.imports) {\n\t\t\ttry {\n\t\t\t\tvar imports = sheet.imports, l = imports.length;\n\t\t\t\tfor(var i=0; i<l; i++) parseStylesheet(sheet.imports[i]);\n\t\t\t} catch(securityException){}\n\t\t}\n\n\t\ttry {\n\t\t\tvar rules = (currentSheet = sheet).rules, l = rules.length;\n\t\t\tfor(var j=0; j<l; j++) parseCSSRule(rules[j]);\n\t\t} catch(securityException){}\n\t}\n\n\tfunction parseCSSRule(rule) {\n\t\tvar select = rule.selectorText, style = rule.style.cssText;\n\t\tif(!csshoverReg.test(select) || !style) return;\n\n\t\tvar pseudo = select.replace(/[^:]+:([a-z-]+).*/i, 'on$1');\n\t\tvar newSelect = select.replace(/(\\.([a-z0-9_-]+):[a-z]+)|(:[a-z]+)/gi, '.$2' + pseudo);\n\t\tvar className = (/\\.([a-z0-9_-]*on(hover|active))/i).exec(newSelect)[1];\n\t\tvar affected = select.replace(/:(hover|active).*$/, '');\n\t\tvar elements = getElementsBySelect(affected);\n\t\tif(elements.length == 0) return;\n\n\t\tcurrentSheet.addRule(newSelect, style);\n\t\tfor(var i=0; i<elements.length; i++)\n\t\t\tnew HoverElement(elements[i], className, activators[pseudo]);\n\t}\n\nfunction HoverElement(node, className, events) {\n\tif(!node.hovers) node.hovers = {};\n\tif(node.hovers[className]) return;\n\tnode.hovers[className] = true;\n\thookHoverEvent(node, events.on, function() { node.className += ' ' + className; });\n\thookHoverEvent(node, events.off, function() { node.className = node.className.replace(new RegExp('\\\\s+'+className, 'g'),''); });\n}\n\tfunction hookHoverEvent(node, type, handler) {\n\t\tnode.attachEvent(type, handler);\n\t\thoverEvents[hoverEvents.length] = { \n\t\t\tnode:node, type:type, handler:handler \n\t\t};\n\t}\n\n\tfunction unhookHoverEvents() {\n\t\tfor(var e,i=0; i<hoverEvents.length; i++) {\n\t\t\te = hoverEvents[i]; \n\t\t\te.node.detachEvent(e.type, e.handler);\n\t\t}\n\t}\n\nfunction getElementsBySelect(rule) {\n\tvar parts, nodes = [doc];\n\tparts = rule.split(' ');\n\tfor(var i=0; i<parts.length; i++) {\n\t\tnodes = getSelectedNodes(parts[i], nodes);\n\t}\treturn nodes;\n}\n\tfunction getSelectedNodes(select, elements) {\n\t\tvar result, node, nodes = [];\n\t\tvar identify = (/\\#([a-z0-9_-]+)/i).exec(select);\n\t\tif(identify) {\n\t\t\tvar element = doc.getElementById(identify[1]);\n\t\t\treturn element? [element]:nodes;\n\t\t}\n\t\t\n\t\tvar classname = (/\\.([a-z0-9_-]+)/i).exec(select);\n\t\tvar tagName = select.replace(/(\\.|\\#|\\:)[a-z0-9_-]+/i, '');\n\t\tvar classReg = classname? new RegExp('\\\\b' + classname[1] + '\\\\b'):false;\n\t\tfor(var i=0; i<elements.length; i++) {\n\t\t\tresult = tagName? elements[i].all.tags(tagName):elements[i].all; \n\t\t\tfor(var j=0; j<result.length; j++) {\n\t\t\t\tnode = result[j];\n\t\t\t\tif(classReg && !classReg.test(node.className)) continue;\n\t\t\t\tnodes[nodes.length] = node;\n\t\t\t}\n\t\t}\t\n\t\t\n\t\treturn nodes;\n\t}\n\nwindow.parseStylesheets = parseStylesheets;\n</script>"
  },
  {
    "path": "public/stylesheets/custom.css",
    "content": "/*\nTemplate:  GT-502\nFile:    custom.css - Use this file to add any custom styles you need\n\nIf you add styles to this template, be sure to include it in your template files.\n*/\n"
  },
  {
    "path": "public/stylesheets/dashboard.css",
    "content": "#main-menu { margin: 0 24px; width: 100%;}\n\nhtml {\n  background-color: #fff;\n}\n\n\ntable, tr, td {\nborder-collapse:collapse;\nmargin:0px;\npadding:0px;\n}\n\ntable td {\npadding:0px;\n}\n\nbody, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td {\nmargin:0;\npadding:0;\n/*overflow: hidden;*/\n}\n\n/*html>body #content { min-height: 200px; overflow: auto; height: 600px; } */\n\nhtml > body #content {\n  min-height: 200px;\n  overflow-y: hidden;\n  overflow-x: visible;\n}\n\nbody  {\n  overflow: hidden;\n}\n\n#main {\n  font-size:1em;\n  line-height:20px;\n  margin:0px 0px 0px 0px;\n  max-width: 9999999px;\n  padding-top: 0px;\n/*  float: left;*/\n  width:100%;\n}\n\n#main_table{\n  margin-top: 13px;\n  float: left;\n}\n\n#panels {\n  background-color: #fff;\n  margin-top: -5px;\n}\n\n.panel {\n  padding: 0px 7px;\n  margin: 0px;\n  border:medium none;\n  min-width:225px;\n  max-width:800px;\n  vertical-align:top;\n}\n\n\n.panelTitle {\nfont-size:1.1em;\nline-height:22px;\nvertical-aling:center;\n}\n\n.list {\n  background-color:#e1eaee;\n  border-color:-moz-use-text-color #6E6E6E #6E6E6E;\n  border-style:none solid solid;\n  border-width:medium 1px 1px;\n  min-height:100px;\n  height:100%;\n}\n\n.items {\n  height:100%;\n  overflow-x:hidden;\n  overflow-y:auto;\n  position:relative;\n  color:#000000;\n}\n\n.help_question_mark{\n   cursor:pointer;\n  margin-bottom: 0px;\n  margin-left: 2px;\n  margin-top: 2px;\n}\n\n\n.layout {\nborder-collapse:separate;\nborder-spacing:16px 0;\n}\n\n.panelHeader {\n  -moz-background-clip:border;\n  -moz-background-inline-policy:continuous;\n  -moz-background-origin:padding;\n  background:transparent url(/images/panel_head_bg.png) repeat-x scroll center top;\n  color:#eee;\n  overflow:hidden;\n}\n\n.panelHeaderLeft {\n  -moz-background-clip:border;\n  -moz-background-inline-policy:continuous;\n  -moz-background-origin:padding;\n  background:transparent url(/images/panel_head.png) no-repeat scroll left top;\n  float:left;\n}\n\n.panelHeaderRight {\n  -moz-background-clip:border;\n  -moz-background-inline-policy:continuous;\n  -moz-background-origin:padding;\n  background:transparent url(/images/panel_head.png) no-repeat scroll right top;\n  float:right;\n}\n\n.panelHeaderLeft, .panelHeaderRight {\n  width:5px;\n}\n\n.panelHeader, .panelHeaderLeft, .panelHeaderRight {\n  height:1.85em;\n}\n\n\n/*Content*/\n\n/*#content a.panelLink {\n  color:#333333;\n  vertical-align:middle;\n}\n\n#content a, #content a:visited, #content a:hover {\n  color:#0957A4;\n  font-weight:normal;\n  text-decoration:none;\n  min-height:300px;\n}*/\n\n#content {\n  font-family:Arial,Verdana,sans-serif;\n  margin: 0px 0px 0px 0px;\n  padding: 6px 10px 0px 6px;\n  border: none;\n/*  overflow-y: none;*/\n}\n\n\n#footer {\n  background-color:#FFFFFF;\n  border:0 none;\n  clear:left;\n  color:#666666;\n  font-size:9px;\n  margin:0px 0px 0px 0px;\n  padding-bottom:3px;\n  text-align:center;\n  padding-top:0px;\n}\n\n.panelLink.closePanelLoading {\n  -moz-background-clip:border;\n  -moz-background-inline-policy:continuous;\n  -moz-background-origin:padding;\n  background:transparent url(/images/ajax-loader.gif) no-repeat scroll 0 0px;\n  height: 20px;\n  margin-right: 0px;\n  width: 14px;\n}\n\n.panelLink.closePanel {\n  -moz-background-clip:border;\n  -moz-background-inline-policy:continuous;\n  -moz-background-origin:padding;\n  background:transparent url(/images/close_panel.png) no-repeat scroll 0 0px;\n  height: 20px;\n  margin-right: 0px;\n  margin-top: 5px;\n  width: 14px;\n}\n\n.panelLink {\n  float:right;\n  font-size:0.8em;\n  margin-right:8px;\n  margin-top:2px;\n}\n\n.endOfList {\n-moz-background-clip:border;\n-moz-background-inline-policy:continuous;\n-moz-background-origin:padding;\n/*background:#B5BDC1 url(/images/dropzone_repeating_pattern.png) repeat-x scroll center top;*/\n/*background: url(/images/drop_repeat_blue.png) repeat-x scroll center top;*/\nbackground: url(/images/dropzone_repeating_pattern.png) repeat-x scroll center top;\nborder-top:1px solid #6E6E6E;\ncolor:#666666;\nheight:7em;\npadding-top:0px;\n}\n\n.hoverable:hover {\nbackground-image:url(/images/hover_gradient.gif);\nbackground-repeat:repeat-y;\n}\n\n\n.new {\n  background-color:#fff;\n}\n\n.deployed .itemCollapsedHeader {\n  font-weight:bold;\n}\n\n.committed {\n  background-color:#fff;\n/*  background-color:#EFEFEF;*/\n  /*background-color:#D8EECE;*/\n}\n\n.open {\n  background-color:#fff;\n/*  background-color:#eee;*/\n/*  background-color: #e2eaee;*/\n/*  background-color:#F6EABB;*/\n}\n\n.canceled {\n  background-color:#fff;\n/*  background-color:#999999;  */\n}\n\n.estimate {\n  background-color:#F6EABB; /*e1d6ad D5CA9F FFF8DC;*/\n}\n\n.accepted{\n  background-color:#ccc;\n}\n\n.done, .finished, .delivered {\n  background-color:#ccc;\n/*  background-color:#e2eaee;*/\n/*  background-color:#E7F3FA;*/\n}\n\n\n.stateChangeButton, .disabledStateChangeButton {\n  margin-left:4px;\n  vertical-align:bottom;\n}\n.disabledStateChangeButton {\n  opacity:0.6;\n}\n.stateChangeButton {\n  cursor:pointer;\n  width:auto;\n}\n\n.toggleExpandedButton {\n  cursor:pointer;\n  float:left;\n  margin-right:4px;\n  padding-top:2px;\n  vertical-align:middle;\n}\n\n.storyTypeIcon, .flyoverIcon, .storyPoints {\n  vertical-align:middle;\n  padding: 0px 0px 0px 2px;\n}\n\n.left {\n  float:left;\n}\n\n.right {\n  float:right;\n}\n\n.clear {\n  clear:both;\n}\n\n.bold {\n  font-weight:bold;\n}\n\n.centeredTable {height: 300px; width: 100%;}\n.centeredTable td {vertical-align:middle; width:100%; height:200px;}\n.centeredTable tr {text-align:center; width:100%; height:100%;}\n\n\n\n\n/*Dashboard*/\n\n/*#loading, #fancy-loading{\n  padding-left: 26px;\n  background-position: 0% 40%;\n  background-repeat: no-repeat;\n  background-image: url(../images/loading.gif);\n  font-style: italic;\n}\n*/\n\n\n.dashboard-button{\n  float: left;\n  margin-left: 3px;\n  margin-top: 9px;\n  font-weight: bold;\n}\n\n.dashboard-button-panel{\n  float: right;\n  margin-left: 2px;\n  margin-top: 0px;\n  font-weight: normal;\n}\n\n\n.watermark{\n  color: #7C7B76;\n  font-style: italic;\n  font-family: 'Lucida Grande';\n}\n\n.dice{\n  padding-right: 2px;\n  cursor: pointer;\n}\n\n\n.searchField  {\nfloat:right;\nmargin-right:23px;\nmargin-top:2px;\n}\n\n.searchField input {\n  padding: 0px;\n}\n\n.searchField img {\n  height:1.5em;\n}\n\n.searchField td.field {\n  background: url(/images/search_middle.png) repeat-x scroll center top transparent;\n}\n\n.searchField #searchString {\nborder:0 none;\n}\n\n.searchField td {\nvertical-align:top;\n}\n\n.panel_notice {\nbackground-color: crimson;\n}\n\n.panel_notice .gt-Iih {\nbackground:none;\ncolor:white;\ncursor:default;\npadding-left:0;\npadding-right:0;\n}\n\n/*.filter-search {\nfloat:right;\nfont-size: 0.8em;\n}\n*/\n/*.fast-search {\nmargin-right:5px;\nfloat:right;\nfont-size: 0.8em;\n}\n*/\n.filtered-message {\n/*text-align:center;*/\nwidth:100%;\n/*align:center;*/\nfloat:left;\n}\n\n#comment_prompt {\n  width:320px;\n}\n\n.comment_prompt_text {\n  width:280px;\n}\n\n/***** Ajax indicator ******/\n#ajax-indicator {\nposition: absolute; /* fixed not supported by IE */\nbackground-image: url(/images/ajax-loader.gif);\n/*background-image: url(/images/loading.gif);*/\nbackground-repeat: no-repeat;\nbackground-color: transparent;\nborder: 0px;\ntop:0;\nleft:0;\npadding:1px;\nz-index:100;\nheight:16px;\nwidth:16px;\nfilter:alpha(opacity=100);\nopacity: 1;\n}\n\nhtml>body #ajax-indicator { position: fixed; }\n\n#ajax-indicator span {\n  display:none;\n}\n\n/********** Overriding base ************/\n.gt-bd { padding: 0px;}\n\n/******** Overriding buttons ************/\nform input[type=submit] {\n  float: none;\n  display: inline;\n  height: auto;\n  line-height: normal;\n  font-weight: normal;\n  color: #000;\n  text-decoration: none!important;\n  font-size: normal;\n  border: normal;\n  padding: 0;\n  margin: 0;\n  width: auto;\n  background-image: none;\n  border: 1px solid #006;\n  border-color: #FFFFFF #666666 #666666 #FFFFFF;\n/*  background-color: #ECE9D8; */\n  background-color: #fff;\n  border-style: solid;\n}\n\ninput[type=submit] {\n  border: 1px solid #006;\n  border-color: #FFFFFF #666666 #666666 #FFFFFF;\n  background-color: #ECE9D8 border-style: solid;\n}\n\n/*form input[type=submit]{\n  background: none; border: none; margin: 0; padding: 0; font-size: 0; line-height: 0; width: auto; overflow: visible;\n}\n\nbutton { background: none; border: none; margin: 0; padding: 0; font-size: 0; line-height: 0; width: auto; overflow: visible; }\n*/\n\ntable.dash_key{\n\n}\ntable.dash_key tr{\n  vertical-align:top;\n}\ntable.dash_key tr td{\n  line-height:2em;\n  padding: 8px;\n}\n\n#loading_error {\n  font-weight: bold;\n  text-align: center;\n  margin-left: auto;\n  margin-right: auto;\n  width: 500px;\n}\n\na.dash-item-title, a.dash-item-title a:visited{\n  float:left;\n  padding-right:5px;\n  color: #000!important;\n}\n"
  },
  {
    "path": "public/stylesheets/enterprise_map.css",
    "content": "#infovis {\n    position:relative;\n    width:100%;\n    height:500px;\n    margin:auto;\n    overflow:hidden;\n}\n\n/*TOOLTIPS*/\n.tip {\n    color: #111;\n    width: 139px;\n    background-color: white;\n    border:1px solid #ccc;\n    -moz-box-shadow:#555 2px 2px 8px;\n    -webkit-box-shadow:#555 2px 2px 8px;\n    -o-box-shadow:#555 2px 2px 8px;\n    box-shadow:#555 2px 2px 8px;\n    opacity:0.9;\n    filter:alpha(opacity=90);\n    font-size:10px;\n    font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;\n    padding:7px;\n}\n"
  },
  {
    "path": "public/stylesheets/fileuploader.css",
    "content": ".qq-uploader { position:relative; width: 100%;}\n\n.qq-upload-button {\n    display:block; /* or inline-block */\n    width: 105px; padding: 7px 0; text-align:center;\n    background:#880000; border-bottom:1px solid #ddd;color:#fff;\n}\n.qq-upload-button-hover {background:#cc0000;}\n.qq-upload-button-focus {outline:1px dotted black;}\n\n.qq-upload-drop-area {\n    position:absolute; top:0; left:0; width:100%; height:100%; min-height: 70px; z-index:2;\n    background:#FF9797; text-align:center;\n}\n.qq-upload-drop-area span {\n    display:block; position:absolute; top: 50%; width:100%; margin-top:-8px; font-size:16px;\n}\n.qq-upload-drop-area-active {background:#FF7171;}\n\n.qq-upload-list {margin:15px 35px; padding:0; list-style:disc;}\n.qq-upload-list li { margin:0; padding:0; line-height:15px; font-size:12px;}\n.qq-upload-file, .qq-upload-spinner, .qq-upload-size, .qq-upload-cancel, .qq-upload-failed-text {\n    margin-right: 7px;\n}\n\n.qq-upload-file {}\n.qq-upload-spinner {display:inline-block; background: url(\"/images/loading_upload.gif\"); width:15px; height:15px; vertical-align:text-bottom;}\n.qq-upload-size,.qq-upload-cancel {font-size:11px;}\n\n.qq-upload-failed-text {display:none;}\n.qq-upload-fail .qq-upload-failed-text {display:inline;}\n"
  },
  {
    "path": "public/stylesheets/gt-fixed.css",
    "content": "/*\nTemplate:  GT-502\nFile:    gt-fixed.css - If you want a fixed width layout, add \"gt-fixed\" to the body tag of your page. You can change\n      the width of the page below. This file is automatically included on all app pages via gt-styles.css.\n*/\n\n.gt-fixed .gt-fixed-wrap, .gt-fixed .gt-bd, .gt-fixed .gt-footer {\n  width: 960px!important;\n  margin-left: auto!important;\n  margin-right: auto!important;\n}\n"
  },
  {
    "path": "public/stylesheets/gt-rounded-corners.css",
    "content": "/* Rounded Corner Styles for Safari/FF */\n/*\n  This file allows Safari/FF to support rounded corners. If you need rounded corner support in other browsers, please contact us at gooeytemplates.com.\n*/\n.gt-sidebar-nav, .gt-sidebar-box, .gt-sidebar-list-content, .gt-footer, .gt-login-box, .gt-content-box, .gt-sidebar-logo, .help-section, .notice {\n  -webkit-border-radius: 5px;\n  -moz-border-radius: 5px;\n}\n"
  },
  {
    "path": "public/stylesheets/gt-styles.css",
    "content": "@import url(\"gt-rounded-corners.css\");\n@import url(\"gt-fixed.css\");\n\n/*\nTemplate:  GT-502\nFile:    gt-styles.css - This contains all the Gooey styles for the template.\n\nAll the styles are separted into the following groups:\nHTML, Body - for the html and body tags\nLayout - any style that defines how the site is laid out (position and size of objects)\nModules - styles for modules\nNav - navigation bar\nHeadings - headings like h1, h2, etc\nText Styles - Styles for text\nLists - unordered and ordered lists\nForms - html forms\nLinks - links\nMisc - anything that doesn't fit elsewhere\n*/\n\n/* @group HTML, Body */\nhtml {\n/*  background-color: #f3f3f3;*/\n  background-color: #e2eaee;\n/*  background-color: #FFF0DD;*/\n/*  background-color: #F9FCE2;\n*/\n}\nbody {\n  font-family: Helvetica, sans-serif;\n/*  word-wrap: break-word;*/\n}\n/* @end */\n\n/* @group Layout */\n/* Heading Styles */\n.gt-hd {\n/*  background: url(/images/gt/hd-bkg.jpg) repeat-x 0 100%;*/\n/*  background: url(/images/gt/hd-bkg.jpg) repeat-x 0 100%;*/\n  padding-top: 0px;\n}\n.gt-hd-top {\n  overflow: hidden;\n  border-bottom: 1px solid #3b2716;\n  padding: 0 0 5px 0;\n  background-color: #323232;\n}\n.gt-hd .gt-logo {\n  margin-left: 35px;\n  margin-bottom: 0;\n  padding-top: 5px;\n  color: #fff;\n  font-size: 1em;\n  font-weight: bold;\n  float: left;\n  display: inline;\n}\n.gt-hd .gt-logo-links{\n  float:right;\n  padding-left:15px;\n  padding-top:4px;\n}\n.gt-hd .gt-logo .gt-leaf {\n  vertical-align: top;\n}\n.gt-leaf{\n  margin-right: 6px;\n}\n.gt-hd .gt-leaf-watermark {\n  background: url(/images/gt/leaves-watermark.png) no-repeat 99% 0;\n}\n.gt-hd .gt-logo select {\n  background-color: transparent;\n  border: 0px;\n  color: #fff;\n/*  display:none;*/\n  font-family: Helvetica,sans-serif;\n  cursor:pointer;\n}\n.gt-hd .gt-logo a:link, .gt-hd .gt-logo a:visited {\n  color: #eee;\n  text-decoration:none;\n}\n.gt-hd .gt-logo a:hover {\n  text-decoration:underline;\n}\n\n\n/* Body Styles */\n.gt-bd {\n  padding: 25px 35px;\n  min-height: 300px;\n}\n\n/* Standard 2 Column */\n.gt-cols .gt-content {\n  width: 68%;\n  float: left;\n  display: inline;\n}\n.gt-cols .gt-sidebar {\n  width: 30%;\n  float: right;\n  display: inline;\n}\n\n/* Lef action menu, Right Sidebar, 2 Column */\n.gt-cols-2 .gt-sidebar {\n  width: 28%;\n  float: right;\n  display: inline;\n}\n.gt-cols-2 .gt-actionmenu {\n  width: 10%;\n  float: left;\n  display: inline;\n}\n.gt-cols-2 .gt-content {\n  width: 59%;\n  float: left;\n  display: inline;\n}\n\n/* 3 Equal Columns Layout */\n.gt-cols-3 .gt-sidebar-left {\n  width: 31%;\n  margin-right: 3.5%;\n  float: left;\n  display: inline;\n}\n.gt-cols-3 .gt-content {\n  width: 31%;\n  float: left;\n  display: inline;\n}\n.gt-cols-3 .gt-sidebar {\n  width: 31%;\n  float: right;\n  display: inline;\n}\n\n/* Action menu, and no sidebar */\n.gt-cols-3 .gt-actionmenu {\n  width: 15%;\n  margin-right: 20px;\n  float: left;\n  display: inline;\n}\n.gt-cols-3 .gt-content {\n  width: 80%;\n  float: left;\n  display: inline;\n}\n\n/* Fixed Width Layout */\n.gt-fixed .gt-bd {\n  padding-left: 0!important;\n  padding-right: 0!important;\n}\n.gt-fixed .gt-nav {\n  margin-left: 0!important;\n}\n.gt-fixed .gt-nav a {\n  padding-left: 0!important;\n}\n.gt-fixed .gt-logo {\n  margin-left: 0!important;\n}\n.gt-fixed .gt-search {\n  margin-right: 0!important;\n}\n.gt-fixed .gt-util-box {\n  margin-right: 0!important;\n}\n\n/* Left and Right Columns */\n.gt-left-col {\n  width: 48%;\n  float: left;\n  display: inline;\n}\n.gt-right-col {\n  width: 48%;\n  float: right;\n  display: inline;\n}\n\n/* Footer Styles */\n.gt-footer {\n  clear: both;\n  border: 1px solid #ccc;\n  border-radius: 5px;\n  font-size: 93%;\n  color: #666666;\n  margin: 20px 35px;\n  text-align: center;\n  background-color: #f4f7f8;\n}\n.gt-footer-inner {\n  padding: 10px;\n}\n.gt-footer p {\n  margin: 0;\n}\n\n.gt-actionmenu{\n  margin-right:35px;\n  margin-left:35px;\n  float:right;\n}\n/* @end */\n\n/* @group Modules */\n/* Width Styles */\n.gt-width-33 {\n  width: 33%;\n}\n.gt-width-66 {\n  width: 66%;\n}\n.gt-width-99 {\n  width: 99%;\n}\n.gt-width-25 {\n  width: 25%;\n}\n.gt-width-50 {\n  width: 50%;\n}\n.gt-width-75 {\n  width: 75%;\n}\n.gt-width-100 {\n  width: 100%;\n}\n\n\n/* Utility Box Styles */\n.gt-util-box {\n  margin-right: 20px;\n  color: #eee;\n  font-size: 93%;\n  float: right;\n  display: inline;\n}\n.gt-util-box p {\n  margin: 0;\n}\n.gt-util-box a:link, .gt-util-box a:visited {\n  color: #eee;\n  text-decoration: none;\n}\n.gt-util-box a:hover {\n  text-decoration: underline;\n}\n.gt-util-box-inner {\n  padding: .35em 2em;\n  float:right;\n}\n.gt-util-separator {\n  padding: 0 .35em;\n}\n.gt-util-box li {\n  margin: 0;\n  padding: 0;\n  float: left;\n  list-style-type: none;\n}\n\n\n/* Default List Table */\n.gt-content-box {\n  background-color: #fff;\n/*  background-color: #f0f0f0;*/\n  border: 1px solid #ccc;\n  border-radius: 5px;\n/*  padding: 1px;*/\n  margin-bottom: 2em;\n}\n.gt-content-box-padding {\n  padding: 15px;\n}\n.gt-table {\n  width: 100%;\n}\n.gt-table th {\n  font-weight: bold;\n  font-size: 100%;\n  padding: 7px 10px;\n  color: #333;\n  border-bottom: 1px solid #e4e4e4;\n}\n.gt-table td {\n  padding: 7px 10px;\n  border-top: 1px solid #e4e4e4;\n  color: #333;\n  vertical-align: top;\n  word-wrap: break-word;\n}\n.gt-table tr:hover td {\n/*  background-color: #f4f7f8;*/\n/*  background-color: #ddd;*/\n}\n.gt-table tr:first-child td {\n  border: none;\n}\n.gt-table h4 {\n  font-size: 108%;\n  color: #365b6d;\n  margin-bottom: 0;\n}\n.gt-table a:link, .gt-table a:visited {\n  color: #365b6d;\n  text-decoration: none;\n}\n.gt-table td a:hover {\n  text-decoration: underline;\n}\n.gt-table-edit {\n  margin: 0;\n}\n.gt-table-edit a {\n  display: block;\n  padding: 1px 0 1px 22px;\n  background: url(/images/famfamfam/icons/pencil.png) no-repeat 0 50%;\n}\n.gt-table-edit a:link, .gt-table-edit a:visited {\n  color: #7898aa;\n}\n.gt-table-edit a:hover {\n  color: #365b6d;\n  text-decoration: none!important;\n}\n.gt-table td.side {\n  width: 100px;\n}\n.padded {\n  padding: 15px;\n}\n\n.no-border td {\n  border-top: 0px;\n}\n\n.project-table {\n  margin-bottom: 10px;\n  margin-top: 10px;\n}\n\n.project-table td {\n    border-top-style: none;\n    border-top-width: 0px;\n    padding-bottom: 2px;\n    padding-left: 15px;\n    padding-right: 10px;\n    padding-top: 3px;\n}\n\n#my_projects_table td{\n  font-weight: bold;\n  font-size: 110%;\n}\n\n.active-projects h3 {\n  padding-bottom:0px!important;\n  margin-bottom:0px!important;\n}\n\n.issues {\n  margin-top: 10px;\n  margin-bottom: 10px;\n\n}\n\n.issues td {\n    border-top-style: none;\n    border-top-width: 0px;\n}\n\n.issues td.id {\n  padding-left:20px;\n}\n\n.project-browse-table td {\n    border-top-style: none;\n    border-top-width: 0px;\n    padding-bottom: 20px;\n    padding-left: 15px;\n    padding-right: 10px;\n    padding-top: 15px;\n}\n\n\n.project-browse-table h4 {\n  font-size: 135%;\n  color: #365b6d;\n  margin-bottom: 10px;\n  display:inline;\n}\n\n.project-browse-table .spark-container{\n  text-align:center;\n  padding-top:5px;\n}\n\nh5 .icon{\n  padding-bottom: 0px;\n}\n\n\n/*Custom indentation*/\n.gt-content-box h3 {\n  margin: 10px;\n}\n\n\n/* Table Buttons */\n.gt-table-buttons {\n  margin: 10px 0 40px 0;\n}\n.gt-table-buttons-inside {\n  margin: 10px 0 10px 0;\n}\n.gt-table-buttons:after, .gt-table-buttons-inside:after {\n    content: \".\";\n    display: block;\n    height: 0;\n    clear: both;\n    visibility: hidden;\n}\n.gt-table-buttons {display: inline-block;}\n.gt-table-buttons-inside {display: block;}\n\n/* Hides from IE-mac \\*/\n* html .gt-table-buttons {height: 1%;}\n.gt-table-buttons {display: block;}\n/* End hide from IE-mac */\n\n/* Table Pager, Table Select Box */\n.gt-table-controls {\n  font-size: 93%;\n  padding: 7px 10px;\n}\n.gt-content-box .gt-table-controls {\n  border-bottom: 1px solid #ccc;\n}\n.gt-content-box .gt-table-controls-btm {\n  border-bottom: none!important;\n  border-top: 1px solid #ccc;\n}\n.gt-table-controls .gt-table-picker {\n  float: left;\n  display: inline;\n}\n.gt-table-controls .gt-table-pager {\n  margin: 0 2px 0 0;\n  color: #aaa;\n  padding: 3px 0 0 0;\n  float: right;\n  display: inline;\n}\n.gt-table-controls .gt-table-pager a {\n  padding: 0 2px;\n}\n.gt-table-controls .gt-table-pager a:link, .gt-table-controls .gt-table-pager a:visited {\n  color: #666666;\n  text-decoration: none;\n}\n.gt-table-controls .gt-table-pager a.current:link, .gt-table-controls .gt-table-pager a.current:visited {\n  color: #333;\n  text-decoration: underline;\n}\n.gt-table-controls .gt-table-pager a:hover {\n  text-decoration: underline;\n}\n\n/* Default Table Columns */\n.gt-table td {\n  width: auto;\n}\n.gt-table th.gt-table-col-checkbox {\n  width: 20px;\n}\n\n/* Categories Sub Table */\n.gt-table-categories th {\n  font-weight: normal;\n  color: #666666;\n  text-align: right;\n  padding: 0 10px 5px 0;\n  vertical-align: top;\n  font-size: 85%;\n  border: none;\n}\n.gt-table-categories td {\n  text-align: left;\n  font-size: 85%;\n  font-weight: bold;\n  color: #666666;\n  vertical-align: top;\n  padding: 0 0 5px 0;\n  border: none;\n}\n.gt-table-categories a:link, .gt-table-categories a:visited {\n  color: #666666;\n  text-decoration: none;\n}\n.gt-table-categories a:hover {\n  text-decoration: underline;\n}\n\n/* Action Links */\n.gt-table .gt-table-action-list {\n  color: #999;\n  margin-top: 10px;\n  margin-bottom: 0px;\n  margin-left: 0px;\n  margin-right: 0px;\n}\n.gt-table .gt-table-action-list img {\n  vertical-align: text-bottom;\n}\n.gt-table .gt-table-action-list .gt-separator {\n  margin: 0 3px;\n}\n.gt-table .gt-table-action-list a:link, .gt-table .gt-table-action-list a:visited {\n  color: #7898aa;\n}\n.gt-table .gt-table-action-list a:hover {\n  color: #365b6d;\n  text-decoration: none!important;\n}\n\n/* User Table */\n.gt-user-table .gt-avatar {\n  width: 1%;\n}\n.gt-user-table .gt-avatar img, , gt-user-table .gt-avatar-tiny img{\n  padding: 2px;\n  border: solid 1px #d5d5d5;\n  background: #fff;\n}\n.gt-user-table p {\n  margin-bottom: 0.6em;\n}\n\n\n/* Login Box Styles */\n.gt-login-hd {\n  width: 430px;\n  margin-left: auto;\n  margin-right: auto;\n  margin-top: 30px;\n  margin-bottom: 10px;\n  font-size: 161.6%;\n  font-weight: bold;\n  color: #0e2029;\n}\n.gt-login-box {\n  width: 400px;\n  margin-left: auto;\n  margin-right: auto;\n  padding: 1.5em 3em;\n  border: 1px solid #ccc;\n  background-color: #fff;\n  border-radius: 5px;\n}\n.gt-login-box .gt-form .gt-form-text {\n  font-size: 116%;\n}\n.gt-login-box .gt-remember-me {\n  display: block;\n  padding: 12px 0 0 0;\n  font-size: 85%;\n  font-weight: normal;\n  color: #666666;\n  float: left;\n  display: inline;\n}\n.gt-forgot-password {\n  font-size: 85%;\n  clear: both;\n  margin: 0;\n  padding: 5px 0 0 0;\n}\n\n\n/* Sidebar Box */\n.gt-sidebar-box {\n  padding: .75em;\n  border-radius: 5px;\n  margin-bottom: 20px;\n}\n.gt-sidebar-box-gray {\n  background: url(/images/gt/sidenav-gray-bkg.gif) repeat-x 0 0 #333;\n}\n.gt-sidebar-box-blue {\n  background: url(/images/gt/sidenav-blue-bkg.gif) repeat-x 0 0 #002f49;\n}\n\n/* Sidebar Content */\n.gt-sidebar-logo {\n  background-color: #fff;\n  border: 1px solid #ccc;\n  border-radius: 5px;\n  padding: 1px;\n  margin-bottom: 1em;\n  text-align: center;\n  padding: 10px;\n}\n.gt-sidebar-content {\n  margin-bottom: 20px;\n  color: #333;\n}\n.gt-sidebar-content h3 {\n  font-size: 108%;\n  font-weight: bold;\n  color: #365b6d;\n  border-bottom: 1px solid #ccc;\n  margin: 0 0 5px 0;\n}\n.gt-sidebar-content p {\n/*  font-size: 85%;*/\n}\n.gt-sidebar-content li {\n/*  font-size: 85%;*/\n}\n.gt-sidebar-content li li {\n/*  font-size: 100%;*/\n}\n\n/* Sidebar List */\n.gt-sidebar-list {\n  margin-bottom: 20px;\n}\n.gt-sidebar-list ul, .gt-sidebar-list li {\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n.gt-sidebar-list h3 {\n  font-size: 108%;\n  font-weight: bold;\n  color: #365b6d;\n  margin: 0 0 5px 0;\n}\n.gt-sidebar-list .gt-sidebar-list-content {\n  border: 1px solid #ccc;\n  background-color: #fff;\n  border-radius: 5px;\n  padding: 1px;\n}\n.gt-sidebar-list .gt-sidebar-list-row {\n  padding: 1em;\n  border-top: 1px solid #e5e6eb;\n  color: #666666;\n  clear: both;\n}\n.gt-sidebar-list .gt-sidebar-list-row:hover {\n  background-color: #f4f7f8;\n}\n.gt-sidebar-list .gt-sidebar-list-row:first-child {\n  border: none;\n}\n.gt-sidebar-list .gt-sidebar-list-row h4 {\n  margin: 0;\n  font-size: 93%;\n  color: #365b6d;\n}\n.gt-sidebar-list .gt-sidebar-list-row h4 a:link, .gt-sidebar-list .gt-sidebar-list-row h4 a:visited {\n  color: #365b6d;\n  text-decoration: none;\n}\n.gt-sidebar-list .gt-sidebar-list-row h4 a:hover {\n  text-decoration: underline;\n}\n.gt-sidebar-list .gt-sidebar-list-row p {\n  font-size: 85%;\n  margin: 0;\n}\n\n/* Avatars */\n.gt-avatar-small {\n  margin: 0 10px 10px 0;\n  float: left;\n  display: inline;\n}\n\n.gt-avatar-tiny {\n  width: 1%;\n  padding: 3px 3px;\n}\n\n.gt-avatar-box{\n  padding: 5px;\n  text-align:center;\n  float: left;\n}\n\n/* Buttons */\n.gt-btn-gray-mini, .gt-btn-gray-small, .gt-btn-gray-medium, .gt-btn-gray-large, .gt-btn-blue-mini, .gt-btn-blue-small, .gt-btn-blue-medium, .gt-btn-blue-large {\n  display: block;\n  height: 38px;\n  line-height: 38px;\n  text-align: center;\n  font-weight: bold;\n  color: #fff!important;\n  text-decoration: none!important;\n  font-size: 13px;\n  border: none;\n  padding: 0;\n  margin: 0;\n}\n.gt-btn-gray-mini {\n  width: 37px;\n  background: url(/images/gt/btn-gray-mini.png) no-repeat 0 0 transparent;\n}\n.gt-btn-gray-small {\n  width: 70px;\n  background: url(/images/gt/btn-gray-small.png) no-repeat 0 0 transparent;\n}\n.gt-btn-gray-medium {\n  width: 126px;\n  background: url(/images/gt/btn-gray-medium.png) no-repeat 0 0 transparent;\n}\n.gt-btn-gray-large {\n  width: 185px;\n  background: url(/images/gt/btn-gray-large.png) no-repeat 0 0 transparent;\n}\n\n.gt-btn-blue-mini {\n  width: 37px;\n  background: url(/images/gt/btn-blue-mini.png) no-repeat 0 0 transparent;\n}\n.gt-btn-blue-small {\n  width: 70px;\n  background: url(/images/gt/btn-blue-small.png) no-repeat 0 0 transparent;\n}\n.gt-btn-blue-medium {\n  width: 126px;\n  background: url(/images/gt/btn-blue-medium.png) no-repeat 0 0 transparent;\n}\n.gt-btn-blue-large {\n  width: 185px;\n  background: url(/images/gt/btn-blue-large.png) no-repeat 0 0 transparent;\n}\n\n/* Button Positioning */\n.gt-btn-left {\n  margin-right: 10px;\n  float: left;\n  display: inline;\n}\n.gt-btn-right {\n  margin-left: 10px;\n  float: right;\n  display: inline;\n}\n/* @end */\n\n/* @group Nav */\n/* Navbar */\n.gt-navbar {\n/*  background: url(/images/gt/navbar-bkg.png) repeat 0 0;\n*/  margin-bottom: 2px;\n  margin-left: 35px;\n  padding-top: 5px;\n}\n\n.gt-nav-breadcrumbs a:link, .gt-nav-breadcrumbs a:visited {\n  color:#333!important;\n  text-decoration: none;\n\n}\n\n/* Main Navigation */\n.gt-nav {\n  margin: 0 0 0 0px;\n  width: 100%;\n  float: left;\n  display: inline;\n}\n.gt-nav h1 {\n  display:inline;\n}\n.gt-nav-sub{\n  width:100%;\n}\n.gt-nav-sub ul {\n  margin: 0;\n  padding: 0;\n  float: left;\n  display: inline;\n}\n.gt-nav-sub ul li {\n  margin: 0;\n  padding: 0;\n  float: left;\n  display: inline;\n}\n.gt-nav-sub ul li a, .gt-nav ul li a:visited {\n  display: block;\n  padding: 0 1em;\n  font-weight: bold;\n  line-height: 22px;\n  font-size: 100%;\n  float: left;\n  display: inline;\n  color: #fff!important;\n  background-color: #365B6D;\n/*  background-color: #1a5472;*/\n  margin-right: 1px;\n}\n\n.gt-nav a:link, .gt-nav a:visited {\n/*  color: #a6cbdc;*/\n  text-decoration: none;\n}\n.gt-nav-sub a:visited:hover, .gt-nav-sub a:hover, .gt-nav a.gt-active:link, .gt-nav a.gt-active:visited, .gt-nav .gt-active a:link, .gt-nav .gt-active a:visited {\n  background-color: #000;\n  color: #fff!important;\n  text-decoration: underline;\n}\n\n.gt-actionmenu a:visited, .gt-actionmenu a {\n  background-color: #CF5D07!important;\n\n/*  background-color: #e58508!important;*/\n}\n\n.gt-actionmenu a:visited:hover, .gt-actionmenu a:hover {\n/*  background-color: #C27006!important;*/\n  background-color: #953404!important;\n}\n\n.gt-actionmenu ul li a.top-help-tip {\n  background-color: #777!important;\n}\n\n.gt-actionmenu ul li a.top-help-tip:hover {\n  background-color: #444  !important;\n}\n\n\n.gt-actionmenu ul li a{\n  -moz-border-radius: 5px;\n  -moz-border-radius: 5px;\n  border-bottom-left-radius: 5px 5px;\n  border-bottom-right-radius: 5px 5px;\n  border-top-left-radius: 5px 5px;\n  border-top-right-radius: 5px 5px;\n  margin-left:1px;\n}\n\n.gt-actionmenu ul li a.icon {\n  background-position: 5px 50%;\n  background-repeat: no-repeat;\n  padding-left: 23px;\n}\n\n\n.gt-nav-sub ul li:first-child a{\n  -moz-border-radius-topleft: 5px;\n  -moz-border-radius-bottomleft: 5px;\n  border-bottom-left-radius: 5px 5px;\n  border-top-left-radius: 5px 5px;\n}\n\n.gt-nav-sub ul li:last-child a{\n  -moz-border-radius-topright: 5px;\n  -moz-border-radius-bottomright: 5px;\n  border-bottom-right-radius: 5px 5px;\n  border-top-right-radius: 5px 5px;\n}\n\n/* Sidebar Navigation */\n.gt-sidebar-nav {\n  margin-bottom: 20px;\n  border-radius: 5px;\n  max-width: 800px;\n}\n.gt-sidebar-nav ul {\n  margin: 0;\n  padding: 0 1px 1px 1px;\n}\n.gt-sidebar-nav ul li {\n  padding: 0 0 0 0;\n  margin: 0;\n  list-style-type: none;\n}\n.gt-sidebar-nav ul li a, .gt-sidebar-nav ul li p {\n  display: block;\n  padding: .6em .6em .6em 1.8em;\n}\n.gt-actionmenu .gt-sidebar-nav ul li a, .gt-sidebar-nav ul li p {\n  padding-left: 1.6em;\n}\n.gt-sidebar-nav ul li p {\n  color: #eee;\n  text-decoration: none;\n  margin-bottom: 15px;\n}\n.gt-sidebar-nav ul li a.icon {\n  margin-left: 1.8em;\n}\n.gt-actionmenu .gt-sidebar-nav ul li a.icon {\n  margin-left: 1em;\n}\n\n.gt-sidebar-nav a:link, .gt-sidebar-nav a:visited {\n  color: #eee;\n  text-decoration: none;\n}\n.gt-sidebar-nav a:hover {\n  color: #fff;\n  text-decoration: none;\n}\n.gt-sidebar-nav h3 {\n  font-size: 108%;\n  margin: 0;\n  padding: .6em .6em .6em 1.2em;\n  color: #fff;\n  font-weight: bold;\n}\n\n/* Brown Sidebar Nav */\n.gt-sidebar-nav-blue {\n  background: url(/images/gt/sidenav-blue-bkg.gif) repeat-x 0 0 #002f49;\n}\n.gt-sidebar-nav-blue li {\n  border-top: 1px solid #1b5c7e;\n}\n.gt-sidebar-nav-blue a:hover {\n  background-color: #1a5472;\n}\n\n/* Green Sidebar Nav */\n.gt-sidebar-nav-gray {\n  background: url(/images/gt/sidenav-gray-bkg.gif) repeat-x 0 0 #333;\n}\n.gt-sidebar-nav-gray li {\n  border-top: 1px solid #6b6b6b;\n}\n.gt-sidebar-nav-gray a:hover {\n  background-color: #5b5b5b;\n}\n/* @end */\n\n/* @group Headings */\nh1 {\n/*  font-size: 182%;*/\n  font-size: 210%;\n  color: #0e2029;\n  margin-bottom: 10px;\n  line-height:1.5em;\n}\n\n/* H2 */\nh2 {\n  font-size: 130%;\n  color: #0e2029;\n/*  color: #365b6d;*/\n  margin-bottom: 5px;\n  font-weight: bold;\n/*  margin-left: 2px;*/\n}\nh2.gt-table-head, h2.gt-form-head {\n  margin-bottom: 5px;\n}\nh3, .gt-sidebar h2 {\n  font-size: 138.5%;\n  color: #0e2029;\n/*  color: #365b6d;*/\n  margin-bottom: 5px;\n  font-weight: bold;\n/*  margin-left: 2px;*/\n}\nh4 {\n  font-size: 123.1%;\n  color: #333;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\nh5 {\n  font-size: 123.1%;\n  color: #333;\n  margin-bottom: 5px;\n}\nh6 {\n  font-size: 100%;\n  color: #365b6d;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n\n/* @end */\n\n/* @group Text Styles */\naddress {\n  margin-bottom: 10px;\n}\nblockquote {\n  margin: 10px 40px 20px 40px;\n  font-style: italic;\n}\ncode {\n  font-family: monospace;\n}\ndl {\n  margin-left: 30px;\n  margin-bottom: 20px;\n}\ndl dt {\n  font-weight: bold;\n}\ndl dd {\n  margin-left: 10px;\n  margin-bottom: 5px;\n}\nem {\n  font-style: italic;\n}\np {\n  margin-bottom: 0.6em;\n  line-height: 130%;\n}\nq {\n  font-style: italic;\n}\nstrong {\n  font-weight: bold;\n}\ntt {\n  font-family: monospace;\n}\n\n\n/* Custom Text Classes */\n.gt-cancel {\n  color: #666666;\n  margin-left: 20px;\n\n}\n.gt-cancel a:link, .gt-cancel a:visited {\n  color: #cc0000;\n  text-decoration: underline;\n\n}\n.gt-cancel a:hover {\n  text-decoration: none;\n}\n\n/*.flash {\n  border: 3px solid #aaa;\n  padding: 1em;\n  background-color: #fff;\n  margin-bottom: 1.5em;\n}\n\n.flash a:link, .flash a:visited {\n  color: #fff;\n  text-decoration: underline;\n}\n.flash a:hover {\n  text-decoration: none;\n}\n\n\n.error {\n  background-color: #cc0000;\n  padding: .5em 1em;\n  color: #fff;\n}\n\n.success {\n  background-color: #47790a;\n  padding: .5em 1em;\n  color: #fff;\n}\n\n.notice {\n  background-color: #47790a;\n  padding: .5em 1em;\n  color: #fff;\n}\n*/\n\n/* new look and feel for flash messages */\n.error, .notice, .success {\n  padding:.8em;\n  margin-bottom:1em;\n  border:1px solid #ddd;\n  clear: both;\n  text-align:center;\n}\n.error {\n  background:#FBE3E4;\n  color:#8a1f11;\n  border-color:#FBC2C4;\n}\n.notice {\n  background: #Fff url(/images/static/clip.png) no-repeat 10px 50% ;\n  color:#595959;\n  border: 1px solid #ccc;\n  border-radius: 5px;\n  text-shadow: 1px 1px #fff;\n  padding:1.4em;\n  font-weight:bold;\n}\n.success {\n  background:#E6EFC2;\n  color:#264409;\n  border-color:#C6D880;\n}\n.error a {\n  color:#8a1f11;\n}\n.notice a {\n  color:#514721;\n}\n.success a {\n  color:#264409;\n}\n\n\n/* @end */\n\n/* @group Lists */\nol {\n  margin-bottom: 20px;\n}\nol li {\n  list-style-type: decimal;\n  margin-left: 40px;\n  margin-bottom: 2px;\n}\nul {\n  margin-bottom: 10px;\n}\nul li {\n  list-style-type: none;\n  margin-left: 2px;\n  margin-bottom: 2px;\n}\n/* @end */\n\n/* @group Forms */\n/* Default Form */\n.gt-form {\n\n}\n.gt-form.gt-content-box {\n  padding: 15px 15px 5px 15px;\n  margin-bottom: 40px;\n}\n.gt-form .gt-form-text, .gt-form .gt-form-textarea {\n  border: 1px solid #ccc;\n  background-color: #f4f7f8;\n  padding: 5px 2px;\n  font-size: 108%;\n  width: 99%;\n}\n.gt-form .gt-form-text:focus, .gt-form .gt-form-textarea:focus {\n  background-color: #fff;\n}\n.gt-form label {\n  font-size: 100%;\n  color: #365b6d;\n  display: block;\n  margin-bottom: 3px;\n  font-weight: bold;\n}\n.gt-form option {\n  font-size: 108%;\n}\n.gt-form .gt-form-row {\n  margin-bottom: 10px;\n}\n\n/* Auto clear the form row */\n.gt-form .gt-form-row:after {\n    content: \".\";\n    display: block;\n    height: 0;\n    clear: both;\n    visibility: hidden;\n}\n\n.gt-form-row {display: inline-block;}\n\n/* Hides from IE-mac \\*/\n* html .gt-form-row {height: 1%;}\n.gt-form-row {display: block;}\n/* End hide from IE-mac */\n/* End auto clearing the form row */\n\n.gt-form .gt-form-row-inline {\n  clear: left;\n}\n.gt-form .gt-form-row-inline label {\n  width: 30%;\n  margin-right: 4%;\n  padding: 1% 0;\n  float: left;\n  display: inline;\n}\n.gt-form .gt-form-element-label {\n  font-size: 93%;\n  margin-bottom: 5px;\n  padding-left: 3px;\n  font-weight: normal;\n  color: #666666;\n}\n.gt-form .gt-form-note {\n  font-size: 93%;\n  margin: 0 0 5px 0;\n  font-style: italic;\n  color: #666666;\n}\n.gt-form .gt-form-row-inline .gt-form-text {\n  width: 63%;\n}\n.gt-form .gt-form-radio, .gt-form .gt-form-checkbox {\n  margin-right: 3px;\n}\n.gt-form .gt-submit-btn {\n  margin: 0 10px 0 0;\n  float: left;\n  display: inline;\n}\n.gt-form .gt-cancel {\n  line-height: 37px;\n  margin-bottom: 0;\n}\n\n/* Search Box */\n.gt-search {\n  background: url(/images/gt/search-box-left.png) no-repeat 0 0;\n  height: 22px;\n  padding: 0 0 0 20px;\n}\n.gt-search-inner {\n  height: 20px;\n  background: url(/images/gt/search-box-right.png) no-repeat 100% 0;\n  padding: 3px 0 0 0;\n}\n.gt-search .gt-search-text {\n  border: none;\n  background-color: transparent;\n  font-size: 93%;\n  color: #999;\n  padding: 0 0 0 5px;\n  margin-top: 2px;\n  width: 95%;\n}\n.gt-navbar .gt-search-wide {\n  width: 20%;\n  margin-bottom: 9px;\n  margin-right: 35px;\n  float: right;\n  display: inline;\n}\n.gt-search-narrow {\n  width: 150px;\n  float:left;\n}\n\n.gt-search-container {\n  width: 600px;\n  margin-top: 9px;\n  margin-right: 9px;\n  margin-left: auto;\n  margin-right: auto;\n}\n.gt-second-navbar{\n  margin-right: 20px;\n  margin-left: 15px;\n  margin-top: 10px;\n}\n\n.dash-filter {\n  float: left;\n  margin-left: 5px;\n}\n/* @end */\n\n/* @group Links - link visited hover active */\na:link, a:visited {\n  color: #365b6d;\n  text-decoration: underline;\n}\na:hover {\n  text-decoration: none;\n}\n/* @end */\n\n/* @group Misc */\n.clear {\n  clear: both;\n}\n.clearfix:after {\n    content: \".\";\n    display: block;\n    height: 0;\n    clear: both;\n    visibility: hidden;\n}\n\n.clearfix {display: inline-block;}\n\n/* Hides from IE-mac \\*/\n* html .clearfix {height: 1%;}\n.clearfix {display: block;}\n/* End hide from IE-mac */\n/* @end */\n\n/* Custom */\n.splitcontentleft{float:left; width:49%;}\n.splitcontentright{float:right; width:49%;}\n\n.loading {\n  padding-left: 26px;\n  background-position: 0% 40%;\n  background-repeat: no-repeat;\n  background-image: url(/images/loading.gif);\n  font-style: italic;\n}\n\n.clickable{\n  cursor:pointer;\n}\n\n.help_question_mark{\n   cursor:pointer;\n  margin-bottom: 3px;\n  margin-left: 4px;\n}\n\n\n.point-scale{\n  float:left;\n  padding-left:15px;\n}\n\n.left{\n  float:left;\n}\n\n.right{\n  float:right;\n}\n\n.hidden{\n  display:none;\n}\n\n.tip{\n  width:300px;\n}\n\n\n/*Activity Table*/\n/*table.activity-item {margin-left: 7px; margin-top: 5px;}*/\ntable.activity-item h5 {margin-bottom: 0px; background-position: 0% 0px; background-repeat: no-repeat; padding-left: 20px; display: inline; }\ntable.activity-item span {display:block;padding-top:5px;}\ntable.activity-item td {background-position: 90% 7px; background-repeat: no-repeat; }\n/*table.activity-item td.border {border-left-style: solid; border-left-color: #ccc; padding: 0px; width: 21px;}*/\ntable.activity-item h5.issue { background-image: url(/images/ticket.png); }\ntable.activity-item h5.issue-edit { background-image: url(/images/ticket_edit.png); }\ntable.activity-item h5.issue-closed { background-image: url(/images/ticket_checked.png); }\ntable.activity-item h5.issue-note { background-image: url(/images/ticket_note.png); }\ntable.activity-item h5.changeset { background-image: url(/images/changeset.png); }\ntable.activity-item h5.news { background-image: url(/images/news.png); }\ntable.activity-item h5.message { background-image: url(/images/message.png); }\ntable.activity-item h5.reply { background-image: url(/images/comments.png); }\ntable.activity-item h5.wiki-page { background-image: url(/images/wiki_edit.png); }\ntable.activity-item h5.wikipage { background-image: url(/images/wiki_edit.png); }\ntable.activity-item h5.attachment { background-image: url(/images/attachment.png); }\ntable.activity-item h5.document { background-image: url(/images/document.png); }\ntable.activity-item h5.project { background-image: url(/images/projects.png); }\ntable.activity-item h5.time-entry { background-image: url(/images/time.png); }\ntable.activity-item h5.cr-note { background-image: url(/images/tag_blue.png); }\ntable.activity-item h5.team-offer { background-image: url(/images/user_new.png); }\ntable.activity-item h5.member-role { background-image: url(/images/users.png); }\ntable.activity-item h5.memberrole { background-image: url(/images/users.png); }\ntable.activity-item h5.motion { background-image: url(/images/weather_lightning.png); }\n\n/*Sub Table*/\ntable.activity-sub {margin-left: 7px; margin-top: 0px;width:99%;}\ntable.activity-sub td {background-color: #e2eaee; padding: 5px;}\ntable.activity-sub tr {border-top-color:#fff; border-top-style:solid; border-width:2px;}\ntable.activity-sub table.gt-table-categories tr {border-top:0px;}\n\ndiv.activity-tag {\n/*  padding: 2px 2px 2px 2px;*/\n  padding-bottom:10px;\n/*  text-align: right;*/\n  font-style:italic;\n}\n\n/************** Dashboards *************************/\n\n.action_link{\n  color: #fff;\n}\n\na.action_link_votes{\n  color: #333!important;\n}\n\n\n.action_button{\n  width:60px;\n  height:21px;\n  line-height:21px;\n  text-align:center;\n  vertical-align:middle;\n  cursor:pointer;\n  color: #ddd;\n  float: right;\n  display: inline;\n  font-size:85%;\n}\n\n.new_request_button{\n  width:90px;\n  height:21px;\n  line-height:23px;\n  text-align:center;\n  vertical-align:middle;\n  cursor:pointer;\n  color: #111;\n  font-weight: bold;\n/*  float: right;*/\n  display: block;\n  background: url(/images/bb_very_white.png) no-repeat;\n}\n\n.panel_button_top{\n/*  width:90px;\n  height:21px;\n  line-height:23px;*/\n  text-align:center;\n  vertical-align:middle;\n  cursor:pointer;\n  color: #eee;\n  font-weight: normal;\n/*  float: right;*/\n  display: block;\n  background-color: #555;\n  padding: 2px 4px 2px 4px;\n  border-radius: 5px;\n  -moz-border-radius: 5px;\n  -webkit-border-radius: 5px;\n}\n\n\n.refresh_button{\n  width:18px;\n  height:18px;\n  line-height:23px;\n  text-align:center;\n  vertical-align:middle;\n  cursor:pointer;\n/*  float: right;*/\n  display: block;\n  background: url(/images/refresh.png) no-repeat;\n  margin:2px;\n}\n\n.dash_key_button{\n  width:16px;\n  height:16px;\n  line-height:23px;\n  text-align:center;\n  vertical-align:middle;\n  cursor:pointer;\n/*  float: right;*/\n  display: block;\n  background: url(/images/key.png) no-repeat;\n  margin:2px;\n}\n\n.action_button_no_float{\n  width:60px;\n  height:21px;\n  line-height:21px;\n  text-align:center;\n  vertical-align:middle;\n  cursor:pointer;\n  color: #fff;\n  float: left;\n}\n\n\n.action_button_change{\n  font-color:#000;\n  font-weight:bold;\n  background: url(/images/bb_ocean.png) no-repeat;\n  float:left;\n  padding-top:2px;\n}\n\n\n.action_button_save{\n  font-color:#000;\n  font-weight:bold;\n  background: url(/images/bb_red.png) no-repeat;\n  float:left;\n  padding-top:2px;\n}\n\n.action_button_votes{\n  text-align: left;\n  margin-right:1px;\n}\n\n.action_button_votes a.vote_arrow{\n  margin-right:3px;\n}\n\n/*Flyovers*/\n.itemCollapsedHeader {\n  padding:4px 4px;\n}\n\n.itemCollapsedHeader a:link, .itemCollapsedHeader a:visited{\n  text-decoration: none;\n}\n\n.itemCollapsedHeader a:hover{\n  text-decoration: underline;\n}\n\n.itemCollapsedButtons {\n  float:right;\n  padding-bottom:1px;\n  padding-top:0px;\n  padding-left:2px;\n  text-align:right;\n/*  width: 100px; /*will be overwritten by javascript*/\n  height: 19px;\n}\n\n.pri-container{\n\n}\n\n.itemCollapsedHeader .icons, .itemCollapsedHeader .itemCollapsedText {\n  padding-bottom:1px;\n  padding-top:1px;\n}\n\n.itemCollapsedText {\n  padding-left:60px;\n  padding-right:160px;\n}\n\n.itemCollapsedTextNewLink{\n  text-align: center;\n  font-weight: bold;\n}\n\n.itemCollapsedInput {\n  padding-left:20px;\n}\n.itemCollapsedText, .storyLabels {\n  -moz-user-select:none;\n}\n\n.icons {\n  float:left;\n  width: 60px;\n}\n\n\n.underEdit .itemCollapsedHeader {\n  background-color:#FFEDA1;\n}\n\n.newlink .itemCollapsedHeader {\n  background-color:#FFEDA1;\n}\n\n\n\n.unstarted, .newStory {\n  background-color:white;\n}\n.unestimatedText .itemCollapsedHeader {\n  font-style:italic;\n}\n\n/*flyover*/\n.gt-Sd {padding: 6px 17px 7px; background-color: #fff8d7}\n.gt-Sd .elementResizerHandle {display: block}\n.gt-SdTable {padding-top: 10px; border-spacing: 0px 0; border-collapse: separate}\n.gt-SdTable td.letContentExpand {width: 1px;border-bottom:none;}\n.gt-SdTable td {border-bottom:none;}\n.gt-SdTable .created_by {text-align:right; line-height:1.3em;}\n.gt-SdButton {padding: 0px;}\n.gt-SdActionButton {text-align: right; padding: 0px;}\n.gt-Sd .section {color:#333; font-weight:normal; font-size:0.95em; line-height: 14px; margin-top: 15px}\n.gt-Sd .section .header {font-weight:bold; color:#3F3D35; font-size: 115%; margin-bottom: 0}\n.gt-Sd .section textArea, .gt-Sd .section input[type=text].tasksTextArea {width: 95%; overflow:auto; padding: 3px; font-weight:bold; margin-top: 5px; font-size: 104%; max-width:500px;}\n.gt-Sd .storyDescriptionTable textArea {margin-top: 3px}\n.gt-Sd .storyDescriptionTable {width: 100%}\n.gt-Sd .tasksTable {width: 100%}\n.tasksTextArea {margin-top: 3px; width: 95%; max-width:500px;}\n.gt-Sd .section textArea.textAreaFocus, .gt-Sd input[type=text].textAreaFocus {font-weight:normal; width: 95%}\n.gt-Sd .section .italic {font-style:italic; color:#7C7B76; font-size:0.85em}\n.gt-Sd .section .specialhighlight {color: #333; font-weight:bold; font-size: 103%;}\n.gt-Sd .section input[type='submit'] {margin-top: 4px; display: block}\n.gt-Sd .section .storyDescriptionTable .descriptionHeaderEdit {font-size: 8pt; width:1px; padding-right: 4px}\n.gt-Sd .section .storyDescriptionTable .lastCell {padding-left: 4px}\n.gt-Sd .section .notesTable {width: 100% }\n.gt-Sd .section .notesTable .italic {margin-left:8px }\n.gt-Sd .section tr.noteTextRow + tr.noteInfoRow > td.noteInfo {padding-top:7px }\n.gt-Sd .section .notesTable tr:first-child td, .gt-Sd .section .tasksTable tr:first-child td {padding-top: 4px; padding-bottom:4px;}\n.gt-Sd .section .tasksTable tr:hover td {background-color:#EBE29C}\n.gt-Sd .section .tasksTable td {padding:3px 5px 0px 0px}\n.gt-Sd .section .taskDescription input {width:100%}\n.gt-Sd .section .taskDescription {width:90%}\n.gt-Sd .section .taskDescription:hover {cursor: pointer}\n.gt-Sd .section .task_editing {margin-left: 8px}\n.gt-Sd .section .task_editing + .task_editing {margin-left: 5px}\n.gt-Sd .section .tasksTable .completed {color: #999}\n.gt-Sd .section table td {border-bottom:none;}\n.gt-Sd .section table td.resource_details_cell {vertical-align: top; padding-left: 15px}\n.gt-Sd .section table td.imageCell {text-align: center; width: 75px}\n.gt-Sd .section .resource_image {cursor:pointer}\n.gt-Sd .section table span.resource_row_span{ padding-right: 0.5em}\n.gt-Sd .section .attachments a.cancelLink {padding-left: 1em}\n.gt-Sd .section .attachments .attachmentHint {font-size: 90%; color: #ff6600; font-weight: bold}\n.gt-Sd .section.storyIdTable {border-spacing: 0px 0; border-collapse: separate; width: 100%}\n.gt-Sd .section.storyIdTable .storyId {font-size: 110%; padding-left: 4px}\n.help.flyover {background:url(/images/bg_gradient_comments_hover.gif) #FFF repeat-x scroll left top; border:1px solid #5593D8; -moz-border-radius: 8px; -webkit-border-radius: 8px; padding: 8px}\n.help.flyover .storyTitle {font-size: 1em; font-weight: bold; margin: 3px 0}\n.overlayContentWrapper.gt-Sfo.flyover {padding: 0}\n/*.gt-Sfo.flyover {background: url('/images/flyover_gray_gradient.png') #FDFDFD top left repeat-x; padding: -15px;}*/\n.gt-Sfo.flyover .storyTitle {background: url('/images/flyover_blue_gradient.png') #FFF top left repeat-x; font-size: 1.15em; font-weight: bold; margin-top:0.3em; padding-bottom:0.75em; padding-left:0.5em; padding-top:0.2em;}\n.gt-Sfo.flyover .gt-Ifc {font-size: 0.9em; background: #fff; padding: 0; -moz-border-radius-bottomleft: 8px; -webkit-border-bottom-left-radius: 8px; -moz-border-radius-bottomright: 8px; -webkit-border-bottom-right-radius: 8px}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .section {margin-bottom: 12px; margin-top: 0px}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .section + .section {margin-top: 13px; margin-bottom: 4px}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .section .header{ background: url('/images/flyover_blue_gradient.png') #FFF top left repeat-x; padding-left: 1em; line-height: 1.7em; font-size: 106%; color: #333; font-weight: bold; letter-spacing: 0.01em; margin-bottom:5px}\n.gt-Sfo.flyover .gt-Sd .section .notesTable tr:first-child td, .gt-Sfo.flyover .gt-Sd .section .tasksTable tr:first-child td {padding-top: auto}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd table, .gt-Sfo.flyover .gt-Ifc.gt-Sd .descriptionText {margin: 0 1.9em 0 1.9em; border-bottom:none;}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .tasksTable td {width: auto; padding: 2px 0px; border-bottom:none;}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .tasksTable td.taskPosition {width: 4%}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .tasksTable tr:hover td {background-color: inherit}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .tasksTable .taskDescription:hover {cursor: auto}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .section table td.resource_details_cell {padding-top: 8px}\n.gt-Sfo.flyover .storyId, .gt-Sfo.flyover .metaInfo {color:#888888; font-size:0.85em;}\n.gt-Sfo.flyover .storyId {font-weight: normal; margin-right: 12px}\n.gt-Sfo.flyover .metaInfo {margin: -0.6em 1.1em 0.5em; padding:2px;}\n.gt-Sfo.flyover .metaInfo .infoSection {color: #666666; font-weight: bold}\n.gt-Sfo.flyover .metaInfo .infoSection img {display: block; padding-top: 1px; padding-right: 3px}\n.gt-Sfo.flyover .metaInfo .infoSection img.estimateIcon {margin-top: 4px; margin-right: 3px}\n.gt-Sfo.flyover .metaInfo .infoSection .text {vertical-align: middle}\n.gt-Sfo.flyover .metaInfo .infoSection + .infoSection {margin-right: 6px}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .section .notesTable {width: auto}\n\n/*.noteText {line-height: 11px;}*/\n\n.overlay {overflow: hidden; font-size: 0.9em;margin-left: -12px; margin-top: -12px;}\n.overlayContentWrapper {padding: 0 1em}\n\n.gt-SdRow .fieldLabel {margin-left: 5px}\n.gt-SdDiv div {display: block; float: left}\n.storyButtonsRow, .gt-SdRow {clear: both; width: 400px}\n.storyButtonsRow {margin-top: 10px; margin-bottom: 10px}\n.storyButtonsRow div {margin-right: 10px}\n.storyDeadlineField {font: normal 12px verdana, sans-serif; line-height: 20px}\n.spacerCell {width:99%}\n.emphasizedFieldLabel {display:inline;}\n.fieldLabel {display:inline; color:gray}\n.gt-SdField, .storyDeadlineField, .gt-SdTextField {width: 200px; margin-top: 1px; margin-bottom: 1px; margin-right: 8px;}\n.gt-SdTextField{ width: 146px}\n.gt-SdStoryLink {width: 95%; margin-top: 1px; margin-bottom: 1px; margin-right: 10px; padding: 5px}\n.gt-Sd .storyLabels {padding-left: 5px}\n.dateChangeLink {margin-left: 3px}\n.inlinePopup {background-color: #ffffff; border: green 2px solid; overflow: auto; width: 20em; margin: 5px; text-align: center; z-index: 3000}\n.stateChangeButton, .disabledStateChangeButton {margin-left: 4px; vertical-align: bottom}\n.disabledStateChangeButton {opacity: 0.6; -moz-opacity: 0.6; filter: alpha(opacity=60)}\n.stateChangeButton {cursor: pointer; width: auto}\n.estimateButton {border-bottom: 1px solid #888; margin-left: 4px; padding-bottom: 2px; vertical-align: bottom; cursor: pointer}\n.toggleExpandedButton, .gt-IihToggleExpandedButton {vertical-align: middle; cursor: pointer; margin-right: 4px; padding-top: 2px; float: left}\n.gt-IihToggleExpandedButton {display: inline; width:11px; height:16px}\n.gt-IihInfo {margin-left: 19px}\n\n.gt-Iih {\nbackground:url(\"/images/bg_iteration.png\") repeat-x scroll center top #747474;\ncolor:white;\ncursor:default;\npadding-left:0;\npadding-right:0;\n}\n.gt-Iih a.date_label {\ncolor:#FFFFFF !important;\ncursor:pointer;\n}\n.gt-Iih a.date_label.overridden {\ncolor:#FFCC44 !important;\n}\n.gt-Iih a.date_label:hover {\ntext-decoration:underline !important;\n}\n.gt-IihInfo {\n-moz-user-select:none;\n}\n\n\n.lastCell {width:95%}\n.item {border-top: 1px solid #6E6E6E}\n.item.proxy {font-size: 0.8em}\n.items, .search {height: 100%; overflow-y: auto; overflow-x: hidden; position: relative}\n.no_xscroll {overflow-x: hidden; padding-bottom: 15px}\n.no_yscroll {overflow-y: hidden; padding-right: 15px}\n.helpIcon {padding: 2px;}\n.titleInputField {width: 94%; font-size: 11pt; max-width:480px;}\n\n\n/*Buttons*/\n\n.pri_button{\n  width:13px;\n  height:21px;\n  text-align:center;\n  float:right;\n  font-weight: bold;\n/*  color: white;*/\n  padding-left:12px;\n  vertical-align:middle;\n}\n\n.pri_button_no_float{\n  width:13px;\n  height:21px;\n  text-align:center;\n/*  float:right;*/\n  font-weight: bold;\n/*  color: white;*/\n  padding-left:12px;\n  vertical-align:middle;\n}\n\n.pri_button_action{\n  padding-left:20px;\n}\n\n.pri_button_up{\n  background: url(/images/up_arrow.png) no-repeat;\n\n}\n\n.pri_button_down{\n  background: url(/images/down_arrow.png) no-repeat;\n}\n\n.pri_button_neutral{\n  background: url(/images/neutral_arrow.png) no-repeat;\n}\n\n.pri_button_none{\n  background: url(/images/none_arrow.png) no-repeat;\n}\n\n.action_button_start{\n  background: url(/images/bb_grey.png) no-repeat;\n/*  background: url(/images/bb_sky.png) no-repeat; */\n}\n\n.action_button_start_no_hide{\n  background: url(/images/bb_sky.png) no-repeat;\n}\n\n.action_button_root{\n  background: url(/images/bb_orange.png) no-repeat;\n}\n\n.action_button_finish{\n  background: url(/images/bb_grey.png) no-repeat;\n/*  background: url(/images/bb_sky.png) no-repeat; */\n}\n\n.action_button_join{\n  background: url(/images/bb_grey.png) no-repeat;\n/*  background: url(/images/bb_sky.png) no-repeat; */\n}\n\n.action_button_accept{\n  background: url(/images/bb_green.png) no-repeat;\n}\n\n.action_button_reject{\n  background: url(/images/bb_red.png) no-repeat;\n}\n\n.action_button_restart{\n  background: url(/images/bb_sky.png) no-repeat;\n}\n\n.action_button_estimate{\n  background: url(/images/bb_orange.png) no-repeat;\n/*  background: url(/images/bb_sky.png) no-repeat; */\n/*  background: url(/images/bb_blue.png) no-repeat; */\n}\n\n.action_button_agree{\n  background: url(/images/bb_green.png) no-repeat;\n}\n\n.action_button_neutral{\n  background: url(/images/bb_grey.png) no-repeat;\n}\n\n.action_button_against{\n  background: url(/images/bb_red.png) no-repeat;\n}\n\n.action_button_disagree{\n  background: url(/images/bb_red.png) no-repeat;\n}\n\n\n.action_button_block{\n  background: url(/images/bb_darkred.png) no-repeat;\n}\n\n.action_button_release{\n  background: url(/images/bb_grey.png) no-repeat;\n/*  background: url(/images/bb_red.png) no-repeat; */\n}\n\n.action_button_leave{\n  background: url(/images/bb_grey.png) no-repeat;\n/*  background: url(/images/bb_red.png) no-repeat; */\n}\n\n.action_button_takeback{\n  background: url(/images/bb_grey.png) no-repeat;\n/*  background: url(/images/bb_red.png) no-repeat; */\n}\n\n.action_button_cancel{\n  width:20px!important;\n  background: url(/images/dash_cancel.png) no-repeat;\n  background-position: 0px 3px!important;\n}\n\n.action_button_tally{\n  font-weight:bold;\n  color: #000;\n/*  background: url(/images/bb_blank.png) no-repeat; */\n  width:60px;\n  height:21px;\n  text-align:center;\n  vertical-align:middle;\n  cursor:pointer;\n  float: right;\n  font-size:85%;\n  font-weight:bold;\n}\n\n.action_button_retro{\n  background: url(/images/bb_purple.png) no-repeat;\n}\n\n\n.action_button_accepted{\n  font-weight:bold;\n  color: #000;\n}\n\n.action_button_rejected{\n  font-weight:bold;\n  color: #000;\n}\n\n\n.action_button a, .action_button a:hover, .action_button a:visited {\n  font-size: 11px;\n  color: #ffffff;\n  line-height: 20px;\n}\n\n.action_button a:hover {\n  text-decoration:underline;\n}\n\n#todo_lightbox .tasksTable{\n  margin: 0 0 0 0px;\n}\n\n#todo_lightbox td {\n  padding: 2px;\n}\n\n#todo_lightbox .header {\n  font-weight: bold;\n}\n\n.updating {\n  padding-left: 17px;\n  background-position: 0% 40%;\n  background-repeat: no-repeat;\n  background-image: url(/images/loading.gif);\n}\n\n.spark {\n  display: none;\n}\n\n.spark-top{\n  padding-top:5px;\n  padding-right:5px;\n  padding-left:5px;\n}\n\n.project-summary h5{\n  font-size: 100%;\n  margin-bottom: 5px;\n  font-weight: bold;\n  color: #777;\n}\n\n.project-summary .spark{\n  margin-top: 12px;\n}\n\n.gt-table-links{\n  text-align: center;\n}\n\n.activity-sub .author, .activity-sub .verb{\n  font-weight: bold;\n}\n\n.gt-activity-details{\n  padding-left: 0px!important;\n}\n\n.gt-activity-table tr:hover {\n/*  background-color: #EBEBEB;*/\n}\n.gt-activity-table tr:hover td {\n/*  background-color: #EBEBEB;*/\n/*  background-color: #f4f7f8;*/\n/*  background-color: none!important;*/\n}\n\n.gt-activity-table td {\n  border-top:none;\n}\n\n.gt-activity-table td.refresh {\n  padding-top:1px;\n  padding-right:1px;\n  padding-bottom:0px;\n  text-align:right;\n}\n\n\n.activity-sub tr:hover td {\n/*  background-color: #f4f7f8;*/\n/*  background-color: none!important;*/\n}\n\n.gt-activity-detail td{\n  border-bottom: 1px solid #e4e4e4;\n  padding-top:3px;\n  padding-right:5px;\n  padding-bottom:3px;\n}\n\n.gt-activity-detail td.main{\n  padding-bottom:20px;\n}\n\n.gt-activity-detail td.gt-avatar{\n  border-top:none;\n  padding-top:6px;\n  padding-right:0px;\n  padding-bottom:6px;\n}\n\n\n.gt-activity-header td{\n  padding-bottom: 0px;\n}\n\n\n\n/***** Icons *****/\n.icon {\nbackground-position: 0% 50%;\nbackground-repeat: no-repeat!important;\npadding-left: 20px;\npadding-top: 2px;\npadding-bottom: 3px;\n}\n\nh2.icon {\n  padding-bottom:0px;\n}\n.icon-x {background: url(/images/cross.png); }\n.icon-refresh {background: url(/images/refresh.png);}\n.icon-key {background: url(/images/key.png); }\n.icon-news { background-image: url(/images/news.png); }\n.icon-add { background-image: url(/images/add.png); }\n.icon-bullet-add { background-image: url(/images/bullet_add.png); }\n.icon-bullet-delete { background-image: url(/images/bullet_delete.png); }\n.icon-edit { background-image: url(/images/edit.png); }\n.icon-copy { background-image: url(/images/copy.png); }\n.icon-duplicate { background-image: url(/images/duplicate.png); }\n.icon-del { background-image: url(/images/delete.png); }\n.icon-move { background-image: url(/images/move.png); }\n.icon-save { background-image: url(/images/save.png); }\n.icon-cancel { background-image: url(/images/cancel.png); }\n.icon-multiple { background-image: url(/images/table_multiple.png); }\n.icon-folder { background-image: url(/images/folder.png); }\n.open .icon-folder { background-image: url(/images/folder_open.png); }\n.icon-package { background-image: url(/images/package.png); }\n.icon-home { background-image: url(/images/home.png); }\n.icon-user { background-image: url(/images/user.png); }\n.icon-users { background-image: url(/images/group.png); }\n.icon-projects { background-image: url(/images/projects.png); }\n.icon-project { background-image: url(/images/projects.png); }\n.icon-issues { background-image: url(/images/ticket.png); }\n.icon-help { background-image: url(/images/help.png); }\n.icon-attachment  { background-image: url(/images/attachment.png); }\n.icon-history  { background-image: url(/images/history.png); }\n.icon-time  { background-image: url(/images/time.png); }\n.icon-time-add  { background-image: url(/images/time_add.png); }\n.icon-stats  { background-image: url(/images/stats.png); }\n.icon-warning  { background-image: url(/images/warning.png); }\n.icon-fav  { background-image: url(/images/fav.png); }\n.icon-fav-off  { background-image: url(/images/fav_off.png); }\n.icon-reload  { background-image: url(/images/reload.png); }\n.icon-lock  { background-image: url(/images/locked.png); }\n.icon-unlock  { background-image: url(/images/unlock.png); }\n.icon-checked  { background-image: url(/images/true.png); }\n.icon-details  { background-image: url(/images/zoom_in.png); }\n.icon-report  { background-image: url(/images/report.png); }\n.icon-comment  { background-image: url(/images/comment.png); }\n.icon-cr-cancel  { background-image: url(/images/cancel16.png); }\n.icon-cr-request { background-image: url(/images/tag_blue.png); }\n.icon-cr-take { background-image: url(/images/wrench.png); }\n.icon-cr-offer { background-image: url(/images/user_go.png); }\n.icon-cr-accept { background-image: url(/images/true.png); }\n.icon-cr-decline { background-image: url(/images/false.png); }\n.icon-cr-ignore { background-image: url(/images/ignore.gif); }\n.icon-summary  { background-image: url(/images/lightning.png); }\n.icon-dashboard { background-image: url(/images/lightning.png); }\n.icon-activate { background-image: url(/images/true.png); }\n.icon-deactivate { background-image: url(/images/false.png); }\n.icon-motion{ background-image: url(/images/motion.png); }\n.icon-activity{ background-image: url(/images/weather_lightning.png); }\n\n.icon-file { background-image: url(/images/files/default.png); }\n.icon-file.text-plain { background-image: url(/images/files/text.png); }\n.icon-file.text-x-c { background-image: url(/images/files/c.png); }\n.icon-file.text-x-csharp { background-image: url(/images/files/csharp.png); }\n.icon-file.text-x-php { background-image: url(/images/files/php.png); }\n.icon-file.text-x-ruby { background-image: url(/images/files/ruby.png); }\n.icon-file.text-xml { background-image: url(/images/files/xml.png); }\n.icon-file.image-gif { background-image: url(/images/files/image.png); }\n.icon-file.image-jpeg { background-image: url(/images/files/image.png); }\n.icon-file.image-png { background-image: url(/images/files/image.png); }\n.icon-file.image-tiff { background-image: url(/images/files/image.png); }\n.icon-file.application-pdf { background-image: url(/images/files/pdf.png); }\n.icon-file.application-zip { background-image: url(/images/files/zip.png); }\n.icon-file.application-x-gzip { background-image: url(/images/files/zip.png); }\n\n.icon-feature{ background-image: url(/images/feature_icon.png); }\n.icon-bug{ background-image: url(/images/bug_icon.png); }\n.icon-chore{ background-image: url(/images/chore_icon.png); }\n.icon-recurring{ background-image: url(/images/recurring_icon.png); }\n.icon-gift{ background-image: url(/images/gift_icon.png); }\n.icon-expense{ background-image: url(/images/expense_icon.png); }\n\n\n/***** Ajax indicator ******/\n#ajax-indicator {\nposition: absolute; /* fixed not supported by IE */\nbackground-color:#eee;\nborder: 1px solid #bbb;\ntop:35%;\nleft:40%;\nwidth:20%;\nfont-weight:bold;\ntext-align:center;\npadding:0.6em;\nz-index:100;\nfilter:alpha(opacity=70);\nopacity: 0.7;\n}\n\nhtml>body #ajax-indicator { position: fixed; }\n\n#ajax-indicator span {\nbackground-position: 0% 40%;\nbackground-repeat: no-repeat;\nbackground-image: url(/images/loading.gif);\npadding-left: 26px;\nvertical-align: bottom;\n}\n\n/***** Diff *****/\n.diff_out { background: #fcc; }\n.diff_in { background: #cfc; }\n\n/***** Wiki *****/\n.wiki {\n  padding: 15px;\n}\n.wiki h1 {\n  margin-bottom:30px;\n  margin-top:5px;\n}\n\ndiv.wiki table {\n    border: 1px solid #505050;\n    border-collapse: collapse;\n    margin-bottom: 1em;\n}\n\ndiv.wiki table, div.wiki td, div.wiki th {\n    border: 1px solid #bbb;\n    padding: 4px;\n}\n\ndiv.wiki .external {\n    background-position: 0% 60%;\n    background-repeat: no-repeat;\n    padding-left: 12px;\n    background-image: url(/images/external.png);\n}\n\ndiv.wiki a.new {\n    color: #b73535;\n}\n\ndiv.wiki pre {\n    margin: 1em 1em 1em 1.6em;\n    padding: 2px;\n    background-color: #fafafa;\n    border: 1px solid #dadada;\n    width:95%;\n    overflow-x: auto;\n}\n\ndiv.wiki ul.toc {\n    background-color: #ffffdd;\n    border: 1px solid #e4e4e4;\n    padding: 4px;\n    line-height: 1.2em;\n    margin-bottom: 12px;\n    margin-right: 12px;\n    margin-left: 0;\n    display: table\n}\n* html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */\n\ndiv.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }\ndiv.wiki ul.toc.left  { float: left; margin-right: 12px; margin-left: 0; width: auto; }\ndiv.wiki ul.toc li { list-style-type:none;}\ndiv.wiki ul.toc li.heading2 { margin-left: 6px; }\ndiv.wiki ul.toc li.heading3 { margin-left: 12px; font-size: 0.8em; }\n\ndiv.wiki ul.toc a {\n    font-size: 0.9em;\n    font-weight: normal;\n    text-decoration: none;\n    color: #606060;\n}\ndiv.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}\n\na.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }\na.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }\nh1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }\n\n\n/*JGROWL*/\n\ndiv.jGrowl {\n  padding:       10px;\n  z-index:       9999;\n  color:         #fff;\n  font-size:       12px;\n}\n\n/** Special IE6 Style Positioning **/\ndiv.ie6 {\n  position:       absolute;\n}\n\ndiv.ie6.top-right {\n  right:         auto;\n  bottom:       auto;\n  left:         expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n    top:         expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.top-left {\n  left:         expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.bottom-right {\n  left:         expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.bottom-left {\n  left:         expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.center {\n  left:         expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n  width:         100%;\n}\n\n/** Normal Style Positions **/\nbody > div.jGrowl {\n  position:      fixed;\n}\n\nbody > div.jGrowl.top-left {\n  left:         0px;\n  top:         0px;\n}\n\nbody > div.jGrowl.top-right {\n  right:         0px;\n  top:         0px;\n}\n\nbody > div.jGrowl.bottom-left {\n  left:         0px;\n  bottom:        0px;\n}\n\nbody > div.jGrowl.bottom-right {\n  right:         0px;\n  bottom:       0px;\n}\n\nbody > div.jGrowl.center {\n  top:         0px;\n  width:         50%;\n  left:         25%;\n}\n\n/** Cross Browser Styling **/\ndiv.center div.jGrowl-notification, div.center div.jGrowl-closer {\n  margin-left:     auto;\n  margin-right:     auto;\n}\n\ndiv.jGrowl div.jGrowl-notification, div.jGrowl div.jGrowl-closer {\n  background-color:     #d30921;\n/*  opacity:         .85;*/\n    -ms-filter:       \"progid:DXImageTransform.Microsoft.Alpha(Opacity=85)\";\n    filter:         progid:DXImageTransform.Microsoft.Alpha(Opacity=85);\n  zoom:           1;\n  width:           235px;\n  padding:         10px;\n  margin-top:       5px;\n  margin-bottom:       5px;\n  font-family:       Tahoma, Arial, Helvetica, sans-serif;\n  font-size:         1em;\n  text-align:       left;\n  display:         none;\n  -moz-border-radius:   5px;\n  -webkit-border-radius:  5px;\n}\n\ndiv.jGrowl div.jGrowl-notification {\n  min-height:       40px;\n}\n\ndiv.jGrowl div.jGrowl-notification div.header {\n  font-weight:       bold;\n  font-size:        .85em;\n}\n\ndiv.jGrowl div.jGrowl-notification div.close {\n  z-index:        99;\n  float:           right;\n  font-weight:       bold;\n  font-size:         1em;\n  cursor:          pointer;\n}\n\ndiv.jGrowl div.jGrowl-closer {\n  padding-top:       4px;\n  padding-bottom:     4px;\n  cursor:         pointer;\n  font-size:        .9em;\n  font-weight:       bold;\n  text-align:       center;\n}\n\n/** Hide jGrowl when printing **/\n@media print {\n  div.jGrowl {\n    display:       none;\n  }\n}\n\n\n/*Retrospectives*/\n\ntable.retrospective {margin-bottom: 30px;}\ntable.retrospective th { vertical-align: top; text-align: left; }\ntable.retrospective td {padding: 3px;border-bottom:none;}\ntable.retrospective td.avatar { vertical-align: top; padding-right: 5px; text-align: center;}\ntable.retrospective td.name { vertical-align: top; padding-right: 5px; width:3em}\ntable.retrospective td.stats { vertical-align: top; border-left-width: 1px; border-left-style:solid; padding-left: 10px; width: 10em;}\ntable.retrospective td.accuracy { vertical-align: top; border-left-width: 1px; border-left-style:solid; padding-left: 10px; width: 10em;}\ntable.retrospective td.percentage { vertical-align: middle; border-left-width: 1px;  font-size: 2em; border-left-style:solid; padding-left: 15px; width: 4em;text-align:center;}\ntable.retrospective td.percentage div.slider { vertical-align: bottom; border-left-width: 0px;  font-size: 0.5em; padding-left: 10px; width: 10em; margin-top:4px;}\ntable.retrospective td.total { vertical-align: top; border-left-width: 0px;  font-size: 2em; border-left-style:solid; padding-left: 10px; width: 4em;text-align:center;}\ntable.retrospective td.button { vertical-align: bottom; border-left-width: 0px;  border-left-style:solid; padding-left: 4px; width: 70px;text-align:center;}\ntable.retrospective td.title { vertical-align: top; border-left-width: 0px;  font-size: 1em; border-left-style:solid; padding-left: 10px; width: 4em;text-align:center;font-weight:bold;}\ntable.retrospective td.subtitle { width: 5em; vertical-align: top; border-left-width: 0px;  font-size: 1em; padding-left: 2em; text-align:right;}\n\n/*Forms*/\n\n/* Default Form */\n/* Form Style */\n\n/*form ul li {\n  margin: 0 0 15px;\n  padding: 0;\n  list-style: none;\n}\n*/\n\nform label {\n  font-size: 100%;\n  color: #365b6d;\n  display: block;\n  margin-bottom: 3px;\n  font-weight: bold;\n}\n\nform option {\n  font-size: 108%;\n}\n\nform label.note {\n  color: #444;\n  font-weight: normal;\n  font-size: 10px;\n}\n\nlabel.choice {\n  margin: 0 15px 0 0;\n  font-weight: normal;\n  font-size: 12px;\n  color: #666;\n}\n\nform input[type=text],\nform input[type=password],\nform textarea {\n  border: 1px solid #ccc;\n  background-color: #f4f7f8;\n  padding: 5px 2px;\n  font-size: 108%;\n  width: 99%;\n}\n\nform input[type=text]:focus,\nform input[type=password]:focus,\nform textarea:focus {\n  background-color: #fff;\n}\n\nform input[type=submit] {\n  margin: 0 10px 0 0;\n  float: left;\n  display: inline;\n  height: 38px;\n  line-height: 38px;\n  text-align: center;\n  font-weight: bold;\n  color: #fff;\n  text-decoration: none;\n  font-size: 13px;\n  border: none;\n  padding: 0;\n  margin: 0;\n  width: 126px;\n  background: url(/images/gt/btn-gray-medium.png) no-repeat 0 0 transparent;\n}\n\n.gt-table-buttons-inside input[type=submit]{\n  float: right;;\n}\n\nform input[type=radio],\nform input[type=checkbox] {\n  margin-right: 3px;\n}\n\nform input[type=select] {\n  font-size: 12px;\n  margin: 5px 5px 0 0;\n  border: 1px solid #d2d2d2;\n}\n\nform input.short { width: 20%;}\nform input.medium { width: 45%;}\nform input.long { width:70%;}\nform input.max { width: 95%;}\n\nform .gt-content-box {\n  padding: 15px 15px 5px 15px;\n  margin-bottom: 40px;\n  max-width: 800px;\n}\n\nform .gt-cancel {\n  line-height: 37px;\n  margin-bottom: 0;\n  margin-left: 20px;\n  float: left;\n}\n\n\n\nform p {\n  margin-bottom: 10px;\n  width: 80%;\n}\n\n\n/********** Search form **************/\n.search-form label {\n  display: inline;\n}\n\n.search-form input[type=\"text\"] {\n  width: 50%;\n}\n\n.search-form input[type=\"submit\"] {\n  float: none;\n  margin: 10px;\n}\n\n.search-form {\n  width: 100%;\n}\n\n.search-form .gt-content-box {\n  max-width: 100%;\n  margin-bottom: 15px;\n}\n\n/*********** Attachment form ***************/\n#attachments_fields input[type=\"text\"] {\n/*  width: 50%;*/\n}\n\n\n\n/*TEMP*/\n.contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;margin-right:10px;}\n.contextual input, .contextual select {font-size:0.9em;}\n.message .contextual { margin-top: 0; }\n\n\n/*Admin Menu*/\n#admin-menu ul {margin: 0;  padding: 0;}\n#admin-menu li {margin: 0;  padding: 0 0 12px 0; list-style-type:none;}\n\n#admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;}\n#admin-menu a.projects { background-image: url(/images/projects.png); }\n#admin-menu a.users { background-image: url(/images/user.png); }\n#admin-menu a.groups { background-image: url(/images/group.png); }\n#admin-menu a.roles { background-image: url(/images/database_key.png); }\n#admin-menu a.trackers { background-image: url(/images/ticket.png); }\n#admin-menu a.issue_statuses { background-image: url(/images/ticket_edit.png); }\n#admin-menu a.workflows { background-image: url(/images/ticket_go.png); }\n#admin-menu a.custom_fields { background-image: url(/images/textfield.png); }\n#admin-menu a.enumerations { background-image: url(/images/text_list_bullets.png); }\n#admin-menu a.settings { background-image: url(/images/changeset.png); }\n#admin-menu a.plugins { background-image: url(/images/plugin.png); }\n#admin-menu a.info { background-image: url(/images/help.png); }\n\n/*Tabs*/\n\n.tabs {height: 2.6em; border-bottom: 1px none #bbbbbb; margin-bottom:0em; position:relative; overflow:hidden;}\n.tabs ul {margin:0; position:absolute; bottom:-2px; padding-left:1em; width: 2000px;}\n.tabs>ul { bottom:-1px; } /* others */\n.tabs ul li {\nfloat:left;\nlist-style-type:none;\nwhite-space:nowrap;\nmargin-right:8px;\nbackground:#fff;\n}\n.tabs ul li a{\ndisplay:block;\nfont-size: 0.9em;\ntext-decoration:none;\nline-height:1.3em;\npadding:4px 6px 4px 6px;\nborder: 1px solid #ccc;\nborder-bottom: 0px solid #bbbbbb;\n/*background-color: #eeeeee;*/\n/*color:#777;*/\nbackground-color: #555;\ncolor: #EEE;\nfont-weight:bold;\n}\n\n.tabs ul li a:hover {\n/*background-color: #ffffdd;*/\nbackground-color: #888;\ntext-decoration:none;\n}\n\n.tabs ul li a.selected {\nbackground-color: #fff;\nborder: 1px solid #bbbbbb;\nborder-bottom: none;\n/*color: #EEE;*/\ncolor:#777\n}\n\n.tabs ul li a.selected:hover {\nbackground-color: #eeeeee;\n}\n\ndiv.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: -1px;  }\n\nbutton.tab-left, button.tab-right {\n  font-size: 0.9em;\n  cursor: pointer;\n  height:24px;\n  border: 1px solid #ccc;\n  border-bottom: 1px solid #bbbbbb;\n  position:absolute;\n  padding:4px;\n  width: 20px;\n}\n\nbutton.tab-left {\n  right: 20px;\n  bottom: 0;\n  background: #eeeeee url(/images/bullet_arrow_left.png) no-repeat 50% 50%;\n}\n\nbutton.tab-right {\n  right: 0;\n  bottom: 0;\n  background: #eeeeee url(/images/bullet_arrow_right.png) no-repeat 50% 50%;}\n}\n\n/*Breadcrumbs*/\np.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}\n\n.highlight { background-color: #FCFD8D;}\n.highlight.token-1 { background-color: #faa;}\n.highlight.token-2 { background-color: #afa;}\n.highlight.token-3 { background-color: #aaf;}\n.search-highlight { background-color: #FCFD8D;font-weight:bold;}\n\n/***** Search Results *******/\n#search-results { margin-left: 2em; }\n#search-results dd { margin-bottom: 1em; padding-left: 8px; font-size: 0.9em; }\n#search-results dt { margin-bottom: 0px; padding-left: 10px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }\n#search-results dd .description { font-style: italic; }\n#search-results span.project:after { content: \" -\"; }\n#search-results dd span.description { display:block; color: #808080; }\n\n#search-results dd { margin-bottom: 1em; padding-left: 10px; margin-left:0px; }\n\ndiv#search-results-counts {float:right;}\ndiv#search-results-counts ul { margin-top: 0.5em; }\ndiv#search-results-counts  li { list-style-type:none; float: left; margin-left: 1em; }\n\n\n/******* MISC ************/\n.nodata {\n  margin: 20px;\n  text-align: center;\n  border-width: 0px;\n}\n\n\nwbr:after { content: \"\\00200B\" } /*opera compatibility with wbr*/\n\n#jumpbox{\n  background: #323232;\n  font-weight: bold;\n}\n\n#project_jumpbox{\n  font-weight: bold;\n  font-size: 0.5em;\n  margin-left: 1em;\n  vertical-align: middle;\n/*  background: transparent;*/\n}\n\n#new_item_jumpbox {\n  background-image: url(/images/add.png);\n  background-repeat: no-repeat;\n  background-position: 4px 3px;\n  text-indent: 16px;\n  height: 22px;\n  border: none;\n  background-color: #E58508;\n  font-weight: bold;\n  color: #FFF;\n}\n\n.activity-comment {\n  width:95%;\n  color:#bbb;\n}\n\n.gt-content {\n  min-height: 300px;\n}\n\n.signup-header{\n  font-family: 'lucida grande',Verdana,sans-serif;\n  color: #333;\n  font-weight: normal;\n  font-size: 1.4em;\n  padding: 7px;\n  text-align: center;\n  width: 100%;\n}\n\n.percentage_label_confidence{\n  font-size: 50%;\n}\n\nform input[type=\"text\"].verification-code {\n  width: auto;\n  margin-right: 10px;\n}\n\n.centered{\n  text-align: center;\n}\n\n.activity-bottom{\n  text-align: center;\n  width: 100%;\n  font-size: 120%;\n  padding-top: 20px;\n  padding-bottom: 20px;\n}\n\nimg.private-workstream, img.volunteer-workstream{\n  margin-left:5px;\n  margin-right:5px;\n}\n\n.help-section {\n/*  border: 3px solid #aaa;*/\n  padding: 1em 1em 1em 1em;\n/*  margin-bottom: 1.5em;*/\n  background-color: #F6EABB;\n/*  background-color: #FEFF6F;*/\n/*  width: 100%;*/\n  display: block;\n  width: 600px;\n}\n\n.help-section h3{\n  float:left;\n}\n\n.help-section p{\n  font-size: 115%;\n  margin-bottom: 0px;\n  padding-top: 1em;\n}\n\n.help-section a.help-section-link{\n  float:right;\n  padding: 3px 1em 0em 1em;\n  font-weight: bold;\n}\n\n#dash_main .help-section {\n  margin: 1em 1em 1.5em 1em;\n}\n\n\n.image-url{\n  width: 60%;\n}\n\n.learn-more{\n  border-top: 1px solid;\n  padding: 10px;\n  text-align:center;\n  vertical-align:middle;\n}\n\n.notification h4{\n  padding-bottom:10px;\n}\n\n.clip-notice {\n  padding:.8em;\n  margin-bottom:1em;\n  border:1px solid #ddd;\n  clear: both;\n  background: #f5f5f5 url(/images/static/clip.png) no-repeat 10px 50% ;\n  color:#595959;\n  border-color:#d9d9d9;\n  text-shadow: 1px 1px #fff;\n  padding:1.4em 1.4em 1.4em 4em;\n/*  text-align:center;*/\n}\n\n.generic-link-reset{\n  float:right;\n}\n.generic-link-text{\n  padding:10px;\n}\n\n.notification-unresponded{\n  padding-left: 20px;\n  background-position: 0% 20%;\n  background-repeat: no-repeat;\n  background-image: url(/images/email.png);\n  font-weight:bold;\n}\n\n.floating-h-link{\n  font-size:60%;\n  padding-left:13px;\n  padding-top:5px;\n  vertical-align:top;\n}\n\n.ui-menu .ui-menu-item a{\n  float: left;\n}\n\n\n\n.ui-menu-item img{\n  vertical-align: middle;\n  padding-top: 3px;\n  float: left;\n\n}\n\n.ui-menu ul li{\n  list-style-type: none;\n}\n\n.small-text {\n  font-size: 85%;\n  font-weight: bold;\n  color: #666666;\n  border: none;\n}\n\n.show-more td{\n/*  padding-bottom: 0px;*/\n  padding-top: 10px;\n  text-align: center;\n  border-top:  1px solid #ccc;\n}\n.show-more a{\n  font-weight:bold;\n  font-size: 85%;\n}\n\n\n\n/*** ESSENTIAL STYLES ***/\n.sf-menu, .sf-menu * {\n  margin:      0;\n  padding:    0;\n  list-style:    none;\n}\n.sf-menu {\n  line-height:  1.0;\n}\n.sf-menu ul {\n  position:    absolute;\n  top:      -999em;\n  width:      10em; /* left offset of submenus need to match (see below) */\n}\n.sf-menu ul li {\n  width:      100%;\n}\n.sf-menu li:hover {\n  visibility:    inherit; /* fixes IE7 'sticky bug' */\n}\n.sf-menu li {\n  float:      left;\n  position:    relative;\n}\n.sf-menu a {\n  display:    block;\n  position:    relative;\n}\n.sf-menu li:hover ul,\n.sf-menu li.sfHover ul {\n  left:      0;\n  top:      2.5em; /* match top ul list item height */\n  z-index:    99;\n}\nul.sf-menu li:hover li ul,\nul.sf-menu li.sfHover li ul {\n  top:      -999em;\n}\nul.sf-menu li li:hover ul,\nul.sf-menu li li.sfHover ul {\n  left:      10em; /* match ul width */\n  top:      0;\n}\nul.sf-menu li li:hover li ul,\nul.sf-menu li li.sfHover li ul {\n  top:      -999em;\n}\nul.sf-menu li li li:hover ul,\nul.sf-menu li li li.sfHover ul {\n  left:      10em; /* match ul width */\n  top:      0;\n}\n\n/*** DEMO SKIN ***/\n.sf-menu {\n  float:      left;\n  margin-bottom:  1em;\n}\n.sf-menu a {\n  border-left:  1px solid #fff;\n  border-top:    1px solid #CFDEFF;\n  padding:     .75em 1em;\n  text-decoration:none;\n}\n.sf-menu a, .sf-menu a:visited  { /* visited pseudo selector so IE6 applies text colour*/\n  color:      #13a;\n}\n.sf-menu li {\n  background:    #BDD2FF;\n}\n.sf-menu li li {\n  background:    #AABDE6;\n}\n.sf-menu li li li {\n  background:    #9AAEDB;\n}\n.sf-menu li:hover, .sf-menu li.sfHover,\n.sf-menu a:focus, .sf-menu a:hover, .sf-menu a:active {\n  background:    #CFDEFF;\n  outline:    0;\n}\n\n/*** arrows **/\n.sf-menu a.sf-with-ul {\n  padding-right:   2.25em;\n  min-width:    1px; /* trigger IE7 hasLayout so spans position accurately */\n}\n.sf-sub-indicator {\n  position:    absolute;\n  display:    block;\n  right:      .75em;\n  top:      1.05em; /* IE6 only */\n  width:      10px;\n  height:      10px;\n  text-indent:   -999em;\n  overflow:    hidden;\n  background:    url('../images/arrows-ffffff.png') no-repeat -10px -100px; /* 8-bit indexed alpha png. IE6 gets solid image only */\n}\na > .sf-sub-indicator {  /* give all except IE6 the correct values */\n  top:      .8em;\n  background-position: 0 -100px; /* use translucent arrow for modern browsers*/\n}\n/* apply hovers to modern browsers */\na:focus > .sf-sub-indicator,\na:hover > .sf-sub-indicator,\na:active > .sf-sub-indicator,\nli:hover > a > .sf-sub-indicator,\nli.sfHover > a > .sf-sub-indicator {\n  background-position: -10px -100px; /* arrow hovers for modern browsers*/\n}\n\n/* point right for anchors in subs */\n.sf-menu ul .sf-sub-indicator { background-position:  -10px 0; }\n.sf-menu ul a > .sf-sub-indicator { background-position:  0 0; }\n/* apply hovers to modern browsers */\n.sf-menu ul a:focus > .sf-sub-indicator,\n.sf-menu ul a:hover > .sf-sub-indicator,\n.sf-menu ul a:active > .sf-sub-indicator,\n.sf-menu ul li:hover > a > .sf-sub-indicator,\n.sf-menu ul li.sfHover > a > .sf-sub-indicator {\n  background-position: -10px 0; /* arrow hovers for modern browsers*/\n}\n\n/*** shadows for all but IE6 ***/\n.sf-shadow ul {\n  background:  url('../images/shadow.png') no-repeat bottom right;\n  padding: 0 8px 9px 0;\n  -moz-border-radius-bottomleft: 17px;\n  -moz-border-radius-topright: 17px;\n  -webkit-border-top-right-radius: 17px;\n  -webkit-border-bottom-left-radius: 17px;\n}\n.sf-shadow ul.sf-shadow-off {\n  background: transparent;\n}\n\n/*** iphone switch http://devgrow.com/iphone-style-switches/ ***/\n\n.cb-enable, .cb-disable, .cb-enable span, .cb-disable span { background: url(/images/switch.gif) repeat-x; display: block; float: left; }\n.cb-enable span, .cb-disable span { line-height: 30px; display: block; background-repeat: no-repeat; font-weight: bold; }\n.cb-enable span { background-position: left -90px; padding: 0 10px; }\n.cb-disable span { background-position: right -180px;padding: 0 10px; }\n.cb-disable.selected { background-position: 0 -30px; }\n.cb-disable.selected span { background-position: right -210px; color: #fff; }\n.cb-enable.selected { background-position: 0 -60px; }\n.cb-enable.selected span { background-position: left -150px; color: #fff; }\n.switch label { cursor: pointer; }\n.switch input { display: none; }\n"
  },
  {
    "path": "public/stylesheets/headerandfooter.css",
    "content": "/************************************************************************\n2.- General Structure\n************************************************************************/\n#page {\n  background:#f3f3f3 url(/images/static/background.jpg) repeat-x;\n}\n#inner-page {\n  background:#f3f3f3 url(/images/static/inner-background.jpg) repeat-x;\n}\n#header {\n  height:63px;\n  position:relative;\n  z-index:999\n}\n#logo a {\n  display:block;\n  background-image: url(/images/static/logo.png);\n  height:48px;\n  width:194px;\n  text-indent:-9999px;\n  margin-top:8px\n}\n\n#logo_app {\n  display:block;\n  background: no-repeat;\n  background-image: url(/images/static/logo_app.png);\n  height:22px;\n  width:157px;\n  text-indent:-9999px;\n  margin-left:6px;\n  float:left;\n  vertical-align:top;\n}\n\n/************************************************************************\nMain Navigation\n************************************************************************/\nul#topnav {\n  padding: 0 0;\n  width: 690px;  /*Change this if you want a bigger nav*/\n  font-size: 1.2em;\n  text-align:center;\n  margin: 19px 0 19px 200px;\n  list-style: none;\n}\n/*ul#topnav .subnav {display:none}*/\nul#topnav li {\n  float: left;\n  display: inline; /*For ignore double margin in IE6*/\n  margin: 0 5px;\n}\nul#topnav li a {\n  text-decoration: none;\n  float:left;\n  cursor: pointer;\n  color:#fff;\n  font-size: .7em;\n  text-shadow:1px 1px #111;\n  padding:0;\n}\nul#topnav li a span {\n  margin: 0 10px 0 -10px;\n  padding: 3px 8px 4px 28px;\n  position: relative; /*To fix IE6 problem (not displaying)*/\n  float:left;\n background:;\n}\nul#topnav li a span.sign-up {\n  padding: 3px 8px 4px 18px;\n}\nul#topnav li a:active {\nbackground:;\n  color:#fff;\n  margin-top:1px\n}\nul#topnav li.active a, ul#topnav li a:hover {\n  text-decoration:none;\n  background:#595959;\n  -moz-border-radius:2px;\n  -webkit-border-radius:2px;\n}\nul#topnav li a.sign-up {\n  background: url(/images/static/nav-2.png) no-repeat top right;\n  color:#fff;\n  text-shadow:1px 1px 1px #349516;\n  text-transform:uppercase;\n}\nul#topnav li span.sign-up {\n  background: url(/images/static/nav-2.png) no-repeat top left;\n}\nul#topnav li a:hover.sign-up {\n  background: url(/images/static/nav-2.png) no-repeat right -28px;\n}\nul#topnav li span:hover.sign-up {\n  background: url(/images/static/nav-2.png) no-repeat left -28px;\n}\nul#topnav li.sign-up {\n  padding-left:15px;\n}\n/************************************************************************\nSub Navigation\n************************************************************************/\n\nul#topnav.sf-menu li.current ul li a, ul#topnav.sf-menu li ul li a {\n  background:transparent none repeat scroll 0 0;\n  float:left;\n  height:auto;\n  width:175px;\n  text-align:left;\n  display:block;\n  padding:7px 6px;\n  margin:0px 0;\n  border-bottom:1px solid #595959;\n  color:#d2d1d1;\n  text-shadow:none;\n}\nul#topnav.sf-menu li.current ul li {\n  margin:0;\n  padding:0px 0\n}\nul#topnav.sf-menu li.current ul li a:hover, ul#topnav.sf-menu li ul li a:hover {\n  color:#fff;\n  text-shadow:none;\n  background:#3e3e3e;\n}\nul#topnav.sf-menu li.current ul, ul#topnav.sf-menu li ul {\n  left:-10px;\n  margin:19px 0 0 10px;\n  top:25px;\n  -moz-box-shadow:0px 0px 5px #111;\n  -webkit-box-shadow:0px 0px 5px #111;\n  background: #303030;\n  width:187px;\n}\nul#topnav.sf-menu li.sfHover ul li {\n  margin:0\n}\nul#topnav.sf-menu li.current ul li.current ul, ul#topnav.sf-menu li.current ul li.sfHover ul, ul#topnav.sf-menu li.sfHover ul li.sfHover ul {\n  left:180px;\n  top:-20px;\n}\n#topnav li ul.subnav, #topnav li ul.subnav ul, #topnav li ul.subnav ul ul ul ul {\n  display:none;\n}\n#topnav li:hover ul.subnav, #topnav li li:hover ul.subnav, #topnav li li li:hover ul.subnav, #topnav li li li li:hover ul.subnav {\n  display:block;\n}\n\n/************************************************************************\nFooter\n************************************************************************/\n\n#footer {\n  margin-top: 100px;\n  height:300px;\n  background:url(/images/footer-bg.png) repeat-x\n}\n#top-footer {\n  height:280px;\n  position:relative\n}\n#top-footer h3 {\n  text-transform:uppercase;\n  color:#010101;\n  font-weight:bold;\n  font-size:1.3em;\n  text-shadow:1px 1px #fff;\n  background: url(/images/static/dot.png) no-repeat 0 50%;\n  padding-left: 15px\n}\n#top-footer .footer-logo {\n  position:absolute;\n  width:252px;\n  top:-13px;\n  overflow:hidden;\n  left:0\n}\n#top-footer div.footer-list {\n  margin-top:38px\n}\n#top-footer div.footer-list ul {\n  margin-left:0\n}\n#top-footer div.footer-list ul li {\n  list-style:none;\n  margin-left:0;\n}\n#top-footer div.footer-list ul li a {\n  color:#4a4949;\n  display:block;\n  border-bottom:1px solid #ccc;\n  padding: 3px 0 3px 3px;\n  text-decoration:none;\n}\n#top-footer div.footer-list ul li a:hover {\n  background:#eeeeee;\n}\n#top-footer div.footer-list ul li div a {\n  color:#4a4949;\n  display:inline;\n  border-bottom:0px;\n  padding: 3px 0 3px 3px;\n  text-decoration:none;\n}\n#top-footer div.footer-list ul li div a:hover {\n  background:none;\n}\n\n#top-footer div.copyright {\n  margin-top:100px\n}\n#top-footer div.copyright p {\n  color:#2e2e2f;\n  text-shadow:1px 1px #fff\n}\n#bottom-footer {\n  height:51px\n}\n#top-footer, #bottom-footer {\n  width:940px;\n  margin:0 auto;\n  display:block\n}\n#footer .menu-lite ul {\n  float:left;\n  padding-top:15px;\n  margin-bottom:-15px;\n  margin-left: -7px\n}\n#footer .menu-lite ul li {\n  float:left;\n  list-style:none;\n  margin:0 8px\n}\n#footer .menu-lite ul li a {\n  color:#fff;\n  text-decoration:none;\n  text-shadow:1px 1px #222\n}\n#footer .menu-lite ul li a:hover {\n  text-decoration:underline\n}\n#toTop {\n  width:96px;\n  text-indent:-9999px;\n  background: url(/images/static/totop.png) no-repeat 0 0;\n  height:15px;\n  padding:5px;\n  position:fixed;\n  bottom:10px;\n  right:10px;\n  cursor:pointer;\n}\na:hover#toTop {\n  background: url(/images/static/totop.png) no-repeat 0 -25px;\n}\na:active#toTop {\n  background: url(/images/static/totop.png) no-repeat 0 -24px;\n}\nul#topnav.sf-menu li.current ul, ul#topnav.sf-menu li ul {\n  display:block\n}\n\n#top-footer img.verify {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n  padding:4px;\n  background:#f3f3f3;\n  border:1px solid #e3e3e3;\n  margin-bottom:14px\n}\n\n\n.column, div.span-1, div.span-2, div.span-3, div.span-4, div.span-5, div.span-6, div.span-7, div.span-8, div.span-9, div.span-10, div.span-11, div.span-12 {\n  float:left;\n  margin-right:20px;\n}\n\n#top-footer .span-3 {\n  width: 220px;\n}\n\n#top-footer .last, #top-footer div.last {\n  margin-right: 0;\n}\n\n\n/*From HN*/\n#top-footer .footer-logo {left:-21px;}\n#top-footer h3 {background:none;padding-left:0;}\n\n#inviteArrow {\nleft:-0.5em;\nposition:relative;\n/*top:-0.3em;*/\n}\n"
  },
  {
    "path": "public/stylesheets/issue.css",
    "content": "body {\n    background-color: rgb(237, 241, 244);\n    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(222, 226, 229)), to(rgb(237, 241, 244)));\n    background-repeat: no-repeat;\n    border-top: 1px solid rgb(208, 212, 215);\n    margin: 0;\n    padding: 0;\n    color: rgb(77, 77, 77);\n    font-size: 12px;\n/*    font-family: \"Helvetica Neue\", \"Lucida Grande\", Arial, sans-serif;*/\n    line-height: 2em;\n    min-width: 500px;\n    word-wrap: break-word;\n/*    text-shadow: 0px 1px 0px white;   */\n  overflow: visible;\n}\n\nh1, #item_header h3 {\n    color: black;\n  font-size: 182%;\n    padding-left: 0px;\n  margin-left: -5px;\n    margin-bottom: -1px;\n    line-height: 32px;\n}\n\n#wrapper {\n    padding: 2em;\n    margin: 0 1em;\n    min-width: 500px;\n}\n\n.issue {\n    background-color: #fff;\n    position: relative;\n    font-size: 12px;\n    line-height: 24px;\n    -webkit-box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.3);\n    -moz-box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.3);\n    box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.3);\n}\n\n.issue p {\n    margin: 0;\n    padding: 0;\n    margin-top: 24px;\n}\n\n.issue-wrapper:after {\n    content: \".\";\n    display: block;\n    height: 0;\n    clear: both;\n    visibility: hidden;\n}\n\n.issue-content {\n    width: 70%;\n    float: left;\n}\n\n.issue-content-wrapper {\n    margin: 1em;\n    padding-top: 0.2em;\n    padding-bottom: 1em;\n}\n\n.issue-meta {\n    width: 30%;\n    float: left;\n    margin-top: 1.5em;\n}\n\n.issue-meta-wrapper {\n    padding: 1em;\n}\n\n.issue-meta-box {\n    border: 1px solid rgb(232, 232, 232);\n    margin-top: -1px;\n    padding: 0.5em 1em;\n    font-size: 90%;\n    line-height: 1.8em;\n}\n\n.issue-meta-box h3 {\n    text-transform: uppercase;\n    color: rgb(194, 194, 194);\n    margin: 0;\n    padding: 0;\n    font-weight: normal;\n    font-size: 11px;\n}\n\n.issue-image-area {\n    position: absolute;\n    top: -8px;\n    right: 6px;\n    -webkit-transform: rotate(4deg);\n    -moz-transform: rotate(4deg);\n    background: white;\n    border: 1px solid rgb(222, 222, 222);\n    -webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);\n    -moz-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);\n    box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);\n    width: 82px;\n    height: 82px;\n}\n\nimg.issue-author-image {\n    position: absolute;\n    margin: auto;\n    width: 68px;\n    height: 68px;\n    top: 7px;\n    left: 7px;\n}\n\n.issue-image-paperclip-placeholder {\n    width: 35px;\n    height: 50px;\n    position: absolute;\n    background-image: url(\"/images/paperclip.png\");\n    -webkit-transform: translate(-1px);\n    -moz-transform: translate(-1px);\n    right: -13px;\n}\n\n.issue-left-border-placeholder {\n    position: absolute;\n    left: 4.2em;\n    top: 2em;\n    bottom: 2em;\n    width: 1px;\n    background-color: rgb(235, 235, 235);\n}\n\n.issue-body {\n    background-image: url(\"/images/textgrid.png\");\n    background-repeat: repeat-x repeat-y;\n    padding: 3px 1em 3em 55px;\n    min-height: 160px;\n}\n\n.issue-body ol, .issue-body ul, .issue-body li, pre {\n    padding-top: 0;\n    padding-bottom: 0;\n    margin-top: 0;\n    margin-bottom: 0;\n}\n\n.issue-closed-placeholder {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 86px;\n    height: 44px;\n/*    background-image: url(\"Resources/closedStamp.png\");*/\n    display: none;\n}\n\n.stamp-closed {\n    display: block;\n}\n\n.issue-meta-action-wrapper {\n    text-align: center;\n    margin: 1.5em 0;\n}\n\n.action-state-button:hover {\n    -webkit-box-shadow: 0px 0px 4px rgba(155, 155, 155, 0.3);\n    -moz-box-shadow: 0px 0px 4px rgba(155, 155, 155, 0.3);\n    box-shadow: 0px 0px 4px rgba(155, 155, 155, 0.3);\n}\n\n.action-state-button:active {\n/*    background-image: -webkit-gradient(linear, left bottom, left top, from(rgb(248, 248, 248)), to(rgb(228, 228, 228)));\n*/}\n\n.action-state-button {\n/*    background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(248, 248, 248)), to(rgb(228, 228, 228)));\n*/  font-size: 12px;\n    padding: 0.5em 0.5em 0.5em 2em;\n    text-decoration: none;\n    color: black;\n    background-color: rgb(228, 228, 228);\n  background-position: 0.5em;\n    border: 1px solid rgb(195, 195, 195);\n    border-radius: 8px;\n    -moz-border-radius: 8px;\n    -webkit-border-radius: 8px;\n\n    -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.3);\n    -moz-box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.3);\n    box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.3);\n}\n\n.wantsopen-closed {\n    display: none;\n}\n\n.wantsclosed-open {\n    display: none;\n}\n.comment {\n    margin: 2em 1em 1em 4em;\n}\n\n.comment-body {\n    float: left;\n    width: 75%;\n}\n\n.comment-body-wrapper {\n    font-size: 12px;\n    background-color: rgb(246, 248, 222);\n    border-radius: 8px;\n    -moz-border-radius: 8px;\n    -webkit-border-radius: 8px;\n    padding: 0.5em 2em 0.5em 2em;\n    -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);\n    -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);\n    box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);\n    position: relative;\n    min-height: 44px;\n}\n\n.comment-accessory {\n    width: 0px;\n    height: 1px;\n    position: absolute;\n    right: -10px;\n    top: 20px;\n    border-left: 10px solid rgb(246, 248, 222);\n    border-top: 10px solid transparent;\n    border-bottom: 10px solid transparent;\n    border-right: none;\n}\n\n.comment-accessory-shadow {\n    width: 0px;\n    height: 1px;\n    position: absolute;\n    right: -10px;\n    top: 21px;\n    border-left: 10px solid rgba(0, 0, 0, 0.2);\n    border-top: 10px solid transparent;\n    border-bottom: 10px solid transparent;\n    border-right: none;\n}\n\n.comment-meta {\n    float: left;\n    width: 25%;\n}\n\n.comment-meta-wrapper {\n    padding: 1em 0em 1em 3em;\n}\n\n.comment:after {\n    content: \".\";\n    display: block;\n    height: 0;\n    clear: both;\n    visibility: hidden;\n}\n\n.comment-author-image {\n    float: left;\n    margin-top: 4px;\n    height: 28px;\n    width: 28px;\n    padding: 2px;\n    background-color: white;\n    -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);\n    -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);\n    box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);\n}\n\n.comment-meta-meta {\n    margin-left: 40px;\n}\n\n.comment-author {\n    font-weight: bold;\n    line-height: 10px;\n    padding-top: 8px;\n}\n\n.comment-date {\n    color: rgb(104, 104, 104);\n}\n\n#add-comment-button-wrapper {\n    text-align: right;\n}\n\n#add-comment-button-wrapper a {\n}\n\n.comment-form-wrapper {\n    text-align: right;\n    margin-top: 2em;\n    margin-bottom: 20px;\n}\n\n.fakebutton {\n    font-size: 12px;\n    background-color: rgb(246, 248, 222);\n    border-radius: 8px;\n    -moz-border-radius: 8px;\n    -webkit-border-radius: 8px;\n    padding: 0.5em 1em 0.5em 1em;\n    color: black;\n    text-decoration: none;\n    border: 1px solid rgb(200, 200, 200);\n}\n\n.fakebutton:active {\n    background-color: rgb(236, 238, 212);\n}\n\n#add-comment-textarea-wrapper-wrapper {\n    padding: 0;\n    margin-right: 0;\n}\n\n#add-comment-textarea {\n    width: 100%;\n    margin: 0;\n    margin-right: 2em;\n    height: 80px;\n    display: block;\n    border: 1px solid transparent;\n    border-radius: 8px;\n    -moz-border-radius: 8px;\n    -webkit-border-radius: 8px;\n    padding: 0.5em 1em 0.5em 1em;\n}\n\n#add-comment-textarea:focus {\n    outline: none;\n    border: 1px solid gray;\n    -webkit-box-shadow: 0px 0px 6px yellow;\n    -moz-box-shadow: 0px 0px 6px yellow;\n    box-shadow: 0px 0px 6px yellow;\n}\n\n#add-comment-textarea-wrapper {\n    margin-right: 0;\n}\n#comment-form-error-message {\n    display: none;\n}\n\n.view-on-github {\n    color: rgb(155, 155, 155);\n}\n\n.error-message {\n    color: red;\n}\n\nimg {\n    border: none;\n}\n                </style>\n<!--[if IE]>\n<style>\n.issue {\n    display: block;\n    clear: both;\n    float: left;\n    width: 100%;\n    border: 1px solid #bbb;\n}\n.comment-author-image {\n    border: 1px solid #bbb;\n}\n.comment {\n    float: left;\n    width: 93%;\n}\n.comment-body-wrapper {\n    border: 1px solid rgb(226, 228, 202);\n}\n#add-comment-textarea {\n    border: 1px solid rgb(226, 228, 202);\n}\n#add-comment-textarea:active {\n    border: 1px solid yellow;\n}\n\n/*Overwrite*/\nissue-meta-action-wrapper a.icon {\n  background-position: 1em;\n}\n/*.icon-edit {\n  background-position: 0em;\n}\n*/\n.icons{\n  width:auto;\n  float:none;\n}\n.help_question_mark{\n  margin-bottom:3px;\n  border:0px;\n}\n.relations{\n  padding-left:2px;\n}\n\nhtml > body #content {\n  min-height: 200px;\n  overflow-y: hidden;\n  overflow-x: hidden;\n}\nform input[type=\"text\"].short {\n  width: auto;\n  margin-right: 10px;\n}\n\nimg.gravatar {\n  padding: 2px;\n  border: solid 1px #d5d5d5;\n  background: #fff;\n}\ntd.author-name {\n  padding-left: 10px;\n}\n\n.open, .hoverable, .new, .inprogress, .canceled, .accepted, .estimate, .done {\n  background-color: transparent;\n}\n\np, li {\n  font-size: 125%;\n}\n\np {\n  margin-bottom: 0.6em;\n}\n\n#todo_lightbox .header {\n  font-size: 125%;\n}\n\nfieldset {\n  border: none;\n}\n\n/***** Ajax indicator ******/\n#ajax-indicator {\nposition: absolute; /* fixed not supported by IE */\nbackground-color:#eee;\nborder: 1px solid #bbb;\ntop:35%;\nleft:40%;\nwidth:20%;\nfont-weight:bold;\ntext-align:center;\npadding:0.6em;\nz-index:100;\nfilter:alpha(opacity=70);\nopacity: 0.7;\nbackground-image: none;\n}\n\nhtml>body #ajax-indicator { position: fixed; }\n\n#ajax-indicator span {\nbackground-position: 0% 40%;\nbackground-repeat: no-repeat;\nbackground-image: url(/images/loading.gif);\npadding-left: 26px;\nvertical-align: bottom;\ndisplay: block;\n}\n"
  },
  {
    "path": "public/stylesheets/jScrollPane.css",
    "content": "\n.jScrollPaneContainer {\n  position: relative;\n  overflow: hidden;\n  z-index: 1;\n}\n\n.jScrollPaneTrack {\n  position: absolute;\n  cursor: pointer;\n  right: 0;\n  top: 0;\n  height: 100%;\n  background: #aaa;\n}\n.jScrollPaneDrag {\n  position: absolute;\n  background: #666;\n  cursor: pointer;\n  overflow: hidden;\n}\n.jScrollPaneDragTop {\n  position: absolute;\n  top: 0;\n  left: 0;\n  overflow: hidden;\n}\n.jScrollPaneDragBottom {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  overflow: hidden;\n}\na.jScrollArrowUp {\n  display: block;\n  position: absolute;\n  z-index: 1;\n  top: 0;\n  right: 0;\n  text-indent: -2000px;\n  overflow: hidden;\n  /*background-color: #666;*/\n  height: 9px;\n}\na.jScrollArrowUp:hover {\n  /*background-color: #f60;*/\n}\n\na.jScrollArrowDown {\n  display: block;\n  position: absolute;\n  z-index: 1;\n  bottom: 0;\n  right: 0;\n  text-indent: -2000px;\n  overflow: hidden;\n  /*background-color: #666;*/\n  height: 9px;\n}\na.jScrollArrowDown:hover {\n  /*background-color: #f60;*/\n}\na.jScrollActiveArrowButton, a.jScrollActiveArrowButton:hover {\n  /*background-color: #f00;*/\n}\n"
  },
  {
    "path": "public/stylesheets/jquery-ui-1.7.2.custom.css",
    "content": "/*\n* jQuery UI CSS Framework\n* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.\n*/\n\n/* Layout helpers\n----------------------------------*/\n.ui-helper-hidden { display: none; }\n.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }\n.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }\n.ui-helper-clearfix:after { content: \".\"; display: block; height: 0; clear: both; visibility: hidden; }\n.ui-helper-clearfix { display: inline-block; }\n/* required comment for clearfix to work in Opera \\*/\n* html .ui-helper-clearfix { height:1%; }\n.ui-helper-clearfix { display:block; }\n/* end clearfix */\n.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }\n\n\n/* Interaction Cues\n----------------------------------*/\n.ui-state-disabled { cursor: default !important; }\n\n\n/* Icons\n----------------------------------*/\n\n/* states and images */\n.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }\n\n\n/* Misc visuals\n----------------------------------*/\n\n/* Overlays */\n.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }\n\n\n\n/*\n* jQuery UI CSS Framework\n* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.\n* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px\n*/\n\n\n/* Component containers\n----------------------------------*/\n.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; }\n.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; }\n.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(/images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }\n.ui-widget-content a { color: #333333; }\n.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(/images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }\n.ui-widget-header a { color: #ffffff; }\n\n/* Interaction states\n----------------------------------*/\n.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(/images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; outline: none; }\n.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; outline: none; }\n.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(/images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; outline: none; }\n.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; outline: none; }\n.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(/images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; outline: none; }\n.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; outline: none; text-decoration: none; }\n\n/* Interaction Cues\n----------------------------------*/\n.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(/images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; }\n.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; }\n.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(/images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; }\n.ui-state-error a, .ui-widget-content .ui-state-error a { color: #ffffff; }\n.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #ffffff; }\n.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }\n.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }\n.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }\n\n/* Icons\n----------------------------------*/\n\n/* states and images */\n.ui-icon { width: 16px; height: 16px; background-image: url(/images/ui-icons_222222_256x240.png); }\n.ui-widget-content .ui-icon {background-image: url(/images/ui-icons_222222_256x240.png); }\n.ui-widget-header .ui-icon {background-image: url(/images/ui-icons_ffffff_256x240.png); }\n.ui-state-default .ui-icon { background-image: url(/images/ui-icons_ef8c08_256x240.png); }\n.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(/images/ui-icons_ef8c08_256x240.png); }\n.ui-state-active .ui-icon {background-image: url(/images/ui-icons_ef8c08_256x240.png); }\n.ui-state-highlight .ui-icon {background-image: url(/images/ui-icons_228ef1_256x240.png); }\n.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(/images/ui-icons_ffd27a_256x240.png); }\n\n/* positioning */\n.ui-icon-carat-1-n { background-position: 0 0; }\n.ui-icon-carat-1-ne { background-position: -16px 0; }\n.ui-icon-carat-1-e { background-position: -32px 0; }\n.ui-icon-carat-1-se { background-position: -48px 0; }\n.ui-icon-carat-1-s { background-position: -64px 0; }\n.ui-icon-carat-1-sw { background-position: -80px 0; }\n.ui-icon-carat-1-w { background-position: -96px 0; }\n.ui-icon-carat-1-nw { background-position: -112px 0; }\n.ui-icon-carat-2-n-s { background-position: -128px 0; }\n.ui-icon-carat-2-e-w { background-position: -144px 0; }\n.ui-icon-triangle-1-n { background-position: 0 -16px; }\n.ui-icon-triangle-1-ne { background-position: -16px -16px; }\n.ui-icon-triangle-1-e { background-position: -32px -16px; }\n.ui-icon-triangle-1-se { background-position: -48px -16px; }\n.ui-icon-triangle-1-s { background-position: -64px -16px; }\n.ui-icon-triangle-1-sw { background-position: -80px -16px; }\n.ui-icon-triangle-1-w { background-position: -96px -16px; }\n.ui-icon-triangle-1-nw { background-position: -112px -16px; }\n.ui-icon-triangle-2-n-s { background-position: -128px -16px; }\n.ui-icon-triangle-2-e-w { background-position: -144px -16px; }\n.ui-icon-arrow-1-n { background-position: 0 -32px; }\n.ui-icon-arrow-1-ne { background-position: -16px -32px; }\n.ui-icon-arrow-1-e { background-position: -32px -32px; }\n.ui-icon-arrow-1-se { background-position: -48px -32px; }\n.ui-icon-arrow-1-s { background-position: -64px -32px; }\n.ui-icon-arrow-1-sw { background-position: -80px -32px; }\n.ui-icon-arrow-1-w { background-position: -96px -32px; }\n.ui-icon-arrow-1-nw { background-position: -112px -32px; }\n.ui-icon-arrow-2-n-s { background-position: -128px -32px; }\n.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }\n.ui-icon-arrow-2-e-w { background-position: -160px -32px; }\n.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }\n.ui-icon-arrowstop-1-n { background-position: -192px -32px; }\n.ui-icon-arrowstop-1-e { background-position: -208px -32px; }\n.ui-icon-arrowstop-1-s { background-position: -224px -32px; }\n.ui-icon-arrowstop-1-w { background-position: -240px -32px; }\n.ui-icon-arrowthick-1-n { background-position: 0 -48px; }\n.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }\n.ui-icon-arrowthick-1-e { background-position: -32px -48px; }\n.ui-icon-arrowthick-1-se { background-position: -48px -48px; }\n.ui-icon-arrowthick-1-s { background-position: -64px -48px; }\n.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }\n.ui-icon-arrowthick-1-w { background-position: -96px -48px; }\n.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }\n.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }\n.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }\n.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }\n.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }\n.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }\n.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }\n.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }\n.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }\n.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }\n.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }\n.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }\n.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }\n.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }\n.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }\n.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }\n.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }\n.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }\n.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }\n.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }\n.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }\n.ui-icon-arrow-4 { background-position: 0 -80px; }\n.ui-icon-arrow-4-diag { background-position: -16px -80px; }\n.ui-icon-extlink { background-position: -32px -80px; }\n.ui-icon-newwin { background-position: -48px -80px; }\n.ui-icon-refresh { background-position: -64px -80px; }\n.ui-icon-shuffle { background-position: -80px -80px; }\n.ui-icon-transfer-e-w { background-position: -96px -80px; }\n.ui-icon-transferthick-e-w { background-position: -112px -80px; }\n.ui-icon-folder-collapsed { background-position: 0 -96px; }\n.ui-icon-folder-open { background-position: -16px -96px; }\n.ui-icon-document { background-position: -32px -96px; }\n.ui-icon-document-b { background-position: -48px -96px; }\n.ui-icon-note { background-position: -64px -96px; }\n.ui-icon-mail-closed { background-position: -80px -96px; }\n.ui-icon-mail-open { background-position: -96px -96px; }\n.ui-icon-suitcase { background-position: -112px -96px; }\n.ui-icon-comment { background-position: -128px -96px; }\n.ui-icon-person { background-position: -144px -96px; }\n.ui-icon-print { background-position: -160px -96px; }\n.ui-icon-trash { background-position: -176px -96px; }\n.ui-icon-locked { background-position: -192px -96px; }\n.ui-icon-unlocked { background-position: -208px -96px; }\n.ui-icon-bookmark { background-position: -224px -96px; }\n.ui-icon-tag { background-position: -240px -96px; }\n.ui-icon-home { background-position: 0 -112px; }\n.ui-icon-flag { background-position: -16px -112px; }\n.ui-icon-calendar { background-position: -32px -112px; }\n.ui-icon-cart { background-position: -48px -112px; }\n.ui-icon-pencil { background-position: -64px -112px; }\n.ui-icon-clock { background-position: -80px -112px; }\n.ui-icon-disk { background-position: -96px -112px; }\n.ui-icon-calculator { background-position: -112px -112px; }\n.ui-icon-zoomin { background-position: -128px -112px; }\n.ui-icon-zoomout { background-position: -144px -112px; }\n.ui-icon-search { background-position: -160px -112px; }\n.ui-icon-wrench { background-position: -176px -112px; }\n.ui-icon-gear { background-position: -192px -112px; }\n.ui-icon-heart { background-position: -208px -112px; }\n.ui-icon-star { background-position: -224px -112px; }\n.ui-icon-link { background-position: -240px -112px; }\n.ui-icon-cancel { background-position: 0 -128px; }\n.ui-icon-plus { background-position: -16px -128px; }\n.ui-icon-plusthick { background-position: -32px -128px; }\n.ui-icon-minus { background-position: -48px -128px; }\n.ui-icon-minusthick { background-position: -64px -128px; }\n.ui-icon-close { background-position: -80px -128px; }\n.ui-icon-closethick { background-position: -96px -128px; }\n.ui-icon-key { background-position: -112px -128px; }\n.ui-icon-lightbulb { background-position: -128px -128px; }\n.ui-icon-scissors { background-position: -144px -128px; }\n.ui-icon-clipboard { background-position: -160px -128px; }\n.ui-icon-copy { background-position: -176px -128px; }\n.ui-icon-contact { background-position: -192px -128px; }\n.ui-icon-image { background-position: -208px -128px; }\n.ui-icon-video { background-position: -224px -128px; }\n.ui-icon-script { background-position: -240px -128px; }\n.ui-icon-alert { background-position: 0 -144px; }\n.ui-icon-info { background-position: -16px -144px; }\n.ui-icon-notice { background-position: -32px -144px; }\n.ui-icon-help { background-position: -48px -144px; }\n.ui-icon-check { background-position: -64px -144px; }\n.ui-icon-bullet { background-position: -80px -144px; }\n.ui-icon-radio-off { background-position: -96px -144px; }\n.ui-icon-radio-on { background-position: -112px -144px; }\n.ui-icon-pin-w { background-position: -128px -144px; }\n.ui-icon-pin-s { background-position: -144px -144px; }\n.ui-icon-play { background-position: 0 -160px; }\n.ui-icon-pause { background-position: -16px -160px; }\n.ui-icon-seek-next { background-position: -32px -160px; }\n.ui-icon-seek-prev { background-position: -48px -160px; }\n.ui-icon-seek-end { background-position: -64px -160px; }\n.ui-icon-seek-first { background-position: -80px -160px; }\n.ui-icon-stop { background-position: -96px -160px; }\n.ui-icon-eject { background-position: -112px -160px; }\n.ui-icon-volume-off { background-position: -128px -160px; }\n.ui-icon-volume-on { background-position: -144px -160px; }\n.ui-icon-power { background-position: 0 -176px; }\n.ui-icon-signal-diag { background-position: -16px -176px; }\n.ui-icon-signal { background-position: -32px -176px; }\n.ui-icon-battery-0 { background-position: -48px -176px; }\n.ui-icon-battery-1 { background-position: -64px -176px; }\n.ui-icon-battery-2 { background-position: -80px -176px; }\n.ui-icon-battery-3 { background-position: -96px -176px; }\n.ui-icon-circle-plus { background-position: 0 -192px; }\n.ui-icon-circle-minus { background-position: -16px -192px; }\n.ui-icon-circle-close { background-position: -32px -192px; }\n.ui-icon-circle-triangle-e { background-position: -48px -192px; }\n.ui-icon-circle-triangle-s { background-position: -64px -192px; }\n.ui-icon-circle-triangle-w { background-position: -80px -192px; }\n.ui-icon-circle-triangle-n { background-position: -96px -192px; }\n.ui-icon-circle-arrow-e { background-position: -112px -192px; }\n.ui-icon-circle-arrow-s { background-position: -128px -192px; }\n.ui-icon-circle-arrow-w { background-position: -144px -192px; }\n.ui-icon-circle-arrow-n { background-position: -160px -192px; }\n.ui-icon-circle-zoomin { background-position: -176px -192px; }\n.ui-icon-circle-zoomout { background-position: -192px -192px; }\n.ui-icon-circle-check { background-position: -208px -192px; }\n.ui-icon-circlesmall-plus { background-position: 0 -208px; }\n.ui-icon-circlesmall-minus { background-position: -16px -208px; }\n.ui-icon-circlesmall-close { background-position: -32px -208px; }\n.ui-icon-squaresmall-plus { background-position: -48px -208px; }\n.ui-icon-squaresmall-minus { background-position: -64px -208px; }\n.ui-icon-squaresmall-close { background-position: -80px -208px; }\n.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }\n.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }\n.ui-icon-grip-solid-vertical { background-position: -32px -224px; }\n.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }\n.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }\n.ui-icon-grip-diagonal-se { background-position: -80px -224px; }\n\n\n/* Misc visuals\n----------------------------------*/\n\n/* Corner radius */\n.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; }\n.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; }\n.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; }\n.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }\n.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; }\n.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }\n.ui-corner-right {  -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; }\n.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; }\n.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; }\n\n/* Overlays */\n.ui-widget-overlay { background: #666666 url(/images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); }\n.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(/images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -webkit-border-radius: 5px; }/* Accordion\n----------------------------------*/\n.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }\n.ui-accordion .ui-accordion-li-fix { display: inline; }\n.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }\n.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; }\n.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }\n.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; }\n.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker\n----------------------------------*/\n.ui-datepicker { width: 17em; padding: .2em .2em 0; }\n.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }\n.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }\n.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }\n.ui-datepicker .ui-datepicker-prev { left:2px; }\n.ui-datepicker .ui-datepicker-next { right:2px; }\n.ui-datepicker .ui-datepicker-prev-hover { left:1px; }\n.ui-datepicker .ui-datepicker-next-hover { right:1px; }\n.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }\n.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }\n.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }\n.ui-datepicker select.ui-datepicker-month-year {width: 100%;}\n.ui-datepicker select.ui-datepicker-month,\n.ui-datepicker select.ui-datepicker-year { width: 49%;}\n.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }\n.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }\n.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }\n.ui-datepicker td { border: 0; padding: 1px; }\n.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }\n.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }\n.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }\n.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }\n\n/* with multiple calendars */\n.ui-datepicker.ui-datepicker-multi { width:auto; }\n.ui-datepicker-multi .ui-datepicker-group { float:left; }\n.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }\n.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }\n.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }\n.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }\n.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }\n.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }\n.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }\n.ui-datepicker-row-break { clear:both; width:100%; }\n\n/* RTL support */\n.ui-datepicker-rtl { direction: rtl; }\n.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }\n.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }\n.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }\n.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }\n.ui-datepicker-rtl .ui-datepicker-group { float:right; }\n.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }\n.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }\n\n/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */\n.ui-datepicker-cover {\n    display: none; /*sorry for IE5*/\n    display/**/: block; /*sorry for IE5*/\n    position: absolute; /*must have*/\n    z-index: -1; /*must have*/\n    filter: mask(); /*must have*/\n    top: -4px; /*must have*/\n    left: -4px; /*must have*/\n    width: 200px; /*must have*/\n    height: 200px; /*must have*/\n}/* Dialog\n----------------------------------*/\n.ui-dialog { position: relative; padding: .2em; width: 300px; }\n.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative;  }\n.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; }\n.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }\n.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }\n.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }\n.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }\n.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }\n.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }\n.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }\n.ui-draggable .ui-dialog-titlebar { cursor: move; }\n/* Progressbar\n----------------------------------*/\n.ui-progressbar { height:2em; text-align: left; }\n.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable\n----------------------------------*/\n.ui-resizable { position: relative;}\n.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}\n.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }\n.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; }\n.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; }\n.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; }\n.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; }\n.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }\n.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }\n.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }\n.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider\n----------------------------------*/\n.ui-slider { position: relative; text-align: left; }\n.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }\n.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }\n\n.ui-slider-horizontal { height: .8em; }\n.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }\n.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }\n.ui-slider-horizontal .ui-slider-range-min { left: 0; }\n.ui-slider-horizontal .ui-slider-range-max { right: 0; }\n\n.ui-slider-vertical { width: .8em; height: 100px; }\n.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }\n.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }\n.ui-slider-vertical .ui-slider-range-min { bottom: 0; }\n.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs\n----------------------------------*/\n.ui-tabs { padding: .2em; zoom: 1; }\n.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; }\n.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; }\n.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; }\n.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; }\n.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }\n.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */\n.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; }\n.ui-tabs .ui-tabs-hide { display: none !important; }\n"
  },
  {
    "path": "public/stylesheets/jquery-ui-1.8.8.custom.css",
    "content": "/*\n * jQuery UI CSS Framework 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Theming/API\n */\n\n/* Layout helpers\n----------------------------------*/\n.ui-helper-hidden { display: none; }\n.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }\n.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }\n.ui-helper-clearfix:after { content: \".\"; display: block; height: 0; clear: both; visibility: hidden; }\n.ui-helper-clearfix { display: inline-block; }\n/* required comment for clearfix to work in Opera \\*/\n* html .ui-helper-clearfix { height:1%; }\n.ui-helper-clearfix { display:block; }\n/* end clearfix */\n.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }\n\n\n/* Interaction Cues\n----------------------------------*/\n.ui-state-disabled { cursor: default !important; }\n\n\n/* Icons\n----------------------------------*/\n\n/* states and images */\n.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }\n\n\n/* Misc visuals\n----------------------------------*/\n\n/* Overlays */\n.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }\n\n\n/*\n * jQuery UI CSS Framework 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Theming/API\n *\n * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px\n */\n\n\n/* Component containers\n----------------------------------*/\n.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; }\n.ui-widget .ui-widget { font-size: 1em; }\n.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; }\n.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(/images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }\n.ui-widget-content a { color: #333333; }\n.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(/images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }\n.ui-widget-header a { color: #ffffff; }\n\n/* Interaction states\n----------------------------------*/\n.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(/images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; }\n.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; }\n.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(/images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; }\n.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; }\n.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(/images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; }\n.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; }\n.ui-widget :active { outline: none; }\n\n/* Interaction Cues\n----------------------------------*/\n.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fed22f; background: #ffe45c url(/images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; }\n.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }\n.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(/images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; }\n.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }\n.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }\n.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }\n.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }\n.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }\n\n/* Icons\n----------------------------------*/\n\n/* states and images */\n.ui-icon { width: 16px; height: 16px; background-image: url(/images/ui-icons_222222_256x240.png); }\n.ui-widget-content .ui-icon {background-image: url(/images/ui-icons_222222_256x240.png); }\n.ui-widget-header .ui-icon {background-image: url(/images/ui-icons_ffffff_256x240.png); }\n.ui-state-default .ui-icon { background-image: url(/images/ui-icons_ef8c08_256x240.png); }\n.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(/images/ui-icons_ef8c08_256x240.png); }\n.ui-state-active .ui-icon {background-image: url(/images/ui-icons_ef8c08_256x240.png); }\n.ui-state-highlight .ui-icon {background-image: url(/images/ui-icons_228ef1_256x240.png); }\n.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(/images/ui-icons_ffd27a_256x240.png); }\n\n/* positioning */\n.ui-icon-carat-1-n { background-position: 0 0; }\n.ui-icon-carat-1-ne { background-position: -16px 0; }\n.ui-icon-carat-1-e { background-position: -32px 0; }\n.ui-icon-carat-1-se { background-position: -48px 0; }\n.ui-icon-carat-1-s { background-position: -64px 0; }\n.ui-icon-carat-1-sw { background-position: -80px 0; }\n.ui-icon-carat-1-w { background-position: -96px 0; }\n.ui-icon-carat-1-nw { background-position: -112px 0; }\n.ui-icon-carat-2-n-s { background-position: -128px 0; }\n.ui-icon-carat-2-e-w { background-position: -144px 0; }\n.ui-icon-triangle-1-n { background-position: 0 -16px; }\n.ui-icon-triangle-1-ne { background-position: -16px -16px; }\n.ui-icon-triangle-1-e { background-position: -32px -16px; }\n.ui-icon-triangle-1-se { background-position: -48px -16px; }\n.ui-icon-triangle-1-s { background-position: -64px -16px; }\n.ui-icon-triangle-1-sw { background-position: -80px -16px; }\n.ui-icon-triangle-1-w { background-position: -96px -16px; }\n.ui-icon-triangle-1-nw { background-position: -112px -16px; }\n.ui-icon-triangle-2-n-s { background-position: -128px -16px; }\n.ui-icon-triangle-2-e-w { background-position: -144px -16px; }\n.ui-icon-arrow-1-n { background-position: 0 -32px; }\n.ui-icon-arrow-1-ne { background-position: -16px -32px; }\n.ui-icon-arrow-1-e { background-position: -32px -32px; }\n.ui-icon-arrow-1-se { background-position: -48px -32px; }\n.ui-icon-arrow-1-s { background-position: -64px -32px; }\n.ui-icon-arrow-1-sw { background-position: -80px -32px; }\n.ui-icon-arrow-1-w { background-position: -96px -32px; }\n.ui-icon-arrow-1-nw { background-position: -112px -32px; }\n.ui-icon-arrow-2-n-s { background-position: -128px -32px; }\n.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }\n.ui-icon-arrow-2-e-w { background-position: -160px -32px; }\n.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }\n.ui-icon-arrowstop-1-n { background-position: -192px -32px; }\n.ui-icon-arrowstop-1-e { background-position: -208px -32px; }\n.ui-icon-arrowstop-1-s { background-position: -224px -32px; }\n.ui-icon-arrowstop-1-w { background-position: -240px -32px; }\n.ui-icon-arrowthick-1-n { background-position: 0 -48px; }\n.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }\n.ui-icon-arrowthick-1-e { background-position: -32px -48px; }\n.ui-icon-arrowthick-1-se { background-position: -48px -48px; }\n.ui-icon-arrowthick-1-s { background-position: -64px -48px; }\n.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }\n.ui-icon-arrowthick-1-w { background-position: -96px -48px; }\n.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }\n.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }\n.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }\n.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }\n.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }\n.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }\n.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }\n.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }\n.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }\n.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }\n.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }\n.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }\n.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }\n.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }\n.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }\n.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }\n.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }\n.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }\n.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }\n.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }\n.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }\n.ui-icon-arrow-4 { background-position: 0 -80px; }\n.ui-icon-arrow-4-diag { background-position: -16px -80px; }\n.ui-icon-extlink { background-position: -32px -80px; }\n.ui-icon-newwin { background-position: -48px -80px; }\n.ui-icon-refresh { background-position: -64px -80px; }\n.ui-icon-shuffle { background-position: -80px -80px; }\n.ui-icon-transfer-e-w { background-position: -96px -80px; }\n.ui-icon-transferthick-e-w { background-position: -112px -80px; }\n.ui-icon-folder-collapsed { background-position: 0 -96px; }\n.ui-icon-folder-open { background-position: -16px -96px; }\n.ui-icon-document { background-position: -32px -96px; }\n.ui-icon-document-b { background-position: -48px -96px; }\n.ui-icon-note { background-position: -64px -96px; }\n.ui-icon-mail-closed { background-position: -80px -96px; }\n.ui-icon-mail-open { background-position: -96px -96px; }\n.ui-icon-suitcase { background-position: -112px -96px; }\n.ui-icon-comment { background-position: -128px -96px; }\n.ui-icon-person { background-position: -144px -96px; }\n.ui-icon-print { background-position: -160px -96px; }\n.ui-icon-trash { background-position: -176px -96px; }\n.ui-icon-locked { background-position: -192px -96px; }\n.ui-icon-unlocked { background-position: -208px -96px; }\n.ui-icon-bookmark { background-position: -224px -96px; }\n.ui-icon-tag { background-position: -240px -96px; }\n.ui-icon-home { background-position: 0 -112px; }\n.ui-icon-flag { background-position: -16px -112px; }\n.ui-icon-calendar { background-position: -32px -112px; }\n.ui-icon-cart { background-position: -48px -112px; }\n.ui-icon-pencil { background-position: -64px -112px; }\n.ui-icon-clock { background-position: -80px -112px; }\n.ui-icon-disk { background-position: -96px -112px; }\n.ui-icon-calculator { background-position: -112px -112px; }\n.ui-icon-zoomin { background-position: -128px -112px; }\n.ui-icon-zoomout { background-position: -144px -112px; }\n.ui-icon-search { background-position: -160px -112px; }\n.ui-icon-wrench { background-position: -176px -112px; }\n.ui-icon-gear { background-position: -192px -112px; }\n.ui-icon-heart { background-position: -208px -112px; }\n.ui-icon-star { background-position: -224px -112px; }\n.ui-icon-link { background-position: -240px -112px; }\n.ui-icon-cancel { background-position: 0 -128px; }\n.ui-icon-plus { background-position: -16px -128px; }\n.ui-icon-plusthick { background-position: -32px -128px; }\n.ui-icon-minus { background-position: -48px -128px; }\n.ui-icon-minusthick { background-position: -64px -128px; }\n.ui-icon-close { background-position: -80px -128px; }\n.ui-icon-closethick { background-position: -96px -128px; }\n.ui-icon-key { background-position: -112px -128px; }\n.ui-icon-lightbulb { background-position: -128px -128px; }\n.ui-icon-scissors { background-position: -144px -128px; }\n.ui-icon-clipboard { background-position: -160px -128px; }\n.ui-icon-copy { background-position: -176px -128px; }\n.ui-icon-contact { background-position: -192px -128px; }\n.ui-icon-image { background-position: -208px -128px; }\n.ui-icon-video { background-position: -224px -128px; }\n.ui-icon-script { background-position: -240px -128px; }\n.ui-icon-alert { background-position: 0 -144px; }\n.ui-icon-info { background-position: -16px -144px; }\n.ui-icon-notice { background-position: -32px -144px; }\n.ui-icon-help { background-position: -48px -144px; }\n.ui-icon-check { background-position: -64px -144px; }\n.ui-icon-bullet { background-position: -80px -144px; }\n.ui-icon-radio-off { background-position: -96px -144px; }\n.ui-icon-radio-on { background-position: -112px -144px; }\n.ui-icon-pin-w { background-position: -128px -144px; }\n.ui-icon-pin-s { background-position: -144px -144px; }\n.ui-icon-play { background-position: 0 -160px; }\n.ui-icon-pause { background-position: -16px -160px; }\n.ui-icon-seek-next { background-position: -32px -160px; }\n.ui-icon-seek-prev { background-position: -48px -160px; }\n.ui-icon-seek-end { background-position: -64px -160px; }\n.ui-icon-seek-start { background-position: -80px -160px; }\n/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */\n.ui-icon-seek-first { background-position: -80px -160px; }\n.ui-icon-stop { background-position: -96px -160px; }\n.ui-icon-eject { background-position: -112px -160px; }\n.ui-icon-volume-off { background-position: -128px -160px; }\n.ui-icon-volume-on { background-position: -144px -160px; }\n.ui-icon-power { background-position: 0 -176px; }\n.ui-icon-signal-diag { background-position: -16px -176px; }\n.ui-icon-signal { background-position: -32px -176px; }\n.ui-icon-battery-0 { background-position: -48px -176px; }\n.ui-icon-battery-1 { background-position: -64px -176px; }\n.ui-icon-battery-2 { background-position: -80px -176px; }\n.ui-icon-battery-3 { background-position: -96px -176px; }\n.ui-icon-circle-plus { background-position: 0 -192px; }\n.ui-icon-circle-minus { background-position: -16px -192px; }\n.ui-icon-circle-close { background-position: -32px -192px; }\n.ui-icon-circle-triangle-e { background-position: -48px -192px; }\n.ui-icon-circle-triangle-s { background-position: -64px -192px; }\n.ui-icon-circle-triangle-w { background-position: -80px -192px; }\n.ui-icon-circle-triangle-n { background-position: -96px -192px; }\n.ui-icon-circle-arrow-e { background-position: -112px -192px; }\n.ui-icon-circle-arrow-s { background-position: -128px -192px; }\n.ui-icon-circle-arrow-w { background-position: -144px -192px; }\n.ui-icon-circle-arrow-n { background-position: -160px -192px; }\n.ui-icon-circle-zoomin { background-position: -176px -192px; }\n.ui-icon-circle-zoomout { background-position: -192px -192px; }\n.ui-icon-circle-check { background-position: -208px -192px; }\n.ui-icon-circlesmall-plus { background-position: 0 -208px; }\n.ui-icon-circlesmall-minus { background-position: -16px -208px; }\n.ui-icon-circlesmall-close { background-position: -32px -208px; }\n.ui-icon-squaresmall-plus { background-position: -48px -208px; }\n.ui-icon-squaresmall-minus { background-position: -64px -208px; }\n.ui-icon-squaresmall-close { background-position: -80px -208px; }\n.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }\n.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }\n.ui-icon-grip-solid-vertical { background-position: -32px -224px; }\n.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }\n.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }\n.ui-icon-grip-diagonal-se { background-position: -80px -224px; }\n\n\n/* Misc visuals\n----------------------------------*/\n\n/* Corner radius */\n.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }\n.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }\n.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }\n.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }\n.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }\n.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }\n.ui-corner-right {  -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }\n.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }\n.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; }\n\n/* Overlays */\n.ui-widget-overlay { background: #666666 url(/images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); }\n.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(/images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*\n * jQuery UI Resizable 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Resizable#theming\n */\n.ui-resizable { position: relative;}\n.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}\n.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }\n.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }\n.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }\n.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }\n.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }\n.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }\n.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }\n.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }\n.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*\n * jQuery UI Selectable 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Selectable#theming\n */\n.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }\n/*\n * jQuery UI Accordion 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Accordion#theming\n */\n/* IE/Win - Fix animation bug - #4615 */\n.ui-accordion { width: 100%; }\n.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }\n.ui-accordion .ui-accordion-li-fix { display: inline; }\n.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }\n.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }\n.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }\n.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }\n.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }\n.ui-accordion .ui-accordion-content-active { display: block; }/*\n * jQuery UI Autocomplete 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Autocomplete#theming\n */\n.ui-autocomplete { position: absolute; cursor: default; }\n\n/* workarounds */\n* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */\n\n/*\n * jQuery UI Menu 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Menu#theming\n */\n.ui-menu {\n  list-style:none;\n  padding: 2px;\n  margin: 0;\n  display:block;\n  float: left;\n}\n.ui-menu .ui-menu {\n  margin-top: -3px;\n}\n.ui-menu .ui-menu-item {\n  margin:0;\n  padding: 0;\n  zoom: 1;\n  float: left;\n  clear: left;\n  width: 100%;\n}\n.ui-menu .ui-menu-item a {\n  text-decoration:none;\n  display:block;\n  padding:.2em .4em;\n  line-height:1.5;\n  zoom:1;\n}\n.ui-menu .ui-menu-item a.ui-state-hover,\n.ui-menu .ui-menu-item a.ui-state-active {\n  font-weight: normal;\n  margin: -1px;\n}\n/*\n * jQuery UI Button 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Button#theming\n */\n.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */\n.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */\nbutton.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */\n.ui-button-icons-only { width: 3.4em; }\nbutton.ui-button-icons-only { width: 3.7em; }\n\n/*button text element */\n.ui-button .ui-button-text { display: block; line-height: 1.4;  }\n.ui-button-text-only .ui-button-text { padding: .4em 1em; }\n.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }\n.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }\n.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }\n.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }\n/* no icon support for input elements, provide padding by default */\ninput.ui-button { padding: .4em 1em; }\n\n/*button icon element(s) */\n.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }\n.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }\n.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }\n.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }\n.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }\n\n/*button sets*/\n.ui-buttonset { margin-right: 7px; }\n.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }\n\n/* workarounds */\nbutton.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */\n/*\n * jQuery UI Dialog 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Dialog#theming\n */\n.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }\n.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative;  }\n.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }\n.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }\n.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }\n.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }\n.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }\n.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }\n.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }\n.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }\n.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }\n.ui-draggable .ui-dialog-titlebar { cursor: move; }\n/*\n * jQuery UI Slider 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Slider#theming\n */\n.ui-slider { position: relative; text-align: left; }\n.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }\n.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }\n\n.ui-slider-horizontal { height: .8em; }\n.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }\n.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }\n.ui-slider-horizontal .ui-slider-range-min { left: 0; }\n.ui-slider-horizontal .ui-slider-range-max { right: 0; }\n\n.ui-slider-vertical { width: .8em; height: 100px; }\n.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }\n.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }\n.ui-slider-vertical .ui-slider-range-min { bottom: 0; }\n.ui-slider-vertical .ui-slider-range-max { top: 0; }/*\n * jQuery UI Tabs 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Tabs#theming\n */\n.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as \"fixed\") */\n.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }\n.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }\n.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }\n.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }\n.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }\n.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */\n.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }\n.ui-tabs .ui-tabs-hide { display: none !important; }\n/*\n * jQuery UI Datepicker 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Datepicker#theming\n */\n.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }\n.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }\n.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }\n.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }\n.ui-datepicker .ui-datepicker-prev { left:2px; }\n.ui-datepicker .ui-datepicker-next { right:2px; }\n.ui-datepicker .ui-datepicker-prev-hover { left:1px; }\n.ui-datepicker .ui-datepicker-next-hover { right:1px; }\n.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }\n.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }\n.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }\n.ui-datepicker select.ui-datepicker-month-year {width: 100%;}\n.ui-datepicker select.ui-datepicker-month,\n.ui-datepicker select.ui-datepicker-year { width: 49%;}\n.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }\n.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }\n.ui-datepicker td { border: 0; padding: 1px; }\n.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }\n.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }\n.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }\n.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }\n\n/* with multiple calendars */\n.ui-datepicker.ui-datepicker-multi { width:auto; }\n.ui-datepicker-multi .ui-datepicker-group { float:left; }\n.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }\n.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }\n.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }\n.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }\n.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }\n.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }\n.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }\n.ui-datepicker-row-break { clear:both; width:100%; }\n\n/* RTL support */\n.ui-datepicker-rtl { direction: rtl; }\n.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }\n.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }\n.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }\n.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }\n.ui-datepicker-rtl .ui-datepicker-group { float:right; }\n.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }\n.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }\n\n/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */\n.ui-datepicker-cover {\n    display: none; /*sorry for IE5*/\n    display/**/: block; /*sorry for IE5*/\n    position: absolute; /*must have*/\n    z-index: -1; /*must have*/\n    filter: mask(); /*must have*/\n    top: -4px; /*must have*/\n    left: -4px; /*must have*/\n    width: 200px; /*must have*/\n    height: 200px; /*must have*/\n}/*\n * jQuery UI Progressbar 1.8.8\n *\n * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * http://docs.jquery.com/UI/Progressbar#theming\n */\n.ui-progressbar { height:2em; text-align: left; }\n.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }\n"
  },
  {
    "path": "public/stylesheets/jquery.autocomplete.css",
    "content": ".ac_results {\n  padding: 0px;\n  border: 1px solid black;\n  background-color: white;\n  overflow: hidden;\n  z-index: 99999;\n}\n\n.ac_results ul {\n  width: 100%;\n  list-style-position: outside;\n  list-style: none;\n  padding: 0;\n  margin: 0;\n}\n\n.ac_results li {\n  margin: 0px;\n  padding: 2px 5px;\n  cursor: default;\n  display: block;\n  /*\n  if width will be 100% horizontal scrollbar will apear\n  when scroll mode will be used\n  */\n  /*width: 100%;*/\n  font: menu;\n  font-size: 12px;\n  /*\n  it is very important, if line-height not setted or setted\n  in relative units scroll will be broken in firefox\n  */\n  line-height: 16px;\n  overflow: hidden;\n}\n\n.ac_loading {\n  background: white url('indicator.gif') right center no-repeat;\n}\n\n.ac_odd {\n  background-color: #eee;\n}\n\n.ac_over {\n  background-color: #0A246A;\n  color: white;\n}\n"
  },
  {
    "path": "public/stylesheets/jquery.fancybox-1.3.0.css",
    "content": "/*\n * FancyBox - jQuery Plugin\n * Simple and fancy lightbox alternative\n *\n * Copyright (c) 20010 Janis Skarnelis\n * Examples and documentation at: http://fancybox.net\n *\n * Version: 1.3.0 (02/02/2010)\n * Requires: jQuery v1.3+\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n */\n\n#fancybox-loading {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  height: 40px;\n  width: 40px;\n  margin-top: -20px;\n  margin-left: -20px;\n  cursor: pointer;\n  overflow: hidden;\n  background: transparent;\n  z-index: 1104;\n  display: none;\n}\n\n* html #fancybox-loading {  /* IE6 */\n  position: absolute;\n  margin-top: 0;\n}\n\n#fancybox-loading div {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 40px;\n  height: 480px;\n  background: transparent url('/images/fancybox/fancy_loading.png') no-repeat;\n}\n\n#fancybox-overlay {\n  position: fixed;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  background: #000;\n  z-index: 1100;\n  display: none;\n}\n\n* html #fancybox-overlay {  /* IE6 */\n  position: absolute;\n  width: 100%;\n}\n\n#fancybox-tmp {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  overflow: auto;\n  display: none;\n}\n\n#fancybox-wrap {\n  position: absolute;\n  top: 0;\n  left: 0;\n  margin: 0;\n  padding: 20px;\n  z-index: 1101;\n  display: none;\n}\n\n#fancybox-outer {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #FFF;\n}\n\n#fancybox-inner {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: 0;\n  outline: none;\n  overflow: hidden;\n}\n\n#fancybox-hide-sel-frame {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: transparent;\n}\n\n#fancybox-close {\n  position: absolute;\n  top: -15px;\n  right: -15px;\n  width: 32px;\n  height: 32px;\n  background: url('/images/fancybox/fancy_close.png') top left no-repeat;\n  cursor: pointer;\n  z-index: 1103;\n  display: none;\n}\n\n#fancybox_error {\n  color: #444;\n  font: normal 12px/20px Arial;\n}\n\n#fancybox-content {\n  height: auto;\n  width: auto;\n  padding: 0;\n  margin: 0;\n}\n\n#fancybox-img {\n  width: 100%;\n  height: 100%;\n  padding: 0;\n  margin: 0;\n  border: none;\n  outline: none;\n  line-height: 0;\n  vertical-align: top;\n  -ms-interpolation-mode: bicubic;\n}\n\n#fancybox-frame {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  border: none;\n  display: block;\n}\n\n#fancybox-title {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  font-family: Arial;\n  font-size: 12px;\n  z-index: 1102;\n}\n\n.fancybox-title-inside {\n  padding: 10px 0;\n  text-align: center;\n  color: #333;\n}\n\n.fancybox-title-outside {\n  padding-top: 5px;\n  color: #FFF;\n  text-align: center;\n  font-weight: bold;\n}\n\n.fancybox-title-over {\n  color: #FFF;\n  text-align: left;\n}\n\n#fancybox-title-over {\n  padding: 10px;\n  background: url('/images/fancybox/fancy_title_over.png');\n  display: block;\n}\n\n#fancybox-title-wrap {\n  display: inline-block;\n}\n\n#fancybox-title-wrap span {\n  height: 32px;\n  float: left;\n}\n\n#fancybox-title-left {\n  padding-left: 15px;\n  background: transparent url('/images/fancybox/fancy_title_left.png') repeat-x;\n}\n\n#fancybox-title-main {\n  font-weight: bold;\n  line-height: 29px;\n  background: transparent url('/images/fancybox/fancy_title_main.png') repeat-x;\n  color: #FFF;\n}\n\n#fancybox-title-right {\n  padding-left: 15px;\n  background: transparent url('/images/fancybox/fancy_title_right.png') repeat-x;\n}\n\n#fancybox-left, #fancybox-right {\n  position: absolute;\n  bottom: 0px;\n  height: 100%;\n  width: 35%;\n  cursor: pointer;\n  outline: none;\n  background-image: url('/images/fancybox/blank.gif');\n  z-index: 1102;\n  display: none;\n}\n\n#fancybox-left {\n  left: 0px;\n}\n\n#fancybox-right {\n  right: 0px;\n}\n\n#fancybox-left-ico, #fancybox-right-ico {\n  position: absolute;\n  top: 50%;\n  left: -9999px;\n  width: 30px;\n  height: 30px;\n  margin-top: -15px;\n  cursor: pointer;\n  z-index: 1102;\n  display: block;\n}\n\n#fancybox-left-ico {\n  background: transparent url('/images/fancybox/fancy_nav_left.png') no-repeat;\n}\n\n#fancybox-right-ico {\n  background: transparent url('/images/fancybox/fancy_nav_right.png') no-repeat;\n}\n\n#fancybox-left:hover, #fancybox-right:hover {\n  visibility: visible;    /* IE6 */\n}\n\n#fancybox-left:hover span {\n  left: 20px;\n}\n\n#fancybox-right:hover span {\n  left: auto;\n  right: 20px;\n}\n\ndiv.fancy-bg {\n  position: absolute;\n  padding: 0;\n  margin: 0;\n  border: 0;\n  z-index: 1001;\n}\n\ndiv#fancy-bg-n {\n  top: -20px;\n  left: 0;\n  width: 100%;\n  height: 20px;\n  background: transparent url('/images/fancybox/fancy_shadow_n.png') repeat-x;\n}\n\ndiv#fancy-bg-ne {\n  top: -20px;\n  right: -20px;\n  width: 20px;\n  height: 20px;\n  background: transparent url('/images/fancybox/fancy_shadow_ne.png') no-repeat;\n}\n\ndiv#fancy-bg-e {\n  top: 0;\n  right: -20px;\n  height: 100%;\n  width: 20px;\n  background: transparent url('/images/fancybox/fancy_shadow_e.png') repeat-y;\n}\n\ndiv#fancy-bg-se {\n  bottom: -20px;\n  right: -20px;\n  width: 20px;\n  height: 20px;\n  background: transparent url('/images/fancybox/fancy_shadow_se.png') no-repeat;\n}\n\ndiv#fancy-bg-s {\n  bottom: -20px;\n  left: 0;\n  width: 100%;\n  height: 20px;\n  background: transparent url('/images/fancybox/fancy_shadow_s.png') repeat-x;\n}\n\ndiv#fancy-bg-sw {\n  bottom: -20px;\n  left: -20px;\n  width: 20px;\n  height: 20px;\n  background: transparent url('/images/fancybox/fancy_shadow_sw.png') no-repeat;\n}\n\ndiv#fancy-bg-w {\n  top: 0;\n  left: -20px;\n  height: 100%;\n  width: 20px;\n  background: transparent url('/images/fancybox/fancy_shadow_w.png') repeat-y;\n}\n\ndiv#fancy-bg-nw {\n  top: -20px;\n  left: -20px;\n  width: 20px;\n  height: 20px;\n  background: transparent url('/images/fancybox/fancy_shadow_nw.png') no-repeat;\n}\n"
  },
  {
    "path": "public/stylesheets/jquery.fancybox-1.3.4.css",
    "content": "/*\n * FancyBox - jQuery Plugin\n * Simple and fancy lightbox alternative\n *\n * Examples and documentation at: http://fancybox.net\n *\n * Copyright (c) 2008 - 2010 Janis Skarnelis\n * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.\n *\n * Version: 1.3.4 (11/11/2010)\n * Requires: jQuery v1.3+\n *\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n */\n\n#fancybox-loading {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 40px;\n  height: 40px;\n  margin-top: -20px;\n  margin-left: -20px;\n  cursor: pointer;\n  overflow: hidden;\n  z-index: 1104;\n  display: none;\n}\n\n#fancybox-loading div {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 40px;\n  height: 480px;\n  background-image: url('/images/fancybox/fancybox.png');\n}\n\n#fancybox-overlay {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  z-index: 1100;\n  display: none;\n}\n\n#fancybox-tmp {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  overflow: auto;\n  display: none;\n}\n\n#fancybox-wrap {\n  position: absolute;\n  top: 0;\n  left: 0;\n  padding: 20px;\n  z-index: 1101;\n  outline: none;\n  display: none;\n}\n\n#fancybox-outer {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  background: #fff;\n}\n\n#fancybox-content {\n  width: 0;\n  height: 0;\n  padding: 0;\n  outline: none;\n  position: relative;\n  overflow: hidden;\n  z-index: 1102;\n  border: 0px solid #fff;\n}\n\n#fancybox-hide-sel-frame {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: transparent;\n  z-index: 1101;\n}\n\n#fancybox-close {\n  position: absolute;\n  top: -15px;\n  right: -15px;\n  width: 30px;\n  height: 30px;\n  background: transparent url('/images/fancybox/fancybox.png') -40px 0px;\n  cursor: pointer;\n  z-index: 1103;\n  display: none;\n}\n\n#fancybox-error {\n  color: #444;\n  font: normal 12px/20px Arial;\n  padding: 14px;\n  margin: 0;\n}\n\n#fancybox-img {\n  width: 100%;\n  height: 100%;\n  padding: 0;\n  margin: 0;\n  border: none;\n  outline: none;\n  line-height: 0;\n  vertical-align: top;\n}\n\n#fancybox-frame {\n  width: 100%;\n  height: 100%;\n  border: none;\n  display: block;\n}\n\n#fancybox-left, #fancybox-right {\n  position: absolute;\n  bottom: 0px;\n  height: 100%;\n  width: 35%;\n  cursor: pointer;\n  outline: none;\n  background: transparent url('/images/fancybox/blank.gif');\n  z-index: 1102;\n  display: none;\n}\n\n#fancybox-left {\n  left: 0px;\n}\n\n#fancybox-right {\n  right: 0px;\n}\n\n#fancybox-left-ico, #fancybox-right-ico {\n  position: absolute;\n  top: 50%;\n  left: -9999px;\n  width: 30px;\n  height: 30px;\n  margin-top: -15px;\n  cursor: pointer;\n  z-index: 1102;\n  display: block;\n}\n\n#fancybox-left-ico {\n  background-image: url('/images/fancybox/fancybox.png');\n  background-position: -40px -30px;\n}\n\n#fancybox-right-ico {\n  background-image: url('/images/fancybox/fancybox.png');\n  background-position: -40px -60px;\n}\n\n#fancybox-left:hover, #fancybox-right:hover {\n  visibility: visible; /* IE6 */\n}\n\n#fancybox-left:hover span {\n  left: 20px;\n}\n\n#fancybox-right:hover span {\n  left: auto;\n  right: 20px;\n}\n\n.fancybox-bg {\n  position: absolute;\n  padding: 0;\n  margin: 0;\n  border: 0;\n  width: 20px;\n  height: 20px;\n  z-index: 1001;\n}\n\n#fancybox-bg-n {\n  top: -20px;\n  left: 0;\n  width: 100%;\n  background-image: url('/images/fancybox/fancybox-x.png');\n}\n\n#fancybox-bg-ne {\n  top: -20px;\n  right: -20px;\n  background-image: url('/images/fancybox/fancybox.png');\n  background-position: -40px -162px;\n}\n\n#fancybox-bg-e {\n  top: 0;\n  right: -20px;\n  height: 100%;\n  background-image: url('/images/fancybox/fancybox-y.png');\n  background-position: -20px 0px;\n}\n\n#fancybox-bg-se {\n  bottom: -20px;\n  right: -20px;\n  background-image: url('/images/fancybox/fancybox.png');\n  background-position: -40px -182px;\n}\n\n#fancybox-bg-s {\n  bottom: -20px;\n  left: 0;\n  width: 100%;\n  background-image: url('/images/fancybox/fancybox-x.png');\n  background-position: 0px -20px;\n}\n\n#fancybox-bg-sw {\n  bottom: -20px;\n  left: -20px;\n  background-image: url('/images/fancybox/fancybox.png');\n  background-position: -40px -142px;\n}\n\n#fancybox-bg-w {\n  top: 0;\n  left: -20px;\n  height: 100%;\n  background-image: url('/images/fancybox/fancybox-y.png');\n}\n\n#fancybox-bg-nw {\n  top: -20px;\n  left: -20px;\n  background-image: url('/images/fancybox/fancybox.png');\n  background-position: -40px -122px;\n}\n\n#fancybox-title {\n  font-family: Helvetica;\n  font-size: 12px;\n  z-index: 1102;\n}\n\n.fancybox-title-inside {\n  padding-bottom: 10px;\n  text-align: center;\n  color: #333;\n  background: #fff;\n  position: relative;\n}\n\n.fancybox-title-outside {\n  padding-top: 10px;\n  color: #fff;\n}\n\n.fancybox-title-over {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  color: #FFF;\n  text-align: left;\n}\n\n#fancybox-title-over {\n  padding: 10px;\n  background-image: url('/images/fancybox/fancy_title_over.png');\n  display: block;\n}\n\n.fancybox-title-float {\n  position: absolute;\n  left: 0;\n  bottom: -20px;\n  height: 32px;\n}\n\n#fancybox-title-float-wrap {\n  border: none;\n  border-collapse: collapse;\n  width: auto;\n}\n\n#fancybox-title-float-wrap td {\n  border: none;\n  white-space: nowrap;\n}\n\n#fancybox-title-float-left {\n  padding: 0 0 0 15px;\n  background: url('/images/fancybox/fancybox.png') -40px -90px no-repeat;\n}\n\n#fancybox-title-float-main {\n  color: #FFF;\n  line-height: 29px;\n  font-weight: bold;\n  padding: 0 0 3px 0;\n  background: url('/images/fancybox/fancybox-x.png') 0px -40px;\n}\n\n#fancybox-title-float-right {\n  padding: 0 0 0 15px;\n  background: url('/images/fancybox/fancybox.png') -55px -90px no-repeat;\n}\n\n/* IE6 */\n\n.fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }\n\n.fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }\n.fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }\n\n.fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }\n.fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }\n.fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }\n.fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }\n\n.fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame {\n  height: expression(this.parentNode.clientHeight + \"px\");\n}\n\n#fancybox-loading.fancybox-ie6 {\n  position: absolute; margin-top: 0;\n  top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px');\n}\n\n#fancybox-loading.fancybox-ie6 div  { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/fancybox/fancy_loading.png', sizingMethod='scale'); }\n\n/* IE6, IE7, IE8 */\n\n.fancybox-ie .fancybox-bg { background: transparent !important; }\n\n.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }\n.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }\n.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }\n.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }\n.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }\n.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }\n.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }\n.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); }\n"
  },
  {
    "path": "public/stylesheets/jquery.fileupload-ui.css",
    "content": ".file_upload {\n  position: relative;\n  overflow: hidden;\n  direction: ltr;\n  cursor: pointer;\n  text-align: center;\n  text-decoration: none;\n  color: black;\n  font-size: 12px;\n  font-weight: bold;\n  width: 100px;\n  height: 20px;\n  line-height: 20px;\n  border: 1px solid #006;\n  border-color: #FFFFFF #666666 #666666 #FFFFFF;\n  padding: 0.1em 0.5em 0.1em 0.5em;\n  background-color: #F0F0F0;\n  background-position: 0.5em;\n  /*border-radius: 8px;\n    -moz-border-radius: 8px;\n    -webkit-border-radius: 8px;\n    -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.3);\n    -moz-box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.3);\n    box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.3);*/\n  cursor:pointer!important;\n}\n\n.file_upload a, .file_upload a:visited{\n  text-decoration:none;\n  color: black;\n  font-weight:normal;\n}\n\n/*.file_upload{\n  border: 1px solid #006;\n  border-color: #FFFFFF #666666 #666666 #FFFFFF;\n  background-color: #ECE9D8 border-style: solid;\n}\n*/\n\n.file_upload_small {\n  width: 200px;\n  height: 30px;\n  line-height: 30px;\n  font-size: auto;\n  background: palegreen;\n  border: 1px solid limegreen;\n}\n\n.file_upload_large {\n  width: 100%;\n  height: 150px;\n  line-height: 150px;\n  font-size: 20px;\n  background: palegreen;\n  border: 1px solid limegreen;\n}\n\n.file_upload_highlight {\n  background: lawngreen;\n}\n\n.file_upload input {\n  position: absolute;\n  top: 0;\n  right: 0;\n  margin: 0;\n  border: 300px solid transparent;\n  opacity: 0;\n  -ms-filter: 'alpha(opacity=0)';\n  filter: alpha(opacity=0);\n  -o-transform: translate(-300px, -300px) scale(10);\n  -moz-transform: translate(-800px, 0) scale(10);\n  cursor: pointer;\n}\n\n.file_upload iframe, .file_upload button {\n  display: none;\n}\n\n.file_upload_preview img {\n  width: 80px;\n}\n\n.file_upload_progress .ui-progressbar-value {\n  background: url(/images/pbar-ani.gif);\n}\n\n.file_upload_progress div {\n  width: 150px;\n  height: 15px;\n}\n\n.file_upload_cancel button {\n  cursor: pointer;\n}\n"
  },
  {
    "path": "public/stylesheets/jquery.tagsinput.css",
    "content": "div.tagsinput, div.tagsoutput {\n  border:0px solid #CCC;\n  background: transparent;\n  padding:5px;\n  }\n\ndiv.tagsinput span.tag {\n  border: 1px solid #73A1D0;\n  -moz-border-radius:2px;\n  -webkit-border-radius:2px;\n  display: block;\n  float: left;\n  padding: 1px 5px 1px 5px;\n  text-decoration:none;\n  background-color: #B2CCE5;\n  color: #365B6D;\n  margin-right: 5px;\n  margin-bottom:5px;\n  font-family: helvetica;\n  font-size:13px;\n  height: 16px;\n  line-height: 17px;\n}\n\ndiv.tagsoutput span.tag {\n  border: 1px solid #73A1D0;\n  -moz-border-radius:2px;\n  -webkit-border-radius:2px;\n  display: block;\n  float: left;\n  padding: 0px 5px 0px 5px;\n  text-decoration:none;\n  background-color: #B2CCE5;\n  color: #365B6D;\n  margin-right: 5px;\n  margin-bottom:5px;\n  font-family: helvetica;\n  font-size:13px;\n  height: 16px;\n  line-height: 17px;\n  }\n\ndiv.tagsdash {\n  float:left;\n  margin-bottom:0px;\n  margin-top:0px;\n  padding-top:1px;\n  padding-left:0px!important;\n  padding-right:1px!important;\n  padding-bottom:0px!important;\n}\n\ndiv.tagsinput span.tag a, div.tagsoutput span.tag a  { font-weight: bold; color: #91928E; text-decoration:none; font-size: 11px;  }\ndiv.tagsinput input, div.tagsoutput input  { width:80px; margin:0px; font-family: helvetica; font-size: 13px; height: 15px; border:1px solid transparent; padding:5px; background: transparent; color: #000; outline:0px;  margin-right:5px; margin-bottom:5px; }\ndiv.tagsinput div, div.tagsoutput div  { display:block; float: left; }\n.tags_clear { clear: both; width: 100%; height: 0px; }\n"
  },
  {
    "path": "public/stylesheets/jquery.ui.autocomplete.css",
    "content": "ul.jq-ui-autocomplete {\n    position: absolute;\n    overflow: hidden;\n    background-color: #fff;\n    border: 1px solid #aaa;\n    margin: 0px;\n    padding: 0;\n    list-style: none;\n    font: normal .75em/.75em Verdana, Arial, sans-serif;\n    color: #333;\n}\nul.jq-ui-autocomplete li {\n  display: block;\n  padding: .3em .5em .3em .3em;\n  overflow: hidden;\n  width: 100%;\n}\n\nul.jq-ui-autocomplete li.active {\n  background-color: #3875d7;\n  color: #fff;\n}\n"
  },
  {
    "path": "public/stylesheets/jstoolbar.css",
    "content": ".jstEditor {\n  padding-left: 0px;\n}\n.jstEditor textarea, .jstEditor iframe {\n  margin: 0;\n}\n\n.jstHandle {\n  height: 10px;\n  font-size: 0.1em;\n  cursor: s-resize;\n  /*background: transparent url(img/resizer.png) no-repeat 45% 50%;*/\n}\n\n.jstElements {\n  padding: 3px 3px;\n}\n\n.jstElements button {\n  margin-right : 6px;\n  width : 24px;\n  height: 24px;\n  padding: 4px;\n  border-style: solid;\n  border-width: 1px;\n  border-color: #ddd;\n  background-color : #f7f7f7;\n  background-position : 50% 50%;\n  background-repeat: no-repeat;\n}\n.jstElements button:hover {\n  border-color : #000;\n}\n.jstElements button span {\n  display : none;\n}\n.jstElements span {\n  display : inline;\n}\n\n.jstSpacer {\n  width : 0px;\n  font-size: 1px;\n  margin-right: 4px;\n}\n\n.jstElements .help { float: right; margin-right: 1em; padding-top: 8px; font-size: 0.9em; }\n\n/* Buttons\n-------------------------------------------------------- */\n.jstb_strong {\n  background-image: url(../images/jstoolbar/bt_strong.png);\n}\n.jstb_em {\n  background-image: url(../images/jstoolbar/bt_em.png);\n}\n.jstb_ins {\n  background-image: url(../images/jstoolbar/bt_ins.png);\n}\n.jstb_del {\n  background-image: url(../images/jstoolbar/bt_del.png);\n}\n.jstb_code {\n  background-image: url(../images/jstoolbar/bt_code.png);\n}\n.jstb_h1 {\n  background-image: url(../images/jstoolbar/bt_h1.png);\n}\n.jstb_h2 {\n  background-image: url(../images/jstoolbar/bt_h2.png);\n}\n.jstb_h3 {\n  background-image: url(../images/jstoolbar/bt_h3.png);\n}\n.jstb_ul {\n  background-image: url(../images/jstoolbar/bt_ul.png);\n}\n.jstb_ol {\n  background-image: url(../images/jstoolbar/bt_ol.png);\n}\n.jstb_bq {\n  background-image: url(../images/jstoolbar/bt_bq.png);\n}\n.jstb_unbq {\n  background-image: url(../images/jstoolbar/bt_bq_remove.png);\n}\n.jstb_pre {\n  background-image: url(../images/jstoolbar/bt_pre.png);\n}\n.jstb_link {\n  background-image: url(../images/jstoolbar/bt_link.png);\n}\n.jstb_img {\n  background-image: url(../images/jstoolbar/bt_img.png);\n}\n"
  },
  {
    "path": "public/stylesheets/lightbox.css",
    "content": "/* - - - - - - - - - - - - - - - - - - - - -\n\nTitle : Lightbox CSS\nAuthor : Kevin Hale\nURL : http://particletree.com/features/lightbox-gone-wild/\n\nCreated : January 13, 2006\nModified : February 1, 2006\n\n- - - - - - - - - - - - - - - - - - - - - */\n\n#lightbox{\n  display:none;\n  position: absolute;\n  top:50%;\n  left:50%;\n  z-index:9999;\n  width:500px;\n  height:400px;\n  margin:-220px 0 0 -250px;\n  border:1px solid #fff;\n  background:#FDFCE9;\n  text-align:left;\n}\n#lightbox[id]{\n  position:fixed;\n}\n\n#overlay{\n  display:none;\n  position:absolute;\n  top:0;\n  left:0;\n  width:100%;\n  height:100%;\n  z-index:5000;\n  background-color:#000;\n  -moz-opacity: 0.8;\n  opacity:.80;\n  filter: alpha(opacity=80);\n}\n#overlay[id]{\n  position:fixed;\n}\n\n#lightbox.done #lbLoadMessage{\n  display:none;\n}\n#lightbox.done #lbContent{\n  display:block;\n}\n#lightbox.loading #lbContent{\n  display:none;\n}\n#lightbox.loading #lbLoadMessage{\n  display:block;\n}\n\n#lightbox.done img{\n  width:100%;\n  height:100%;\n}\n"
  },
  {
    "path": "public/stylesheets/oldapplication.css",
    "content": "body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; }\n\nh1, h2, h3, h4, h5 { font-family: \"Trebuchet MS\", Verdana, sans-serif;}\nh1 {margin:0; padding:0; font-size: 20px;}\nh2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}\nh3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;}\nh4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 4px dotted #bbbbbb; color: #444;}\nh5, .wiki h4 {font-size: 10px;padding: 2px 1px 1px 0px;margin-bottom: 5px; margin-top: -6px; border-bottom: 0px dotted #bbbbbb; color: #444;}\n\n/***** Layout *****/\n#wrapper {background: white;}\n\n#top-menu {background: #2C4056; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;}\n#top-menu ul {margin: 0;  padding: 0;}\n#top-menu li {\n  float:left;\n  list-style-type:none;\n  margin: 0px 0px 0px 0px;\n  padding: 0px 0px 0px 0px;\n  white-space:nowrap;\n}\n#top-menu a {color: #fff; margin-right: 6px; font-weight: bold;}\n#top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }\n#top-menu #notification { float: left; margin-left: 0.5em; margin-top: 4px; color: #fff; font-weight:bold; }\n\n#account {float:right;}\n\n#header {height:5.3em;margin:0;background-color:#507AAA;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;}\n#header a {color:#FFFFFF;}\n#header h1 a.ancestor { font-size: 80%; }\n#quick-search {float:right;}\n\n#main-menu {position: absolute;  bottom: 0px;  left:6px; margin-right: -500px;}\n#main-menu ul {margin: 0;  padding: 0; float: left;}\n#main-menu li {\n  float:left;\n  list-style-type:none;\n  margin: 0px 2px 0px 0px;\n  padding: 0px 0px 0px 0px;\n  white-space:nowrap;\n}\n#main-menu li a {\n  display: block;\n  color: #fff;\n  text-decoration: none;\n  font-weight: bold;\n  margin: 0;\n  padding: 4px 10px 4px 10px;\n}\n#main-menu li a:hover {background:#759FCF; color:#fff;}\n#main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;}\n\n#admin-menu ul {margin: 0;  padding: 0;}\n#admin-menu li {margin: 0;  padding: 0 0 12px 0; list-style-type:none;}\n\n#admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;}\n#admin-menu a.projects { background-image: url(../images/projects.png); }\n#admin-menu a.users { background-image: url(../images/user.png); }\n#admin-menu a.groups { background-image: url(../images/group.png); }\n#admin-menu a.roles { background-image: url(../images/database_key.png); }\n#admin-menu a.trackers { background-image: url(../images/ticket.png); }\n#admin-menu a.issue_statuses { background-image: url(../images/ticket_edit.png); }\n#admin-menu a.workflows { background-image: url(../images/ticket_go.png); }\n#admin-menu a.custom_fields { background-image: url(../images/textfield.png); }\n#admin-menu a.enumerations { background-image: url(../images/text_list_bullets.png); }\n#admin-menu a.settings { background-image: url(../images/changeset.png); }\n#admin-menu a.plugins { background-image: url(../images/plugin.png); }\n#admin-menu a.info { background-image: url(../images/help.png); }\n\n#main {background-color:#EEEEEE;}\n\n#sidebar{ float: right; width: 30%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;}\n* html #sidebar{ width: 17%; }\n#sidebar h3{ font-size: 14px; margin-top:14px; color: #666;  }\n#sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }\n* html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }\n\n#content { /*width: 70%;*/ background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }\n* html #content{/* width: 70%;*/ padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}\nhtml>body #content { min-height: 600px; overflow-x: hidden; border-bottom: hidden; }\n* html body #content { height: 600px; } /* IE */\n\n#main.nosidebar #sidebar{ display: none; }\n#main.nosidebar #content{ width: auto; border-right: 0; }\n\n#footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;}\n\n#login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; }\n#login-form table td {padding: 6px;}\n#login-form label {font-weight: bold;}\n#login-form input#username, #login-form input#password { width: 300px; }\n\ninput#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; }\n\n.clear:after{ content: \".\"; display: block; height: 0; clear: both; visibility: hidden; }\n\n/***** Links *****/\na, a:link, a:visited{ color: #2A5685; text-decoration: none; }\na:hover, a:active{ color: #c61a1a; text-decoration: underline;}\na img{ border: 0; }\n\na.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; }\n\n/***** Tables *****/\ntable.list { border: 1px solid #e4e4e4;  border-collapse: collapse; width: 100%; margin-bottom: 4px; }\ntable.list th {  background-color:#EEEEEE; padding: 4px; white-space:nowrap; text-align: left; }\ntable.list td { vertical-align: top; }\ntable.list td.id { width: 2%; text-align: center;}\ntable.list td.checkbox { width: 15px; padding: 0px;}\ntable.list td.buttons { width: 15%; white-space:nowrap; text-align: right; }\ntable.list td.buttons a { padding-right: 0.6em; }\n\ntr.project td.name a { padding-left: 16px; white-space:nowrap; }\ntr.project.parent td.name a { background: url('../images/bullet_toggle_minus.png') no-repeat; }\n\ntr.issue { text-align: center; white-space: nowrap; }\ntr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; }\ntr.issue td.subject { text-align: left; }\ntr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}\n\ntr.entry { border: 1px solid #f8f8f8; }\ntr.entry td { white-space: nowrap; }\ntr.entry td.filename { width: 30%; }\ntr.entry td.size { text-align: right; font-size: 90%; }\ntr.entry td.revision, tr.entry td.author { text-align: center; }\ntr.entry td.age { text-align: right; }\ntr.entry.file td.filename a { margin-left: 16px; }\n\ntr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;}\ntr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);}\n\ntr.changeset td.author { text-align: center; width: 15%; }\ntr.changeset td.committed_on { text-align: center; width: 15%; }\n\ntable.files tr.file td { text-align: center; }\ntable.files tr.file td.filename { text-align: left; padding-left: 24px; }\ntable.files tr.file td.digest { font-size: 80%; }\n\ntable.members td.roles, table.memberships td.roles { width: 45%; }\n\ntr.message { height: 2.6em; }\ntr.message td.last_message { font-size: 80%; }\ntr.message.locked td.subject a { background-image: url(../images/locked.png); }\ntr.message.sticky td.subject a { background-image: url(../images/sticky.png); font-weight: bold; }\n\ntr.version.closed, tr.version.closed a { color: #999; }\ntr.version td.name { padding-left: 20px; }\ntr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; }\ntr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; }\n\ntr.user td { width:13%; }\ntr.user td.email { width:18%; }\ntr.user td { white-space: nowrap; }\ntr.user.locked, tr.user.registered { color: #aaa; }\ntr.user.locked a, tr.user.registered a { color: #aaa; }\n\ntr.time-entry { text-align: center; white-space: nowrap; }\ntr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; }\ntd.hours { text-align: right; font-weight: bold; padding-right: 0.5em; }\ntd.hours .hours-dec { font-size: 0.9em; }\n\ntable.plugins td { vertical-align: middle; }\ntable.plugins td.configure { text-align: right; padding-right: 1em; }\ntable.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; }\ntable.plugins span.description { display: block; font-size: 0.9em; }\ntable.plugins span.url { display: block; font-size: 0.9em; }\n\ntable.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; }\ntable.list tbody tr.group span.count { color: #aaa; font-size: 80%; }\n\ntable.list tbody tr:hover { background-color:#ffffdd; }\ntable.list tbody tr.group:hover { background-color:inherit; }\ntable td {padding:2px;}\ntable p {margin:0;}\n.odd {background-color:#f6f7f8;}\n.even {background-color: #fff;}\n\na.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; }\na.sort.asc  { background-image: url(../images/sort_asc.png); }\na.sort.desc { background-image: url(../images/sort_desc.png); }\n\n/*table.attributes { width: 100% }*/\ntable.attributes th { text-align: left; }\ntable.attributes td { padding: 2px;}\n\ntable.boards a.board, h3.comments { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; }\n\ntd.center {text-align:center;}\n\nh3.version { background: url(../images/package.png) no-repeat 0% 50%; padding-left: 20px; }\n\ndiv.issues h3 { background: url(../images/ticket.png) no-repeat 0% 50%; padding-left: 20px; }\ndiv.members h3 { background: url(../images/group.png) no-repeat 0% 50%; padding-left: 20px; }\ndiv.news h3 { background: url(../images/news.png) no-repeat 0% 50%; padding-left: 20px; }\ndiv.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padding-left: 20px; }\n\n.highlight { background-color: #FCFD8D;}\n.highlight.token-1 { background-color: #faa;}\n.highlight.token-2 { background-color: #afa;}\n.highlight.token-3 { background-color: #aaf;}\n.search-highlight { background-color: #FCFD8D;font-weight:bold;}\n\n.box{\npadding:6px;\nmargin-bottom: 10px;\nbackground-color:#f6f6f6;\ncolor:#505050;\nline-height:1.5em;\nborder: 1px solid #e4e4e4;\n}\n\ndiv.square {\n border: 1px solid #999;\n float: left;\n margin: .3em .4em 0 .4em;\n overflow: hidden;\n width: .6em; height: .6em;\n}\n.contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;}\n.contextual input, .contextual select {font-size:0.9em;}\n.message .contextual { margin-top: 0; }\n\n.splitcontentleft{float:left; width:49%;}\n.splitcontentright{float:right; width:49%;}\nform {display: inline;}\ninput, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}\nfieldset {border: 1px solid #e4e4e4; margin:0;}\nlegend {color: #484848;}\nhr { width: 100%; height: 1px; background: #ccc; border: 0;}\nblockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}\nblockquote blockquote { margin-left: 0;}\nacronym  { border-bottom: 1px dotted; cursor: help; }\ntextarea.wiki-edit { width: 99%; }\nli p {margin-top: 0;}\ndiv.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}\np.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}\np.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }\np.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }\n\nfieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; }\nfieldset.collapsible legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; }\nfieldset.collapsible.collapsed legend { background-image: url(../images/arrow_collapsed.png); }\n\nfieldset#date-range p { margin: 2px 0 2px 0; }\nfieldset#filters table { border-collapse: collapse; }\nfieldset#filters table td { padding: 0; vertical-align: middle; }\nfieldset#filters tr.filter { height: 2em; }\nfieldset#filters td.add-filter { text-align: right; vertical-align: top; }\n.buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; }\n\ndiv#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}\ndiv#issue-changesets .changeset { padding: 4px;}\ndiv#issue-changesets .changeset { border-bottom: 1px solid #ddd; }\ndiv#issue-changesets p { margin-top: 0; margin-bottom: 1em;}\n\ndiv#activity dl, #search-results { margin-left: 2em; }\ndiv#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }\ndiv#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }\ndiv#activity dt.me .time { border-bottom: 1px solid #999; }\ndiv#activity dt .time { color: #777; font-size: 80%; }\ndiv#activity dd .description, #search-results dd .description { font-style: italic; }\ndiv#activity span.project:after, #search-results span.project:after { content: \" -\"; }\ndiv#activity dd span.description, #search-results dd span.description { display:block; color: #808080; }\n\n#search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }\n\ndiv#search-results-counts {float:right;}\ndiv#search-results-counts ul { margin-top: 0.5em; }\ndiv#search-results-counts  li { list-style-type:none; float: left; margin-left: 1em; }\n\ndt.issue { background-image: url(../images/ticket.png); }\ndt.issue-edit { background-image: url(../images/ticket_edit.png); }\ndt.issue-closed { background-image: url(../images/ticket_checked.png); }\ndt.issue-note { background-image: url(../images/ticket_note.png); }\ndt.changeset { background-image: url(../images/changeset.png); }\ndt.news { background-image: url(../images/news.png); }\ndt.message { background-image: url(../images/message.png); }\ndt.reply { background-image: url(../images/comments.png); }\ndt.wiki-page { background-image: url(../images/wiki_edit.png); }\ndt.attachment { background-image: url(../images/attachment.png); }\ndt.document { background-image: url(../images/document.png); }\ndt.project { background-image: url(../images/projects.png); }\ndt.time-entry { background-image: url(../images/time.png); }\ndt.cr-note { background-image: url(../images/tag_blue.png); }\ndt.team-offer { background-image: url(../images/user_new.png); }\ndt.member-role { background-image: url(../images/users.png); }\n\n#search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); }\n\ndiv#roadmap fieldset.related-issues { margin-bottom: 1em; }\ndiv#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; }\ndiv#roadmap .wiki h1:first-child { display: none; }\ndiv#roadmap .wiki h1 { font-size: 120%; }\ndiv#roadmap .wiki h2 { font-size: 110%; }\n\ndiv#version-summary { float:right; width:380px; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }\ndiv#version-summary fieldset { margin-bottom: 1em; }\ndiv#version-summary .total-hours { text-align: right; }\n\ntable#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; }\ntable#time-report tbody tr { font-style: italic; color: #777; }\ntable#time-report tbody tr.last-level { font-style: normal; color: #555; }\ntable#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; }\ntable#time-report .hours-dec { font-size: 0.9em; }\n\nform#issue-form .attributes { margin-bottom: 8px; }\nform#issue-form .attributes p { padding-top: 1px; padding-bottom: 2px; }\nform#issue-form .attributes select { min-width: 30%; }\n\nul.projects { margin: 0; padding-left: 1em; }\nul.projects.root { margin: 0;  padding: 0; }\nul.projects ul { border-left: 3px solid #e0e0e0; }\nul.projects li { list-style-type:none; }\nul.projects li.root { margin-bottom: 1em; }\nul.projects li.child { margin-top: 1em;}\nul.projects div.root a.project { font-family: \"Trebuchet MS\", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }\n.my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; }\n\n#tracker_project_ids ul { margin: 0;  padding-left: 1em; }\n#tracker_project_ids li { list-style-type:none; }\n\nul.properties {padding:0; font-size: 0.9em; color: #777;}\nul.properties li {list-style-type:none;}\nul.properties li span {font-style:italic;}\n\n.total-hours { font-size: 110%; font-weight: bold; }\n.total-hours span.hours-int { font-size: 120%; }\n\n.autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}\n#user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }\n\n#workflow_copy_form select { width: 200px; }\n\n.pagination {font-size: 90%}\np.pagination {margin-top:8px;}\n\n/***** Tabular forms ******/\n.tabular p{\nmargin: 0;\npadding: 5px 0 8px 0;\npadding-left: 180px; /*width of left column containing the label elements*/\nheight: 1%;\nclear:left;\n}\n\nhtml>body .tabular p {overflow:hidden;}\n\n.tabular label{\nfont-weight: bold;\nfloat: left;\ntext-align: right;\nmargin-left: -180px; /*width of left column*/\nwidth: 175px; /*width of labels. Should be smaller than left column to create some right\nmargin*/\n}\n\n.tabular label.floating{\nfont-weight: normal;\nmargin-left: 0px;\ntext-align: left;\nwidth: 270px;\n}\n\n.tabular label.block{\nfont-weight: normal;\nmargin-left: 0px !important;\ntext-align: left;\nfloat: none;\ndisplay: block;\nwidth: auto;\n}\n\ninput#time_entry_comments { width: 90%;}\n\n#preview fieldset {margin-top: 1em; background: url(../images/draft.png)}\n\n.tabular.settings p{ padding-left: 300px; }\n.tabular.settings label{ margin-left: -300px; width: 295px; }\n.tabular.settings textarea { width: 99%; }\n\nfieldset.settings label { display: block; }\n\n.required {color: #bb0000;}\n.summary {font-style: italic;}\n\n#attachments_fields input[type=text] {margin-left: 8px; }\n\ndiv.attachments { margin-top: 12px; }\ndiv.attachments p { margin:4px 0 2px 0; }\ndiv.attachments img { vertical-align: middle; }\ndiv.attachments span.author { font-size: 0.9em; color: #888; }\n\np.other-formats { text-align: right; font-size:0.9em; color: #666; }\n.other-formats span + span:before { content: \"| \"; }\n\na.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }\n\n/* Project members tab */\ndiv#tab-content-members .splitcontentleft, div#tab-content-memberships .splitcontentleft, div#tab-content-users .splitcontentleft { width: 64% }\ndiv#tab-content-members .splitcontentright, div#tab-content-memberships .splitcontentright, div#tab-content-users .splitcontentright { width: 34% }\ndiv#tab-content-members fieldset, div#tab-content-memberships fieldset, div#tab-content-users fieldset { padding:1em; margin-bottom: 1em; }\ndiv#tab-content-members fieldset legend, div#tab-content-memberships fieldset legend, div#tab-content-users fieldset legend { font-weight: bold; }\ndiv#tab-content-members fieldset label, div#tab-content-memberships fieldset label, div#tab-content-users fieldset label { display: block; }\ndiv#tab-content-members fieldset div, div#tab-content-users fieldset div { max-height: 400px; overflow:auto; }\n\ntable.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; }\n\n* html div#tab-content-members fieldset div { height: 450px; }\n\n/***** Flash & error messages ****/\n#errorExplanation, div.flash, .nodata, .warning {\n    padding: 4px 4px 4px 30px;\n    margin-bottom: 12px;\n  font-size: 1.1em;\n  border: 2px solid;\n}\n\ndiv.flash {margin-top: 8px;}\n\ndiv.flash.error, #errorExplanation {\n  background: url(../images/exclamation.png) 8px 50% no-repeat;\n  background-color: #ffe3e3;\n  border-color: #dd0000;\n  color: #880000;\n}\n\ndiv.flash.notice {\n    background: url(../images/true.png) 8px 5px no-repeat;\n  background-color: #dfffdf;\n  border-color: #9fcf9f;\n  color: #005f00;\n}\n\ndiv.flash.warning {\n  background: url(../images/warning.png) 8px 5px no-repeat;\n  background-color: #FFEBC1;\n  border-color: #FDBF3B;\n  color: #A6750C;\n  text-align: left;\n}\n\n.nodata, .warning {\n    text-align: center;\n  background-color: #FFEBC1;\n  border-color: #FDBF3B;\n  color: #A6750C;\n}\n\n#errorExplanation ul { font-size: 0.9em;}\n#errorExplanation h2, #errorExplanation p { display: none; }\n\n/***** Ajax indicator ******/\n#ajax-indicator {\nposition: absolute; /* fixed not supported by IE */\nbackground-color:#eee;\nborder: 1px solid #bbb;\ntop:35%;\nleft:40%;\nwidth:20%;\nfont-weight:bold;\ntext-align:center;\npadding:0.6em;\nz-index:100;\nfilter:alpha(opacity=50);\nopacity: 0.5;\n}\n\nhtml>body #ajax-indicator { position: fixed; }\n\n#ajax-indicator span {\nbackground-position: 0% 40%;\nbackground-repeat: no-repeat;\nbackground-image: url(../images/loading.gif);\npadding-left: 26px;\nvertical-align: bottom;\n}\n\n/***** Calendar *****/\ntable.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}\ntable.cal thead th {width: 14%;}\ntable.cal tbody tr {height: 100px;}\ntable.cal th { background-color:#EEEEEE; padding: 4px; }\ntable.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}\ntable.cal td p.day-num {font-size: 1.1em; text-align:right;}\ntable.cal td.odd p.day-num {color: #bbb;}\ntable.cal td.today {background:#ffffdd;}\ntable.cal td.today p.day-num {font-weight: bold;}\n\n/***** Tooltips ******/\n.tooltip{position:relative;z-index:24;}\n.tooltip:hover{z-index:25;color:#000;}\n.tooltip span.tip{display: none; text-align:left;}\n\ndiv.tooltip:hover span.tip{\ndisplay:block;\nposition:absolute;\ntop:12px; left:24px; width:270px;\nborder:1px solid #555;\nbackground-color:#fff;\npadding: 4px;\nfont-size: 0.8em;\ncolor:#505050;\n}\n\n/***** Progress bar *****/\ntable.progress {\n    border: 1px solid #D7D7D7;\n    border-collapse: collapse;\n    border-spacing: 0pt;\n    empty-cells: show;\n    text-align: center;\n    float:left;\n    margin: 1px 6px 1px 0px;\n}\n\ntable.progress td { height: 0.9em; }\ntable.progress td.closed { background: #BAE0BA none repeat scroll 0%; }\ntable.progress td.done { background: #DEF0DE none repeat scroll 0%; }\ntable.progress td.open { background: #FFF none repeat scroll 0%; }\np.pourcent {font-size: 80%;}\np.progress-info {clear: left; font-style: italic; font-size: 80%;}\n\n/***** Tabs *****/\n#content .tabs {height: 2.6em; border-bottom: 1px solid #bbbbbb; margin-bottom:1.2em; position:relative; overflow:hidden;}\n#content .tabs ul {margin:0; position:absolute; bottom:-2px; padding-left:1em; width: 2000px;}\n#content .tabs>ul { bottom:-1px; } /* others */\n#content .tabs ul li {\nfloat:left;\nlist-style-type:none;\nwhite-space:nowrap;\nmargin-right:8px;\nbackground:#fff;\n}\n#content .tabs ul li a{\ndisplay:block;\nfont-size: 0.9em;\ntext-decoration:none;\nline-height:1.3em;\npadding:4px 6px 4px 6px;\nborder: 1px solid #ccc;\nborder-bottom: 1px solid #bbbbbb;\nbackground-color: #eeeeee;\ncolor:#777;\nfont-weight:bold;\n}\n\n#content .tabs ul li a:hover {\nbackground-color: #ffffdd;\ntext-decoration:none;\n}\n\n#content .tabs ul li a.selected {\nbackground-color: #fff;\nborder: 1px solid #bbbbbb;\nborder-bottom: 1px solid #fff;\n}\n\n#content .tabs ul li a.selected:hover {\nbackground-color: #fff;\n}\n\ndiv.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: -1px;  }\n\nbutton.tab-left, button.tab-right {\n  font-size: 0.9em;\n  cursor: pointer;\n  height:24px;\n  border: 1px solid #ccc;\n  border-bottom: 1px solid #bbbbbb;\n  position:absolute;\n  padding:4px;\n  width: 20px;\n}\n\nbutton.tab-left {\n  right: 20px;\n  bottom: 0;\n  background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%;\n}\n\nbutton.tab-right {\n  right: 0;\n  bottom: 0;\n  background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%;}\n}\n\n/***** Auto-complete *****/\ndiv.autocomplete {\n  position:absolute;\n  width:250px;\n  background-color:white;\n  margin:0;\n  padding:0;\n}\ndiv.autocomplete ul {\n  list-style-type:none;\n  margin:0;\n  padding:0;\n}\ndiv.autocomplete ul li.selected { background-color: #ffb;}\ndiv.autocomplete ul li {\n  list-style-type:none;\n  display:block;\n  margin:0;\n  padding:2px;\n  cursor:pointer;\n  font-size: 90%;\n  border-bottom: 1px solid #ccc;\n  border-left: 1px solid #ccc;\n  border-right: 1px solid #ccc;\n}\ndiv.autocomplete ul li span.informal {\n  font-size: 80%;\n  color: #aaa;\n}\n\n/***** Diff *****/\n.diff_out { background: #fcc; }\n.diff_in { background: #cfc; }\n\n/***** Wiki *****/\ndiv.wiki table {\n    border: 1px solid #505050;\n    border-collapse: collapse;\n    margin-bottom: 1em;\n}\n\ndiv.wiki table, div.wiki td, div.wiki th {\n    border: 1px solid #bbb;\n    padding: 4px;\n}\n\ndiv.wiki .external {\n    background-position: 0% 60%;\n    background-repeat: no-repeat;\n    padding-left: 12px;\n    background-image: url(../images/external.png);\n}\n\ndiv.wiki a.new {\n    color: #b73535;\n}\n\ndiv.wiki pre {\n    margin: 1em 1em 1em 1.6em;\n    padding: 2px;\n    background-color: #fafafa;\n    border: 1px solid #dadada;\n    width:95%;\n    overflow-x: auto;\n}\n\ndiv.wiki ul.toc {\n    background-color: #ffffdd;\n    border: 1px solid #e4e4e4;\n    padding: 4px;\n    line-height: 1.2em;\n    margin-bottom: 12px;\n    margin-right: 12px;\n    margin-left: 0;\n    display: table\n}\n* html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */\n\ndiv.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }\ndiv.wiki ul.toc.left  { float: left; margin-right: 12px; margin-left: 0; width: auto; }\ndiv.wiki ul.toc li { list-style-type:none;}\ndiv.wiki ul.toc li.heading2 { margin-left: 6px; }\ndiv.wiki ul.toc li.heading3 { margin-left: 12px; font-size: 0.8em; }\n\ndiv.wiki ul.toc a {\n    font-size: 0.9em;\n    font-weight: normal;\n    text-decoration: none;\n    color: #606060;\n}\ndiv.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}\n\na.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }\na.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }\nh1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }\n\n/***** My page layout *****/\n.block-receiver {\nborder:1px dashed #c0c0c0;\nmargin-bottom: 20px;\npadding: 15px 0 15px 0;\n}\n\n.mypage-box {\nmargin:0 0 20px 0;\ncolor:#505050;\nline-height:1.5em;\n}\n\n.handle {\ncursor: move;\n}\n\na.close-icon {\ndisplay:block;\nmargin-top:3px;\noverflow:hidden;\nwidth:12px;\nheight:12px;\nbackground-repeat: no-repeat;\ncursor:pointer;\nbackground-image:url('../images/close.png');\n}\n\na.close-icon:hover {\nbackground-image:url('../images/close_hl.png');\n}\n\n/***** Gantt chart *****/\n.gantt_hdr {\n  position:absolute;\n  top:0;\n  height:16px;\n  border-top: 1px solid #c0c0c0;\n  border-bottom: 1px solid #c0c0c0;\n  border-right: 1px solid #c0c0c0;\n  text-align: center;\n  overflow: hidden;\n}\n\n.task {\n  position: absolute;\n  height:8px;\n  font-size:0.8em;\n  color:#888;\n  padding:0;\n  margin:0;\n  line-height:0.8em;\n}\n\n.task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }\n.task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }\n.task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }\n.milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }\n\n/***** Icons *****/\n.icon {\nbackground-position: 0% 50%;\nbackground-repeat: no-repeat;\npadding-left: 20px;\npadding-top: 2px;\npadding-bottom: 3px;\n}\n\n.icon-add { background-image: url(../images/add.png); }\n.icon-bullet-add { background-image: url(../images/bullet_add.png); }\n.icon-bullet-delete { background-image: url(../images/bullet_delete.png); }\n.icon-edit { background-image: url(../images/edit.png); }\n.icon-copy { background-image: url(../images/copy.png); }\n.icon-duplicate { background-image: url(../images/duplicate.png); }\n.icon-del { background-image: url(../images/delete.png); }\n.icon-move { background-image: url(../images/move.png); }\n.icon-save { background-image: url(../images/save.png); }\n.icon-cancel { background-image: url(../images/cancel.png); }\n.icon-multiple { background-image: url(../images/table_multiple.png); }\n.icon-folder { background-image: url(../images/folder.png); }\n.open .icon-folder { background-image: url(../images/folder_open.png); }\n.icon-package { background-image: url(../images/package.png); }\n.icon-home { background-image: url(../images/home.png); }\n.icon-user { background-image: url(../images/user.png); }\n.icon-projects { background-image: url(../images/projects.png); }\n.icon-help { background-image: url(../images/help.png); }\n.icon-attachment  { background-image: url(../images/attachment.png); }\n.icon-history  { background-image: url(../images/history.png); }\n.icon-time  { background-image: url(../images/time.png); }\n.icon-time-add  { background-image: url(../images/time_add.png); }\n.icon-stats  { background-image: url(../images/stats.png); }\n.icon-warning  { background-image: url(../images/warning.png); }\n.icon-fav  { background-image: url(../images/fav.png); }\n.icon-fav-off  { background-image: url(../images/fav_off.png); }\n.icon-reload  { background-image: url(../images/reload.png); }\n.icon-lock  { background-image: url(../images/locked.png); }\n.icon-unlock  { background-image: url(../images/unlock.png); }\n.icon-checked  { background-image: url(../images/true.png); }\n.icon-details  { background-image: url(../images/zoom_in.png); }\n.icon-report  { background-image: url(../images/report.png); }\n.icon-comment  { background-image: url(../images/comment.png); }\n.icon-cr-cancel  { background-image: url(../images/cancel16.png); }\n.icon-cr-request { background-image: url(../images/tag_blue.png); }\n.icon-cr-take { background-image: url(../images/wrench.png); }\n.icon-cr-offer { background-image: url(../images/user_go.png); }\n.icon-cr-accept { background-image: url(../images/true.png); }\n.icon-cr-decline { background-image: url(../images/false.png); }\n.icon-cr-ignore { background-image: url(../images/ignore.gif); }\n.icon-summary  { background-image: url(../images/lightning.png); }\n\n.icon-file { background-image: url(../images/files/default.png); }\n.icon-file.text-plain { background-image: url(../images/files/text.png); }\n.icon-file.text-x-c { background-image: url(../images/files/c.png); }\n.icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); }\n.icon-file.text-x-php { background-image: url(../images/files/php.png); }\n.icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); }\n.icon-file.text-xml { background-image: url(../images/files/xml.png); }\n.icon-file.image-gif { background-image: url(../images/files/image.png); }\n.icon-file.image-jpeg { background-image: url(../images/files/image.png); }\n.icon-file.image-png { background-image: url(../images/files/image.png); }\n.icon-file.image-tiff { background-image: url(../images/files/image.png); }\n.icon-file.application-pdf { background-image: url(../images/files/pdf.png); }\n.icon-file.application-zip { background-image: url(../images/files/zip.png); }\n.icon-file.application-x-gzip { background-image: url(../images/files/zip.png); }\n\nimg.gravatar {\n  padding: 2px;\n  border: solid 1px #d5d5d5;\n  background: #fff;\n}\n\ndiv.issue img.gravatar {\n  float: right;\n  margin: 0 0 0 1em;\n  padding: 5px;\n}\n\ndiv.issue table img.gravatar {\n  height: 14px;\n  width: 14px;\n  padding: 2px;\n  float: left;\n  margin: 0 0.5em 0 0;\n}\n\n#history img.gravatar {\n  padding: 3px;\n  margin: 0 1.5em 1em 0;\n  float: left;\n}\n\ntd.username img.gravatar {\n  float: left;\n  margin: 0 1em 0 0;\n}\n\n#activity dt img.gravatar {\n  float: left;\n  margin: 0 1em 1em 0;\n}\n\n#activity dt,\n.journal {\n  clear: left;\n}\n\n.gravatar-margin {\n  margin-left: 60px;\n}\n\nh2 img { vertical-align:middle; }\n\n.hascontextmenu { cursor: context-menu; }\n\n/***** Media print specific styles *****/\n@media print {\n  #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }\n  #main { background: #fff; }\n  #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}\n  #wiki_add_attachment { display:none; }\n}\n\n\n/*Voting*/\n\n.issuevote {\n/*  float: left;*/\n  margin: 2px 0px 1px;\n  padding: 1px;\n  font-size: 12px;\n  font-weight: bold;\n  font-family: baskerville, Times, Times New Roman, serif;\n  color:#484848;\n  text-align:center;\n  width:20px;\n\n}\n\n.issuevote table{\n  padding: 0px;\n  margin: 0px;\n}\n\n.issuevote tr{\n  padding: 0px;\n  margin: 0px;\n  height: 14px;\n  width: 15px;\n}\n\n.issuevote td{\n  padding: 0px;\n  margin: 0px;\n}\n\n.messagevote {\n  -moz-border-radius-bottomleft:3px;\n  -moz-border-radius-bottomright:3px;\n  -moz-border-radius-topleft:3px;\n  -moz-border-radius-topright:3px;\n  background-color:#CDE9A7;\n  border:1px solid #ADDE6B;\n  color:#455138;\n  font-family:baskerville,Times,Times New Roman,serif;\n  font-size:21px;\n  font-weight:normal;\n  margin:2px 0 10px;\n  padding:0px 0px 0px 10px;\n  flaot: left;\n}\n\n.messagevote table{\n  padding: 0px;\n  margin: 0px;\n  font-size:12px;\n}\n\n.messagevote tr{\n  padding: 0px;\n  margin: 0px;\n/*  width: 15px;*/\n}\n\n.messagevote td{\n  padding: 0px 2px 0px 0px;\n  margin: 0px;\n  text-align: center;\n}\n\n.messagevote td#topic{\n  font-size: 21px;\n  vertical-align: top;\n}\n\n.journalvote {\n/*  float:right; */\n  white-space: nowrap;\n  line-height:1.4em;\n  padding-left: 10px;\n  font-size:0.9em;\n  margin-top: 1.4em;\n  margin-right: 1em; f\n  padding: 1px;\n  font-weight: bold;\n  font-family: baskerville, Times, Times New Roman, serif;\n  color:#484848;\n  text-align:center;\n/*  float: right;*/\n}\n\n.replyvote {\n  float:right;\n  white-space: nowrap;\n  line-height:1.4em;\n  padding-left: 10px;\n  font-size:0.9em;\n  margin-top: 1.4em;\n  margin-right: 1em; f\n  padding: 1px;\n  font-weight: bold;\n  font-family: baskerville, Times, Times New Roman, serif;\n  color:#484848;\n  text-align:center;\n/*  float: right;*/\n}\n\n/*create_request_dialogue*/\n.create_request_dialogue {\n  margin: -13px 10px 0px 10px;\n  text-align: center;\n}\n\n.help_dialogue {\n  margin: -13px 10px 0px 10px;\n  text-align: center;\n}\n\n/*Notifications*/\n\n.notification {\nborder-style:solid;\n/*background-color:#F7F7F7;*/\nborder-color:#CCCCCC;\nborder-style:solid;\nborder-width:1px 0;\nline-height:15px;\nmargin:0 0 -1px;\npadding:1px 20px 12px 20px;\n}\n\n.notification_response {\nbackground-color:#F7F7F7;\nborder-style:solid;\n/*background-color:#F7F7F7;*/\nborder-color:#CCCCCC;\nborder-style:solid;\nborder-width:1px 0;\nline-height:15px;\nmargin:0 0 -1px;\npadding:1px 20px 1px 20px;\n}\n\n\n/*JGROWL*/\n\ndiv.jGrowl {\n  padding:       10px;\n  z-index:       9999;\n  color:         #fff;\n  font-size:       12px;\n}\n\n/** Special IE6 Style Positioning **/\ndiv.ie6 {\n  position:       absolute;\n}\n\ndiv.ie6.top-right {\n  right:         auto;\n  bottom:       auto;\n  left:         expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n    top:         expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.top-left {\n  left:         expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.bottom-right {\n  left:         expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.bottom-left {\n  left:         expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.center {\n  left:         expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n  width:         100%;\n}\n\n/** Normal Style Positions **/\nbody > div.jGrowl {\n  position:      fixed;\n}\n\nbody > div.jGrowl.top-left {\n  left:         0px;\n  top:         0px;\n}\n\nbody > div.jGrowl.top-right {\n  right:         0px;\n  top:         0px;\n}\n\nbody > div.jGrowl.bottom-left {\n  left:         0px;\n  bottom:        0px;\n}\n\nbody > div.jGrowl.bottom-right {\n  right:         0px;\n  bottom:       0px;\n}\n\nbody > div.jGrowl.center {\n  top:         0px;\n  width:         50%;\n  left:         25%;\n}\n\n/** Cross Browser Styling **/\ndiv.center div.jGrowl-notification, div.center div.jGrowl-closer {\n  margin-left:     auto;\n  margin-right:     auto;\n}\n\ndiv.jGrowl div.jGrowl-notification, div.jGrowl div.jGrowl-closer {\n  background-color:     #d30921;\n/*  opacity:         .85;*/\n    -ms-filter:       \"progid:DXImageTransform.Microsoft.Alpha(Opacity=85)\";\n    filter:         progid:DXImageTransform.Microsoft.Alpha(Opacity=85);\n  zoom:           1;\n  width:           235px;\n  padding:         10px;\n  margin-top:       5px;\n  margin-bottom:       5px;\n  font-family:       Tahoma, Arial, Helvetica, sans-serif;\n  font-size:         1em;\n  text-align:       left;\n  display:         none;\n  -moz-border-radius:   5px;\n  -webkit-border-radius:  5px;\n}\n\ndiv.jGrowl div.jGrowl-notification {\n  min-height:       40px;\n}\n\ndiv.jGrowl div.jGrowl-notification div.header {\n  font-weight:       bold;\n  font-size:        .85em;\n}\n\ndiv.jGrowl div.jGrowl-notification div.close {\n  z-index:        99;\n  float:           right;\n  font-weight:       bold;\n  font-size:         1em;\n  cursor:          pointer;\n}\n\ndiv.jGrowl div.jGrowl-closer {\n  padding-top:       4px;\n  padding-bottom:     4px;\n  cursor:         pointer;\n  font-size:        .9em;\n  font-weight:       bold;\n  text-align:       center;\n}\n\n/** Hide jGrowl when printing **/\n@media print {\n  div.jGrowl {\n    display:       none;\n  }\n}\n\ntable.retrospective {margin-bottom: 30px;}\ntable.retrospective th { vertical-align: top; text-align: left; }\ntable.retrospective td {padding: 3px;}\ntable.retrospective td.avatar { vertical-align: top; padding-right: 5px;}\ntable.retrospective td.name { vertical-align: top; padding-right: 5px; width:3em}\ntable.retrospective td.stats { vertical-align: top; border-left-width: 1px; border-left-style:solid; padding-left: 10px; width: 10em;}\ntable.retrospective td.percentage { vertical-align: top; border-left-width: 1px;  font-size: 2em; border-left-style:solid; padding-left: 15px; width: 4em;text-align:center;}\ntable.retrospective td.percentage div.slider { vertical-align: top; border-left-width: 0px;  font-size: 0.5em; padding-left: 10px; width: 10em; margin-top:4px;}\ntable.retrospective td.total { vertical-align: top; border-left-width: 0px;  font-size: 2em; border-left-style:solid; padding-left: 10px; width: 4em;text-align:center;}\ntable.retrospective td.button { vertical-align: bottom; border-left-width: 0px;  border-left-style:solid; padding-left: 4px; width: 70px;text-align:center;}\ntable.retrospective td.title { vertical-align: top; border-left-width: 0px;  font-size: 1em; border-left-style:solid; padding-left: 10px; width: 4em;text-align:center;font-weight:bold;}\ntable.retrospective td.subtitle { width: 5em; vertical-align: top; border-left-width: 0px;  font-size: 1em; padding-left: 2em; text-align:right;}\n\n\n.action_button{\n  width:60px;\n  height:21px;\n  text-align:center;\n  float:right;\n  cursor:pointer;\n}\n\n.action_button_change{\n  font-color:#000;\n  font-weight:bold;\n  background: url(/images/bb_ocean.png) no-repeat;\n  float:left;\n  padding-top:2px;\n}\n\n\n.action_button_save{\n  font-color:#000;\n  font-weight:bold;\n  background: url(/images/bb_red.png) no-repeat;\n  float:left;\n  padding-top:2px;\n}\n\n.loading {\n  padding-left: 26px;\n  background-position: 0% 40%;\n  background-repeat: no-repeat;\n  background-image: url(../images/loading.gif);\n  font-style: italic;\n}\n\n.clickable{\n  cursor:pointer;\n}\n\n.point-scale{\n  float:left;\n  padding-left:15px;\n}\n\n.left{\n  float:left;\n}\n\n.right{\n  float:right;\n}\n\n.hidden{\n  display:none;\n}\n\n.tip{\n  width:300px;\n}\n\n.bold{\n  font-weight:bold;\n}\n"
  },
  {
    "path": "public/stylesheets/override.css",
    "content": "\n"
  },
  {
    "path": "public/stylesheets/reset-fonts.css",
    "content": "/*\nTHIS IS THE RESET CSS FILE, DO NOT MODIFY THIS FILE.\nIF YOU NEED TO MAKE CHANGES TO ANY OF THESE STYLES, MAKE THE CHANGES IN OVERRIDE.CSS\n\nCopyright (c) 2009, Yahoo! Inc. All rights reserved.\nCode licensed under the BSD License:\nhttp://developer.yahoo.net/yui/license.txt\nversion: 2.7.0\n*/\nhtml{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}\n\n/* Reset the z-index on the body to make negative z-indexes work in FF2 */\nbody {\n  position: relative;\n  top: 0;\n  left: 0;\n  z-index: 0;\n}\n\n/* Fixes for link borders */\na:active {\n  outline: none;\n}\n:focus {\n  -moz-outline-style: none;\n}\n"
  },
  {
    "path": "public/stylesheets/scaffold.css",
    "content": "body { background-color: #fff; color: #333; }\n\nbody, p, ol, ul, td {\n  font-family: verdana, arial, helvetica, sans-serif;\n  font-size:   13px;\n  line-height: 18px;\n}\n\npre {\n  background-color: #eee;\n  padding: 10px;\n  font-size: 11px;\n}\n\na { color: #000; }\na:visited { color: #666; }\na:hover { color: #fff; background-color:#000; }\n\n.fieldWithErrors {\n  padding: 2px;\n  background-color: red;\n  display: table;\n}\n\n#errorExplanation {\n  width: 400px;\n  border: 2px solid red;\n  padding: 7px;\n  padding-bottom: 12px;\n  margin-bottom: 20px;\n  background-color: #f0f0f0;\n}\n\n#errorExplanation h2 {\n  text-align: left;\n  font-weight: bold;\n  padding: 5px 5px 5px 15px;\n  font-size: 12px;\n  margin: -7px;\n  background-color: #c00;\n  color: #fff;\n}\n\n#errorExplanation p {\n  color: #333;\n  margin-bottom: 0;\n  padding: 5px;\n}\n\n#errorExplanation ul li {\n  font-size: 12px;\n  list-style: square;\n}\n\n"
  },
  {
    "path": "public/stylesheets/scm.css",
    "content": "\ndiv.changeset-changes ul { margin: 0; padding: 0; }\ndiv.changeset-changes ul > ul { margin-left: 18px; padding: 0; }\n\nli.change {\n    list-style-type:none;\n    background-image: url(../images/bullet_black.png);\n    background-position: 1px 1px;\n    background-repeat: no-repeat;\n    padding-top: 1px;\n    padding-bottom: 1px;\n    padding-left: 20px;\n    margin: 0;\n}\nli.change.folder { background-image: url(../images/folder_open.png); }\nli.change.folder.change-A { background-image: url(../images/folder_open_add.png); }\nli.change.folder.change-M { background-image: url(../images/folder_open_orange.png); }\nli.change.change-A { background-image: url(../images/bullet_add.png); }\nli.change.change-M { background-image: url(../images/bullet_orange.png); }\nli.change.change-C { background-image: url(../images/bullet_blue.png); }\nli.change.change-R { background-image: url(../images/bullet_purple.png); }\nli.change.change-D { background-image: url(../images/bullet_delete.png); }\n\nli.change .copied-from { font-style: italic; color: #999; font-size: 0.9em; }\nli.change .copied-from:before { content: \" - \"}\n\n#changes-legend { float: right; font-size: 0.8em; margin: 0; }\n#changes-legend li { float: left; background-position: 5px 0; }\n\ntable.filecontent { border: 1px solid #ccc;  border-collapse: collapse; width:98%; }\ntable.filecontent th { border: 1px solid #ccc; background-color: #eee; }\ntable.filecontent th.filename {  background-color: #e4e4d4; text-align: left; padding: 0.2em;}\ntable.filecontent tr.spacing th { text-align:center; }\ntable.filecontent tr.spacing td { height: 0.4em; background: #EAF2F5;}\ntable.filecontent th.line-num {\n    border: 1px solid #d7d7d7;\n  font-size: 0.8em;\n  text-align: right;\n  width: 2%;\n  padding-right: 3px;\n  color: #999;\n}\ntable.filecontent th.line-num a {\n  text-decoration: none;\n  color: inherit;\n}\ntable.filecontent td.line-code pre {\n    white-space: pre-wrap; /* CSS2.1 compliant */\n    white-space: -moz-pre-wrap; /* Mozilla-based browsers */\n    white-space: -o-pre-wrap; /* Opera 7+ */\n}\n\n/* 12 different colors for the annonate view */\ntable.annotate tr.bloc-0 {background: #FFFFBF;}\ntable.annotate tr.bloc-1 {background: #EABFFF;}\ntable.annotate tr.bloc-2 {background: #BFFFFF;}\ntable.annotate tr.bloc-3 {background: #FFD9BF;}\ntable.annotate tr.bloc-4 {background: #E6FFBF;}\ntable.annotate tr.bloc-5 {background: #BFCFFF;}\ntable.annotate tr.bloc-6 {background: #FFBFEF;}\ntable.annotate tr.bloc-7 {background: #FFE6BF;}\ntable.annotate tr.bloc-8 {background: #FFE680;}\ntable.annotate tr.bloc-9 {background: #AA80FF;}\ntable.annotate tr.bloc-10 {background: #FFBFDC;}\ntable.annotate tr.bloc-11 {background: #BFE4FF;}\n\ntable.annotate td.revision {\n    text-align: center;\n    width: 2%;\n    padding-left: 1em;\n    background: inherit;\n}\n\ntable.annotate td.author {\n    text-align: center;\n    border-right: 1px solid #d7d7d7;\n    white-space: nowrap;\n    padding-left: 1em;\n    padding-right: 1em;\n    width: 3%;\n    background: inherit;\n    font-size: 90%;\n}\n\ntable.annotate td.line-code { background-color: #fafafa; }\n\ndiv.action_M { background: #fd8 }\ndiv.action_D { background: #f88 }\ndiv.action_A { background: #bfb }\n\n/************* Coderay styles *************/\n\ntable.CodeRay {\n  background-color: #fafafa;\n}\n.CodeRay pre { margin: 0px }\n\nspan.CodeRay { white-space: pre; border: 0px; padding: 2px }\n\n.CodeRay .no { padding: 0px 4px }\n.CodeRay .code {  }\n\nol.CodeRay { font-size: 10pt }\nol.CodeRay li { white-space: pre }\n\n.CodeRay .code pre { overflow: auto }\n\n.CodeRay .debug { color:white ! important; background:blue ! important; }\n\n.CodeRay .af { color:#00C }\n.CodeRay .an { color:#007 }\n.CodeRay .av { color:#700 }\n.CodeRay .aw { color:#C00 }\n.CodeRay .bi { color:#509; font-weight:bold }\n.CodeRay .c  { color:#666; }\n\n.CodeRay .ch { color:#04D }\n.CodeRay .ch .k { color:#04D }\n.CodeRay .ch .dl { color:#039 }\n\n.CodeRay .cl { color:#B06; font-weight:bold }\n.CodeRay .co { color:#036; font-weight:bold }\n.CodeRay .cr { color:#0A0 }\n.CodeRay .cv { color:#369 }\n.CodeRay .df { color:#099; font-weight:bold }\n.CodeRay .di { color:#088; font-weight:bold }\n.CodeRay .dl { color:black }\n.CodeRay .do { color:#970 }\n.CodeRay .ds { color:#D42; font-weight:bold }\n.CodeRay .e  { color:#666; font-weight:bold }\n.CodeRay .en { color:#800; font-weight:bold }\n.CodeRay .er { color:#F00; background-color:#FAA }\n.CodeRay .ex { color:#F00; font-weight:bold }\n.CodeRay .fl { color:#60E; font-weight:bold }\n.CodeRay .fu { color:#06B; font-weight:bold }\n.CodeRay .gv { color:#d70; font-weight:bold }\n.CodeRay .hx { color:#058; font-weight:bold }\n.CodeRay .i  { color:#00D; font-weight:bold }\n.CodeRay .ic { color:#B44; font-weight:bold }\n\n.CodeRay .il { background: #eee }\n.CodeRay .il .il { background: #ddd }\n.CodeRay .il .il .il { background: #ccc }\n.CodeRay .il .idl { font-weight: bold; color: #888 }\n\n.CodeRay .in { color:#B2B; font-weight:bold }\n.CodeRay .iv { color:#33B }\n.CodeRay .la { color:#970; font-weight:bold }\n.CodeRay .lv { color:#963 }\n.CodeRay .oc { color:#40E; font-weight:bold }\n.CodeRay .of { color:#000; font-weight:bold }\n.CodeRay .op { }\n.CodeRay .pc { color:#038; font-weight:bold }\n.CodeRay .pd { color:#369; font-weight:bold }\n.CodeRay .pp { color:#579 }\n.CodeRay .pt { color:#339; font-weight:bold }\n.CodeRay .r  { color:#080; font-weight:bold }\n\n.CodeRay .rx { background-color:#fff0ff }\n.CodeRay .rx .k { color:#808 }\n.CodeRay .rx .dl { color:#404 }\n.CodeRay .rx .mod { color:#C2C }\n.CodeRay .rx .fu  { color:#404; font-weight: bold }\n\n.CodeRay .s  { background-color:#fff0f0 }\n.CodeRay .s  .s { background-color:#ffe0e0 }\n.CodeRay .s  .s  .s { background-color:#ffd0d0 }\n.CodeRay .s  .k { color:#D20 }\n.CodeRay .s  .dl { color:#710 }\n\n.CodeRay .sh { background-color:#f0fff0 }\n.CodeRay .sh .k { color:#2B2 }\n.CodeRay .sh .dl { color:#161 }\n\n.CodeRay .sy { color:#A60 }\n.CodeRay .sy .k { color:#A60 }\n.CodeRay .sy .dl { color:#630 }\n\n.CodeRay .ta { color:#070 }\n.CodeRay .tf { color:#070; font-weight:bold }\n.CodeRay .ts { color:#D70; font-weight:bold }\n.CodeRay .ty { color:#339; font-weight:bold }\n.CodeRay .v  { color:#036 }\n.CodeRay .xt { color:#444 }\n"
  },
  {
    "path": "public/stylesheets/static/print.css",
    "content": "body { line-height:1.5; font-family:\"Helvetica Neue\", Arial, Helvetica, sans-serif; color:#000; background:none; font-size:10pt;}.container { background:none;}hr { background:#ccc; color:#ccc; width:100%; height:2px; margin:2em 0; padding:0; border:none;}hr.space { background:#fff; color:#fff; visibility:hidden;}h1,h2,h3,h4,h5,h6 { font-family:\"Helvetica Neue\", Arial, \"Lucida Grande\", sans-serif; }code { font:.9em \"Courier New\", Monaco, Courier, monospace; } a img { border:none; }p img.top { margin-top:0; }blockquote { margin:1.5em; padding:1em; font-style:italic; font-size:.9em;}.small { font-size:.9em; }.large { font-size:1.1em; }.quiet { color:#999; }.hide { display:none; }a:link, a:visited { background:transparent; font-weight:700; text-decoration:underline;}a:link:after, a:visited:after { content:\" (\" attr(href) \")\"; font-size:90%;}\n"
  },
  {
    "path": "public/stylesheets/static/screen.css",
    "content": "html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {\n  margin:0;\n  padding:0;\n  border:0;\n  font-weight:inherit;\n  font-style:inherit;\n  font-size:100%;\n  font-family:inherit;\n  vertical-align:baseline;\n}\nbody {\n  line-height:1.4; /*used to be 1.7*/\n}\ntable {\n  border-collapse:separate;\n  border-spacing:0;\n}\ncaption, th, td {\n  text-align:left;\n  font-weight:normal;\n}\ntable, td, th {\n  vertical-align:middle;\n}\nblockquote:before, blockquote:after, q:before, q:after {\n  content:\"\";\n}\nblockquote, q {\n  quotes:\"\" \"\";\n}\na img {\n  border:none;\n}\nhtml {\n  font-size:100.01%;\n  background-color: #f3f3f3;\n}\nbody {\n/*  font-size:75%;*/\n  font-family: helvetica,arial,freesans,clean,sans-serif;\n/*  font-family:\"Helvetica Neue\", Arial, Helvetica, sans-serif;*/\n\n}\nh1,h2, h3, h4, h5, h6 {\n  font-weight:normal;\n  color:#111;\n}\n\nh1 {\n  font-size:2em;\n  line-height:1;\n  margin-bottom:0.4em;\n  text-shadow: 1px 1px #9E9E9F;\n  font-weight: bold;\n  color: #2f2f2f;\n\n   }\n#main-inner h1{\n  text-align: center;\n}\nh2 {\n  color: #02293C;\n  font-weight:bold;\n  font-size:1.5em;\n  margin-bottom:0.4em;\n  line-height: 110%;\n}\nh3 {\n  font-size:1em;\n/*  line-height:1.15;*/\n  line-height: 110%;\n  font-weight: bold;\n  color: #022356;\n}\nh4 {\n  font-size:1.2em;\n  line-height:1.25;\n  margin-bottom:1.25em;\n}\nh5 {\n  font-size:1em;\n  font-weight:bold;\n  margin-bottom:1.5em;\n}\nh6 {\n  font-size:.9em;\n  font-weight:bold;\n}\nh1 img, h2 img, h3 img, h4 img, h5 img, h6 img {\n  margin:0;\n}\np {\n  margin:0 0.5em 1.5em;\n  font-size: 110%;\n  line-height: 120%;\n/*  color: #818181*/\n}\np img.left {\n  float:left;\n  margin:1.5em 1.5em 1.5em 0;\n  padding:0;\n}\np img.right {\n  float:right;\n  margin:1.5em 0 1.5em 1.5em;\n}\n\n/*blockquote {\n  margin:1.5em;\n  color:#666;\n  font-style:italic;\n}\n*/\nstrong {\n  font-weight:bold;\n}\nem, dfn {\n  font-style:italic;\n}\ndfn {\n  font-weight:bold;\n}\nsup, sub {\n  line-height:0;\n}\nabbr, acronym {\n  border-bottom:1px dotted #666;\n}\naddress {\n  margin:0 0 1.5em;\n  font-style:italic;\n}\ndel {\n  color:#666;\n}\npre {\n  margin:1.5em 0;\n  white-space:pre;\n}\npre, code, tt {\n  font:1em 'andale mono', 'lucida console', monospace;\n  line-height:1.5;\n}\nli ul, li ol {\n  margin:0 1.5em;\n}\nul, ol {\n  margin:0 1.5em 1.5em 1.5em;\n}\nul {\n  list-style-type:disc;\n}\nul li {\n  font-size: 110%;\n/*  line-height: 120%;\n*//*  color: #818181*/\n}\nol {\n  list-style-type:decimal;\n}\ndl {\n  margin:0 0 1.5em 0;\n}\ndl dt {\n  font-weight:bold;\n}\ndd {\n  margin-left:1.5em;\n}\ntable {\n  margin-bottom:1.4em;\n  width:100%;\n}\nth {\n  font-weight:bold;\n}\nthead th {\n  background:#c3d9ff;\n}\nth, td, caption {\n  padding:4px 10px 4px 5px;\n}\ntr.even td {\n  background:#e5ecf9;\n}\ntfoot {\n  font-style:italic;\n}\ncaption {\n  background:#eee;\n}\n.small {\n  font-size:.8em;\n  margin-bottom:1.875em;\n  line-height:1.875em;\n}\n.large {\n  font-size:1.2em;\n  line-height:2.5em;\n  margin-bottom:1.25em;\n}\n.hide {\n  display:none;\n}\n.quiet {\n  color:#666;\n}\n.loud {\n  color:#000;\n}\n.highlight {\n  background:#ff0;\n}\n.added {\n  background:#060;\n  color:#fff;\n}\n.removed {\n  background:#900;\n  color:#fff;\n}\n.first {\n  margin-left:0;\n  padding-left:0;\n}\n.last {\n  margin-right:0;\n  padding-right:0;\n}\n.top {\n  margin-top:0;\n  padding-top:0;\n}\n.bottom {\n  margin-bottom:0;\n  padding-bottom:0;\n}\n.container {\n  width:940px;\n  margin:0 auto;\n  min-height:400px;\n}\n.showgrid {\n  background:url(grid.png);\n}\n.column, div.span-1, div.span-2, div.span-3, div.span-4, div.span-5, div.span-6, div.span-7, div.span-8, div.span-9, div.span-10, div.span-11, div.span-12 {\n  float:left;\n  margin-right:20px;\n}\n.last, div.last {\n  margin-right:0;\n}\n.span-1 {\n  width:60px;\n}\n.span-2 {\n  width:140px;\n}\n.span-3 {\n  width:220px;\n}\n.span-4 {\n  width:300px;\n}\n.span-5 {\n  width:380px;\n}\n.span-6 {\n  width:460px;\n}\n.span-7 {\n  width:540px;\n}\n.span-8 {\n  width:620px;\n}\n.span-9 {\n  width:700px;\n}\n.span-10 {\n  width:780px;\n}\n.span-11 {\n  width:860px;\n}\n.span-12 {\n  width:940px;\n  margin-right:0;\n}\ninput.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12 {\n  border-left-width:1px!important;\n  border-right-width:1px!important;\n  padding-left:5px!important;\n  padding-right:5px!important;\n}\ninput.span-1, textarea.span-1 {\n  width:48px!important;\n}\ninput.span-2, textarea.span-2 {\n  width:128px!important;\n}\ninput.span-3, textarea.span-3 {\n  width:208px!important;\n}\ninput.span-4, textarea.span-4 {\n  width:288px!important;\n}\ninput.span-5, textarea.span-5 {\n  width:368px!important;\n}\ninput.span-6, textarea.span-6 {\n  width:448px!important;\n}\ninput.span-7, textarea.span-7 {\n  width:528px!important;\n}\ninput.span-8, textarea.span-8 {\n  width:608px!important;\n}\ninput.span-9, textarea.span-9 {\n  width:688px!important;\n}\ninput.span-10, textarea.span-10 {\n  width:768px!important;\n}\ninput.span-11, textarea.span-11 {\n  width:848px!important;\n}\ninput.span-12, textarea.span-12 {\n  width:928px!important;\n}\n.append-1 {\n  padding-right:80px;\n}\n.append-2 {\n  padding-right:160px;\n}\n.append-3 {\n  padding-right:240px;\n}\n.append-4 {\n  padding-right:320px;\n}\n.append-5 {\n  padding-right:400px;\n}\n.append-6 {\n  padding-right:480px;\n}\n.append-7 {\n  padding-right:560px;\n}\n.append-8 {\n  padding-right:640px;\n}\n.append-9 {\n  padding-right:720px;\n}\n.append-10 {\n  padding-right:800px;\n}\n.append-11 {\n  padding-right:880px;\n}\n.prepend-1 {\n  padding-left:80px;\n}\n.prepend-2 {\n  padding-left:160px;\n}\n.prepend-3 {\n  padding-left:240px;\n}\n.prepend-4 {\n  padding-left:320px;\n}\n.prepend-5 {\n  padding-left:400px;\n}\n.prepend-6 {\n  padding-left:480px;\n}\n.prepend-7 {\n  padding-left:560px;\n}\n.prepend-8 {\n  padding-left:640px;\n}\n.prepend-9 {\n  padding-left:720px;\n}\n.prepend-10 {\n  padding-left:800px;\n}\n.prepend-11 {\n  padding-left:880px;\n}\ndiv.border {\n  padding-right:9px;\n  margin-right:10px;\n  border-right:1px solid #eee;\n}\ndiv.colborder {\n  padding-right:49px;\n  margin-right:50px;\n  border-right:1px solid #eee;\n}\n.pull-1 {\n  margin-left:-80px;\n}\n.pull-2 {\n  margin-left:-160px;\n}\n.pull-3 {\n  margin-left:-240px;\n}\n.pull-4 {\n  margin-left:-320px;\n}\n.pull-5 {\n  margin-left:-400px;\n}\n.pull-6 {\n  margin-left:-480px;\n}\n.pull-7 {\n  margin-left:-560px;\n}\n.pull-8 {\n  margin-left:-640px;\n}\n.pull-9 {\n  margin-left:-720px;\n}\n.pull-10 {\n  margin-left:-800px;\n}\n.pull-11 {\n  margin-left:-880px;\n}\n.pull-12 {\n  margin-left:-960px;\n}\n.pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12 {\n  float:left;\n  position:relative;\n}\n.push-1 {\n  margin:0 -80px 1.5em 80px;\n}\n.push-2 {\n  margin:0 -160px 1.5em 160px;\n}\n.push-3 {\n  margin:0 -240px 1.5em 240px;\n}\n.push-4 {\n  margin:0 -320px 1.5em 320px;\n}\n.push-5 {\n  margin:0 -400px 1.5em 400px;\n}\n.push-6 {\n  margin:0 -480px 1.5em 480px;\n}\n.push-7 {\n  margin:0 -560px 1.5em 560px;\n}\n.push-8 {\n  margin:0 -640px 1.5em 640px;\n}\n.push-9 {\n  margin:0 -720px 1.5em 720px;\n}\n.push-10 {\n  margin:0 -800px 1.5em 800px;\n}\n.push-11 {\n  margin:0 -880px 1.5em 880px;\n}\n.push-12 {\n  margin:0 -960px 1.5em 960px;\n}\n.push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12 {\n  float:right;\n  position:relative;\n}\n.prepend-top {\n  margin-top:1.5em;\n}\n.append-bottom {\n  margin-bottom:1.5em;\n}\n.box {\n  padding:1.2em 1.2em .5em 1.2em;\n  background:#ebebeb;\n  -moz-border-radius: 4px;\n  -webkit-border-radius:4px;\n  border: 1px solid #c6c6c6;\n  text-shadow: 1px 1px 1px #fff;\n  color: #444444;\n  text-align: justify\n}\nhr {\n  background:#ddd;\n  color:#ddd;\n  clear:both;\n  float:none;\n  width:100%;\n  height:1px;\n  margin:0 0 1.45em;\n  border:none;\n}\nhr.space {\n  background:#fff;\n  color:#fff;\n}\n.clearfix:after, .container:after {\n  content:\"\\0020\";\n  display:block;\n  height:0;\n  clear:both;\n  visibility:hidden;\n  overflow:hidden;\n}\n.clearfix, .container {\n  display:block;\n}\n.clear {\n  clear:both;\n}\nlabel {\n  font-weight:bold;\n}\nfieldset {\n  padding:1.4em;\n  margin:0 0 1.5em 0;\n  border:1px solid #ccc;\n}\nlegend {\n  font-weight:bold;\n  font-size:1.2em;\n}\ninput[type=text], input[type=password], input.text, input.title, textarea, select {\n  background-color:#fff;\n  border:1px solid #bbb;\n}\ninput[type=text]:focus, input[type=password]:focus, input.text:focus, input.title:focus, textarea:focus, select:focus {\n  border-color:#666;\n}\ninput[type=text], input[type=password], input.text, input.title, textarea, select {\n  margin:0.5em 0;\n}\ninput.text, input.title {\n  width:300px;\n  padding:5px;\n}\ninput.title {\n  font-size:1.5em;\n}\ntextarea {\n  width:390px;\n  height:250px;\n  padding:5px;\n}\ninput[type=checkbox], input[type=radio], input.checkbox, input.radio {\n  position:relative;\n  top:.25em;\n}\nform.inline {\n  line-height:3;\n}\nform.inline p {\n  margin-bottom:0;\n}\n.error, .notice, .success {\n  padding:.8em;\n  margin-bottom:1em;\n  border:1px solid #ddd;\n  clear: both;\n}\n.error {\n  background:#FBE3E4;\n  color:#8a1f11;\n  border-color:#FBC2C4;\n}\n.notice {\n  background: #FAFFBD url(/images/static/clip.png) no-repeat 10px 50% ;\n  color:#595959;\n  border-color:#d9d9d9;\n  text-shadow: 1px 1px #fff;\n  padding:1.4em;\n  text-align:center;\n}\n.success {\n  background:#E6EFC2;\n  color:#264409;\n  border-color:#C6D880;\n}\n.error a {\n  color:#8a1f11;\n}\n.notice a {\n  color:#514721;\n}\n.success a {\n  color:#264409;\n}\n\n\n/*pricing*/\n.gt-pl{margin:10px 0;padding:10px;-webkit-font-smoothing:antialiased;border:1px solid transparent;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}\n.gt-pl p{margin:0;font-size:14px;}\n.gt-pls-row{margin-top:-10px;margin-left:-25px;width:945px;}\n.gt-pls-row .gt-pl{float:left;margin-left:25px;width:268px;text-shadow:1px 1px 0 rgba(255,255,255,0.8);}\n.gt-pls-row .gt-pl .gt-r{margin:0;width:100%;padding:0 10px;margin-left:-10px;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.6);}\n.gt-pls-row.foured{width:940px;margin-left:-20px;}\n.gt-pls-row.foured .gt-pl{margin-left:20px;}\n.gt-pls-row .gt-pl .button.classy{display:block;margin:2px 0;text-align:center;}\n.gt-pl h3{margin:-5px 0 2px 0;font-size:24px;}\n.gt-pl .gt-pr{float:right;}\n.gt-pl .gt-pr .amount{color:#000;}\n.gt-pl .gt-pr .symbol{position:relative;top:-5px;font-size:16px;opacity:.7;}\n.gt-pl .gt-pr .duration{font-size:14px;opacity:.5;}\n.gt-pl ul.gt-bp{margin:12px 0;padding:7px 9px;font-weight:bold;font-size:16px;color:#000;background:rgba(255,255,255,0.5);border:1px solid rgba(0,0,0,0.2);border-right-color:rgba(0,0,0,0.1);border-bottom-color:rgba(0,0,0,0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}\n.gt-pl ul.gt-bp li{list-style-type:none;margin:0;}\n.gt-pl ul.gt-sp{margin:-10px 0 0 0;}\n.gt-pl ul.gt-sp li{list-style-type:none;padding:5px 0;opacity:.6;border-top:1px solid rgba(0,0,0,0.15);}\n.gt-pl ul.gt-sp li:first-child{border-top:none;}\n.gt-pl.hgt-pl{margin:20px 0;height:40px;filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#fafafa',endColorstr='#eeeeee');background:-webkit-gradient(linear,0% 0,0% 100%,from(#fafafa),to(#eee));background:-moz-linear-gradient(270deg,#fafafa,#eee);border-color:#e1e1e1;}\n.gt-pl.final:hover{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}\n.hgt-pl .gt-pr{float:left;margin-right:12px;height:100%;padding:0 8px;font-weight:bold;background:#fff;border:1px solid #b6b69e;border-right-color:#e0dfcb;border-bottom-color:#f4f2d2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}\n.hgt-pl .gt-pr .symbol{position:relative;top:-14px;color:#666;font-size:20px;}\n.hgt-pl .gt-pr .amount{position:relative;top:-4px;font-size:34px;color:#000;}\n.hgt-pl .gt-pr .duration{position:relative;top:-4px;color:#999;font-size:16px;}\n.hgt-pl .button{margin:1px 0 0 0;float:right;}\n.hgt-pl h3{margin:1px 0 0 0;font-size:16px;color:#000;text-shadow:1px 1px 0 rgba(255,255,255,0.8);}\n.final h3{font-weight:normal;}\n.hgt-pl p{color:#666;color:rgba(0,0,0,0.6);text-shadow:1px 1px 0 rgba(255,255,255,0.8);}\n.hgt-pl p strong{color:#000;}\n.gt-pl.personal h3{color:#1a526b;}\n.gt-pl.pro,.gt-pl.large.final,.gt-pl.mega.final,.gt-pl.giga.final{background:#d9eff6;background:-webkit-gradient(linear,0% 0,0% 100%,from(#eaf5fb),to(#c5e8f2));background:-moz-linear-gradient(-90deg,#eaf5fb,#c5e8f2);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#eaf5fb',endColorstr='#c5e8f2');border-color:#c4dce2;}\n.gt-pl.pro{background:-webkit-gradient(linear,25% 0,0% 100%,from(#eaf5fb),to(#c5e8f2));background:-moz-linear-gradient(-112deg,#eaf5fb,#c5e8f2);}\n.gt-pl.pro h3{color:#1f5714;}\n.gt-pl.free-box{background:#fbf9da;filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#fefef3',endColorstr='#fbf8d4');background:-webkit-gradient(linear,0% 0,0% 100%,from(#fefef3),to(#fbf8d4));background:-moz-linear-gradient(270deg,#fefef3,#fbf8d4);border-color:#e7e4c2;}\n.gt-pl.free{width:900px;background:#fbf9da;filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#fefef3',endColorstr='#fbf8d4');background:-webkit-gradient(linear,0% 0,0% 100%,from(#fefef3),to(#fbf8d4));background:-moz-linear-gradient(270deg,#fefef3,#fbf8d4);border-color:#e7e4c2;}\n.gt-pl.free:hover{border-color:#d6d2ac;}\n.free p{color:#4e4d29;}\nul.gt-pls-features{margin:5px 0 8px -20px;font-size:16px;}\nul.gt-pls-features li{list-style-type:none;margin:0 0 0 20px;padding-left:20px;font-size:100%;font-weight:bold;color:#000;background:url(/images/static/check2.png) 0 50% no-repeat; float:left;}\nul.gt-pls-features li.intro{font-weight:normal;color:#666;padding:0;background:transparent;padding-bottom:10px;}\nbutton.classy,a.button.classy{height:34px;padding:0;position:relative;top:1px;margin-left:10px;font-family:helvetica,arial,freesans,clean,sans-serif;font-weight:bold;font-size:12px;color:#333;text-shadow:1px 1px 0 #fff;white-space:nowrap;border:none;overflow:visible;background:#ddd;filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#ffffff',endColorstr='#e1e1e1');background:-webkit-gradient(linear,0% 0,0% 100%,from(#fff),to(#e1e1e1));background:-moz-linear-gradient(-90deg,#fff,#e1e1e1);border-bottom:1px solid #ebebeb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.3);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.3);box-shadow:0 1px 4px rgba(0,0,0,0.3);cursor:pointer;-webkit-font-smoothing:subpixel-antialiased!important;}\na.button.classy{display:inline-block;}\nbutton.classy span,a.button.classy span{display:block;height:34px;padding:0 13px;line-height:36px;}\n\n\n/*forms*/\n/* Login Box Styles */\n.gt-login-hd {\n  width: 430px;\n  margin-left: auto;\n  margin-right: auto;\n/*  margin-top: 30px;*/\n  margin-bottom: 5px;\n  font-size: 140%;\n  font-weight: bold;\n  color: #0e2029;\n}\n.gt-login-box {\n  width: 400px;\n  margin-left: auto;\n  margin-right: auto;\n  padding: 1.5em 3em;\n  border: 1px solid #ccc;\n  background-color: #fff;\n  border-radius: 5px;\n}\n.gt-login-box .gt-form .gt-form-text {\n  font-size: 116%;\n}\n.gt-login-box .gt-remember-me {\n  display: block;\n  padding: 12px 0 0 0;\n  font-size: 85%;\n  font-weight: normal;\n  color: #666666;\n  float: left;\n  display: inline;\n}\n.gt-forgot-password {\n  font-size: 85%;\n  clear: both;\n  margin: 0;\n  padding: 5px 0 0 0;\n}\n\n.signup-header{\n  font-family: 'lucida grande',Verdana,sans-serif;\n  color: #333;\n  font-weight: normal;\n  font-size: 1.4em;\n  padding: 7px;\n  text-align: center;\n  width: 100%;\n}\n\nform input[type=text],\nform input[type=password],\nform textarea {\n  border: 1px solid #ccc;\n  background-color: #f4f7f8;\n  padding: 5px 2px;\n  font-size: 108%;\n  width: 99%;\n}\n\nform input[type=text]:focus,\nform input[type=password]:focus,\nform textarea:focus {\n  background-color: #fff;\n}\n\nform input[type=submit] {\n  margin: 0 10px 0 0;\n  float: left;\n  display: inline;\n  height: 38px;\n  line-height: 38px;\n  text-align: center;\n  font-weight: bold;\n  color: #fff;\n  text-decoration: none;\n  font-size: 13px;\n  border: none;\n  padding: 0;\n  margin: 0;\n  width: 126px;\n  background: url(/images/gt/btn-gray-medium.png) no-repeat 0 0 transparent;\n}\n\n.gt-table-buttons-inside input[type=submit]{\n  float: right;;\n}\n\nform label {\n  font-size: 100%;\n  color: #365b6d;\n  display: block;\n  margin-bottom: 3px;\n  font-weight: bold;\n}\n\nform option {\n  font-size: 108%;\n}\n\nform label.note {\n  color: #444;\n  font-weight: normal;\n  font-size: 10px;\n}\n\nlabel.choice {\n  margin: 0 15px 0 0;\n  font-weight: normal;\n  font-size: 12px;\n  color: #666;\n}\n\n\nform input[type=radio],\nform input[type=checkbox] {\n  margin-right: 3px;\n}\n\nform input[type=select] {\n  font-size: 12px;\n  margin: 5px 5px 0 0;\n  border: 1px solid #d2d2d2;\n}\n\nform input.short { width: 20%;}\nform input.medium { width: 45%;}\nform input.long { width:70%;}\nform input.max { width: 95%;}\n\nform .gt-content-box {\n  padding: 15px 15px 5px 15px;\n  margin-bottom: 40px;\n  max-width: 800px;\n}\n\nform .gt-cancel {\n  line-height: 37px;\n  margin-bottom: 0;\n  margin-left: 20px;\n  float: left;\n}\n\n\n\nform p {\n  margin-bottom: 10px;\n  width: 80%;\n}\n\n.gt-login-box .errorExplanation h2{\n  display:none;\n}\n\n.gt-login-box .errorExplanation ul li{\n  color: #DF0000;\n  font-weight: bold;\n}\n\n.gt-login-box .errorExplanation p {\n    color: #DF0000;\n    font-weight: bold;\n    margin-top: 15px;\n}\n\nblockquote {\nfont-family: georgia, 'Times New Roman';\ndisplay: block;\npadding: 0px 60px 40px 90px;\nwidth: 300px;\n/*margin:1.5em;*/\ncolor:#666;\nfont-style:italic;\n}\n\nblockquote author{\n  font-weight:bold;\n  padding-left:20px;\n}\n\nblockquote author:before{\n  content: \"~\";\n}\n\n\nblockquote:before, blockquote:after {\ncolor: #69c;\ndisplay: block;\nfont-size: 700%;\nwidth: 50px;\n}\n\nblockquote:before {\ncontent: \"\\201C\";\nheight: 30px;\nmargin-left: -0.55em;\n\n}\nblockquote:after {\ncontent: '\\201D';\nheight: 50px;\nmargin-top: -70px;\nmargin-left: 290px;\npadding-right: 5px;\n}\n\nblockquote.middle{\n  padding-left:320px;\n  padding-bottom:70px;\n}\n\ndiv.paint {\n  -moz-background-clip:border;\n  -moz-background-origin:padding;\n  -moz-background-size:auto auto;\n  background-attachment:scroll;\n  background-color:transparent;\n  background-image:url(\"/images/static/paint_blue.png\");\n  background-position:0 0;\n  background-repeat:no-repeat;\n  float:left;\n  height:115px;\n  margin-bottom:0;\n  margin-left:200px;\n  margin-right:0;\n  margin-top:0;\n  text-align:center;\n  width:600px;\n}\n\ndiv.side-paint {\n  -moz-background-clip:border;\n  -moz-background-origin:padding;\n  -moz-background-size:auto auto;\n  background-attachment:scroll;\n  background-color:transparent;\n  background-image:url(\"/images/static/paint_orange.png\");\n  background-position:0 0;\n  background-repeat:no-repeat;\n  height:115px;\n  margin-bottom:0;\n  margin-left:auto;\n  margin-right:auto;\n  margin-top:2px;\n  text-align:center;\n  width:450px;\n}\n\ndiv.paint p,div.side-paint p{\n  color:#fff;\n  font-size:22px;\n  font-style:italic;\n  line-height:normal;\n  margin-bottom:0;\n  margin-left:0;\n  margin-right:0;\n  margin-top:15px;\n  padding-top:10px;\n  font-family: georgia, times, \"times new roman\";\n}\n\ndiv.paint p a,div.side-paint p a{\n  color:#666;\n}\n\n.span-6 h2{\n  text-align:center;\n}\n\n#homebanner{\n  height: 300px;\n  background-image:url(\"/images/static/HomePageMain.png\");\n  background-repeat:no-repeat;\n  background-position: right center;\n/*  margin-bottom: 44px;*/\n}\n\n#topsection{\n  background-color: #444;\n}\n"
  },
  {
    "path": "public/stylesheets/static/style.css",
    "content": "/*\nTheme Name: BetterMeans Corporate Template\nTheme URI:\nDescription: A corporate theme perfect for your business\nVersion: 1.0\nAuthor: Ivor Padilla\nAuthor URI: http://ivorpadilla.net\nTags: corporate, themeforest, stylish, clean\n*/\n\n\n/************************************************************************\nTable of Content:\n\n1.- General Cascade Stylesheets Rules\n2.- Structure\n************************************************************************/\n\n/************************************************************************\n1.- General Cascade Stylesheets Rules\n************************************************************************/\nbody {\n  color: #343434;\n/*  background-color: #f3f3f3;*/\n}\na, a:link {\n  color: #409edc;\n  text-decoration: none;\n}\na:visited {\n  color: #409edc;\n}\na:hover, a:focus {\n  color: #2379b2;\n  text-decoration: underline;\n}\na:active {\n  color: #2379b2;\n}\n:-moz-any-link:focus {\n outline: none;\n}\n/* Mozilla based browsers */\n::-moz-selection {\n background-color: #cfecff;\n color: #000;\n}\n/* Works in Safari */\n::selection {\n background-color: #cfecff;\n color: #000;\n}\n/*Add Scroll bar in all browsers*/\nhtml {\n  overflow-y: scroll;\n}\n/*html h1, html h2, html h3, html h4 {\n  font-family: Helvetica, sans-serif;\n  font-weight:normal;\n  color:#545454;\n}\n*//* =Clearfix (all browsers)\n--------------------------------*/\n/* new clearfix */\n.clearfix:after {\n  visibility: hidden;\n  display: block;\n  font-size: 0;\n  content: \" \";\n  clear: both;\n  height: 0;\n}\n* html .clearfix {\n  zoom: 1;\n} /* IE6 */\n*:first-child+html .clearfix {\n  zoom: 1;\n} /* IE7 */\n.clearing {\n  clear:both;\n  height:0;\n  overflow:hidden;\n  margin:-1px 0 0 0;\n}\n.left {\n  float: left\n}\n.right {\n  float: right\n}\n.overflow {\n  overflow:hidden\n}\n.hr {\n  clear:both;\n  float:none;\n  width:100%;\n  border-bottom:1px dotted #ccc;\n  padding:20px 0;\n}\n/************************************************************************\nBanner\n************************************************************************/\n\n#banner {\n  height:340px;\n  position:relative;\n  z-index:100\n}\n#description {\n  margin-top:20px;/*63px;*/\n  width:450px\n}\n#description p {\n  font-size:2em;\n  color:#fff\n}\n#description a {\n  color:#d6efff;\n  text-decoration: underline\n}\n#description a:hover {\n  text-decoration: underline\n}\n#description span {\n  display:block;\n  float:right;\n  margin:-30px 80px 0 0;\n  color:#fff;\n}\n#description small {\n  display:block;\n  color:#fff;\n  font-style:italic;\n  margin-left:25px;\n  text-shadow:1px 1px #2e8fcc\n}\n#description a.pricing-buttom {\n  background:url(/images/static/pricings-buttom.png) no-repeat 0 -47px;\n  height:44px;\n  width:240px;\n  display:block;\n  text-indent:-9999px;\n  font-size:0;\n  line-height:0\n}\n#description a.phover {\n  background:url(/images/static/pricings-buttom.png) no-repeat 0 0px;\n  height:44px;\n  width:240px;\n  display:block;\n  text-indent:-9999px;\n}\n#display {\n  background: url(/images/static/lcd.png) no-repeat;\n  margin-top:29px;\n  width:399px;\n  height:333px;\n  margin-left:-19px;\n  margin-left:21px;\n  position:relative;\n  z-index:-10\n}\n#display #photos {\n  position:relative;\n  top:20px;\n  left:18px;\n}\n.galleryview {\n  font-size: 11px;\n  font-family: Helvetica, sans-serif;\n  }\n.panel-overlay h2, .panel-overlay p {\n  margin: .4em 0;\n}\n.panel-overlay p {\n  line-height: .8em;\n}\n/************************************************************************\nMain\n************************************************************************/\n/* Read more buttons */\na.readmore {\n  width: 87px;\n  height:24px;\n  text-indent:-9999px;\n  overflow: hidden;\n  background: url(/images/static/readmore.png) no-repeat 0 -25px;\n  display: block;\n  float:left;\n  margin-top:10px\n}\na.readmore .hover {\n  width: 87px;\n  height:24px;\n  text-indent:-9999px;\n  overflow: hidden;\n  background: url(/images/static/readmore.png) no-repeat 0 0px;\n  display: block;\n  float:left;\n}\n/* /Read more buttons */\n\n#columns {\n  margin-bottom:60px\n} /*Just to work better - temporal*/\n#main {\n  margin-top:0px /*50*/\n}\n#main #columns .cols {\n  width:280px;\n  padding:0 10px\n}\n#main .cols h2 {\n  font-weight:bold;\n  color:#464646;\n  margin:0;\n  line-height:35px\n}\n#main .cols h6 {\n  color:#3798d6;\n  font-style:italic;\n  font-weight:normal;\n  margin-bottom:15px;\n  padding-bottom:5px;\n  border-bottom:1px solid #d8d8d8\n}\n#main .cols img {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n  padding:4px;\n  background:#f3f3f3;\n  border:1px solid #e3e3e3;\n  margin-bottom:14px\n}\nimg.shadow {\n  margin: 0 auto;\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  z-index: 1;\n}\ndiv.separator {\n  background: url(/images/static/sep-hoz-home.jpg);\n  height:47px;\n  width:941px\n}\n#main-secondary {\n  margin-top:10px\n}\n#main-secondary h3 {\n  color:#464646;\n/*  font-weight:200;*/\n}\n#main-secondary .left-content-secondary img {\n  float:right;\n  padding:10px\n}\n#main-secondary .left-content-secondary {\n  width:612px;\n  padding-right:40px;\n  border-right:1px solid #ccc\n}\n#main-secondary .right-content-secondary {\n  padding-left:20px;\n  width:240px;\n}\n#main-secondary .right-content-secondary ul {\n  margin-left:0;\n  width:240px;\n}\n#main-secondary .right-content-secondary ul li {\n  list-style:none;\n  border-bottom:1px solid #ccc;\n  margin-left:0;\n}\n#main-secondary .right-content-secondary ul li a {\n  color:#6f6f6f;\n  text-transform:uppercase;\n  text-decoration:none;\n  display:block;\n  padding:6px 0 6px 5px;\n}\n#main-secondary .right-content-secondary ul li a:hover {\n  background:#f6f6f6\n}\n#main-secondary .right-content-secondary ul li a span.meta {\n  display:block;\n  font-size:.9em;\n  text-transform:none;\n  padding-right: 13px\n}\n#main-secondary .right-content-secondary ul li a span.meta span.sub-meta {\n  padding-right:4px;\n  border-right: 1px solid #ccc\n}\n/*Main Inner*/\n#main-inner {\n  margin-top:80px\n}\n#main-inner div.title h3 {\n  color: #545454;\n  font-size: 2.3em;\n  font-weight: bold;\n  text-decoration: none;\n  padding:0;\n  margin: 0\n}\n#main-inner .left-content-secondary img {\n  float:right;\n  padding:10px\n}\n#main-inner .left-content-secondary {\n  width:612px;\n  padding-right:40px;\n  border-right:1px solid #ccc\n}\n#main-inner .left-content-secondary .small-title {\n  margin-left: 2px;\n  color: #4f4f4f\n}\n#main-inner .left-content-secondary div.title {\n  padding-bottom:3px;\n  border-bottom:1px solid #ccc;\n  margin-bottom:24px\n}\n#main-inner .left-content-secondary img.laptop {\n  float: left;\n  margin-top: 35px\n}\n#main-inner .left-content-secondary div.product-quote {\n  padding:70px 0\n}\n#main-inner .left-content-secondary div.product-quote h4 {\n  font-size:1.6em;\n  font-weight:bold;\n  margin-bottom:0;\n  color:#efa049;\n}\n#main-inner .left-content-secondary div.product-quote p {\n  font-style: italic;\n  color: #959494\n}\n#main-inner .right-content-secondary {\n  padding-left:20px;\n  width:240px;\n  margin-top: 30px\n}\n#main-inner .right-content-secondary img {\n  float: left;\n  margin: 0px 15px 0px 5px\n}\n#main-inner .right-content-secondary ul {\n  margin-left:0;\n  width:240px;\n}\n#main-inner .right-content-secondary ul li {\n  list-style:none;\n  border-bottom:1px solid #ccc;\n  margin-left:0;\n}\n#main-inner .right-content-secondary ul li a {\n  color:#6f6f6f;\n  text-transform:uppercase;\n  text-decoration:none;\n  display:block;\n  padding:8px 0 14px 5px;\n  clear: both;\n  font-weight: bold\n}\n#main-inner .right-content-secondary ul li a:hover {\n  background:#f6f6f6\n}\n#main-inner .right-content-secondary ul li a span.meta {\n  display:block;\n  font-size:.9em;\n  text-transform:none;\n  padding-right: 13px\n}\n#main-inner .right-content-secondary ul li a span.meta span.sub-meta {\n  padding-right:4px;\n  font-weight: normal\n}\n/*Main Inner Secondary Blog */\n\n#main-inner .left-content-secondary a.blog-post-title {\n  color: #545454;\n  font-size: 2.3em;\n  font-weight: bold;\n  text-decoration: none;\n}\n#main-inner .left-content-secondary a.blog-post-title:hover {\n  text-decoration: none;\n  color: #47a4de;\n}\n#main-inner .left-content-secondary .blog-post {\n  background: url(/images/static/blog-post-separator.jpg) no-repeat center bottom;\n  padding-bottom: 120px\n}\n#main-inner .left-content-secondary .blog-post img {\n  float: none;\n  padding: 6px;\n  background: #fff;\n  outline: 1px dotted #ccc;\n  margin: 15px 0\n}\n#main-inner .left-content-secondary .blog-post a:hover img {\n  background: #f2f2f2;\n  outline: 1px dotted #ccc\n}\n#main-inner .right-content-secondary h1 {\n  text-align: center;\n  font-size: 1.6em;\n  color: #545454;\n  font-weight: bold;\n  letter-spacing: 1px;\n  border-top: 1px dotted #ccc;\n  border-bottom: 1px dotted #ccc;\n  padding: 8px 0;\n  margin: 0 0;\n}\n#main-inner .right-content-secondary .arrow {\n  background: url(/images/static/arrow.jpg) no-repeat 7px 0;\n  width: 30px;\n  text-indent: -9999px;\n  margin: -2px auto 0 auto\n}\n#main-inner .right-content-secondary ul#categories li a {\n  font-weight: normal;\n  text-transform: capitalize;\n  padding:8px 0 8px 5px;\n}\n#main-inner .right-content-secondary ul.blog-sidebar-a li a {\n  font-weight: normal;\n  text-transform: capitalize;\n  padding:8px 0 8px 5px;\n}\n#main-inner .right-content-secondary div#archives {\n  margin-top: 40px\n}\n#main-inner .right-content-secondary div#text-widget {\n  margin-top: 40px\n}\n#main-inner .right-content-secondary div#ads {\n  margin-top: 40px\n}\n\n#main-inner-testimonial{\n  padding-top: 40px;\n  padding-right: 20px;\n  padding-left: 20px;\n}\n\n#main-inner-testimonial p{\n  text-align:right;\n  font-size:170%;\n  color: #aaa;\n}\n\n#main-inner-testimonial img{\n  padding-right:50px;\n}\n\ndiv.meta {\n  width: 360px;\n  float: left\n}\n.comments-counter {\n  background:transparent url(/images/static/balloon.png) no-repeat scroll 100px 50%;\n  float:right;\n  margin-left:31px;\n  padding-left:22px;\n  text-align:right;\n  width:190px;\n}\ndiv.blog-content p {\n  clear: both\n}\n.navigator {\n  margin:15px 0 0 0;\n  clear:both;\n  position:relative;\n  bottom:5px;\n  right: 160px\n}\n.navigator a, .navigator span {\n  font-weight:bold;\n  float:right;\n  display:block;\n  padding:3px 10px;\n  margin:0 3px 0 0;\n  background-color:white;\n  border:1px solid #c5d6e6;\n  -moz-border-radius:3px;\n  -webkit-border-radius:3px\n}\n.navigator a.selected, .navigator span.selected {\n  background-color:#38a2d7;\n  border:1px solid #3186b0\n}\n.navigator b {\n  color:white !important\n}\n.navigator a:hover {\n  -moz-box-shadow: 0 0 3px #ccc;\n  -webkit-box-shadow: 0 0 3px #ccc;\n}\ndiv#ads a.adhere100px {\n  width:100px;\n  height:100px;\n  background:#e7e7e7;\n  display:block;\n  margin:5px;\n  float:left;\n  border: 1px solid #ccc;\n  text-align: center;\n  line-height: 850%;\n  color: #545454;\n  font-weight: bold;\n  text-decoration: none;\n}\ndiv#ads a.adhere100px:hover {\n  background: #ddd\n}\ndiv#ads div.ad-boxes {\n  margin:0 7px;\n}\n/************************************************************************\nTour Page\n************************************************************************/\n#main-inner h2.main-title {\n  color:#44a1dc;\n  width: 450px;\n  float: left\n}\n#main-inner h1.tour-title {\n  color:#44a1dc;\n  text-align:center\n}\n#main-inner ul#tour-menu {\n  float:left;\n  width: 400px;\n  margin: 20px 0 0 80px\n}\n#main-inner ul#tour-menu li {\n  border-right:1px solid #CCCCCC;\n  float:left;\n  list-style-image:none;\n  list-style-position:outside;\n  list-style-type:none;\n  margin:0 0px 0 13px;\n  padding:0 12px 0 0px;\n  line-height:13px;\n}\n#main-inner ul#tour-menu li:last-child {\n  border: none\n}\n#main-inner ul#tour-menu li a {\n  color:#575757\n}\n#main-inner ul#tour-menu li a.selected {\n  color: #111;\n  text-decoration: underline\n}\n#main-inner ul#tour-menu li a:hover {\n  color: #111\n}\n#video-container {\n  text-align: center;\n  text-indent: -9999px;\n  background: url(\"/images/static/video-shadow.jpg\") no-repeat center 413px\n}\n#video-container #video {\n  width: 790px;\n  margin-left: auto;\n  margin-right: auto\n}\n#tags {\n  padding: 40px 0\n}\n#tags p {\n  color: #818181;\n  font-size: 1.8em;\n  font-size: 1.4em;\n  text-align: center\n}\n#main-tour-content {\n  margin-top: 40px;\n  width:650px;\n  margin-right: 0;\n  width: 700px;\n}\n#main-tour-content h3 {\n  color: #44a1dc\n}\n#main-tour-content img {\n  padding:3px;\n  margin:0 3px;\n  background:#f9f9f9;\n  border:1px solid #ccc;\n}\n.separator-big {\n  background: url(/images/static/separator-big.jpg) no-repeat 0 0;\n  text-indent: -9999px;\n  height: 56px\n}\ndiv#secondary-text {\n  margin-top: 30px;\n  padding-top: 40px\n}\ndiv#secondary-text p {\n  font-style: italic\n}\ndiv#secondary-text hr {\n  margin-bottom:30px;\n  background: #ededed\n}\nul#styled-menu {\n  margin-top: 40px;\n  margin-left:27px;\n  width:189px;\n  border-top: 1px solid #e5e5e5;\n  border-left: 1px solid #e5e5e5;\n  border-right: 1px solid #e5e5e5;\n  float:right\n}\nul#styled-menu li {\n  list-style:none;\n  border-bottom:1px solid #ccc;\n  margin-left:0;\n}\nul#styled-menu li a {\n  color:#6f6f6f;\n  text-transform:uppercase;\n  text-decoration:none;\n  display:block;\n  padding:4px 0 4px 5px;\n  background: #f8f8f8;\n  border-top: 1px solid #fff\n}\nul#styled-menu li a:hover {\n  background:#efeeee\n}\nul#styled-menu li a span.meta {\n  display:block;\n  font-size:.9em;\n  text-transform:none;\n  padding-right: 13px\n}\nul#styled-menu li a span.meta span.sub-meta {\n  padding-right:4px;\n  border-right: 1px solid #ccc\n}\n#main-tour-content div.col {\n  padding:0 15px;\n}\nul#styled-menu li a span {\n  text-transform:none;\n  padding-left:12px;\n}\nul#styled-menu li a img {\n  padding-left: 8px;\n  line-height:18px;\n  vertical-align:middle;\n}\n/************************************************************************\nHeadquarters Page\n************************************************************************/\n.strong {\n  color:#242F33;\n  font-size:17px;\n  font-weight:bold;\n  line-height: 1.2\n}\n#hq-left-intro {\n  width:450px;\n  padding-right:10px;\n  padding-bottom:50px;\n}\ndiv#hq-main {\n  margin-top:110px;\n  clear:both\n}\ndiv.hq-info h3 {\n  margin:0;\n  font-size:1.7em;\n  font-weight:bold;\n  color:#12689e;\n  padding-top:10px\n}\ndiv.hq-info span {\n  font-style:italic;\n}\ndiv.hq-info p {\n  padding-top:10px\n}\ndiv.hq-info img {\n  padding:4px;\n  outline:1px solid #ccc;\n}\n#video-add {\n  padding-top:20px;\n  padding-bottom:35px;\n  overflow:hidden\n}\ndiv#hq-cols {\n  padding-top:10px\n}\ndiv#video-add div.video p {\n  display: none\n}\ndiv.video {\n  margin-top: 53px\n}\n/************************************************************************\nPricings Page\n************************************************************************/\n#pricing {\n  width: 902px;\n  margin-left: auto;\n  margin-right: auto\n}\ntable#pricing-chart td {\n  text-align:center\n}\n#main-inner div.inner-page-title {\n  margin-bottom:30px;\n  text-align:center;\n}\n#main-inner h2.main-title-2 {\n  color:#44a1dc;\n  margin:0;\n\n}\n#main-inner div.inner-page-title span {\n  font-size:.9em;\n  margin-left:2px;\n  border-bottom:1px solid #ccc;\n  padding-bottom:3px;\n  color: #666;\n  display:block;\n  width:460px\n}\n#main-inner #main-pricing-list {\n  margin:0px 40px 20px 40px\n}\n#main-inner ul#main-pricing-list li {\n  color:#666;\n  line-height:30px;\n  list-style:none;\n  font-weight:normal\n}\n#main-inner ul#main-pricing-list li.check {\n  background:url(/images/static/check.png) no-repeat 0 40%;\n  padding-left:25px\n}\n#main-inner ul#main-pricing-list li.credit-card {\n  background:url(/images/static/cc.png) no-repeat 0 40%;\n  padding-left:25px\n}\n#main-inner ul#main-pricing-list li.clock {\n  background:url(/images/static/clock.png) no-repeat 0 40%;\n  padding-left:25px\n}\n#main-inner div#right-call-buttom {\n  float:right;\n  width:226px;\n  margin-top:5px\n}\n#main-inner div#right-call-buttom a {\n  color:#0C3;\n  background:url(/images/static/call-us.png) no-repeat 0 0;\n  height:70px;\n  display:block;\n  text-indent:-9999px\n}\n#main-inner div#right-call-buttom a:hover {\n  background:url(/images/static/call-us.png) no-repeat 0 -73px;\n}\ntable#pricing-chart th.table-col-0 {\n  text-align:center\n}\n#main-inner div#pricing-col {\n  margin-top: 5px\n}\n#main-inner div#pricing-col div.column {\n/*  width: 259px;*/\n  padding: 0 20px\n}\n#main-inner div#pricing-col h4 {\n  font-weight:bold;\n}\n#main-inner div#pricing-col img {\n  padding: 2px;\n  background: #ccc;\n  outline: 1px solid #b7b7b7;\n  margin-bottom: 15px\n}\n/************************************************************************\nSign Up Page\n************************************************************************/\n\n\nform#new_user_old {\n  background: #f4f4f4 url(/images/static/white-space.gif) repeat-x top left;\n  border: 1px solid #ccc;\n  overflow: hidden;\n  width: 500px;\n  padding: 30px 50px;\n}\nform#new_user_old input[type=\"text\"] {\n  -moz-border-radius:4px 4px 4px 4px;\n  -webkit-border-radius:4px;\n  float:right;\n  margin:1.5em 0;\n  padding:10px 11px;\n  width:362px;\n  background: url(/images/static/text-form-bg.jpg) repeat-x\n}\nform#new_user_old label {\n  line-height:62px;\n  margin: 0 10px\n}\nform#new_user_old h3 {\n  background: url(/images/static/1.png) no-repeat 0 0;\n  padding-left: 60px;\n  height: 43px;\n  line-height: 47px;\n  text-shadow: 1px 1px #fff\n}\ndiv#main-inner form#sign-up-bottom {\n  background: #f4f4f4 url(/images/static/white-space.gif) repeat-x top left;\n  border: 1px solid #ccc;\n  overflow: hidden;\n  width: 500px;\n  padding: 50px;\n  margin-top: 50px;\n}\ndiv#main-inner form#sign-up-bottom input[type=\"text\"] {\n  -moz-border-radius:4px 4px 4px 4px;\n  -webkit-border-radius:4px;\n  float:right;\n  margin:1.5em 0;\n  padding:10px 11px;\n  width:362px;\n  background: url(/images/static/text-form-bg.jpg) repeat-x\n}\ndiv#main-inner form#sign-up-bottom input[type=\"password\"] {\n  -moz-border-radius:4px 4px 4px 4px;\n  -webkit-border-radius:4px;\n  float:right;\n  margin:1.5em 0;\n  padding:10px 11px;\n  width:362px;\n  background: url(/images/static/text-form-bg.jpg) repeat-x\n}\ndiv#main-inner form#sign-up-bottom label {\n  line-height:62px;\n  margin: 0 10px\n}\ndiv#main-inner form#sign-up-bottom h3 {\n  background: url(/images/static/2.png) no-repeat 0 0;\n  padding-left: 60px;\n  height: 43px;\n  line-height: 47px;\n  text-shadow: 1px 1px #fff\n}\ndiv#main-inner input#create[type=\"submit\"] {\n  border: 0;\n  background: url(/images/static/create.gif) no-repeat 0 0;\n  cursor: pointer;\n  text-indent: -9999px;\n  height:70px;\n  width: 539px;\n  margin: 35px\n}\ndiv#main-inner input#create[type=\"submit\"]:hover {\n  background-position: 0 -76px\n}\ndiv#thanks img {\n  padding-bottom:30px;\n  padding-left:15px\n}\ndiv#trial {\n  clear:both;\n  padding-top:10px;\n  padding-bottom:15px\n}\ndiv#trial h3 {\n  text-align:center;\n  background:url(/images/static/trial.jpg) no-repeat 0 0;\n  text-indent:-9999px;\n  width:187px;\n  margin:5px 30px 5px auto\n}\ndiv#trial p {\n  font-size:.9em;\n  text-align:center\n}\ndiv#text-widget div.cloud {\n  background:url(/images/static/bubble.jpg) no-repeat 0 0;\n  padding:8px;\n  margin-bottom:15px\n}\ndiv#text-widget div.cloud p {\n  font-size:.9em;\n  text-shadow:1px 1px #fff;\n}\ndiv#text-widget p.client strong {\n  color:#111;\n}\ndiv#text-widget p.client {\n  margin-top:-10px;\n  margin-left:21px\n}\ndiv#text-widget div.cloud h3 {\n  font-size:1.6em;\n  margin:0;\n  line-height:20px;\n  padding-bottom:5px\n}\ndiv#widget-4 h3 {\n  background:url(/images/static/who.jpg) no-repeat 0 0;\n  text-indent:-9999px;\n  height:28px;\n  margin-left:10px\n}\ndiv#widget-4 img {\n  padding:10px;\n  outline:1px solid #ccc\n}\nform#new_user_old input[type=\"text\"] {\n  -moz-border-radius:4px 4px 4px 4px;\n  -webkit-border-radius:4px;\n  float:right;\n  margin:1.5em 0;\n  padding:10px 11px;\n  width:362px;\n  background: url(/images/static/text-form-bg.jpg) repeat-x\n}\ndiv#main-inner form#sign-up-bottom input[type=\"text\"] {\n  -moz-border-radius:4px 4px 4px 4px;\n  -webkit-border-radius:4px;\n  float:right;\n  margin:1.5em 0;\n  padding:10px 11px;\n  width:362px;\n  background: url(/images/static/text-form-bg.jpg) repeat-x\n}\ndiv#main-inner form#sign-up-bottom input[type=\"password\"] {\n  -moz-border-radius:4px 4px 4px 4px;\n  -webkit-border-radius:4px;\n  float:right;\n  margin:1.5em 0;\n  padding:10px 11px;\n  width:362px;\n  background: url(/images/static/text-form-bg.jpg) repeat-x\n}\n/************************************************************************\nContact\n************************************************************************/\n\n\ndiv#main-inner form#contact-form {\n  background: #f4f4f4 url(/images/static/white-space.gif) repeat-x top left;\n  border: 1px solid #ccc;\n  overflow: hidden;\n  width: 500px;\n  padding: 30px 50px;\n  margin-top: 50px;\n}\ndiv#main-inner form#contact-form input[type=\"text\"] {\n  -moz-border-radius:4px 4px 4px 4px;\n  -webkit-border-radius:4px;\n  float:right;\n  margin:1.5em 0;\n  padding:10px 11px;\n  width:362px;\n  background: url(/images/static/text-form-bg.jpg) repeat-x\n}\ndiv#main-inner form#contact-form label {\n  line-height:62px;\n  margin: 0 10px\n}\ndiv#main-inner form#contact-form h3 {\n  background: url(/images/static/as.png) no-repeat 0 0;\n  padding-left: 60px;\n  height: 43px;\n  line-height: 47px;\n  text-shadow: 1px 1px #fff\n}\ndiv#main-inner form#contact-form textarea {\n  -webkit-border-radius:4px;\n  -moz-border-radius:4px 4px 4px 4px;\n  float:right;\n  height:100px;\n  width:373px;\n  background: #fff url(/images/static/text-form-bg.jpg) repeat-x;\n}\ndiv.left-content-secondary p.contact-intro {\n  clear:both;\n  font-size:1.3em;\n  padding-top:35px;\n}\ndiv.left-content-secondary div.trib {\n  background:url(/images/static/trib.jpg) no-repeat 0 0;\n  text-indent:-9999px;\n  height:22px;\n  width:82px;\n  margin:30px auto;\n}\n#main-inner .right-content-secondary ul#map li a {\n  font-weight: normal;\n  text-transform: capitalize;\n  padding:8px 0 8px 5px;\n}\n#main-inner .right-content-secondary div#details {\n  clear:both;\n  padding-top:30px;\n  margin-bottom:0\n}\n#main-inner .right-content-secondary div#details p {\n  margin:0;\n  line-height:25px\n}\n#main-inner .right-content-secondary div#details p.mail {\n  background:url(/images/static/mail.png) 0 30% no-repeat;\n  padding-left:25px\n}\n#main-inner .right-content-secondary div#details p.tel {\n  background:url(/images/static/phone.png) 0 30% no-repeat;\n  padding-left:25px\n}\n#main-inner .right-content-secondary div#details p.fax {\n  background:url(/images/static/fax.png) 0 30% no-repeat;\n  padding-left:25px\n}\n#main-inner .right-content-secondary div#text-widget-contact {\n  margin-top: 20px\n}\n#main-inner .right-content-secondary div#text-widget-contact p {\n  font-size:.9em\n}\ndiv#main-inner form#contact-form input#contact-submit[type=\"submit\"] {\n  border: 0;\n  background: url(/images/static/contact-submit.png) no-repeat 0 0;\n  cursor: pointer;\n  text-indent: -9999px;\n  height:38px;\n  width: 125px;\n  float:right;\n  position:relative;\n  top:10px\n}\ndiv#main-inner form#contact-form input#contact-submit[type=\"submit\"]:hover {\n  background-position:0 -40px\n}\ndiv#main-inner form#blog-comment-form input#contact-submit[type=\"submit\"] {\n  border: 0;\n  background: url(/images/static/contact-submit.png) no-repeat 0 0;\n  cursor: pointer;\n  text-indent: -9999px;\n  height:38px;\n  width: 125px;\n  float:right;\n  position:relative;\n  top:50px;\n  left:30px\n}\ndiv#main-inner form#blog-comment-form input#contact-submit[type=\"submit\"]:hover {\n  background-position:0 -40px\n}\n#message {\n  margin: 5px 0;\n  padding: 0;\n}\n#message h2 {\n  margin: 0;\n}\n.error_message {\n  display: block;\n  height: 22px;\n  line-height: 22px;\n  background: #FBE3E4 url('assets/error.gif') no-repeat 10px center;\n  padding: 3px 10px 3px 35px;\n  color:#8a1f11;\n  border: 1px solid #FBC2C4;\n  -webkit-border-radius:5px;\n}\n.loader {\n  padding: 0 10px;\n}\n#message h2 {\n  background: url('/images/static/success.png') left no-repeat;\n  padding-left:62px;\n}\nacronym {\n  border-bottom:1px dotted #ccc;\n}\n/************************************************************************\nSingle Page\n************************************************************************/\n/*Single*/\n#main-inner .left-content-secondary .blog-post-single {\nno-repeat center bottom;\n  padding-bottom: 120px\n}\n#main-inner .left-content-secondary .blog-post-single img {\n  float: none;\n  padding: 6px;\n  background: #fff;\n  outline: 1px dotted #ccc;\n  margin: 15px 0\n}\n#main-inner .left-content-secondary .blog-post-single a:hover img {\n  background: #f2f2f2;\n  outline: 1px dotted #ccc\n}\ndiv.blog-post-single p.rating {\n  background:url(/images/static/stars.jpg) no-repeat 0 50%;\n  padding-left: 110px;\n  width: 180px;\n  margin-top: 60px;\n}\n.tweetmemebutton {\n  color:#333;\n  font-family: Helvetica, sans-serif;\n  font-size:81.3%;\n  line-height:1.5em;\n  margin:0;\n  padding:0 35px;\n  margin-right:10px;\n  position: relative;\n  top: -55px\n}\n.tweetmemebutton .count {\n  background:url(/images/static/widget.gif) no-repeat;\n  color:#444;\n  display:block;\n  font-size:17px;\n  height:34px;\n  padding:4px 0;\n  position:relative;\n  text-align:center;\n  text-decoration:none;\n  width:50px\n}\n.tweetmemebutton .count span.t {\n  display:block;\n  font-size:10px;\n  left:10px;\n  line-height:10px;\n  position:absolute;\n  top:23px\n}\n.tweetmemebutton .retweet {\n  background:url(/images/static/widget.gif) no-repeat 0 -45px;\n  color:#FFF;\n  cursor:pointer;\n  display:block;\n  font-size:11px;\n  height:16px;\n  line-height:16px;\n  margin-top:3px;\n  padding:0;\n  text-align:center;\n  text-decoration:none;\n  width:50px\n}\n.tweetmemebutton .retweet:hover, .tweet .left .retweet.selected {\n  background-position:0 -61px;\n  color:#80b62a\n}\ndiv.blog-post-single div#author {\n  background: #f4f4f4 url(/images/static/author-bg.jpg) no-repeat right bottom;\n  outline:1px solid #e3e3e3;\n  padding: 2px 15px\n}\ndiv.blog-post-single div#author p {\n  margin-top: 18px;\n  text-shadow: 1px 1px #fff\n}\ndiv#main-inner div.blog-post-single div#author img {\n  -webkit-border-radius:3px;\n  -moz-border-radius:3px 3px 3px 3px;\n  -moz-box-shadow:0 0 5px #B1B1B1;\n  -webkit-box-shadow:0 0 5px #B1B1B1;\n  background:none repeat scroll 0 0 #FFFFFF;\n  border:medium none;\n  outline:medium none;\n  padding:4px;\n  float: left;\n  margin-right: 10px;\n}\n/************************************************************************\nComments\n************************************************************************/\n\ndiv#comments-content {\n  margin-top: 60px\n}\ndiv#comments-content h1 {\n  color: #ccc;\n  border-bottom: 1px dotted #ccc;\n  margin-bottom: 40px\n}\ndiv#main-inner div#comments-content div ol li.reader-comment {\n  background:#fff url(/images/static/comment-bg.jpg) repeat-x top left;\n  border-top:1px solid #dfdfdf;\n  border-left: 1px solid #dfdfdf;\n  border-right: 1px solid #dfdfdf;\n  list-style:none outside none;\n  margin:0;\n  padding:25px;\n}\ndiv#main-inner div#comments-content div ol li.reader-comment:last-child {\n  border-bottom: 1px solid #dfdfdf\n}\ndiv#main-inner div#comments-content div ol li.reader-comment img {\n  border:none;\n  outline:none;\n  float:left;\n  background:none;\n  margin-top:-5px\n}\ndiv#main-inner div#comments-content div ol li.reader-comment span {\n  display:block\n}\na.comment-counter {\n  padding:10px 30px;\n  background:#1389cc;\n  font-size:1.6em;\n  color: #fff\n}\na.comment-counter:hover {\n  text-decoration:none;\n  background:#2a9cde\n}\ndiv#comment-box {\n  margin-top:50px;\n  position: relative\n}\ndiv#comment-box h3 {\n  color:#ccc;\n  border-bottom: 1px dotted #ccc;\n  width:550px;\n  margin: 0 auto\n}\ndiv#comment-box div.comment-intro {\n  width: 550px;\n  margin: 20px auto\n}\ndiv#comment-box form#blog-comment-form {\n  background: #f4f4f4 url(/images/static/white-space.gif) repeat-x top left;\n  width: 450px;\n  margin: 0 auto;\n  padding: 30px;\n  border: 1px solid #e3e3e3\n}\ndiv#comment-box form#blog-comment-form input[type=\"submit\"].comments {\n  position: relative;\n  top: 26px;\n  left: 36px\n}\ndiv#comment-box form#blog-comment-form input[type=\"text\"] {\n  padding: 8px 5px;\n  width: 250px;\n  background: url(/images/static/comment-form-bg.gif) repeat-x;\n}\ndiv#comment-box form#blog-comment-form label {\n  display: none\n}\ndiv#comment-box form#blog-comment-form textarea {\n  height: 150px;\n  width: 435px;\n  background:#fff url(/images/static/comment-form-bg.gif) repeat-x\n}\n/************************************************************************\nGallery\n************************************************************************/\n\n\ndiv#gallery div.gallery-content {\n  padding:40px 0;\n}\ndiv#gallery div.gallery-content ul li {\n  background:url(/images/static/list.png) no-repeat 0 50%;\n  padding-left:20px;\n  list-style:none;\n  font-size: 110%;\n}\ndiv#gallery div.gallery-content p {\n  font-size: 110%;\n}\n/* --- viewport configuration ---------------------------------------------------------- */\n        .viewport {\n  border: 3px solid #eee;\n/*  float: left;\n*/  height: 248px;\n  margin: 0 0px 9px 0px;\n  overflow: hidden;\n  position: relative;\n  width: 459px;\n  left:15px;\n  display:block;\n}\n/* This is so that the 2nd thumbnail in each row fits snugly. You will want to add a similar\n           class to the last thumbnail in each row to get rid of the margin-right. */\n        .no-margin {\n  margin-right: 0;\n}\n/* --- Link configuration that contains the image and label ----------------------------- */\n        .viewport a {\n  display: block;\n  position: relative;\n}\n/*.viewport a img {\n  height: 268px;\n  left: -20px;\n  position: relative;\n  top: -20px;\n  width: 480px;\n}\n*//* --- Label configuration -------------------------------------------------------------- */\n        .viewport a span {\n  display: none;\n  font-size: 3.0em;\n  font-weight: bold;\n  height: 100%;\n  padding-top: 120px;\n  position: absolute;\n  text-align: center;\n  text-decoration: none;\n  width: 100%;\n  z-index: 100;\n}\n.viewport a span em {\n  display: block;\n  font-size: 0.45em;\n  font-weight: normal;\n}\n/* --- Dark hover background ------------------------------------------------------------ */\n        .dark-background {\n  background:rgba(15, 15, 15, 0.6) url(/images/static/zoom.png) no-repeat 50% 30%;\n  color: #fff;\n  text-shadow: #000 0px 0px 20px;\n}\n.dark-background em {\n  color: #ccc;\n}\n/* --- Light hover background ----------------------------------------------------------- */\n        .light-background {\n  background-color: rgba(255, 255, 255, 0.6);\n  color: #333;\n  text-shadow: #fff 0px 0px 20px;\n}\n.light-background em {\n  color: #707070;\n}\n/**\n         * You could create multiple hover background classes for different looks depending on the\n         * image type. Use your imagination!\n         */\n\n\n\n\n/************************************************************************\nBrowser Specific Fixes\n************************************************************************/\n\n/*WebKit*/\n.webkit table#pricing-chart th.business {\n  height:158px\n}\n.webkit table#pricing-chart th.top {\n  background:url(/images/static/table-top.jpg) no-repeat -5px bottom\n}\n/*Opera*/\n\n\n\n/*MSIE*/\n.ie a.readmore .hover {\n  background: url(/images/static/readmore.png) no-repeat 0 10px;\n}\n.ie7 div#main-inner form#contact-form input[type=\"text\"]#name {\n  margin-top:-50px\n}\n.ie7 div#main-inner form#contact-form input[type=\"text\"]#email {\n  margin-top:-50px\n}\n.ie7 div#main-inner form#contact-form input[type=\"text\"]#website {\n  margin-top:-50px\n}\n.ie7 div#main-inner form#contact-form input[type=\"text\"]#phone {\n  margin-top:-50px\n}\n.ie7 div#main-inner form#contact-form input[type=\"text\"]#subject {\n  margin-top:-50px\n}\n.ie7 div#main-inner form#contact-form input[type=\"text\"]#email {\n  margin-top:-50px\n}\n.ie7 div#main-inner form#contact-form textarea {\n  margin-top:-50px;\n  margin-bottom:30px\n}\n.ie7 div#main-inner form#contact-form input#contact-submit[type=\"submit\"] {\n  border: 0;\n  background: url(/images/static/contact-submit.png) no-repeat 0 0;\n  cursor: pointer;\n  text-indent: -9999px;\n  height:38px;\n  width: 125px;\n  float:right;\n  position:relative;\n  top:65px;\n  line-height:0;\n  font-size:0;\n  left:375px\n}\n.ie7 div#main-inner form#contact-form input#contact-submit[type=\"submit\"]:hover {\n  background-position:0 -40px\n}\n.ie7 form#new_user_old input[type=\"text\"] {\n  margin-top:-50px\n}\n.ie7 form#sign-up-bottom input[type=\"text\"] {\n  margin-top:-50px\n}\n.ie7 form#sign-up-bottom input[type=\"password\"] {\n  margin-top:-50px\n}\n.ie7 form#new_user_old {\n  margin-top:0\n}\n.ie7 div#main-inner input#create[type=\"submit\"] {\n  border: 0;\n  background: url(/images/static/create.gif) no-repeat 0 0;\n  cursor: pointer;\n  text-indent: 0px;\n  line-height:0;\n  font-size:0;\n  color:#86af38;\n  height:70px;\n  width: 539px;\n  margin: 35px\n}\n.ie7 div#hq-main {\n  margin-top:0px;\n  clear:both\n}\n.ie7 div#gallery div.gallery-content {\n  padding:20px 0 40px 0\n}\n\n\n\na.sign-up-floating {\n  background:url(\"/images/static/sign-up-orange.png\") no-repeat scroll 0 0 transparent;\n  height:35px;\n  left:4px;\n/*  margin:0 auto;\n  position:relative;\n*/  text-indent:-9999px;\n  margin-left:40px;\n  margin-right:40px;\n  width:105px;\n  float:left;\n}\na.sign-up-floating:hover {\n  background-position: 0 -37px;\n}\na.sign-up-floating:active {\n  background-position: 0 -36px;\n}\n\n\np.free-plan{\n  margin-top: -10px;\n}\n\n\n\n.fade-left {\n  background: url(/images/static/retro_front.png) no-repeat 0 0px;\n  float: left;\n  position: relative;\n  top: 100px;\n  cursor: pointer;\n  height: 160px;\n}\n\n.screenshot {\n  float: left;\n  background: url(/images/static/border.png) repeat-x 0 0px;\n  padding: 1em;\n  -moz-border-radius: 4px;\n  -webkit-border-radius: 4px;\n  border-radius: 4px;\n}\n\n.screenshot img {\n  border: 1px solid #f3f3f3;\n}\n\n.fade {\n  background: url(/images/static/home_front.png) no-repeat 0 0px;\n  float: left;\n  position: relative;\n  top: 100px;\n  cursor: pointer;\n  height: 160px;\n}\n\n.fade img, .fade-left img {\n  width: 200px;\n  height: 160px;\n}\n\n.catchPhrase {\n  text-align: center;\n  font-size: 1.5em;\n  padding-top: 2em;\n}\n\n.feature {\n  margin-left: 3em;\n}\n\n#arrow {\n  float: left;\n  width: 50px;\n  height: 50px;\n}\n\n#better {\n  margin-bottom: 1em;\n}\n\n.copyright {\n  color: #999;\n  float: right;\n}\n\n/* Learn More */\n.learnMore {\n  margin-top: 2.5em;\n}\n.learnMore h1 {\n  text-align: center;\n/*  margin-top: 0.5em;\n  line-height: 1.15em;\n*/}\n\n.learnMore ul {\n  padding: 0 1.5em 0 0;\n}\n\n.learnMore li {\n  font-family: \"Helvetica Neue\", Arial, sans-serif;\n  font-size:1.5em;line-height:1.5em; margin-bottom:1em;\n  list-style: none;\n  text-shadow: 0 2px #fff;\n}\n\n#caption {\n  margin-left: 20px;\n/*  margin-top: 1em;*/\n  font-weight: bold;\n  color: #555;\n  text-align: center;\n}\n\n.signup-button {\n  width: 185px;\n  background: url(/images/gt/btn-blue-large.png) no-repeat 0 0 transparent;\n  height: 36px;\n    margin-left: auto;\n    margin-right: auto;\n    margin-top: 15px;\n    padding-bottom: 5px;\n    padding-left: 5px;\n    padding-right: 5px;\n    padding-top: 7px;\n    text-align: center;\n    width: 185px;\n}\n\n.signup-area a{\n  color: #fff;\n}\n\n.signup-account{\n  font-size: 80%;\n  margin-top: 26px;\n}\n\n\n.learnMore .box {\n  background-color: #FFF;\n}\n\n.learnMore p {\n  font-family: Georgia, 'Times New Roman', Times, serif;\n  font-size: 16px;\n  line-height: 24px;\n}\n\n.whitebox {padding:1.5em;margin-bottom:1.5em;background:#fff; border: 1px solid #ddd;}\n\n.spacer {height: 2.5em;}\n\n/*.colborder {padding-right:24px;margin-right:25px;border-right:1px solid #eee;}\n.colborder { border-color: #666; }\n*/\n\n.box, .whitebox {\n  -webkit-border-radius: 5px;\n  -moz-border-radius: 5px;\n}\n"
  },
  {
    "path": "public/stylesheets/static/superfish.css",
    "content": "\n/*** ESSENTIAL STYLES ***/\n.sf-menu, .sf-menu * {\n  margin:      0;\n  padding:    0;\n  list-style:    none;\n}\n\nul#topnav .sf-menu a {padding:0}\n\n.sf-menu ul {\n  position:    absolute;\n  top:      -999em;\n  width:      10em; /* left offset of submenus need to match (see below) */\n}\n.sf-menu ul li {\n  width:      100%;\n}\n.sf-menu li:hover {\n  visibility:    inherit; /* fixes IE7 'sticky bug' */\n}\n.sf-menu li {\n  float:      left;\n  position:    relative;\n}\n.sf-menu a {\n  display:    block;\n  position:    relative;\n}\n.sf-menu li:hover ul,\n.sf-menu li.sfHover ul {\n  left:      0;\n  top:      2.5em; /* match top ul list item height */\n  z-index:    9999;\n}\nul.sf-menu li:hover li ul,\nul.sf-menu li.sfHover li ul {\n  top:      -999em;\n}\nul.sf-menu li li:hover ul,\nul.sf-menu li li.sfHover ul {\n  left:      10em; /* match ul width */\n  top:      0;\n}\nul.sf-menu li li:hover li ul,\nul.sf-menu li li.sfHover li ul {\n  top:      -999em;\n}\nul.sf-menu li li li:hover ul,\nul.sf-menu li li li.sfHover ul {\n  left:      10em; /* match ul width */\n  top:      0;\n}\n\n/*** DEMO SKIN ***/\n.sf-menu {\n  float:      left;\n  margin-bottom:  1em;\n}\n.sf-menu a {\n  padding:   .75em 1em;\n  text-decoration:none;\n}\n/*** arrows **/\n.sf-menu a.sf-with-ul {\n  padding-right:   2.25em;\n  min-width:    1px; /* trigger IE7 hasLayout so spans position accurately */\n}\n.sf-sub-indicator {\n  position:    absolute;\n  display:    block;\n  right:      .75em;\n  top:      1.05em; /* IE6 only */\n  width:      10px;\n  height:      10px;\n  text-indent:   -999em;\n  overflow:    hidden;\n  background:    url('/images/static/arrows-ffffff.png') no-repeat -10px -100px; /* 8-bit indexed alpha png. IE6 gets solid image only */\n}\na > .sf-sub-indicator {  /* give all except IE6 the correct values */\n  top:      .8em;\n  background-position: 0 -100px; /* use translucent arrow for modern browsers*/\n}\n/* apply hovers to modern browsers */\na:focus > .sf-sub-indicator,\na:hover > .sf-sub-indicator,\na:active > .sf-sub-indicator,\nli:hover > a > .sf-sub-indicator,\nli.sfHover > a > .sf-sub-indicator {\n  background-position: -10px -100px; /* arrow hovers for modern browsers*/\n}\n\n/* point right for anchors in subs */\n.sf-menu ul .sf-sub-indicator { background-position:  -10px 0; }\n.sf-menu ul a > .sf-sub-indicator { background-position:  0 0; }\n/* apply hovers to modern browsers */\n.sf-menu ul a:focus > .sf-sub-indicator,\n.sf-menu ul a:hover > .sf-sub-indicator,\n.sf-menu ul a:active > .sf-sub-indicator,\n.sf-menu ul li:hover > a > .sf-sub-indicator,\n.sf-menu ul li.sfHover > a > .sf-sub-indicator {\n  background-position: -10px 0; /* arrow hovers for modern browsers*/\n}\n\n/*** shadows for all but IE6 ***/\n.sf-shadow ul {\n  background:  url('/images/static/shadow.png') no-repeat bottom right;\n  padding: 0 8px 9px 0;\n  -moz-border-radius-bottomleft: 17px;\n  -moz-border-radius-topright: 17px;\n  -webkit-border-top-right-radius: 17px;\n  -webkit-border-bottom-left-radius: 17px;\n}\n.sf-shadow ul.sf-shadow-off {\n  background: transparent;\n}\n"
  },
  {
    "path": "public/stylesheets/textile-editor.css",
    "content": "div.textile-toolbar span.ed_sep {\n  xposition: relative;\n  xtop: -4px;\n  padding: 0;\n  height: 6px;\n  width: 2px;\n  margin: 0 2px;\n  border-left: solid 1px #d5d5d5;\n  border-right: solid 1px #f5f5f5;\n}\n\ndiv.textile-toolbar button {\n  margin: 0;\n  background-color: #f0f0ee;\n  background-repeat: no-repeat;\n  border: 1px solid #f0f0ee;\n  padding: 2px 0;\n}\n\ndiv.textile-toolbar button.standard {\n  text-align: center;\n  width: 24px;\n}\n\ndiv.textile-toolbar button img {\n  vertical-align: text-bottom;\n}\n\ndiv.textile-toolbar button:hover,\ndiv.textile-toolbar button.unselected:hover {\n  border: 1px solid #999;\n}\n\ndiv.textile-toolbar button.selected {\n  border: 1px solid #ce9100;\n  background-color: #ffffff;\n}\n\ndiv.textile-toolbar button.unselected {\n  border: 1px solid #f0f0ee;\n  background-color: #f0f0ee;\n}\n\ndiv.textile-toolbar button.publish {\n  padding:5px;\n  display:block;\n}\n\ndiv.textile-toolbar {\n  background-color: #f0f0ee;\n  padding: 0px;\n  margin-bottom: 4px;\n  width: 99%;\n}\n"
  },
  {
    "path": "public/themes/README",
    "content": "Put your Redmine themes here.\n"
  },
  {
    "path": "public/themes/bettermeans/stylesheets/application.css",
    "content": "#admin-menu ul {margin: 0;  padding: 0;}\n#admin-menu li {margin: 0;  padding: 0 0 12px 0; list-style-type:none;}\n\n#admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;}\n#admin-menu a.projects { background-image: url(/images/projects.png); }\n#admin-menu a.users { background-image: url(/images/user.png); }\n#admin-menu a.groups { background-image: url(/images/group.png); }\n#admin-menu a.roles { background-image: url(/images/database_key.png); }\n#admin-menu a.trackers { background-image: url(/images/ticket.png); }\n#admin-menu a.issue_statuses { background-image: url(/images/ticket_edit.png); }\n#admin-menu a.workflows { background-image: url(/images/ticket_go.png); }\n#admin-menu a.custom_fields { background-image: url(/images/textfield.png); }\n#admin-menu a.enumerations { background-image: url(/images/text_list_bullets.png); }\n#admin-menu a.settings { background-image: url(/images/changeset.png); }\n#admin-menu a.plugins { background-image: url(/images/plugin.png); }\n#admin-menu a.info { background-image: url(/images/help.png); }\n\n\n#sidebar{ float: right; width: 30%; position: relative; z-index: 9; min-height: 600px; padding-top:10px; padding-left: 2px; padding-right: 2px padding-botton: 0px; margin: 0;}\n* html #sidebar{ width: 17%; }\n#sidebar h3{ font-size: 14px; margin-top:14px; color: #666;  }\n#sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; }\n* html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; }\n\n#content { /*width: 70%;*/ background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; }\n* html #content{/* width: 70%;*/ padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;}\nhtml>body #content { min-height: 600px; border-bottom: hidden; min-width: 400px; overflow-x:hidden; }\n* html body #content { height: 600px; } /* IE */\n\n#main.nosidebar {width: 100%;}\n#main.nosidebar #sidebar{ display: none; }\n#main.nosidebar #content{ width: 100%; border-right: 0; }\n\n.highlight { background-color: #FCFD8D;}\n.highlight.token-1 { background-color: #faa;}\n.highlight.token-2 { background-color: #afa;}\n.highlight.token-3 { background-color: #aaf;}\n.search-highlight { background-color: #FCFD8D;font-weight:bold;}\n\n.box{\npadding:6px;\nmargin-bottom: 10px;\nbackground-color:#f6f6f6;\ncolor:#505050;\nline-height:1.5em;\nborder: 1px solid #e4e4e4;\n}\n\ndiv.square {\n border: 1px solid #999;\n float: left;\n margin: .3em .4em 0 .4em;\n overflow: hidden;\n width: .6em; height: .6em;\n}\n.contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;margin-right:10px;}\n.contextual input, .contextual select {font-size:0.9em;}\n.message .contextual { margin-top: 0; }\n\n.splitcontentleft{float:left; width:49%;}\n.splitcontentright{float:right; width:49%;}\nform {display: inline;}\ninput, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;}\nfieldset {border: 1px solid #e4e4e4; margin:0;}\nlegend {color: #484848;}\nhr { width: 100%; height: 1px; background: #ccc; border: 0;}\nblockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;}\nblockquote blockquote { margin-left: 0;}\nacronym  { border-bottom: 1px dotted; cursor: help; }\ntextarea.wiki-edit { width: 98%; }\nli p {margin-top: 0;}\ndiv.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;}\np.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;}\np.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; }\np.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; }\n\nfieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; }\nfieldset.collapsible legend { padding-left: 16px; background: url(/images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; }\nfieldset.collapsible.collapsed legend { background-image: url(/images/arrow_collapsed.png); }\n\nfieldset#date-range p { margin: 2px 0 2px 0; }\nfieldset#filters table { border-collapse: collapse; }\nfieldset#filters table td { padding: 0; vertical-align: middle; }\nfieldset#filters tr.filter { height: 2em; }\nfieldset#filters td.add-filter { text-align: right; vertical-align: top; }\n.buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; }\n\ndiv#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;}\ndiv#issue-changesets .changeset { padding: 4px;}\ndiv#issue-changesets .changeset { border-bottom: 1px solid #ddd; }\ndiv#issue-changesets p { margin-top: 0; margin-bottom: 1em;}\n\n#search-results { margin-left: 2em; }\n#search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; }\n#search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; }\n#search-results dd .description { font-style: italic; }\n#search-results span.project:after { content: \" -\"; }\n#search-results dd span.description { display:block; color: #808080; }\n\n#search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; }\n\ndiv#search-results-counts {float:right;}\ndiv#search-results-counts ul { margin-top: 0.5em; }\ndiv#search-results-counts  li { list-style-type:none; float: left; margin-left: 1em; }\n\ndiv#activity dl { margin-left: 2em; }\ndiv#activity dt { margin-bottom: 0px; line-height: 18px; background-position: 0 0; background-repeat: no-repeat;}\ndiv#activity dt.me .time { border-bottom: 1px solid #999; }\ndiv#activity dt .description { display:block; font-style: normal; }\ndiv#activity dt .count { font-size: 80%; font-style: italic; }\ndiv#activity dd .time { color: #777; font-size: 80%; }\ndiv#activity dd .project { color: #777; font-size: 80%; }\ndiv#activity dd .title { font-weight: normal;  padding-left: 25px; }\ndiv#activity dd .description { font-style: normal; padding-left: 25px; }\ndiv#activity dd .bordered { border-left: 2px solid #ccc;}\ndiv#activity dd { margin-bottom: 1em; padding-left: 4px; font-size: 0.9em; margin-left:55px; background-position: 10px 0; background-repeat: no-repeat; }\ndiv#activity dd span.description { display:block; color: #333; }\n\ndiv#activity dl.sub { margin-left: 0; }\ndiv#activity dt.sub { margin-bottom: 0px; line-height: 18px; background-position: 0 0; background-repeat: no-repeat; }\ndiv#activity dt.sub .time { color: #777; }\ndiv#activity dt.sub .count { font-size: 80%; font-style: italic; }\ndiv#activity dd.sub .title { font-weight: bold; padding-left: 15px;}\ndiv#activity dd.sub .description { font-style: normal; padding-left: 5px; }\ndiv#activity dd.sub { margin-bottom: 2px; padding-left: 4px; font-size: 0.9em; margin-left:18px; line-height: 0.9em; background-position: 0 0; background-repeat: no-repeat; }\ndiv#activity dd.sub span.description { display:block; color: #808080; }\n\ndd.issue { background-image: url(/images/ticket.png); }\ndd.issue-edit { background-image: url(/images/ticket_edit.png); }\ndd.issue-closed { background-image: url(/images/ticket_checked.png); }\ndd.issue-note { background-image: url(/images/ticket_note.png); }\ndd.changeset { background-image: url(/images/changeset.png); }\ndd.news { background-image: url(/images/news.png); }\ndd.message { background-image: url(/images/message.png); }\ndd.reply { background-image: url(/images/comments.png); }\ndd.wiki-page, dd.wikipage { background-image: url(/images/wiki_edit.png); }\ndd.attachment { background-image: url(/images/attachment.png); }\ndd.document { background-image: url(/images/document.png); }\ndd.project { background-image: url(/images/projects.png); }\ndd.time-entry { background-image: url(/images/time.png); }\ndd.cr-note { background-image: url(/images/tag_blue.png); }\ndd.team-offer { background-image: url(/images/user_new.png); }\ndd.member-role { background-image: url(/images/users.png); }\n\n#search-results dt.issue.closed { background-image: url(/images/ticket_checked.png); }\n\nform#issue-form .attributes { margin-bottom: 8px; }\nform#issue-form .attributes p { padding-top: 1px; padding-bottom: 2px; }\nform#issue-form .attributes select { min-width: 30%; }\n\nul.projects { margin: 0; padding-left: 1em; }\nul.projects.root { margin: 0;  padding: 0; }\nul.projects ul { border-left: 3px solid #e0e0e0; }\nul.projects li { list-style-type:none; }\nul.projects li.root { margin-bottom: 1em; }\nul.projects li.child { margin-top: 1em;}\nul.projects div.root a.project { font-family: \"Trebuchet MS\", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; }\n.my-project { padding-left: 18px; background: url(/images/fav.png) no-repeat 0 50%; }\n\ntable.projects td {vertical-align:bottom; padding:0px; height:25px;}\n\n#tracker_project_ids ul { margin: 0;  padding-left: 1em; }\n#tracker_project_ids li { list-style-type:none; }\n\nul.properties {padding:0; font-size: 0.9em; color: #777;}\nul.properties li {list-style-type:none;}\nul.properties li span {font-style:italic;}\n\n.total-hours { font-size: 110%; font-weight: bold; }\n.total-hours span.hours-int { font-size: 120%; }\n\n.autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;}\n#user_firstname, #user_lastname, #user_mail, #my_account_form select { width: 90%; }\n\n#workflow_copy_form select { width: 200px; }\n\n.pagination {font-size: 90%}\np.pagination {margin-top:8px;}\n\n/***** Tabular forms ******/\n.tabular p{\nmargin: 0;\npadding: 5px 0 8px 0;\npadding-left: 180px; /*width of left column containing the label elements*/\nheight: 1%;\nclear:left;\n}\n\nhtml>body .tabular p {overflow:hidden;}\n\n.tabular label{\nfont-weight: bold;\nfloat: left;\ntext-align: right;\nmargin-left: -180px; /*width of left column*/\nwidth: 175px; /*width of labels. Should be smaller than left column to create some right\nmargin*/\n}\n\n.tabular label.floating{\nfont-weight: normal;\nmargin-left: 0px;\ntext-align: left;\nwidth: 270px;\n}\n\n.tabular label.block{\nfont-weight: normal;\nmargin-left: 0px !important;\ntext-align: left;\nfloat: none;\ndisplay: block;\nwidth: auto;\n}\n\ninput#time_entry_comments { width: 90%;}\n\n#preview fieldset {margin-top: 1em; background: url(/images/draft.png)}\n\n.tabular.settings p{ padding-left: 300px; }\n.tabular.settings label{ margin-left: -300px; width: 295px; }\n.tabular.settings textarea { width: 99%; }\n\nfieldset.settings label { display: block; }\n\n.required {color: #bb0000;}\n.summary {font-style: italic;}\n\n#attachments_fields input[type=text] {margin-left: 8px; }\n\ndiv.attachments { margin-top: 12px; }\ndiv.attachments p { margin:4px 0 2px 0; }\ndiv.attachments img { vertical-align: middle; }\ndiv.attachments span.author { font-size: 0.9em; color: #888; }\n\np.other-formats { text-align: right; font-size:0.9em; color: #666; }\n.other-formats span + span:before { content: \"| \"; }\n\na.atom { background: url(/images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }\n\n/* Project members tab */\ndiv#tab-content-members .splitcontentleft, div#tab-content-memberships .splitcontentleft, div#tab-content-users .splitcontentleft { width: 64% }\ndiv#tab-content-members .splitcontentright, div#tab-content-memberships .splitcontentright, div#tab-content-users .splitcontentright { width: 34% }\ndiv#tab-content-members fieldset, div#tab-content-memberships fieldset, div#tab-content-users fieldset { padding:1em; margin-bottom: 1em; }\ndiv#tab-content-members fieldset legend, div#tab-content-memberships fieldset legend, div#tab-content-users fieldset legend { font-weight: bold; }\ndiv#tab-content-members fieldset label, div#tab-content-memberships fieldset label, div#tab-content-users fieldset label { display: block; }\ndiv#tab-content-members fieldset div, div#tab-content-users fieldset div { max-height: 400px; overflow:auto; }\n\ntable.members td.group { padding-left: 20px; background: url(/images/group.png) no-repeat 0% 50%; }\n\n* html div#tab-content-members fieldset div { height: 450px; }\n\n\n/***** Gantt chart *****/\n.gantt_hdr {\n  position:absolute;\n  top:0;\n  height:16px;\n  border-top: 1px solid #c0c0c0;\n  border-bottom: 1px solid #c0c0c0;\n  border-right: 1px solid #c0c0c0;\n  text-align: center;\n  overflow: hidden;\n}\n\n.task {\n  position: absolute;\n  height:8px;\n  font-size:0.8em;\n  color:#888;\n  padding:0;\n  margin:0;\n  line-height:0.8em;\n}\n\n.task_late { background:#f66 url(/images/task_late.png); border: 1px solid #f66; }\n.task_done { background:#66f url(/images/task_done.png); border: 1px solid #66f; }\n.task_todo { background:#aaa url(/images/task_todo.png); border: 1px solid #aaa; }\n.milestone { background-image:url(/images/milestone.png); background-repeat: no-repeat; border: 0; }\n\n/***** Icons *****/\n.icon {\nbackground-position: 0% 50%;\nbackground-repeat: no-repeat;\npadding-left: 20px;\npadding-top: 2px;\npadding-bottom: 3px;\n}\n\n.icon-add { background-image: url(/images/add.png); }\n.icon-bullet-add { background-image: url(/images/bullet_add.png); }\n.icon-bullet-delete { background-image: url(/images/bullet_delete.png); }\n.icon-edit { background-image: url(/images/edit.png); }\n.icon-copy { background-image: url(/images/copy.png); }\n.icon-duplicate { background-image: url(/images/duplicate.png); }\n.icon-del { background-image: url(/images/delete.png); }\n.icon-move { background-image: url(/images/move.png); }\n.icon-save { background-image: url(/images/save.png); }\n.icon-cancel { background-image: url(/images/cancel.png); }\n.icon-multiple { background-image: url(/images/table_multiple.png); }\n.icon-folder { background-image: url(/images/folder.png); }\n.open .icon-folder { background-image: url(/images/folder_open.png); }\n.icon-package { background-image: url(/images/package.png); }\n.icon-home { background-image: url(/images/home.png); }\n.icon-user { background-image: url(/images/user.png); }\n.icon-projects { background-image: url(/images/projects.png); }\n.icon-help { background-image: url(/images/help.png); }\n.icon-attachment  { background-image: url(/images/attachment.png); }\n.icon-history  { background-image: url(/images/history.png); }\n.icon-time  { background-image: url(/images/time.png); }\n.icon-time-add  { background-image: url(/images/time_add.png); }\n.icon-stats  { background-image: url(/images/stats.png); }\n.icon-warning  { background-image: url(/images/warning.png); }\n.icon-fav  { background-image: url(/images/fav.png); }\n.icon-fav-off  { background-image: url(/images/fav_off.png); }\n.icon-reload  { background-image: url(/images/reload.png); }\n.icon-lock  { background-image: url(/images/locked.png); }\n.icon-unlock  { background-image: url(/images/unlock.png); }\n.icon-checked  { background-image: url(/images/true.png); }\n.icon-details  { background-image: url(/images/zoom_in.png); }\n.icon-report  { background-image: url(/images/report.png); }\n.icon-comment  { background-image: url(/images/comment.png); }\n.icon-cr-cancel  { background-image: url(/images/cancel16.png); }\n.icon-cr-request { background-image: url(/images/tag_blue.png); }\n.icon-cr-take { background-image: url(/images/wrench.png); }\n.icon-cr-offer { background-image: url(/images/user_go.png); }\n.icon-cr-accept { background-image: url(/images/true.png); }\n.icon-cr-decline { background-image: url(/images/false.png); }\n.icon-cr-ignore { background-image: url(/images/ignore.gif); }\n.icon-summary  { background-image: url(/images/lightning.png); }\n.icon-dashboard { background-image: url(/images/lightning.png); }\n\n\n.icon-file { background-image: url(/images/files/default.png); }\n.icon-file.text-plain { background-image: url(/images/files/text.png); }\n.icon-file.text-x-c { background-image: url(/images/files/c.png); }\n.icon-file.text-x-csharp { background-image: url(/images/files/csharp.png); }\n.icon-file.text-x-php { background-image: url(/images/files/php.png); }\n.icon-file.text-x-ruby { background-image: url(/images/files/ruby.png); }\n.icon-file.text-xml { background-image: url(/images/files/xml.png); }\n.icon-file.image-gif { background-image: url(/images/files/image.png); }\n.icon-file.image-jpeg { background-image: url(/images/files/image.png); }\n.icon-file.image-png { background-image: url(/images/files/image.png); }\n.icon-file.image-tiff { background-image: url(/images/files/image.png); }\n.icon-file.application-pdf { background-image: url(/images/files/pdf.png); }\n.icon-file.application-zip { background-image: url(/images/files/zip.png); }\n.icon-file.application-x-gzip { background-image: url(/images/files/zip.png); }\n\nimg.gravatar {\n  padding: 2px;\n  border: solid 1px #d5d5d5;\n  background: #fff;\n}\n\ndiv.issue img.gravatar {\n  float: right;\n  margin: 0 0 0 1em;\n  padding: 5px;\n}\n\ndiv.issue table img.gravatar {\n  height: 14px;\n  width: 14px;\n  padding: 2px;\n  float: left;\n  margin: 0 0.5em 0 0;\n}\n\n#history img.gravatar {\n  padding: 3px;\n  margin: 0 1.5em 1em 0;\n  float: left;\n}\n\ntd.username img.gravatar {\n  float: left;\n  margin: 0 1em 0 0;\n}\n\n#activity dt img.gravatar {\n  float: left;\n  margin: 0 1em 1em 0;\n}\n\n#activity dt.sub img.gravatar {\n  float: left;\n  margin: 0 2px 2px 0;\n}\n\n#activity dt,\n.journal {\n  clear: left;\n}\n\n.gravatar-margin {\n  margin-left: 60px;\n}\n\nh2 img { vertical-align:middle; }\n\n.hascontextmenu { cursor: context-menu; }\n\n/***** Media print specific styles *****/\n@media print {\n  #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }\n  #main { background: #fff; }\n  #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;}\n  #wiki_add_attachment { display:none; }\n}\n\n\n/***** Flash & error messages ****/\n#errorExplanation, div.flash, .nodata, .warning {\n    padding: 4px 4px 4px 30px;\n    margin-bottom: 12px;\n  font-size: 1.1em;\n  border: 2px solid;\n}\n\ndiv.flash {margin-top: 8px;}\n\ndiv.flash.error, #errorExplanation {\n  background: url(/images/exclamation.png) 8px 50% no-repeat;\n  background-color: #ffe3e3;\n  border-color: #dd0000;\n  color: #880000;\n}\n\ndiv.flash.notice {\n    background: url(/images/true.png) 8px 5px no-repeat;\n  background-color: #dfffdf;\n  border-color: #9fcf9f;\n  color: #005f00;\n}\n\ndiv.flash.warning {\n  background: url(/images/warning.png) 8px 5px no-repeat;\n  background-color: #FFEBC1;\n  border-color: #FDBF3B;\n  color: #A6750C;\n  text-align: left;\n}\n\n.nodata, .warning {\n    text-align: center;\n  background-color: #FFEBC1;\n/*  border-color: #FDBF3B;*/\n/*  color: #A6750C;*/\n}\n\n#errorExplanation ul { font-size: 0.9em;}\n#errorExplanation h2, #errorExplanation p { display: none; }\n\n/***** Ajax indicator ******/\n#ajax-indicator {\nposition: absolute; /* fixed not supported by IE */\nbackground-color:#eee;\nborder: 1px solid #bbb;\ntop:35%;\nleft:40%;\nwidth:20%;\nfont-weight:bold;\ntext-align:center;\npadding:0.6em;\nz-index:100;\nfilter:alpha(opacity=70);\nopacity: 0.7;\n}\n\nhtml>body #ajax-indicator { position: fixed; }\n\n#ajax-indicator span {\nbackground-position: 0% 40%;\nbackground-repeat: no-repeat;\nbackground-image: url(/images/loading.gif);\npadding-left: 26px;\nvertical-align: bottom;\n}\n\n/***** Calendar *****/\ntable.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;}\ntable.cal thead th {width: 14%;}\ntable.cal tbody tr {height: 100px;}\ntable.cal th { background-color:#EEEEEE; padding: 4px; }\ntable.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;}\ntable.cal td p.day-num {font-size: 1.1em; text-align:right;}\ntable.cal td.odd p.day-num {color: #bbb;}\ntable.cal td.today {background:#ffffdd;}\ntable.cal td.today p.day-num {font-weight: bold;}\n\n/***** Tooltips ******/\n.tooltip{position:relative;z-index:24;}\n.tooltip:hover{z-index:25;color:#000;}\n.tooltip span.tip{display: none; text-align:left;}\n\ndiv.tooltip:hover span.tip{\ndisplay:block;\nposition:absolute;\ntop:12px; left:24px; width:270px;\nborder:1px solid #555;\nbackground-color:#fff;\npadding: 4px;\nfont-size: 0.8em;\ncolor:#505050;\n}\n\n/***** Progress bar *****/\ntable.progress {\n    border: 1px solid #D7D7D7;\n    border-collapse: collapse;\n    border-spacing: 0pt;\n    empty-cells: show;\n    text-align: center;\n    float:left;\n    margin: 1px 6px 1px 0px;\n}\n\ntable.progress td { height: 0.9em; }\ntable.progress td.closed { background: #BAE0BA none repeat scroll 0%; }\ntable.progress td.done { background: #DEF0DE none repeat scroll 0%; }\ntable.progress td.open { background: #FFF none repeat scroll 0%; }\np.pourcent {font-size: 80%;}\np.progress-info {clear: left; font-style: italic; font-size: 80%;}\n\n/***** Tabs *****/\n#content .tabs {height: 2.6em; border-bottom: 1px solid #bbbbbb; margin-bottom:1.2em; position:relative; overflow:hidden;}\n#content .tabs ul {margin:0; position:absolute; bottom:-2px; padding-left:1em; width: 2000px;}\n#content .tabs>ul { bottom:-1px; } /* others */\n#content .tabs ul li {\nfloat:left;\nlist-style-type:none;\nwhite-space:nowrap;\nmargin-right:8px;\nbackground:#fff;\n}\n#content .tabs ul li a{\ndisplay:block;\nfont-size: 0.9em;\ntext-decoration:none;\nline-height:1.3em;\npadding:4px 6px 4px 6px;\nborder: 1px solid #ccc;\nborder-bottom: 1px solid #bbbbbb;\nbackground-color: #eeeeee;\ncolor:#777;\nfont-weight:bold;\n}\n\n#content .tabs ul li a:hover {\nbackground-color: #ffffdd;\ntext-decoration:none;\n}\n\n#content .tabs ul li a.selected {\nbackground-color: #fff;\nborder: 1px solid #bbbbbb;\nborder-bottom: 1px solid #fff;\n}\n\n#content .tabs ul li a.selected:hover {\nbackground-color: #fff;\n}\n\ndiv.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: -1px;  }\n\nbutton.tab-left, button.tab-right {\n  font-size: 0.9em;\n  cursor: pointer;\n  height:24px;\n  border: 1px solid #ccc;\n  border-bottom: 1px solid #bbbbbb;\n  position:absolute;\n  padding:4px;\n  width: 20px;\n}\n\nbutton.tab-left {\n  right: 20px;\n  bottom: 0;\n  background: #eeeeee url(/images/bullet_arrow_left.png) no-repeat 50% 50%;\n}\n\nbutton.tab-right {\n  right: 0;\n  bottom: 0;\n  background: #eeeeee url(/images/bullet_arrow_right.png) no-repeat 50% 50%;}\n}\n\n/***** Auto-complete *****/\ndiv.autocomplete {\n  position:absolute;\n  width:250px;\n  background-color:white;\n  margin:0;\n  padding:0;\n}\ndiv.autocomplete ul {\n  list-style-type:none;\n  margin:0;\n  padding:0;\n}\ndiv.autocomplete ul li.selected { background-color: #ffb;}\ndiv.autocomplete ul li {\n  list-style-type:none;\n  display:block;\n  margin:0;\n  padding:2px;\n  cursor:pointer;\n  font-size: 90%;\n  border-bottom: 1px solid #ccc;\n  border-left: 1px solid #ccc;\n  border-right: 1px solid #ccc;\n}\ndiv.autocomplete ul li span.informal {\n  font-size: 80%;\n  color: #aaa;\n}\n\n/***** Diff *****/\n.diff_out { background: #fcc; }\n.diff_in { background: #cfc; }\n\n/***** Wiki *****/\n.wiki h1 {\n  margin-bottom:30px;\n  margin-top:5px;\n}\n\ndiv.wiki table {\n    border: 1px solid #505050;\n    border-collapse: collapse;\n    margin-bottom: 1em;\n}\n\ndiv.wiki table, div.wiki td, div.wiki th {\n    border: 1px solid #bbb;\n    padding: 4px;\n}\n\ndiv.wiki .external {\n    background-position: 0% 60%;\n    background-repeat: no-repeat;\n    padding-left: 12px;\n    background-image: url(/images/external.png);\n}\n\ndiv.wiki a.new {\n    color: #b73535;\n}\n\ndiv.wiki pre {\n    margin: 1em 1em 1em 1.6em;\n    padding: 2px;\n    background-color: #fafafa;\n    border: 1px solid #dadada;\n    width:95%;\n    overflow-x: auto;\n}\n\ndiv.wiki ul.toc {\n    background-color: #ffffdd;\n    border: 1px solid #e4e4e4;\n    padding: 4px;\n    line-height: 1.2em;\n    margin-bottom: 12px;\n    margin-right: 12px;\n    margin-left: 0;\n    display: table\n}\n* html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */\n\ndiv.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; }\ndiv.wiki ul.toc.left  { float: left; margin-right: 12px; margin-left: 0; width: auto; }\ndiv.wiki ul.toc li { list-style-type:none;}\ndiv.wiki ul.toc li.heading2 { margin-left: 6px; }\ndiv.wiki ul.toc li.heading3 { margin-left: 12px; font-size: 0.8em; }\n\ndiv.wiki ul.toc a {\n    font-size: 0.9em;\n    font-weight: normal;\n    text-decoration: none;\n    color: #606060;\n}\ndiv.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;}\n\na.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; }\na.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }\nh1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; }\n\ndiv.concerned_user {\n  text-align: center;\n  width: 100px;\n  float:left;\n}\n\ndiv.motion-description {\n  width: 400px;\n  float:left;\n}\n\n/***** My page layout *****/\n.block-receiver {\nborder:1px dashed #c0c0c0;\nmargin-bottom: 20px;\npadding: 15px 0 15px 0;\n}\n\n.mypage-box {\nmargin:0 0 20px 0;\ncolor:#505050;\nline-height:1.5em;\n}\n\n.handle {\ncursor: move;\n}\n\na.close-icon {\ndisplay:block;\nmargin-top:3px;\noverflow:hidden;\nwidth:12px;\nheight:12px;\nbackground-repeat: no-repeat;\ncursor:pointer;\nbackground-image:url('/images/close.png');\n}\n\na.close-icon:hover {\nbackground-image:url('/images/close_hl.png');\n}\n\n/*Voting*/\n\n.issuevote {\n/*  float: left;*/\n  margin: 2px 0px 1px;\n  padding: 1px;\n  font-size: 12px;\n  font-weight: bold;\n  font-family: baskerville, Times, Times New Roman, serif;\n  color:#484848;\n  text-align:center;\n  width:20px;\n\n}\n\n.issuevote table{\n  padding: 0px;\n  margin: 0px;\n}\n\n.issuevote tr{\n  padding: 0px;\n  margin: 0px;\n  height: 14px;\n  width: 15px;\n}\n\n.issuevote td{\n  padding: 0px;\n  margin: 0px;\n}\n\n.messagevote {\n  -moz-border-radius-bottomleft:3px;\n  -moz-border-radius-bottomright:3px;\n  -moz-border-radius-topleft:3px;\n  -moz-border-radius-topright:3px;\n  background-color:#CDE9A7;\n  border:1px solid #ADDE6B;\n  color:#455138;\n  font-family:baskerville,Times,Times New Roman,serif;\n  font-size:21px;\n  font-weight:normal;\n  margin:2px 0 10px;\n  padding:0px 0px 0px 10px;\n  flaot: left;\n}\n\n.messagevote table{\n  padding: 0px;\n  margin: 3px;\n  font-size:12px;\n}\n\n.messagevote tr{\n  padding: 0px;\n  margin: 0px;\n/*  width: 15px;*/\n}\n\n.messagevote td{\n  padding: 0px 2px 0px 0px;\n  margin: 0px;\n  text-align: center;\n  border: none;\n}\n\n.messagevote td#topic{\n  font-size: 16px;\n  vertical-align: top;\n}\n\n.journalvote {\n/*  float:right; */\n  white-space: nowrap;\n  line-height:1.4em;\n  padding-left: 10px;\n  font-size:0.9em;\n  margin-top: 1.4em;\n  margin-right: 1em; f\n  padding: 1px;\n  font-weight: bold;\n  font-family: baskerville, Times, Times New Roman, serif;\n  color:#484848;\n  text-align:center;\n/*  float: right;*/\n}\n\n.replyvote {\n  float:right;\n  white-space: nowrap;\n  line-height:1.4em;\n  padding-left: 10px;\n  font-size:0.9em;\n  margin-top: 1.4em;\n  margin-right: 1em; f\n  padding: 1px;\n  font-weight: bold;\n  font-family: baskerville, Times, Times New Roman, serif;\n  color:#484848;\n  text-align:center;\n/*  float: right;*/\n}\n\n/*create_request_dialogue*/\n.create_request_dialogue {\n  margin: -13px 10px 0px 10px;\n  text-align: center;\n}\n\n.help_dialogue {\n  margin: -13px 10px 0px 10px;\n  text-align: center;\n}\n\n/*Notifications*/\n\n.notification {\nborder-style:solid;\n/*background-color:#F7F7F7;*/\nborder-color:#CCCCCC;\nborder-style:solid;\nborder-width:1px 0;\nline-height:15px;\nmargin:0 0 -1px;\npadding:1px 20px 12px 20px;\n}\n\n.notification_response {\nbackground-color:#F7F7F7;\nborder-style:solid;\n/*background-color:#F7F7F7;*/\nborder-color:#CCCCCC;\nborder-style:solid;\nborder-width:1px 0;\nline-height:15px;\nmargin:0 0 -1px;\npadding:1px 20px 1px 20px;\n}\n\n.notification table td {\n  border: none;\n  padding: none;\n\n}\n\n.notification h5 {\n  padding-bottom: 5px;\n}\n\n\n/*JGROWL*/\n\ndiv.jGrowl {\n  padding:       10px;\n  z-index:       9999;\n  color:         #fff;\n  font-size:       12px;\n}\n\n/** Special IE6 Style Positioning **/\ndiv.ie6 {\n  position:       absolute;\n}\n\ndiv.ie6.top-right {\n  right:         auto;\n  bottom:       auto;\n  left:         expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n    top:         expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.top-left {\n  left:         expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.bottom-right {\n  left:         expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.bottom-left {\n  left:         expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n}\n\ndiv.ie6.center {\n  left:         expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );\n  top:         expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );\n  width:         100%;\n}\n\n/** Normal Style Positions **/\nbody > div.jGrowl {\n  position:      fixed;\n}\n\nbody > div.jGrowl.top-left {\n  left:         0px;\n  top:         0px;\n}\n\nbody > div.jGrowl.top-right {\n  right:         0px;\n  top:         0px;\n}\n\nbody > div.jGrowl.bottom-left {\n  left:         0px;\n  bottom:        0px;\n}\n\nbody > div.jGrowl.bottom-right {\n  right:         0px;\n  bottom:       0px;\n}\n\nbody > div.jGrowl.center {\n  top:         0px;\n  width:         50%;\n  left:         25%;\n}\n\n/** Cross Browser Styling **/\ndiv.center div.jGrowl-notification, div.center div.jGrowl-closer {\n  margin-left:     auto;\n  margin-right:     auto;\n}\n\ndiv.jGrowl div.jGrowl-notification, div.jGrowl div.jGrowl-closer {\n  background-color:     #d30921;\n/*  opacity:         .85;*/\n    -ms-filter:       \"progid:DXImageTransform.Microsoft.Alpha(Opacity=85)\";\n    filter:         progid:DXImageTransform.Microsoft.Alpha(Opacity=85);\n  zoom:           1;\n  width:           235px;\n  padding:         10px;\n  margin-top:       5px;\n  margin-bottom:       5px;\n  font-family:       Tahoma, Arial, Helvetica, sans-serif;\n  font-size:         1em;\n  text-align:       left;\n  display:         none;\n  -moz-border-radius:   5px;\n  -webkit-border-radius:  5px;\n}\n\ndiv.jGrowl div.jGrowl-notification {\n  min-height:       40px;\n}\n\ndiv.jGrowl div.jGrowl-notification div.header {\n  font-weight:       bold;\n  font-size:        .85em;\n}\n\ndiv.jGrowl div.jGrowl-notification div.close {\n  z-index:        99;\n  float:           right;\n  font-weight:       bold;\n  font-size:         1em;\n  cursor:          pointer;\n}\n\ndiv.jGrowl div.jGrowl-closer {\n  padding-top:       4px;\n  padding-bottom:     4px;\n  cursor:         pointer;\n  font-size:        .9em;\n  font-weight:       bold;\n  text-align:       center;\n}\n\n/** Hide jGrowl when printing **/\n@media print {\n  div.jGrowl {\n    display:       none;\n  }\n}\n\ntable.retrospective {margin-bottom: 30px;}\ntable.retrospective th { vertical-align: top; text-align: left; }\ntable.retrospective td {padding: 3px;border-bottom:none;}\ntable.retrospective td.avatar { vertical-align: top; padding-right: 5px; text-align: center;}\ntable.retrospective td.name { vertical-align: top; padding-right: 5px; width:3em}\ntable.retrospective td.stats { vertical-align: top; border-left-width: 1px; border-left-style:solid; padding-left: 10px; width: 10em;}\ntable.retrospective td.accuracy { vertical-align: top; border-left-width: 1px; border-left-style:solid; padding-left: 10px; width: 10em;}\ntable.retrospective td.percentage { vertical-align: middle; border-left-width: 1px;  font-size: 2em; border-left-style:solid; padding-left: 15px; width: 4em;text-align:center;}\ntable.retrospective td.percentage div.slider { vertical-align: bottom; border-left-width: 0px;  font-size: 0.5em; padding-left: 10px; width: 10em; margin-top:4px;}\ntable.retrospective td.total { vertical-align: top; border-left-width: 0px;  font-size: 2em; border-left-style:solid; padding-left: 10px; width: 4em;text-align:center;}\ntable.retrospective td.button { vertical-align: bottom; border-left-width: 0px;  border-left-style:solid; padding-left: 4px; width: 70px;text-align:center;}\ntable.retrospective td.title { vertical-align: top; border-left-width: 0px;  font-size: 1em; border-left-style:solid; padding-left: 10px; width: 4em;text-align:center;font-weight:bold;}\ntable.retrospective td.subtitle { width: 5em; vertical-align: top; border-left-width: 0px;  font-size: 1em; padding-left: 2em; text-align:right;}\n\n.action_link{\n  color: #fff;\n}\n\na.action_link_votes{\n  color: #333!important;\n}\n\n.action_button{\n  width:60px;\n  height:21px;\n  line-height:21px;\n  text-align:center;\n  vertical-align:middle;\n  cursor:pointer;\n  color: #fff;\n  float: right;\n}\n\n.action_button_no_float{\n  width:60px;\n  height:21px;\n  line-height:21px;\n  text-align:center;\n  vertical-align:middle;\n  cursor:pointer;\n  color: #fff;\n  float: left;\n}\n\n\n.action_button_change{\n  font-color:#000;\n  font-weight:bold;\n  background: url(/images/bb_ocean.png) no-repeat;\n  float:left;\n  padding-top:2px;\n}\n\n\n.action_button_save{\n  font-color:#000;\n  font-weight:bold;\n  background: url(/images/bb_red.png) no-repeat;\n  float:left;\n  padding-top:2px;\n}\n\n.loading {\n  padding-left: 26px;\n  background-position: 0% 40%;\n  background-repeat: no-repeat;\n  background-image: url(/images/loading.gif);\n  font-style: italic;\n}\n\n.clickable{\n  cursor:pointer;\n}\n\n.help_question_mark{\n   cursor:pointer;\n  margin-bottom: 3px;\n  margin-left: 4px;\n}\n\n\n.point-scale{\n  float:left;\n  padding-left:15px;\n}\n\n.left{\n  float:left;\n}\n\n.right{\n  float:right;\n}\n\n.hidden{\n  display:none;\n}\n\n.tip{\n  width:300px;\n}\n\n.bold{\n  font-weight:bold;\n}\n\n\n/*bettermeans stylesheet*/\n\n* {\n  margin: 0;\n  padding: 0;\n}\n\nbody {\n  font: 12px/14px Arial, Helvetica, sans-serif;\n  color: #222;\n  text-align: left;\n  background:  url(/images/top_background.gif) repeat-x;\n}\n\n/* Styles */\n\na { color: #0088cc; text-decoration: none;}\na:hover { text-decoration: underline;}\na img { border: none;}\n\np { margin: 0px 0px 20px 0px; line-height: 18px;}\n\nul { margin: 5px 0px 15px 0px; padding: 0px;}\nli { margin-left: 20px;}\n\n#notice {\n  clear: both;\n  margin: 0 0 15px;\n  padding: 0 10px;\n  background: #fffbcc;\n  border: 1px solid #e6db55;\n  line-height: 25px;\n  color: #222;\n}\n\n#succeed {\n  clear: both;\n  margin: 0 0 15px;\n  padding: 0 10px;\n  background: #d1ecb8;\n  border: 1px solid #81c445;\n  line-height: 25px;\n  color: #222;\n}\n\n#error {\n  clear: both;\n  margin: 0 0 15px;\n  padding: 0 10px;\n  background: #ffebe8;\n  border: 1px solid #f0baa2;\n  line-height: 25px;\n  color: #222;\n}\n\n.clear { clear:both;}\n\n/* Header */\n\n#header {\n  height: 38px;\n  margin: 0 auto;\n  padding: 0 20px;\n  max-width: 1280px;\n  min-width: 760px;\n}\n\n#header h1 {\n  color: #fff;\n  font: 15px Helvetica, Arial, sans-serif;\n}\n\n#header h1 a {\n  color: #fff;\n  text-decoration: none;\n}\n\n#header #quick-search {\n  float: right;\n}\n\n/* main */\n\n#main {\n  margin: 0 auto;\n  padding-top: 10px;\n  max-width: 1280px;\n  min-width: 760px;\n}\n\n#main h2 {\n  margin: 0 0 10px;\n  font: bold 16px/17px Helvetica, Arial, sans-serif;\n  color: #333;\n  padding-top: 10px;\n}\n\n.box {\n  margin: 0 0 20px;\n  padding: 15px 15px 0 15px;\n  border: 1px solid #e8e8e8;\n  background: #fff;\n  position: relative;\n}\n\n/* Sidebar */\n\n#sidebar {\n  float: right;\n/*  width: 220px;*/\n  position: relative;\n  padding-left:10px;\n}\n\n#sidebar h3 {\n  margin: 0 0 15px;\n/*  padding: 0 0 5px;*/\n  color: #222;\n  font-size: 16px;\n/*  border-bottom: 1px dotted #d2d2d2;*/\n/*  padding-top: 5px;*/\n}\n\n\n/* Navigation */\n\n.navigation {\n  margin: 0 0 20px;\n  background: #fff;\n  border-left: 1px solid #e8e8e8;\n  border-right: 1px solid #e8e8e8;\n  border-bottom: 1px solid #e8e8e8;\n}\n\n.navigation ul {\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n\n.navigation ul li {\n  margin: 0;\n  padding: 0 15px;\n  border-top: 1px solid #e8e8e8;\n  background: url(/images/navigation-off.gif) repeat-x;\n  line-height: 24px;\n  height: 100%;\n  display: block;\n  font-size: 12px;\n}\n\n.navigation ul li a {\n  color: #666;\n  height: 100%;\n  width: 100%;\n  display: block;\n}\n\n.navigation ul li.active {\n  background: url(/images/navigation-on.gif) repeat-x;\n}\n\n.navigation ul li.active a {\n  color: #fff;\n}\n\n.navigation ul li ul {\n  margin: 5px 0;\n}\n\n.navigation ul li ul li {\n  margin: 0;\n  padding: 0;\n  font-size: 11px;\n  border: none;\n  background: none;\n}\n\n.navigation ul li ul li a {\n  color: #0088cc;\n}\n\n/* Search */\n\n#search-form {\n  height: 33px;\n}\n\n.search-input {\n  border: 1px solid #d2d2d2;\n  width: 133px;\n  height: 12px;\n  padding: 3px 5px;\n  position: absolute;\n  font-size: 11px;\n}\n\n.search-submit {\n  left: 160px;\n  position: absolute;\n}\n\n/* Blog */\n\n#blog li {\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n\n#blog li h4 {\n  margin: 0 0 5px;\n  font-size: 12px;\n  font-weight: normal;\n}\n\n#blog li h4 abbr {\n  font-size: 10px;\n  color: #999;\n  border: none;\n}\n\n\n/* Content */\n#content h3 {\n  margin: 0 0 15px;\n/*  padding: 5px;*/\n  color: #222;\n  font-size: 16px;\n/*  border-bottom: 1px dotted #d2d2d2;*/\n/*  padding-top: 5px;*/\n}\n\n#content h4 {\n  margin: 0 0 15px;\n  color: #222;\n  font-size: 14px;\n  padding-top: 10px;\n}\n\n#content .notification h4 {\n  margin: 0px;\n  color: #222;\n  font-size: 14px;\n  padding-top: 10px;\n}\n\n/*.notification h4 {\n  margin: 0;\n}\n*/\n\n/* Pagination */\n\n.pagination {\n  text-align: right;\n  display: block;\n  margin: 0 0 15px;\n  font-weight: bold;\n  position: relative;\n}\n\n.pagination ul {\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n\n.pagination ul li {\n  display: inline;\n  margin: 0 5px 0 0;\n  padding: 0;\n  color: #222;\n}\n\n.pagination ul li a {\n}\n\n/* Footer */\n\n#footer {\n/*  background: #fff;*/\n/*  border: 1px solid #e8e8e8;*/\n  padding: 15px;\n  height: 12px;\n  clear: both;\n  text-align: center;\n  margin-top: 10px;\n  width: 50%;\n  min-width: 400px;\n}\n\n#footer .left { float: left;}\n#footer .right { float: right;}\n\n\n/* Form Style */\n\nform ul li {\n  margin: 0 0 15px;\n  padding: 0;\n  list-style: none;\n}\n\nform ul li label {\n  color: #222;\n  font-weight: bold;\n  font-size: 12px;\n}\n\nlabel.note {\n  color: #444;\n  font-weight: normal;\n  font-size: 10px;\n}\n\nlabel.choice {\n  margin: 0 15px 0 0;\n  font-weight: normal;\n  font-size: 12px;\n  color: #666;\n}\n\ninput.text,\ntextarea {\n  margin: 5px 0 5px 0;\n  padding: 3px 5px;\n  border: 1px solid #d2d2d2;\n  font-size: 12px;\n}\n\ninput.radio,\ninput.checkbox,\ninput.file {\n  margin: 5px 5px 0 0;\n}\n\ninput.button {\n  padding: 0 5px 3px 5px;\n  font-size: 12px;\n}\n\nselect.drop {\n  font-size: 12px;\n  margin: 5px 5px 0 0;\n  border: 1px solid #d2d2d2;\n}\n\ninput.short { width: 20%;}\ninput.medium { width: 45%;}\ninput.long { width:70%;}\ninput.max { width: 95%;}\n\n.success {\n  color: #008000;\n}\n\n.error, .req {\n  color: #d8122d;\n  font-weight: normal;\n}\n\n/* Table Style */\n\ntable {\n/*  width: 100%;*/\n  height: 100%;\n  margin: 0 0 15px;\n  text-align: left;\n  border-collapse: collapse;\n}\n\ntable thead,\ntable tfoot {\n/*  background: url(/images/background-table.gif) repeat-x;*/\n}\n\ntable th {\n  font-weight: bold;\n  padding: 5px 8px;\n  color: #444;\n  vertical-align: top;\n}\n\ntable td {\n  padding: 8px;\n  color: #444;\n/*  border-bottom: 1px solid #d2d2d2;*/\n}\n\n#joined_by {\n  line-height:20px;\n}\n\n.half-page{\n  width: 50%;\n  float:left;\n}\n\ntable td span.active { color: #55a34a;}\ntable td span.pending { color: #c5a059;}\ntable td span.closed { color: #a02b2b;}\n\ntable .odd {\n  background: #ddd;\n}\n\ntable.list tr {\n  line-height: 1.1em;\n}\n\ntable.list td.currency {\n  text-align:right;\n}\n\ntable.list th {\n  vertical-align:middle;\n}\n\n/*Old stuff*/\n\n/* Header */\n\n#top-menu { position: relative; padding: 2px 2px 0px 6px; height: 2em; margin: 0 auto; max-width: 1280px; min-width: 760px; font-size:11px;}\n\n#top-menu a {\n  color: #fff;\n}\n\n#top-menu ul {margin: 0;  padding: 0;}\n#top-menu li {\n  float:left;\n  list-style-type:none;\n  margin: 0px 0px 0px 0px;\n  padding: 0px 0px 0px 0px;\n  white-space:nowrap;\n}\n#top-menu li a { color: #fff; font-weight: normal;}\n#top-menu a {color: #fff; margin-right: 0.5em; font-weight: normal;}\n\n#top-menu #loggedas, #top-menu #account { float: right;}\n#top-menu #notification { float: left; margin-left: 0.5em; font-weight:bold; }\n\n/* Menu */\n#header #main-menu {\n  float: left;\n}\n\n#header #main-menu a {\n  color: #fff;\n}\n\n\n/*#header #main-menu {position: relative;  bottom: 0px;  left:6px; margin-right: -500px;}*/\n#header #main-menu ul {margin: 0;  padding: 0; float: left;}\n#header #main-menu li {\n  float:left;\n  list-style-type:none;\n  margin: 0px 2px 0px 0px;\n  padding: 0px 0px 0px 0px;\n  white-space:nowrap;\n}\n#header #main-menu li a {\n  display: block;\n  color: #fff;\n  text-decoration: none;\n  font-weight: bold;\n  margin: 0;\n  padding: 4px 10px 4px 10px;\n}\n\n#header #main-menu li a.selected, #header #main-menu li a.selected:hover {background:#fff; color:#555;}\n\n#header #main-menu { margin: 0; margin-top: 3px;}\n#header #main-menu li a { font-weight: normal; padding:4px 8px 8px;}\n#header #main-menu li a:hover { background: #fff; color:#000; text-decoration: none; }\n#header #main-menu li a.selected, #header #main-menu li a.selected:hover { background-color:#fff; color: #111; font-weight:bold; }\n\n#login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; width:auto; }\n#login-form table td {padding: 6px; border:none;}\n#login-form label {font-weight: bold;}\n#login-form input#username, #login-form input#password { width: 300px; }\n\ninput#openid_url { background: url(/images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; }\n\n.clear:after{ content: \".\"; display: block; height: 0; clear: both; visibility: hidden; }\n\n\ndiv.issues h3 { background: url(/images/ticket.png) no-repeat 0% 50%; padding-left: 20px; }\ndiv.members h3 { background: url(/images/group.png) no-repeat 0% 50%; padding-left: 20px; }\ndiv.news h3 { background: url(/images/news.png) no-repeat 0% 50%; padding-left: 20px; }\ndiv.motions h3 { background: url(/images/wand.png) no-repeat 0% 50%; padding-left: 20px; }\ndiv.projects h3 { background: url(/images/projects.png) no-repeat 0% 50%; padding-left: 20px; }\n\n#search-label{\n  color:#fff;\n}\n\n#quote{\n  width:30%;\n}\n\n\n/*Flyovers*/\n.itemCollapsedHeader {\n  padding:1px 4px;\n}\n\n.itemCollapsedButtons {\n  float:right;\n  padding-bottom:1px;\n  padding-top:2px;\n  padding-left:2px;\n  text-align:right;\n}\n\n.itemCollapsedHeader .icons, .itemCollapsedHeader .itemCollapsedText {\n  padding-bottom:1px;\n  padding-top:1px;\n}\n\n.itemCollapsedText {\n  padding-left:80px;\n}\n\n.itemCollapsedInput {\n  padding-left:20px;\n}\n.itemCollapsedText, .storyLabels {\n  -moz-user-select:none;\n}\n\n\n.underEdit .itemCollapsedHeader {\n  background-color:#FFEDA1;\n}\n\n.unstarted, .newStory {\n  background-color:white;\n}\n.unestimatedText .itemCollapsedHeader {\n  font-style:italic;\n}\n\n/*flyover*/\n.gt-Sd {padding: 6px 17px 7px; background-color: #fff8d7}\n.gt-Sd .elementResizerHandle {display: block}\n.gt-SdTable {padding-top: 10px; border-spacing: 0px 0; border-collapse: separate}\n.gt-SdTable td.letContentExpand {width: 1px;border-bottom:none;}\n.gt-SdTable td {border-bottom:none;}\n.gt-SdTable .created_by {text-align:right; line-height:1.3em;}\n.gt-SdButton {padding: 0px;}\n.gt-SdActionButton {text-align: right; padding: 0px;}\n.gt-Sd .section {color:#333; font-weight:normal; font-size:0.95em; line-height: 14px; margin-top: 15px}\n.gt-Sd .section .header {font-weight:bold; color:#3F3D35; font-size: 115%; margin-bottom: 0}\n.gt-Sd .section textArea, .gt-Sd .section input[type=text].tasksTextArea {width: 95%; overflow:auto; padding: 3px; font-weight:bold; margin-top: 5px; font-size: 104%; max-width:500px;}\n.gt-Sd .storyDescriptionTable textArea {margin-top: 3px}\n.gt-Sd .storyDescriptionTable {width: 100%}\n.gt-Sd .tasksTable {width: 100%}\n.tasksTextArea {margin-top: 3px; width: 95%; overflow:auto; max-width:500px;}\n.gt-Sd .section textArea.textAreaFocus, .gt-Sd input[type=text].textAreaFocus {font-weight:normal; width: 95%}\n.gt-Sd .section .italic {font-style:italic; color:#7C7B76; font-size:0.85em}\n.gt-Sd .section .specialhighlight {color: #333; font-weight:bold; font-size: 103%;}\n.gt-Sd .section input[type='submit'] {margin-top: 4px; display: block}\n.gt-Sd .section .storyDescriptionTable .descriptionHeaderEdit {font-size: 8pt; width:1px; padding-right: 4px}\n.gt-Sd .section .storyDescriptionTable .lastCell {padding-left: 4px}\n.gt-Sd .section .notesTable {width: 100% }\n.gt-Sd .section .notesTable .italic {margin-left:8px }\n.gt-Sd .section tr.noteTextRow + tr.noteInfoRow > td.noteInfo {padding-top:7px }\n.gt-Sd .section .notesTable tr:first-child td, .gt-Sd .section .tasksTable tr:first-child td {padding-top: 4px; padding-bottom:4px;}\n.gt-Sd .section .tasksTable tr:hover td {background-color:#EBE29C}\n.gt-Sd .section .tasksTable td {padding:3px 5px 0px 0px}\n.gt-Sd .section .taskDescription input {width:100%}\n.gt-Sd .section .taskDescription {width:90%}\n.gt-Sd .section .taskDescription:hover {cursor: pointer}\n.gt-Sd .section .task_editing {margin-left: 8px}\n.gt-Sd .section .task_editing + .task_editing {margin-left: 5px}\n.gt-Sd .section .tasksTable .completed {color: #999}\n.gt-Sd .section table td {border-bottom:none;}\n.gt-Sd .section table td.resource_details_cell {vertical-align: top; padding-left: 15px}\n.gt-Sd .section table td.imageCell {text-align: center; width: 75px}\n.gt-Sd .section .resource_image {cursor:pointer}\n.gt-Sd .section table span.resource_row_span{ padding-right: 0.5em}\n.gt-Sd .section .attachments a.cancelLink {padding-left: 1em}\n.gt-Sd .section .attachments .attachmentHint {font-size: 90%; color: #ff6600; font-weight: bold}\n.gt-Sd .section.storyIdTable {border-spacing: 0px 0; border-collapse: separate; width: 100%}\n.gt-Sd .section.storyIdTable .storyId {font-size: 110%; padding-left: 4px}\n.help.flyover {background:url(/images/bg_gradient_comments_hover.gif) #FFF repeat-x scroll left top; border:1px solid #5593D8; -moz-border-radius: 8px; -webkit-border-radius: 8px; padding: 8px}\n.help.flyover .storyTitle {font-size: 1em; font-weight: bold; margin: 3px 0}\n.overlayContentWrapper.gt-Sfo.flyover {padding: 0}\n.gt-Sfo.flyover .storyTitle {background: url('/images/flyover_blue_gradient.png') #FFF top left repeat-x; font-size: 1.15em; font-weight: bold; margin-top:0.3em; padding-bottom:0.75em; padding-left:0.5em; padding-top:0.2em;}\n.gt-Sfo.flyover .gt-Ifc {font-size: 0.9em; background: #fff; padding: 0; -moz-border-radius-bottomleft: 8px; -webkit-border-bottom-left-radius: 8px; -moz-border-radius-bottomright: 8px; -webkit-border-bottom-right-radius: 8px}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .section {margin-bottom: 12px; margin-top: 0px}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .section + .section {margin-top: 13px; margin-bottom: 4px}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .section .header{ background: url('/images/flyover_blue_gradient.png') #FFF top left repeat-x; padding-left: 1em; line-height: 1.7em; font-size: 106%; color: #333; font-weight: bold; letter-spacing: 0.01em; margin-bottom:5px}\n.gt-Sfo.flyover .gt-Sd .section .notesTable tr:first-child td, .gt-Sfo.flyover .gt-Sd .section .tasksTable tr:first-child td {padding-top: auto}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd table, .gt-Sfo.flyover .gt-Ifc.gt-Sd .descriptionText {margin: 0 1.9em 0 1.9em; border-bottom:none;}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .tasksTable td {width: auto; padding: 2px 0px; border-bottom:none;}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .tasksTable td.taskPosition {width: 4%}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .tasksTable tr:hover td {background-color: inherit}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .tasksTable .taskDescription:hover {cursor: auto}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .section table td.resource_details_cell {padding-top: 8px}\n.gt-Sfo.flyover .storyId, .gt-Sfo.flyover .metaInfo {color:#888888; font-size:0.85em;}\n.gt-Sfo.flyover .storyId {font-weight: normal; margin-right: 12px}\n.gt-Sfo.flyover .metaInfo {margin: -0.6em 1.1em 0.5em; padding:2px;}\n.gt-Sfo.flyover .metaInfo .infoSection {color: #666666; font-weight: bold}\n.gt-Sfo.flyover .metaInfo .infoSection img {display: block; padding-top: 1px; padding-right: 3px}\n.gt-Sfo.flyover .metaInfo .infoSection img.estimateIcon {margin-top: 4px; margin-right: 3px}\n.gt-Sfo.flyover .metaInfo .infoSection .text {vertical-align: middle}\n.gt-Sfo.flyover .metaInfo .infoSection + .infoSection {margin-right: 6px}\n.gt-Sfo.flyover .gt-Ifc.gt-Sd .section .notesTable {width: auto}\n\n/*.noteText {line-height: 11px;}*/\n\n.overlay {overflow: hidden; font-size: 0.9em;margin-left: -12px; margin-top: -12px;}\n.overlayContentWrapper {padding: 0 1em}\n\n.gt-SdRow .fieldLabel {margin-left: 5px}\n.gt-SdDiv div {display: block; float: left}\n.storyButtonsRow, .gt-SdRow {clear: both; width: 400px}\n.storyButtonsRow {margin-top: 10px; margin-bottom: 10px}\n.storyButtonsRow div {margin-right: 10px}\n.storyDeadlineField {font: normal 12px verdana, sans-serif; line-height: 20px}\n.spacerCell {width:99%}\n.emphasizedFieldLabel {display:inline;}\n.fieldLabel {display:inline; color:gray}\n.gt-SdField, .storyDeadlineField, .gt-SdTextField {width: 150px; margin-top: 1px; margin-bottom: 1px; margin-right: 8px;}\n.gt-SdTextField{ width: 146px}\n.gt-SdStoryLink {width: 95%; margin-top: 1px; margin-bottom: 1px; margin-right: 10px; padding: 5px}\n.gt-Sd .storyLabels {padding-left: 5px}\n.dateChangeLink {margin-left: 3px}\n.inlinePopup {background-color: #ffffff; border: green 2px solid; overflow: auto; width: 20em; margin: 5px; text-align: center; z-index: 3000}\n.stateChangeButton, .disabledStateChangeButton {margin-left: 4px; vertical-align: bottom}\n.disabledStateChangeButton {opacity: 0.6; -moz-opacity: 0.6; filter: alpha(opacity=60)}\n.stateChangeButton {cursor: pointer; width: auto}\n.estimateButton {border-bottom: 1px solid #888; margin-left: 4px; padding-bottom: 2px; vertical-align: bottom; cursor: pointer}\n.toggleExpandedButton, .gt-IihToggleExpandedButton {vertical-align: middle; cursor: pointer; margin-right: 4px; padding-top: 2px; float: left}\n.gt-IihToggleExpandedButton {display: inline; width:11px; height:16px}\n.gt-IihInfo {margin-left: 19px}\n\n.gt-Iih {\nbackground:url(\"/images/bg_iteration.png\") repeat-x scroll center top #747474;\ncolor:white;\ncursor:default;\npadding-left:0;\npadding-right:0;\n}\n.gt-Iih a.date_label {\ncolor:#FFFFFF !important;\ncursor:pointer;\n}\n.gt-Iih a.date_label.overridden {\ncolor:#FFCC44 !important;\n}\n.gt-Iih a.date_label:hover {\ntext-decoration:underline !important;\n}\n.gt-IihInfo {\n-moz-user-select:none;\n}\n\n\n.lastCell {width:95%}\n.item {border-top: 1px solid #6E6E6E}\n.item.proxy {font-size: 0.8em}\n.items, .search {height: 100%; overflow-y: auto; overflow-x: hidden; position: relative}\n.no_xscroll {overflow-x: hidden; padding-bottom: 15px}\n.no_yscroll {overflow-y: hidden; padding-right: 15px}\n.helpIcon {padding: 2px;}\n.titleInputField {width: 94%; font-size: 11pt; max-width:480px;}\n\n\n/*Buttons*/\n\n.pri_button{\n  width:13px;\n  height:21px;\n  text-align:center;\n  float:right;\n  font-weight: bold;\n/*  color: white;*/\n  padding-left:12px;\n  vertical-align:middle;\n}\n\n.pri_button_action{\n  padding-left:20px;\n}\n\n.pri_button_up{\n  background: url(/images/up_arrow.png) no-repeat;\n\n}\n\n.pri_button_down{\n  background: url(/images/down_arrow.png) no-repeat;\n}\n\n.pri_button_neutral{\n  background: url(/images/neutral_arrow.png) no-repeat;\n}\n\n.pri_button_none{\n  background: url(/images/none_arrow.png) no-repeat;\n}\n\n.action_button_start{\n  background: url(/images/bb_grey.png) no-repeat;\n}\n\n.action_button_root{\n  background: url(/images/bb_grey.png) no-repeat;\n}\n\n.action_button_finish{\n  background: url(/images/bb_grey.png) no-repeat;\n}\n\n.action_button_join{\n  background: url(/images/bb_grey.png) no-repeat;\n}\n\n.action_button_accept{\n  background: url(/images/bb_green.png) no-repeat;\n}\n\n.action_button_reject{\n  background: url(/images/bb_red.png) no-repeat;\n}\n\n.action_button_restart{\n  background: url(/images/bb_purple.png) no-repeat;\n}\n\n.action_button_estimate{\n  background: url(/images/bb_grey.png) no-repeat;\n/*  background: url(/images/bb_blue.png) no-repeat; */\n}\n\n.action_button_agree{\n  background: url(/images/bb_green.png) no-repeat;\n}\n\n.action_button_neutral{\n  background: url(/images/bb_green.png) no-repeat;\n}\n\n.action_button_against{\n  background: url(/images/bb_red.png) no-repeat;\n}\n\n.action_button_block{\n  background: url(/images/bb_red.png) no-repeat;\n}\n\n.action_button_release{\n  background: url(/images/bb_sky.png) no-repeat;\n}\n\n.action_button_leave{\n  background: url(/images/bb_sky.png) no-repeat;\n}\n\n.action_button_cancel{\n  background: url(/images/bb_ocean.png) no-repeat;\n}\n\n.action_button_tally{\n  font-weight:bold;\n  color: #000;\n  background: url(/images/bb_blank.png) no-repeat;\n  width:60px;\n  height:21px;\n  text-align:center;\n  vertical-align:middle;\n  cursor:pointer;\n  float: right;\n}\n\n.action_button_retro{\n  background: url(/images/bb_purple.png) no-repeat;\n}\n\n\n.action_button_accepted{\n  font-weight:bold;\n  color: #000;\n}\n\n.action_button_rejected{\n  font-weight:bold;\n  color: #000;\n}\n\n\n.action_button a, .action_button a:hover, .action_button a:visited {\n  font-size: 11px;\n  color: #ffffff;\n  line-height: 20px;\n}\n\n.action_button a:hover {\n  text-decoration:underline;\n}\n\n#todo_lightbox .tasksTable{\n  margin: 0 0 0 0px;\n}\n\n#todo_lightbox td {\n  padding: 2px;\n}\n\n#todo_lightbox .header {\n  font-weight: bold;\n}\n\n.updating {\n  padding-left: 17px;\n  background-position: 0% 40%;\n  background-repeat: no-repeat;\n  background-image: url(/images/loading.gif);\n}\n\n.spark {\n  display: none;\n}\n\n"
  },
  {
    "path": "script/about",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\n$LOAD_PATH.unshift \"#{RAILTIES_PATH}/builtin/rails_info\"\nrequire 'commands/about'\n\nRedmine::About.print_plugin_info\n"
  },
  {
    "path": "script/autospec",
    "content": "#!/usr/bin/env ruby\ngem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9\nENV['RSPEC'] = 'true'     # allows autotest to discover rspec\nENV['AUTOTEST'] = 'true'  # allows autotest to run w/ color on linux\nsystem((RUBY_PLATFORM =~ /mswin|mingw/ ? 'autotest.bat' : 'autotest'), *ARGV) ||\n  $stderr.puts(\"Unable to find autotest.  Please install ZenTest or fix your PATH\")\n"
  },
  {
    "path": "script/breakpointer",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/breakpointer'"
  },
  {
    "path": "script/console",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/console'"
  },
  {
    "path": "script/cucumber",
    "content": "#!/usr/bin/env ruby\n\nvendored_cucumber_binary = Dir[File.join(File.dirname(__FILE__),\n                                         '..',\n                                         'vendor',\n                                         '{gems,plugins}',\n                                         'cucumber*',\n                                         'bin',\n                                         'cucumber')].first\n\nif vendored_cucumber_binary\n  load File.expand_path(vendored_cucumber_binary)\nelse\n  require 'rubygems' unless ENV['NO_RUBYGEMS']\n  require 'cucumber'\n  load Cucumber::BINARY\nend\n"
  },
  {
    "path": "script/dbconsole",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/dbconsole'\n"
  },
  {
    "path": "script/delayed_job",
    "content": "#!/usr/bin/env ruby\n\nrequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))\nrequire 'delayed/command'\nDelayed::Command.new(ARGV).daemonize\n"
  },
  {
    "path": "script/destroy",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/destroy'"
  },
  {
    "path": "script/generate",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/generate'"
  },
  {
    "path": "script/performance/benchmarker",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../../config/boot'\nrequire 'commands/performance/benchmarker'\n"
  },
  {
    "path": "script/performance/profiler",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../../config/boot'\nrequire 'commands/performance/profiler'\n"
  },
  {
    "path": "script/performance/request",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../../config/boot'\nrequire 'commands/performance/request'\n"
  },
  {
    "path": "script/plugin",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/plugin'"
  },
  {
    "path": "script/process/inspector",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../../config/boot'\nrequire 'commands/process/inspector'\n"
  },
  {
    "path": "script/process/reaper",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../../config/boot'\nrequire 'commands/process/reaper'\n"
  },
  {
    "path": "script/process/spawner",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../../config/boot'\nrequire 'commands/process/spawner'\n"
  },
  {
    "path": "script/process/spinner",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../../config/boot'\nrequire 'commands/process/spinner'\n"
  },
  {
    "path": "script/runner",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/runner'"
  },
  {
    "path": "script/server",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/server'"
  },
  {
    "path": "script/spec",
    "content": "#!/usr/bin/env ruby\nif ARGV.any? {|arg| %w[--drb -X --generate-options -G --help -h --version -v].include?(arg)}\n  require 'rubygems' unless ENV['NO_RUBYGEMS']\nelse\n  gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9\n  ENV[\"RAILS_ENV\"] ||= 'test'\n  require File.expand_path(File.dirname(__FILE__) + \"/../config/environment\") unless defined?(RAILS_ROOT)\nend\nrequire 'spec/autorun'\nexit ::Spec::Runner::CommandLine.run\n"
  },
  {
    "path": "spec/acceptance/acceptance_helper.rb",
    "content": "require File.expand_path(File.dirname(__FILE__) + \"/../spec_helper\")\nrequire \"steak\"\nrequire 'capybara/rails'\n\nSpec::Runner.configure do |config|\n  config.include Capybara\nend\n\n# Put your acceptance spec helpers inside /spec/acceptance/support\nDir[\"#{File.dirname(__FILE__)}/support/**/*.rb\"].each {|f| require f}\n"
  },
  {
    "path": "spec/acceptance/support/helpers.rb",
    "content": "module HelperMethods\n  # Put helper methods you need to be available in all tests here.\nend\n\nSpec::Runner.configuration.include(HelperMethods)\n"
  },
  {
    "path": "spec/acceptance/support/paths.rb",
    "content": "module NavigationHelpers\n  # Put helper methods related to the paths in your application here.\n\n  def homepage\n    \"/\"\n  end\nend\n\nSpec::Runner.configuration.include(NavigationHelpers)\n"
  },
  {
    "path": "spec/acceptance/user_login_spec.rb",
    "content": "require File.expand_path(File.dirname(__FILE__) + '/acceptance_helper')\n\nfeature \"Feature name\", %q{\n  In order to ...\n  As a ...\n  I want to ...\n} do\n\n  scenario \"Scenario name\" do\n    visit '/'\n    page.should have_content('Open, Democratic Project Management')\n    click_link 'sign up'\n    page.should have_content('Plans and Pricing')\n    page.should have_content('Pricing FAQ’s')\n  end\nend\n"
  },
  {
    "path": "spec/controllers/account_controller_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe AccountController do\n  # TODO: can't do this yet, as successful_authentication is stubbed:\n  # integrate_views\n  before :each do\n    @request.env['HTTPS'] = 'on'\n  end\n\n  describe \"#login\" do\n    context \"on an http request\" do\n      it \"redirects to https\" do\n        @request.env['HTTPS'] = nil\n        get(:login)\n        url = \"https://#{@request.host}#{@request.request_uri}\"\n        response.should redirect_to url\n      end\n    end\n\n    context \"given an invitation token in the session\" do\n      context \"with invitation token passed as a param\" do\n        it \"assigns the params version to @invitation_token\" do\n          session[:invitation_token] = 'stuff'\n          get(:login, :invitation_token => 'blah')\n          assigns(:invitation_token).should == 'blah'\n        end\n      end\n\n      context \"without invitiation token passed as param\" do\n        it \"assigns the session version to @invitation_token\" do\n          session[:invitation_token] = 'stuff'\n          get(:login)\n          assigns(:invitation_token).should == 'stuff'\n        end\n      end\n    end\n\n    context \"when request is a GET\" do\n      before :each do\n        Setting.stub(:openid?).and_return(true)\n        controller.stub(:using_open_id?).and_return(true)\n      end\n\n      it \"logs out the user\" do\n        user = Factory.create(:user)\n        User.current = user\n        get(:login)\n        User.current.should == User.anonymous\n      end\n\n      it \"sets the session invitation_token\" do\n        get(:login, :invitation_token => 'blah')\n        session[:invitation_token].should == 'blah'\n      end\n\n      it \"renders the static layout\" do\n        get(:login)\n        response.layout.should == 'layouts/static'\n      end\n    end\n\n    context \"when request is not a GET\" do\n      context \"when openid\" do\n        it \"authenticates via openid\" do\n          Setting.should_receive(:openid?).and_return(true)\n          controller.should_receive(:using_open_id?).and_return(true)\n          user = Factory.create(:user)\n          User.stub(:find_or_initialize_by_identity_url).and_return(user)\n          mock_result = mock(\"result\", :successful? => true)\n          controller.should_receive(:authenticate_with_open_id).\n            and_yield(mock_result, \"something else\", \"whatever\")\n          post(:login, :openid_url => 'blah')\n        end\n      end\n\n      context \"when not openid\" do\n        it \"authenticates via password\" do\n          mock_invitation = mock(\"invitation\", :accept => nil)\n          Invitation.should_receive(:find_by_token).with('blah').and_return(mock_invitation)\n          User.stub(:try_to_login).and_return(Factory.create(:user))\n          post(:login, :invitation_token => 'blah')\n        end\n      end\n    end\n  end\n\n  describe '#rpx_token' do\n    context \"when token is invalid\" do\n      it \"raises an error\" do\n        RPXNow.should_receive(:user_data).with('blah').and_return(nil)\n        expect {\n          get(:rpx_token, :token => 'blah')\n        }.to raise_error(\"hackers?\")\n      end\n    end\n\n    context \"when token is valid\" do\n      let(:user_data) {\n        {\n          :email => 'wah@wah.com',\n          :identifier => 'something',\n          :name => 'steve',\n          :username => 'stevinator'\n        }\n      }\n      before :each do\n        RPXNow.stub(:user_data).and_return(user_data)\n      end\n\n      context \"when there's a session[:invitation_token]\" do\n        before :each do\n          session[:invitation_token] = 'blah'\n        end\n\n        it \"looks up the invitation\" do\n          Invitation.should_receive(:find_by_token).with('blah').twice\n          get(:rpx_token)\n        end\n\n        it \"sets @invitation_token\" do\n          get(:rpx_token)\n          assigns(:invitation_token).should == 'blah'\n        end\n\n        context \"when there's no data[:email]\" do\n          context \"when an invitation was found\" do\n            it \"sets a new user instance with the invitation mail\" do\n              this_data = user_data\n              this_data.delete(:email)\n              RPXNow.stub(:user_data).and_return(this_data)\n              invitation = Factory.create(:invitation, :mail => 'stuff@stuff.com')\n              Invitation.stub(:find_by_token).and_return(invitation)\n              this_data = { :firstname => 'steve', :mail => 'stuff@stuff.com', :identifier => 'something' }\n              user = Factory.build(:user, this_data)\n              User.should_receive(:new).with(this_data).and_return(user)\n              get(:rpx_token)\n            end\n          end\n\n          context \"when an invitation was not found\" do\n            it \"sets the mail to a random mail\" do\n              this_data = user_data\n              this_data.delete(:email)\n              RPXNow.stub(:user_data).and_return(this_data)\n              controller.should_receive(:rand).exactly(8).times.with(25).and_return(5)\n              get(:rpx_token)\n              assigns(:user).mail.should =~ /\\w+_noemail@bettermeans\\.com/\n            end\n          end\n        end\n      end\n\n      context \"when a user is not found for the identifier\" do\n        it \"tries to look up the user by mail\" do\n          User.stub(:find_by_identifier).and_return(nil)\n          User.should_receive(:find_by_mail)\n          get(:rpx_token)\n        end\n\n        context \"if the user is found by mail\" do\n          it \"sets the identifier for that user\" do\n            this_data = { :firstname => 'steve', :mail => 'stuff@stuff.com', :identifier => 'stuff' }\n            user = Factory.build(:user, this_data)\n            User.stub(:find_by_identifier).and_return(nil)\n            User.should_receive(:find_by_mail).and_return(user)\n            get(:rpx_token)\n            user.reload.identifier.should == 'something'\n          end\n        end\n\n        context \"if the user is not found by mail\" do\n          context \"if RPX provides a name\" do\n            it \"initializes a user with firstname set to the given name\" do\n              get(:rpx_token)\n              assigns(:user).firstname.should == 'steve'\n            end\n          end\n\n          context \"if RPX does not provide a name\" do\n            it \"initializes a user with firstname set to the username\" do\n              this_data = user_data\n              this_data.delete(:name)\n              RPXNow.stub(:user_data).and_return(this_data)\n              get(:rpx_token)\n              assigns(:user).firstname.should == 'stevinator'\n            end\n          end\n\n          context \"if RPX provides an email\" do\n            it \"initializes a user with mail set to the email\" do\n              get(:rpx_token)\n              assigns(:user).mail.should == 'wah@wah.com'\n            end\n          end\n\n          context \"if RPX does not provide an email\" do\n            before :each do\n              this_data = user_data\n              this_data.delete(:email)\n              RPXNow.stub(:user_data).and_return(this_data)\n            end\n\n            context \"if an invitation was found\" do\n              it \"initializes a user with mail set to the invitation_mail\" do\n                invitation = Factory.create(:invitation, :mail => 'stuff@stuff.com')\n                Invitation.stub(:find_by_token).and_return(invitation)\n                session[:invitation_token] = 'stuff'\n                get(:rpx_token)\n                assigns(:user).mail.should == 'stuff@stuff.com'\n              end\n            end\n\n            context \"if an invitation was not found\" do\n              it \"initializes a user with mail set to a random email\" do\n                get(:rpx_token)\n                assigns(:user).mail.should =~ /_noemail@bettermeans.com/\n              end\n            end\n          end\n\n          it \"initializes a new user with the identifier given by RPX\" do\n            get(:rpx_token)\n            assigns(:user).identifier.should == 'something'\n          end\n\n          context \"when cleaning up the username\" do\n            before :each do\n              this_data = user_data.merge(:username => \"'\\\"<> stuff\", :name => \"what what\")\n              RPXNow.stub(:user_data).and_return(this_data)\n            end\n\n            context \"if a user does not exist for the *really* clean version\" do\n              it \"assigns the *really* clean username as the user's login\" do\n                User.should_receive(:find_by_login).with(\"_____stuff\").and_return(false)\n                get(:rpx_token)\n                assigns(:user).login.should == \"_____stuff\"\n              end\n            end\n\n            context \"if a user already exists for the *really* clean version\" do\n              it \"assigns a cleaned up version of the name as their login\" do\n                User.stub(:find_by_login).and_return(true)\n                User.should_receive(:find_by_login).with(\"what_what\").and_return(false)\n                get(:rpx_token)\n                assigns(:user).login.should == \"what_what\"\n              end\n            end\n\n            context \"if a user already exists for both versions of the login\" do\n              it \"assigns the user's email as their login\" do\n                User.stub(:find_by_login).and_return(true, true)\n                get(:rpx_token)\n                assigns(:user).login.should == \"wah@wah.com\"\n              end\n            end\n          end\n\n          context \"when the invitation exists\" do\n            it \"assigns invitation.new_mail as the user mail\" do\n              session[:invitation_token] = 'blah'\n              invitation = Factory.create(:invitation)\n              Invitation.stub(:find_by_token).and_return(invitation)\n              get(:rpx_token)\n              invitation.reload.new_mail.should == assigns(:user).mail\n            end\n          end\n\n          context \"when the user does not validate\" do\n            before :each do\n              this_data = user_data.merge(:username => \"admin\", :name => 'what what')\n              RPXNow.stub(:user_data).and_return(this_data)\n              User.stub(:find_by_login).and_return(false)\n            end\n\n            it \"puts the user in the session for debugging\" do\n              begin\n                get(:rpx_token)\n              rescue RuntimeError\n              end\n              session[:debug_user].should =~ /User/\n            end\n\n            it \"puts the rpx data hash in the session for debugging\" do\n              begin\n                get(:rpx_token)\n              rescue RuntimeError\n              end\n              session[:debug_data].should =~ /admin/\n            end\n\n            it \"raises an error\" do\n              expect {\n                get(:rpx_token)\n              }.to raise_error(\"Couldn't create new account\")\n            end\n          end\n        end\n      end\n\n      context \"when a user is found by the identifier\" do\n        context \"when the invitation exists\" do\n          it \"assigns invitation.new_mail as the user mail\" do\n            user = Factory.create(:user, :identifier => 'stuff')\n            this_data = user_data.merge(:identifier => 'stuff')\n            RPXNow.stub(:user_data).and_return(this_data)\n            session[:invitation_token] = 'blah'\n            invitation = Factory(:invitation)\n            Invitation.stub(:find_by_token).and_return(invitation)\n            get(:rpx_token)\n            invitation.reload.new_mail.should == assigns(:user).mail\n          end\n        end\n      end\n\n      context \"when user is not active\" do\n        before :each do\n          this_data = { :status => 2, :firstname => 'steve', :mail => 'stuff@stuff.com', :identifier => 'something' }\n          @user = Factory.create(:user, this_data)\n          session[:invitation_token] = 'blah'\n        end\n\n        it \"reactivates the user\" do\n          get(:rpx_token)\n          assigns(:user).should be_active\n        end\n\n        it \"authenticates with a reactivation message\" do\n          mock_invitation = mock(:update_attributes => nil)\n          mock_invitation.should_receive(:accept).with(@user)\n          Invitation.should_receive(:find_by_token).with('blah').twice.and_return(mock_invitation)\n          get(:rpx_token)\n          response.session[:flash][:notice].should =~ /reactivated/\n        end\n      end\n\n      context \"when user is active\" do\n        before :each do\n          this_data = { :firstname => 'steve', :mail => 'stuff@stuff.com', :identifier => 'something' }\n          @user = Factory.create(:user, this_data)\n          session[:invitation_token] = 'blah'\n        end\n\n        it \"authenticates without a message\" do\n          mock_invitation = mock(:update_attributes => nil)\n          mock_invitation.should_receive(:accept).with(@user)\n          Invitation.should_receive(:find_by_token).with('blah').twice.and_return(mock_invitation)\n          get(:rpx_token)\n        end\n      end\n    end\n  end\n\n  describe '#logout' do\n    let(:user) { Factory.create(:user) }\n\n    before :each do\n      User.current = user\n      @token = Token.create(:user => user, :action => 'autologin')\n      request.cookies[\"autologin\"] = @token.value\n      get(:logout)\n    end\n\n    it 'deletes the autologin cookie' do\n      # for some reason both request.cookies and response.cookies are nil regardless\n      controller.send(:cookies)[:autologin].should_not be\n    end\n\n    it 'deletes all autologin tokens for the given user' do\n      Token.find_by_id(@token.id).should_not be\n    end\n\n    it 'sets the currently logged in user to nil' do\n      User.current.should be_anonymous\n    end\n\n    it 'redirects to the homepage' do\n      response.should redirect_to home_url\n    end\n  end\n\n  describe '#lost_password' do\n    before :each do\n      Setting.stub(:lost_password?).and_return(true)\n    end\n\n    context 'when lost_password setting is not set' do\n      it 'redirects to home_url' do\n        Setting.stub(:lost_password?).and_return(false)\n        get(:lost_password)\n        response.should redirect_to(home_url)\n      end\n    end\n\n    context \"when there is params[:token]\" do\n      let(:user) { Factory.create(:user) }\n      let(:token) { Factory.create(:token, :user => user, :action => 'recovery') }\n\n      context \"if a Token doesn't exist for that param\" do\n        it \"redirects to home_url\" do\n          get(:lost_password, :token => 'bad_token')\n          response.should redirect_to(home_url)\n        end\n      end\n\n      context \"if a Token exists, but is expired\" do\n        it \"redirects to home_url\" do\n          token.stub(:expired?).and_return(true)\n          Token.stub(:find_by_action_and_value).and_return(token)\n          get(:lost_password, :token => token.value)\n          response.should redirect_to(home_url)\n        end\n      end\n\n      context \"if the request is a POST\" do\n        context \"if the user is valid\" do\n          before :each do\n            post(:lost_password, :token => token.value,\n                                 :new_password => 'new_password',\n                                 :new_password_confirmation => 'new_password')\n          end\n\n          it \"changes the user's password\" do\n            User.try_to_login(user.login, 'new_password').should == user\n          end\n\n          it \"destroys the token\" do\n            Token.find_by_id(token.id).should_not be\n          end\n\n          it \"flashes a success message\" do\n            response.session[:flash][:success].should =~ /updated/\n          end\n\n          it \"renders the login page\" do\n            response.should render_template('login')\n          end\n\n          it \"renders the static layout\" do\n            response.layout.should == 'layouts/static'\n          end\n        end\n\n        context \"if the user is not valid\" do\n          before :each do\n            post(:lost_password, :token => token.value,\n                                 :new_password => 'new_password',\n                                 :new_password_confirmation => 'bad_password')\n          end\n\n          it \"does not change the user\" do\n            User.try_to_login(user.login, 'new_password').should_not be\n          end\n\n          it \"renders the password_recovery template\" do\n            response.should render_template('password_recovery')\n          end\n        end\n      end\n\n      it \"renders the password recovery template\" do\n        get(:lost_password, :token => token.value)\n        response.should render_template('account/password_recovery')\n      end\n    end\n\n    context \"when there is no params[:token]\" do\n      let(:user) { Factory.create(:user) }\n\n      context \"if the request is a POST\" do\n        context \"when the mail is invalid\" do\n          before :each do\n            post(:lost_password, :mail => 'bad_mail')\n          end\n\n          it \"flashes an error message\" do\n            response.session[:flash][:error].should =~ /unknown/i\n          end\n\n          it \"renders the lost_password template\" do\n            response.should render_template('lost_password')\n          end\n        end\n\n        context \"when the user uses an external auth source\" do\n          before :each do\n            user.update_attribute(:auth_source_id, 5)\n            post(:lost_password, :mail => user.mail)\n          end\n\n          it \"flashes an error message\" do\n            response.session[:flash][:error].should =~ /impossible to change/i\n          end\n\n          it \"renders the lost_password template\" do\n            response.should render_template('lost_password')\n          end\n        end\n\n        context \"if  the token is valid\" do\n          it \"saves the token\" do\n            post(:lost_password, :mail => user.mail)\n            user.tokens.find_by_action('recovery').should be\n          end\n\n          it \"sends an email\" do\n            Mailer.should_receive(:send_later).with(:deliver_lost_password, instance_of(Token))\n            post(:lost_password, :mail => user.mail)\n          end\n\n          it \"flashes a success message\" do\n            post(:lost_password, :mail => user.mail)\n            response.session[:flash][:success].should =~ /email.*sent/\n          end\n\n          it \"renders the login page\" do\n            post(:lost_password, :mail => user.mail)\n            response.should render_template('login')\n          end\n\n          it \"renders the static layout\" do\n            post(:lost_password, :mail => user.mail)\n            response.layout.should == 'layouts/static'\n          end\n        end\n      end\n\n      context \"if the request is not a POST\" do\n        it \"renders the lost_password template\" do\n          get(:lost_password)\n          response.should render_template('lost_password')\n        end\n      end\n    end\n  end\n\n  describe '#register' do\n    context \"when there is no self_registration setting or session[:auth_source_registration]\" do\n      it \"redirects to home_url\" do\n        Setting.stub(:self_registration?).and_return(false)\n        get(:register)\n        response.should redirect_to(home_url)\n      end\n    end\n\n    context \"when there is a Setting.self_registration\" do\n      before :each do\n        Setting.self_registration = 5\n        get(:register)\n      end\n\n      it \"renders the static layout\" do\n        response.layout.should == 'layouts/static'\n      end\n\n      it \"renders the register template\" do\n        response.should render_template('register')\n      end\n    end\n\n    context \"when there is a session[:auth_source_registration]\" do\n      before :each do\n        Setting.stub(:self_registration?).and_return(false)\n        session[:auth_source_registration] = \"stuff\"\n        get(:register)\n      end\n\n      it \"renders the static layout\" do\n        response.layout.should == 'layouts/static'\n      end\n\n      it \"renders the register template\" do\n        response.should render_template('register')\n      end\n    end\n\n    context \"when given params[:plan]\" do\n      it \"sets the plan id to that of the given plan\" do\n        plan = Plan.find_by_code(1)\n        get(:register, :plan => plan.code)\n        assigns(:plan_id).should == plan.id\n      end\n    end\n\n    context \"when given params[:plan_id]\" do\n      it \"sets the plan id to that id\" do\n        get(:register, :plan_id => \"5\")\n        assigns(:plan_id).should == \"5\"\n      end\n    end\n\n    context \"when not given a param for plan\" do\n      it \"sets the plan id to the id of the free plan\" do\n        get(:register)\n        assigns(:plan_id).should == Plan.free.id\n      end\n    end\n\n    context \"when the request is GET\" do\n      it \"sets the session[:auth_source_registration] to nil\" do\n        session[:auth_source_registration] = \"something\"\n        get(:register)\n        session[:auth_source_registration].should be_nil\n      end\n\n      it \"logs out the current user\" do\n        user = Factory.create(:user)\n        User.current = user\n        get(:register)\n        User.current.should == User.anonymous\n      end\n\n      it \"initializes a new user with the default language\" do\n        Setting.stub(:default_language).and_return('swahili')\n        get(:register)\n        assigns(:user).language.should == 'swahili'\n      end\n\n      context \"when there's a params[:invitation_token]\" do\n        let(:invitation) { Factory.create(:invitation, :mail => 'b@b.com') }\n\n        before :each do\n          get(:register, :invitation_token => invitation.token)\n        end\n\n        it \"sets the session[:invitation_token]\" do\n          session[:invitation_token].should == invitation.token\n        end\n\n        context \"when an invitation is found\" do\n          it \"sets the user's mail from the invitation\" do\n            assigns(:user).mail.should == 'b@b.com'\n          end\n        end\n\n        it \"flashes a message\" do\n          response.session[:flash][:notice].should =~ /activate your invitation.*#{invitation.token}.*Login here/\n        end\n      end\n    end\n\n    context \"when the request is not a GET\" do\n      let(:invitation) { Factory(:invitation, :mail => 'b@b.com') }\n\n      it \"initializes a new user with the given params\" do\n        post(:register, :user => { :mail => 'bill@bill.com' }, :invitation_token => invitation.token)\n        assigns(:user).mail.should == 'bill@bill.com'\n      end\n\n      it \"sets the user's plan to the one found before\" do\n        post(:register, :user => { :mail => 'bill@bill.com' }, :invitation_token => invitation.token)\n        assigns(:user).plan.should == Plan.find(assigns(:plan_id))\n      end\n\n      context \"if the user is not on the free plan\" do\n        it \"sets the user's trial to expire 30 days from now\" do\n          this_time = Time.now\n          Time.stub(:now).and_return(this_time)\n          plan_id = Plan.find_by_code('1').id\n          post(:register, :plan_id => plan_id, :user => { :mail => 'bill@bill.com' }, :invitation_token => invitation.token)\n          assigns(:user).trial_expires_on.should == 30.days.from_now\n        end\n      end\n\n      context \"if the user is on the free plan\" do\n        it \"does not set the user's trial to expire 30 days from now\" do\n          post(:register, :user => { :mail => 'bill@bill.com' }, :invitation_token => invitation.token)\n          assigns(:user).trial_expires_on.should_not be\n        end\n      end\n\n      it \"sets the user not to be an admin\" do\n        post(:register, :user => { :admin => true, :mail => 'bill@bill.com' }, :invitation_token => invitation.token)\n        assigns(:user).should_not be_admin\n      end\n\n      it \"sets the user's status to registered\" do\n        post(:register, :user => { :mail => 'bill@bill.com' }, :invitation_token => invitation.token)\n        assigns(:user).status.should == User::STATUS_REGISTERED\n      end\n\n      context \"when there's a session[:auth_source_registration]\" do\n        before :each do\n          session[:auth_source_registration] = { :login => 'stuff',\n                                                 :auth_source_id => 15 }\n        end\n\n        it \"sets the user's status to active\" do\n          post(:register, :user => { :mail => 'bill@bill.com', :firstname => 'bill' },\n                          :invitation_token => invitation.token)\n          assigns(:user).status.should == User::STATUS_ACTIVE\n        end\n\n        it \"sets the user's login from the auth hash\" do\n          post(:register, :user => { :mail => 'bill@bill.com', :firstname => 'bill' },\n                          :invitation_token => invitation.token)\n          assigns(:user).login.should == 'stuff'\n        end\n\n        it \"sets the user's auth_source_id from the auth hash\" do\n          post(:register, :user => { :mail => 'bill@bill.com', :firstname => 'bill' },\n                          :invitation_token => invitation.token)\n          assigns(:user).auth_source_id.should == 15\n        end\n\n        context \"if the user is valid\" do\n          it \"sets the session[:auth_source_registration] to nil\" do\n            post(:register, :user => { :mail => 'bill@bill.com', :firstname => 'bill' },\n                            :invitation_token => invitation.token)\n            session[:auth_source_registration].should_not be\n          end\n\n          it \"sets the current user to the assigned user\" do\n            post(:register, :user => { :mail => 'bill@bill.com', :firstname => 'bill' },\n                            :invitation_token => invitation.token)\n            User.current.should == assigns(:user)\n          end\n\n          it \"tracks the login\" do\n            session[:client_ip] = 5\n            Track.should_receive(:log).with(Track::LOGIN, 5)\n            post(:register, :user => { :mail => 'bill@bill.com', :firstname => 'bill' },\n                            :invitation_token => invitation.token)\n          end\n\n          it \"redirects to my controller, action account\" do\n            post(:register, :user => { :mail => 'bill@bill.com', :firstname => 'bill' },\n                            :invitation_token => invitation.token)\n            response.should redirect_to({ :controller => 'my', :action => 'account' })\n          end\n\n          it \"flashes a notice\" do\n            post(:register, :user => { :mail => 'bill@bill.com', :firstname => 'bill' },\n                            :invitation_token => invitation.token)\n            response.session[:flash][:notice].should =~ /activated/\n          end\n        end\n      end\n\n      context \"when there is not a session[:auth_source_registration]\" do\n        it \"sets the user's login from the params hash\" do\n          post(:register, :user => { :mail => 'bill@bill.com',\n                                      :firstname => 'bill',\n                                      :login => 'stuff' },\n                          :invitation_token => invitation.token)\n          assigns(:user).login.should == 'stuff'\n        end\n\n        it \"sets the user's password and password confirmation from the hash\" do\n          post(:register, :user => { :mail => 'bill@bill.com',\n                                      :firstname => 'bill',\n                                      :login => 'stuff'},\n                          :invitation_token => invitation.token,\n                          :password => 'blah',\n                          :password_confirmation => 'blah')\n          assigns(:user).password.should == 'blah'\n          assigns(:user).password_confirmation.should == 'blah'\n        end\n\n        context \"when Setting.self_registration == '1'\" do\n          it \"registers by email activation\" do\n            Setting.stub(:self_registration).and_return('1')\n            controller.should_receive(:register_by_email_activation).\n              with(instance_of(User), invitation.token).\n              and_return(true)\n\n            post(:register, :user => { :mail => 'bill@bill.com',\n                                        :firstname => 'bill',\n                                        :login => 'stuff' },\n                            :invitation_token => invitation.token)\n          end\n        end\n\n        context \"when Setting.self_registration == '3'\" do\n          it \"registers automatically\" do\n            Setting.stub(:self_registration).and_return('3')\n            mock_plan = mock(\"plan\", :free? => false)\n            mock_user = mock(\"user\", :plan_id => 5, :plan => mock_plan, :trial_expires_on= => nil, :admin= => nil, :status= => nil, :login= => nil, :auth_source_id= => nil, :save => true, :password= => nil, :password_confirmation= => nil, :last_login_on= => nil)\n            mock_user.should_receive(:plan_id=)\n            User.stub(:new).and_return(mock_user)\n            controller.should_receive(:redirect_to).with(:controller => 'welcome', :action => 'index')\n\n            post(:register, :user => { :mail => 'bill@bill.com',\n                                        :firstname => 'bill',\n                                        :login => 'stuff' },\n                            :invitation_token => invitation.token)\n          end\n        end\n\n        context \"when Setting.self_registration == anything else\" do\n          it \"registers by administrator\" do\n            Setting.stub(:self_registration).and_return('13')\n            controller.should_receive(:register_manually_by_administrator).\n              with(instance_of(User))\n\n            post(:register, :user => { :mail => 'bill@bill.com',\n                                        :firstname => 'bill',\n                                        :login => 'stuff' },\n                            :invitation_token => invitation.token)\n          end\n\n        end\n      end\n    end\n  end\n\n  describe '#activate' do\n    context \"if self_registration is not set\" do\n      it \"redirects to home_url\" do\n        user = Factory.create(:user, :status => User::STATUS_REGISTERED)\n        token = Token.create(:user => user, :action => 'register')\n        Setting.stub(:self_registration?).and_return(false)\n        get(:activate, :token => token.value)\n        response.should redirect_to(home_url)\n      end\n    end\n\n    context \"if params[:token] is not present\" do\n      it \"redirects to home_url\" do\n        user = Factory.create(:user, :status => User::STATUS_REGISTERED)\n        token = Token.create(:user => user, :action => 'register')\n        Setting.stub(:self_registration?).and_return(true)\n        get(:activate)\n        response.should redirect_to(home_url)\n      end\n    end\n\n    context \"if the token is not found\" do\n      it \"redirects to home_url\" do\n        Setting.stub(:self_registration?).and_return(true)\n        get(:activate, :token => 'blah')\n        response.should redirect_to(home_url)\n      end\n    end\n\n    context \"if the token is found but expired\" do\n      it \"redirects to home_url\" do\n        Setting.stub(:self_registration?).and_return(true)\n        user = Factory.create(:user, :status => User::STATUS_REGISTERED)\n        token = Token.create(:user => user, :action => 'register')\n        token.stub(:expired?).and_return(true)\n        Token.should_receive(:find_by_action_and_value).\n          with('register', token.value).\n          and_return(token)\n        get(:activate, :token => token.value)\n        response.should redirect_to(home_url)\n      end\n    end\n\n    context \"if the user is not registered\" do\n      it \"redirects to home_url\" do\n        Setting.stub(:self_registration?).and_return(true)\n        user = Factory.create(:user, :status => User::STATUS_ACTIVE)\n        token = Token.create(:user => user, :action => 'register')\n        get(:activate, :token => token.value)\n        response.should redirect_to(home_url)\n      end\n    end\n\n    context \"if the user is valid\" do\n      let(:user) { Factory.create(:user, :status => User::STATUS_REGISTERED) }\n      let(:token) { Token.create(:user => user, :action => 'register') }\n\n      before :each do\n        Setting.stub(:self_registration?).and_return(true)\n      end\n\n      it \"changes the user's status to active\" do\n        get(:activate, :token => token.value)\n        user.reload.status.should == User::STATUS_ACTIVE\n      end\n\n      it \"destroys the token\" do\n        get(:activate, :token => token.value)\n        Token.find_by_id(token.id).should_not be\n      end\n\n      it \"authenticates the user\" do\n        controller.should_receive(:successful_authentication).with(user)\n        get(:activate, :token => token.value)\n      end\n    end\n\n    context \"if the user is invalid\" do\n      let(:user) { Factory.create(:user, :status => User::STATUS_REGISTERED) }\n      let(:token) { Token.create(:user => user, :action => 'register') }\n\n      before :each do\n        Setting.stub(:self_registration?).and_return(true)\n        user.stub(:save).and_return(false)\n        token.stub(:user).and_return(user)\n        Token.stub(:find_by_action_and_value).and_return(token)\n        get(:activate, :token => token.value)\n      end\n\n      it \"renders the login page\" do\n        response.should render_template('login')\n      end\n\n      it \"renders the static layout\" do\n        response.layout.should == 'layouts/static'\n      end\n    end\n  end\n\n  describe '#cancel' do\n    let(:user) { Factory.create(:user, :mail => 'bob@bob.com') }\n\n    before :each do\n      User.stub(:current).and_return(user)\n    end\n\n    it \"cancels the current user's account\" do\n      get(:cancel)\n      user.reload.should be_canceled\n    end\n\n    it \"renders an account canceled message\" do\n      get(:cancel)\n      response.should render_template ''\n      response.session[:flash][:notice].should =~ /canceled/\n    end\n  end\n\n  # private method, no state\n  describe '#password_authentication' do\n    let(:user) { Factory.create(:user) }\n    before :each do\n      controller.stub(:render)\n    end\n\n    it \"tries to login the user\" do\n      User.should_receive(:try_to_login).with('bill', 'bill_password')\n      controller.stub(:params).and_return({ :username => 'bill', :password => 'bill_password' })\n      controller.send(:password_authentication)\n    end\n\n    context \"when the user does not login properly\" do\n      it \"goes through the invalid credentials flow\" do\n        User.stub(:try_to_login)\n        controller.should_receive(:render).with(:layout => 'static')\n        controller.send(:password_authentication)\n      end\n    end\n\n    context \"when the user is a new record\" do\n      it \"goes through the onthefly creation failed flow\" do\n        user.login = 'bill'\n        user.auth_source_id = 15\n        user.stub(:new_record?).and_return(true)\n        User.stub(:try_to_login).and_return(user)\n        controller.should_receive(:onthefly_creation_failed).with(user, { :login => 'bill', :auth_source_id => 15 })\n        controller.send(:password_authentication)\n      end\n    end\n\n    context \"when the user is not active\" do\n      it \"goes through the inactive_user flow\" do\n        user.stub(:active?).and_return(false)\n        User.stub(:try_to_login).and_return(user)\n        controller.should_receive(:inactive_user)\n        controller.send(:password_authentication)\n      end\n    end\n\n    context \"otherwise\" do\n      context \"when the user is active\" do\n        it \"goes through the successful_authentication flow\" do\n          user.stub(:active?).and_return(true)\n          User.stub(:try_to_login).and_return(user)\n          controller.should_receive(:successful_authentication).with(user, 'token')\n          controller.send(:password_authentication, 'token')\n        end\n      end\n    end\n  end\n\nend\n"
  },
  {
    "path": "spec/controllers/projects/index_active_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe ProjectsController,\"#index_active\" do\n  before :each do\n    login\n    controller.stub(:respond_to)\n    controller.params[:offset] = 5\n    @request.env['HTTPS'] = 'on'\n  end\n\n  it \"finds the 10 most active public workstreams only\" do\n    Project.should_receive(:most_active_public).with(10, anything)\n    Project.should_not_receive(:latest_public)\n\n    get :index_active\n  end\n\n  it \"returns most active public workstreams (as active_enterprises)\" do\n    expected_most_active = \"xxx\"\n\n    Project.should_receive(:most_active_public).with(10, anything).and_return expected_most_active\n\n    get :index_active\n\n    controller.instance_variable_get(:@active_enterprises).should eql expected_most_active\n  end\n\n  it \"uses the offset parameter from query string\" do\n    expected_offset = 1337\n\n    Project.should_receive(:most_active_public).with(anything, expected_offset)\n\n    get :index_active, :offset => expected_offset\n  end\nend\n"
  },
  {
    "path": "spec/controllers/projects/index_latest_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe ProjectsController,\"#index_latest\" do\n  before :each do\n    login\n    @request.env['HTTPS'] = 'on'\n    controller.stub(:respond_to) # TODO: pretty lame to have to do this. Hidden collaborators.\n    controller.params[:offset] = 5\n  end\n\n  it \"finds the 10 latest public workstreams only\" do\n    Project.should_receive(:latest_public).with(10, anything)\n    Project.should_not_receive(:most_active_public)\n\n    get :index_latest\n  end\n\n  it \"returns latest public workstreams (as latest_enterprises)\" do\n    expected_latest_public = \"xxx\"\n\n    Project.should_receive(:latest_public).with(10, anything).and_return expected_latest_public\n\n    get :index_latest\n\n    controller.instance_variable_get(:@latest_enterprises).should eql expected_latest_public\n  end\n\n  it \"uses the offset parameter from query string\" do\n    expected_offset = 1337\n\n    Project.should_receive(:latest_public).with(anything, expected_offset)\n\n    get :index_latest, :offset => expected_offset\n  end\nend\n"
  },
  {
    "path": "spec/controllers/projects/index_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe ProjectsController, \"#index\" do\n  it \"finds the latest public workstreams\" do\n    Project.should_receive(:latest_public)\n\n    controller.index\n  end\n\n  it \"finds the most active public workstreams\" do\n    Project.should_receive(:most_active_public)\n\n    controller.index\n  end\n\n  it \"returns latest public workstreams (as latest_enterprises)\" do\n    expected_latest_public = \"xxx\"\n\n    Project.should_receive(:latest_public).and_return expected_latest_public\n\n    controller.index\n\n    controller.instance_variable_get(:@latest_enterprises).should eql expected_latest_public\n  end\n\n  it \"returns most active public workstreams (as active_enterprises)\" do\n    expected_most_active_public = \"xxx\"\n\n    Project.should_receive(:most_active_public).and_return expected_most_active_public\n\n    controller.index\n\n    controller.instance_variable_get(:@active_enterprises).should eql expected_most_active_public\n  end\nend\n"
  },
  {
    "path": "spec/controllers/projects/move_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe ProjectsController do\n  before(:each) do\n    login\n    @request.env['HTTPS'] = 'on'\n    User.stub_chain(:current, :allowed_to?).and_return true\n    @root = Factory.create(:project, :name => 'root')\n    @parent = Factory.create(:project, :name => 'parent')\n    @project = Factory.create(:project, :name => 'project')\n    @parent.set_parent!(@root)\n    @project.set_parent!(@parent)\n  end\n\n  describe \"#move\" do\n    it \"should redirect if project has no parent\" do\n      get :move, :id => @root.id\n      response.should be_redirect\n    end\n\n    it \"should deny access if user not authorized\" do\n      User.stub_chain(:current, :allowed_to?).and_return false\n      controller.should_receive(:deny_access)\n      get :move, :id => @project.id\n    end\n\n    describe \"(GET)\" do\n      it \"should render move template\" do\n        get :move, :id => @project.id\n        response.should render_template('projects/move.html.erb')\n      end\n\n      it \"should not show children or self in allowed parents\" do\n        get :move, :id => @parent.id\n        assigns(:allowed_projects).should include(@root)\n        assigns(:allowed_projects).should_not include(@parent)\n        assigns(:allowed_projects).should_not include(@project)\n      end\n    end\n\n    describe \"(POST)\" do\n      describe \"with valid parent\" do\n        it \"should update projects parent_id\" do\n          post :move, :id => @project.id, :parent_id => @root.id\n          @project.reload.parent_id.should == @root.id\n        end\n        it \"should redirect to project page\" do\n          post :move, :id => @project.id, :parent_id => @root.id\n          response.should be_redirect\n        end\n        it \"should create an activity stream\" do\n          lambda {\n            post :move, :id => @project.id, :parent_id => @root.id\n          }.should change {ActivityStream.count}\n        end\n      end\n      describe \"with invalid parent\" do\n        it \"should render 403\" do\n          @new_project = Factory.create(:project)\n          post :move, :id => @project.id, :parent_id => @new_project\n          response.should render_template('common/403')\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/controllers/projects/new_dash_data_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe ProjectsController,\"#new_dash_data\" do\n  before :each do\n    login\n    @request.env['HTTPS'] = 'on'\n\n    controller.stub(:respond_to)\n    controller.params[:offset] = 5\n\n    Issue.stub(:find).and_return []\n\n    @project = Project.new\n    @project.stub :locked?\n    given_project_has_issue_count 0\n\n    Project.stub(:find).and_return @project\n\n    @when_william_married_kate = Time.utc 2011,\"apr\",29,10,00\n  end\n\n  context \"given we are not including sub workstreams\" do\n    it \"sets the project's last_item_updated_on to now and then saves it if it does not have one\" do\n      given_the_time_now_is @when_william_married_kate\n      given_the_project_last_had_an_item_updated_at nil\n\n      @project.should_receive(:save).once\n\n      get :new_dashdata\n\n      @project.last_item_updated_on.should eql @when_william_married_kate\n    end\n  end\n\n  context \"given we are including sub workstreams\" do\n    it \"sets the project's last_item_sub_updated_on to DateTime.now and then saves it if it does not have one\" do\n      given_the_time_now_is @when_william_married_kate\n\n      @project.last_item_updated_on = @when_william_married_kate\n      @project.last_item_sub_updated_on = nil\n      @project.stub(:sub_project_array_visible_to).and_return []\n      @project.should_receive(:save).once\n\n      get :new_dashdata, :include_subworkstreams => true\n\n      @project.last_item_sub_updated_on.should eql @when_william_married_kate\n    end\n  end\n\n  it \"does not find issues when the last modification was too long ago\" do\n    two_hours_before_the_wedding = @when_william_married_kate - 2.hours\n\n    given_project_has_issue_count issue_count=10\n    given_the_time_now_is @when_william_married_kate\n    given_the_project_last_had_an_item_updated_at two_hours_before_the_wedding\n\n    Issue.should_not_receive :find\n\n    get :new_dashdata, :seconds => 1, :issuecount => issue_count\n  end\n\n  it \"does not find issues when the last modification is equal to range\" do\n    one_second_before_the_wedding = @when_william_married_kate - 1.seconds\n\n    given_project_has_issue_count issue_count=10\n    given_the_time_now_is @when_william_married_kate\n    given_the_project_last_had_an_item_updated_at one_second_before_the_wedding\n\n    Issue.should_not_receive(:find)\n\n    get :new_dashdata, :seconds => 1, :issuecount => issue_count\n  end\n\n  it \"does not find issues when the last modification is within the range\" do\n    one_second_before_the_wedding = @when_william_married_kate - 1.seconds\n\n    given_project_has_issue_count issue_count=10\n    given_the_time_now_is @when_william_married_kate\n    given_the_project_last_had_an_item_updated_at one_second_before_the_wedding\n\n    Issue.should_receive(:find).once\n\n    get :new_dashdata, :seconds => 2, :issuecount => issue_count\n  end\n\n  private\n\n  def given_the_project_last_had_an_item_updated_at(_when)\n    @project.last_item_updated_on = _when\n  end\n\n  def given_the_time_now_is(what); DateTime.stub(:now).and_return what; end\n  def given_project_has_issue_count(how_many)\n    @project.stub(:issue_count).and_return(how_many)\n  end\nend\n"
  },
  {
    "path": "spec/factories.rb",
    "content": "Factory.define :project do |f|\n  f.sequence(:name) { |n| \"Name of project #{n}\" }\n  f.sequence(:identifier) { |n| \"workstreamid#{n}\" }\n  f.status 1\n  f.trackers Tracker.all\n  f.is_public true\n  f.enabled_module_names Redmine::AccessControl.available_project_modules\nend\n\nFactory.define :user do |f|\n  f.sequence(:login) { |n| \"username#{n}\" }\n  f.password \"password\"\n  f.sequence(:mail) { |n| \"username#{n}@testing.com\" }\n  f.sequence(:firstname) { |n| \"first#{n}\" }\n  f.sequence(:lastname) { |n| \"last#{n}\" }\nend\n\nFactory.define :invitation do |f|\n  f.association :project, :factory => :project\nend\n\nFactory.define :tracker do |f|\n  f.sequence(:position) { |n| \"#{n}\"}\n  f.sequence(:name) { |n| \"tracker#{n}\"}\nend\n\nFactory.define :issue_status do |f|\n  f.sequence(:name) { |n| \"status#{n}\"}\nend\n\nFactory.define :enterprise do |f|\n  f.sequence(:name) { |n| \"Name #{n}\"}\n  f.sequence(:description) { |n| \"Description #{n}\"}\n  f.sequence(:homepage) { |n| \"Homepage #{n}\"}\nend\n\nFactory.define :issue_priority do |f|\n  f.sequence(:name) { |n| \"pri#{n}\" }\nend\n\nFactory.define :issue do |f|\n  f.sequence(:subject) { |n| \"Subject #{n}\"}\n  f.sequence(:description) { |n| \"Description #{n}\"}\n  f.association :tracker, :factory => :tracker\n  f.association :project, :factory => :project\n  f.association :author, :factory => :user\n  f.association :status, :factory => :issue_status\n  f.association :priority, :factory => :issue_priority\nend\n\nFactory.define :token do |f|\n  f.association :user\n  f.action :autologin\nend\n"
  },
  {
    "path": "spec/lib/hash_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe Hash do\n  describe \"#to_array_conditions\" do\n    it \"should load individual values\" do\n      hash = {:v1 => 1, :v2 => '2'}\n\n      possible_results = [\n        [\"v1 = ? AND v2 = ?\",'1','2'],\n        [\"v2 = ? AND v1 = ?\",'2','1'],\n      ]\n\n      possible_results.should include(hash.to_array_conditions)\n    end\n\n    it \"should use in for array values\" do\n      hash = {:v1 => 1, :v2 => [2,'two']}\n\n      possible_results = [\n        [\"v1 = ? AND v2 in (?)\", '1', [2,'two']],\n        [\"v2 in (?) AND v1 = ?\", [2,'two'], '1'],\n      ]\n\n      possible_results.should include(hash.to_array_conditions)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/models/project_spec.rb",
    "content": "require \"spec_helper\"\n\ndescribe Project,\"#visible_by\" do\n  fake_user = Class.new do\n    def initialize(admin = false, memberships = [])\n      @admin,@memberships = admin,memberships\n    end\n\n    def admin?; @admin; end\n    def memberships; @memberships end\n  end\n\n  describe \"given user is admin\" do\n    it \"returns project status filter if user is admin\" do\n      result = Project.visible_by fake_user.new true\n      result.should eql \"projects.status=1\"\n    end\n\n    it \"returns project status and publicity filter if user is not supplied\" do\n      result = Project.visible_by\n      result.should eql \"projects.status=1 AND projects.is_public = 't'\"\n    end\n\n    it \"returns project status and publicity filter if user supplied as nil\" do\n      result = Project.visible_by nil\n      result.should eql \"projects.status=1 AND projects.is_public = 't'\"\n    end\n  end\n\n  describe \"given user is not admin and has memberships\" do\n    it \"returns project status and either public or memberof filter\" do\n      membership = Member.new\n      membership.project_id = 1337\n\n      user = fake_user.new false, [membership]\n\n      result = Project.visible_by user\n\n      result.should eql \"projects.status=1 AND \" +\n        \"(projects.is_public = 't' or projects.id IN (#{membership.project_id}))\"\n    end\n  end\n\n  describe \"given user is not admin and has no memberships\" do\n    it \"returns project status and publicity filter\" do\n      a_user_that_is_not_admin_and_has_no_memberships = fake_user, false, []\n      result = Project.visible_by User.anonymous\n      result.should eql \"projects.status=1 AND projects.is_public = 't'\"\n    end\n  end\nend\n\ndescribe Project,\"#latest_public\" do\n  it \"only queries for root projects, i.e., projects that are not children of other projects\" do\n    fake_named_scope = mock(\"Fake named scope\")\n    fake_named_scope.stub(:find).with(any_args)\n\n    Project.should_receive(:all_roots).once.and_return fake_named_scope\n    Project.should_not_receive(:all_children)\n\n    Project.latest_public fake_admin\n  end\n\n  def fake_admin\n    result = mock(\"A fake admin\")\n    result.stub(:admin?).and_return true\n    result\n  end\nend\n\ndescribe Project,\"#most_active_public\" do\n  it \"only queries for root projects, i.e., projects that are not children of other projects\" do\n    fake_named_scope = mock(\"Fake named scope\")\n    fake_named_scope.stub(:find).with(any_args)\n\n    Project.should_receive(:all_roots).once.and_return fake_named_scope\n    Project.should_not_receive(:all_children)\n\n    Project.most_active_public fake_admin\n  end\n\n  def fake_admin\n    result = mock(\"A fake admin\")\n    result.stub(:admin?).and_return true\n    result\n  end\nend\n\ndescribe User.anonymous,\" user type\" do\n  it \"has zero memberships\" do\n    User.anonymous.memberships.any?.should be_false\n  end\n\n  it \"is not admin\" do\n    User.anonymous.admin?.should be_false\n  end\nend\n"
  },
  {
    "path": "spec/rcov.opts",
    "content": "--exclude \"spec/*,gems/*\"\n--rails"
  },
  {
    "path": "spec/routing/accounts_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe AccountController do\n\n  describe \"routing\" do\n\n    it \"routes to #login\" do\n      route_for(:controller => \"account\", :action => \"login\").should == \"/login\"\n    end\n\n    it \"routes to #rpx_token\" do\n      route_for(:controller => \"account\", :action => \"rpx_token\").should == \"/accounts/rpx_token\"\n    end\n\n    it \"routes to #logout\" do\n      route_for(:controller => \"account\", :action => \"logout\").should == \"/logout\"\n    end\n\n    it \"routes to #lost_password\" do\n      route_for(:controller => \"account\", :action => \"lost_password\").should == \"/account/lost_password\"\n    end\n\n    it \"routes to #register\" do\n      route_for(:controller => \"account\", :action => \"register\").should == \"/account/register\"\n    end\n\n    it \"routes to #activate\" do\n      route_for(:controller => \"account\", :action => \"activate\").should == \"/account/activate\"\n    end\n\n    it \"routes to #cancel\" do\n      route_for(:controller => \"account\", :action => \"cancel\").should == \"/account/cancel\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/activity_stream_preferences_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe ActivityStreamPreferencesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"activity_stream_preferences\", :action => \"index\").should == \"/activity_stream_preferences\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/activity_streams_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe ActivityStreamsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"activity_streams\", :action => \"index\").should == \"/activity_streams\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"activity_streams\", :action => \"show\", :id => \"1\").should == \"/activity_streams/1\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"activity_streams\", :action => \"new\").should == \"/activity_streams/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"activity_streams\", :action => \"edit\", :id => \"1\").should == \"/activity_streams/1/edit\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"activity_streams\", :action => \"create\").should == { :path => \"/activity_streams\", :method => :post }\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"activity_streams\", :action => \"update\", :id => \"1\").should == { :path => \"/activity_streams/1\", :method => :put }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"activity_streams\", :action => \"destroy\", :id => \"1\").should == { :path => \"/activity_streams/1\", :method => :delete }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/admin_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe AdminController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"admin\", :action => \"index\").should == \"/admin\"\n    end\n\n    it \"routes to #projects\" do\n      route_for(:controller => \"admin\", :action => \"projects\").should == \"/admin/projects\"\n    end\n\n    it \"routes to #plugins\" do\n      route_for(:controller => \"admin\", :action => \"plugins\").should == \"/admin/plugins\"\n    end\n\n    it \"routes to #test_email\" do\n      route_for(:controller => \"admin\", :action => \"test_email\").should == \"/admin/test_email\"\n    end\n\n    it \"routes to #user_data_dump\" do\n      route_for(:controller => \"admin\", :action => \"user_data_dump\").should == \"/admin/user_data_dump\"\n    end\n\n    it \"routes to #info\" do\n      route_for(:controller => \"admin\", :action => \"info\").should == \"/admin/info\"\n    end\n\n    it \"routes to #user_stats\" do\n      route_for(:controller => \"admin\", :action => \"user_stats\").should == \"/admin/user_stats\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/attachments_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe AttachmentsController do\n\n  describe \"routing\" do\n\n    it \"routes to #create\" do\n      route_for(:controller => \"attachments\", :action => \"create\", :container_id => \"5\").should == { :path => \"/issues/5/attachments/create\", :method => :post }\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"attachments\", :action => \"show\", :id => \"5\").should == \"/attachments/5\"\n      route_for(:controller => \"attachments\", :action => \"show\", :id => \"5\", :filename => 'five').should == \"/attachments/5/five\"\n    end\n\n    it \"routes to #download\" do\n      route_for(:controller => \"attachments\", :action => \"download\", :id => \"5\", :filename => \"my_file\").should == { :path => \"/attachments/download/5/my_file\" }\n    end\n\n    it \"routes to #destroy\" do\n      # this doesn't make sense.  Can't pass in an id\n      route_for(:controller => \"attachments\", :action => \"destroy\").should == { :path => \"/attachments/destroy\" }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/auth_sources_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe AuthSourcesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"auth_sources\", :action => \"index\").should == \"/auth_sources\"\n    end\n\n    it \"routes to #list\" do\n      route_for(:controller => \"auth_sources\", :action => \"list\").should == \"/auth_sources/list\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"auth_sources\", :action => \"new\").should == \"/auth_sources/new\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"auth_sources\", :action => \"create\").should == \"/auth_sources/create\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"auth_sources\", :action => \"edit\").should == \"/auth_sources/edit\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"auth_sources\", :action => \"update\").should == \"/auth_sources/update\"\n    end\n\n    it \"routes to #test_connection\" do\n      route_for(:controller => \"auth_sources\", :action => \"test_connection\").should == \"/auth_sources/test_connection\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"auth_sources\", :action => \"destroy\").should == \"/auth_sources/destroy\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/boards_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe BoardsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"boards\", :action => \"index\").should == \"/boards\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"boards\", :action => \"show\").should == \"/boards/show\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"boards\", :action => \"new\").should == \"/boards/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"boards\", :action => \"edit\").should == \"/boards/edit\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"boards\", :action => \"destroy\").should == \"/boards/destroy\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/comments_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe CommentsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"comments\", :action => \"index\").should == \"/comments\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"comments\", :action => \"create\").should == \"/comments/create\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/credit_distributions_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe CreditDistributionsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"credit_distributions\", :action => \"index\").should == \"/credit_distributions\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"credit_distributions\", :action => \"show\", :id => \"5\").should == \"/credit_distributions/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"credit_distributions\", :action => \"new\").should == \"/credit_distributions/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"credit_distributions\", :action => \"edit\", :id => \"5\").should == \"/credit_distributions/5/edit\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"credit_distributions\", :action => \"create\").should == { :path => \"/credit_distributions\", :method => :post }\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"credit_distributions\", :action => \"update\", :id => \"5\").should == { :path => \"/credit_distributions/5\", :method => :put }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"credit_distributions\", :action => \"destroy\", :id => \"5\").should == { :path => \"/credit_distributions/5\", :method => :delete }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/credit_transfers_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe CreditTransfersController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"credit_transfers\", :action => \"index\").should == \"/credit_transfers\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"credit_transfers\", :action => \"show\", :id => \"5\").should == \"/credit_transfers/show/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"credit_transfers\", :action => \"new\").should == \"/credit_transfers/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"credit_transfers\", :action => \"edit\", :id => \"5\").should == \"/credit_transfers/edit/5\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"credit_transfers\", :action => \"create\").should == \"/credit_transfers/create\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"credit_transfers\", :action => \"update\", :id => \"5\").should == \"/credit_transfers/update/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"credit_transfers\", :action => \"destroy\", :id => \"5\").should == \"/credit_transfers/destroy/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/credits_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe CreditsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"credits\", :action => \"index\").should == \"/credits\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"credits\", :action => \"show\", :id => \"5\").should == \"/credits/show/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"credits\", :action => \"new\").should == \"/credits/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"credits\", :action => \"edit\", :id => \"5\").should == \"/credits/edit/5\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"credits\", :action => \"create\").should == \"/credits/create\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"credits\", :action => \"update\", :id => \"5\").should == \"/credits/update/5\"\n    end\n\n    it \"routes to #disable\" do\n      route_for(:controller => \"credits\", :action => \"disable\").should == \"/credits/disable\"\n    end\n\n    it \"routes to #enable\" do\n      route_for(:controller => \"credits\", :action => \"enable\").should == \"/credits/enable\"\n    end\n\n    it \"routes to #update_credit_partials\" do\n      route_for(:controller => \"credits\", :action => \"update_credit_partials\").should == \"/credits/update_credit_partials\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"credits\", :action => \"destroy\", :id => \"5\").should == \"/credits/destroy/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/documents_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe DocumentsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"documents\", :action => \"index\", :project_id => \"5\").should == \"/projects/5/documents\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"documents\", :action => \"show\", :id => \"5\").should == \"/documents/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"documents\", :action => \"new\", :project_id => \"5\").should == \"/projects/5/documents/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"documents\", :action => \"edit\", :id => \"5\").should == \"/documents/5/edit\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"documents\", :action => \"destroy\", :id => \"5\").should == {:path => \"/documents/5/destroy\", :method => :post}\n    end\n\n    it \"routes to #add_attachment\" do\n      route_for(:controller => \"documents\", :action => \"add_attachment\", :id => \"5\").should == \"/documents/add_attachment/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/email_updates_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe EmailUpdatesController do\n\n  describe \"routing\" do\n\n    it \"routes to #new\" do\n      route_for(:controller => \"email_updates\", :action => \"new\").should == \"/email_updates/new\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"email_updates\", :action => \"create\").should == {:path => \"/email_updates\", :method => :post }\n    end\n\n    it \"routes to #activate\" do\n      route_for(:controller => \"email_updates\", :action => \"activate\").should == \"/email_updates/activate\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/enterprises_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe EnterprisesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"enterprises\", :action => \"index\").should == \"/enterprises\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"enterprises\", :action => \"show\", :id => '5').should == \"/enterprises/show/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"enterprises\", :action => \"new\").should == \"/enterprises/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"enterprises\", :action => \"edit\", :id => '5').should == \"/enterprises/edit/5\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"enterprises\", :action => \"create\").should == \"/enterprises/create\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"enterprises\", :action => \"destroy\", :id => '5').should == \"/enterprises/destroy/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/enumerations_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe EnumerationsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"enumerations\", :action => \"index\").should == \"/enumerations\"\n    end\n\n    it \"routes to #list\" do\n      route_for(:controller => \"enumerations\", :action => \"list\").should == \"/enumerations/list\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"enumerations\", :action => \"new\").should == \"/enumerations/new\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"enumerations\", :action => \"create\").should == \"/enumerations/create\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"enumerations\", :action => \"edit\", :id => '5').should == \"/enumerations/edit/5\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"enumerations\", :action => \"update\", :id => '5').should == \"/enumerations/update/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"enumerations\", :action => \"destroy\").should == \"/enumerations/destroy\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/help_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe HelpController do\n\n  describe \"routing\" do\n\n    it \"routes to #show\" do\n      route_for(:controller => \"help\", :action => \"show\", :id => \"show\").should == \"/help/show\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/help_sections_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe HelpSectionsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"help_sections\", :action => \"index\").should == \"/help_sections\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"help_sections\", :action => \"show\", :id => \"5\").should == \"/help_sections/5\"\n    end\n\n    it \"routes to #dont_show\" do\n      route_for(:controller => \"help_sections\", :action => \"dont_show\", :id => '5').should == \"/help_sections/dont_show/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"help_sections\", :action => \"new\").should == \"/help_sections/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"help_sections\", :action => \"edit\", :id => \"5\").should == \"/help_sections/5/edit\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"help_sections\", :action => \"create\").should == { :path => \"/help_sections\", :method => :post }\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"help_sections\", :action => \"update\", :id => '5').should == { :path => \"/help_sections/5\", :method => :put }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"help_sections\", :action => \"destroy\", :id => '5').should == { :path => \"/help_sections/5\", :method => :delete }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/home_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe HomeController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"home\", :action => \"index\").should == \"/\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"home\", :action => \"show\", :page => \"index.html\").should == \"/front/index.html\"\n    end\n\n    it \"routes to #robots\" do\n      route_for(:controller => \"home\", :action => \"robots\").should == \"/home/robots\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/hourly_types_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe HourlyTypesController do\n\n  describe \"routing\" do\n\n    it \"routes to #new\" do\n      route_for(:controller => \"hourly_types\", :action => \"new\", :project_id => \"4\").should == \"/projects/4/hourly_types/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"hourly_types\", :action => \"edit\", :project_id => \"4\", :id => \"5\").should == \"/projects/4/hourly_types/5/edit\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"hourly_types\", :action => \"destroy\", :project_id => \"4\", :id => \"5\").should == { :path => \"/projects/4/hourly_types/5/destroy\", :method => :post }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/invitations_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe InvitationsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"invitations\", :action => \"index\", :id => '5').should == \"/invitations/index/5\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"invitations\", :action => \"show\", :id => '5').should == \"/invitations/show/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"invitations\", :action => \"new\", :id => '5').should == \"/invitations/new/5\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"invitations\", :action => \"edit\", :id => '5').should == \"/invitations/edit/5\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"invitations\", :action => \"create\", :id => '5').should == \"/invitations/create/5\"\n    end\n\n    it \"routes to #accept\" do\n      route_for(:controller => \"invitations\", :action => \"accept\", :id => \"5\").should == \"/invitations/5\"\n    end\n\n    it \"routes to #resend\" do\n      route_for(:controller => \"invitations\", :action => \"resend\", :project_id => \"4\", :id => \"5\").should == { :path => \"/projects/4/invitations/5/resend\", :method => :post }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"invitations\", :action => \"destroy\", :project_id => \"4\", :id => \"5\").should == { :path => \"/projects/4/invitations/5/destroy\", :method => :post }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/issue_invitations_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe IssueInvitationsController do\n\n  describe \"routing\" do\n\n    it \"routes to #new\" do\n      route_for(:controller => \"issue_invitations\", :action => \"new\", :id => '5').should == \"/issue_invitations/new/5\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"issue_invitations\", :action => \"create\", :id => '5').should == \"/issue_invitations/create/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/issue_relations_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe IssueRelationsController do\n\n  describe \"routing\" do\n\n    it \"routes to #new\" do\n      route_for(:controller => \"issue_relations\", :action => \"new\", :id => '5').should == \"/issue_relations/new/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"issue_relations\", :action => \"destroy\", :id => '5').should == \"/issue_relations/destroy/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/issue_statuses_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe IssueStatusesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"issue_statuses\", :action => \"index\", :id => '5').should == \"/issue_statuses/index/5\"\n    end\n\n    it \"routes to #list\" do\n      route_for(:controller => \"issue_statuses\", :action => \"list\", :id => '5').should == \"/issue_statuses/list/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"issue_statuses\", :action => \"new\", :id => '5').should == \"/issue_statuses/new/5\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"issue_statuses\", :action => \"create\", :id => '5').should == \"/issue_statuses/create/5\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"issue_statuses\", :action => \"edit\", :id => '5').should == \"/issue_statuses/edit/5\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"issue_statuses\", :action => \"update\", :id => '5').should == \"/issue_statuses/update/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"issue_statuses\", :action => \"destroy\", :id => '5').should == \"/issue_statuses/destroy/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/issue_votes_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe IssueVotesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"issue_votes\", :action => \"index\", :id => '5').should == \"/issue_votes/index/5\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"issue_votes\", :action => \"show\", :id => '5').should == \"/issue_votes/show/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"issue_votes\", :action => \"new\", :id => '5').should == \"/issue_votes/new/5\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"issue_votes\", :action => \"edit\", :id => '5').should == \"/issue_votes/edit/5\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"issue_votes\", :action => \"create\", :id => '5').should == \"/issue_votes/create/5\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"issue_votes\", :action => \"update\", :id => '5').should == \"/issue_votes/update/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"issue_votes\", :action => \"destroy\", :id => '5').should == \"/issue_votes/destroy/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/issues_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe IssuesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"issues\", :action => \"index\").should == \"/issues\"\n      route_for(:controller => \"issues\", :action => \"index\", :project_id => 'pizza').should == \"/projects/pizza/issues\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"issues\", :action => \"show\", :id => '5').should == \"/issues/5/show\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"issues\", :action => \"new\", :project_id => 'pizza').should == \"/projects/pizza/issues/new\"\n      route_for(:controller => \"issues\", :action => \"new\", :project_id => 'pizza', :copy_from => '5').should == \"/projects/pizza/issues/5/copy\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"issues\", :action => \"edit\", :id => '5').should == \"/issues/5/edit\"\n      route_for(:controller => \"issues\", :action => \"edit\", :id => '5').should == { :path => \"/issues/5/edit\", :method => :post }\n    end\n\n    it \"routes to #start\" do\n      route_for(:controller => \"issues\", :action => \"start\", :id => '5').should == { :path => \"/issues/5/start\", :method => :post }\n    end\n\n    it \"routes to #finish\" do\n      route_for(:controller => \"issues\", :action => \"finish\", :id => '5').should == { :path => \"/issues/5/finish\", :method => :post }\n    end\n\n    it \"routes to #release\" do\n      route_for(:controller => \"issues\", :action => \"release\", :id => '5').should == { :path => \"/issues/5/release\", :method => :post }\n    end\n\n    it \"routes to #cancel\" do\n      route_for(:controller => \"issues\", :action => \"cancel\", :id => '5').should == { :path => \"/issues/5/cancel\", :method => :post }\n    end\n\n    it \"routes to #restart\" do\n      route_for(:controller => \"issues\", :action => \"restart\", :id => '5').should == { :path => \"/issues/5/restart\", :method => :post }\n    end\n\n    it \"routes to #change_status\" do\n      route_for(:controller => \"issues\", :action => \"change_status\", :id => '5').should == \"/issues/change_status/5\"\n    end\n\n    it \"routes to #prioritize\" do\n      route_for(:controller => \"issues\", :action => \"prioritize\", :id => '5').should == { :path => \"/issues/5/prioritize\", :method => :post }\n    end\n\n    it \"routes to #update_tags\" do\n      route_for(:controller => \"issues\", :action => \"update_tags\", :id => '5').should == { :path => \"/issues/5/update_tags\", :method => :post }\n    end\n\n    it \"routes to #estimate\" do\n      route_for(:controller => \"issues\", :action => \"estimate\", :id => '5').should == { :path => \"/issues/5/estimate\", :method => :post }\n    end\n\n    it \"routes to #agree\" do\n      route_for(:controller => \"issues\", :action => \"agree\", :id => '5').should == { :path => \"/issues/5/agree\", :method => :post }\n    end\n\n    it \"routes to #accept\" do\n      route_for(:controller => \"issues\", :action => \"accept\", :id => '5').should == { :path => \"/issues/5/accept\", :method => :post }\n    end\n\n    it \"routes to #join\" do\n      route_for(:controller => \"issues\", :action => \"join\", :id => '5').should == { :path => \"/issues/5/join\", :method => :post }\n    end\n\n    it \"routes to #add_team_member\" do\n      route_for(:controller => \"issues\", :action => \"add_team_member\", :id => '5').should == { :path => \"/issues/5/add_team_member\", :method => :post }\n    end\n\n    it \"routes to #remove_team_member\" do\n      route_for(:controller => \"issues\", :action => \"remove_team_member\", :id => '5').should == \"/issues/remove_team_member/5\"\n    end\n\n    it \"routes to #leave\" do\n      route_for(:controller => \"issues\", :action => \"leave\", :id => '5').should == { :path => \"/issues/5/leave\", :method => :post }\n    end\n\n    it \"routes to #reply\" do\n      route_for(:controller => \"issues\", :action => \"reply\", :id => '5').should == { :path => \"/issues/5/quoted\", :method => :post }\n    end\n\n    it \"routes to #bulk_edit\" do\n      route_for(:controller => \"issues\", :action => \"bulk_edit\", :id => '5').should == \"/issues/bulk_edit/5\"\n    end\n\n    it \"routes to #move\" do\n      route_for(:controller => \"issues\", :action => \"move\", :id => '5').should == \"/issues/5/move\"\n      route_for(:controller => \"issues\", :action => \"move\", :id => '5').should == { :path => \"/issues/5/move\", :method => :post }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"issues\", :action => \"destroy\", :id => '5').should == { :path => \"/issues/5/destroy\", :method => :post }\n    end\n\n    it \"routes to #gantt\" do\n      route_for(:controller => \"issues\", :action => \"gantt\", :project_id => '5').should == \"/projects/5/issues/gantt\"\n    end\n\n    it \"routes to #calendar\" do\n      route_for(:controller => \"issues\", :action => \"calendar\", :project_id => '5').should == \"/projects/5/issues/calendar\"\n    end\n\n    it \"routes to #context_menu\" do\n      route_for(:controller => \"issues\", :action => \"context_menu\", :id => '5').should == \"/issues/context_menu/5\"\n    end\n\n    it \"routes to #update_form\" do\n      route_for(:controller => \"issues\", :action => \"update_form\", :id => '5').should == \"/issues/update_form/5\"\n    end\n\n    it \"routes to #preview\" do\n      route_for(:controller => \"issues\", :action => \"preview\", :id => '5').should == \"/issues/preview/5\"\n    end\n\n    it \"routes to #datadump\" do\n      route_for(:controller => \"issues\", :action => \"datadump\").should == \"/issues/datadump\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/journals_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe JournalsController do\n\n  describe \"routing\" do\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"journals\", :action => \"edit\", :id => '5').should == \"/journals/edit/5\"\n    end\n\n    it \"routes to #edit_from_dashboard\" do\n      route_for(:controller => \"journals\", :action => \"edit_from_dashboard\", :id => '5').should == \"/journals/edit_from_dashboard/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/mail_handler_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe MailHandlerController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"mail_handler\", :action => \"index\", :id => '5').should == \"/mail_handler/index/5\"\n    end\n\n    it \"routes to #sendgrid\" do\n      route_for(:controller => \"mail_handler\", :action => \"sendgrid\", :id => '5').should == \"/mail_handler/sendgrid/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/mails_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe MailsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"mails\", :action => \"index\", :id => '5').should == \"/mails/index/5\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"mails\", :action => \"show\", :id => '5').should == \"/mails/show/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"mails\", :action => \"new\", :id => '5').should == \"/mails/new/5\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"mails\", :action => \"create\", :id => '5').should == { :path => \"/mails/create/5\", :method => :post }\n    end\n\n    it \"routes to #delete_selected\" do\n      route_for(:controller => \"mails\", :action => \"delete_selected\", :user_id => '5').should == { :path => \"/users/5/mails/delete_selected\", :method => :post }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/members_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe MembersController do\n\n  describe \"routing\" do\n\n    it \"routes to #new\" do\n      route_for(:controller => \"members\", :action => \"new\", :id => '5').should == \"/projects/5/members/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"members\", :action => \"edit\", :id => '5').should == \"/members/edit/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"members\", :action => \"destroy\", :id => '5').should == { :path => \"/members/destroy/5\", :method => :post }\n    end\n\n    it \"routes to #autocomplete_for_member\" do\n      route_for(:controller => \"members\", :action => \"autocomplete_for_member\").should == \"/members/autocomplete_for_member\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/messages_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe MessagesController do\n\n  describe \"routing\" do\n\n    it \"routes to #show\" do\n      route_for(:controller => \"messages\", :action => \"show\", :board_id => '5', :id => '4').should == \"/boards/5/topics/4\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"messages\", :action => \"new\", :board_id => '5').should == \"/boards/5/topics/new\"\n      route_for(:controller => \"messages\", :action => \"new\", :board_id => '5').should == { :path => \"/boards/5/topics/new\", :method => :post }\n    end\n\n    it \"routes to #reply\" do\n      route_for(:controller => \"messages\", :action => \"reply\", :board_id => '5', :id => '4').should == { :path => \"/boards/5/topics/4/replies\", :method => :post }\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"messages\", :action => \"edit\", :board_id => '5', :id => '4').should == { :path => \"/boards/5/topics/4/edit\", :method => :post }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"messages\", :action => \"destroy\", :board_id => '5', :id => '4').should == { :path => \"/boards/5/topics/4/destroy\", :method => :post }\n    end\n\n    it \"routes to #quote\" do\n      route_for(:controller => \"messages\", :action => \"quote\", :board_id => '5', :id => '4').should == \"/boards/5/topics/quote/4\"\n    end\n\n    it \"routes to #preview\" do\n      route_for(:controller => \"messages\", :action => \"preview\", :board_id => '5', :id => '4').should == \"/boards/5/topics/preview/4\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/motion_votes_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe MotionVotesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"motion_votes\", :action => \"index\", :id => '5').should == \"/motion_votes/index/5\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"motion_votes\", :action => \"show\", :id => '5').should == \"/motion_votes/show/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"motion_votes\", :action => \"new\", :id => '5').should == \"/motion_votes/new/5\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"motion_votes\", :action => \"edit\", :id => '5').should == \"/motion_votes/edit/5\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"motion_votes\", :action => \"create\", :id => '5').should == \"/motion_votes/create/5\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"motion_votes\", :action => \"update\", :id => '5').should == \"/motion_votes/update/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"motion_votes\", :action => \"destroy\", :id => '5').should == \"/motion_votes/destroy/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/motions_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe MotionsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"motions\", :action => \"index\", :project_id => '5').should == \"projects/5/motions\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"motions\", :action => \"show\", :project_id => '5', :id => '4').should == \"projects/5/motions/4\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"motions\", :action => \"new\", :project_id => '5').should == \"projects/5/motions/new\"\n    end\n\n    it \"routes to #eligible_users\" do\n      route_for(:controller => \"motions\", :action => \"eligible_users\", :id => '5').should == \"/motions/eligible_users/5\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"motions\", :action => \"edit\", :project_id => '5', :id => '4').should == \"projects/5/motions/4/edit\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"motions\", :action => \"create\", :project_id => '5').should == { :path => \"projects/5/motions\", :method => :post }\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"motions\", :action => \"update\", :project_id => '5', :id => '4').should == { :path => \"projects/5/motions/4\", :method => :put }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"motions\", :action => \"destroy\", :project_id => '5', :id => '4').should == { :path => \"projects/5/motions/4\", :method => :delete }\n    end\n\n    it \"routes to #reply\" do\n      route_for(:controller => \"motions\", :action => \"reply\", :id => '5').should == \"/motions/reply/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/my_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe MyController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"my\", :action => \"index\", :id => '5').should == \"/my/index/5\"\n    end\n\n    it \"routes to #page\" do\n      route_for(:controller => \"my\", :action => \"page\", :id => '5').should == \"/my/page/5\"\n    end\n\n    it \"routes to #projects\" do\n      route_for(:controller => \"my\", :action => \"projects\", :id => '5').should == \"/my/projects/5\"\n    end\n\n    it \"routes to #issues\" do\n      route_for(:controller => \"my\", :action => \"issues\", :id => '5').should == \"/my/issues/5\"\n    end\n\n    it \"routes to #account\" do\n      route_for(:controller => \"my\", :action => \"account\", :id => '5').should == \"/my/account/5\"\n    end\n\n    it \"routes to #upgrade\" do\n      route_for(:controller => \"my\", :action => \"upgrade\", :id => '5').should == \"/my/upgrade/5\"\n    end\n\n    it \"routes to #password\" do\n      route_for(:controller => \"my\", :action => \"password\", :id => '5').should == \"/my/password/5\"\n    end\n\n    it \"routes to #reset_rss_key\" do\n      route_for(:controller => \"my\", :action => \"reset_rss_key\", :id => '5').should == \"/my/reset_rss_key/5\"\n    end\n\n    it \"routes to #reset_api_key\" do\n      route_for(:controller => \"my\", :action => \"reset_api_key\", :id => '5').should == \"/my/reset_api_key/5\"\n    end\n\n    it \"routes to #page_layout\" do\n      route_for(:controller => \"my\", :action => \"page_layout\", :id => '5').should == \"/my/page_layout/5\"\n    end\n\n    it \"routes to #add_block\" do\n      route_for(:controller => \"my\", :action => \"add_block\", :id => '5').should == \"/my/add_block/5\"\n    end\n\n    it \"routes to #remove_block\" do\n      route_for(:controller => \"my\", :action => \"remove_block\", :id => '5').should == \"/my/remove_block/5\"\n    end\n\n    it \"routes to #order_blocks\" do\n      route_for(:controller => \"my\", :action => \"order_blocks\", :id => '5').should == \"/my/order_blocks/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/news_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe NewsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"news\", :action => \"index\").should == \"/news\"\n      route_for(:controller => \"news\", :action => \"index\", :project_id => '5').should == \"projects/5/news\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"news\", :action => \"show\", :id => '5').should == \"/news/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"news\", :action => \"new\", :project_id => '5').should == \"/projects/5/news/new\"\n      params_from(:post, \"/projects/5/news\").should == { :controller => \"news\", :action => \"new\", :project_id => '5' }\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"news\", :action => \"edit\", :id => '5').should == \"/news/5/edit\"\n      route_for(:controller => \"news\", :action => \"edit\", :id => '5').should == { :path => \"/news/5/edit\", :method => :post }\n    end\n\n    it \"routes to #add_comment\" do\n      route_for(:controller => \"news\", :action => \"add_comment\", :id => '5').should == \"/news/add_comment/5\"\n    end\n\n    it \"routes to #destroy_comment\" do\n      route_for(:controller => \"news\", :action => \"destroy_comment\", :id => '5').should == \"/news/destroy_comment/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"news\", :action => \"destroy\", :id => '5').should == { :path => \"/news/5/destroy\", :method => :post }\n    end\n\n    it \"routes to #preview\" do\n      route_for(:controller => \"news\", :action => \"preview\", :id => '5').should == \"/news/preview/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/notifications_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe NotificationsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"notifications\", :action => \"index\", :id => '5').should == \"/notifications/index/5\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"notifications\", :action => \"show\", :id => '5').should == \"/notifications/show/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"notifications\", :action => \"new\", :id => '5').should == \"/notifications/new/5\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"notifications\", :action => \"edit\", :id => '5').should == \"/notifications/edit/5\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"notifications\", :action => \"create\", :id => '5').should == \"/notifications/create/5\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"notifications\", :action => \"update\", :id => '5').should == \"/notifications/update/5\"\n    end\n\n    it \"routes to #hide\" do\n      route_for(:controller => \"notifications\", :action => \"hide\", :id => '5').should == \"/notifications/hide/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"notifications\", :action => \"destroy\", :id => '5').should == \"/notifications/destroy/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/projects_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe ProjectsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"projects\", :action => \"index\").should == \"/projects\"\n    end\n\n    it \"routes to #index_latest\" do\n      route_for(:controller => \"projects\", :action => \"index_latest\").should == \"/projects/index_latest\"\n    end\n\n    it \"routes to #index_active\" do\n      route_for(:controller => \"projects\", :action => \"index_active\").should == \"/projects/index_active\"\n    end\n\n    it \"routes to #map\" do\n      route_for(:controller => \"projects\", :action => \"map\", :id => '5').should == \"/projects/5/map\"\n    end\n\n    it \"routes to #add\" do\n      route_for(:controller => \"projects\", :action => \"add\").should == \"/projects/new\"\n      route_for(:controller => \"projects\", :action => \"add\").should == { :path => \"/projects/new\", :method => :post }\n      params_from(:post, \"/projects\").should == { :controller => \"projects\", :action => \"add\" }\n    end\n\n    it \"routes to #copy\" do\n      route_for(:controller => \"projects\", :action => \"copy\", :id => '5').should == \"/projects/copy/5\"\n    end\n\n    it \"routes to #reset_invitation_token\" do\n      route_for(:controller => \"projects\", :action => \"reset_invitation_token\", :id => '5').should == \"/projects/reset_invitation_token/5\"\n    end\n\n    it \"routes to #join\" do\n      route_for(:controller => \"projects\", :action => \"join\", :id => '5').should == \"/projects/5/join\"\n    end\n\n    it \"routes to #overview\" do\n      route_for(:controller => \"projects\", :action => \"overview\", :id => '5').should == \"/projects/5\"\n      params_from(:get, \"/projects/5/show\").should == { :controller => \"projects\", :action => \"overview\", :id => '5' }\n      params_from(:get, \"/projects/5/overview\").should == { :controller => \"projects\", :action => \"overview\", :id => '5' }\n    end\n\n    it \"routes to #hourly_types\" do\n      route_for(:controller => \"projects\", :action => \"hourly_types\", :id => '5').should == \"/projects/5/hourly_types\"\n    end\n\n    it \"routes to #community_members\" do\n      route_for(:controller => \"projects\", :action => \"community_members\", :id => '5').should == \"/projects/5/community_members\"\n    end\n\n    it \"routes to #community_members_array\" do\n      route_for(:controller => \"projects\", :action => \"community_members_array\", :id => '5').should == \"/projects/5/community_members_array\"\n    end\n\n    it \"routes to #issue_search\" do\n      route_for(:controller => \"projects\", :action => \"issue_search\", :id => '5').should == \"/projects/5/issue_search\"\n    end\n\n    it \"routes to #all_tags\" do\n      route_for(:controller => \"projects\", :action => \"all_tags\", :id => '5').should == \"/projects/5/all_tags\"\n    end\n\n    it \"routes to #dashboard\" do\n      route_for(:controller => \"projects\", :action => \"dashboard\", :id => '5').should == \"/projects/5/dashboard\"\n      route_for(:controller => \"projects\", :action => \"dashboard\", :show_issue_id => '5').should == \"/issues/5\"\n    end\n\n    it \"routes to #dashdata\" do\n      route_for(:controller => \"projects\", :action => \"dashdata\", :id => '5').should == \"/projects/5/dashdata\"\n    end\n\n    it \"routes to #new_dashdata\" do\n      route_for(:controller => \"projects\", :action => \"new_dashdata\", :id => '5').should == \"/projects/5/new_dashdata\"\n    end\n\n    it \"routes to #update_scale\" do\n      route_for(:controller => \"projects\", :action => \"update_scale\").should == \"/projects/update_scale\"\n    end\n\n    it \"routes to #mypris\" do\n      route_for(:controller => \"projects\", :action => \"mypris\", :id => '5').should == \"/projects/5/mypris\"\n    end\n\n    it \"routes to #settings\" do\n      route_for(:controller => \"projects\", :action => \"settings\", :id => '5').should == \"/projects/5/settings\"\n      route_for(:controller => \"projects\", :action => \"settings\", :id => '5', :tab => '4').should == \"/projects/5/settings/4\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"projects\", :action => \"edit\", :id => '5').should == { :path => \"/projects/5/edit\", :method => :post }\n    end\n\n    it \"routes to #modules\" do\n      route_for(:controller => \"projects\", :action => \"modules\", :id => '5').should == \"/projects/modules/5\"\n    end\n\n    it \"routes to #archive\" do\n      route_for(:controller => \"projects\", :action => \"archive\", :id => '5').should == { :path => \"/projects/5/archive\", :method => :post }\n    end\n\n    it \"routes to #unarchive\" do\n      route_for(:controller => \"projects\", :action => \"unarchive\", :id => '5').should == { :path => \"/projects/5/unarchive\", :method => :post }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"projects\", :action => \"destroy\", :id => '5').should == \"/projects/5/destroy\"\n      route_for(:controller => \"projects\", :action => \"destroy\", :id => '5').should == { :path => \"/projects/5/destroy\", :method => :post }\n    end\n\n    it \"routes to #move\" do\n      route_for(:controller => \"projects\", :action => \"move\", :id => '5').should == \"/projects/move/5\"\n    end\n\n    it \"routes to #add_file\" do\n      route_for(:controller => \"projects\", :action => \"add_file\", :id => '5').should == \"/projects/5/files/new\"\n      route_for(:controller => \"projects\", :action => \"add_file\", :id => '5').should == { :path => \"/projects/5/files/new\", :method => :post }\n    end\n\n    it \"routes to #list_files\" do\n      route_for(:controller => \"projects\", :action => \"list_files\", :id => '5').should == \"/projects/5/files\"\n    end\n\n    it \"routes to #team\" do\n      route_for(:controller => \"projects\", :action => \"team\", :id => '5').should == \"/projects/5/team\"\n    end\n\n    it \"routes to #credits\" do\n      route_for(:controller => \"projects\", :action => \"credits\", :id => '5').should == \"/projects/5/credits\"\n    end\n\n    it \"routes to #activity\" do\n      route_for(:controller => \"projects\", :action => \"activity\", :id => '5').should == \"/projects/5/activity\"\n      route_for(:controller => \"projects\", :action => \"activity\", :id => nil).should == \"/activity\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/queries_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe QueriesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"queries\", :action => \"index\", :id => '5').should == \"/queries/index/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"queries\", :action => \"new\", :id => '5').should == \"/queries/new/5\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"queries\", :action => \"edit\", :id => '5').should == \"/queries/edit/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"queries\", :action => \"destroy\", :id => '5').should == \"/queries/destroy/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/quotes_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe QuotesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"quotes\", :action => \"index\").should == \"/quotes\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"quotes\", :action => \"show\", :id => '5').should == \"/quotes/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"quotes\", :action => \"new\").should == \"/quotes/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"quotes\", :action => \"edit\", :id => '5').should == \"/quotes/5/edit\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"quotes\", :action => \"create\").should == { :path => \"/quotes\", :method => :post }\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"quotes\", :action => \"update\", :id => '5').should == { :path => \"/quotes/5\", :method => :put }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"quotes\", :action => \"destroy\", :id => '5').should == { :path => \"/quotes/5\", :method => :delete }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/recurly_notifications_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe RecurlyNotificationsController do\n\n  describe \"routing\" do\n\n    it \"routes to #listen\" do\n      route_for(:controller => \"recurly_notifications\", :action => \"listen\").should == { :path => \"/recurly_notifications/listen\", :method => :post }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/reports_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe ReportsController do\n\n  describe \"routing\" do\n\n    it \"routes to #issue_report\" do\n      route_for(:controller => \"reports\", :action => \"issue_report\", :id => '5').should == \"projects/5/issues/report\"\n      route_for(:controller => \"reports\", :action => \"issue_report\", :id => '5', :detail => 'stuff').should == \"projects/5/issues/report/stuff\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/reputations_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe ReputationsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"reputations\", :action => \"index\").should == \"/reputations\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"reputations\", :action => \"show\", :id => '5').should == \"/reputations/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"reputations\", :action => \"new\").should == \"/reputations/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"reputations\", :action => \"edit\", :id => '5').should == \"/reputations/5/edit\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"reputations\", :action => \"create\").should == { :path => \"/reputations\", :method => :post }\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"reputations\", :action => \"update\", :id => '5').should == { :path => \"/reputations/5\", :method => :put }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"reputations\", :action => \"destroy\", :id => '5').should == { :path => \"/reputations/5\", :method => :delete }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/retro_ratings_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe RetroRatingsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"retro_ratings\", :action => \"index\", :id => '5').should == \"/retro_ratings/index/5\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"retro_ratings\", :action => \"show\", :id => '5').should == \"/retro_ratings/show/5\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"retro_ratings\", :action => \"new\", :id => '5').should == \"/retro_ratings/new/5\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"retro_ratings\", :action => \"edit\", :id => '5').should == \"/retro_ratings/edit/5\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"retro_ratings\", :action => \"create\", :id => '5').should == \"/retro_ratings/create/5\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"retro_ratings\", :action => \"update\", :id => '5').should == \"/retro_ratings/update/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"retro_ratings\", :action => \"destroy\", :id => '5').should == \"/retro_ratings/destroy/5\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/retros_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe RetrosController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"retros\", :action => \"index\", :project_id => '5').should == \"/projects/5/retros\"\n    end\n\n    it \"routes to #index_json\" do\n      route_for(:controller => \"retros\", :action => \"index_json\", :project_id => '5').should == \"/projects/5/retros/index_json\"\n    end\n\n    it \"routes to #dashdata\" do\n      route_for(:controller => \"retros\", :action => \"dashdata\", :project_id => '5', :id => '4').should == \"/projects/5/retros/4/dashdata\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"retros\", :action => \"show\", :project_id => '5', :id => '4').should == \"/projects/5/retros/4/show\"\n      params_from(:get, \"/projects/5/retros/4\").should == { :controller => \"retros\", :action => \"show\", :id => '4', :project_id => '5' }\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"retros\", :action => \"new\", :project_id => '5').should == \"/projects/5/retros/new\"\n      params_from(:post, \"/projects/5/retros\").should == { :controller => \"retros\", :action => \"new\", :project_id => '5' }\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"retros\", :action => \"edit\", :project_id => '5', :id => '4').should == \"/projects/5/retros/4/edit\"\n      route_for(:controller => \"retros\", :action => \"edit\", :project_id => '5', :id => '4').should == { :path => \"/projects/5/retros/4/edit\", :method => :post }\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"retros\", :action => \"create\", :id => '5').should == \"/retros/create/5\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"retros\", :action => \"update\", :id => '5').should == \"/retros/update/5\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"retros\", :action => \"destroy\", :id => '5').should == \"/retros/destroy/5\"\n      route_for(:controller => \"retros\", :action => \"destroy\", :project_id => '5', :id => '4').should == { :path => \"/projects/5/retros/4/destroy\", :method => :post }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/roles_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe RolesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"roles\", :action => \"index\").should == \"/roles\"\n    end\n\n    it \"routes to #list\" do\n      route_for(:controller => \"roles\", :action => \"list\").should == \"/roles/list\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"roles\", :action => \"new\").should == \"/roles/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"roles\", :action => \"edit\", :id => '4').should == \"/roles/edit/4\"\n      route_for(:controller => \"roles\", :action => \"edit\", :id => '4').should == { :path => \"/roles/edit/4\", :method => :post }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"roles\", :action => \"destroy\", :id => '4').should == { :path => \"/roles/destroy/4\", :method => :post }\n    end\n\n    it \"routes to #report\" do\n      route_for(:controller => \"roles\", :action => \"report\", :id => '4').should == { :path => \"/roles/report/4\", :method => :post }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/search_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe SearchController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"search\", :action => \"index\").should == \"/search\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/settings_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe SettingsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"settings\", :action => \"index\").should == \"/settings\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"settings\", :action => \"edit\", :id => '5').should == \"/settings/edit/5\"\n      route_for(:controller => \"settings\", :action => \"edit\", :id => '5').should == { :path => \"/settings/edit/5\", :method => :post }\n    end\n\n    it \"routes to #plugin\" do\n      route_for(:controller => \"settings\", :action => \"plugin\", :id => '5').should == \"/settings/plugin/5\"\n      route_for(:controller => \"settings\", :action => \"plugin\", :id => '5').should == { :path => \"/settings/plugin/5\", :method => :post }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/shares_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe SharesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"shares\", :action => \"index\").should == \"/shares\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"shares\", :action => \"show\", :id => '4').should == \"/shares/show/4\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"shares\", :action => \"new\").should == \"/shares/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"shares\", :action => \"edit\", :id => '4').should == \"/shares/edit/4\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"shares\", :action => \"create\").should == \"/shares/create\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"shares\", :action => \"update\", :id => '4').should == \"/shares/update/4\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"shares\", :action => \"destroy\", :id => '4').should == \"/shares/destroy/4\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/todos_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe TodosController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"todos\", :action => \"index\").should == \"/todos\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"todos\", :action => \"show\", :id => '4').should == \"/todos/show/4\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"todos\", :action => \"new\").should == \"/todos/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"todos\", :action => \"edit\", :id => '4').should == \"/todos/edit/4\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"todos\", :action => \"create\").should == \"/todos/create\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"todos\", :action => \"update\", :id => '4').should == \"/todos/update/4\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"todos\", :action => \"destroy\", :id => '4').should == \"/todos/destroy/4\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/trackers_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe TrackersController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"trackers\", :action => \"index\").should == \"/trackers\"\n    end\n\n    it \"routes to #list\" do\n      route_for(:controller => \"trackers\", :action => \"list\", :id => '4').should == \"/trackers/list/4\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"trackers\", :action => \"new\").should == \"/trackers/new\"\n      route_for(:controller => \"trackers\", :action => \"new\").should == { :path => \"/trackers/new\", :method => :post }\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"trackers\", :action => \"edit\", :id => '4').should == \"/trackers/edit/4\"\n      route_for(:controller => \"trackers\", :action => \"edit\", :id => '4').should == { :path => \"/trackers/edit/4\", :method => :post }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"trackers\", :action => \"destroy\", :id => '4').should == \"/trackers/destroy/4\"\n      route_for(:controller => \"trackers\", :action => \"destroy\", :id => '4').should == { :path => \"/trackers/destroy/4\", :method => :post }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/users_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe UsersController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"users\", :action => \"index\").should == \"/users\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"users\", :action => \"show\", :id => '4').should == \"/users/4\"\n    end\n\n    it \"routes to #add\" do\n      route_for(:controller => \"users\", :action => \"add\").should == { :path => \"/users/new\", :method => :post }\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"users\", :action => \"edit\", :id => '4', :tab => 'stuff').should == \"/users/4/edit/stuff\"\n      route_for(:controller => \"users\", :action => \"edit\", :id => '4').should == { :path => \"/users/4/edit\", :method => :post }\n    end\n\n    it \"routes to #edit_membership\" do\n      route_for(:controller => \"users\", :action => \"edit_membership\", :id => '4').should == { :path => \"/users/4/memberships\", :method => :post }\n      route_for(:controller => \"users\", :action => \"edit_membership\", :id => '4', :membership_id => '5').should == { :path => \"/users/4/memberships/5\", :method => :post }\n    end\n\n    it \"routes to #destroy_membership\" do\n      route_for(:controller => \"users\", :action => \"destroy_membership\", :id => '4', :membership_id => '5').should == { :path => \"/users/4/memberships/5/destroy\", :method => :post }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/votes_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe VotesController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"votes\", :action => \"index\").should == \"/votes\"\n    end\n\n    it \"routes to #show\" do\n      route_for(:controller => \"votes\", :action => \"show\", :id => '4').should == \"/votes/show/4\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"votes\", :action => \"new\").should == \"/votes/new\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"votes\", :action => \"edit\", :id => '4').should == \"/votes/edit/4\"\n    end\n\n    it \"routes to #create\" do\n      route_for(:controller => \"votes\", :action => \"create\").should == \"/votes/create\"\n    end\n\n    it \"routes to #update\" do\n      route_for(:controller => \"votes\", :action => \"update\", :id => '4').should == \"/votes/update/4\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"votes\", :action => \"destroy\", :id => '4').should == \"/votes/destroy/4\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/watchers_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe WatchersController do\n\n  describe \"routing\" do\n\n    it \"routes to #watch\" do\n      route_for(:controller => \"watchers\", :action => \"watch\", :id => '4').should == \"/watchers/watch/4\"\n    end\n\n    it \"routes to #unwatch\" do\n      route_for(:controller => \"watchers\", :action => \"unwatch\", :id => '4').should == \"/watchers/unwatch/4\"\n    end\n\n    it \"routes to #new\" do\n      route_for(:controller => \"watchers\", :action => \"new\").should == \"/watchers/new\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"watchers\", :action => \"destroy\", :id => '4').should == \"/watchers/destroy/4\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/welcome_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe WelcomeController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"welcome\", :action => \"index\").should == \"/welcome\"\n    end\n\n    it \"routes to #robots\" do\n      route_for(:controller => \"welcome\", :action => \"robots\").should == \"/welcome/robots\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/wiki_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe WikiController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"wiki\", :action => \"index\", :id => '5', :page => 'stuff').should == \"projects/5/wiki/stuff\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"wiki\", :action => \"edit\", :id => '5', :page => 'stuff').should == \"/projects/5/wiki/stuff/edit\"\n      route_for(:controller => \"wiki\", :action => \"edit\", :id => '5', :page => 'stuff').should == { :path => \"/projects/5/wiki/stuff/edit\", :method => :post }\n    end\n\n    it \"routes to #rename\" do\n      route_for(:controller => \"wiki\", :action => \"rename\", :id => '5', :page => 'stuff').should == \"/projects/5/wiki/stuff/rename\"\n      route_for(:controller => \"wiki\", :action => \"rename\", :id => '5', :page => 'stuff').should == { :path => \"/projects/5/wiki/stuff/rename\", :method => :post }\n    end\n\n    it \"routes to #protect\" do\n      route_for(:controller => \"wiki\", :action => \"protect\", :id => '5', :page => 'stuff').should == { :path => \"/projects/5/wiki/stuff/protect\", :method => :post }\n    end\n\n    it \"routes to #history\" do\n      route_for(:controller => \"wiki\", :action => \"history\", :id => '5', :page => 'stuff').should == \"/projects/5/wiki/stuff/history\"\n    end\n\n    it \"routes to #diff\" do\n      route_for(:controller => \"wiki\", :action => \"diff\", :id => '5', :page => 'stuff', :version => '2', :version_from => '3').should == \"/projects/5/wiki/stuff/diff/2/vs/3\"\n    end\n\n    it \"routes to #annotate\" do\n      route_for(:controller => \"wiki\", :action => \"annotate\", :id => '5', :page => 'stuff', :version => '2').should == \"/projects/5/wiki/stuff/annotate/2\"\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"wiki\", :action => \"destroy\", :id => '5', :page => 'stuff').should == { :path => \"/projects/5/wiki/stuff/destroy\", :method => :post }\n    end\n\n    it \"routes to #special\" do\n      route_for(:controller => \"wiki\", :action => \"special\", :id => '5', :page => 'page_index').should == \"/projects/5/wiki/page_index\"\n      route_for(:controller => \"wiki\", :action => \"special\", :id => '5', :page => 'date_index').should == \"/projects/5/wiki/date_index\"\n      route_for(:controller => \"wiki\", :action => \"special\", :id => '5', :page => 'export').should == \"/projects/5/wiki/export\"\n    end\n\n    it \"routes to #preview\" do\n      route_for(:controller => \"wiki\", :action => \"preview\", :id => '5', :page => 'stuff').should == { :path => \"/projects/5/wiki/stuff/preview\", :method => :post }\n    end\n\n    it \"routes to #add_attachment\" do\n      route_for(:controller => \"wiki\", :action => \"add_attachment\", :id => '5', :page => 'stuff').should == \"/wiki/5/stuff/add_attachment\"\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/wikis_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe WikisController do\n\n  describe \"routing\" do\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"wikis\", :action => \"edit\", :id => '5').should == { :path => \"/projects/5/wiki\", :method => :post }\n    end\n\n    it \"routes to #destroy\" do\n      route_for(:controller => \"wikis\", :action => \"destroy\", :id => '5').should == \"/projects/5/wiki/destroy\"\n      route_for(:controller => \"wikis\", :action => \"destroy\", :id => '5').should == { :path => \"/projects/5/wiki/destroy\", :method => :post }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/routing/workflows_routing_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe WorkflowsController do\n\n  describe \"routing\" do\n\n    it \"routes to #index\" do\n      route_for(:controller => \"workflows\", :action => \"index\").should == \"/workflows\"\n    end\n\n    it \"routes to #edit\" do\n      route_for(:controller => \"workflows\", :action => \"edit\", :id => '5').should == \"/workflows/edit/5\"\n      route_for(:controller => \"workflows\", :action => \"edit\", :id => '5').should == { :path => \"/workflows/edit/5\", :method => :post }\n    end\n\n    it \"routes to #copy\" do\n      route_for(:controller => \"workflows\", :action => \"copy\", :id => '5').should == \"/workflows/copy/5\"\n      route_for(:controller => \"workflows\", :action => \"copy\", :id => '5').should == { :path => \"/workflows/copy/5\", :method => :post }\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "spec/spec.opts",
    "content": "--colour\n--format profile\n--loadby mtime\n--reverse\n"
  },
  {
    "path": "spec/spec_helper.rb",
    "content": "require 'rubygems'\nrequire 'spork'\n\nSpork.prefork do\n  ENV[\"RAILS_ENV\"] ||= 'test'\n  require File.expand_path(File.join(File.dirname(__FILE__),'..','config','environment'))\n  require 'spec/autorun'\n  require 'spec/rails'\n  require 'factory_girl'\n\n  require File.dirname(__FILE__) + \"/factories\"\n\n  Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}\n\n  Spec::Runner.configure do |config|\n    # If you're not using ActiveRecord you should remove these\n    # lines, delete config/database.yml and disable :active_record\n    # in your config/boot.rb\n    config.use_transactional_fixtures = true\n    config.use_instantiated_fixtures  = false\n    config.fixture_path = RAILS_ROOT + '/spec/fixtures/'\n\n    config.before :suite do\n      FakeWeb.allow_net_connect = false\n      load File.dirname(__FILE__) + '/../db/seeds.rb'\n    end\n\n    config.after :suite do\n      FakeWeb.allow_net_connect = true\n    end\n  end\n\n  def login\n    @user = Factory.create(:user)\n    User.stub(:current).and_return @user\n  end\nend\n\nSpork.each_run do\n\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/.rspec",
    "content": "--colour\n--backtrace\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/CHANGELOG",
    "content": "== 2010-02-17\n* Converted the plugin to be compatible with Rails3\n\n== 2009-12-02\n\n* PostgreSQL is now supported (via morgoth)\n\n== 2008-07-17\n\n* Can now use a named_scope to find tags!\n\n== 2008-06-23\n\n* Can now find related objects of another class (tristanzdunn)\n* Removed extraneous down migration cruft (azabaj)\n\n== 2008-06-09\n\n * Added support for Single Table Inheritance\n * Adding gemspec and rails/init.rb for gemified plugin\n\n== 2007-12-12\n\n * Added ability to use dynamic tag contexts\n * Fixed missing migration generator"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/Gemfile",
    "content": "source :gemcutter\n\n# Rails 3.0\ngem 'rails',        '3.0.0.beta3'\ngem 'rspec',        '2.0.0.beta.8'\ngem 'sqlite3-ruby', :require => 'sqlite3'\ngem 'mysql'\ngem 'pg'\ngem 'jeweler'\ngem 'rcov'"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/MIT-LICENSE",
    "content": "Copyright (c) 2007 Michael Bleigh and Intridea Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/README.rdoc",
    "content": "= ActsAsTaggableOn\n\nThis plugin was originally based on Acts as Taggable on Steroids by Jonathan Viney.\nIt has evolved substantially since that point, but all credit goes to him for the\ninitial tagging functionality that so many people have used.\n\nFor instance, in a social network, a user might have tags that are called skills,\ninterests, sports, and more. There is no real way to differentiate between tags and\nso an implementation of this type is not possible with acts as taggable on steroids.\n\nEnter Acts as Taggable On. Rather than tying functionality to a specific keyword\n(namely \"tags\"), acts as taggable on allows you to specify an arbitrary number of\ntag \"contexts\" that can be used locally or in combination in the same way steroids\nwas used.\n\n== Installation\n\n=== Rails 2.3.x\n\nActs As Taggable On is tested to work in Rails 2.3.5. \n\n==== Plugin\n\nActs As Taggable On is available both as a gem and as a traditional plugin. For the\ntraditional plugin you can install like so:\n\n  script/plugin install git://github.com/mbleigh/acts-as-taggable-on.git\n\nActs As Taggable On is also available as a gem plugin using Rails 2.1's gem dependencies.\nTo install the gem, add this to your config/environment.rb:\n  \n  config.gem \"acts-as-taggable-on\", :source => \"http://gemcutter.org\", :version => '2.0.0.rc1'\n  \nAfter that, you can run \"rake gems:install\" to install the gem if you don't already have it.\n\n==== Post Installation\n\n1. script/generate acts_as_taggable_on_migration\n2. rake db:migrate\n\n=== Rails 3.0\n\nActs As Taggable On is now useable in Rails 3.0, thanks to the excellent work of Szymon Nowak\nand Jelle Vandebeeck.\n\nTo use it, add it to your Gemfile:\n  \n  gem 'acts-as-taggable-on'\n\n==== Post Installation\n\n1. rails generate acts_as_taggable_on:migration\n2. rake db:migrate\n\n== Testing\n\nActs As Taggable On uses RSpec for its test coverage. Inside the plugin\ndirectory, you can run the specs for RoR 3.0.0 with:\n\n  rake spec\n\nIf you want to test the plugin for Rails 2.3.x, use:\n\n  rake rails2.3:spec\n\nIf you already have RSpec on your application, the specs will run while using:\n\nrake spec:plugins\n\n\n== Usage\n\n    class User < ActiveRecord::Base\n      # Alias for <tt>acts_as_taggable_on :tags</tt>:\n      acts_as_taggable\n      acts_as_taggable_on :skills, :interests\n    end\n\n    @user = User.new(:name => \"Bobby\")\n    @user.tag_list = \"awesome, slick, hefty\"      # this should be familiar\n    @user.skill_list = \"joking, clowning, boxing\" # but you can do it for any context!\n    @user.skill_list                              # => [\"joking\",\"clowning\",\"boxing\"] as TagList\n    @user.save\n\n    @user.tags # => [<Tag name:\"awesome\">,<Tag name:\"slick\">,<Tag name:\"hefty\">]\n    @user.skills # => [<Tag name:\"joking\">,<Tag name:\"clowning\">,<Tag name:\"boxing\">]\n\n    @frankie = User.create(:name => \"Frankie\", :skill_list => \"joking, flying, eating\")\n    User.skill_counts # => [<Tag name=\"joking\" count=2>,<Tag name=\"clowning\" count=1>...]\n    @frankie.skill_counts\n\n=== Finding Tagged Objects\n\nActs As Taggable On utilizes named_scopes to create an association for tags.\nThis way you can mix and match to filter down your results, and it also improves\ncompatibility with the will_paginate gem:\n\n    class User < ActiveRecord::Base\n      acts_as_taggable_on :tags\n      named_scope :by_join_date, :order => \"created_at DESC\"\n    end\n\n    User.tagged_with(\"awesome\").by_date\n    User.tagged_with(\"awesome\").by_date.paginate(:page => params[:page], :per_page => 20)\n\n    # Find a user with matching all tags, not just one\n    User.tagged_with([\"awesome\", \"cool\"], :match_all => :true)\n    \n    # Find a user with any of the tags:\n    User.tagged_with([\"awesome\", \"cool\"], :any => true)\n\n=== Relationships\n\nYou can find objects of the same type based on similar tags on certain contexts.\nAlso, objects will be returned in descending order based on the total number of \nmatched tags.\n\n    @bobby = User.find_by_name(\"Bobby\")\n    @bobby.skill_list # => [\"jogging\", \"diving\"]\n\n    @frankie = User.find_by_name(\"Frankie\")\n    @frankie.skill_list # => [\"hacking\"]\n\n    @tom = User.find_by_name(\"Tom\")\n    @tom.skill_list # => [\"hacking\", \"jogging\", \"diving\"]\n\n    @tom.find_related_skills # => [<User name=\"Bobby\">,<User name=\"Frankie\">]\n    @bobby.find_related_skills # => [<User name=\"Tom\">] \n    @frankie.find_related_skills # => [<User name=\"Tom\">] \n\n=== Dynamic Tag Contexts\n\nIn addition to the generated tag contexts in the definition, it is also possible\nto allow for dynamic tag contexts (this could be user generated tag contexts!)\n\n    @user = User.new(:name => \"Bobby\")\n    @user.set_tag_list_on(:customs, \"same, as, tag, list\")\n    @user.tag_list_on(:customs) # => [\"same\",\"as\",\"tag\",\"list\"]\n    @user.save\n    @user.tags_on(:customs) # => [<Tag name='same'>,...]\n    @user.tag_counts_on(:customs)\n    User.tagged_with(\"same\", :on => :customs) # => [@user]\n\n=== Tag Ownership\n\nTags can have owners:\n\n    class User < ActiveRecord::Base\n      acts_as_tagger\n    end\n\n    class Photo < ActiveRecord::Base\n      acts_as_taggable_on :locations\n    end\n\n    @some_user.tag(@some_photo, :with => \"paris, normandy\", :on => :locations)\n    @some_user.owned_taggings\n    @some_user.owned_tags\n    @some_photo.locations_from(@some_user)\n    \n=== Tag cloud calculations\n\nTo construct tag clouds, the frequency of each tag needs to be calculated.\nBecause we specified +acts_as_taggable_on+ on the <tt>User</tt> class, we can\nget a calculation of all the tag counts by using <tt>User.tag_counts_on(:customs)</tt>. But what if we wanted a tag count for\nan single user's posts? To achieve this we call tag_counts on the association:\n\n  User.find(:first).posts.tag_counts_on(:tags)\n\nA helper is included to assist with generating tag clouds.\n\nHere is an example that generates a tag cloud.\n\nHelper:\n\n  module PostsHelper\n    include ActsAsTaggableOn::TagsHelper\n  end\n\nController:\n\n  class PostController < ApplicationController\n    def tag_cloud\n      @tags = Post.tag_counts_on(:tags)\n    end\n  end\n\nView:\n\n  <% tag_cloud(@tags, %w(css1 css2 css3 css4)) do |tag, css_class| %>\n    <%= link_to tag.name, { :action => :tag, :id => tag.name }, :class => css_class %>\n  <% end %>\n\nCSS:\n\n  .css1 { font-size: 1.0em; }\n  .css2 { font-size: 1.2em; }\n  .css3 { font-size: 1.4em; }\n  .css4 { font-size: 1.6em; }\n\n== Contributors\n\n* TomEric (i76) - Maintainer\n* Michael Bleigh - Original Author\n* Szymon Nowak - Rails 3.0 compatibility\n* Jelle Vandebeeck - Rails 3.0 compatibility\n* Brendan Lim - Related Objects\n* Pradeep Elankumaran - Taggers\n* Sinclair Bain - Patch King\n\n=== Patch Contributors\n\n* tristanzdunn - Related objects of other classes\n* azabaj - Fixed migrate down\n* Peter Cooper - named_scope fix\n* slainer68 - STI fix\n* harrylove - migration instructions and fix-ups\n* lawrencepit - cached tag work\n* sobrinho - fixed tag_cloud helper\n\nCopyright (c) 2007-2010 Michael Bleigh (http://mbleigh.com/) and Intridea Inc. (http://intridea.com/), released under the MIT license\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/Rakefile",
    "content": "begin\n  # Rspec 1.3.0\n  require 'spec/rake/spectask'\n\n  desc 'Default: run specs'\n  task :default => :spec\n  Spec::Rake::SpecTask.new do |t|\n    t.spec_files = FileList[\"spec/**/*_spec.rb\"]\n  end\n\n  Spec::Rake::SpecTask.new('rcov') do |t|\n    t.spec_files = FileList[\"spec/**/*_spec.rb\"]\n    t.rcov = true\n    t.rcov_opts = ['--exclude', 'spec']\n  end\n  \nrescue LoadError\n  # Rspec 2.0\n  require 'rspec/core/rake_task'\n\n  desc 'Default: run specs'\n  task :default => :spec  \n  Rspec::Core::RakeTask.new do |t|\n    t.pattern = \"spec/**/*_spec.rb\"\n  end\n  \n  Rspec::Core::RakeTask.new('rcov') do |t|\n    t.pattern = \"spec/**/*_spec.rb\"\n    t.rcov = true\n    t.rcov_opts = ['--exclude', 'spec']\n  end\n\nrescue LoadError\n  puts \"Rspec not available. Install it with: gem install rspec\"  \nend\n\nnamespace 'rails2.3' do\n  task :spec do\n    gemfile = File.join(File.dirname(__FILE__), 'lib', 'acts_as_taggable_on', 'compatibility', 'Gemfile')\n    ENV['BUNDLE_GEMFILE'] = gemfile\n    Rake::Task['spec'].invoke    \n  end\nend\n\nbegin\n  require 'jeweler'\n  Jeweler::Tasks.new do |gemspec|\n    gemspec.name = \"acts-as-taggable-on\"\n    gemspec.summary = \"ActsAsTaggableOn is a tagging plugin for Rails that provides multiple tagging contexts on a single model.\"\n    gemspec.description = \"With ActsAsTaggableOn, you could tag a single model on several contexts, such as skills, interests, and awards. It also provides other advanced functionality.\"\n    gemspec.email = \"michael@intridea.com\"\n    gemspec.homepage = \"http://github.com/mbleigh/acts-as-taggable-on\"\n    gemspec.authors = [\"Michael Bleigh\"]\n    gemspec.files =  FileList[\"[A-Z]*\", \"{generators,lib,spec,rails}/**/*\"] - FileList[\"**/*.log\"]\n  end\n  Jeweler::GemcutterTasks.new\nrescue LoadError\n  puts \"Jeweler not available. Install it with: gem install jeweler\"\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/VERSION",
    "content": "2.0.6\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/acts-as-taggable-on.gemspec",
    "content": "# Generated by jeweler\n# DO NOT EDIT THIS FILE DIRECTLY\n# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command\n# -*- encoding: utf-8 -*-\n\nGem::Specification.new do |s|\n  s.name = %q{acts-as-taggable-on}\n  s.version = \"2.0.6\"\n\n  s.required_rubygems_version = Gem::Requirement.new(\">= 0\") if s.respond_to? :required_rubygems_version=\n  s.authors = [\"Michael Bleigh\"]\n  s.date = %q{2010-10-20}\n  s.description = %q{With ActsAsTaggableOn, you could tag a single model on several contexts, such as skills, interests, and awards. It also provides other advanced functionality.}\n  s.email = %q{michael@intridea.com}\n  s.extra_rdoc_files = [\n    \"README.rdoc\"\n  ]\n  s.files = [\n    \"CHANGELOG\",\n     \"Gemfile\",\n     \"MIT-LICENSE\",\n     \"README.rdoc\",\n     \"Rakefile\",\n     \"VERSION\",\n     \"generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb\",\n     \"generators/acts_as_taggable_on_migration/templates/migration.rb\",\n     \"lib/acts-as-taggable-on.rb\",\n     \"lib/acts_as_taggable_on/acts_as_tagger.rb\",\n     \"lib/acts_as_taggable_on/compatibility/Gemfile\",\n     \"lib/acts_as_taggable_on/compatibility/active_record_backports.rb\",\n     \"lib/acts_as_taggable_on/tag.rb\",\n     \"lib/acts_as_taggable_on/tag_list.rb\",\n     \"lib/acts_as_taggable_on/taggable.rb\",\n     \"lib/acts_as_taggable_on/taggable/cache.rb\",\n     \"lib/acts_as_taggable_on/taggable/collection.rb\",\n     \"lib/acts_as_taggable_on/taggable/core.rb\",\n     \"lib/acts_as_taggable_on/taggable/ownership.rb\",\n     \"lib/acts_as_taggable_on/taggable/related.rb\",\n     \"lib/acts_as_taggable_on/tagging.rb\",\n     \"lib/acts_as_taggable_on/tags_helper.rb\",\n     \"lib/generators/acts_as_taggable_on/migration/migration_generator.rb\",\n     \"lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb\",\n     \"rails/init.rb\",\n     \"spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb\",\n     \"spec/acts_as_taggable_on/acts_as_tagger_spec.rb\",\n     \"spec/acts_as_taggable_on/tag_list_spec.rb\",\n     \"spec/acts_as_taggable_on/tag_spec.rb\",\n     \"spec/acts_as_taggable_on/taggable_spec.rb\",\n     \"spec/acts_as_taggable_on/tagger_spec.rb\",\n     \"spec/acts_as_taggable_on/tagging_spec.rb\",\n     \"spec/acts_as_taggable_on/tags_helper_spec.rb\",\n     \"spec/bm.rb\",\n     \"spec/database.yml.sample\",\n     \"spec/models.rb\",\n     \"spec/schema.rb\",\n     \"spec/spec_helper.rb\"\n  ]\n  s.homepage = %q{http://github.com/mbleigh/acts-as-taggable-on}\n  s.rdoc_options = [\"--charset=UTF-8\"]\n  s.require_paths = [\"lib\"]\n  s.rubygems_version = %q{1.3.7}\n  s.summary = %q{ActsAsTaggableOn is a tagging plugin for Rails that provides multiple tagging contexts on a single model.}\n  s.test_files = [\n    \"spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb\",\n     \"spec/acts_as_taggable_on/acts_as_tagger_spec.rb\",\n     \"spec/acts_as_taggable_on/tag_list_spec.rb\",\n     \"spec/acts_as_taggable_on/tag_spec.rb\",\n     \"spec/acts_as_taggable_on/taggable_spec.rb\",\n     \"spec/acts_as_taggable_on/tagger_spec.rb\",\n     \"spec/acts_as_taggable_on/tagging_spec.rb\",\n     \"spec/acts_as_taggable_on/tags_helper_spec.rb\",\n     \"spec/bm.rb\",\n     \"spec/models.rb\",\n     \"spec/schema.rb\",\n     \"spec/spec_helper.rb\"\n  ]\n\n  if s.respond_to? :specification_version then\n    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION\n    s.specification_version = 3\n\n    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then\n    else\n    end\n  else\n  end\nend\n\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb",
    "content": "class ActsAsTaggableOnMigrationGenerator < Rails::Generator::Base \n  def manifest \n    record do |m| \n      m.migration_template 'migration.rb', 'db/migrate', :migration_file_name => \"acts_as_taggable_on_migration\"\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/generators/acts_as_taggable_on_migration/templates/migration.rb",
    "content": "class ActsAsTaggableOnMigration < ActiveRecord::Migration\n  def self.up\n    create_table :tags do |t|\n      t.column :name, :string\n    end\n    \n    create_table :taggings do |t|\n      t.column :tag_id, :integer\n      t.column :taggable_id, :integer\n      t.column :tagger_id, :integer\n      t.column :tagger_type, :string\n      \n      # You should make sure that the column created is\n      # long enough to store the required class names.\n      t.column :taggable_type, :string\n      t.column :context, :string\n      \n      t.column :created_at, :datetime\n    end\n    \n    add_index :taggings, :tag_id\n    add_index :taggings, [:taggable_id, :taggable_type, :context]\n  end\n  \n  def self.down\n    drop_table :taggings\n    drop_table :tags\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts-as-taggable-on.rb",
    "content": "require \"active_record\"\nrequire \"action_view\"\n\n$LOAD_PATH.unshift(File.dirname(__FILE__))\n\nrequire \"acts_as_taggable_on/compatibility/active_record_backports\" if ActiveRecord::VERSION::MAJOR < 3\n\nrequire \"acts_as_taggable_on/taggable\"\nrequire \"acts_as_taggable_on/taggable/core\"\nrequire \"acts_as_taggable_on/taggable/collection\"\nrequire \"acts_as_taggable_on/taggable/cache\"\nrequire \"acts_as_taggable_on/taggable/ownership\"\nrequire \"acts_as_taggable_on/taggable/related\"\n\nrequire \"acts_as_taggable_on/acts_as_tagger\"\nrequire \"acts_as_taggable_on/tag\"\nrequire \"acts_as_taggable_on/tag_list\"\nrequire \"acts_as_taggable_on/tags_helper\"\nrequire \"acts_as_taggable_on/tagging\"\n\n$LOAD_PATH.shift\n\nif defined?(ActiveRecord::Base)\n  ActiveRecord::Base.extend ActsAsTaggableOn::Taggable\n  ActiveRecord::Base.send :include, ActsAsTaggableOn::Tagger\nend\n\nif defined?(ActionView::Base)\n  ActionView::Base.send :include, ActsAsTaggableOn::TagsHelper\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/acts_as_tagger.rb",
    "content": "module ActsAsTaggableOn\n  module Tagger\n    def self.included(base)\n      base.extend ClassMethods\n    end\n\n    module ClassMethods\n      ##\n      # Make a model a tagger. This allows an instance of a model to claim ownership\n      # of tags.\n      #\n      # Example:\n      #   class User < ActiveRecord::Base\n      #     acts_as_tagger\n      #   end\n      def acts_as_tagger(opts={})\n        class_eval do\n          has_many :owned_taggings, opts.merge(:as => :tagger, :dependent => :destroy,\n                                               :include => :tag, :class_name => \"ActsAsTaggableOn::Tagging\")\n          has_many :owned_tags, :through => :owned_taggings, :source => :tag, :uniq => true, :class_name => \"ActsAsTaggableOn::Tag\"\n        end\n\n        include ActsAsTaggableOn::Tagger::InstanceMethods\n        extend ActsAsTaggableOn::Tagger::SingletonMethods\n      end\n\n      def is_tagger?\n        false\n      end\n    end\n\n    module InstanceMethods\n      ##\n      # Tag a taggable model with tags that are owned by the tagger. \n      #\n      # @param taggable The object that will be tagged\n      # @param [Hash] options An hash with options. Available options are:\n      #               * <tt>:with</tt> - The tags that you want to\n      #               * <tt>:on</tt>   - The context on which you want to tag\n      #\n      # Example:\n      #   @user.tag(@photo, :with => \"paris, normandy\", :on => :locations)\n      def tag(taggable, opts={})\n        opts.reverse_merge!(:force => true)\n\n        return false unless taggable.respond_to?(:is_taggable?) && taggable.is_taggable?\n\n        raise \"You need to specify a tag context using :on\"                unless opts.has_key?(:on)\n        raise \"You need to specify some tags using :with\"                  unless opts.has_key?(:with)\n        raise \"No context :#{opts[:on]} defined in #{taggable.class.to_s}\" unless (opts[:force] || taggable.tag_types.include?(opts[:on]))\n\n        taggable.set_owner_tag_list_on(self, opts[:on].to_s, opts[:with])\n        taggable.save\n      end\n\n      def is_tagger?\n        self.class.is_tagger?\n      end\n    end\n\n    module SingletonMethods\n      def is_tagger?\n        true\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/compatibility/Gemfile",
    "content": "source :gemcutter\n\n# Rails 2.3\ngem 'rails',        '2.3.5'\ngem 'rspec',        '1.3.0', :require => 'spec'\ngem 'sqlite3-ruby', '1.2.5', :require => 'sqlite3'\ngem 'mysql'\ngem 'pg'\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/compatibility/active_record_backports.rb",
    "content": "module ActsAsTaggableOn\n  module ActiveRecord\n    module Backports\n      def self.included(base)\n        base.class_eval do\n          named_scope :where,    lambda { |conditions| { :conditions => conditions } }  \n          named_scope :joins,    lambda { |joins|      { :joins => joins } }\n          named_scope :group,    lambda { |group|      { :group => group } }\n          named_scope :order,    lambda { |order|      { :order => order } }\n          named_scope :select,   lambda { |select|     { :select => select } }\n          named_scope :limit,    lambda { |limit|      { :limit => limit } }\n          named_scope :readonly, lambda { |readonly|   { :readonly => readonly } }\n          \n          def self.to_sql\n            construct_finder_sql({})\n          end\n        end\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tag.rb",
    "content": "module ActsAsTaggableOn\n  class Tag < ::ActiveRecord::Base\n    include ActsAsTaggableOn::ActiveRecord::Backports if ::ActiveRecord::VERSION::MAJOR < 3\n  \n    attr_accessible :name\n\n    ### ASSOCIATIONS:\n\n    has_many :taggings, :dependent => :destroy, :class_name => 'ActsAsTaggableOn::Tagging'\n\n    ### VALIDATIONS:\n\n    validates_presence_of :name\n    validates_uniqueness_of :name\n\n    ### SCOPES:\n    \n    def self.using_postgresql?\n      connection.adapter_name == 'PostgreSQL'\n    end\n\n    def self.named(name)\n      where([\"name #{like_operator} ?\", name])\n    end\n  \n    def self.named_any(list)\n      where(list.map { |tag| sanitize_sql([\"name #{like_operator} ?\", tag.to_s]) }.join(\" OR \"))\n    end\n  \n    def self.named_like(name)\n      where([\"name #{like_operator} ?\", \"%#{name}%\"])\n    end\n\n    def self.named_like_any(list)\n      where(list.map { |tag| sanitize_sql([\"name #{like_operator} ?\", \"%#{tag.to_s}%\"]) }.join(\" OR \"))\n    end\n\n    ### CLASS METHODS:\n\n    def self.find_or_create_with_like_by_name(name)\n      named_like(name).first || create(:name => name)\n    end\n\n    def self.find_or_create_all_with_like_by_name(*list)\n      list = [list].flatten\n\n      return [] if list.empty?\n\n      existing_tags = Tag.named_any(list).all\n      new_tag_names = list.reject do |name| \n                        name = comparable_name(name)\n                        existing_tags.any? { |tag| comparable_name(tag.name) == name }\n                      end\n      created_tags  = new_tag_names.map { |name| Tag.create(:name => name) }\n\n      existing_tags + created_tags\n    end\n\n    ### INSTANCE METHODS:\n\n    def ==(object)\n      super || (object.is_a?(Tag) && name == object.name)\n    end\n\n    def to_s\n      name\n    end\n\n    def count\n      read_attribute(:count).to_i\n    end\n\n    class << self\n      private\n        def like_operator\n          using_postgresql? ? 'ILIKE' : 'LIKE'\n        end\n        \n        def comparable_name(str)\n          RUBY_VERSION >= \"1.9\" ? str.downcase : str.mb_chars.downcase\n        end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tag_list.rb",
    "content": "module ActsAsTaggableOn\n  class TagList < Array\n    cattr_accessor :delimiter\n    self.delimiter = ','\n\n    attr_accessor :owner\n\n    def initialize(*args)\n      add(*args)\n    end\n  \n    ##\n    # Returns a new TagList using the given tag string.\n    #\n    # Example:\n    #   tag_list = TagList.from(\"One , Two,  Three\")\n    #   tag_list # [\"One\", \"Two\", \"Three\"]\n    def self.from(string)\n      glue   = delimiter.ends_with?(\" \") ? delimiter : \"#{delimiter} \"\n      string = string.join(glue) if string.respond_to?(:join)\n\n      new.tap do |tag_list|\n        string = string.to_s.dup\n\n        # Parse the quoted tags\n        string.gsub!(/(\\A|#{delimiter})\\s*\"(.*?)\"\\s*(#{delimiter}\\s*|\\z)/) { tag_list << $2; $3 }\n        string.gsub!(/(\\A|#{delimiter})\\s*'(.*?)'\\s*(#{delimiter}\\s*|\\z)/) { tag_list << $2; $3 }\n\n        tag_list.add(string.split(delimiter))\n      end\n    end\n\n    ##\n    # Add tags to the tag_list. Duplicate or blank tags will be ignored.\n    # Use the <tt>:parse</tt> option to add an unparsed tag string.\n    #\n    # Example:\n    #   tag_list.add(\"Fun\", \"Happy\")\n    #   tag_list.add(\"Fun, Happy\", :parse => true)\n    def add(*names)\n      extract_and_apply_options!(names)\n      concat(names)\n      clean!\n      self\n    end\n\n    ##\n    # Remove specific tags from the tag_list.\n    # Use the <tt>:parse</tt> option to add an unparsed tag string.\n    #\n    # Example:\n    #   tag_list.remove(\"Sad\", \"Lonely\")\n    #   tag_list.remove(\"Sad, Lonely\", :parse => true)\n    def remove(*names)\n      extract_and_apply_options!(names)\n      delete_if { |name| names.include?(name) }\n      self\n    end\n\n    ##\n    # Transform the tag_list into a tag string suitable for edting in a form.\n    # The tags are joined with <tt>TagList.delimiter</tt> and quoted if necessary.\n    #\n    # Example:\n    #   tag_list = TagList.new(\"Round\", \"Square,Cube\")\n    #   tag_list.to_s # 'Round, \"Square,Cube\"'\n    def to_s\n      tags = frozen? ? self.dup : self\n      tags.send(:clean!)\n\n      tags.map do |name|\n        name.include?(delimiter) ? \"\\\"#{name}\\\"\" : name\n      end.join(delimiter.ends_with?(\" \") ? delimiter : \"#{delimiter} \")\n    end\n\n    private\n  \n    # Remove whitespace, duplicates, and blanks.\n    def clean!\n      reject!(&:blank?)\n      map!(&:strip)\n      uniq!\n    end\n\n    def extract_and_apply_options!(args)\n      options = args.last.is_a?(Hash) ? args.pop : {}\n      options.assert_valid_keys :parse\n\n      if options[:parse]\n        args.map! { |a| self.class.from(a) }\n      end\n\n      args.flatten!\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/taggable/cache.rb",
    "content": "module ActsAsTaggableOn::Taggable\n  module Cache\n    def self.included(base)\n      # Skip adding caching capabilities if table not exists or no cache columns exist\n      return unless base.table_exists? && base.tag_types.any? { |context| base.column_names.include?(\"cached_#{context.to_s.singularize}_list\") }\n\n      base.send :include, ActsAsTaggableOn::Taggable::Cache::InstanceMethods\n      base.extend ActsAsTaggableOn::Taggable::Cache::ClassMethods\n      \n      base.class_eval do\n        before_save :save_cached_tag_list        \n      end\n      \n      base.initialize_acts_as_taggable_on_cache\n    end\n    \n    module ClassMethods\n      def initialize_acts_as_taggable_on_cache      \n        tag_types.map(&:to_s).each do |tag_type|\n          class_eval %(\n            def self.caching_#{tag_type.singularize}_list?\n              caching_tag_list_on?(\"#{tag_type}\")\n            end        \n          )\n        end        \n      end\n      \n      def acts_as_taggable_on(*args)\n        super(*args)\n        initialize_acts_as_taggable_on_cache\n      end\n      \n      def caching_tag_list_on?(context)\n        column_names.include?(\"cached_#{context.to_s.singularize}_list\")\n      end\n    end\n    \n    module InstanceMethods      \n      def save_cached_tag_list\n        tag_types.map(&:to_s).each do |tag_type|\n          if self.class.send(\"caching_#{tag_type.singularize}_list?\")\n            if tag_list_cache_set_on(tag_type)\n              list = tag_list_cache_on(tag_type.singularize).to_a.flatten.compact.join(', ')\n              self[\"cached_#{tag_type.singularize}_list\"] = list\n            end\n          end\n        end\n        \n        true\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/taggable/collection.rb",
    "content": "module ActsAsTaggableOn::Taggable\n  module Collection\n    def self.included(base)\n      base.send :include, ActsAsTaggableOn::Taggable::Collection::InstanceMethods\n      base.extend ActsAsTaggableOn::Taggable::Collection::ClassMethods\n      base.initialize_acts_as_taggable_on_collection\n    end\n    \n    module ClassMethods\n      def initialize_acts_as_taggable_on_collection\n        tag_types.map(&:to_s).each do |tag_type|\n          class_eval %(\n            def self.#{tag_type.singularize}_counts(options={})\n              tag_counts_on('#{tag_type}', options)\n            end\n\n            def #{tag_type.singularize}_counts(options = {})\n              tag_counts_on('#{tag_type}', options)\n            end\n\n            def top_#{tag_type}(limit = 10)\n              tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)\n            end\n\n            def self.top_#{tag_type}(limit = 10)\n              tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)\n            end        \n          )\n        end        \n      end\n      \n      def acts_as_taggable_on(*args)\n        super(*args)\n        initialize_acts_as_taggable_on_collection\n      end\n      \n      def tag_counts_on(context, options = {})\n        all_tag_counts(options.merge({:on => context.to_s}))\n      end\n      \n      ##\n      # Calculate the tag counts for all tags.\n      #\n      # @param [Hash] options Options:\n      #                       * :start_at   - Restrict the tags to those created after a certain time\n      #                       * :end_at     - Restrict the tags to those created before a certain time\n      #                       * :conditions - A piece of SQL conditions to add to the query\n      #                       * :limit      - The maximum number of tags to return\n      #                       * :order      - A piece of SQL to order by. Eg 'tags.count desc' or 'taggings.created_at desc'\n      #                       * :at_least   - Exclude tags with a frequency less than the given value\n      #                       * :at_most    - Exclude tags with a frequency greater than the given value\n      #                       * :on         - Scope the find to only include a certain context\n      def all_tag_counts(options = {})\n        options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit, :on, :id\n\n        scope = if ActiveRecord::VERSION::MAJOR >= 3\n                  {}\n                else\n                  scope(:find) || {}           \n                end\n\n        ## Generate conditions:\n        options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions]     \n\n        start_at_conditions = sanitize_sql([\"#{ActsAsTaggableOn::Tagging.table_name}.created_at >= ?\", options.delete(:start_at)]) if options[:start_at]\n        end_at_conditions   = sanitize_sql([\"#{ActsAsTaggableOn::Tagging.table_name}.created_at <= ?\", options.delete(:end_at)])   if options[:end_at]\n        \n        taggable_conditions  = sanitize_sql([\"#{ActsAsTaggableOn::Tagging.table_name}.taggable_type = ?\", base_class.name])\n        taggable_conditions << sanitize_sql([\" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = ?\", options.delete(:id)])  if options[:id]\n        taggable_conditions << sanitize_sql([\" AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?\", options.delete(:on).to_s]) if options[:on]\n        \n        tagging_conditions = [\n          taggable_conditions,\n          scope[:conditions],\n          start_at_conditions,\n          end_at_conditions\n        ].compact.reverse\n        \n        tag_conditions = [\n          options[:conditions]        \n        ].compact.reverse\n        \n        ## Generate joins:\n        taggable_join = \"INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id\"\n        taggable_join << \" AND #{table_name}.#{inheritance_column} = '#{name}'\" unless descends_from_active_record? # Current model is STI descendant, so add type checking to the join condition      \n\n        tagging_joins = [\n          taggable_join,\n          scope[:joins]\n        ].compact\n\n        tag_joins = [\n        ].compact\n\n        [tagging_joins, tag_joins].each(&:reverse!) if ActiveRecord::VERSION::MAJOR < 3\n\n        ## Generate scope:\n        tagging_scope = ActsAsTaggableOn::Tagging.select(\"#{ActsAsTaggableOn::Tagging.table_name}.tag_id, COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) AS tags_count\")\n        tag_scope = ActsAsTaggableOn::Tag.select(\"#{ActsAsTaggableOn::Tag.table_name}.*, #{ActsAsTaggableOn::Tagging.table_name}.tags_count AS count\").order(options[:order]).limit(options[:limit])   \n\n        # Joins and conditions\n        tagging_joins.each      { |join|      tagging_scope = tagging_scope.joins(join)      }        \n        tagging_conditions.each { |condition| tagging_scope = tagging_scope.where(condition) }\n\n        tag_joins.each          { |join|      tag_scope     = tag_scope.joins(join)          }\n        tag_conditions.each     { |condition| tag_scope     = tag_scope.where(condition)     }\n\n        # GROUP BY and HAVING clauses:\n        at_least  = sanitize_sql(['tags_count >= ?', options.delete(:at_least)]) if options[:at_least]\n        at_most   = sanitize_sql(['tags_count <= ?', options.delete(:at_most)]) if options[:at_most]\n        having    = [\"COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) > 0\", at_least, at_most].compact.join(' AND ')    \n\n        group_columns = \"#{ActsAsTaggableOn::Tagging.table_name}.tag_id\"\n\n        if ActiveRecord::VERSION::MAJOR >= 3\n          # Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:\n          scoped_select = \"#{table_name}.#{primary_key}\"\n          tagging_scope = tagging_scope.where(\"#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{select(scoped_select).to_sql})\").\n                                        group(group_columns).\n                                        having(having)\n        else\n          # Having is not available in 2.3.x:\n          group_by  = \"#{group_columns} HAVING COUNT(*) > 0\"\n          group_by << \" AND #{having}\" unless having.blank?\n          tagging_scope = tagging_scope.group(group_by)\n        end\n\n        tag_scope = tag_scope.joins(\"JOIN (#{tagging_scope.to_sql}) AS taggings ON taggings.tag_id = tags.id\")\n        tag_scope\n      end\n    end\n    \n    module InstanceMethods\n      def tag_counts_on(context, options={})\n        self.class.tag_counts_on(context, options.merge(:id => id))\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/taggable/core.rb",
    "content": "module ActsAsTaggableOn::Taggable\n  module Core\n    def self.included(base)\n      base.send :include, ActsAsTaggableOn::Taggable::Core::InstanceMethods\n      base.extend ActsAsTaggableOn::Taggable::Core::ClassMethods\n\n      base.class_eval do\n        attr_writer :custom_contexts\n        after_save :save_tags\n      end\n      \n      base.initialize_acts_as_taggable_on_core\n    end\n    \n    module ClassMethods\n      def initialize_acts_as_taggable_on_core\n        tag_types.map(&:to_s).each do |tags_type|\n          tag_type         = tags_type.to_s.singularize\n          context_taggings = \"#{tag_type}_taggings\".to_sym\n          context_tags     = tags_type.to_sym\n\n          class_eval do\n            has_many context_taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => \"ActsAsTaggableOn::Tagging\",\n                     :conditions => [\"#{ActsAsTaggableOn::Tagging.table_name}.tagger_id IS NULL AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?\", tags_type]\n            has_many context_tags, :through => context_taggings, :source => :tag, :class_name => \"ActsAsTaggableOn::Tag\"\n          end\n\n          class_eval %(\n            def #{tag_type}_list\n              tag_list_on('#{tags_type}')\n            end\n\n            def #{tag_type}_list=(new_tags)\n              set_tag_list_on('#{tags_type}', new_tags)\n            end\n\n            def all_#{tags_type}_list\n              all_tags_list_on('#{tags_type}')\n            end\n          )\n        end        \n      end\n      \n      def acts_as_taggable_on(*args)\n        super(*args)\n        initialize_acts_as_taggable_on_core\n      end\n      \n      # all column names are necessary for PostgreSQL group clause\n      def grouped_column_names_for(object)\n        object.column_names.map { |column| \"#{object.table_name}.#{column}\" }.join(\", \")\n      end\n\n      ##\n      # Return a scope of objects that are tagged with the specified tags.\n      #\n      # @param tags The tags that we want to query for\n      # @param [Hash] options A hash of options to alter you query:\n      #                       * <tt>:exclude</tt> - if set to true, return objects that are *NOT* tagged with the specified tags\n      #                       * <tt>:any</tt> - if set to true, return objects that are tagged with *ANY* of the specified tags\n      #                       * <tt>:match_all</tt> - if set to true, return objects that are *ONLY* tagged with the specified tags\n      #\n      # Example:\n      #   User.tagged_with(\"awesome\", \"cool\")                     # Users that are tagged with awesome and cool\n      #   User.tagged_with(\"awesome\", \"cool\", :exclude => true)   # Users that are not tagged with awesome or cool\n      #   User.tagged_with(\"awesome\", \"cool\", :any => true)       # Users that are tagged with awesome or cool\n      #   User.tagged_with(\"awesome\", \"cool\", :match_all => true) # Users that are tagged with just awesome and cool\n      def tagged_with(tags, options = {})\n        tag_list = ActsAsTaggableOn::TagList.from(tags)\n\n        return self if tag_list.empty?\n\n        joins = []\n        conditions = []\n\n        context = options.delete(:on)\n\n        if options.delete(:exclude)\n          tags_conditions = tag_list.map { |t| sanitize_sql([\"#{ActsAsTaggableOn::Tag.table_name}.name LIKE ?\", t]) }.join(\" OR \")\n          conditions << \"#{table_name}.#{primary_key} NOT IN (SELECT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id FROM #{ActsAsTaggableOn::Tagging.table_name} JOIN #{ActsAsTaggableOn::Tag.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})\"\n\n        elsif options.delete(:any)\n          tags_conditions = tag_list.map { |t| sanitize_sql([\"#{ActsAsTaggableOn::Tag.table_name}.name LIKE ?\", t]) }.join(\" OR \")\n          conditions << \"#{table_name}.#{primary_key} IN (SELECT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id FROM #{ActsAsTaggableOn::Tagging.table_name} JOIN #{ActsAsTaggableOn::Tag.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})\"\n\n        else\n          tags = ActsAsTaggableOn::Tag.named_any(tag_list)\n          return scoped(:conditions => \"1 = 0\") unless tags.length == tag_list.length\n\n          tags.each do |tag|\n            safe_tag = tag.name.gsub(/[^a-zA-Z0-9]/, '')\n            prefix   = \"#{safe_tag}_#{rand(1024)}\"\n\n            taggings_alias = \"#{undecorated_table_name}_taggings_#{prefix}\"\n\n            tagging_join  = \"JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}\" +\n                            \"  ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}\" +\n                            \" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}\" +\n                            \" AND #{taggings_alias}.tag_id = #{tag.id}\"\n            tagging_join << \" AND \" + sanitize_sql([\"#{taggings_alias}.context = ?\", context.to_s]) if context\n\n            joins << tagging_join\n          end\n        end\n\n        taggings_alias, tags_alias = \"#{undecorated_table_name}_taggings_group\", \"#{undecorated_table_name}_tags_group\"\n\n        if options.delete(:match_all)\n          joins << \"LEFT OUTER JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}\" +\n                   \"  ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}\" +\n                   \" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}\"\n\n\n          group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(self) : \"#{table_name}.#{primary_key}\"\n          group = \"#{group_columns} HAVING COUNT(#{taggings_alias}.taggable_id) = #{tags.size}\"\n        end\n\n\n        scoped(:joins      => joins.join(\" \"),\n               :group      => group,\n               :conditions => conditions.join(\" AND \"),\n               :order      => options[:order],\n               :readonly   => false)\n      end\n\n      def is_taggable?\n        true\n      end\n    end    \n    \n    module InstanceMethods\n      # all column names are necessary for PostgreSQL group clause\n      def grouped_column_names_for(object)\n        self.class.grouped_column_names_for(object)\n      end\n\n      def custom_contexts\n        @custom_contexts ||= []\n      end\n\n      def is_taggable?\n        self.class.is_taggable?\n      end\n\n      def add_custom_context(value)\n        custom_contexts << value.to_s unless custom_contexts.include?(value.to_s) or self.class.tag_types.map(&:to_s).include?(value.to_s)\n      end\n\n      def cached_tag_list_on(context)\n        self[\"cached_#{context.to_s.singularize}_list\"]\n      end\n\n      def tag_list_cache_set_on(context)\n        variable_name = \"@#{context.to_s.singularize}_list\"\n        !instance_variable_get(variable_name).nil?\n      end\n\n      def tag_list_cache_on(context)\n        variable_name = \"@#{context.to_s.singularize}_list\"\n        instance_variable_get(variable_name) || instance_variable_set(variable_name, ActsAsTaggableOn::TagList.new(tags_on(context).map(&:name)))\n      end\n\n      def tag_list_on(context)\n        add_custom_context(context)\n        tag_list_cache_on(context)\n      end\n\n      def all_tags_list_on(context)\n        variable_name = \"@all_#{context.to_s.singularize}_list\"\n        return instance_variable_get(variable_name) if instance_variable_get(variable_name)\n\n        instance_variable_set(variable_name, ActsAsTaggableOn::TagList.new(all_tags_on(context).map(&:name)).freeze)\n      end\n\n      ##\n      # Returns all tags of a given context\n      def all_tags_on(context)\n        tag_table_name = ActsAsTaggableOn::Tag.table_name\n        tagging_table_name = ActsAsTaggableOn::Tagging.table_name\n\n        opts  =  [\"#{tagging_table_name}.context = ?\", context.to_s]\n        scope = base_tags.where(opts)\n        \n        if ActsAsTaggableOn::Tag.using_postgresql?\n          group_columns = grouped_column_names_for(ActsAsTaggableOn::Tag)\n          scope = scope.order(\"max(#{tagging_table_name}.created_at)\").group(group_columns)\n        else\n          scope = scope.group(\"#{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key}\")\n        end\n\n        scope.all\n      end\n\n      ##\n      # Returns all tags that are not owned of a given context\n      def tags_on(context)\n        base_tags.where([\"#{ActsAsTaggableOn::Tagging.table_name}.context = ? AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_id IS NULL\", context.to_s]).all\n      end\n\n      def set_tag_list_on(context, new_list)\n        add_custom_context(context)\n\n        variable_name = \"@#{context.to_s.singularize}_list\"\n        instance_variable_set(variable_name, ActsAsTaggableOn::TagList.from(new_list))\n      end\n\n      def tagging_contexts\n        custom_contexts + self.class.tag_types.map(&:to_s)\n      end\n\n      def reload(*args)\n        self.class.tag_types.each do |context|\n          instance_variable_set(\"@#{context.to_s.singularize}_list\", nil)\n          instance_variable_set(\"@all_#{context.to_s.singularize}_list\", nil)\n        end\n      \n        super(*args)\n      end\n\n      def save_tags\n        tagging_contexts.each do |context|\n          next unless tag_list_cache_set_on(context)\n\n          tag_list = tag_list_cache_on(context).uniq\n\n          # Find existing tags or create non-existing tags:\n          tag_list = ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name(tag_list)\n\n          current_tags = tags_on(context)\n          old_tags     = current_tags - tag_list\n          new_tags     = tag_list     - current_tags\n          \n          # Find taggings to remove:\n          old_taggings = taggings.where(:tagger_type => nil, :tagger_id => nil,\n                                        :context => context.to_s, :tag_id => old_tags).all\n\n          if old_taggings.present?\n            # Destroy old taggings:\n            ActsAsTaggableOn::Tagging.destroy_all :id => old_taggings.map(&:id)\n          end\n\n          # Create new taggings:\n          new_tags.each do |tag|\n            taggings.create!(:tag_id => tag.id, :context => context.to_s, :taggable => self)\n          end\n        end\n\n        true\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/taggable/ownership.rb",
    "content": "module ActsAsTaggableOn::Taggable\n  module Ownership\n    def self.included(base)\n      base.send :include, ActsAsTaggableOn::Taggable::Ownership::InstanceMethods\n      base.extend ActsAsTaggableOn::Taggable::Ownership::ClassMethods\n     \n      base.class_eval do\n        after_save :save_owned_tags    \n      end\n      \n      base.initialize_acts_as_taggable_on_ownership\n    end\n    \n    module ClassMethods\n      def acts_as_taggable_on(*args)\n        initialize_acts_as_taggable_on_ownership\n        super(*args)\n      end\n      \n      def initialize_acts_as_taggable_on_ownership      \n        tag_types.map(&:to_s).each do |tag_type|\n          class_eval %(\n            def #{tag_type}_from(owner)\n              owner_tag_list_on(owner, '#{tag_type}')\n            end      \n          )\n        end        \n      end\n    end\n    \n    module InstanceMethods\n      def owner_tags_on(owner, context)\n        if owner.nil?\n          base_tags.where([%(#{ActsAsTaggableOn::Tagging.table_name}.context = ?), context.to_s]).all                    \n        else\n          base_tags.where([%(#{ActsAsTaggableOn::Tagging.table_name}.context = ? AND\n                             #{ActsAsTaggableOn::Tagging.table_name}.tagger_id = ? AND\n                             #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = ?), context.to_s, owner.id, owner.class.to_s]).all          \n        end\n      end\n\n      def cached_owned_tag_list_on(context)\n        variable_name = \"@owned_#{context}_list\"\n        cache = instance_variable_get(variable_name) || instance_variable_set(variable_name, {})\n      end\n      \n      def owner_tag_list_on(owner, context)\n        add_custom_context(context)\n\n        cache = cached_owned_tag_list_on(context)\n        cache.delete_if { |key, value| key.id == owner.id && key.class == owner.class }\n        \n        cache[owner] ||= ActsAsTaggableOn::TagList.new(*owner_tags_on(owner, context).map(&:name))\n      end\n      \n      def set_owner_tag_list_on(owner, context, new_list)\n        add_custom_context(context)\n        \n        cache = cached_owned_tag_list_on(context)\n        cache.delete_if { |key, value| key.id == owner.id && key.class == owner.class }\n\n        cache[owner] = ActsAsTaggableOn::TagList.from(new_list)\n      end\n      \n      def reload(*args)\n        self.class.tag_types.each do |context|\n          instance_variable_set(\"@owned_#{context}_list\", nil)\n        end\n      \n        super(*args)\n      end\n    \n      def save_owned_tags\n        tagging_contexts.each do |context|\n          cached_owned_tag_list_on(context).each do |owner, tag_list|\n            # Find existing tags or create non-existing tags:\n            tag_list = ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name(tag_list.uniq)            \n\n            owned_tags = owner_tags_on(owner, context)              \n            old_tags   = owned_tags - tag_list\n            new_tags   = tag_list   - owned_tags\n          \n            # Find all taggings that belong to the taggable (self), are owned by the owner, \n            # have the correct context, and are removed from the list.\n            old_taggings = ActsAsTaggableOn::Tagging.where(:taggable_id => id, :taggable_type => self.class.base_class.to_s,\n                                                           :tagger_type => owner.class.to_s, :tagger_id => owner.id,\n                                                           :tag_id => old_tags, :context => context).all\n          \n            if old_taggings.present?\n              # Destroy old taggings:\n              ActsAsTaggableOn::Tagging.destroy_all(:id => old_taggings.map(&:id))\n            end\n\n            # Create new taggings:\n            new_tags.each do |tag|\n              taggings.create!(:tag_id => tag.id, :context => context.to_s, :tagger => owner, :taggable => self)\n            end\n          end\n        end\n        \n        true\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/taggable/related.rb",
    "content": "module ActsAsTaggableOn::Taggable\n  module Related\n    def self.included(base)\n      base.send :include, ActsAsTaggableOn::Taggable::Related::InstanceMethods\n      base.extend ActsAsTaggableOn::Taggable::Related::ClassMethods\n      base.initialize_acts_as_taggable_on_related\n    end\n    \n    module ClassMethods\n      def initialize_acts_as_taggable_on_related\n        tag_types.map(&:to_s).each do |tag_type|\n          class_eval %(\n            def find_related_#{tag_type}(options = {})\n              related_tags_for('#{tag_type}', self.class, options)\n            end\n            alias_method :find_related_on_#{tag_type}, :find_related_#{tag_type}\n\n            def find_related_#{tag_type}_for(klass, options = {})\n              related_tags_for('#{tag_type}', klass, options)\n            end\n\n            def find_matching_contexts(search_context, result_context, options = {})\n              matching_contexts_for(search_context.to_s, result_context.to_s, self.class, options)\n            end\n\n            def find_matching_contexts_for(klass, search_context, result_context, options = {})\n              matching_contexts_for(search_context.to_s, result_context.to_s, klass, options)\n            end\n          )\n        end        \n      end\n      \n      def acts_as_taggable_on(*args)\n        super(*args)\n        initialize_acts_as_taggable_on_related\n      end\n    end\n    \n    module InstanceMethods\n      def matching_contexts_for(search_context, result_context, klass, options = {})\n        tags_to_find = tags_on(search_context).collect { |t| t.name }\n\n        exclude_self = \"#{klass.table_name}.id != #{id} AND\" if self.class == klass\n        \n        group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(klass) : \"#{klass.table_name}.#{klass.primary_key}\"\n        \n        klass.scoped({ :select     => \"#{klass.table_name}.*, COUNT(#{ActsAsTaggableOn::Tag.table_name}.id) AS count\",\n                       :from       => \"#{klass.table_name}, #{ActsAsTaggableOn::Tag.table_name}, #{ActsAsTaggableOn::Tagging.table_name}\",\n                       :conditions => [\"#{exclude_self} #{klass.table_name}.id = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id AND #{ActsAsTaggableOn::Tag.table_name}.name IN (?) AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?\", tags_to_find, result_context],\n                       :group      => group_columns,\n                       :order      => \"count DESC\" }.update(options))\n      end\n      \n      def related_tags_for(context, klass, options = {})\n        tags_to_find = tags_on(context).collect { |t| t.name }\n\n        exclude_self = \"#{klass.table_name}.id != #{id} AND\" if self.class == klass\n\ngroup_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(klass) : \"#{klass.table_name}.#{klass.primary_key}\"\n\n        klass.scoped({ :select     => \"#{klass.table_name}.*, COUNT(#{ActsAsTaggableOn::Tag.table_name}.id) AS count\",\n                       :from       => \"#{klass.table_name}, #{ActsAsTaggableOn::Tag.table_name}, #{ActsAsTaggableOn::Tagging.table_name}\",\n                       :conditions => [\"#{exclude_self} #{klass.table_name}.id = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id AND #{ActsAsTaggableOn::Tag.table_name}.name IN (?)\", tags_to_find],\n                       :group      => group_columns,\n                       :order      => \"count DESC\" }.update(options))\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/taggable.rb",
    "content": "module ActsAsTaggableOn\n  module Taggable\n    def taggable?\n      false\n    end\n\n    ##\n    # This is an alias for calling <tt>acts_as_taggable_on :tags</tt>.\n    #\n    # Example:\n    #   class Book < ActiveRecord::Base\n    #     acts_as_taggable\n    #   end\n    def acts_as_taggable\n      acts_as_taggable_on :tags\n    end\n\n    ##\n    # Make a model taggable on specified contexts.\n    #\n    # @param [Array] tag_types An array of taggable contexts\n    #\n    # Example:\n    #   class User < ActiveRecord::Base\n    #     acts_as_taggable_on :languages, :skills\n    #   end\n    def acts_as_taggable_on(*tag_types)\n      tag_types = tag_types.to_a.flatten.compact.map(&:to_sym)\n\n      if taggable?\n        write_inheritable_attribute(:tag_types, (self.tag_types + tag_types).uniq)\n      else\n        write_inheritable_attribute(:tag_types, tag_types)\n        class_inheritable_reader(:tag_types)\n        \n        class_eval do\n          has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => \"ActsAsTaggableOn::Tagging\"\n          has_many :base_tags, :through => :taggings, :source => :tag, :class_name => \"ActsAsTaggableOn::Tag\"\n\n          def self.taggable?\n            true\n          end\n        \n          include ActsAsTaggableOn::Taggable::Core\n          include ActsAsTaggableOn::Taggable::Collection\n          include ActsAsTaggableOn::Taggable::Cache\n          include ActsAsTaggableOn::Taggable::Ownership\n          include ActsAsTaggableOn::Taggable::Related\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tagging.rb",
    "content": "module ActsAsTaggableOn\n  class Tagging < ::ActiveRecord::Base #:nodoc:\n    include ActsAsTaggableOn::ActiveRecord::Backports if ::ActiveRecord::VERSION::MAJOR < 3\n\n    attr_accessible :tag,\n                    :tag_id,\n                    :context,\n                    :taggable,\n                    :taggable_type,\n                    :taggable_id,\n                    :tagger,\n                    :tagger_type,\n                    :tagger_id\n\n    belongs_to :tag, :class_name => 'ActsAsTaggableOn::Tag'\n    belongs_to :taggable, :polymorphic => true\n    belongs_to :tagger,   :polymorphic => true\n    belongs_to :project\n\n    validates_presence_of :context\n    validates_presence_of :tag_id\n\n    validates_uniqueness_of :tag_id, :scope => [ :taggable_type, :taggable_id, :context, :tagger_id, :tagger_type ]\n    \n    def before_save\n      self.project_id = self.taggable.project_id if self.taggable_type == 'Issue'\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/acts_as_taggable_on/tags_helper.rb",
    "content": "module ActsAsTaggableOn\n  module TagsHelper\n    # See the README for an example using tag_cloud.\n    def tag_cloud(tags, classes)\n      tags = tags.all if tags.respond_to?(:all)\n\n      return [] if tags.empty?\n\n      max_count = tags.sort_by(&:count).last.count.to_f\n\n      tags.each do |tag|\n        index = ((tag.count / max_count) * (classes.size - 1)).round\n        yield tag, classes[index]\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/generators/acts_as_taggable_on/migration/migration_generator.rb",
    "content": "require 'rails/generators/migration'\n\nmodule ActsAsTaggableOn\n  class MigrationGenerator < Rails::Generators::Base\n    include Rails::Generators::Migration\n\n    desc \"Generates migration for Tag and Tagging models\"\n\n    def self.orm\n      Rails::Generators.options[:rails][:orm]\n    end\n\n    def self.source_root\n      File.join(File.dirname(__FILE__), 'templates', (orm.to_s unless orm.class.eql?(String)) )\n    end\n\n    def self.orm_has_migration?\n      [:active_record].include? orm\n    end\n\n    def self.next_migration_number(path)\n      Time.now.utc.strftime(\"%Y%m%d%H%M%S\")\n    end\n\n    def create_migration_file\n      if self.class.orm_has_migration?\n        migration_template 'migration.rb', 'db/migrate/acts_as_taggable_on_migration'\n      end\n    end\n  end\nend\n\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb",
    "content": "class ActsAsTaggableOnMigration < ActiveRecord::Migration\n  def self.up\n    create_table :tags do |t|\n      t.string :name\n    end\n\n    create_table :taggings do |t|\n      t.references :tag\n\n      # You should make sure that the column created is\n      # long enough to store the required class names.\n      t.references :taggable, :polymorphic => true\n      t.references :tagger, :polymorphic => true\n\n      t.string :context\n\n      t.datetime :created_at\n    end\n\n    add_index :taggings, :tag_id\n    add_index :taggings, [:taggable_id, :taggable_type, :context]\n  end\n\n  def self.down\n    drop_table :taggings\n    drop_table :tags\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/rails/init.rb",
    "content": "require 'acts-as-taggable-on'"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\ndescribe \"Acts As Taggable On\" do\n  before(:each) do\n    clean_database!\n  end\n\n  it \"should provide a class method 'taggable?' that is false for untaggable models\" do\n    UntaggableModel.should_not be_taggable\n  end\n\n  describe \"Taggable Method Generation\" do\n    before(:each) do\n      clean_database!\n      TaggableModel.write_inheritable_attribute(:tag_types, [])\n      TaggableModel.acts_as_taggable_on(:tags, :languages, :skills, :needs, :offerings)\n      @taggable = TaggableModel.new(:name => \"Bob Jones\")\n    end\n\n    it \"should respond 'true' to taggable?\" do\n      @taggable.class.should be_taggable\n    end\n\n    it \"should create a class attribute for tag types\" do\n      @taggable.class.should respond_to(:tag_types)\n    end\n\n    it \"should create an instance attribute for tag types\" do\n      @taggable.should respond_to(:tag_types)\n    end\n    \n    it \"should have all tag types\" do\n      @taggable.tag_types.should == [:tags, :languages, :skills, :needs, :offerings]\n    end\n\n    it \"should generate an association for each tag type\" do\n      @taggable.should respond_to(:tags, :skills, :languages)\n    end\n\n    it \"should add tagged_with and tag_counts to singleton\" do\n      TaggableModel.should respond_to(:tagged_with, :tag_counts)\n    end\n\n    it \"should generate a tag_list accessor/setter for each tag type\" do\n      @taggable.should respond_to(:tag_list, :skill_list, :language_list)\n      @taggable.should respond_to(:tag_list=, :skill_list=, :language_list=)\n    end\n    \n    it \"should generate a tag_list accessor, that includes owned tags, for each tag type\" do\n      @taggable.should respond_to(:all_tags_list, :all_skills_list, :all_languages_list)\n    end\n  end\n\n  describe \"Single Table Inheritance\" do\n    before do\n      @taggable = TaggableModel.new(:name => \"taggable\")\n      @inherited_same = InheritingTaggableModel.new(:name => \"inherited same\")\n      @inherited_different = AlteredInheritingTaggableModel.new(:name => \"inherited different\")\n    end\n  \n    it \"should pass on tag contexts to STI-inherited models\" do\n      @inherited_same.should respond_to(:tag_list, :skill_list, :language_list)\n      @inherited_different.should respond_to(:tag_list, :skill_list, :language_list)\n    end\n  \n    it \"should have tag contexts added in altered STI models\" do\n      @inherited_different.should respond_to(:part_list)\n    end\n  end\n  \n  describe \"Reloading\" do\n    it \"should save a model instantiated by Model.find\" do\n      taggable = TaggableModel.create!(:name => \"Taggable\")\n      found_taggable = TaggableModel.find(taggable.id)\n      found_taggable.save\n    end\n  end\n\n  describe \"Related Objects\" do\n    it \"should find related objects based on tag names on context\" do\n      taggable1 = TaggableModel.create!(:name => \"Taggable 1\")\n      taggable2 = TaggableModel.create!(:name => \"Taggable 2\")\n      taggable3 = TaggableModel.create!(:name => \"Taggable 3\")\n  \n      taggable1.tag_list = \"one, two\"\n      taggable1.save\n  \n      taggable2.tag_list = \"three, four\"\n      taggable2.save\n  \n      taggable3.tag_list = \"one, four\"\n      taggable3.save\n  \n      taggable1.find_related_tags.should include(taggable3)\n      taggable1.find_related_tags.should_not include(taggable2)\n    end\n  \n    it \"should find other related objects based on tag names on context\" do\n      taggable1 = TaggableModel.create!(:name => \"Taggable 1\")\n      taggable2 = OtherTaggableModel.create!(:name => \"Taggable 2\")\n      taggable3 = OtherTaggableModel.create!(:name => \"Taggable 3\")\n  \n      taggable1.tag_list = \"one, two\"\n      taggable1.save\n  \n      taggable2.tag_list = \"three, four\"\n      taggable2.save\n  \n      taggable3.tag_list = \"one, four\"\n      taggable3.save\n  \n      taggable1.find_related_tags_for(OtherTaggableModel).should include(taggable3)\n      taggable1.find_related_tags_for(OtherTaggableModel).should_not include(taggable2)\n    end\n  \n    it \"should not include the object itself in the list of related objects\" do\n      taggable1 = TaggableModel.create!(:name => \"Taggable 1\")\n      taggable2 = TaggableModel.create!(:name => \"Taggable 2\")\n  \n      taggable1.tag_list = \"one\"\n      taggable1.save\n  \n      taggable2.tag_list = \"one, two\"\n      taggable2.save\n  \n      taggable1.find_related_tags.should include(taggable2)\n      taggable1.find_related_tags.should_not include(taggable1)\n    end\n  end\n\n  describe \"Matching Contexts\" do\n    it \"should find objects with tags of matching contexts\" do\n      taggable1 = TaggableModel.create!(:name => \"Taggable 1\")\n      taggable2 = TaggableModel.create!(:name => \"Taggable 2\")\n      taggable3 = TaggableModel.create!(:name => \"Taggable 3\")\n  \n      taggable1.offering_list = \"one, two\"\n      taggable1.save!\n  \n      taggable2.need_list = \"one, two\"\n      taggable2.save!\n  \n      taggable3.offering_list = \"one, two\"\n      taggable3.save!\n  \n      taggable1.find_matching_contexts(:offerings, :needs).should include(taggable2)\n      taggable1.find_matching_contexts(:offerings, :needs).should_not include(taggable3)\n    end\n  \n    it \"should find other related objects with tags of matching contexts\" do\n      taggable1 = TaggableModel.create!(:name => \"Taggable 1\")\n      taggable2 = OtherTaggableModel.create!(:name => \"Taggable 2\")\n      taggable3 = OtherTaggableModel.create!(:name => \"Taggable 3\")\n  \n      taggable1.offering_list = \"one, two\"\n      taggable1.save\n  \n      taggable2.need_list = \"one, two\"\n      taggable2.save\n  \n      taggable3.offering_list = \"one, two\"\n      taggable3.save\n  \n      taggable1.find_matching_contexts_for(OtherTaggableModel, :offerings, :needs).should include(taggable2)\n      taggable1.find_matching_contexts_for(OtherTaggableModel, :offerings, :needs).should_not include(taggable3)\n    end\n  \n    it \"should not include the object itself in the list of related objects\" do\n      taggable1 = TaggableModel.create!(:name => \"Taggable 1\")\n      taggable2 = TaggableModel.create!(:name => \"Taggable 2\")\n  \n      taggable1.tag_list = \"one\"\n      taggable1.save\n  \n      taggable2.tag_list = \"one, two\"\n      taggable2.save\n  \n      taggable1.find_related_tags.should include(taggable2)\n      taggable1.find_related_tags.should_not include(taggable1)\n    end\n  end\n\n  describe 'Tagging Contexts' do\n    it 'should eliminate duplicate tagging contexts ' do\n      TaggableModel.acts_as_taggable_on(:skills, :skills)\n      TaggableModel.tag_types.freq[:skills].should_not == 3\n    end\n\n    it \"should not contain embedded/nested arrays\" do\n      TaggableModel.acts_as_taggable_on([:array], [:array])\n      TaggableModel.tag_types.freq[[:array]].should == 0\n    end\n\n    it \"should _flatten_ the content of arrays\" do\n      TaggableModel.acts_as_taggable_on([:array], [:array])\n      TaggableModel.tag_types.freq[:array].should == 1\n    end\n\n    it \"should not raise an error when passed nil\" do\n      lambda {\n        TaggableModel.acts_as_taggable_on()\n      }.should_not raise_error\n    end\n\n    it \"should not raise an error when passed [nil]\" do\n      lambda {\n        TaggableModel.acts_as_taggable_on([nil])\n      }.should_not raise_error\n    end\n  end\n  \n  describe 'Caching' do\n    before(:each) do\n      @taggable = CachedModel.new(:name => \"Bob Jones\")  \n    end\n    \n    it \"should add saving of tag lists and cached tag lists to the instance\" do\n      @taggable.should respond_to(:save_cached_tag_list)\n      @taggable.should respond_to(:save_tags)\n    end  \n\n    it \"should generate a cached column checker for each tag type\" do\n      CachedModel.should respond_to(:caching_tag_list?)\n    end  \n    \n    it 'should not have cached tags' do\n      @taggable.cached_tag_list.should be_blank  \n    end\n    \n    it 'should cache tags' do\n      @taggable.update_attributes(:tag_list => 'awesome, epic')\n      @taggable.cached_tag_list.should == 'awesome, epic'\n    end\n    \n    it 'should keep the cache' do\n      @taggable.update_attributes(:tag_list => 'awesome, epic')\n      @taggable = CachedModel.find(@taggable)  \n      @taggable.save!\n      @taggable.cached_tag_list.should == 'awesome, epic'   \n    end\n    \n    it 'should update the cache' do\n      @taggable.update_attributes(:tag_list => 'awesome, epic')\n      @taggable.update_attributes(:tag_list => 'awesome')\n      @taggable.cached_tag_list.should == 'awesome'      \n    end\n    \n    it 'should remove the cache' do\n      @taggable.update_attributes(:tag_list => 'awesome, epic')\n      @taggable.update_attributes(:tag_list => '')\n      @taggable.cached_tag_list.should be_blank  \n    end\n    \n    it 'should have a tag list' do\n      @taggable.update_attributes(:tag_list => 'awesome, epic')\n      @taggable = CachedModel.find(@taggable.id)\n      @taggable.tag_list.sort.should == %w(awesome epic).sort\n    end\n    \n    it 'should keep the tag list' do\n      @taggable.update_attributes(:tag_list => 'awesome, epic')\n      @taggable = CachedModel.find(@taggable.id)\n      @taggable.save!\n      @taggable.tag_list.sort.should == %w(awesome epic).sort\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/acts_as_tagger_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\ndescribe \"acts_as_tagger\" do\n  before(:each) do\n    clean_database!\n  end\n  \n  describe \"Tagger Method Generation\" do\n    before(:each) do\n      @tagger = TaggableUser.new()\n    end\n\n    it \"should add #is_tagger? query method to the class-side\" do\n      TaggableUser.should respond_to(:is_tagger?)\n    end\n    \n    it \"should return true from the class-side #is_tagger?\" do\n      TaggableUser.is_tagger?.should be_true\n    end\n    \n    it \"should return false from the base #is_tagger?\" do\n      ActiveRecord::Base.is_tagger?.should be_false\n    end\n    \n    it \"should add #is_tagger? query method to the singleton\" do\n      @tagger.should respond_to(:is_tagger?)\n    end\n    \n    it \"should add #tag method on the instance-side\" do\n      @tagger.should respond_to(:tag)\n    end\n    \n    it \"should generate an association for #owned_taggings and #owned_tags\" do\n      @tagger.should respond_to(:owned_taggings, :owned_tags)\n    end\n  end\n  \n  describe \"#tag\" do\n    context 'when called with a non-existent tag context' do\n      before(:each) do\n        @tagger = TaggableUser.new()\n        @taggable = TaggableModel.new(:name=>\"Richard Prior\")\n      end\n      \n      it \"should by default not throw an exception \" do\n        @taggable.tag_list_on(:foo).should be_empty\n        lambda {\n          @tagger.tag(@taggable, :with=>'this, and, that', :on=>:foo)\n        }.should_not raise_error\n      end\n      \n      it 'should by default create the tag context on-the-fly' do\n        @taggable.tag_list_on(:here_ond_now).should be_empty\n        @tagger.tag(@taggable, :with=>'that', :on => :here_ond_now)\n        @taggable.tag_list_on(:here_ond_now).should_not include('that')\n        @taggable.all_tags_list_on(:here_ond_now).should include('that')\n      end\n      \n      it \"should show all the tag list when both public and owned tags exist\" do\n        @taggable.tag_list = 'ruby, python'\n        @tagger.tag(@taggable, :with => 'java, lisp', :on => :tags)\n        @taggable.all_tags_on(:tags).map(&:name).sort.should == %w(ruby python java lisp).sort\n      end\n      \n      it \"should not add owned tags to the common list\" do\n        @taggable.tag_list = 'ruby, python'\n        @tagger.tag(@taggable, :with => 'java, lisp', :on => :tags)\n        @taggable.tag_list.should == %w(ruby python)\n        @tagger.tag(@taggable, :with => '', :on => :tags)\n        @taggable.tag_list.should == %w(ruby python)\n      end\n      \n      it \"should throw an exception when the default is over-ridden\" do\n        @taggable.tag_list_on(:foo_boo).should be_empty\n        lambda {\n          @tagger.tag(@taggable, :with=>'this, and, that', :on=>:foo_boo, :force=>false)\n        }.should raise_error        \n      end\n\n      it \"should not create the tag context on-the-fly when the default is over-ridden\" do\n        @taggable.tag_list_on(:foo_boo).should be_empty\n        @tagger.tag(@taggable, :with=>'this, and, that', :on=>:foo_boo, :force=>false) rescue\n        @taggable.tag_list_on(:foo_boo).should be_empty\n      end\n    end\n    \n    describe \"when called by multiple tagger's\" do\n      before(:each) do\n        @user_x = TaggableUser.create(:name => \"User X\")\n        @user_y = TaggableUser.create(:name => \"User Y\")\n        @taggable = TaggableModel.create(:name => 'acts_as_taggable_on', :tag_list => 'plugin')\n        \n        @user_x.tag(@taggable, :with => 'ruby, rails',  :on => :tags)\n        @user_y.tag(@taggable, :with => 'ruby, plugin', :on => :tags)\n\n        @user_y.tag(@taggable, :with => '', :on => :tags)\n        @user_y.tag(@taggable, :with => '', :on => :tags)\n      end\n      \n      it \"should delete owned tags\" do        \n        @user_y.owned_tags.should == []\n      end\n      \n      it \"should not delete other taggers tags\" do\n        @user_x.owned_tags.should have(2).items\n      end\n      \n      it \"should not delete original tags\" do\n        @taggable.all_tags_list_on(:tags).should include('plugin')\n      end\n    end\n  end\n\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tag_list_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\ndescribe ActsAsTaggableOn::TagList do\n  before(:each) do\n    @tag_list = ActsAsTaggableOn::TagList.new(\"awesome\",\"radical\")\n  end\n  \n  it \"should be an array\" do\n    @tag_list.is_a?(Array).should be_true\n  end\n  \n  it \"should be able to be add a new tag word\" do\n    @tag_list.add(\"cool\")\n    @tag_list.include?(\"cool\").should be_true\n  end\n  \n  it \"should be able to add delimited lists of words\" do\n    @tag_list.add(\"cool, wicked\", :parse => true)\n    @tag_list.include?(\"cool\").should be_true\n    @tag_list.include?(\"wicked\").should be_true\n  end\n  \n  it \"should be able to add delimited list of words with quoted delimiters\" do\n    @tag_list.add(\"'cool, wicked', \\\"really cool, really wicked\\\"\", :parse => true)\n    @tag_list.include?(\"cool, wicked\").should be_true\n    @tag_list.include?(\"really cool, really wicked\").should be_true\n  end\n  \n  it \"should be able to handle other uses of quotation marks correctly\" do\n    @tag_list.add(\"john's cool car, mary's wicked toy\", :parse => true)\n    @tag_list.include?(\"john's cool car\").should be_true\n    @tag_list.include?(\"mary's wicked toy\").should be_true\n  end\n  \n  it \"should be able to add an array of words\" do\n    @tag_list.add([\"cool\", \"wicked\"], :parse => true)\n    @tag_list.include?(\"cool\").should be_true\n    @tag_list.include?(\"wicked\").should be_true\n  end\n  \n  it \"should be able to remove words\" do\n    @tag_list.remove(\"awesome\")\n    @tag_list.include?(\"awesome\").should be_false\n  end\n  \n  it \"should be able to remove delimited lists of words\" do\n    @tag_list.remove(\"awesome, radical\", :parse => true)\n    @tag_list.should be_empty\n  end\n  \n  it \"should be able to remove an array of words\" do\n    @tag_list.remove([\"awesome\", \"radical\"], :parse => true)\n    @tag_list.should be_empty\n  end\n  \n  it \"should give a delimited list of words when converted to string\" do\n    @tag_list.to_s.should == \"awesome, radical\"\n  end\n  \n  it \"should quote escape tags with commas in them\" do\n    @tag_list.add(\"cool\",\"rad,bodacious\")\n    @tag_list.to_s.should == \"awesome, radical, cool, \\\"rad,bodacious\\\"\"\n  end\n  \n  it \"should be able to call to_s on a frozen tag list\" do\n    @tag_list.freeze\n    lambda { @tag_list.add(\"cool\",\"rad,bodacious\") }.should raise_error\n    lambda { @tag_list.to_s }.should_not raise_error\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tag_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\ndescribe ActsAsTaggableOn::Tag do\n  before(:each) do\n    clean_database!\n    @tag = ActsAsTaggableOn::Tag.new\n    @user = TaggableModel.create(:name => \"Pablo\")\n  end\n\n  describe \"named like any\" do\n    before(:each) do\n      ActsAsTaggableOn::Tag.create(:name => \"awesome\")\n      ActsAsTaggableOn::Tag.create(:name => \"epic\")\n    end\n\n    it \"should find both tags\" do\n      ActsAsTaggableOn::Tag.named_like_any([\"awesome\", \"epic\"]).should have(2).items\n    end\n  end\n\n  describe \"find or create by name\" do\n    before(:each) do\n      @tag.name = \"awesome\"\n      @tag.save\n    end\n\n    it \"should find by name\" do\n      ActsAsTaggableOn::Tag.find_or_create_with_like_by_name(\"awesome\").should == @tag\n    end\n\n    it \"should find by name case insensitive\" do\n      ActsAsTaggableOn::Tag.find_or_create_with_like_by_name(\"AWESOME\").should == @tag\n    end\n\n    it \"should create by name\" do\n      lambda {\n        ActsAsTaggableOn::Tag.find_or_create_with_like_by_name(\"epic\")\n      }.should change(ActsAsTaggableOn::Tag, :count).by(1)\n    end\n  end\n\n  describe \"find or create all by any name\" do\n    before(:each) do\n      @tag.name = \"awesome\"\n      @tag.save\n    end\n\n    it \"should find by name\" do\n      ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name(\"awesome\").should == [@tag]\n    end\n\n    it \"should find by name case insensitive\" do\n      ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name(\"AWESOME\").should == [@tag]\n    end\n\n    it \"should create by name\" do\n      lambda {\n        ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name(\"epic\")\n      }.should change(ActsAsTaggableOn::Tag, :count).by(1)\n    end\n\n    it \"should find or create by name\" do\n      lambda {\n        ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name(\"awesome\", \"epic\").map(&:name).should == [\"awesome\", \"epic\"]\n      }.should change(ActsAsTaggableOn::Tag, :count).by(1)\n    end\n\n    it \"should return an empty array if no tags are specified\" do\n      ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name([]).should == []\n    end\n  end\n\n  it \"should require a name\" do\n    @tag.valid?\n    \n    if ActiveRecord::VERSION::MAJOR >= 3\n      @tag.errors[:name].should == [\"can't be blank\"]\n    else\n      @tag.errors[:name].should == \"can't be blank\"\n    end\n\n    @tag.name = \"something\"\n    @tag.valid?\n    \n    if ActiveRecord::VERSION::MAJOR >= 3      \n      @tag.errors[:name].should == []\n    else\n      @tag.errors[:name].should be_nil\n    end\n  end\n\n  it \"should equal a tag with the same name\" do\n    @tag.name = \"awesome\"\n    new_tag = ActsAsTaggableOn::Tag.new(:name => \"awesome\")\n    new_tag.should == @tag\n  end\n\n  it \"should return its name when to_s is called\" do\n    @tag.name = \"cool\"\n    @tag.to_s.should == \"cool\"\n  end\n\n  it \"have named_scope named(something)\" do\n    @tag.name = \"cool\"\n    @tag.save!\n    ActsAsTaggableOn::Tag.named('cool').should include(@tag)\n  end\n\n  it \"have named_scope named_like(something)\" do\n    @tag.name = \"cool\"\n    @tag.save!\n    @another_tag = ActsAsTaggableOn::Tag.create!(:name => \"coolip\")\n    ActsAsTaggableOn::Tag.named_like('cool').should include(@tag, @another_tag)\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/taggable_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\ndescribe \"Taggable\" do\n  before(:each) do\n    clean_database!\n    @taggable = TaggableModel.new(:name => \"Bob Jones\")\n  end\n\n  it \"should have tag types\" do\n    [:tags, :languages, :skills, :needs, :offerings].each do |type|\n      TaggableModel.tag_types.should include type\n    end\n\n    @taggable.tag_types.should == TaggableModel.tag_types\n  end\n\n  it \"should have tag_counts_on\" do\n    TaggableModel.tag_counts_on(:tags).all.should be_empty\n\n    @taggable.tag_list = [\"awesome\", \"epic\"]\n    @taggable.save\n\n    TaggableModel.tag_counts_on(:tags).length.should == 2\n    @taggable.tag_counts_on(:tags).length.should == 2\n  end\n\n  it \"should be able to create tags\" do\n    @taggable.skill_list = \"ruby, rails, css\"\n    @taggable.instance_variable_get(\"@skill_list\").instance_of?(ActsAsTaggableOn::TagList).should be_true\n    \n    lambda {\n      @taggable.save\n    }.should change(ActsAsTaggableOn::Tag, :count).by(3)\n    \n    @taggable.reload\n    @taggable.skill_list.sort.should == %w(ruby rails css).sort\n  end\n\n  it \"should be able to create tags through the tag list directly\" do\n    @taggable.tag_list_on(:test).add(\"hello\")\n    @taggable.tag_list_cache_on(:test).should_not be_empty\n    @taggable.tag_list_on(:test).should == [\"hello\"]\n    \n    @taggable.save\n    @taggable.save_tags\n    \n    @taggable.reload\n    @taggable.tag_list_on(:test).should == [\"hello\"]\n  end\n\n  it \"should differentiate between contexts\" do\n    @taggable.skill_list = \"ruby, rails, css\"\n    @taggable.tag_list = \"ruby, bob, charlie\"\n    @taggable.save\n    @taggable.reload\n    @taggable.skill_list.should include(\"ruby\")\n    @taggable.skill_list.should_not include(\"bob\")\n  end\n\n  it \"should be able to remove tags through list alone\" do\n    @taggable.skill_list = \"ruby, rails, css\"\n    @taggable.save\n    @taggable.reload\n    @taggable.should have(3).skills\n    @taggable.skill_list = \"ruby, rails\"\n    @taggable.save\n    @taggable.reload\n    @taggable.should have(2).skills\n  end\n\n  it \"should be able to find by tag\" do\n    @taggable.skill_list = \"ruby, rails, css\"\n    @taggable.save\n\n    TaggableModel.tagged_with(\"ruby\").first.should == @taggable\n  end\n\n  it \"should be able to find by tag with context\" do\n    @taggable.skill_list = \"ruby, rails, css\"\n    @taggable.tag_list = \"bob, charlie\"\n    @taggable.save\n\n    TaggableModel.tagged_with(\"ruby\").first.should == @taggable\n    TaggableModel.tagged_with(\"ruby, css\").first.should == @taggable\n    TaggableModel.tagged_with(\"bob\", :on => :skills).first.should_not == @taggable\n    TaggableModel.tagged_with(\"bob\", :on => :tags).first.should == @taggable\n  end\n\n  it \"should not care about case\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"ruby\")\n    frank = TaggableModel.create(:name => \"Frank\", :tag_list => \"Ruby\")\n\n    ActsAsTaggableOn::Tag.find(:all).size.should == 1\n    TaggableModel.tagged_with(\"ruby\").to_a.should == TaggableModel.tagged_with(\"Ruby\").to_a\n  end\n\n  it \"should be able to get tag counts on model as a whole\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"ruby, rails, css\")\n    frank = TaggableModel.create(:name => \"Frank\", :tag_list => \"ruby, rails\")\n    charlie = TaggableModel.create(:name => \"Charlie\", :skill_list => \"ruby\")\n    TaggableModel.tag_counts.all.should_not be_empty\n    TaggableModel.skill_counts.all.should_not be_empty\n  end\n\n  it \"should be able to get all tag counts on model as whole\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"ruby, rails, css\")\n    frank = TaggableModel.create(:name => \"Frank\", :tag_list => \"ruby, rails\")\n    charlie = TaggableModel.create(:name => \"Charlie\", :skill_list => \"ruby\")\n\n    TaggableModel.all_tag_counts.all.should_not be_empty\n    TaggableModel.all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby\n  end\n\n  if ActiveRecord::VERSION::MAJOR >= 3\n    it \"should not return read-only records\" do\n      TaggableModel.create(:name => \"Bob\", :tag_list => \"ruby, rails, css\")\n      TaggableModel.tagged_with(\"ruby\").first.should_not be_readonly\n    end\n  else\n    xit \"should not return read-only records\" do\n      # apparantly, there is no way to set readonly to false in a scope if joins are made\n    end\n    \n    it \"should be possible to return writable records\" do\n      TaggableModel.create(:name => \"Bob\", :tag_list => \"ruby, rails, css\")\n      TaggableModel.tagged_with(\"ruby\").first(:readonly => false).should_not be_readonly      \n    end\n  end\n\n  it \"should be able to get scoped tag counts\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"ruby, rails, css\")\n    frank = TaggableModel.create(:name => \"Frank\", :tag_list => \"ruby, rails\")\n    charlie = TaggableModel.create(:name => \"Charlie\", :skill_list => \"ruby\")\n\n    TaggableModel.tagged_with(\"ruby\").tag_counts(:order => 'tags.id').first.count.should == 2   # ruby\n    TaggableModel.tagged_with(\"ruby\").skill_counts.first.count.should == 1 # ruby\n  end\n\n  it \"should be able to get all scoped tag counts\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"ruby, rails, css\")\n    frank = TaggableModel.create(:name => \"Frank\", :tag_list => \"ruby, rails\")\n    charlie = TaggableModel.create(:name => \"Charlie\", :skill_list => \"ruby\")\n\n    TaggableModel.tagged_with(\"ruby\").all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby\n  end\n\n  it 'should only return tag counts for the available scope' do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"ruby, rails, css\")\n    frank = TaggableModel.create(:name => \"Frank\", :tag_list => \"ruby, rails\")\n    charlie = TaggableModel.create(:name => \"Charlie\", :skill_list => \"ruby, java\")\n \n    TaggableModel.tagged_with('rails').all_tag_counts.should have(3).items\n    TaggableModel.tagged_with('rails').all_tag_counts.any? { |tag| tag.name == 'java' }.should be_false\n    \n    # Test specific join syntaxes:\n    frank.untaggable_models.create!\n    TaggableModel.tagged_with('rails').scoped(:joins => :untaggable_models).all_tag_counts.should have(2).items\n    TaggableModel.tagged_with('rails').scoped(:joins => { :untaggable_models => :taggable_model }).all_tag_counts.should have(2).items\n    TaggableModel.tagged_with('rails').scoped(:joins => [:untaggable_models]).all_tag_counts.should have(2).items\n  end\n\n  it \"should be able to set a custom tag context list\" do\n    bob = TaggableModel.create(:name => \"Bob\")\n    bob.set_tag_list_on(:rotors, \"spinning, jumping\")\n    bob.tag_list_on(:rotors).should == [\"spinning\",\"jumping\"]\n    bob.save\n    bob.reload\n    bob.tags_on(:rotors).should_not be_empty\n  end\n\n  it \"should be able to find tagged\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"fitter, happier, more productive\", :skill_list => \"ruby, rails, css\")\n    frank = TaggableModel.create(:name => \"Frank\", :tag_list => \"weaker, depressed, inefficient\", :skill_list => \"ruby, rails, css\")\n    steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')\n\n    TaggableModel.tagged_with(\"ruby\", :order => 'taggable_models.name').to_a.should == [bob, frank, steve]\n    TaggableModel.tagged_with(\"ruby, rails\", :order => 'taggable_models.name').to_a.should == [bob, frank]\n    TaggableModel.tagged_with([\"ruby\", \"rails\"], :order => 'taggable_models.name').to_a.should == [bob, frank]\n  end\n  \n  it \"should be able to find tagged with quotation marks\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"fitter, happier, more productive, 'I love the ,comma,'\")\n    TaggableModel.tagged_with(\"'I love the ,comma,'\").should include(bob)\n  end\n  \n  it \"should be able to find tagged with invalid tags\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"fitter, happier, more productive\")    \n    TaggableModel.tagged_with(\"sad, happier\").should_not include(bob)    \n  end\n\n  it \"should be able to find tagged with any tag\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"fitter, happier, more productive\", :skill_list => \"ruby, rails, css\")\n    frank = TaggableModel.create(:name => \"Frank\", :tag_list => \"weaker, depressed, inefficient\", :skill_list => \"ruby, rails, css\")\n    steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')\n\n    TaggableModel.tagged_with([\"ruby\", \"java\"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, frank, steve]\n    TaggableModel.tagged_with([\"c++\", \"fitter\"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, steve]\n    TaggableModel.tagged_with([\"depressed\", \"css\"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, frank]\n  end\n\n  it \"should be able to find tagged on a custom tag context\" do\n    bob = TaggableModel.create(:name => \"Bob\")\n    bob.set_tag_list_on(:rotors, \"spinning, jumping\")\n    bob.tag_list_on(:rotors).should == [\"spinning\",\"jumping\"]\n    bob.save\n\n    TaggableModel.tagged_with(\"spinning\", :on => :rotors).to_a.should == [bob]\n  end\n\n  it \"should be able to use named scopes to chain tag finds\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"fitter, happier, more productive\", :skill_list => \"ruby, rails, css\")\n    frank = TaggableModel.create(:name => \"Frank\", :tag_list => \"weaker, depressed, inefficient\", :skill_list => \"ruby, rails, css\")\n    steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, python')\n\n    # Let's only find those productive Rails developers\n    TaggableModel.tagged_with('rails', :on => :skills, :order => 'taggable_models.name').to_a.should == [bob, frank]\n    TaggableModel.tagged_with('happier', :on => :tags, :order => 'taggable_models.name').to_a.should == [bob, steve]\n    TaggableModel.tagged_with('rails', :on => :skills).tagged_with('happier', :on => :tags).to_a.should == [bob]\n    TaggableModel.tagged_with('rails').tagged_with('happier', :on => :tags).to_a.should == [bob]\n  end\n\n  it \"should be able to find tagged with only the matching tags\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"lazy, happier\")\n    frank = TaggableModel.create(:name => \"Frank\", :tag_list => \"fitter, happier, inefficient\")\n    steve = TaggableModel.create(:name => 'Steve', :tag_list => \"fitter, happier\")\n\n    TaggableModel.tagged_with(\"fitter, happier\", :match_all => true).to_a.should == [steve]\n  end\n\n  it \"should be able to find tagged with some excluded tags\" do\n    bob = TaggableModel.create(:name => \"Bob\", :tag_list => \"happier, lazy\")\n    frank = TaggableModel.create(:name => \"Frank\", :tag_list => \"happier\")\n    steve = TaggableModel.create(:name => 'Steve', :tag_list => \"happier\")\n\n    TaggableModel.tagged_with(\"lazy\", :exclude => true).to_a.should == [frank, steve]\n  end\n\n  it \"should not create duplicate taggings\" do\n    bob = TaggableModel.create(:name => \"Bob\")\n    lambda {\n      bob.tag_list << \"happier\"\n      bob.tag_list << \"happier\"\n      bob.save\n    }.should change(ActsAsTaggableOn::Tagging, :count).by(1)\n  end\n \n  describe \"Associations\" do\n    before(:each) do\n      @taggable = TaggableModel.create(:tag_list => \"awesome, epic\")\n    end\n    \n    it \"should not remove tags when creating associated objects\" do\n      @taggable.untaggable_models.create!\n      @taggable.reload\n      @taggable.tag_list.should have(2).items\n    end\n  end\n\n  describe \"grouped_column_names_for method\" do\n    it \"should return all column names joined for Tag GROUP clause\" do\n      @taggable.grouped_column_names_for(ActsAsTaggableOn::Tag).should == \"tags.id, tags.name\"\n    end\n\n    it \"should return all column names joined for TaggableModel GROUP clause\" do\n      @taggable.grouped_column_names_for(TaggableModel).should == \"taggable_models.id, taggable_models.name, taggable_models.type\"\n    end\n  end\n\n  describe \"Single Table Inheritance\" do\n    before do\n      @taggable = TaggableModel.new(:name => \"taggable\")\n      @inherited_same = InheritingTaggableModel.new(:name => \"inherited same\")\n      @inherited_different = AlteredInheritingTaggableModel.new(:name => \"inherited different\")\n    end\n  \n    it \"should be able to save tags for inherited models\" do\n      @inherited_same.tag_list = \"bob, kelso\"\n      @inherited_same.save\n      InheritingTaggableModel.tagged_with(\"bob\").first.should == @inherited_same\n    end\n  \n    it \"should find STI tagged models on the superclass\" do\n      @inherited_same.tag_list = \"bob, kelso\"\n      @inherited_same.save\n      TaggableModel.tagged_with(\"bob\").first.should == @inherited_same\n    end\n  \n    it \"should be able to add on contexts only to some subclasses\" do\n      @inherited_different.part_list = \"fork, spoon\"\n      @inherited_different.save\n      InheritingTaggableModel.tagged_with(\"fork\", :on => :parts).should be_empty\n      AlteredInheritingTaggableModel.tagged_with(\"fork\", :on => :parts).first.should == @inherited_different\n    end\n  \n    it \"should have different tag_counts_on for inherited models\" do\n      @inherited_same.tag_list = \"bob, kelso\"\n      @inherited_same.save!\n      @inherited_different.tag_list = \"fork, spoon\"\n      @inherited_different.save!\n  \n      InheritingTaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(bob kelso)\n      AlteredInheritingTaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(fork spoon)\n      TaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(bob kelso fork spoon)\n    end\n  \n    it 'should store same tag without validation conflict' do\n      @taggable.tag_list = 'one'\n      @taggable.save!\n  \n      @inherited_same.tag_list = 'one'\n      @inherited_same.save!\n  \n      @inherited_same.update_attributes! :name => 'foo'\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tagger_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\ndescribe \"Tagger\" do\n  before(:each) do\n    clean_database!\n    @user = TaggableUser.create\n    @taggable = TaggableModel.create(:name => \"Bob Jones\")\n  end\n\n  it \"should have taggings\" do\n    @user.tag(@taggable, :with=>'ruby,scheme', :on=>:tags)\n    @user.owned_taggings.size == 2\n  end\n\n  it \"should have tags\" do\n    @user.tag(@taggable, :with=>'ruby,scheme', :on=>:tags)\n    @user.owned_tags.size == 2\n  end\n  \n  it \"should not overlap tags from different taggers\" do\n    @user2 = TaggableUser.new\n    lambda{\n      @user.tag(@taggable, :with => 'ruby, scheme', :on => :tags)\n      @user2.tag(@taggable, :with => 'java, python, lisp, ruby', :on => :tags)\n    }.should change(ActsAsTaggableOn::Tagging, :count).by(6)\n\n    [@user, @user2, @taggable].each(&:reload)\n\n    @user.owned_tags.map(&:name).sort.should == %w(ruby scheme).sort\n    @user2.owned_tags.map(&:name).sort.should == %w(java python lisp ruby).sort\n    \n    @taggable.tags_from(@user).sort.should == %w(ruby scheme).sort\n    @taggable.tags_from(@user2).sort.should == %w(java lisp python ruby).sort\n    \n    @taggable.all_tags_list.sort.should == %w(ruby scheme java python lisp).sort\n    @taggable.all_tags_on(:tags).size.should == 5\n  end\n  \n  it \"should not lose tags from different taggers\" do\n    @user2 = TaggableUser.create\n    @user2.tag(@taggable, :with => 'java, python, lisp, ruby', :on => :tags)\n    @user.tag(@taggable, :with => 'ruby, scheme', :on => :tags)  \n    \n    lambda {\n      @user2.tag(@taggable, :with => 'java, python, lisp', :on => :tags)\n    }.should change(ActsAsTaggableOn::Tagging, :count).by(-1)\n\n    [@user, @user2, @taggable].each(&:reload)\n    \n    @taggable.tags_from(@user).sort.should == %w(ruby scheme).sort\n    @taggable.tags_from(@user2).sort.should == %w(java python lisp).sort\n    \n    @taggable.all_tags_list.sort.should == %w(ruby scheme java python lisp).sort\n    @taggable.all_tags_on(:tags).length.should == 5\n  end\n\n  it \"should not lose tags\" do\n    @user2 = TaggableUser.create\n    \n    @user.tag(@taggable, :with => 'awesome', :on => :tags)\n    @user2.tag(@taggable, :with => 'awesome, epic', :on => :tags)\n\n    lambda {\n      @user2.tag(@taggable, :with => 'epic', :on => :tags)\n    }.should change(ActsAsTaggableOn::Tagging, :count).by(-1)\n\n    @taggable.reload  \n    @taggable.all_tags_list.should include('awesome')\n    @taggable.all_tags_list.should include('epic')\n  end\n  \n  it \"should not lose tags\" do\n    @taggable.update_attributes(:tag_list => 'ruby')\n    @user.tag(@taggable, :with => 'ruby, scheme', :on => :tags)\n    \n    [@taggable, @user].each(&:reload)\n    @taggable.tag_list.should == %w(ruby)\n    @taggable.all_tags_list.sort.should == %w(ruby scheme).sort\n    \n    lambda {\n      @taggable.update_attributes(:tag_list => \"\")\n    }.should change(ActsAsTaggableOn::Tagging, :count).by(-1)\n    \n    @taggable.tag_list.should == []\n    @taggable.all_tags_list.sort.should == %w(ruby scheme).sort\n  end\n\n  it \"is tagger\" do\n    @user.is_tagger?.should(be_true)\n  end  \nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tagging_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\ndescribe ActsAsTaggableOn::Tagging do\n  before(:each) do\n    clean_database!\n    @tagging = ActsAsTaggableOn::Tagging.new\n  end\n\n  it \"should not be valid with a invalid tag\" do\n    @tagging.taggable = TaggableModel.create(:name => \"Bob Jones\")\n    @tagging.tag = ActsAsTaggableOn::Tag.new(:name => \"\")\n    @tagging.context = \"tags\"\n\n    @tagging.should_not be_valid\n    \n    if ActiveRecord::VERSION::MAJOR >= 3\n      @tagging.errors[:tag_id].should == [\"can't be blank\"]\n    else\n      @tagging.errors[:tag_id].should == \"can't be blank\"\n    end\n  end\n\n  it \"should not create duplicate taggings\" do\n    @taggable = TaggableModel.create(:name => \"Bob Jones\")\n    @tag = ActsAsTaggableOn::Tag.create(:name => \"awesome\")\n\n    lambda {\n      2.times { ActsAsTaggableOn::Tagging.create(:taggable => @taggable, :tag => @tag, :context => 'tags') }\n    }.should change(ActsAsTaggableOn::Tagging, :count).by(1)\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/acts_as_taggable_on/tags_helper_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\ndescribe ActsAsTaggableOn::TagsHelper do\n  before(:each) do\n    clean_database!\n    \n    @bob = TaggableModel.create(:name => \"Bob Jones\",  :language_list => \"ruby, php\")\n    @tom = TaggableModel.create(:name => \"Tom Marley\", :language_list => \"ruby, java\")\n    @eve = TaggableModel.create(:name => \"Eve Nodd\",   :language_list => \"ruby, c++\")\n    \n    @helper = class Helper\n      include ActsAsTaggableOn::TagsHelper\n    end.new\n  end\n  \n  it \"should yield the proper css classes\" do \n    tags = { }\n    \n    @helper.tag_cloud(TaggableModel.tag_counts_on(:languages), [\"sucky\", \"awesome\"]) do |tag, css_class|\n      tags[tag.name] = css_class\n    end\n    \n    tags[\"ruby\"].should == \"awesome\"\n    tags[\"java\"].should == \"sucky\"\n    tags[\"c++\"].should == \"sucky\"\n    tags[\"php\"].should == \"sucky\"\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/bm.rb",
    "content": "require 'active_record'\nrequire 'action_view'\nrequire File.expand_path('../../lib/acts-as-taggable-on', __FILE__)\n\nif defined?(ActiveRecord::Acts::TaggableOn)\n  ActiveRecord::Base.send :include, ActiveRecord::Acts::TaggableOn\n  ActiveRecord::Base.send :include, ActiveRecord::Acts::Tagger\n  ActionView::Base.send :include, TagsHelper if defined?(ActionView::Base)\nend\n\nTEST_DATABASE_FILE = File.join(File.dirname(__FILE__), '..', 'test.sqlite3')\nFile.unlink(TEST_DATABASE_FILE) if File.exist?(TEST_DATABASE_FILE)\nActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => TEST_DATABASE_FILE\n\nActiveRecord::Base.silence do\n  ActiveRecord::Migration.verbose = false\n  ActiveRecord::Schema.define :version => 0 do\n    create_table \"taggings\", :force => true do |t|\n      t.integer  \"tag_id\",        :limit => 11\n      t.integer  \"taggable_id\",   :limit => 11\n      t.string   \"taggable_type\"\n      t.string   \"context\"\n      t.datetime \"created_at\"\n      t.integer  \"tagger_id\",     :limit => 11\n      t.string   \"tagger_type\"\n    end\n\n    add_index \"taggings\", [\"tag_id\"], :name => \"index_taggings_on_tag_id\"\n    add_index \"taggings\", [\"taggable_id\", \"taggable_type\", \"context\"], :name => \"index_taggings_on_taggable_id_and_taggable_type_and_context\"\n\n    create_table \"tags\", :force => true do |t|\n      t.string \"name\"\n    end\n\n    create_table :taggable_models, :force => true do |t|\n      t.column :name, :string\n      t.column :type, :string\n      t.column :cached_tag_list, :string\n    end\n  end\n\n  class TaggableModel < ActiveRecord::Base\n    acts_as_taggable\n    acts_as_taggable_on :languages\n    acts_as_taggable_on :skills\n    acts_as_taggable_on :needs, :offerings\n  end\nend\n\nputs Benchmark.measure {\n  1000.times { TaggableModel.create :tag_list => \"awesome, epic, neat\" }\n}"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/database.yml.sample",
    "content": "sqlite3:\n  adapter: sqlite3\n  database: acts_as_taggable_on.sqlite3\n\nmysql:\n  adapter: mysql\n  hostname: localhost\n  username: root\n  password:\n  database: acts_as_taggable_on\n\npostgresql:\n  adapter: postgresql\n  hostname: localhost\n  username: postgres\n  password:\n  database: acts_as_taggable_on\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/models.rb",
    "content": "class TaggableModel < ActiveRecord::Base\n  acts_as_taggable\n  acts_as_taggable_on :languages\n  acts_as_taggable_on :skills\n  acts_as_taggable_on :needs, :offerings\n  has_many :untaggable_models\nend\n\nclass CachedModel < ActiveRecord::Base\n  acts_as_taggable\nend\n\nclass OtherTaggableModel < ActiveRecord::Base\n  acts_as_taggable_on :tags, :languages\n  acts_as_taggable_on :needs, :offerings\nend\n\nclass InheritingTaggableModel < TaggableModel\nend\n\nclass AlteredInheritingTaggableModel < TaggableModel\n  acts_as_taggable_on :parts\nend\n\nclass TaggableUser < ActiveRecord::Base\n  acts_as_tagger\nend\n\nclass UntaggableModel < ActiveRecord::Base\n  belongs_to :taggable_model\nend"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/schema.rb",
    "content": "ActiveRecord::Schema.define :version => 0 do\n  create_table \"taggings\", :force => true do |t|\n    t.integer  \"tag_id\",        :limit => 11\n    t.integer  \"taggable_id\",   :limit => 11\n    t.string   \"taggable_type\"\n    t.string   \"context\"\n    t.datetime \"created_at\"\n    t.integer  \"tagger_id\",     :limit => 11\n    t.string   \"tagger_type\"\n  end\n\n  add_index \"taggings\", [\"tag_id\"], :name => \"index_taggings_on_tag_id\"\n  add_index \"taggings\", [\"taggable_id\", \"taggable_type\", \"context\"], :name => \"index_taggings_on_taggable_id_and_taggable_type_and_context\"\n\n  create_table \"tags\", :force => true do |t|\n    t.string \"name\"\n  end\n  \n  create_table :taggable_models, :force => true do |t|\n    t.column :name, :string\n    t.column :type, :string\n  end\n  \n  create_table :untaggable_models, :force => true do |t|\n    t.column :taggable_model_id, :integer\n    t.column :name, :string\n  end\n  \n  create_table :cached_models, :force => true do |t|\n    t.column :name, :string\n    t.column :type, :string\n    t.column :cached_tag_list, :string\n  end\n  \n  create_table :taggable_users, :force => true do |t|\n    t.column :name, :string\n  end\n  \n  create_table :other_taggable_models, :force => true do |t|\n    t.column :name, :string\n    t.column :type, :string\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/spec/spec_helper.rb",
    "content": "$LOAD_PATH << \".\" unless $LOAD_PATH.include?(\".\")\n\nbegin\n  require \"rubygems\"\n  require \"bundler\"\n\n  if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new(\"0.9.5\")\n    raise RuntimeError, \"Your bundler version is too old.\" +\n     \"Run `gem install bundler` to upgrade.\"\n  end\n\n  # Set up load paths for all bundled gems\n  Bundler.setup\nrescue Bundler::GemNotFound\n  raise RuntimeError, \"Bundler couldn't find some gems.\" +\n    \"Did you run `bundle install`?\"\nend\n\nBundler.require\nrequire File.expand_path('../../lib/acts-as-taggable-on', __FILE__)\n\nunless [].respond_to?(:freq)\n  class Array\n    def freq\n      k=Hash.new(0)\n      each {|e| k[e]+=1}\n      k\n    end\n  end\nend\n\nENV['DB'] ||= 'sqlite3'\n\ndatabase_yml = File.expand_path('../database.yml', __FILE__)\nif File.exists?(database_yml)\n  active_record_configuration = YAML.load_file(database_yml)[ENV['DB']]\n  \n  ActiveRecord::Base.establish_connection(active_record_configuration)\n  ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), \"debug.log\"))\n  \n  ActiveRecord::Base.silence do\n    ActiveRecord::Migration.verbose = false\n    \n    load(File.dirname(__FILE__) + '/schema.rb')\n    load(File.dirname(__FILE__) + '/models.rb')\n  end  \n  \nelse\n  raise \"Please create #{database_yml} first to configure your database. Take a look at: #{database_yml}.sample\"\nend\n\ndef clean_database!\n  models = [ActsAsTaggableOn::Tag, ActsAsTaggableOn::Tagging, TaggableModel, OtherTaggableModel, InheritingTaggableModel,\n            AlteredInheritingTaggableModel, TaggableUser, UntaggableModel]\n  models.each do |model|\n    ActiveRecord::Base.connection.execute \"DELETE FROM #{model.table_name}\"\n  end\nend\n\nclean_database!"
  },
  {
    "path": "vendor/plugins/acts-as-taggable-on/uninstall.rb",
    "content": "# Uninstall hook code here\n"
  },
  {
    "path": "vendor/plugins/acts_as_attachable/init.rb",
    "content": "require File.dirname(__FILE__) + '/lib/acts_as_attachable'\nActiveRecord::Base.send(:include, Redmine::Acts::Attachable)\n"
  },
  {
    "path": "vendor/plugins/acts_as_attachable/lib/acts_as_attachable.rb",
    "content": "# Redmine - project management software\n# Copyright (C) 2006-2011  See readme for details and license\n#\n\nmodule Redmine\n  module Acts\n    module Attachable\n      def self.included(base)\n        base.extend ClassMethods\n      end\n\n      module ClassMethods\n        def acts_as_attachable(options = {})\n          cattr_accessor :attachable_options\n          self.attachable_options = {}\n          attachable_options[:view_permission] = options.delete(:view_permission) || \"view_#{self.name.pluralize.underscore}\".to_sym\n          attachable_options[:delete_permission] = options.delete(:delete_permission) || \"edit_#{self.name.pluralize.underscore}\".to_sym\n          \n          has_many :attachments, options.merge(:as => :container,\n                                               :order => \"#{Attachment.table_name}.created_at\",\n                                               :dependent => :destroy)\n          send :include, Redmine::Acts::Attachable::InstanceMethods\n        end\n      end\n\n      module InstanceMethods\n        def self.included(base)\n          base.extend ClassMethods\n        end\n        \n        def attachments_visible?(user=User.current)\n          user.allowed_to?(self.class.attachable_options[:view_permission], self.project)\n        end\n        \n        def attachments_deletable?(user=User.current)\n          user.allowed_to?(self.class.attachable_options[:delete_permission], self.project)\n        end\n        \n        module ClassMethods\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts_as_event/init.rb",
    "content": "require File.dirname(__FILE__) + '/lib/acts_as_event'\nActiveRecord::Base.send(:include, Redmine::Acts::Event)\n"
  },
  {
    "path": "vendor/plugins/acts_as_event/lib/acts_as_event.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine\n  module Acts\n    module Event\n      def self.included(base)\n        base.extend ClassMethods\n      end\n\n      module ClassMethods\n        def acts_as_event(options = {})\n          return if self.included_modules.include?(Redmine::Acts::Event::InstanceMethods)\n          default_options = { :datetime => :created_at,\n                              :title => :title,\n                              :description => :description,\n                              :author => :author,\n                              :url => {:controller => 'welcome'},\n                              :type => self.name.underscore.dasherize }\n                              \n          cattr_accessor :event_options\n          self.event_options = default_options.merge(options)\n          send :include, Redmine::Acts::Event::InstanceMethods\n        end\n      end\n\n      module InstanceMethods\n        def self.included(base)\n          base.extend ClassMethods\n        end\n        \n        %w(datetime title description author type).each do |attr|\n          src = <<-END_SRC\n            def event_#{attr}\n              option = event_options[:#{attr}]\n              if option.is_a?(Proc)\n                option.call(self)\n              elsif option.is_a?(Symbol)\n                send(option)\n              else\n                option\n              end\n            end\n          END_SRC\n          class_eval src, __FILE__, __LINE__\n        end\n        \n        def event_date\n          event_datetime.to_date\n        end\n        \n        def event_url(options = {})\n          option = event_options[:url]\n          (option.is_a?(Proc) ? option.call(self) : send(option)).merge(options)\n        end\n\n        module ClassMethods\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts_as_list/README",
    "content": "ActsAsList\n==========\n\nThis acts_as extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a +position+ column defined as an integer on the mapped database table.\n\n\nExample\n=======\n\n  class TodoList < ActiveRecord::Base\n    has_many :todo_items, :order => \"position\"\n  end\n\n  class TodoItem < ActiveRecord::Base\n    belongs_to :todo_list\n    acts_as_list :scope => :todo_list\n  end\n\n  todo_list.first.move_to_bottom\n  todo_list.last.move_higher\n\n\nCopyright (c) 2007 David Heinemeier Hansson, released under the MIT license"
  },
  {
    "path": "vendor/plugins/acts_as_list/init.rb",
    "content": "$:.unshift \"#{File.dirname(__FILE__)}/lib\"\nrequire 'active_record/acts/list'\nActiveRecord::Base.class_eval { include ActiveRecord::Acts::List }\n"
  },
  {
    "path": "vendor/plugins/acts_as_list/lib/active_record/acts/list.rb",
    "content": "module ActiveRecord\n  module Acts #:nodoc:\n    module List #:nodoc:\n      def self.included(base)\n        base.extend(ClassMethods)\n      end\n\n      # This +acts_as+ extension provides the capabilities for sorting and reordering a number of objects in a list.\n      # The class that has this specified needs to have a +position+ column defined as an integer on\n      # the mapped database table.\n      #\n      # Todo list example:\n      #\n      #   class TodoList < ActiveRecord::Base\n      #     has_many :todo_items, :order => \"position\"\n      #   end\n      #\n      #   class TodoItem < ActiveRecord::Base\n      #     belongs_to :todo_list\n      #     acts_as_list :scope => :todo_list\n      #   end\n      #\n      #   todo_list.first.move_to_bottom\n      #   todo_list.last.move_higher\n      module ClassMethods\n        # Configuration options are:\n        #\n        # * +column+ - specifies the column name to use for keeping the position integer (default: +position+)\n        # * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach <tt>_id</tt> \n        #   (if it hasn't already been added) and use that as the foreign key restriction. It's also possible \n        #   to give it an entire string that is interpolated if you need a tighter scope than just a foreign key.\n        #   Example: <tt>acts_as_list :scope => 'todo_list_id = #{todo_list_id} AND completed = 0'</tt>\n        def acts_as_list(options = {})\n          configuration = { :column => \"position\", :scope => \"1 = 1\" }\n          configuration.update(options) if options.is_a?(Hash)\n\n          configuration[:scope] = \"#{configuration[:scope]}_id\".intern if configuration[:scope].is_a?(Symbol) && configuration[:scope].to_s !~ /_id$/\n\n          if configuration[:scope].is_a?(Symbol)\n            scope_condition_method = %(\n              def scope_condition\n                if #{configuration[:scope].to_s}.nil?\n                  \"#{configuration[:scope].to_s} IS NULL\"\n                else\n                  \"#{configuration[:scope].to_s} = \\#{#{configuration[:scope].to_s}}\"\n                end\n              end\n            )\n          else\n            scope_condition_method = \"def scope_condition() \\\"#{configuration[:scope]}\\\" end\"\n          end\n\n          class_eval <<-EOV\n            include ActiveRecord::Acts::List::InstanceMethods\n\n            def acts_as_list_class\n              ::#{self.name}\n            end\n\n            def position_column\n              '#{configuration[:column]}'\n            end\n\n            #{scope_condition_method}\n\n            before_destroy :remove_from_list\n            before_create  :add_to_list_bottom\n          EOV\n        end\n      end\n\n      # All the methods available to a record that has had <tt>acts_as_list</tt> specified. Each method works\n      # by assuming the object to be the item in the list, so <tt>chapter.move_lower</tt> would move that chapter\n      # lower in the list of all chapters. Likewise, <tt>chapter.first?</tt> would return +true+ if that chapter is\n      # the first in the list of all chapters.\n      module InstanceMethods\n        # Insert the item at the given position (defaults to the top position of 1).\n        def insert_at(position = 1)\n          insert_at_position(position)\n        end\n\n        # Swap positions with the next lower item, if one exists.\n        def move_lower\n          return unless lower_item\n\n          acts_as_list_class.transaction do\n            lower_item.decrement_position\n            increment_position\n          end\n        end\n\n        # Swap positions with the next higher item, if one exists.\n        def move_higher\n          return unless higher_item\n\n          acts_as_list_class.transaction do\n            higher_item.increment_position\n            decrement_position\n          end\n        end\n\n        # Move to the bottom of the list. If the item is already in the list, the items below it have their\n        # position adjusted accordingly.\n        def move_to_bottom\n          return unless in_list?\n          acts_as_list_class.transaction do\n            decrement_positions_on_lower_items\n            assume_bottom_position\n          end\n        end\n\n        # Move to the top of the list. If the item is already in the list, the items above it have their\n        # position adjusted accordingly.\n        def move_to_top\n          return unless in_list?\n          acts_as_list_class.transaction do\n            increment_positions_on_higher_items\n            assume_top_position\n          end\n        end\n        \n        # Move to the given position\n        def move_to=(pos)\n          case pos.to_s\n          when 'highest'\n            move_to_top\n          when 'higher'\n            move_higher\n          when 'lower'\n            move_lower\n          when 'lowest'\n            move_to_bottom\n          end\n        end\n\n        # Removes the item from the list.\n        def remove_from_list\n          if in_list?\n            decrement_positions_on_lower_items\n            update_attribute position_column, nil\n          end\n        end\n\n        # Increase the position of this item without adjusting the rest of the list.\n        def increment_position\n          return unless in_list?\n          update_attribute position_column, self.send(position_column).to_i + 1\n        end\n\n        # Decrease the position of this item without adjusting the rest of the list.\n        def decrement_position\n          return unless in_list?\n          update_attribute position_column, self.send(position_column).to_i - 1\n        end\n\n        # Return +true+ if this object is the first in the list.\n        def first?\n          return false unless in_list?\n          self.send(position_column) == 1\n        end\n\n        # Return +true+ if this object is the last in the list.\n        def last?\n          return false unless in_list?\n          self.send(position_column) == bottom_position_in_list\n        end\n\n        # Return the next higher item in the list.\n        def higher_item\n          return nil unless in_list?\n          acts_as_list_class.find(:first, :conditions =>\n            \"#{scope_condition} AND #{position_column} = #{(send(position_column).to_i - 1).to_s}\"\n          )\n        end\n\n        # Return the next lower item in the list.\n        def lower_item\n          return nil unless in_list?\n          acts_as_list_class.find(:first, :conditions =>\n            \"#{scope_condition} AND #{position_column} = #{(send(position_column).to_i + 1).to_s}\"\n          )\n        end\n\n        # Test if this record is in a list\n        def in_list?\n          !send(position_column).nil?\n        end\n\n        private\n          def add_to_list_top\n            increment_positions_on_all_items\n          end\n\n          def add_to_list_bottom\n            self[position_column] = bottom_position_in_list.to_i + 1\n          end\n\n          # Overwrite this method to define the scope of the list changes\n          def scope_condition() \"1\" end\n\n          # Returns the bottom position number in the list.\n          #   bottom_position_in_list    # => 2\n          def bottom_position_in_list(except = nil)\n            item = bottom_item(except)\n            item ? item.send(position_column) : 0\n          end\n\n          # Returns the bottom item\n          def bottom_item(except = nil)\n            conditions = scope_condition\n            conditions = \"#{conditions} AND #{self.class.primary_key} != #{except.id}\" if except\n            acts_as_list_class.find(:first, :conditions => conditions, :order => \"#{position_column} DESC\")\n          end\n\n          # Forces item to assume the bottom position in the list.\n          def assume_bottom_position\n            update_attribute(position_column, bottom_position_in_list(self).to_i + 1)\n          end\n\n          # Forces item to assume the top position in the list.\n          def assume_top_position\n            update_attribute(position_column, 1)\n          end\n\n          # This has the effect of moving all the higher items up one.\n          def decrement_positions_on_higher_items(position)\n            acts_as_list_class.update_all(\n              \"#{position_column} = (#{position_column} - 1)\", \"#{scope_condition} AND #{position_column} <= #{position}\"\n            )\n          end\n\n          # This has the effect of moving all the lower items up one.\n          def decrement_positions_on_lower_items\n            return unless in_list?\n            acts_as_list_class.update_all(\n              \"#{position_column} = (#{position_column} - 1)\", \"#{scope_condition} AND #{position_column} > #{send(position_column).to_i}\"\n            )\n          end\n\n          # This has the effect of moving all the higher items down one.\n          def increment_positions_on_higher_items\n            return unless in_list?\n            acts_as_list_class.update_all(\n              \"#{position_column} = (#{position_column} + 1)\", \"#{scope_condition} AND #{position_column} < #{send(position_column).to_i}\"\n            )\n          end\n\n          # This has the effect of moving all the lower items down one.\n          def increment_positions_on_lower_items(position)\n            acts_as_list_class.update_all(\n              \"#{position_column} = (#{position_column} + 1)\", \"#{scope_condition} AND #{position_column} >= #{position}\"\n           )\n          end\n\n          # Increments position (<tt>position_column</tt>) of all items in the list.\n          def increment_positions_on_all_items\n            acts_as_list_class.update_all(\n              \"#{position_column} = (#{position_column} + 1)\",  \"#{scope_condition}\"\n            )\n          end\n\n          def insert_at_position(position)\n            remove_from_list\n            increment_positions_on_lower_items(position)\n            self.update_attribute(position_column, position)\n          end\n      end \n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts_as_list/test/list_test.rb",
    "content": "require 'test/unit'\n\nrequire 'rubygems'\ngem 'activerecord', '>= 1.15.4.7794'\nrequire 'active_record'\n\nrequire \"#{File.dirname(__FILE__)}/../init\"\n\nActiveRecord::Base.establish_connection(:adapter => \"sqlite3\", :dbfile => \":memory:\")\n\ndef setup_db\n  ActiveRecord::Schema.define(:version => 1) do\n    create_table :mixins do |t|\n      t.column :pos, :integer\n      t.column :parent_id, :integer\n      t.column :created_at, :datetime      \n      t.column :updated_at, :datetime\n    end\n  end\nend\n\ndef teardown_db\n  ActiveRecord::Base.connection.tables.each do |table|\n    ActiveRecord::Base.connection.drop_table(table)\n  end\nend\n\nclass Mixin < ActiveRecord::Base\nend\n\nclass ListMixin < Mixin\n  acts_as_list :column => \"pos\", :scope => :parent\n\n  def self.table_name() \"mixins\" end\nend\n\nclass ListMixinSub1 < ListMixin\nend\n\nclass ListMixinSub2 < ListMixin\nend\n\nclass ListWithStringScopeMixin < ActiveRecord::Base\n  acts_as_list :column => \"pos\", :scope => 'parent_id = #{parent_id}'\n\n  def self.table_name() \"mixins\" end\nend\n\n\nclass ListTest < Test::Unit::TestCase\n\n  def setup\n    setup_db\n    (1..4).each { |counter| ListMixin.create! :pos => counter, :parent_id => 5 }\n  end\n\n  def teardown\n    teardown_db\n  end\n\n  def test_reordering\n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n\n    ListMixin.find(2).move_lower\n    assert_equal [1, 3, 2, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n\n    ListMixin.find(2).move_higher\n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n\n    ListMixin.find(1).move_to_bottom\n    assert_equal [2, 3, 4, 1], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n\n    ListMixin.find(1).move_to_top\n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n\n    ListMixin.find(2).move_to_bottom\n    assert_equal [1, 3, 4, 2], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n\n    ListMixin.find(4).move_to_top\n    assert_equal [4, 1, 3, 2], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n  end\n\n  def test_move_to_bottom_with_next_to_last_item\n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n    ListMixin.find(3).move_to_bottom\n    assert_equal [1, 2, 4, 3], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n  end\n\n  def test_next_prev\n    assert_equal ListMixin.find(2), ListMixin.find(1).lower_item\n    assert_nil ListMixin.find(1).higher_item\n    assert_equal ListMixin.find(3), ListMixin.find(4).higher_item\n    assert_nil ListMixin.find(4).lower_item\n  end\n\n  def test_injection\n    item = ListMixin.new(:parent_id => 1)\n    assert_equal \"parent_id = 1\", item.scope_condition\n    assert_equal \"pos\", item.position_column\n  end\n\n  def test_insert\n    new = ListMixin.create(:parent_id => 20)\n    assert_equal 1, new.pos\n    assert new.first?\n    assert new.last?\n\n    new = ListMixin.create(:parent_id => 20)\n    assert_equal 2, new.pos\n    assert !new.first?\n    assert new.last?\n\n    new = ListMixin.create(:parent_id => 20)\n    assert_equal 3, new.pos\n    assert !new.first?\n    assert new.last?\n\n    new = ListMixin.create(:parent_id => 0)\n    assert_equal 1, new.pos\n    assert new.first?\n    assert new.last?\n  end\n\n  def test_insert_at\n    new = ListMixin.create(:parent_id => 20)\n    assert_equal 1, new.pos\n\n    new = ListMixin.create(:parent_id => 20)\n    assert_equal 2, new.pos\n\n    new = ListMixin.create(:parent_id => 20)\n    assert_equal 3, new.pos\n\n    new4 = ListMixin.create(:parent_id => 20)\n    assert_equal 4, new4.pos\n\n    new4.insert_at(3)\n    assert_equal 3, new4.pos\n\n    new.reload\n    assert_equal 4, new.pos\n\n    new.insert_at(2)\n    assert_equal 2, new.pos\n\n    new4.reload\n    assert_equal 4, new4.pos\n\n    new5 = ListMixin.create(:parent_id => 20)\n    assert_equal 5, new5.pos\n\n    new5.insert_at(1)\n    assert_equal 1, new5.pos\n\n    new4.reload\n    assert_equal 5, new4.pos\n  end\n\n  def test_delete_middle\n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n\n    ListMixin.find(2).destroy\n\n    assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n\n    assert_equal 1, ListMixin.find(1).pos\n    assert_equal 2, ListMixin.find(3).pos\n    assert_equal 3, ListMixin.find(4).pos\n\n    ListMixin.find(1).destroy\n\n    assert_equal [3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n\n    assert_equal 1, ListMixin.find(3).pos\n    assert_equal 2, ListMixin.find(4).pos\n  end\n\n  def test_with_string_based_scope\n    new = ListWithStringScopeMixin.create(:parent_id => 500)\n    assert_equal 1, new.pos\n    assert new.first?\n    assert new.last?\n  end\n\n  def test_nil_scope\n    new1, new2, new3 = ListMixin.create, ListMixin.create, ListMixin.create\n    new2.move_higher\n    assert_equal [new2, new1, new3], ListMixin.find(:all, :conditions => 'parent_id IS NULL', :order => 'pos')\n  end\n  \n  \n  def test_remove_from_list_should_then_fail_in_list? \n    assert_equal true, ListMixin.find(1).in_list?\n    ListMixin.find(1).remove_from_list\n    assert_equal false, ListMixin.find(1).in_list?\n  end \n  \n  def test_remove_from_list_should_set_position_to_nil \n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n  \n    ListMixin.find(2).remove_from_list \n  \n    assert_equal [2, 1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n  \n    assert_equal 1,   ListMixin.find(1).pos\n    assert_equal nil, ListMixin.find(2).pos\n    assert_equal 2,   ListMixin.find(3).pos\n    assert_equal 3,   ListMixin.find(4).pos\n  end \n  \n  def test_remove_before_destroy_does_not_shift_lower_items_twice \n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n  \n    ListMixin.find(2).remove_from_list \n    ListMixin.find(2).destroy \n  \n    assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)\n  \n    assert_equal 1, ListMixin.find(1).pos\n    assert_equal 2, ListMixin.find(3).pos\n    assert_equal 3, ListMixin.find(4).pos\n  end \n  \nend\n\nclass ListSubTest < Test::Unit::TestCase\n\n  def setup\n    setup_db\n    (1..4).each { |i| ((i % 2 == 1) ? ListMixinSub1 : ListMixinSub2).create! :pos => i, :parent_id => 5000 }\n  end\n\n  def teardown\n    teardown_db\n  end\n\n  def test_reordering\n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n\n    ListMixin.find(2).move_lower\n    assert_equal [1, 3, 2, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n\n    ListMixin.find(2).move_higher\n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n\n    ListMixin.find(1).move_to_bottom\n    assert_equal [2, 3, 4, 1], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n\n    ListMixin.find(1).move_to_top\n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n\n    ListMixin.find(2).move_to_bottom\n    assert_equal [1, 3, 4, 2], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n\n    ListMixin.find(4).move_to_top\n    assert_equal [4, 1, 3, 2], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n  end\n\n  def test_move_to_bottom_with_next_to_last_item\n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n    ListMixin.find(3).move_to_bottom\n    assert_equal [1, 2, 4, 3], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n  end\n\n  def test_next_prev\n    assert_equal ListMixin.find(2), ListMixin.find(1).lower_item\n    assert_nil ListMixin.find(1).higher_item\n    assert_equal ListMixin.find(3), ListMixin.find(4).higher_item\n    assert_nil ListMixin.find(4).lower_item\n  end\n\n  def test_injection\n    item = ListMixin.new(\"parent_id\"=>1)\n    assert_equal \"parent_id = 1\", item.scope_condition\n    assert_equal \"pos\", item.position_column\n  end\n\n  def test_insert_at\n    new = ListMixin.create(\"parent_id\" => 20)\n    assert_equal 1, new.pos\n\n    new = ListMixinSub1.create(\"parent_id\" => 20)\n    assert_equal 2, new.pos\n\n    new = ListMixinSub2.create(\"parent_id\" => 20)\n    assert_equal 3, new.pos\n\n    new4 = ListMixin.create(\"parent_id\" => 20)\n    assert_equal 4, new4.pos\n\n    new4.insert_at(3)\n    assert_equal 3, new4.pos\n\n    new.reload\n    assert_equal 4, new.pos\n\n    new.insert_at(2)\n    assert_equal 2, new.pos\n\n    new4.reload\n    assert_equal 4, new4.pos\n\n    new5 = ListMixinSub1.create(\"parent_id\" => 20)\n    assert_equal 5, new5.pos\n\n    new5.insert_at(1)\n    assert_equal 1, new5.pos\n\n    new4.reload\n    assert_equal 5, new4.pos\n  end\n\n  def test_delete_middle\n    assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n\n    ListMixin.find(2).destroy\n\n    assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n\n    assert_equal 1, ListMixin.find(1).pos\n    assert_equal 2, ListMixin.find(3).pos\n    assert_equal 3, ListMixin.find(4).pos\n\n    ListMixin.find(1).destroy\n\n    assert_equal [3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)\n\n    assert_equal 1, ListMixin.find(3).pos\n    assert_equal 2, ListMixin.find(4).pos\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/acts_as_searchable/init.rb",
    "content": "require File.dirname(__FILE__) + '/lib/acts_as_searchable'\nActiveRecord::Base.send(:include, Redmine::Acts::Searchable)\n"
  },
  {
    "path": "vendor/plugins/acts_as_searchable/lib/acts_as_searchable.rb",
    "content": "# BetterMeans - Work 2.0\n# Copyright (C) 2006-2011  See readme for details and license#\n\nmodule Redmine\n  module Acts\n    module Searchable\n      def self.included(base) \n        base.extend ClassMethods\n      end \n\n      module ClassMethods\n        # Options:\n        # * :columns - a column or an array of columns to search\n        # * :project_key - project foreign key (default to project_id)\n        # * :date_column - name of the datetime column (default to created_at)\n        # * :sort_order - name of the column used to sort results (default to :date_column or created_at)\n        # * :permission - permission required to search the model (default to :view_\"objects\")\n        def acts_as_searchable(options = {})\n          return if self.included_modules.include?(Redmine::Acts::Searchable::InstanceMethods)\n                    \n          cattr_accessor :searchable_options\n          self.searchable_options = options\n\n          if searchable_options[:columns].nil?\n            raise 'No searchable column defined.'\n          elsif !searchable_options[:columns].is_a?(Array)\n            searchable_options[:columns] = [] << searchable_options[:columns]\n          end\n\n          searchable_options[:project_key] ||= \"#{table_name}.project_id\"\n          searchable_options[:date_column] ||= \"#{table_name}.created_at\"\n          searchable_options[:order_column] ||= searchable_options[:date_column]\n          \n          # Permission needed to search this model\n          searchable_options[:permission] = \"view_#{self.name.underscore.pluralize}\".to_sym unless searchable_options.has_key?(:permission)\n          \n          # Should we search custom fields on this model ?\n          searchable_options[:search_custom_fields] = !reflect_on_association(:custom_values).nil?\n          \n          send :include, Redmine::Acts::Searchable::InstanceMethods\n        end\n      end\n\n      module InstanceMethods\n        def self.included(base)\n          base.extend ClassMethods\n        end\n\n        module ClassMethods\n          # Searches the model for the given tokens\n          # projects argument can be either nil (will search all projects), a project or an array of projects\n          # Returns the results and the results count\n          def search(tokens, projects=nil, options={})\n            tokens = [] << tokens unless tokens.is_a?(Array)\n            projects = [] << projects unless projects.nil? || projects.is_a?(Array)\n            \n            find_options = {:include => searchable_options[:include]}\n            find_options[:order] = \"#{searchable_options[:order_column]} \" + (options[:before] ? 'DESC' : 'ASC')\n            \n            limit_options = {}\n            limit_options[:limit] = options[:limit] if options[:limit]\n            if options[:offset]\n              limit_options[:conditions] = \"(#{searchable_options[:date_column]} \" + (options[:before] ? '<' : '>') + \"'#{connection.quoted_date(options[:offset])}')\"\n            end\n            \n            columns = searchable_options[:columns]\n            columns = columns[0..0] if options[:titles_only]\n            \n            token_clauses = columns.collect {|column| \"(LOWER(#{column}) LIKE ?)\"}\n            \n            if !options[:titles_only] && searchable_options[:search_custom_fields]\n              searchable_custom_field_ids = CustomField.find(:all,\n                                                             :select => 'id',\n                                                             :conditions => { :type => \"#{self.name}CustomField\",\n                                                                              :searchable => true }).collect(&:id)\n              if searchable_custom_field_ids.any?\n                custom_field_sql = \"#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}\" +\n                  \" WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?\" +\n                  \" AND #{CustomValue.table_name}.custom_field_id IN (#{searchable_custom_field_ids.join(',')}))\"\n                token_clauses << custom_field_sql\n              end\n            end\n            \n            sql = (['(' + token_clauses.join(' OR ') + ')'] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ')\n            \n            find_options[:conditions] = [sql, * (tokens * token_clauses.size).sort]\n            \n            project_conditions = []\n            project_conditions << (searchable_options[:permission].nil? ? Project.visible_by(User.current) :\n                                                 Project.allowed_to_condition(User.current, searchable_options[:permission]))\n            project_conditions << \"#{searchable_options[:project_key]} IN (#{projects.collect(&:id).join(',')})\" unless projects.nil?\n            \n            results = []\n            results_count = 0\n            \n            with_scope(:find => {:conditions => project_conditions.join(' AND ')}) do\n              with_scope(:find => find_options) do\n                results_count = count(:all)\n                results = find(:all, limit_options)\n              end\n            end\n            [results, results_count]\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts_as_tree/README",
    "content": "acts_as_tree\n============\n\nSpecify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children\nassociation. This requires that you have a foreign key column, which by default is called +parent_id+.\n\n  class Category < ActiveRecord::Base\n    acts_as_tree :order => \"name\"\n  end\n\n  Example:\n  root\n   \\_ child1\n        \\_ subchild1\n        \\_ subchild2\n\n  root      = Category.create(\"name\" => \"root\")\n  child1    = root.children.create(\"name\" => \"child1\")\n  subchild1 = child1.children.create(\"name\" => \"subchild1\")\n\n  root.parent   # => nil\n  child1.parent # => root\n  root.children # => [child1]\n  root.children.first.children.first # => subchild1\n\nCopyright (c) 2007 David Heinemeier Hansson, released under the MIT license  "
  },
  {
    "path": "vendor/plugins/acts_as_tree/Rakefile",
    "content": "require 'rake'\nrequire 'rake/testtask'\nrequire 'rake/rdoctask'\n\ndesc 'Default: run unit tests.'\ntask :default => :test\n\ndesc 'Test acts_as_tree plugin.'\nRake::TestTask.new(:test) do |t|\n  t.libs << 'lib'\n  t.pattern = 'test/**/*_test.rb'\n  t.verbose = true\nend\n\ndesc 'Generate documentation for acts_as_tree plugin.'\nRake::RDocTask.new(:rdoc) do |rdoc|\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title    = 'acts_as_tree'\n  rdoc.options << '--line-numbers' << '--inline-source'\n  rdoc.rdoc_files.include('README')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n"
  },
  {
    "path": "vendor/plugins/acts_as_tree/init.rb",
    "content": "ActiveRecord::Base.send :include, ActiveRecord::Acts::Tree\n"
  },
  {
    "path": "vendor/plugins/acts_as_tree/lib/active_record/acts/tree.rb",
    "content": "module ActiveRecord\n  module Acts\n    module Tree\n      def self.included(base)\n        base.extend(ClassMethods)\n      end\n\n      # Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children\n      # association. This requires that you have a foreign key column, which by default is called +parent_id+.\n      #\n      #   class Category < ActiveRecord::Base\n      #     acts_as_tree :order => \"name\"\n      #   end\n      #\n      #   Example:\n      #   root\n      #    \\_ child1\n      #         \\_ subchild1\n      #         \\_ subchild2\n      #\n      #   root      = Category.create(\"name\" => \"root\")\n      #   child1    = root.children.create(\"name\" => \"child1\")\n      #   subchild1 = child1.children.create(\"name\" => \"subchild1\")\n      #\n      #   root.parent   # => nil\n      #   child1.parent # => root\n      #   root.children # => [child1]\n      #   root.children.first.children.first # => subchild1\n      #\n      # In addition to the parent and children associations, the following instance methods are added to the class\n      # after calling <tt>acts_as_tree</tt>:\n      # * <tt>siblings</tt> - Returns all the children of the parent, excluding the current node (<tt>[subchild2]</tt> when called on <tt>subchild1</tt>)\n      # * <tt>self_and_siblings</tt> - Returns all the children of the parent, including the current node (<tt>[subchild1, subchild2]</tt> when called on <tt>subchild1</tt>)\n      # * <tt>ancestors</tt> - Returns all the ancestors of the current node (<tt>[child1, root]</tt> when called on <tt>subchild2</tt>)\n      # * <tt>root</tt> - Returns the root of the current node (<tt>root</tt> when called on <tt>subchild2</tt>)\n      module ClassMethods\n        # Configuration options are:\n        #\n        # * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)\n        # * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.\n        # * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).\n        def acts_as_tree(options = {})\n          configuration = { :foreign_key => \"parent_id\", :dependent => :destroy, :order => nil, :counter_cache => nil }\n          configuration.update(options) if options.is_a?(Hash)\n\n          belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]\n          has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => configuration[:dependent]\n\n          class_eval <<-EOV\n            include ActiveRecord::Acts::Tree::InstanceMethods\n\n            def self.roots\n              find(:all, :conditions => \"#{configuration[:foreign_key]} IS NULL\", :order => #{configuration[:order].nil? ? \"nil\" : %Q{\"#{configuration[:order]}\"}})\n            end\n\n            def self.root\n              find(:first, :conditions => \"#{configuration[:foreign_key]} IS NULL\", :order => #{configuration[:order].nil? ? \"nil\" : %Q{\"#{configuration[:order]}\"}})\n            end\n          EOV\n        end\n      end\n\n      module InstanceMethods\n        # Returns list of ancestors, starting from parent until root.\n        #\n        #   subchild1.ancestors # => [child1, root]\n        def ancestors\n          node, nodes = self, []\n          nodes << node = node.parent while node.parent\n          nodes\n        end\n\n        # Returns list of descendants.\n        #\n        #   root.descendants # => [child1, subchild1, subchild2]\n        def descendants\n          children + children.collect(&:children).flatten\n        end\n\n        # Returns list of descendants and a reference to the current node.\n        #\n        #   root.self_and_descendants # => [root, child1, subchild1, subchild2]\n        def self_and_descendants\n          [self] + descendants\n        end\n\n        # Returns the root node of the tree.\n        def root\n          node = self\n          node = node.parent while node.parent\n          node\n        end\n\n        # Returns all siblings of the current node.\n        #\n        #   subchild1.siblings # => [subchild2]\n        def siblings\n          self_and_siblings - [self]\n        end\n\n        # Returns all siblings and a reference to the current node.\n        #\n        #   subchild1.self_and_siblings # => [subchild1, subchild2]\n        def self_and_siblings\n          parent ? parent.children : self.class.roots\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts_as_tree/test/abstract_unit.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/acts_as_tree/test/acts_as_tree_test.rb",
    "content": "require 'test/unit'\n\nrequire 'rubygems'\nrequire 'active_record'\n\n$:.unshift File.dirname(__FILE__) + '/../lib'\nrequire File.dirname(__FILE__) + '/../init'\n\nclass Test::Unit::TestCase\n  def assert_queries(num = 1)\n    $query_count = 0\n    yield\n  ensure\n    assert_equal num, $query_count, \"#{$query_count} instead of #{num} queries were executed.\"\n  end\n\n  def assert_no_queries(&block)\n    assert_queries(0, &block)\n  end\nend\n\nActiveRecord::Base.establish_connection(:adapter => \"sqlite3\", :dbfile => \":memory:\")\n\n# AR keeps printing annoying schema statements\n$stdout = StringIO.new\n\ndef setup_db\n  ActiveRecord::Base.logger\n  ActiveRecord::Schema.define(:version => 1) do\n    create_table :mixins do |t|\n      t.column :type, :string\n      t.column :parent_id, :integer\n    end\n  end\nend\n\ndef teardown_db\n  ActiveRecord::Base.connection.tables.each do |table|\n    ActiveRecord::Base.connection.drop_table(table)\n  end\nend\n\nclass Mixin < ActiveRecord::Base\nend\n\nclass TreeMixin < Mixin \n  acts_as_tree :foreign_key => \"parent_id\", :order => \"id\"\nend\n\nclass TreeMixinWithoutOrder < Mixin\n  acts_as_tree :foreign_key => \"parent_id\"\nend\n\nclass RecursivelyCascadedTreeMixin < Mixin\n  acts_as_tree :foreign_key => \"parent_id\"\n  has_one :first_child, :class_name => 'RecursivelyCascadedTreeMixin', :foreign_key => :parent_id\nend\n\nclass TreeTest < Test::Unit::TestCase\n  \n  def setup\n    setup_db\n    @root1 = TreeMixin.create!\n    @root_child1 = TreeMixin.create! :parent_id => @root1.id\n    @child1_child = TreeMixin.create! :parent_id => @root_child1.id\n    @root_child2 = TreeMixin.create! :parent_id => @root1.id\n    @root2 = TreeMixin.create!\n    @root3 = TreeMixin.create!\n  end\n\n  def teardown\n    teardown_db\n  end\n\n  def test_children\n    assert_equal @root1.children, [@root_child1, @root_child2]\n    assert_equal @root_child1.children, [@child1_child]\n    assert_equal @child1_child.children, []\n    assert_equal @root_child2.children, []\n  end\n\n  def test_parent\n    assert_equal @root_child1.parent, @root1\n    assert_equal @root_child1.parent, @root_child2.parent\n    assert_nil @root1.parent\n  end\n\n  def test_delete\n    assert_equal 6, TreeMixin.count\n    @root1.destroy\n    assert_equal 2, TreeMixin.count\n    @root2.destroy\n    @root3.destroy\n    assert_equal 0, TreeMixin.count\n  end\n\n  def test_insert\n    @extra = @root1.children.create\n\n    assert @extra\n\n    assert_equal @extra.parent, @root1\n\n    assert_equal 3, @root1.children.size\n    assert @root1.children.include?(@extra)\n    assert @root1.children.include?(@root_child1)\n    assert @root1.children.include?(@root_child2)\n  end\n\n  def test_ancestors\n    assert_equal [], @root1.ancestors\n    assert_equal [@root1], @root_child1.ancestors\n    assert_equal [@root_child1, @root1], @child1_child.ancestors\n    assert_equal [@root1], @root_child2.ancestors\n    assert_equal [], @root2.ancestors\n    assert_equal [], @root3.ancestors\n  end\n\n  def test_root\n    assert_equal @root1, TreeMixin.root\n    assert_equal @root1, @root1.root\n    assert_equal @root1, @root_child1.root\n    assert_equal @root1, @child1_child.root\n    assert_equal @root1, @root_child2.root\n    assert_equal @root2, @root2.root\n    assert_equal @root3, @root3.root\n  end\n\n  def test_roots\n    assert_equal [@root1, @root2, @root3], TreeMixin.roots\n  end\n\n  def test_siblings\n    assert_equal [@root2, @root3], @root1.siblings\n    assert_equal [@root_child2], @root_child1.siblings\n    assert_equal [], @child1_child.siblings\n    assert_equal [@root_child1], @root_child2.siblings\n    assert_equal [@root1, @root3], @root2.siblings\n    assert_equal [@root1, @root2], @root3.siblings\n  end\n\n  def test_self_and_siblings\n    assert_equal [@root1, @root2, @root3], @root1.self_and_siblings\n    assert_equal [@root_child1, @root_child2], @root_child1.self_and_siblings\n    assert_equal [@child1_child], @child1_child.self_and_siblings\n    assert_equal [@root_child1, @root_child2], @root_child2.self_and_siblings\n    assert_equal [@root1, @root2, @root3], @root2.self_and_siblings\n    assert_equal [@root1, @root2, @root3], @root3.self_and_siblings\n  end           \nend\n\nclass TreeTestWithEagerLoading < Test::Unit::TestCase\n  \n  def setup \n    teardown_db\n    setup_db\n    @root1 = TreeMixin.create!\n    @root_child1 = TreeMixin.create! :parent_id => @root1.id\n    @child1_child = TreeMixin.create! :parent_id => @root_child1.id\n    @root_child2 = TreeMixin.create! :parent_id => @root1.id\n    @root2 = TreeMixin.create!\n    @root3 = TreeMixin.create!\n    \n    @rc1 = RecursivelyCascadedTreeMixin.create!\n    @rc2 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc1.id \n    @rc3 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc2.id\n    @rc4 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc3.id\n  end\n\n  def teardown\n    teardown_db\n  end\n    \n  def test_eager_association_loading\n    roots = TreeMixin.find(:all, :include => :children, :conditions => \"mixins.parent_id IS NULL\", :order => \"mixins.id\")\n    assert_equal [@root1, @root2, @root3], roots                     \n    assert_no_queries do\n      assert_equal 2, roots[0].children.size\n      assert_equal 0, roots[1].children.size\n      assert_equal 0, roots[2].children.size\n    end   \n  end\n  \n  def test_eager_association_loading_with_recursive_cascading_three_levels_has_many\n    root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :children => { :children => :children } }, :order => 'mixins.id')\n    assert_equal @rc4, assert_no_queries { root_node.children.first.children.first.children.first }\n  end\n  \n  def test_eager_association_loading_with_recursive_cascading_three_levels_has_one\n    root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :first_child => { :first_child => :first_child } }, :order => 'mixins.id')\n    assert_equal @rc4, assert_no_queries { root_node.first_child.first_child.first_child }\n  end\n  \n  def test_eager_association_loading_with_recursive_cascading_three_levels_belongs_to\n    leaf_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :parent => { :parent => :parent } }, :order => 'mixins.id DESC')\n    assert_equal @rc1, assert_no_queries { leaf_node.parent.parent.parent }\n  end \nend\n\nclass TreeTestWithoutOrder < Test::Unit::TestCase\n  \n  def setup                               \n    setup_db\n    @root1 = TreeMixinWithoutOrder.create!\n    @root2 = TreeMixinWithoutOrder.create!\n  end\n\n  def teardown\n    teardown_db\n  end\n\n  def test_root\n    assert [@root1, @root2].include?(TreeMixinWithoutOrder.root)\n  end\n  \n  def test_roots\n    assert_equal [], [@root1, @root2] - TreeMixinWithoutOrder.roots\n  end\nend \n"
  },
  {
    "path": "vendor/plugins/acts_as_tree/test/database.yml",
    "content": ""
  },
  {
    "path": "vendor/plugins/acts_as_tree/test/fixtures/mixin.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/acts_as_tree/test/fixtures/mixins.yml",
    "content": ""
  },
  {
    "path": "vendor/plugins/acts_as_tree/test/schema.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/acts_as_versioned/CHANGELOG",
    "content": "*SVN* (version numbers are overrated)\n\n* (5 Oct 2006) Allow customization of #versions association options [Dan Peterson]\n\n*0.5.1*\n\n* (8 Aug 2006) Versioned models now belong to the unversioned model.  @article_version.article.class => Article [Aslak Hellesoy]\n\n*0.5* # do versions even matter for plugins?\n\n* (21 Apr 2006) Added without_locking and without_revision methods.\n\n  Foo.without_revision do\n    @foo.update_attributes ...\n  end\n\n*0.4*\n\n* (28 March 2006) Rename non_versioned_fields to non_versioned_columns (old one is kept for compatibility).\n* (28 March 2006) Made explicit documentation note that string column names are required for non_versioned_columns.\n\n*0.3.1*\n\n* (7 Jan 2006) explicitly set :foreign_key option for the versioned model's belongs_to assocation for STI [Caged]\n* (7 Jan 2006) added tests to prove has_many :through joins work\n\n*0.3*\n\n* (2 Jan 2006) added ability to share a mixin with versioned class\n* (2 Jan 2006) changed the dynamic version model to MyModel::Version\n\n*0.2.4*\n\n* (27 Nov 2005) added note about possible destructive behavior of if_changed? [Michael Schuerig]\n\n*0.2.3*\n\n* (12 Nov 2005) fixed bug with old behavior of #blank? [Michael Schuerig]\n* (12 Nov 2005) updated tests to use ActiveRecord Schema\n\n*0.2.2*\n\n* (3 Nov 2005) added documentation note to #acts_as_versioned [Martin Jul]\n\n*0.2.1*\n\n* (6 Oct 2005) renamed dirty? to changed? to keep it uniform.  it was aliased to keep it backwards compatible.\n\n*0.2* \n\n* (6 Oct 2005)  added find_versions and find_version class methods.\n\n* (6 Oct 2005)  removed transaction from create_versioned_table().  \n  this way you can specify your own transaction around a group of operations.\n\n* (30 Sep 2005) fixed bug where find_versions() would order by 'version' twice. (found by Joe Clark)\n\n* (26 Sep 2005) added :sequence_name option to acts_as_versioned to set the sequence name on the versioned model\n\n*0.1.3* (18 Sep 2005)\n\n* First RubyForge release\n\n*0.1.2*\n\n* check if module is already included when acts_as_versioned is called\n\n*0.1.1*\n\n* Adding tests and rdocs\n\n*0.1* \n\n* Initial transfer from Rails ticket: http://dev.rubyonrails.com/ticket/1974"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/MIT-LICENSE",
    "content": "Copyright (c) 2005 Rick Olson\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "vendor/plugins/acts_as_versioned/README",
    "content": "= acts_as_versioned\n\nThis library adds simple versioning to an ActiveRecord module.  ActiveRecord is required.\n\n== Resources\n\nInstall\n\n* gem install acts_as_versioned\n\nRubyforge project\n\n* http://rubyforge.org/projects/ar-versioned\n\nRDocs\n\n* http://ar-versioned.rubyforge.org\n\nSubversion\n\n* http://techno-weenie.net/svn/projects/acts_as_versioned\n\nCollaboa\n\n* http://collaboa.techno-weenie.net/repository/browse/acts_as_versioned\n\nSpecial thanks to Dreamer on ##rubyonrails for help in early testing.  His ServerSideWiki (http://serversidewiki.com) \nwas the first project to use acts_as_versioned <em>in the wild</em>."
  },
  {
    "path": "vendor/plugins/acts_as_versioned/RUNNING_UNIT_TESTS",
    "content": "== Creating the test database\n\nThe default name for the test databases is \"activerecord_versioned\". If you \nwant to use another database name then be sure to update the connection \nadapter setups you want to test with in test/connections/<your database>/connection.rb. \nWhen you have the database online, you can import the fixture tables with \nthe test/fixtures/db_definitions/*.sql files.\n\nMake sure that you create database objects with the same user that you specified in i\nconnection.rb otherwise (on Postgres, at least) tests for default values will fail.\n\n== Running with Rake\n\nThe easiest way to run the unit tests is through Rake. The default task runs\nthe entire test suite for all the adapters. You can also run the suite on just\none adapter by using the tasks test_mysql_ruby, test_ruby_mysql, test_sqlite, \nor test_postresql. For more information, checkout the full array of rake tasks with \"rake -T\"\n\nRake can be found at http://rake.rubyforge.org\n\n== Running by hand\n\nUnit tests are located in test directory. If you only want to run a single test suite, \nor don't want to bother with Rake, you can do so with something like:\n\n   cd test; ruby -I \"connections/native_mysql\" base_test.rb\n   \nThat'll run the base suite using the MySQL-Ruby adapter. Change the adapter\nand test suite name as needed.\n\n== Faster tests\n\nIf you are using a database that supports transactions, you can set the\n\"AR_TX_FIXTURES\" environment variable to \"yes\" to use transactional fixtures.\nThis gives a very large speed boost. With rake:\n\n  rake AR_TX_FIXTURES=yes\n\nOr, by hand:\n\n  AR_TX_FIXTURES=yes ruby -I connections/native_sqlite3 base_test.rb\n"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/Rakefile",
    "content": "require 'rubygems'\n\nGem::manage_gems\n\nrequire 'rake/rdoctask'\nrequire 'rake/packagetask'\nrequire 'rake/gempackagetask'\nrequire 'rake/testtask'\nrequire 'rake/contrib/rubyforgepublisher'\n\nPKG_NAME           = 'acts_as_versioned'\nPKG_VERSION        = '0.3.1'\nPKG_FILE_NAME      = \"#{PKG_NAME}-#{PKG_VERSION}\"\nPROD_HOST          = \"technoweenie@bidwell.textdrive.com\"\nRUBY_FORGE_PROJECT = 'ar-versioned'\nRUBY_FORGE_USER    = 'technoweenie'\n\ndesc 'Default: run unit tests.'\ntask :default => :test\n\ndesc 'Test the calculations plugin.'\nRake::TestTask.new(:test) do |t|\n  t.libs << 'lib'\n  t.pattern = 'test/**/*_test.rb'\n  t.verbose = true\nend\n\ndesc 'Generate documentation for the calculations plugin.'\nRake::RDocTask.new(:rdoc) do |rdoc|\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title    = \"#{PKG_NAME} -- Simple versioning with active record models\"\n  rdoc.options << '--line-numbers --inline-source'\n  rdoc.rdoc_files.include('README', 'CHANGELOG', 'RUNNING_UNIT_TESTS')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n\nspec = Gem::Specification.new do |s|\n  s.name            = PKG_NAME\n  s.version         = PKG_VERSION\n  s.platform        = Gem::Platform::RUBY\n  s.summary         = \"Simple versioning with active record models\"\n  s.files           = FileList[\"{lib,test}/**/*\"].to_a + %w(README MIT-LICENSE CHANGELOG RUNNING_UNIT_TESTS)\n  s.files.delete      \"acts_as_versioned_plugin.sqlite.db\"\n  s.files.delete      \"acts_as_versioned_plugin.sqlite3.db\"\n  s.files.delete      \"test/debug.log\"\n  s.require_path    = 'lib'\n  s.autorequire     = 'acts_as_versioned'\n  s.has_rdoc        = true\n  s.test_files      = Dir['test/**/*_test.rb']\n  s.add_dependency    'activerecord', '>= 1.10.1'\n  s.add_dependency    'activesupport', '>= 1.1.1'\n  s.author          = \"Rick Olson\"\n  s.email           = \"technoweenie@gmail.com\"\n  s.homepage        = \"http://techno-weenie.net\"\nend\n\nRake::GemPackageTask.new(spec) do |pkg|\n  pkg.need_tar = true\nend\n\ndesc \"Publish the API documentation\"\ntask :pdoc => [:rdoc] do\n  Rake::RubyForgePublisher.new(RUBY_FORGE_PROJECT, RUBY_FORGE_USER).upload\nend\n\ndesc 'Publish the gem and API docs'\ntask :publish => [:pdoc, :rubyforge_upload]\n\ndesc \"Publish the release files to RubyForge.\"\ntask :rubyforge_upload => :package do\n  files = %w(gem tgz).map { |ext| \"pkg/#{PKG_FILE_NAME}.#{ext}\" }\n\n  if RUBY_FORGE_PROJECT then\n    require 'net/http'\n    require 'open-uri'\n\n    project_uri = \"http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/\"\n    project_data = open(project_uri) { |data| data.read }\n    group_id = project_data[/[?&]group_id=(\\d+)/, 1]\n    raise \"Couldn't get group id\" unless group_id\n\n    # This echos password to shell which is a bit sucky\n    if ENV[\"RUBY_FORGE_PASSWORD\"]\n      password = ENV[\"RUBY_FORGE_PASSWORD\"]\n    else\n      print \"#{RUBY_FORGE_USER}@rubyforge.org's password: \"\n      password = STDIN.gets.chomp\n    end\n\n    login_response = Net::HTTP.start(\"rubyforge.org\", 80) do |http|\n      data = [\n        \"login=1\",\n        \"form_loginname=#{RUBY_FORGE_USER}\",\n        \"form_pw=#{password}\"\n      ].join(\"&\")\n      http.post(\"/account/login.php\", data)\n    end\n\n    cookie = login_response[\"set-cookie\"]\n    raise \"Login failed\" unless cookie\n    headers = { \"Cookie\" => cookie }\n\n    release_uri = \"http://rubyforge.org/frs/admin/?group_id=#{group_id}\"\n    release_data = open(release_uri, headers) { |data| data.read }\n    package_id = release_data[/[?&]package_id=(\\d+)/, 1]\n    raise \"Couldn't get package id\" unless package_id\n\n    first_file = true\n    release_id = \"\"\n\n    files.each do |filename|\n      basename  = File.basename(filename)\n      file_ext  = File.extname(filename)\n      file_data = File.open(filename, \"rb\") { |file| file.read }\n\n      puts \"Releasing #{basename}...\"\n\n      release_response = Net::HTTP.start(\"rubyforge.org\", 80) do |http|\n        release_date = Time.now.strftime(\"%Y-%m-%d %H:%M\")\n        type_map = {\n          \".zip\"    => \"3000\",\n          \".tgz\"    => \"3110\",\n          \".gz\"     => \"3110\",\n          \".gem\"    => \"1400\"\n        }; type_map.default = \"9999\"\n        type = type_map[file_ext]\n        boundary = \"rubyqMY6QN9bp6e4kS21H4y0zxcvoor\"\n\n        query_hash = if first_file then\n          {\n            \"group_id\" => group_id,\n            \"package_id\" => package_id,\n            \"release_name\" => PKG_FILE_NAME,\n            \"release_date\" => release_date,\n            \"type_id\" => type,\n            \"processor_id\" => \"8000\", # Any\n            \"release_notes\" => \"\",\n            \"release_changes\" => \"\",\n            \"preformatted\" => \"1\",\n            \"submit\" => \"1\"\n          }\n        else\n          {\n            \"group_id\" => group_id,\n            \"release_id\" => release_id,\n            \"package_id\" => package_id,\n            \"step2\" => \"1\",\n            \"type_id\" => type,\n            \"processor_id\" => \"8000\", # Any\n            \"submit\" => \"Add This File\"\n          }\n        end\n\n        query = \"?\" + query_hash.map do |(name, value)|\n          [name, URI.encode(value)].join(\"=\")\n        end.join(\"&\")\n\n        data = [\n          \"--\" + boundary,\n          \"Content-Disposition: form-data; name=\\\"userfile\\\"; filename=\\\"#{basename}\\\"\",\n          \"Content-Type: application/octet-stream\",\n          \"Content-Transfer-Encoding: binary\",\n          \"\", file_data, \"\"\n          ].join(\"\\x0D\\x0A\")\n\n        release_headers = headers.merge(\n          \"Content-Type\" => \"multipart/form-data; boundary=#{boundary}\"\n        )\n\n        target = first_file ? \"/frs/admin/qrs.php\" : \"/frs/admin/editrelease.php\"\n        http.post(target + query, data, release_headers)\n      end\n\n      if first_file then\n        release_id = release_response.body[/release_id=(\\d+)/, 1]\n        raise(\"Couldn't get release id\") unless release_id\n      end\n\n      first_file = false\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/init.rb",
    "content": "require 'acts_as_versioned'"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb",
    "content": "# Copyright (c) 2005 Rick Olson\n# \n# Permission is hereby granted, free of charge, to any person obtaining\n# a copy of this software and associated documentation files (the\n# \"Software\"), to deal in the Software without restriction, including\n# without limitation the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the Software, and to\n# permit persons to whom the Software is furnished to do so, subject to\n# the following conditions:\n# \n# The above copyright notice and this permission notice shall be\n# included in all copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nmodule ActiveRecord #:nodoc:\n  module Acts #:nodoc:\n    # Specify this act if you want to save a copy of the row in a versioned table.  This assumes there is a \n    # versioned table ready and that your model has a version field.  This works with optimistic locking if the lock_version\n    # column is present as well.\n    #\n    # The class for the versioned model is derived the first time it is seen. Therefore, if you change your database schema you have to restart\n    # your container for the changes to be reflected. In development mode this usually means restarting WEBrick.\n    #\n    #   class Page < ActiveRecord::Base\n    #     # assumes pages_versions table\n    #     acts_as_versioned\n    #   end\n    #\n    # Example:\n    #\n    #   page = Page.create(:title => 'hello world!')\n    #   page.version       # => 1\n    #\n    #   page.title = 'hello world'\n    #   page.save\n    #   page.version       # => 2\n    #   page.versions.size # => 2\n    #\n    #   page.revert_to(1)  # using version number\n    #   page.title         # => 'hello world!'\n    #\n    #   page.revert_to(page.versions.last) # using versioned instance\n    #   page.title         # => 'hello world'\n    #\n    #   page.versions.earliest # efficient query to find the first version\n    #   page.versions.latest   # efficient query to find the most recently created version\n    #\n    #\n    # Simple Queries to page between versions\n    #\n    #   page.versions.before(version) \n    #   page.versions.after(version)\n    #\n    # Access the previous/next versions from the versioned model itself\n    #\n    #   version = page.versions.latest\n    #   version.previous # go back one version\n    #   version.next     # go forward one version\n    #\n    # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options\n    module Versioned\n      CALLBACKS = [:set_new_version, :save_version_on_create, :save_version?, :clear_altered_attributes]\n      def self.included(base) # :nodoc:\n        base.extend ClassMethods\n      end\n\n      module ClassMethods\n        # == Configuration options\n        #\n        # * <tt>class_name</tt> - versioned model class name (default: PageVersion in the above example)\n        # * <tt>table_name</tt> - versioned model table name (default: page_versions in the above example)\n        # * <tt>foreign_key</tt> - foreign key used to relate the versioned model to the original model (default: page_id in the above example)\n        # * <tt>inheritance_column</tt> - name of the column to save the model's inheritance_column value for STI.  (default: versioned_type)\n        # * <tt>version_column</tt> - name of the column in the model that keeps the version number (default: version)\n        # * <tt>sequence_name</tt> - name of the custom sequence to be used by the versioned model.\n        # * <tt>limit</tt> - number of revisions to keep, defaults to unlimited\n        # * <tt>if</tt> - symbol of method to check before saving a new version.  If this method returns false, a new version is not saved.\n        #   For finer control, pass either a Proc or modify Model#version_condition_met?\n        #\n        #     acts_as_versioned :if => Proc.new { |auction| !auction.expired? }\n        #\n        #   or...\n        #\n        #     class Auction\n        #       def version_condition_met? # totally bypasses the <tt>:if</tt> option\n        #         !expired?\n        #       end\n        #     end\n        #\n        # * <tt>if_changed</tt> - Simple way of specifying attributes that are required to be changed before saving a model.  This takes\n        #   either a symbol or array of symbols.  WARNING - This will attempt to overwrite any attribute setters you may have.\n        #   Use this instead if you want to write your own attribute setters (and ignore if_changed):\n        # \n        #     def name=(new_name)\n        #       write_changed_attribute :name, new_name\n        #     end\n        #\n        # * <tt>extend</tt> - Lets you specify a module to be mixed in both the original and versioned models.  You can also just pass a block\n        #   to create an anonymous mixin:\n        #\n        #     class Auction\n        #       acts_as_versioned do\n        #         def started?\n        #           !started_at.nil?\n        #         end\n        #       end\n        #     end\n        #\n        #   or...\n        #\n        #     module AuctionExtension\n        #       def started?\n        #         !started_at.nil?\n        #       end\n        #     end\n        #     class Auction\n        #       acts_as_versioned :extend => AuctionExtension\n        #     end\n        #\n        #  Example code:\n        #\n        #    @auction = Auction.find(1)\n        #    @auction.started?\n        #    @auction.versions.first.started?\n        #\n        # == Database Schema\n        #\n        # The model that you're versioning needs to have a 'version' attribute. The model is versioned \n        # into a table called #{model}_versions where the model name is singlular. The _versions table should \n        # contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field.\n        #\n        # A lock_version field is also accepted if your model uses Optimistic Locking.  If your table uses Single Table inheritance,\n        # then that field is reflected in the versioned model as 'versioned_type' by default.\n        #\n        # Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table \n        # method, perfect for a migration.  It will also create the version column if the main model does not already have it.\n        #\n        #   class AddVersions < ActiveRecord::Migration\n        #     def self.up\n        #       # create_versioned_table takes the same options hash\n        #       # that create_table does\n        #       Post.create_versioned_table\n        #     end\n        # \n        #     def self.down\n        #       Post.drop_versioned_table\n        #     end\n        #   end\n        # \n        # == Changing What Fields Are Versioned\n        #\n        # By default, acts_as_versioned will version all but these fields: \n        # \n        #   [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column]\n        #\n        # You can add or change those by modifying #non_versioned_columns.  Note that this takes strings and not symbols.\n        #\n        #   class Post < ActiveRecord::Base\n        #     acts_as_versioned\n        #     self.non_versioned_columns << 'comments_count'\n        #   end\n        # \n        def acts_as_versioned(options = {}, &extension)\n          # don't allow multiple calls\n          return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods)\n\n          send :include, ActiveRecord::Acts::Versioned::ActMethods\n\n          cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column, \n            :version_column, :max_version_limit, :track_altered_attributes, :version_condition, :version_sequence_name, :non_versioned_columns,\n            :version_association_options\n\n          # legacy\n          alias_method :non_versioned_fields,  :non_versioned_columns\n          alias_method :non_versioned_fields=, :non_versioned_columns=\n\n          class << self\n            alias_method :non_versioned_fields,  :non_versioned_columns\n            alias_method :non_versioned_fields=, :non_versioned_columns=\n          end\n\n          send :attr_accessor, :altered_attributes\n\n          self.versioned_class_name         = options[:class_name]  || \"Version\"\n          self.versioned_foreign_key        = options[:foreign_key] || self.to_s.foreign_key\n          self.versioned_table_name         = options[:table_name]  || \"#{table_name_prefix}#{base_class.name.demodulize.underscore}_versions#{table_name_suffix}\"\n          self.versioned_inheritance_column = options[:inheritance_column] || \"versioned_#{inheritance_column}\"\n          self.version_column               = options[:version_column]     || 'version'\n          self.version_sequence_name        = options[:sequence_name]\n          self.max_version_limit            = options[:limit].to_i\n          self.version_condition            = options[:if] || true\n          self.non_versioned_columns        = [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column]\n          self.version_association_options  = {\n                                                :class_name  => \"#{self.to_s}::#{versioned_class_name}\",\n                                                :foreign_key => versioned_foreign_key,\n                                                :dependent   => :delete_all\n                                              }.merge(options[:association_options] || {})\n\n          if block_given?\n            extension_module_name = \"#{versioned_class_name}Extension\"\n            silence_warnings do\n              self.const_set(extension_module_name, Module.new(&extension))\n            end\n\n            options[:extend] = self.const_get(extension_module_name)\n          end\n\n          class_eval do\n            has_many :versions, version_association_options do\n              # finds earliest version of this record\n              def earliest\n                @earliest ||= find(:first, :order => 'version')\n              end\n\n              # find latest version of this record\n              def latest\n                @latest ||= find(:first, :order => 'version desc')\n              end\n            end\n            before_save  :set_new_version\n            after_create :save_version_on_create\n            after_update :save_version\n            after_save   :clear_old_versions\n            after_save   :clear_altered_attributes\n\n            unless options[:if_changed].nil?\n              self.track_altered_attributes = true\n              options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array)\n              options[:if_changed].each do |attr_name|\n                define_method(\"#{attr_name}=\") do |value|\n                  write_changed_attribute attr_name, value\n                end\n              end\n            end\n\n            include options[:extend] if options[:extend].is_a?(Module)\n          end\n\n          # create the dynamic versioned model\n          const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do\n            def self.reloadable? ; false ; end\n            # find first version before the given version\n            def self.before(version)\n              find :first, :order => 'version desc',\n                :conditions => [\"#{original_class.versioned_foreign_key} = ? and version < ?\", version.send(original_class.versioned_foreign_key), version.version]\n            end\n\n            # find first version after the given version.\n            def self.after(version)\n              find :first, :order => 'version',\n                :conditions => [\"#{original_class.versioned_foreign_key} = ? and version > ?\", version.send(original_class.versioned_foreign_key), version.version]\n            end\n\n            def previous\n              self.class.before(self)\n            end\n\n            def next\n              self.class.after(self)\n            end\n\n            def versions_count\n              page.version\n            end\n          end\n\n          versioned_class.cattr_accessor :original_class\n          versioned_class.original_class = self\n          versioned_class.set_table_name versioned_table_name\n          versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym, \n            :class_name  => \"::#{self.to_s}\", \n            :foreign_key => versioned_foreign_key\n          versioned_class.send :include, options[:extend]         if options[:extend].is_a?(Module)\n          versioned_class.set_sequence_name version_sequence_name if version_sequence_name\n        end\n      end\n\n      module ActMethods\n        def self.included(base) # :nodoc:\n          base.extend ClassMethods\n        end\n\n        # Finds a specific version of this record\n        def find_version(version = nil)\n          self.class.find_version(id, version)\n        end\n\n        # Saves a version of the model if applicable\n        def save_version\n          save_version_on_create if save_version?\n        end\n\n        # Saves a version of the model in the versioned table.  This is called in the after_save callback by default\n        def save_version_on_create\n          rev = self.class.versioned_class.new\n          self.clone_versioned_model(self, rev)\n          rev.version = send(self.class.version_column)\n          rev.send(\"#{self.class.versioned_foreign_key}=\", self.id)\n          rev.save\n        end\n\n        # Clears old revisions if a limit is set with the :limit option in <tt>acts_as_versioned</tt>.\n        # Override this method to set your own criteria for clearing old versions.\n        def clear_old_versions\n          return if self.class.max_version_limit == 0\n          excess_baggage = send(self.class.version_column).to_i - self.class.max_version_limit\n          if excess_baggage > 0\n            sql = \"DELETE FROM #{self.class.versioned_table_name} WHERE version <= #{excess_baggage} AND #{self.class.versioned_foreign_key} = #{self.id}\"\n            self.class.versioned_class.connection.execute sql\n          end\n        end\n\n        def versions_count\n          version\n        end\n\n        # Reverts a model to a given version.  Takes either a version number or an instance of the versioned model\n        def revert_to(version)\n          if version.is_a?(self.class.versioned_class)\n            return false unless version.send(self.class.versioned_foreign_key) == self.id and !version.new_record?\n          else\n            return false unless version = versions.find_by_version(version)\n          end\n          self.clone_versioned_model(version, self)\n          self.send(\"#{self.class.version_column}=\", version.version)\n          true\n        end\n\n        # Reverts a model to a given version and saves the model.\n        # Takes either a version number or an instance of the versioned model\n        def revert_to!(version)\n          revert_to(version) ? save_without_revision : false\n        end\n\n        # Temporarily turns off Optimistic Locking while saving.  Used when reverting so that a new version is not created.\n        def save_without_revision\n          save_without_revision!\n          true\n        rescue\n          false\n        end\n\n        def save_without_revision!\n          without_locking do\n            without_revision do\n              save!\n            end\n          end\n        end\n\n        # Returns an array of attribute keys that are versioned.  See non_versioned_columns\n        def versioned_attributes\n          self.attributes.keys.select { |k| !self.class.non_versioned_columns.include?(k) }\n        end\n\n        # If called with no parameters, gets whether the current model has changed and needs to be versioned.\n        # If called with a single parameter, gets whether the parameter has changed.\n        def changed?(attr_name = nil)\n          attr_name.nil? ?\n            (!self.class.track_altered_attributes || (altered_attributes && altered_attributes.length > 0)) :\n            (altered_attributes && altered_attributes.include?(attr_name.to_s))\n        end\n\n        # keep old dirty? method\n        alias_method :dirty?, :changed?\n\n        # Clones a model.  Used when saving a new version or reverting a model's version.\n        def clone_versioned_model(orig_model, new_model)\n          self.versioned_attributes.each do |key|\n            new_model.send(\"#{key}=\", orig_model.send(key)) if orig_model.has_attribute?(key)\n          end\n\n          if orig_model.is_a?(self.class.versioned_class)\n            new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column]\n          elsif new_model.is_a?(self.class.versioned_class)\n            new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column]\n          end\n        end\n\n        # Checks whether a new version shall be saved or not.  Calls <tt>version_condition_met?</tt> and <tt>changed?</tt>.\n        def save_version?\n          version_condition_met? && changed?\n        end\n\n        # Checks condition set in the :if option to check whether a revision should be created or not.  Override this for\n        # custom version condition checking.\n        def version_condition_met?\n          case\n          when version_condition.is_a?(Symbol)\n            send(version_condition)\n          when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1)\n            version_condition.call(self)\n          else\n            version_condition\n          end\n        end\n\n        # Executes the block with the versioning callbacks disabled.\n        #\n        #   @foo.without_revision do\n        #     @foo.save\n        #   end\n        #\n        def without_revision(&block)\n          self.class.without_revision(&block)\n        end\n\n        # Turns off optimistic locking for the duration of the block\n        #\n        #   @foo.without_locking do\n        #     @foo.save\n        #   end\n        #\n        def without_locking(&block)\n          self.class.without_locking(&block)\n        end\n\n        def empty_callback() end #:nodoc:\n\n        protected\n          # sets the new version before saving, unless you're using optimistic locking.  In that case, let it take care of the version.\n          def set_new_version\n            self.send(\"#{self.class.version_column}=\", self.next_version) if new_record? || (!locking_enabled? && save_version?)\n          end\n\n          # Gets the next available version for the current record, or 1 for a new record\n          def next_version\n            return 1 if new_record?\n            (versions.calculate(:max, :version) || 0) + 1\n          end\n\n          # clears current changed attributes.  Called after save.\n          def clear_altered_attributes\n            self.altered_attributes = []\n          end\n\n          def write_changed_attribute(attr_name, attr_value)\n            # Convert to db type for comparison. Avoids failing Float<=>String comparisons.\n            attr_value_for_db = self.class.columns_hash[attr_name.to_s].type_cast(attr_value)\n            (self.altered_attributes ||= []) << attr_name.to_s unless self.changed?(attr_name) || self.send(attr_name) == attr_value_for_db\n            write_attribute(attr_name, attr_value_for_db)\n          end\n\n        module ClassMethods\n          # Finds a specific version of a specific row of this model\n          def find_version(id, version = nil)\n            return find(id) unless version\n\n            conditions = [\"#{versioned_foreign_key} = ? AND version = ?\", id, version]\n            options = { :conditions => conditions, :limit => 1 }\n\n            if result = find_versions(id, options).first\n              result\n            else\n              raise RecordNotFound, \"Couldn't find #{name} with ID=#{id} and VERSION=#{version}\"\n            end\n          end\n\n          # Finds versions of a specific model.  Takes an options hash like <tt>find</tt>\n          def find_versions(id, options = {})\n            versioned_class.find :all, {\n              :conditions => [\"#{versioned_foreign_key} = ?\", id],\n              :order      => 'version' }.merge(options)\n          end\n\n          # Returns an array of columns that are versioned.  See non_versioned_columns\n          def versioned_columns\n            self.columns.select { |c| !non_versioned_columns.include?(c.name) }\n          end\n\n          # Returns an instance of the dynamic versioned model\n          def versioned_class\n            const_get versioned_class_name\n          end\n\n          # Rake migration task to create the versioned table using options passed to acts_as_versioned\n          def create_versioned_table(create_table_options = {})\n            # create version column in main table if it does not exist\n            if !self.content_columns.find { |c| %w(version lock_version).include? c.name }\n              self.connection.add_column table_name, :version, :integer\n            end\n\n            self.connection.create_table(versioned_table_name, create_table_options) do |t|\n              t.column versioned_foreign_key, :integer\n              t.column :version, :integer\n            end\n\n            updated_col = nil\n            self.versioned_columns.each do |col| \n              updated_col = col if !updated_col && %(updated_at updated_at).include?(col.name)\n              self.connection.add_column versioned_table_name, col.name, col.type, \n                :limit => col.limit, \n                :default => col.default,\n                :scale => col.scale,\n                :precision => col.precision\n            end\n\n            if type_col = self.columns_hash[inheritance_column]\n              self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type, \n                :limit => type_col.limit, \n                :default => type_col.default,\n                :scale => type_col.scale,\n                :precision => type_col.precision\n            end\n\n            if updated_col.nil?\n              self.connection.add_column versioned_table_name, :updated_at, :timestamp\n            end\n          end\n\n          # Rake migration task to drop the versioned table\n          def drop_versioned_table\n            self.connection.drop_table versioned_table_name\n          end\n\n          # Executes the block with the versioning callbacks disabled.\n          #\n          #   Foo.without_revision do\n          #     @foo.save\n          #   end\n          #\n          def without_revision(&block)\n            class_eval do \n              CALLBACKS.each do |attr_name|\n                alias_method \"orig_#{attr_name}\".to_sym, attr_name\n                alias_method attr_name, :empty_callback\n              end\n            end\n            block.call\n          ensure\n            class_eval do \n              CALLBACKS.each do |attr_name|\n                alias_method attr_name, \"orig_#{attr_name}\".to_sym\n              end\n            end\n          end\n\n          # Turns off optimistic locking for the duration of the block\n          #\n          #   Foo.without_locking do\n          #     @foo.save\n          #   end\n          #\n          def without_locking(&block)\n            current = ActiveRecord::Base.lock_optimistically\n            ActiveRecord::Base.lock_optimistically = false if current\n            result = block.call\n            ActiveRecord::Base.lock_optimistically = true if current\n            result\n          end\n        end\n      end\n    end\n  end\nend\n\nActiveRecord::Base.send :include, ActiveRecord::Acts::Versioned"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/abstract_unit.rb",
    "content": "$:.unshift(File.dirname(__FILE__) + '/../../../rails/activesupport/lib')\n$:.unshift(File.dirname(__FILE__) + '/../../../rails/activerecord/lib')\n$:.unshift(File.dirname(__FILE__) + '/../lib')\nrequire 'test/unit'\nbegin\n  require 'active_support'\n  require 'active_record'\n  require 'active_record/fixtures'\nrescue LoadError\n  require 'rubygems'\n  retry\nend\nrequire 'acts_as_versioned'\n\nconfig = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))\nActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + \"/debug.log\")\nActiveRecord::Base.configurations = {'test' => config[ENV['DB'] || 'sqlite3']}\nActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])\n\nload(File.dirname(__FILE__) + \"/schema.rb\")\n\n# set up custom sequence on widget_versions for DBs that support sequences\nif ENV['DB'] == 'postgresql'\n  ActiveRecord::Base.connection.execute \"DROP SEQUENCE widgets_seq;\" rescue nil\n  ActiveRecord::Base.connection.remove_column :widget_versions, :id\n  ActiveRecord::Base.connection.execute \"CREATE SEQUENCE widgets_seq START 101;\"\n  ActiveRecord::Base.connection.execute \"ALTER TABLE widget_versions ADD COLUMN id INTEGER PRIMARY KEY DEFAULT nextval('widgets_seq');\"\nend\n\nTest::Unit::TestCase.fixture_path = File.dirname(__FILE__) + \"/fixtures/\"\n$:.unshift(Test::Unit::TestCase.fixture_path)\n\nclass Test::Unit::TestCase #:nodoc:\n  # Turn off transactional fixtures if you're working with MyISAM tables in MySQL\n  self.use_transactional_fixtures = true\n  \n  # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)\n  self.use_instantiated_fixtures  = false\n\n  # Add more helper methods to be used by all tests here...\nend"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/database.yml",
    "content": "sqlite:\n  :adapter: sqlite\n  :dbfile: acts_as_versioned_plugin.sqlite.db\nsqlite3:\n  :adapter: sqlite3\n  :dbfile: acts_as_versioned_plugin.sqlite3.db\npostgresql:\n  :adapter: postgresql\n  :username: postgres\n  :password: postgres\n  :database: acts_as_versioned_plugin_test\n  :min_messages: ERROR\nmysql:\n  :adapter: mysql\n  :host: localhost\n  :username: rails\n  :password:\n  :database: acts_as_versioned_plugin_test"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/fixtures/authors.yml",
    "content": "caged:\n  id: 1\n  name: caged\nmly:\n  id: 2\n  name: mly"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/fixtures/landmark.rb",
    "content": "class Landmark < ActiveRecord::Base\n  acts_as_versioned :if_changed => [ :name, :longitude, :latitude ]\nend\n"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/fixtures/landmark_versions.yml",
    "content": "washington:\n    id: 1\n    landmark_id: 1\n    version: 1\n    name: Washington, D.C.\n    latitude: 38.895\n    longitude: -77.036667\n"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/fixtures/landmarks.yml",
    "content": "washington:\n    id: 1\n    name: Washington, D.C.\n    latitude: 38.895\n    longitude: -77.036667\n    version: 1\n"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/fixtures/locked_pages.yml",
    "content": "welcome:\n  id: 1\n  title: Welcome to the weblog\n  lock_version: 24\n  type: LockedPage\nthinking:\n  id: 2\n  title: So I was thinking\n  lock_version: 24\n  type: SpecialLockedPage\n"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/fixtures/locked_pages_revisions.yml",
    "content": "welcome_1:\n  id: 1\n  page_id: 1\n  title: Welcome to the weblg\n  version: 23\n  version_type: LockedPage\n\nwelcome_2:\n  id: 2\n  page_id: 1\n  title: Welcome to the weblog\n  version: 24\n  version_type: LockedPage\n\nthinking_1:\n  id: 3\n  page_id: 2\n  title: So I was thinking!!!\n  version: 23\n  version_type: SpecialLockedPage\n\nthinking_2:\n  id: 4\n  page_id: 2\n  title: So I was thinking\n  version: 24\n  version_type: SpecialLockedPage\n"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/fixtures/migrations/1_add_versioned_tables.rb",
    "content": "class AddVersionedTables < ActiveRecord::Migration\n  def self.up\n    create_table(\"things\") do |t|\n      t.column :title, :text\n    end\n    Thing.create_versioned_table\n  end\n  \n  def self.down\n    Thing.drop_versioned_table\n    drop_table \"things\" rescue nil\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/fixtures/page.rb",
    "content": "class Page < ActiveRecord::Base\n  belongs_to :author\n  has_many   :authors,  :through => :versions, :order => 'name'\n  belongs_to :revisor,  :class_name => 'Author'\n  has_many   :revisors, :class_name => 'Author', :through => :versions, :order => 'name'\n  acts_as_versioned :if => :feeling_good? do\n    def self.included(base)\n      base.cattr_accessor :feeling_good\n      base.feeling_good = true\n      base.belongs_to :author\n      base.belongs_to :revisor, :class_name => 'Author'\n    end\n    \n    def feeling_good?\n      @@feeling_good == true\n    end\n  end\nend\n\nmodule LockedPageExtension\n  def hello_world\n    'hello_world'\n  end\nend\n\nclass LockedPage < ActiveRecord::Base\n  acts_as_versioned \\\n    :inheritance_column => :version_type, \n    :foreign_key        => :page_id, \n    :table_name         => :locked_pages_revisions, \n    :class_name         => 'LockedPageRevision',\n    :version_column     => :lock_version,\n    :limit              => 2,\n    :if_changed         => :title,\n    :extend             => LockedPageExtension\nend\n\nclass SpecialLockedPage < LockedPage\nend\n\nclass Author < ActiveRecord::Base\n  has_many :pages\nend"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/fixtures/page_versions.yml",
    "content": "welcome_2:\n  id: 1\n  page_id: 1\n  title: Welcome to the weblog\n  body: Such a lovely day\n  version: 24\n  author_id: 1\n  revisor_id: 1\nwelcome_1:\n  id: 2\n  page_id: 1\n  title: Welcome to the weblg\n  body: Such a lovely day\n  version: 23\n  author_id: 2\n  revisor_id: 2\n"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/fixtures/pages.yml",
    "content": "welcome:\n  id: 1\n  title: Welcome to the weblog\n  body: Such a lovely day\n  version: 24\n  author_id: 1\n  revisor_id: 1"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/fixtures/widget.rb",
    "content": "class Widget < ActiveRecord::Base\n  acts_as_versioned :sequence_name => 'widgets_seq', :association_options => {\n    :dependent => :nullify, :order => 'version desc'\n  }\n  non_versioned_columns << 'foo'\nend"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/migration_test.rb",
    "content": "require File.join(File.dirname(__FILE__), 'abstract_unit')\n\nif ActiveRecord::Base.connection.supports_migrations? \n  class Thing < ActiveRecord::Base\n    attr_accessor :version\n    acts_as_versioned\n  end\n\n  class MigrationTest < Test::Unit::TestCase\n    self.use_transactional_fixtures = false\n    def teardown\n      if ActiveRecord::Base.connection.respond_to?(:initialize_schema_information)\n        ActiveRecord::Base.connection.initialize_schema_information\n        ActiveRecord::Base.connection.update \"UPDATE schema_info SET version = 0\"\n      else\n        ActiveRecord::Base.connection.initialize_schema_migrations_table\n        ActiveRecord::Base.connection.assume_migrated_upto_version(0)\n      end\n      \n      Thing.connection.drop_table \"things\" rescue nil\n      Thing.connection.drop_table \"thing_versions\" rescue nil\n      Thing.reset_column_information\n    end\n        \n    def test_versioned_migration\n      assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' }\n      # take 'er up\n      ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/')\n      t = Thing.create :title => 'blah blah', :price => 123.45, :type => 'Thing'\n      assert_equal 1, t.versions.size\n      \n      # check that the price column has remembered its value correctly\n      assert_equal t.price,  t.versions.first.price\n      assert_equal t.title,  t.versions.first.title\n      assert_equal t[:type], t.versions.first[:type]\n      \n      # make sure that the precision of the price column has been preserved\n      assert_equal 7, Thing::Version.columns.find{|c| c.name == \"price\"}.precision\n      assert_equal 2, Thing::Version.columns.find{|c| c.name == \"price\"}.scale\n\n      # now lets take 'er back down\n      ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/')\n      assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' }\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/schema.rb",
    "content": "ActiveRecord::Schema.define(:version => 0) do\n  create_table :pages, :force => true do |t|\n    t.column :version, :integer\n    t.column :title, :string, :limit => 255\n    t.column :body, :text\n    t.column :updated_at, :datetime\n    t.column :author_id, :integer\n    t.column :revisor_id, :integer\n  end\n\n  create_table :page_versions, :force => true do |t|\n    t.column :page_id, :integer\n    t.column :version, :integer\n    t.column :title, :string, :limit => 255\n    t.column :body, :text\n    t.column :updated_at, :datetime\n    t.column :author_id, :integer\n    t.column :revisor_id, :integer\n  end\n  \n  create_table :authors, :force => true do |t|\n    t.column :page_id, :integer\n    t.column :name, :string\n  end\n  \n  create_table :locked_pages, :force => true do |t|\n    t.column :lock_version, :integer\n    t.column :title, :string, :limit => 255\n    t.column :type, :string, :limit => 255\n  end\n\n  create_table :locked_pages_revisions, :force => true do |t|\n    t.column :page_id, :integer\n    t.column :version, :integer\n    t.column :title, :string, :limit => 255\n    t.column :version_type, :string, :limit => 255\n    t.column :updated_at, :datetime\n  end\n\n  create_table :widgets, :force => true do |t|\n    t.column :name, :string, :limit => 50\n    t.column :foo, :string\n    t.column :version, :integer\n    t.column :updated_at, :datetime\n  end\n\n  create_table :widget_versions, :force => true do |t|\n    t.column :widget_id, :integer\n    t.column :name, :string, :limit => 50\n    t.column :version, :integer\n    t.column :updated_at, :datetime\n  end\n  \n  create_table :landmarks, :force => true do |t|\n    t.column :name, :string\n    t.column :latitude, :float\n    t.column :longitude, :float\n    t.column :version, :integer\n  end\n\n  create_table :landmark_versions, :force => true do |t|\n    t.column :landmark_id, :integer\n    t.column :name, :string\n    t.column :latitude, :float\n    t.column :longitude, :float\n    t.column :version, :integer\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/acts_as_versioned/test/versioned_test.rb",
    "content": "require File.join(File.dirname(__FILE__), 'abstract_unit')\nrequire File.join(File.dirname(__FILE__), 'fixtures/page')\nrequire File.join(File.dirname(__FILE__), 'fixtures/widget')\n\nclass VersionedTest < Test::Unit::TestCase\n  fixtures :pages, :page_versions, :locked_pages, :locked_pages_revisions, :authors, :landmarks, :landmark_versions\n  set_fixture_class :page_versions => Page::Version\n\n  def test_saves_versioned_copy\n    p = Page.create! :title => 'first title', :body => 'first body'\n    assert !p.new_record?\n    assert_equal 1, p.versions.size\n    assert_equal 1, p.version\n    assert_instance_of Page.versioned_class, p.versions.first\n  end\n\n  def test_saves_without_revision\n    p = pages(:welcome)\n    old_versions = p.versions.count\n\n    p.save_without_revision\n\n    p.without_revision do\n      p.update_attributes :title => 'changed'\n    end\n\n    assert_equal old_versions, p.versions.count\n  end\n\n  def test_rollback_with_version_number\n    p = pages(:welcome)\n    assert_equal 24, p.version\n    assert_equal 'Welcome to the weblog', p.title\n\n    assert p.revert_to!(p.versions.first.version), \"Couldn't revert to 23\"\n    assert_equal 23, p.version\n    assert_equal 'Welcome to the weblg', p.title\n  end\n\n  def test_versioned_class_name\n    assert_equal 'Version', Page.versioned_class_name\n    assert_equal 'LockedPageRevision', LockedPage.versioned_class_name\n  end\n\n  def test_versioned_class\n    assert_equal Page::Version,                  Page.versioned_class\n    assert_equal LockedPage::LockedPageRevision, LockedPage.versioned_class\n  end\n\n  def test_special_methods\n    assert_nothing_raised { pages(:welcome).feeling_good? }\n    assert_nothing_raised { pages(:welcome).versions.first.feeling_good? }\n    assert_nothing_raised { locked_pages(:welcome).hello_world }\n    assert_nothing_raised { locked_pages(:welcome).versions.first.hello_world }\n  end\n\n  def test_rollback_with_version_class\n    p = pages(:welcome)\n    assert_equal 24, p.version\n    assert_equal 'Welcome to the weblog', p.title\n\n    assert p.revert_to!(p.versions.first), \"Couldn't revert to 23\"\n    assert_equal 23, p.version\n    assert_equal 'Welcome to the weblg', p.title\n  end\n\n  def test_rollback_fails_with_invalid_revision\n    p = locked_pages(:welcome)\n    assert !p.revert_to!(locked_pages(:thinking))\n  end\n\n  def test_saves_versioned_copy_with_options\n    p = LockedPage.create! :title => 'first title'\n    assert !p.new_record?\n    assert_equal 1, p.versions.size\n    assert_instance_of LockedPage.versioned_class, p.versions.first\n  end\n\n  def test_rollback_with_version_number_with_options\n    p = locked_pages(:welcome)\n    assert_equal 'Welcome to the weblog', p.title\n    assert_equal 'LockedPage', p.versions.first.version_type\n\n    assert p.revert_to!(p.versions.first.version), \"Couldn't revert to 23\"\n    assert_equal 'Welcome to the weblg', p.title\n    assert_equal 'LockedPage', p.versions.first.version_type\n  end\n\n  def test_rollback_with_version_class_with_options\n    p = locked_pages(:welcome)\n    assert_equal 'Welcome to the weblog', p.title\n    assert_equal 'LockedPage', p.versions.first.version_type\n\n    assert p.revert_to!(p.versions.first), \"Couldn't revert to 1\"\n    assert_equal 'Welcome to the weblg', p.title\n    assert_equal 'LockedPage', p.versions.first.version_type\n  end\n\n  def test_saves_versioned_copy_with_sti\n    p = SpecialLockedPage.create! :title => 'first title'\n    assert !p.new_record?\n    assert_equal 1, p.versions.size\n    assert_instance_of LockedPage.versioned_class, p.versions.first\n    assert_equal 'SpecialLockedPage', p.versions.first.version_type\n  end\n\n  def test_rollback_with_version_number_with_sti\n    p = locked_pages(:thinking)\n    assert_equal 'So I was thinking', p.title\n\n    assert p.revert_to!(p.versions.first.version), \"Couldn't revert to 1\"\n    assert_equal 'So I was thinking!!!', p.title\n    assert_equal 'SpecialLockedPage', p.versions.first.version_type\n  end\n\n  def test_lock_version_works_with_versioning\n    p = locked_pages(:thinking)\n    p2 = LockedPage.find(p.id)\n\n    p.title = 'fresh title'\n    p.save\n    assert_equal 2, p.versions.size # limit!\n\n    assert_raises(ActiveRecord::StaleObjectError) do\n      p2.title = 'stale title'\n      p2.save\n    end\n  end\n\n  def test_version_if_condition\n    p = Page.create! :title => \"title\"\n    assert_equal 1, p.version\n\n    Page.feeling_good = false\n    p.save\n    assert_equal 1, p.version\n    Page.feeling_good = true\n  end\n\n  def test_version_if_condition2\n    # set new if condition\n    Page.class_eval do\n      def new_feeling_good() title[0..0] == 'a'; end\n      alias_method :old_feeling_good, :feeling_good?\n      alias_method :feeling_good?, :new_feeling_good\n    end\n\n    p = Page.create! :title => \"title\"\n    assert_equal 1, p.version # version does not increment\n    assert_equal 1, p.versions(true).size\n\n    p.update_attributes(:title => 'new title')\n    assert_equal 1, p.version # version does not increment\n    assert_equal 1, p.versions(true).size\n\n    p.update_attributes(:title => 'a title')\n    assert_equal 2, p.version\n    assert_equal 2, p.versions(true).size\n\n    # reset original if condition\n    Page.class_eval { alias_method :feeling_good?, :old_feeling_good }\n  end\n\n  def test_version_if_condition_with_block\n    # set new if condition\n    old_condition = Page.version_condition\n    Page.version_condition = Proc.new { |page| page.title[0..0] == 'b' }\n\n    p = Page.create! :title => \"title\"\n    assert_equal 1, p.version # version does not increment\n    assert_equal 1, p.versions(true).size\n\n    p.update_attributes(:title => 'a title')\n    assert_equal 1, p.version # version does not increment\n    assert_equal 1, p.versions(true).size\n\n    p.update_attributes(:title => 'b title')\n    assert_equal 2, p.version\n    assert_equal 2, p.versions(true).size\n\n    # reset original if condition\n    Page.version_condition = old_condition\n  end\n\n  def test_version_no_limit\n    p = Page.create! :title => \"title\", :body => 'first body'\n    p.save\n    p.save\n    5.times do |i|\n      assert_page_title p, i\n    end\n  end\n\n  def test_version_max_limit\n    p = LockedPage.create! :title => \"title\"\n    p.update_attributes(:title => \"title1\")\n    p.update_attributes(:title => \"title2\")\n    5.times do |i|\n      assert_page_title p, i, :lock_version\n      assert p.versions(true).size <= 2, \"locked version can only store 2 versions\"\n    end\n  end\n\n  def test_track_altered_attributes_default_value\n    assert !Page.track_altered_attributes\n    assert LockedPage.track_altered_attributes\n    assert SpecialLockedPage.track_altered_attributes\n  end\n\n  def test_version_order\n    assert_equal 23, pages(:welcome).versions.first.version\n    assert_equal 24, pages(:welcome).versions.last.version\n  end\n\n  def test_track_altered_attributes\n    p = LockedPage.create! :title => \"title\"\n    assert_equal 1, p.lock_version\n    assert_equal 1, p.versions(true).size\n\n    p.title = 'title'\n    assert !p.save_version?\n    p.save\n    assert_equal 2, p.lock_version # still increments version because of optimistic locking\n    assert_equal 1, p.versions(true).size\n\n    p.title = 'updated title'\n    assert p.save_version?\n    p.save\n    assert_equal 3, p.lock_version\n    assert_equal 1, p.versions(true).size # version 1 deleted\n\n    p.title = 'updated title!'\n    assert p.save_version?\n    p.save\n    assert_equal 4, p.lock_version\n    assert_equal 2, p.versions(true).size # version 1 deleted\n  end\n\n  def assert_page_title(p, i, version_field = :version)\n    p.title = \"title#{i}\"\n    p.save\n    assert_equal \"title#{i}\", p.title\n    assert_equal (i+4), p.send(version_field)\n  end\n\n  def test_find_versions\n    assert_equal 2, locked_pages(:welcome).versions.size\n    assert_equal 1, locked_pages(:welcome).versions.find(:all, :conditions => ['title LIKE ?', '%weblog%']).length\n    assert_equal 2, locked_pages(:welcome).versions.find(:all, :conditions => ['title LIKE ?', '%web%']).length\n    assert_equal 0, locked_pages(:thinking).versions.find(:all, :conditions => ['title LIKE ?', '%web%']).length\n    assert_equal 2, locked_pages(:welcome).versions.length\n  end\n\n  def test_find_version\n    assert_equal page_versions(:welcome_1), Page.find_version(pages(:welcome).id, 23)\n    assert_equal page_versions(:welcome_2), Page.find_version(pages(:welcome).id, 24)\n    assert_equal pages(:welcome), Page.find_version(pages(:welcome).id)\n\n    assert_equal page_versions(:welcome_1), pages(:welcome).find_version(23)\n    assert_equal page_versions(:welcome_2), pages(:welcome).find_version(24)\n    assert_equal pages(:welcome), pages(:welcome).find_version\n\n    assert_raise(ActiveRecord::RecordNotFound) { Page.find_version(pages(:welcome).id, 1) }\n    assert_raise(ActiveRecord::RecordNotFound) { Page.find_version(0, 23) }\n  end\n\n  def test_with_sequence\n    assert_equal 'widgets_seq', Widget.versioned_class.sequence_name\n    3.times { Widget.create! :name => 'new widget' }\n    assert_equal 3, Widget.count\n    assert_equal 3, Widget.versioned_class.count\n  end\n\n  def test_has_many_through\n    assert_equal [authors(:caged), authors(:mly)], pages(:welcome).authors\n  end\n\n  def test_has_many_through_with_custom_association\n    assert_equal [authors(:caged), authors(:mly)], pages(:welcome).revisors\n  end\n\n  def test_referential_integrity\n    pages(:welcome).destroy\n    assert_equal 0, Page.count\n    assert_equal 0, Page::Version.count\n  end\n\n  def test_association_options\n    association = Page.reflect_on_association(:versions)\n    options = association.options\n    assert_equal :delete_all, options[:dependent]\n    assert_equal 'version', options[:order]\n\n    association = Widget.reflect_on_association(:versions)\n    options = association.options\n    assert_equal :nullify, options[:dependent]\n    assert_equal 'version desc', options[:order]\n    assert_equal 'widget_id', options[:foreign_key]\n\n    widget = Widget.create! :name => 'new widget'\n    assert_equal 1, Widget.count\n    assert_equal 1, Widget.versioned_class.count\n    widget.destroy\n    assert_equal 0, Widget.count\n    assert_equal 1, Widget.versioned_class.count\n  end\n\n  def test_versioned_records_should_belong_to_parent\n    page = pages(:welcome)\n    page_version = page.versions.last\n    assert_equal page, page_version.page\n  end\n\n  def test_unaltered_attributes\n    landmarks(:washington).attributes = landmarks(:washington).attributes.except(\"id\")\n    assert !landmarks(:washington).changed?\n  end\n\n  def test_unchanged_string_attributes\n    landmarks(:washington).attributes = landmarks(:washington).attributes.except(\"id\").inject({}) { |params, (key, value)| params.update(key => value.to_s) }\n    assert !landmarks(:washington).changed?\n  end\n\n  def test_should_find_earliest_version\n    assert_equal page_versions(:welcome_1), pages(:welcome).versions.earliest\n  end\n\n  def test_should_find_latest_version\n    assert_equal page_versions(:welcome_2), pages(:welcome).versions.latest\n  end\n\n  def test_should_find_previous_version\n    assert_equal page_versions(:welcome_1), page_versions(:welcome_2).previous\n    assert_equal page_versions(:welcome_1), pages(:welcome).versions.before(page_versions(:welcome_2))\n  end\n\n  def test_should_find_next_version\n    assert_equal page_versions(:welcome_2), page_versions(:welcome_1).next\n    assert_equal page_versions(:welcome_2), pages(:welcome).versions.after(page_versions(:welcome_1))\n  end\n\n  def test_should_find_version_count\n    assert_equal 24, pages(:welcome).versions_count\n    assert_equal 24, page_versions(:welcome_1).versions_count\n    assert_equal 24, page_versions(:welcome_2).versions_count\n  end\nend"
  },
  {
    "path": "vendor/plugins/acts_as_watchable/init.rb",
    "content": "# Include hook code here\nrequire File.dirname(__FILE__) + '/lib/acts_as_watchable'\nActiveRecord::Base.send(:include, Redmine::Acts::Watchable)\n"
  },
  {
    "path": "vendor/plugins/acts_as_watchable/lib/acts_as_watchable.rb",
    "content": "# ActsAsWatchable\nmodule Redmine\n  module Acts\n    module Watchable\n      def self.included(base) \n        base.extend ClassMethods\n      end \n\n      module ClassMethods\n        def acts_as_watchable(options = {})\n          return if self.included_modules.include?(Redmine::Acts::Watchable::InstanceMethods)          \n          send :include, Redmine::Acts::Watchable::InstanceMethods\n          \n          class_eval do\n            has_many :watchers, :as => :watchable, :dependent => :delete_all\n            has_many :watcher_users, :through => :watchers, :source => :user\n            \n            attr_protected :watcher_ids, :watcher_user_ids\n          end\n        end\n      end\n\n      module InstanceMethods\n        def self.included(base)\n          base.extend ClassMethods\n        end\n        \n        # Returns an array of users that are proposed as watchers\n        def addable_watcher_users\n          self.project.users.sort - self.watcher_users\n        end\n        \n        # Adds user as a watcher\n        def add_watcher(user)\n          self.watchers << Watcher.new(:user => user)\n        end\n        \n        # Removes user from the watchers list\n        def remove_watcher(user)\n          return nil unless user && user.is_a?(User)\n          Watcher.delete_all \"watchable_type = '#{self.class}' AND watchable_id = #{self.id} AND user_id = #{user.id}\"\n        end\n        \n        # Adds/removes watcher\n        def set_watcher(user, watching=true)\n          watching ? add_watcher(user) : remove_watcher(user)\n        end\n        \n        # Returns true if object is watched by user\n        def watched_by?(user)\n          !!(user && self.watchers.detect {|w| w.user_id == user.id })\n        end\n        \n        # Returns an array of watchers' email addresses\n        def watcher_recipients\n          notified = watchers.collect(&:user).select(&:active?)\n          if respond_to?(:visible?)\n            notified.reject! {|user| !visible?(user)}\n          end\n          notified.reject! {|user| user.pref[:no_emails]}\n          notified.collect(&:mail).compact\n        end\n\n        module ClassMethods\n          # Returns the objects that are watched by user\n          def watched_by(user)\n            find(:all, \n                 :include => :watchers,\n                 :conditions => [\"#{Watcher.table_name}.user_id = ?\", user.id])\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/History.txt",
    "content": "=== 2010-04-14\n\n* JavaScript code refactoring\n* More JavaScript code test\n* Moved functionalities from layout to helper\n\n=== 0.0.37 2010-01-28\n\n* refactored the code to take inline style out to style section\n* moves a lot of ruby code from view to helpers and controllers\n* better indentation\n\n=== 0.0.36 2010-01-05\n\n* Fixing the online validation of models that have primary key not id\n\n=== 0.0.35 2010-01-05\n\n* If invalid children value is passed in apply rescue\n\n=== 0.0.34 2010-01-04\n\n* updated README\n\n=== 0.0.33 2009-12-27\n\n* added authentication for feed\n\n=== 0.0.32 2009-12-23\n\n* the default search result for advance search should be primary key des\n* changed the layout for quick search\n\n=== 0.0.31 2009-12-15\n\n* association information is rescued so that show method works even if association info throws error\n* association info is displayed with belongs_to or has_many name instead of class name\n* debugging variable $debug_admin_data\n\n=== 0.0.30 2009-12-02\n\n* RSS feed for all the models\n\n=== 0.0.29 2009-11-18\n\n* rake task to validate all the models\n* ability to validate all the models using browser\n* increased the font size of overall app\n\n=== 0.0.28 2009-11-12\n\n* has_many association_info were too close to each other\n* fixing the issue where a class is used as a hash key. It breaks in development\n\n=== 0.0.28 2009-11-11\n\n* better link color\n\n=== 0.0.28 2009-11-11\n\n* refactored the way advance search JavaScript code\n* for pretty urls like /42-SEO-friendly-title the show method should pickup 42 as id\n\n=== 0.0.27 2009-11-04\n\n* test for has_one association\n\n=== 0.0.26 2009-11-04\n\n* cleaning up History.txt file \n\n=== 0.0.25 2009-11-03\n\n* fix for issue #14 so that not like will also include records which are null\n\n=== 0.0.24 2009-11-03\n\n* advance search refactoring\n\n=== 0.0.23 2009-10-29\n\n* advance search bug fix\n\n=== 0.0.22 2009-10-26\n\n* fixed adding rows on advanced search\n* consistenly use model_id for search and association parent objects\n* datetime/date/time fixes on edit and advanced search pages\n* added configuration to not use admin_data layout and use application one instead\n\n=== 0.0.21 2009-10-26\n\n* fixed the formatting issue while displaying missing index in diagnostic section \n* by passing additional parameter called 'attr' editing of a record would display\nonly one field to avoid any accidental change.\n\n=== 0.0.20 2009-10-22\n\n* warning message if JavaScript is disabled\n\n=== 0.0.19 2009-10-20\n\n* ability to pass :find_conditions to settings so that models with to_param method could\noverride the sql that is built by admin_data\n\n=== 0.0.18 2009-10-16\n\n* changed theme from warehouse to dark because the association info on the right \nhand side was not appearing correctly\n* homepage should have main tab selected\n* changed urls to support models that override to_param to other than id\n* fixed the sorting order. model a, model B and model A/Q was being sorted\nas A,Q,B instead of A,B,Q.\n\n=== 0.0.17 2009-10-08\n\n* drop down of klasses is now available at the center of home page\n* current model will be selected in the drop down  \n\n=== 0.0.16 2009-10-07\n\n* form UI foreign keys are dropdown (display name attribute if it exists and id otherwise)\n* form UI date fields use date_select (with free text year since we cannot guess a good range)\n* form UI refactored to use form_for instead of form_tag and hadcoded html\n     \n=== 0.0.15 2009-10-06\n\n* cache the list of models\n* advance search refactoring\n* jQuery UI datepicker for date field\n* advance search now shows validation error for integer and date fields\n* log.js for easy logging in JavaScript\n\n=== 0.0.14 2009-10-05\n\n* while editing match was being done for hard coded value id. Now it looks for klass.primary_key \n\n=== 0.0.13 2009-10-04\n\n* fixed IE7 bug \n\n=== 0.0.12 2009-10-04\n\n* fixed bug regarding integer values not appearning in listing \n* better indentation\n\n=== 0.0.11 2009-10-01\n\n* Major contribution in this release by Alex Rothenberg. http://github.com/alexrothenberg \n* this plugin now treats each model as a restful resource. \n* security fix and test for it\n* commented out offending code for has_one relationship\n* has_one and habtm relationships along with test would be taken up in next release\n\n=== 0.0.11 2009-09-28\n\n* renamed quick search to search\n* using jQuery theme to make drop down boxes jazzier\n* more tests\n* moved some inline css to external css file\n\n=== 0.0.10 2009-09-18\n\n* fixed listing and has_many association info for namespaced model \n\n=== 0.0.9 2009-09-18\n\n* fixed security issue\n\n=== 0.0.8 2009-09-18\n\n* do not assume that primary key is 'id' . Respect the primary key set by model.\n\n* test for alternate primary key\n\n=== 0.0.7 2009-09-17\n\n* fixed test for Vehicle::Car \n\n=== 0.0.6 2009-09-09\n\n* more tests for the plugin. Now 151 tests and 229 assertions\n\n* support for name spaced models like Vehicle::Car and Vehicle::Engine\n\n* fixed a bug related to advance search\n\n* refactored JavaScript code for advance search\n\n=== 0.0.5 2009-09-04\n\n* tests for the plugin\n\n* changed the way security configiruation is passed to the plugin\n\n* users can configure number of records in a page. Default is 50 \n\n* fixed bug associated with advance search \n\n* added link to report bug in footer\n\n* fixed bug in date parsing\n\n=== 0.0.4 2009-08-28\n\n* storing serialized array in string causing problem in truncate method. more at\n  http://github.com/neerajdotname/admin_data/issues#issue/3. \n\n=== 0.0.3 2009-08-10\n\n* not requiring rubygems\n* if will_paginate is missing then not raising exception\n\n=== 0.0.2 2009-07-06\n\n* ability to sort records\n* better visual clue that search is in progress\n\n=== 0.0.1 2009-05-01\n\n* Initial release\n"
  },
  {
    "path": "vendor/plugins/admin_data/README.md",
    "content": "\n# This plugin works with both Rails 2.3.x and Rails 3.\n* master branch hosts code where admin_data is a plugin and it works with Rails 2.3.x .\n* rails3_gem branch hosts code where admin_data is a gem and it works with Rails 3.x . \n\n[More info about Rails3](http://github.com/neerajdotname/admin_data/wiki/Installing-admin_data-in-a-Rails-3-project)\n\n## [Live Demo](http://admin-data-test.heroku.com/admin_data)\n\n## [Documentation](http://github.com/neerajdotname/admin_data/wiki)\n\n## [Source Code](http://github.com/neerajdotname/admin_data)\n\n### License\n\nDual licensed under the [MIT](http://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt) and [GPL version 2](http://github.com/jquery/jquery/blob/master/GPL-LICENSE.txt) licenses.\n"
  },
  {
    "path": "vendor/plugins/admin_data/Rakefile",
    "content": "require 'rake'\nrequire 'rake/testtask'\nrequire 'rake/rdoctask'\n\ndesc 'Default: run unit tests.'\ntask :default => :test\n\ndesc 'Test admin_data plugin.'\nRake::TestTask.new(:test) do |t|\n  t.libs << 'lib'\n  t.pattern = 'test/**/*_test.rb'\n  t.verbose = true\nend\n\ndesc 'Generate documentation for admin_data plugin.'\nRake::RDocTask.new(:rdoc) do |rdoc|\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title    = 'AdminData'\n  rdoc.options << '--line-numbers' << '--inline-source'\n  rdoc.rdoc_files.include('README')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/controllers/admin_data/base_controller.rb",
    "content": "class AdminData::BaseController < ApplicationController\n\n  unloadable\n\n  helper_method :admin_data_is_allowed_to_update?\n\n  layout 'admin_data'\n  ssl_required :all  \n\n  include AdminData::Chelper\n\n  before_filter :build_klasses, :build_drop_down_for_klasses, :check_page_parameter, :prepare_drop_down_klasses\n\n  attr_reader :klass\n  attr_reader :model\n\n  private\n\n  def prepare_drop_down_klasses\n    k = params[:klass] || ''\n    @drop_down_url = \"http://#{request.host_with_port}/admin_data/quick_search/#{CGI.escape(k)}\"\n  end\n\n  def ensure_is_allowed_to_view\n    render :text => '<h2>not authorized</h2>', :status => :unauthorized, :layout => true unless admin_data_is_allowed_to_view?\n  end\n\n  def ensure_is_allowed_to_view_model\n    render :text => 'not authorized', :status => :unauthorized, :layout => true unless admin_data_is_allowed_to_view_model?\n  end\n\n  def ensure_is_allowed_to_update\n    render :text => 'not authorized', :status => :unauthorized, :layout => true unless admin_data_is_allowed_to_update?\n  end\n\n  def ensure_is_allowed_to_update_model\n    render :text => 'not authorized', :status => :unauthorized, :layout => true unless admin_data_is_allowed_to_update_model?\n  end\n\n  def ensure_is_allowed_to_view_feed\n    render :text => 'not authorized', :status => :unauthorized, :layout => true unless AdminData::Util.is_allowed_to_view_feed?(self)\n  end\n\n  def get_class_from_params\n    begin\n      @klass = AdminData::Util.camelize_constantize(params[:klass])\n    rescue TypeError => e # in case no params[:klass] is supplied\n      Rails.logger.debug 'no params[:klass] was supplied'\n      redirect_to admin_data_index_path\n    rescue NameError # in case wrong params[:klass] is supplied\n      Rails.logger.debug 'wrong params[:klass] was supplied'\n      redirect_to admin_data_index_path\n    end\n  end\n\n  def build_klasses\n    unless defined? $admin_data_klasses\n      model_dir = File.join(Rails.root,'app','models')\n      model_names = Dir.chdir(model_dir) { Dir[\"**/*.rb\"] }\n      klasses = get_klass_names(model_names)\n      filtered_klasses = remove_klasses_without_table(klasses).sort_by {|r| r.name.underscore}\n      klasses_with_security_clearance = filtered_klasses.select do |klass_local|\n        @klass = klass_local\n        admin_data_is_allowed_to_view_model?\n      end\n      $admin_data_klasses = klasses_with_security_clearance\n    end\n    @klasses = $admin_data_klasses\n  end\n\n  def remove_klasses_without_table(klasses)\n    klasses.select { |k| k.ancestors.include?(ActiveRecord::Base) &&\n    k.connection.table_exists?(k.table_name) }\n  end\n\n  def get_klass_names(model_names)\n    model_names.inject([]) do |output, model_name|\n      klass_name = model_name.sub(/\\.rb$/,'').camelize\n      begin\n        output << AdminData::Util.constantize_klass(klass_name)\n      rescue Exception => e\n        Rails.logger.debug e.message\n      end\n      output\n    end\n  end\n\n  def build_drop_down_for_klasses\n    @drop_down_for_klasses = @klasses.inject([]) do |result,klass|\n      result << [klass.name.underscore, admin_data_search_url(:klass => klass.name.underscore)]\n    end\n  end\n\n  def check_page_parameter\n    # Got hoptoad error because of url like http://localhost:3000/admin_data/User/advance_search?page=http://201.134.249.164/intranet/on.txt?\n    if params[:page].blank? || (params[:page] =~ /\\A\\d+\\z/)\n      # proceed\n    else\n      render :text => 'Invalid params[:page]', :status => :unprocessable_entity\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/controllers/admin_data/diagnostic_controller.rb",
    "content": "class AdminData::DiagnosticController < AdminData::BaseController\n\n  unloadable\n\n  before_filter :ensure_is_allowed_to_view\n\n  def index\n    @page_title = 'diagnostic'\n    respond_to {|format| format.html}\n  end\n\n  def missing_index\n    @page_title = 'missing index'\n    @indexes = {}\n    conn = ActiveRecord::Base.connection\n    conn.tables.each do |table|\n      indexed_columns = conn.indexes(table).map { |i| i.columns }.flatten\n      conn.columns(table).each do |column|\n        if column.name.match(/_id/) && !indexed_columns.include?(column.name)\n          @indexes[table] ||= []\n          @indexes[table] << column.name\n        end\n      end\n    end\n    respond_to {|format| format.html}\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/controllers/admin_data/feed_controller.rb",
    "content": "class AdminData::FeedController < AdminData::BaseController\n\n  unloadable\n\n  before_filter :ensure_is_allowed_to_view_feed\n\n  def index\n    render :text => \"usage: http://localhost:3000/admin_data/feed/user\" and return if params[:klasss].blank?\n\n    begin\n      @klass = AdminData::Util.camelize_constantize(params[:klasss])\n    rescue NameError => e\n      render :text => \"No constant was found with name #{params[:klasss]}\" and return\n    end\n  end\n\n  private\n\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/controllers/admin_data/main_controller.rb",
    "content": "class AdminData::MainController  < AdminData::BaseController\n\n  unloadable\n\n  before_filter :get_class_from_params, :only => [ :table_structure, :show, :destroy, :del, :edit, :new, :update, :create]\n\n  before_filter :ensure_is_allowed_to_view\n\n  before_filter :get_model_and_verify_it, :only => [:destroy, :del, :edit, :update, :show]\n\n  before_filter :ensure_is_allowed_to_view_model, :except => [:all_models, :index]\n\n  before_filter :ensure_is_allowed_to_update, :only => [:destroy, :del, :edit, :update, :create]\n\n  before_filter :ensure_is_allowed_to_update_model, :only => [:destroy, :del, :edit, :update, :create]\n\n\n  def table_structure\n    @page_title = 'table_structure'\n    @indexes = []\n    if (indexes = ActiveRecord::Base.connection.indexes(@klass.table_name)).any?\n      add_index_statements = indexes.map do |index|\n        statment_parts = [ ('add_index ' + index.table.inspect) ]\n        statment_parts << index.columns.inspect\n        statment_parts << (':name => ' + index.name.inspect)\n        statment_parts << ':unique => true' if index.unique\n\n        '  ' + statment_parts.join(', ')\n      end\n      add_index_statements.sort.each { |index| @indexes << index }\n    end\n    respond_to {|format| format.html}\n  end\n\n  def all_models\n    respond_to {|format| format.html}\n  end\n\n  def show\n    @page_title = \"#{@klass.name.underscore}:#{@model.id}\"\n    respond_to {|format| format.html}\n  end\n\n  def destroy\n    @klass.send(:destroy, params[:id])\n    redirect_to admin_data_search_path(:klass => @klass.name.underscore)\n  end\n\n  def del\n    @klass.send(:delete, params[:id])\n    flash[:success] = 'Record was deleted'\n    redirect_to admin_data_search_path(:klass => @klass.name.underscore)\n  end\n\n  def edit\n    @page_title = \"edit #{@klass.name.underscore}:#{@model.id}\"\n    @columns = columns_list\n    respond_to {|format| format.html}\n  end\n\n  def new\n    @page_title = \"new #{@klass.name.underscore}\"\n    @model = @klass.send(:new)\n    @columns = columns_list\n    respond_to {|format| format.html}\n  end\n\n  def update\n    model_name_underscored = @klass.name.underscore\n    model_attrs = params[model_name_underscored]\n    @columns = columns_list\n    respond_to do |format|\n      if @model.update_attributes(model_attrs)\n        format.html do\n          flash[:success] = \"Record was updated\"\n          redirect_to admin_data_on_k_path(:id => @model, :klass => @klass.name.underscore)\n        end\n        format.js { render :json => {:success => true}}\n      else\n        format.html { render :action => 'edit' }\n        format.js { render :json => {:error => @model.errors.full_messages.join } }\n      end\n    end\n  end\n\n  def create\n    model_name_underscored = @klass.name.underscore\n    model_attrs = params[model_name_underscored]\n    @model = @klass.create(model_attrs)\n    @columns = columns_list\n\n    respond_to do |format|\n      if @model.errors.any?\n        format.html { render :action => 'new' }\n        format.js { render :json => {:error => @model.errors.full_messages.join() }}\n      else\n        format.html do\n          flash[:success] = \"Record was created\"\n          redirect_to admin_data_on_k_path(:id => @model, :klass => @klass.name.underscore)\n        end\n        format.js { render :json => {} }\n      end\n    end\n  end\n\n  private\n\n  def get_model_and_verify_it\n    primary_key = @klass.primary_key.intern\n    conditional_id = params[:id] =~ /^(\\d+)-.*/ ? params[:id].to_i : params[:id]\n    condition = {primary_key => conditional_id}\n\n    # http://neerajdotname.github.com/admin_data/#override_find_condition\n    find_conditions_proc = AdminData::Config.setting[:find_conditions] ?  AdminData::Config.setting[:find_conditions][@klass.name] : nil\n    if find_conditions_proc && find_conditions = find_conditions_proc.call(params)\n\n      if find_conditions.has_key?(:conditions)\n        condition = find_conditions.fetch(:conditions)\n      end\n    end\n\n    @model = @klass.send('find', :first, :conditions => condition)\n    unless @model\n      render :text => \"<h2>#{@klass.name} not found: #{params[:id]}</h2>\", :status => :not_found\n    end\n  end\n\n  def columns_list\n    params[:attr].blank? ? @klass.columns : @klass.columns.find_all {|col| params[:attr] == col.name}\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/controllers/admin_data/migration_controller.rb",
    "content": "class AdminData::MigrationController < AdminData::BaseController\n\n  unloadable\n\n  before_filter :ensure_is_allowed_to_view\n\n  def index\n    @page_title = 'migration information'\n    m = 'select * from schema_migrations'\n    @data = ActiveRecord::Base.connection.select_all(m)\n    respond_to {|format| format.html}\n  end\n\n  def jstest\n    @page_title = 'jstest'\n    respond_to {|format| format.html { render :layout => false}}\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/controllers/admin_data/search_controller.rb",
    "content": "require File.join(File.dirname(__FILE__) , '..', '..', '..', 'lib', 'admin_data', 'search')\n\nclass AdminData::SearchController  < AdminData::BaseController\n\n  include Search\n\n  unloadable\n\n  before_filter :get_class_from_params\n  before_filter :ensure_is_allowed_to_view\n  before_filter :ensure_is_allowed_to_view_model\n  before_filter :ensure_valid_children_klass, :only => [:quick_search]\n  before_filter :ensure_is_authorized_for_update_opration, :only => [:advance_search]\n  before_filter :set_collection_of_columns, :only => [:advance_search]\n\n  def quick_search\n    @page_title = \"Search #{@klass.name.underscore}\"\n    @order = default_order\n\n    if params[:base]\n      klass = AdminData::Util.camelize_constantize(params[:base])\n      model = klass.find(params[:model_id])\n      has_many_proxy = model.send(params[:children].intern)\n      @total_num_of_children = has_many_proxy.send(:count)\n      h = { :page => params[:page], :per_page => per_page, :order => @order }\n      @records = has_many_proxy.send(:paginate, h)\n    else\n      params[:query] = params[:query].strip unless params[:query].blank?\n      cond = build_quick_search_conditions(@klass, params[:query])\n      h = { :page => params[:page], :per_page => per_page, :order => @order, :conditions => cond }\n      @records = @klass.paginate(h)\n    end\n    respond_to {|format| format.html}\n  end\n\n\n  def advance_search\n    @page_title = \"Advance search #{@klass.name.underscore}\"\n    plugin_dir = AdminData::Config.setting[:plugin_dir]\n    hash = build_advance_search_conditions(@klass, params[:adv_search])\n    @cond = hash[:cond]\n    errors = hash[:errors]\n    @order = default_order\n\n    respond_to do |format|\n      format.html { render }\n      format.js {\n\n        if !hash[:errors].blank?\n          render :file =>  \"#{plugin_dir}/app/views/admin_data/search/search/_errors.html.erb\", :locals => {:errors => errors}\n          return\n        end\n        if params[:admin_data_advance_search_action_type] == 'destroy'\n          handle_advance_search_action_type_destroy\n        elsif params[:admin_data_advance_search_action_type] == 'delete'\n          handle_advance_search_action_type_delete\n        else\n          @records = @klass.paginate(:page => params[:page], :per_page => per_page, :order => @order, :conditions => @cond )\n        end\n\n        if @success_message\n          render :json => {:success => @success_message }\n        else\n          render   :file =>  \"#{plugin_dir}/app/views/admin_data/search/search/_listing.html.erb\", \n                    :locals => {:klass => @klass, :records => @records}\n        end\n      }\n    end\n  end\n\n  private\n\n  def ensure_valid_children_klass\n    if params[:base]\n      begin\n        model_klass = AdminData::Util.camelize_constantize(params[:base])\n      rescue NameError => e #incase params[:base] is junk value\n        render :text => \"#{params[:base]} is an invalid value\", :status => :not_found\n        return\n      end\n      unless AdminData::Util.has_many_what(model_klass).include?(params[:children])\n        render :text => \"<h2>#{params[:children]} is not a valid has_many association</h2>\",\n        :status => :not_found\n        return\n      end\n    end\n  end\n\n  def ensure_is_authorized_for_update_opration\n    if %w(destroy delete).include? params[:admin_data_advance_search_action_type]\n      render :text => 'not authorized', :status => :unauthorized unless admin_data_is_allowed_to_update?\n    end\n  end\n\n  def handle_advance_search_action_type_delete\n    count = @klass.send(:count, :conditions => @cond);\n    @klass.find_in_batches( :conditions => @cond ) do |group|\n      group.each {|record| @klass.send(:delete, record) }\n    end\n    @success_message = \"#{count} #{AdminData::Util.pluralize(count, 'record')} deleted\"\n  end\n\n  def handle_advance_search_action_type_destroy\n    count = @klass.send(:count, :conditions => @cond);\n    @klass.find_in_batches( :conditions => @cond ) do |group|\n      group.each {|record| record.destroy }\n    end\n    @success_message = \"#{count} #{AdminData::Util.pluralize(count, 'record')} destroyed\"\n  end\n\n  def default_order\n    params[:sortby] || \"#{@klass.send(:table_name)}.#{@klass.send(:primary_key)} desc\"\n  end\n\n  def set_collection_of_columns\n    collection_of_colums = @klass.columns.collect { |column|\n      #JSLint complains if a hash has key named boolean. So I am changing the key to booleant\n      column_type =  (column.type.to_s == 'boolean') ? 'booleant' : column.type.to_s\n      \"#{column.name}:'#{column_type}'\"\n    }\n    collection_of_colums = collection_of_colums.join(',')\n    @collection_of_colums = \"[{#{collection_of_colums}}]\"\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/controllers/admin_data/validate_model_controller.rb",
    "content": "require 'fileutils'\n\nclass AdminData::ValidateModelController < AdminData::BaseController\n\n  unloadable\n\n  before_filter :ensure_is_allowed_to_view\n\n  def tid\n    @data = gather_data(params[:tid])\n    respond_to {|format| format.html}\n  end\n\n  def validate\n    @page_title = 'validate model'\n    @tid = Time.now.strftime('%Y%m%d%H%M%S')\n\n    dir = Rails.root.join('tmp', 'admin_data', 'validate_model')\n    FileUtils.mkdir_p(dir)\n    tids = Dir.chdir(dir) { Dir[\"*\"] }\n    @tids = tids.sort!\n\n    respond_to {|format| format.html}\n  end\n\n  def validate_model\n    respond_to do |format|\n      format.js do\n        if params[:tid].blank?\n          render :json => {:error => 'Something went wrong. Please try again !!' }\n          return\n\n        elsif params[:model].blank? && params[:still_processing].blank?\n          render :json => {:error => 'Please select at least one model' }\n          return\n\n        elsif !params[:still_processing].blank?\n          tid = params[:tid]\n          data = gather_data(tid)\n          done_file = File.join(Rails.root, 'tmp', 'admin_data', 'validate_model', tid, 'done.txt')\n          answer = File.exists?(done_file) ? 'no' : 'yes'\n          h = {\n            :still_processing => answer,\n            :data => data,\n            :currently_processing_klass =>  AdminData::Util.read_validation_file(tid, 'processing.txt')\n          }\n          render :json => h\n          return\n        else\n          tid = params[:tid]\n          klasses = params[:model].keys.join(',')\n          start_validation_rake_task(tid, klasses)\n          base_url = request.protocol + request.host_with_port\n          render :json => {:still_processing => 'yes', :base_url => base_url }\n          return\n        end\n      end\n    end\n  end\n\n  private\n\n  def start_validation_rake_task(tid, klasses)\n    f = File.join(Rails.root, 'tmp', 'admin_data', 'validate_model', tid)\n    FileUtils.rm_rf(f) if File.directory?(f)\n    FileUtils.mkdir_p(f)\n\n    AdminData::Util.write_to_validation_file('', 'a', tid, 'processing.txt')\n    AdminData::Util.write_to_validation_file('', 'a', tid, 'bad.txt')\n    AdminData::Util.write_to_validation_file('', 'a', tid, 'good.txt')\n    AdminData::Util.write_to_validation_file('', 'a', tid, 'error.txt')\n\n    call_rake('admin_data:validate_models_bg', {:tid => tid, :klasses => klasses} )\n  end\n\n  def call_rake(task, options = {})\n    options[:rails_env] ||= Rails.env\n    args = options.map { |n, v| \"#{n.to_s.upcase}='#{v}'\" }\n    rake_command = AdminDataConfig.setting[:rake_command]\n    command =  \"#{rake_command} #{task} #{args.join(' ')}\"\n    Rails.logger.info \"command: #{command}\"\n    p1 = Process.fork { system(command) }\n    AdminData::Util.write_to_validation_file(p1, 'a', options[:tid], 'pid.txt')\n    Process.detach(p1)\n  end\n\n  def gather_data(tid)\n    good_file = File.join(Rails.root, 'tmp', 'admin_data', 'validate_model', tid, 'good.txt')\n    bad_file = File.join(Rails.root, 'tmp', 'admin_data', 'validate_model', tid, 'bad.txt')\n    regex = /(\\w+)\\s+\\|\\s+(\\d+)\\s+\\|\\s+(.*)/\n\n    data = []\n    File.open(bad_file, \"r\") do |f|\n      f.each_line do |line|\n        next if line.strip.blank?\n        data << '<p>'\n        m = regex.match(line)\n        data << render_to_string(:partial => 'bad', :locals => {:klassu => m[1], :id => m[2], :error => m[3]})\n        data << '</p>'\n      end\n    end\n    File.open(good_file, \"r\") { |f| f.each_line { |line| data << \"<p>#{line}</p>\" } }\n    data.join\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/diagnostic/index.html.erb",
    "content": "<div id=\"main\">\n  <div class=\"block\" id=\"block-tables\">\n\n    <div class=\"content rounded\">          \n      <h2 class=\"title\">Diagnostic test</h2>\n      <div class=\"inner\">\n        <h2>\n          <%= link_to 'Find missing database index', admin_data_diagnostic_missing_index_url %>\n        </h2>\n        <h2>\n          <%= link_to 'Validate Models', admin_data_validate_url %>\n        </h2> \n      </div>\n    </div>\n\n  </div>\n</div>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/diagnostic/missing_index.html.erb",
    "content": "<div id=\"main\">\n  <div class=\"block\" id=\"block-tables\">\n    <div class=\"content rounded\">          \n      <h2 class=\"title\">Missing Index Report</h2>\n      <div class=\"inner\">\n        <p>It is recommended that all foreign keys be indexed.</p>  \n        <p>\n          Given below is the migration code that should be performed to create index.  \n        </p>\n        \n        <table id='missing_index'>\n          <% @indexes.each do |table, columns|\n            columns.map do |column| %>\n              <tr>\n                <td>\n                  add_index '<%=table%>', '<%=column%>'\n                </td>\n              </tr>\n            <% end %>\n          <% end %>\n        </table>  \n\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/feed/index.rss.builder",
    "content": "xml.instruct! :xml, :version => \"1.0\"\nxml.rss(:version => \"2.0\" ){\n  xml.channel{\n    xml.title(\"Feeds from admin_data #{@klass.name}\")\n    xml.link(request.host_with_port)\n    xml.description(\"feeds from AdminData #{@klass.name}\")\n    xml.language('en-us')\n    h = {:order => \"#{@klass.primary_key} desc\", :limit => 100}\n    @klass.find(:all, h).each do |record|\n      xml.item do\n        xml.title(\"#{@klasss} id: #{record.id}\")\n\n        desc = AdminData::Util.label_values_pair_for(record, self).inject([]) do |sum, a|\n          sum << \"<p>#{a[0]}: #{a[1]}</p>\"\n        end.join\n\n        xml.description(desc)\n        d = record.respond_to?(:created_at) ?  record.created_at : Time.now\n        xml.pubDate(d.strftime(\"%a, %d %b %Y %H:%M:%S %z\"))\n        xml.link(admin_data_on_k_path(:id => record, :klass => @klass.name))\n        xml.guid(admin_data_on_k_path(:id => record, :klass => @klass.name))\n      end\n    end\n  }\n}\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/main/all_models.html.erb",
    "content": "<div id=\"main\">\n  <div class=\"block\" id=\"block-tables\">\n    <div class=\"content rounded select_box\">          \n      <h2 style='margin-left:0;'>Select a model</h2>\n      <p class='notice'>\n        Note that this drop down is also available at top right corner of every page .\n      </p>\n      <%= render '/admin_data/shared/drop_down_klasses', :drop_down_for_klasses => @drop_down_for_klasses %>\n      <div class=\"clear\"></div>\n    </div>\n  </div>\n</div>\n\n<style>\n  .select_box {\n    padding: 15px;\n  }\n  p.notice {\n    color: dimgray;\n    font-size:15px;\n  }\n</style>   \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/main/association/_association_info.html.erb",
    "content": "<div class=\"block rounded\">\n  <h3>Association Information</h3>\n  <div class='content association_info'>\n    <% if AdminData::Util.admin_data_association_info_size(klass) %>\n      <%= render 'admin_data/main/association/belongs_to_info' ,  :klass => klass, :model => model %>\n      <%= render 'admin_data/main/association/has_one_info',      :klass => klass, :model => model %>\n      <%= render 'admin_data/main/association/has_many_info' ,    :klass => klass, :model => model %> \n    <% end %>\n  </div>\n</div>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/main/association/_belongs_to_info.html.erb",
    "content": "<% if AdminData::Util.belongs_to_what(klass).size > 0 %>\n  <p class='belongs_to'>\n    <strong>belongs_to :</strong> \n    &nbsp;      \n    <%= admin_data_belongs_to_data(model, klass) %>\n  </p> \n<% end %>  \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/main/association/_has_many_info.html.erb",
    "content": "<% if AdminData::Util.has_many_what(klass).size > 0 %>\n  <p>\n    <strong>has_many :</strong>\n    <%= admin_data_has_many_data(model, klass) %>\n    &nbsp;\n  </p> \n<% end %>  \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/main/association/_has_one_info.html.erb",
    "content": "<% if AdminData::Util.has_one_what(klass).size > 0 %>\n  <p>\n    <strong>has_one :</strong> \n    <%= admin_data_has_one(model, klass) %>\n  </p> \n<% end %>  \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/main/edit.html.erb",
    "content": "<div id=\"main\">\n  <% admin_data_breadcrum do %>\n    <%= link_to @klass, admin_data_search_path(:klass => @klass.name.underscore) %> \n    >\n    <%= link_to \"ID #{@model.id}\", ''%>  \n  <% end %>\n\n  <h2 class=\"title\">\n    Editing <%=@model.class.name%> id <%=@model.id%>\n  </h2>        \n\n  <div class=\"block\" id=\"block-tables\">\n\n    <div class=\"content rounded\">          \n      <div class=\"inner umbrella\">\n        <% url = admin_data_on_k_path(:klass => @klass.name, :id => @model)  \n           html_options = {:class => 'form', :method => :put} %>\n        <% form_for @klass.name.underscore.to_sym, @model, :url => url, :html=> html_options do |f| %>\n          <%= render 'admin_data/shared/flash_message', :model => @model %>\n          <%= render 'admin_data/main/misc/form', :klass => @klass, :f => f %>\n        <% end %>\n      </div>\n    </div>\n\n  </div>\n</div>\n\n<div id=\"sidebar\">\n  <%= render 'admin_data/main/association/association_info', :klass => @klass, :model => @model %>\n  <%= render 'admin_data/main/misc/modify_record', :model => @model, :klass => @klass %>\n</div>  \n\n<style type=\"text/css\">\n  #main {\n    width:70%;\n  }\n</style>  \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/main/misc/_form.html.erb",
    "content": "<% @columns.each do |col| %>\n  <div class='col_box'>\n    <span class='col_name'><%= col.name %></span>\n    <span class='col_type'>[<%= col.type.to_s %>]</span>\n  </div>\n  <%= admin_data_form_field(klass, @model, col, f).html_safe %>\n<% end %>\n\n<div class='group navform' style='padding-top:10px;'>\n  <%= f.submit('Save', :class => 'button', :disable_with => 'Please wait ...') %>\n</div>\n\n<style>\n  .col_name { \n    color: #222;\n    font-size: 15px;\n  }\n  .col_type {\n    color: dimgray;\n  }\n  .col_box { \n    margin-top: 20px;\n    padding-bottom: 4px;\n  }\n</style>   \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/main/misc/_modify_record.html.erb",
    "content": "<% if controller.send(:admin_data_is_allowed_to_update?) %>\n  <% @help = link_to('[?]','http://neerajdotname.github.com/admin_data/#delete_vs_destroy') %>\n  \n  <div class=\"block rounded\">\n    <h3>Modify Record</h3>\n    <div style='padding-left:15px'>\n      <p>\n        <%= link_to 'Edit', edit_admin_data_on_k_path(:klass => klass.name.underscore, :id => model) %> \n      </p>\n      <p>\n        <%= link_to 'Delete', del_admin_data_on_k_path(:klass => klass.name.underscore, :id => model) ,\n               { :confirm => ' You are deleting (not destroying) a record. Are you sure?', :method => :delete} %> \n        <%= @help %>      \n      </p>\n      <p>\n        <%= link_to \"Destroy\", admin_data_on_k_path(:klass => klass.name.underscore, :id => model), \n              { :confirm => 'You are destroying a record. Are you sure?', :method => :delete} %>\n        <%= @help %>      \n      </p>\n    </div>\n  </div>\n<% end %>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/main/new.html.erb",
    "content": "<div id=\"main\">\n\n  <% admin_data_breadcrum do %>\n    <%= link_to @klass, admin_data_search_path(:klass => @klass.name) %> \n  <% end %>\n\n  <div class=\"block\" id=\"block-tables\">\n    <div class=\"secondary-navigation\">\n      <%= render 'admin_data/shared/secondary_navigation', :klass => @klass %>\n      <div class=\"clear\"></div>\n    </div>          \n\n    <div class=\"content rounded\">          \n      <div class=\"inner umbrella\">\n        <h1>Create a new record</h1>\n        <% form_for @klass.name.underscore.to_sym, @model, :url  => admin_data_on_k_index_path(:klass => @klass.name), :html => {:class => 'form', :method => :post} do |f| %>\n          <%= render 'admin_data/shared/flash_message', :model => @model %>\n          <%= render 'admin_data/main/misc/form', :klass => @klass, :f => f %>\n        <% end %>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/main/show.html.erb",
    "content": "<div id=\"main\">\n\n  <% admin_data_breadcrum do %>\n    <%= link_to @klass, admin_data_search_path(:klass => @klass.name) %> \n    >\n    <%= link_to \"ID #{@model.id}\", ''%>  \n  <% end %>\n\n  <h2 class=\"title\"><%=@model.class.name%> ID <%=@model.id%></h2>        \n\n  <%= render 'admin_data/shared/flash_message', :model => @model %>\n  \n  <div class=\"block\" id=\"block-tables\">\n    <div class=\"content rounded\">          \n      <div class=\"inner\">\n        <table class=\"table with_border\" cellspacing=\"3\" cellpadding=\"3\">\n          <% AdminData::Util.label_values_pair_for(@model, self).each do |pair| %>\n            <tr>\n              <td><%=pair[0]%></td>\n              <td class='smaller'><%=pair[1]%></td>\n            </tr>   \n          <% end %>   \n        </table>\n      </div>\n    </div>\n  </div>\n</div>\n\n<div id=\"sidebar\">\n  <%= render 'admin_data/main/association/association_info', :klass => @klass, :model => @model %>\n  <%= render 'admin_data/main/misc/modify_record', :model => @model, :klass => @klass %>\n</div> \n\n<style>\n  #main {\n    width:70%;\n  }\n  table.with_border td.smaller {\n    font-size: 120%;\n  }\n</style>  \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/main/table_structure.html.erb",
    "content": "<div id=\"main\">\n\n  <% admin_data_breadcrum do %>\n    <%= link_to @klass, admin_data_search_path(:klass => @klass.name) %> \n  <% end %>\n  \n  <%= render 'admin_data/shared/flash_message', :model => @model %>\n  \n  <div class=\"block\" id=\"block-tables\">\n    <div class=\"secondary-navigation\">\n      <%= render 'admin_data/shared/secondary_navigation', :klass => @klass %>\n      <div class=\"clear\"></div>\n    </div>          \n    <div class=\"content rounded\">          \n      <h2 class=\"title\"></h2>\n      <div class=\"inner\">\n        <h1 class='table_name'>Table name : <%=@klass.send(:table_name)%></h1>\n        <h2>Columns</h2>\n        <table class=\"table colorize\">\n          <tr>\n            <th>Column Name</th>\n            <th>Type</th>\n            <th>Null</th>\n            <th>Default</th>\n          </tr>\n          <% @klass.columns.each do |column| %>\n            <tr>\n              <td><%=column.name%></td>\n              <td><%=column.type%></td>\n              <td><%=column.null%></td>\n              <td><%= AdminData::Util.string_representation_of_data(column.default) if column.has_default?%></td>\n            </tr>\n          <% end %>  \n        </table>\n\n        <h2>Index</h2>            \n        <% if @indexes.size == 0 %>\n          <p>No index was found </p>\n        <% else %>  \n          <table class=\"table colorize\">\n            <tr>\n              <th>Info</th>\n            </tr>\n            <% @indexes.each do |index| %>\n              <tr>\n                <td><%= index %></td>\n              </tr>\n            <% end %>  \n          </table>\n        <% end %>\n        \n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/migration/index.html.erb",
    "content": "<div id=\"main\">\n  <div class=\"block\" id=\"block-tables\">\n    <div class=\"content rounded\">          \n      <h2 class=\"title\">Migration Information from schema_migrations table</h2>\n      <div class=\"inner\">\n        <table class=\"table colorize\">\n          <tr>             \n            <th class='first last'>version</th>\n          </tr>\n          <% @data.each do |record| %>\n            <tr><td><%=record.values.first%></td></tr>\n          <% end %>  \n        </table>\n      </div>\n      <div class=\"clear\"></div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/migration/jstest.html.erb",
    "content": "<!DOCTYPE html>\n<html id=\"html\">\n  <head>\n\t  <title>admin_data JavaScript test</title>\n    <%= AdminData::Util.stylesheet_link_tag('vendor/qunit') %> \n    <%= AdminData::Util.javascript_include_tag( 'vendor/jquery-1.4.1', \n                                                'vendor/jquery-ui-1.7.2.custom.min',\n                                                'vendor/log', \n                                                'vendor/jquery.form', \n                                                'vendor/jquery.ba-isjquery', \n                                                'vendor/jack', \n                                                'misc/drop_down_change',\n                                                'misc/quick_search_input_focus',\n                                                'misc/js_util',\n                                                'advance_search/global_ajax_setting', \n                                                'advance_search/advance_search', \n                                                'advance_search/advance_search_structure', \n                                                'advance_search/ajaxify_advance_search',\n                                                'advance_search/act_on_result',\n                                                'advance_search/build_first_row',\n                                                'advance_search/event_bindings',\n                                                'advance_search/trigger_submit_on_domready',\n                                                'vendor/qunit',\n                                                'test/ajaxify_advance_search',\n                                                'test/act_on_result',\n                                                'test/build_first_row',\n                                                'test/event_bindings',\n                                                'test/advance_search'\n                                                ) %>\n  </head>\n\n  <body id=\"body\">\n\n    <h1 id=\"qunit-header\">admin_data JavaScript test</h1>\n    <h2 id=\"qunit-banner\"></h2>\n    <h2 id=\"qunit-userAgent\"></h2>\n    <ol id=\"qunit-tests\">\n    </ol>\n\n    <div id='advance_search' class='search_box' style='display:none;'>\n      <table id='advance_search_table' class='advtable'>\n      </table>\n    </div>\n\n    <div style='display:none;' id='admin_data_table_structure_data'>\n      [{id:'integer',first_name:'string',last_name:'string',age:'integer',active:'booleant',description:'text',society_type:'string',society_id:'integer',created_at:'datetime',updated_at:'datetime',birth_date:'datetime'}]\n    </div>\n    \n  </body>\n\n</html>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/search/_search_base.html.erb",
    "content": "<% admin_data_breadcrum do %>\n  <%= link_to klass.name, admin_data_search_path(:klass => klass.name.underscore) %> \n<% end %>  \n\n<div class=\"block\" id=\"block-text\">\n  <div class=\"secondary-navigation\">\n    <%= render 'admin_data/shared/secondary_navigation', :klass => klass %>\n    <div class=\"clear\"></div>\n  </div>          \n\n  <div class=\"content\">         \n    <% if advance_search %>\n      <%= render 'admin_data/search/search/advance_search_form', :klass => klass %>\n    <% else %>\n      <%= render 'admin_data/search/search/search_form', :klass => klass %>\n    <% end %>  \n  </div>\n\n  <div class='clear'></div>\n\n  <div class='main2 rounded'> \n    <div class=\"block\" id=\"block-tables\">\n      <div class=\"content\">          \n        <div class='inner'>\n          <div id='results'>\n            <% if params[:action] == 'quick_search' || request.xhr? %>\n              <%= render 'admin_data/search/search/listing', :klass => klass, :records => records %>\n            <% end %>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/search/advance_search.html.erb",
    "content": "<div id=\"main\">\n  <%= render '/admin_data/search/search_base' , :klass => @klass, :model => @model, :records => @records, :advance_search => true %>\n</div>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/search/quick_search.html.erb",
    "content": "<div id='main'>\n  <%= render '/admin_data/search/search_base' , :klass => @klass, :model => @model, :records => @records, :advance_search => false %>\n</div>  \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/search/search/_advance_search_form.html.erb",
    "content": "<%= form_tag(admin_data_advance_search_path(:klass=>klass),   \n             :method => 'get', \n             :class => 'form search_form', \n             :id => 'advance_search_form') %>\n\n    <div id='advance_search' class='search_box'>\n     <table id='advance_search_table' class='advtable'>\n     </table>\n\n      <div class='sortby_umbrella'>\n        <input type=\"submit\" value=\"Search\" class='submit_search' />\n        <div class='group'>     \n          <div class='sortby_text'>sort by</div>\n          <select name='sortby' id='sortby'>\n            <%= AdminData::Util.build_sort_options(klass,params[:sortby]) %>\n          </select>\n        </div> \n        <div class='clear'></div>\n      </div> \n   </div>\n\n</form>   \n\n<div style='display:none;' id='admin_data_table_structure_data'>\n  <%=@collection_of_colums%>\n</div>\n\n<style>\n   .sortby_umbrella { \n      margin-top: 6px;\n   }\n   .submit_search {\n      margin-left: 15px;\n      margin-right: 20px;\n   }\n   .sortby_umbrella .group {\n      float: left;\n   }\n   .sortby_text { \n      float: left;\n      margin-right: 5px;\n   }\n   #sortby { \n      width: 200px; \n      float: left;\n   }\n</style>\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/search/search/_errors.html.erb",
    "content": "<div>\n   <% errors.each do |error| %>\n      <p class='error'><%= error %></p>\n   <% end %>   \n</div>   \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/search/search/_listing.html.erb",
    "content": "<%= render :partial => 'admin_data/search/search/title', :locals => { \n                                                            :records => records, \n                                                            :total_num_of_children => @total_num_of_children } %>\n\n<div class=\"pagination\">\n  <%= will_paginate @records, :container => false, :params => {:klass => klass.name} %>\n</div>\n<div class='clear'></div>\n\n<table cellspacing=\"3\" cellpadding=\"3\" id=\"view_table\" class='table colorize'>\n\n  <thead>\n     <tr>\n      <% AdminData::Util.columns_order(klass.name).each do |column| %>\n        <th> <%= column %> </th>\n      <% end %>\n    </tr>\n  </thead>\n\n  <% @records.each do |record| %>\n    <tr>\n      <% AdminData::Util.columns_order(klass.name).each do |column| %>\n        <td>\n          <% if (column == klass.primary_key) %>\n            <%= link_to(record.send(column), admin_data_on_k_path(:klass => klass.name.underscore, :id => record)) %>\n         <% else %>\n            <%=h  admin_data_get_value_for_column(admin_data_column_native(klass, column), record) %>\n          <% end %>  \n        </td>\n      <% end %>\n    </tr>\n  <% end %>  \n</table>\n\n<div class=\"pagination\">\n  <%= will_paginate records, :container => false, :params => {:klass => klass.name.underscore} %>\n</div>\n\n<div class='clear'></div>\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/search/search/_search_form.html.erb",
    "content": "<%= form_tag(admin_data_search_path(:klass=>klass),  :method => 'get', :class => 'form search_form', :id => 'search') %>   \n\n  <div class='search_box'>\n    <div id='quick_search'>\n      <label class='label keyword_label'>search keyword</label>\n      <input type=\"text\" id=\"quick_search_input\" name=\"query\" value=\"<%=params[:query]%>\" />\n      <%= render :partial => 'admin_data/search/search/sortby', :locals => {:klass => klass} %>\n      <div class='clear'></div>\n      <%= submit_tag 'Search', :name => nil, :disable_with => 'searching ...', :class => 'submit_search' %>\n    </div>\n  </div>\n\n</form>\n\n<br />\n\n<style>\n  .keyword_label { \n    float: left;\n    padding-right: 10px;\n    margin-right: 10px;\n  }\n  #quick_search_input { \n    float: left;\n    margin-left: 10px;\n    margin-right: 20px;\n  }\n</style>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/search/search/_sortby.html.erb",
    "content": "<label class='label sortby_label'>sort by</label>\n<select name='sortby' id='sortby'>\n   <%= AdminData::Util.build_sort_options(klass,params[:sortby]) %>\n</select>\n\n<style>\n   .sortby_label { \n      float: left;\n      vertical-align: bottom; \n      margin-left: 40px;\n      width: 70px;\n   }\n   #sortyby {\n      width: 200px;\n      float: left;\n   }\n</style>   \n\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/search/search/_title.html.erb",
    "content": "<div>\n  <h2 class='title' id='search_result_title'> \n    <%=search_result_title(total_num_of_children, records)%>\n  </h2>\n\n  <% if admin_data_is_allowed_to_update? && params[:action] == 'advance_search' %>\n    <div class='delete_destroy_box'>\n      <span style=''>\n        <%= link_to 'Delete All', '#', :id => 'advance_search_delete_all' %>\n      </span>\n      |\n      <span> \n        <%= link_to 'Destroy All', '#', :id => 'advance_search_destroy_all' %>\n      </span>\n    </div>\n  <% end %>\n\n  <div class='clear'></div>\n\n</div>\n\n<style>\n  #search_result_title {\n    float: left;\n    margin-top: 5px; \n    padding-top: 5px; \n   }\n  .delete_destroy_box { \n    float: left;\n    margin-top: 6px;\n    padding-top: 6px;\n    margin-left: 20px;\n  }\n</style>   \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/shared/_breadcrum.html.erb",
    "content": "<div class='breadcrum rounded'>\n  <%= link_to 'Home',admin_data_index_path %>\n  >\n  <%= data %>\n  <% if params[:klass] && !(params[:action] == 'show') %>\n    <span class='description'>\n      (<%= pluralize(@klass.count, 'record') %> ) \n    </span>  \n  <% end %>  \n</div>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/shared/_drop_down_klasses.html.erb",
    "content": "<select class='drop_down_value_klass'> \n  <option></option>\n  <%= options_for_select(drop_down_for_klasses, @drop_down_url) %> \n</select>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/shared/_flash_message.html.erb",
    "content": "<% if model && model.errors.any? %>\n  <div class='flash rounded'>\n    <div class='message error'>\n      <% model.errors.full_messages.each do |message| %>\n        <p><%=message%></p>\n      <% end %>  \n    </div>\n  </div>\n<% end %>  \n\n<% if flash[:success] %>\n  <div class='flash rounded'><div class='message warning'><p><%= flash[:success] %></p></div></div>\n<% end %>  \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/shared/_header.html.erb",
    "content": "<div id=\"header\">\n    <h1>\n      <%= link_to 'admin_data', admin_data_index_path %>\n    </h1>  \n\n    <ul id='subnav'>\n      <li>\n        <%= link_to 'Home', admin_data_index_path %>\n      </li>\n\n      <li>\n        <%= link_to 'Migration Information', admin_data_migration_information_path %>\n      </li>\n\n    </ul>\n\n    <div id='model_drop_down'>\n      <%= render '/admin_data/shared/drop_down_klasses', :drop_down_for_klasses => drop_down_for_klasses %>\n    </div>\n\n    <div class='clear'></div>\n\n</div>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/shared/_powered_by.html.erb",
    "content": "<div id=\"footer\">\n  <p>\n    Powered by \n    <a href='http://github.com/neerajdotname/admin_data/tree/master' class='powered_by'>\n      admin_data\n    </a>\n  </p>\n\n  <p> \n    <a href='http://github.com/neerajdotname/admin_data/issues' class='powered_by'>\n      Report Bug\n    </a>\n  </p>\n\n  <p> \n    <a href='http://neerajdotname.github.com/admin_data' class='powered_by'>\n      Documentation \n    </a>\n  </p>\n\n  <div class='clear'></div>\n\n</div>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/shared/_secondary_navigation.html.erb",
    "content": "<%\n  @quick_search_tab_active = params[:action] == 'quick_search' ? 'active' : ''\n  @advance_search_tab_active = params[:action] == 'advance_search' ? 'active' : ''\n  @table_structure_tab_active = params[:action] == 'table_structure' ? 'active' : ''\n  @add_new_record_tab_active = %w(new create).include?(params[:action]) ? 'active' : ''\n%>\n\n<ul>\n\n  <li class=\"first <%=@quick_search_tab_active%>\">\n    <%= link_to 'Quick Search', admin_data_search_path(:klass => klass.name.underscore) %> \n  </li>\n\n  <li class=\"<%=@advance_search_tab_active%>\">\n    <%= link_to 'Advance Search', admin_data_advance_search_path(:klass => klass.name.underscore)  %>\n  </li>\n\n  <li class=\"<%=@table_structure_tab_active%>\">\n    <%= link_to 'Table Structure', table_structure_admin_data_on_k_path(:klass => klass.name.underscore) %>\n  </li>\n  \n  <% if admin_data_is_allowed_to_update? %>\n    <li class=\"<%=@add_new_record_tab_active%>\"> \n      <%= link_to '+Add New Record', new_admin_data_on_k_path(:klass => klass.name.underscore) %>\n    </li>\n  <% end %>  \n  \n</ul>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/validate_model/_bad.html.erb",
    "content": "<%=admin_data_invalid_record_link(klassu, id, error)%>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/validate_model/tid.html.erb",
    "content": "<%= AdminData::Util.read_validation_file(params[:tid], 'processing.txt') %>\n<%=@data%>\n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/admin_data/validate_model/validate.html.erb",
    "content": "<div id=\"main\">\n  <div class=\"block\" id=\"block-tables\">\n\n    <div class=\"content rounded\">          \n      <div class='validate_model_umbrella'>\n\n        <div class='lhs'>   \n          <h2 class=\"title\">Validate model</h2>\n          <div id='error'></div>\n            \n          <div id='tid' style='display:none'><%=@tid%></div>\n\n\n          <% form_tag \"/admin_data/diagnostic/validate_model?tid=#{@tid}\", :method => \"post\", :id => \"validate_model_form\" do |f| %>\n            <%= check_box_tag 'validate_model_select_all' %>\n            <strong>\n              <%= label_tag 'Select all models', nil, :for => 'validate_model_select_all' %>\n            </strong>  \n            <% $admin_data_klasses.each do |klass| %>\n              <p>\n                <%= check_box_tag klass.name, '1', false, :name => \"model[#{klass.name}]\" %>\n                <%= label_tag klass.name, nil, :id => klass.name.downcase.underscore %>\n              </p>\n            <% end %>   \n            <%= submit_tag('Start validation', :id => 'submit') %>\n          <% end %>\n\n          <h3>Previous runs</h3>\n          <%@tids.each do |tid| %>\n            <p><%= link_to tid, \"/admin_data/diagnostic/tid/#{tid}\" %></p>\n          <% end %>\n\n        </div>\n\n        <div class='rhs'>\n          <h2 id='validation_result'>\n            Validation result\n          </h2>\n          <div id='validate_model_rhs_data'></div>\n        </div>\n\n        <div class='clear'></div>\n      </div>\n    </div>\n  </div>\n</div>\n\n<style>\n  .lhs {\n    float: left;\n    width: 300px;\n  }\n  .rhs {\n    float: left;\n  }\n  #error {\n    color: red;\n    font-size: 120%;\n  }\n  #validate_model_form {\n    padding: 10px;\n  }\n  #validation_result {\n    display: none;\n    margin-left: 0;\n  }\n</style>   \n"
  },
  {
    "path": "vendor/plugins/admin_data/app/views/layouts/admin_data.html.erb",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\">\n  <head>\n\t  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n    <title>\n      <%= @page_title.blank? ? 'admin_data' : \"#{@page_title} - admin_data\" %>\n    </title>\n\n    <%= AdminData::Util.google_hosted_jquery_ui_css(self).html_safe %>\n\n    <%= AdminData::Util.stylesheet_link_tag('base').html_safe %>\n\n    <%= AdminData::Util.google_hosted_jquery(self).html_safe %>\n\n    <!-- It is breaking the html markup and test is full of messages \n          like ignoring attempt to close string with script Hence not including jquery.form in test -->\n    <%= AdminData::Util.javascript_include_tag('vendor/jquery.form').html_safe unless Rails.env.test? %> \n\n    <%= AdminData::Util.javascript_include_tag('vendor/log', \n                                               'misc/drop_down_change',\n                                               'misc/quick_search_input_focus',\n                                               'advance_search/global_ajax_setting',\n                                               'misc/js_util').html_safe %>\n\n    <!-- assert_tag is throwing a lot of warning with these inline javascripts.  \n    no need of these javascripts in test mode -->\n    <% if params[:action] == 'advance_search' && !Rails.env.test? %>\n      <%= AdminData::Util.javascript_include_tag(\n                                                 'advance_search/advance_search', \n                                                 'advance_search/advance_search_structure', \n                                                 'advance_search/ajaxify_advance_search',\n                                                 'advance_search/act_on_result',\n                                                 'advance_search/build_first_row',\n                                                 'advance_search/event_bindings',\n                                                 'advance_search/trigger_submit_on_domready'\n                                                ).html_safe %>\n    <% end %>\n  \n  </head>\n\n  <body>\n    \n    \t\t  <div class=\"gt-util-box-inner\">\n          <%= render :partial => \"layouts/account_menu\" -%>\n    \t\t\t</div>\n\n    \n    <noscript>\n      <div id=\"noscript-warning\">JavaScript is disabled. A few things might not work properly.</div>\n      <br />\n      <br />\n    </noscript>\n    <div>\n      <%= render 'admin_data/shared/header', :drop_down_for_klasses => @drop_down_for_klasses %>\n      <div class='clear'></div>\n    </div>  \n    <div id=\"container\">\n      <div id=\"wrapper\">\n        <%= yield %>\n        <div class=\"clear\"></div>      \n      </div>    \n      <%= render :partial => 'admin_data/shared/powered_by' %>\n    </div>\n  </body>\n  \n</html>\n"
  },
  {
    "path": "vendor/plugins/admin_data/config/routes.rb",
    "content": "ActionController::Routing::Routes.draw do |map|\n\n  map.namespace(:admin_data) do |admin_data|\n    \n    admin_data.with_options :controller => 'main' do |m|\n      m.index                       '/',                                :action => 'all_models'\n    end\n\n    admin_data.with_options :controller => 'migration' do |m|\n      m.migration_information       '/migration',                       :action => 'index'\n      m.jstest                      '/jstest',                          :action => 'jstest'\n    end\n\n    admin_data.with_options :controller => 'feed' do |m|\n      m.feed                        '/feed/:klasss',                    :action => 'index', \n                                                                        :format => :rss\n    end\n\n    admin_data.with_options :controller => 'search' do |m|\n      m.search                      '/quick_search/:klass',             :action => 'quick_search'\n      m.advance_search              '/advance_search/:klass',           :action => 'advance_search'\n    end\n\n\n    admin_data.resources  :on_k,\n                          :as => ':klass',\n                          :path_prefix => 'admin_data/klass',\n                          :controller => 'main',\n                          :member => {:del => :delete},\n                          :collection => {:table_structure => :get}\n\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/doc/git.txt",
    "content": "git co gh-pages\n"
  },
  {
    "path": "vendor/plugins/admin_data/init.rb",
    "content": "# do not raise exception if will_paginate is missing because running\n# rake gems:install will never complete\ndef load_will_paginate\n  begin\n    require 'will_paginate'\n    true\n  rescue LoadError => e\n    $stderr.puts %(\n    ***********************************************\n    * gem will_paginate is missing                *\n    * plugin admin_data depends on will_paginate  *\n    * Please install will_paginate by executing   *\n    * sudo gem install will_paginate              *\n    ***********************************************\n    )\n    false\n  end\nend\n\nif load_will_paginate\n\n  require 'admin_data_date_validation'\n\n  if Rails.version < \"2.2.0\"\n    raise %( plugin admin_data only works with Rails 2.2 and higher)\n  elsif Rails.version > '2.2.0' && Rails.version < '2.3.0'\n    raise %( This version of plugin admin_data only works with Rails 2.3 and higher. ) << \n          %( You are using Rails 2.2 . Please read README on how to use this plugin with Rails 2.2')\n  end\n\n  ActionView::Base.send :include, AdminData::Helpers\n\n  require File.join(Rails.root, 'vendor', 'plugins', 'admin_data', 'lib', 'admin_data', 'compatibility.rb')\n  require File.join(Rails.root, 'vendor', 'plugins', 'admin_data', 'lib', 'admin_data', 'settings.rb')\n\n  AdminData::Config.initialize_defaults\n\n  require File.join(Rails.root, 'vendor', 'plugins', 'admin_data', 'lib', 'admin_data','util.rb')\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/admin_data/chelper.rb",
    "content": "module AdminData::Chelper\n\n  def per_page\n    AdminData::Config.setting[:will_paginate_per_page]\n  end\n\n  def admin_data_is_allowed_to_view?\n    # return true if Rails.env.development?\n    AdminData::Config.setting[:is_allowed_to_view].call(self)\n  end\n\n  def admin_data_is_allowed_to_view_model?\n    # return true if Rails.env.development?\n    AdminData::Config.setting[:is_allowed_to_view_model].call(self)\n  end\n\n  def admin_data_is_allowed_to_update?\n    # return true if Rails.env.development?\n    AdminData::Config.setting[:is_allowed_to_update].call(self)\n  end\n\n  def admin_data_is_allowed_to_update_model?\n    # return true if Rails.env.development?\n    AdminData::Config.setting[:is_allowed_to_update_model].call(self)\n  end\n\n  def admin_data_invalid_record_link(klassu, id, error)\n    record = klassu.camelize.constantize.send(:find, id)\n    tmp = admin_data_on_k_path(:klass => klasss.underscore, :id => record)\n    a = []\n    a << link_to(klasss, tmp, :target => '_blank')\n    a << id\n    a << error\n    a.join(' | ')\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/admin_data/compatibility.rb",
    "content": "class String\n  unless method_defined?(:html_safe)\n    def html_safe\n      self\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/admin_data/lib/admin_data/helpers.rb",
    "content": "module AdminData::Helpers\n\n  def search_result_title(total_num_of_children, records)\n    output = []\n    if params[:base]\n      label = params[:base].camelize + ' ID ' + params[:model_id]\n      output << link_to(label, admin_data_on_k_path(:klass => params[:base], :id => params[:model_id]))\n      output << 'has'\n      output << pluralize(total_num_of_children, params[:klass])\n\n    elsif !params[:query].blank? || params[:adv_search]\n      output << 'Search result:'\n      output << pluralize(records.total_entries, 'record')\n      output << 'found'\n\n    else\n      output << 'All '\n      output << params[:klass].camelize\n      output << 'records'\n    end\n    output.join(' ')\n  end\n\n  def admin_data_column_native(klass, column)\n    klass.send(:columns).select {|r| r.instance_variable_get('@name') == column}.first\n  end\n\n  def admin_data_invalid_record_link(klassu, id, error)\n    record = klassu.camelize.constantize.send(:find, id)\n    tmp = admin_data_on_k_path(:klass => klassu, :id => record)\n    a = []\n    a << link_to(klassu.camelize, tmp, :target => '_blank')\n    a << id\n    a << error\n    a.join(' | ')\n  end\n\n  def admin_data_has_one(model, klass)\n    tmp = AdminData::Util.has_one_what(klass)\n    tmp.inject('') do |output, ho|\n      begin\n        label = ho\n        if model.send(ho)\n          has_one_klass_name = AdminData::Util.get_class_name_for_has_one_association(model, ho).name.underscore\n          output << link_to(label, admin_data_on_k_path(:klass => ho.underscore, :id => model.send(ho)))\n        else\n          output << label\n        end\n      rescue => e\n        Rails.logger.debug AdminData::Util.exception_info(e)\n      end\n      output\n    end\n  end\n\n  def admin_data_has_many_data(model, klass)\n    array = AdminData::Util.has_many_what(klass).inject([]) do |output, hm|\n      begin\n        label = hm + '(' + AdminData::Util.has_many_count(model,hm).to_s + ')'\n        if AdminData::Util.has_many_count(model,hm) > 0\n          has_many_klass_name = AdminData::Util.get_class_name_for_has_many_association(model,hm).name.underscore\n          output << link_to(label, admin_data_search_path(  :klass => has_many_klass_name,\n          :children => hm,\n          :base => klass.name.underscore,\n          :model_id => model.id))\n        else\n          output << label\n        end\n      rescue => e\n        Rails.logger.debug AdminData::Util.exception_info(e)\n      end\n      output\n    end\n    array.join(', ')\n  end\n\n  def admin_data_belongs_to_data(model, klass)\n    array = AdminData::Util.belongs_to_what(klass).inject([]) do |output, bt|\n      begin\n        t = AdminData::Util.get_class_name_for_belongs_to_class(model, bt)\n        klass_name = t[:polymorphic] ? 'Polymorphic' : t[:klass_name]\n        belongs_to_record = model.send(bt)\n\n        if belongs_to_record && t[:polymorphic]\n          output << link_to(belongs_to_record.class.name,\n          admin_data_on_k_path(:klass => belongs_to_record.class.name.underscore, :id => belongs_to_record))\n        elsif belongs_to_record\n          output << link_to(bt, admin_data_on_k_path(:klass => klass_name.underscore, :id => model.send(bt)))\n        else\n          output << bt\n        end\n      rescue => e\n        Rails.logger.info AdminData::Util.exception_info(e)\n      end\n      output\n    end\n    array.join(', ')\n  end\n\n  def admin_data_breadcrum(&block)\n    partial_value = render(:partial => '/admin_data/shared/breadcrum', :locals => {:data => capture(&block)})\n    concat(partial_value)\n  end\n\n  def admin_data_form_field(klass, model, col, f)\n    html = []\n    column_value = model.send(col.name)\n\n    if klass.serialized_attributes.has_key?(col.name)\n      return AdminData::Util.get_serialized_value(html,column_value)\n    end\n\n    if col.primary\n      html <<  model.new_record? ? '(auto)' : model.id\n\n    elsif get_reflection_for_column(klass, col) && AdminData::Config.setting[:drop_down_for_associations]\n      admin_data_form_field_for_association_records(klass, col, f, html)\n    else\n      admin_data_handle_column_type(col, html, model, column_value, f)\n    end\n  end\n\n\n  def admin_data_form_field_for_association_records(klass, col, f, html)\n    begin\n      reflection = get_reflection_for_column(klass, col)\n\n      # in some edge cases following code throws exception. investigating ..\n      options = reflection.options\n      if options.keys.include?(:polymorphic) && options.fetch(:polymorphic)\n        build_text_field(html, f, col)\n      else\n        ref_klass = reflection.klass\n        association_name = ref_klass.columns.map(&:name).include?('name') ? :name : ref_klass.primary_key\n        all_for_dropdown = ref_klass.all(:order => \"#{association_name} asc\")\n        html << f.collection_select(col.name, all_for_dropdown, :id, association_name, :include_blank => true)\n      end\n      html.join\n    rescue Exception => e\n      Rails.logger.info AdminData::Util.exception_info(e)\n      'could not retrieve' # returning nil\n    end\n  end\n\n  def admin_data_handle_column_type(col, html, model, column_value, f)\n    case col.type\n    when :text\n      html << f.text_area(col.name, :rows => 6, :cols => 70)\n\n    when :datetime\n      if ['created_at', 'updated_at'].include?(col.name)\n        html <<  model.new_record? ? '(auto)' : column_value\n      else\n        value = params[:action] == 'new' ? Time.now : column_value\n        year_value = value.year if value\n        datetime_selects = f.datetime_select(col.name, :include_blank => true)\n        html << datetime_selects.gsub('type=\"hidden\"', 'type=\"text\" size=\"4\" class=\"nice-field\"')\n      end\n\n    when :date\n      value = params[:action] == 'new' ? Time.now : column_value\n      year_value = value.year if value\n      date_selects = f.date_select(col.name, :discard_year => true, :include_blank => true)\n      html << date_selects.gsub('type=\"hidden\"', 'type=\"text\" size=\"4\" class=\"nice-field\"')\n\n    when :time\n      # time_select method of rails is buggy and is causing problem\n      # 1 error(s) on assignment of multiparameter attributes\n      #\n      # will try again this method with Rails 3\n      #html << f.time_select(col.name, :include_blank => true, :include_seconds => true)\n\n    when :boolean\n      html << f.select(col.name, [['True', true], ['False', false]], :include_blank => true)\n\n    else\n      build_text_field(html, f, col)\n    end\n    html.join\n  end\n\n\n  def build_text_field(html, f, col)\n    options = {:class => 'nice-field'}\n    if AdminData::Config.setting[:ignore_column_limit]\n      options[:size] = 60\n      options[:maxlength] = 255\n    else\n      options[:size] = (col && col.limit && col.limit < 60) ? col.limit : 60\n      options[:maxlength] = col.limit if col.limit\n    end\n    html << f.text_field(col.name, options)\n    html.join\n  end\n\n  # uses truncate method\n  # options supports :limit which is applied if the column type is string or text.\n  # calls the inspect method to convert to a string if the column is serialized.\n  def admin_data_get_value_for_column(column, model, options = {})\n    options.reverse_merge!(:limit => 400)\n\n    value = AdminData::Util.custom_value_for_column(column, model)\n\n    if column.type == :datetime\n      value.strftime('%d-%B-%Y %H:%M:%S %p') unless value.blank?\n    elsif column.type == :string || column.type == :text\n      value = value.inspect if model.class.serialized_attributes.keys.include?(column.name)\n      return value if options[:limit].blank?\n      begin\n        truncate(value,:length => options[:limit])\n      rescue # truncate method failed\n        '<actual data is not being shown because truncate method failed.>'\n      end\n    else\n      value\n    end\n  end\n\n  def get_reflection_for_column(klass, col)\n    klass.reflections.values.detect { |reflection| reflection.primary_key_name.to_sym == col.name.to_sym }\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/admin_data/rake_util.rb",
    "content": "class AdminData::RakeUtil\n\n  def self.process_klass(klasss, tid)\n    begin\n      puts \"processing #{klasss.inspect}\"\n      klass = AdminData::Util.constantize_klass(klasss)\n\n      AdminData::Util.write_to_validation_file(klass.name, 'a', tid, 'processing.txt')\n      number_of_records = klass.send(:count)\n      index = 0\n      all_records_are_valid = true\n\n      klass.paginated_each(:order => klass.primary_key) do |record|\n        index += 1\n        s = \"processed #{index} of #{number_of_records} #{name} records\"\n        AdminData::Util.write_to_validation_file(s, 'a', tid, 'processing.txt')\n        unless record.valid?\n          all_records_are_valid = false\n          error = [klass.name, record.id, record.errors.full_messages]\n          AdminData::Util.write_to_validation_file(error.join(' | '), 'a', tid, 'bad.txt')\n        end\n      end\n\n      if all_records_are_valid\n        s = \"#{klass.name} | #{klass.send(:count)} records: all valid\"\n        AdminData::Util.write_to_validation_file(s, 'a', tid, 'good.txt')\n      end\n    rescue Exception => e\n      AdminData::Util.write_to_validation_file(AdminData::Util.exception_info(e), 'a', 'rake_errors.txt')\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/admin_data/search.rb",
    "content": "module Search\n\n  class Dbbase\n    def initialize(operands, table_name, field_name, operator)\n      @operands = operands\n      @table_name = table_name\n      @field_name = field_name\n      @operator = operator\n    end\n\n    def like_operator\n      'LIKE'\n    end\n\n    def sql_field_name\n      \"#{@table_name}.#{@field_name}\"\n    end\n\n    def operands\n      @operands\n    end\n  end\n\n  class PostgresqlSpecific < Dbbase\n    def like_operator\n      'ILIKE'\n    end\n  end\n\n  class OracleSpecific < Dbbase\n    def sql_field_name\n      result = super\n      %w(contains is_exactly does_not_contain).include?(@operator) ?  \"upper(#{result})\" : result\n    end\n\n    def operands\n      result = super\n      %w(contains is_exactly does_not_contain).include?(@operator) ?  result.upcase : result\n    end\n  end\n\n  class Term\n\n    attr_accessor :error, :table_name, :field, :operator, :operands, :dbbase\n\n    def initialize(klass, value, search_type)\n      @table_name = klass.table_name\n      compute_search_fields(value)\n\n      adapter = AdminData::Config.setting[:adapter_name].downcase\n      if adapter =~ /postgresql/\n        self.dbbase = PostgresqlSpecific.new(@operands, table_name, field, operator)\n      elsif adapter =~ /oracle/\n        self.dbbase = OracleSpecific.new(@operands, table_name, field, operator)\n      else\n        self.dbbase = Dbbase.new(@operands, table_name, field, operator)\n      end\n    end\n\n    def attribute_condition\n      return if valid? && operand_required? && operands.blank?\n      case operator\n      when 'contains'\n        [\"#{sql_field_name} #{like_operator} ?\",\"%#{operands}%\"]\n\n      when 'is_exactly'\n        [\"#{sql_field_name} = ?\", operands]\n\n      when 'does_not_contain'\n        [\"#{sql_field_name} IS NULL OR #{sql_field_name} NOT #{like_operator} ?\",\"%#{operands}%\"]\n\n      when 'is_false'\n        [\"#{sql_field_name} = ?\",false]\n\n      when 'is_true'\n        [\"#{sql_field_name} = ?\",true]\n\n      when 'is_null'\n        [\"#{sql_field_name} IS NULL\"]\n\n      when 'is_not_null'\n        [\"#{sql_field_name} IS NOT NULL\"]\n\n      when 'is_on'\n        [\"#{sql_field_name} >= ? AND #{sql_field_name} < ?\",   values_after_cast.beginning_of_day,\n        values_after_cast.end_of_day]\n\n      when 'is_on_or_before_date'\n        [\"#{sql_field_name} <= ?\",values_after_cast.end_of_day]\n\n      when 'is_on_or_after_date'\n        [\"#{sql_field_name} >= ?\",values_after_cast.beginning_of_day]\n\n      when 'is_equal_to'\n        [\"#{sql_field_name} = ?\",values_after_cast]\n\n      when 'greater_than'\n        [\"#{sql_field_name} > ?\",values_after_cast]\n\n      when 'less_than'\n        [\"#{sql_field_name} < ?\",values_after_cast]\n\n      else\n        # it means user did not select anything in operator. Ignore it.\n      end\n    end\n\n    def valid?\n      @error = nil\n      @error = validate\n      @error.blank?\n    end\n\n    private\n\n    def like_operator\n      dbbase.like_operator\n    end\n\n    def sql_field_name\n      dbbase.sql_field_name\n    end\n\n    def operands\n      dbbase.operands\n    end\n\n    def operand_required?\n      operator =~ /(contains|is_exactly|does_not_contain|is_on |is_on_or_before_date|is_on_or_after_date |greater_than|less_than|is_equal_to)/\n    end\n\n    def compute_search_fields(value)\n      @field, @operator, @operands = value.values_at(:col1, :col2, :col3)\n      # field value is directly used in the sql statement. So it is important to sanitize it\n      @field      = @field.gsub(/\\W/,'')\n      @operands   = (@operands.blank? ? @operands : @operands.downcase.strip)\n    end\n\n    def values_after_cast\n      case operator\n      when /(is_on|is_on_or_before_date|is_on_or_after_date)/\n        AdminDataDateValidation.validate(operands)\n      when /(is_equal_to|greater_than|less_than)/\n        operands.to_i\n      else\n        operands\n      end\n    end\n\n    def validate\n      case operator\n      when /(is_on|is_on_or_before_date|is_on_or_after_date)/\n        \"#{operands} is not a valid date\" unless AdminDataDateValidation.validate(operands)\n      when /(is_equal_to|greater_than|less_than)/\n        unless operands.blank?\n          \"#{operands} is not a valid integer\" unless operands =~ /^\\d+$/\n        end\n      end\n    end\n\n  end # end of Term\n\n\n  def build_quick_search_conditions( klass, search_term )\n    return nil if search_term.blank?\n    str_columns = klass.columns.select { |column| column.type.to_s =~ /(string|text)/i }\n    conditions = str_columns.collect do |column|\n      t = Term.new(klass, {:col1 => column.name,\n        :col2 => 'contains',\n      :col3 => search_term}, 'quick_search')\n      t.attribute_condition\n    end\n    AdminData::Util.or_merge_conditions(klass, *conditions)\n  end\n\n  def build_advance_search_conditions(klass, options )\n    values        = ( options.blank? ? [] : options.values )\n    terms         = values.collect {|value| Term.new(klass, value, 'advance_search') }\n    valid_terms   = terms.select{ |t| t.valid? }\n\n    errors        = (terms - valid_terms).collect { |t| t.error }\n    return {:errors => errors} if errors.any?\n\n    conditions    = valid_terms.collect { |t| t.attribute_condition }\n    cond = klass.send(:merge_conditions, *conditions) # queries are joined by AND\n    { :cond => cond }\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/admin_data/settings.rb",
    "content": "class AdminData::Config\n\n  cattr_accessor :setting\n\n  def self.set=(input = {})\n    valid_keys =\n    %w(\n    find_conditions\n    plugin_dir\n    will_paginate_per_page\n    is_allowed_to_view\n    feed_authentication_user_id\n    feed_authentication_password\n    is_allowed_to_view_model\n    is_allowed_to_update\n    is_allowed_to_update_model\n    column_settings\n    columns_order\n    use_google_hosting_for_jquery\n    rake_options\n    drop_down_for_associations\n    ignore_column_limit\n    ).collect(&:intern)\n\n    extra_keys = input.keys - valid_keys\n    raise \"Following options are not supported. #{extra_keys.inspect}\" unless extra_keys.empty?\n\n    self.setting ||= {}\n    self.setting.merge!(input)\n\n    unless self.setting[:rake_options].blank?\n      env = self.setting[:rake_options][:env]\n      if env.blank? || env.include?(Rails.env.intern)\n        self.setting[:rake_command] = self.setting[:rake_options][:command]\n      end\n    end\n\n  end\n\n  def self.initialize_defaults\n    self.setting = {\n\n      :plugin_dir                   => File.expand_path(File.join(File.dirname(__FILE__), '..', '..')),\n\n      :will_paginate_per_page       => 50,\n\n      :is_allowed_to_view           => lambda {|controller| return true if Rails.env.development? },\n\n      :is_allowed_to_update         => lambda {|controller| return true if Rails.env.development? },\n\n      :is_allowed_to_view_model     => lambda {|controller| return true  },\n\n      :is_allowed_to_update_model   => lambda {|controller| return true  },\n\n      :find_conditions              => nil,\n\n      :use_google_hosting_for_jquery => true,\n\n      :drop_down_for_associations   => true,\n\n      :ignore_column_limit          => false,\n\n      :columns_order                => nil,\n\n      :adapter_name                 =>  ActiveRecord::Base.connection.adapter_name\n\n    }\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/admin_data/util.rb",
    "content": "class AdminData::Util\n\n  def self.google_hosted_jquery_ui_css(context)\n    if AdminData::Config.setting[:use_google_hosting_for_jquery]\n      jquery_ui_css = 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/base/jquery-ui.css'\n      jquery_ui_theme_css = 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/blitzer/jquery-ui.css'\n      context.send(:stylesheet_link_tag, jquery_ui_css, jquery_ui_theme_css)\n    else\n      stylesheet_link_tag('vendor/jquery-ui-1.7.2.custom')\n    end\n  end\n\n  def self.google_hosted_jquery(context)\n    if AdminData::Config.setting[:use_google_hosting_for_jquery]\n      jquery_min = 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js'\n      jquery_ui_min = 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js'\n      context.send(:javascript_include_tag, jquery_min, jquery_ui_min)\n    elsif Rails.env.test?\n      #  It is breaking the html markup and test is full of messages like\n      #  ignoring attempt to close string with script Hence not including jquery.form in test\n    else\n      javascript_include_tag('vendor/jquery-1.4.1', 'vendor/jquery-ui-1.7.2.custom.min')\n    end\n  end\n\n  def self.is_allowed_to_view_feed?(controller)\n    return true if Rails.env.development?\n    return true if Rails.env.test? #FIXME remove this line\n\n    if AdminData::Config.setting[:feed_authentication_user_id].blank?\n      Rails.logger.info 'No user id has been supplied for feed'\n      return false\n    end\n\n    if AdminData::Config.setting[:feed_authentication_password].blank?\n      Rails.logger.info 'No password has been supplied for feed'\n      return false\n    end\n\n    stored_userid = AdminData::Config.setting[:feed_authentication_user_id]\n    stored_password = AdminData::Config.setting[:feed_authentication_password]\n    self.perform_basic_authentication(stored_userid, stored_password, controller)\n  end\n\n  def self.perform_basic_authentication(stored_userid, stored_password, controller)\n    controller.authenticate_or_request_with_http_basic do |input_userid, input_password|\n      (input_userid == stored_userid) && (input_password == stored_password)\n    end\n  end\n\n\n  def self.label_values_pair_for(model, view)\n    model.class.columns.inject([]) do |sum, column|\n      tmp = view.admin_data_get_value_for_column(column, model, :limit => nil)\n      sum << [column.name, view.send(:h,tmp)]\n    end\n  end\n\n  def self.custom_value_for_column(column, model)\n    # some would say that if I use try method then I will not be raising exception and\n    # I agree. However in this case for clarity I would prefer to not to have try after each call\n    begin\n      AdminData::Config.setting[:column_settings].fetch(model.class.name.to_s).fetch(column.name.intern).call(model)\n    rescue\n      model.send(column.name)\n    end\n  end\n\n  def self.get_serialized_value(html, column_value)\n    html << %{ <i>Cannot edit serialized field.</i> }\n    unless column_value.blank?\n      html << %{ <i>Raw contents:</i><br/> }\n      html << column_value.inspect\n    end\n    html.join\n  end\n\n  def self.pluralize(count, text)\n    count > 1 ? text+'s' : text\n  end\n\n  # Rails method merge_conditions ANDs all the conditions. I need to ORs all the conditions\n  def self.or_merge_conditions(klass, *conditions)\n    s = ') OR ('\n    cond = conditions.inject([]) do |sum, condition|\n      condition.blank? ? sum : sum << klass.send(:sanitize_sql, condition)\n    end.compact.join(s)\n    \"(#{cond})\" unless cond.blank?\n  end\n\n  def self.camelize_constantize(klassu)\n    klasss = klassu.camelize\n    self.constantize_klass(klasss)\n  end\n\n  # klass_name = model_name.sub(/\\.rb$/,'').camelize\n  # constantize_klass(klass_name)\n  def self.constantize_klass(klass_name)\n    klass_name.split('::').inject(Object) do |klass, part|\n      klass.const_get(part)\n    end\n  end\n\n  def self.columns_order(klasss)\n    klass = self.constantize_klass(klasss)\n    columns = klass.columns.map(&:name)\n    columns_symbol = columns.map(&:intern)\n\n    columns_order = AdminData::Config.setting[:columns_order]\n\n    if columns_order && columns_order[klasss]\n      primary_key = klass.send(:primary_key).intern\n      order = [primary_key] + columns_order.fetch(klasss)\n      order.uniq!\n      sanitized_order = order - (order - columns_symbol)\n      sorted_columns = sanitized_order + (columns_symbol - sanitized_order)\n      return sorted_columns.map(&:to_s)\n    end\n\n    # created_at and updated_at should be at the very end\n    if columns_symbol.include? :created_at\n      columns_symbol = (columns_symbol - [:created_at]) + [:created_at]\n    end\n\n    if columns_symbol.include? :updated_at\n      columns_symbol = (columns_symbol - [:updated_at]) + [:updated_at]\n    end\n\n    columns_symbol.map(&:to_s)\n  end\n\n  # Usage: write 'hello world' to tmp/hello.txt file\n  # Util.write_to_file('hello world', 'a+', 'tmp', 'hello.txt')\n  def self.write_to_file(data, mode, *path)\n    path = File.expand_path(Rails.root.join(*path.flatten.compact))\n    FileUtils.mkdir_p(File.dirname(path))\n    File.open(path, mode) {|fh| fh.puts(data) }\n  end\n\n  def self.javascript_include_tag(*args)\n    data = args.inject('') do |sum, arg|\n      f = File.new(File.join(AdminData::Config.setting[:plugin_dir], 'lib', 'js', \"#{arg}.js\"))\n      sum << f.read\n    end\n    ['<script type=\"text/javascript\">', data, '</script>'].join\n  end\n\n  def self.stylesheet_link_tag(*args)\n    data = args.inject('') do |sum, arg|\n      f = File.new(File.join(AdminData::Config.setting[:plugin_dir], 'lib', 'css', \"#{arg}.css\"))\n      sum << f.read\n    end\n    [\"<style type='text/css'>\", data, '</style>'].join\n  end\n\n  def self.get_class_name_for_has_many_association(model, has_many_string)\n    data = model.class.name.camelize.constantize.reflections.values.detect do |value|\n      value.macro == :has_many && value.name.to_s == has_many_string\n    end\n    data.klass if data # output of detect from hash is an array with key and value\n  end\n\n  def self.get_class_name_for_belongs_to_class(model, belongs_to_string)\n    reflections = model.class.name.camelize.constantize.reflections\n    options = reflections.fetch(belongs_to_string.intern).send(:options)\n    return {:polymorphic => true} if options.keys.include?(:polymorphic) && options.fetch(:polymorphic)\n    {:klass_name => reflections[belongs_to_string.intern].klass.name }\n  end\n\n  def self.get_class_name_for_has_one_association(model, has_one_string)\n    data = model.class.name.camelize.constantize.reflections.values.detect do |value|\n      value.macro == :has_one && value.name.to_s == has_one_string\n    end\n    data.klass if data\n  end\n\n  def self.has_many_count(model, hm)\n    model.send(hm.intern).count\n  end\n\n  def self.has_many_what(klass)\n    associations_for(klass, :has_many).map(&:name).map(&:to_s)\n  end\n\n  def self.has_one_what(klass)\n    associations_for(klass, :has_one).map(&:name).map(&:to_s)\n  end\n\n  def self.belongs_to_what(klass)\n    associations_for(klass, :belongs_to).map(&:name).map(&:to_s)\n  end\n\n  def self.habtm_what(klass)\n    associations_for(klass, :has_and_belongs_to_many).map(&:name).map(&:to_s)\n  end\n\n  def self.admin_data_association_info_size(klass)\n    (belongs_to_what(klass).size > 0)  ||\n    (has_many_what(klass).size > 0) ||\n    (has_one_what(klass).size > 0) ||\n    (habtm_what(klass).size > 0)\n  end\n\n  def self.string_representation_of_data(value)\n    case value\n    when BigDecimal\n      value.to_s\n    when Date, DateTime, Time\n      \"'#{value.to_s(:db)}'\"\n    else\n      value.inspect\n    end\n  end\n\n  def self.build_sort_options(klass, sortby)\n    klass.columns.inject([]) do |result, column|\n      name = column.name\n\n      selected_text = sortby == \"#{name} desc\" ? \"selected='selected'\" : ''\n      result << \"<option value='#{name} desc' #{selected_text}>&nbsp;#{name} desc</option>\"\n\n      selected_text = sortby == \"#{name} asc\" ? \"selected='selected'\" : ''\n      result << \"<option value='#{name} asc' #{selected_text}>&nbsp;#{name} asc</option>\"\n    end\n  end\n\n  def self.associations_for(klass, association_type)\n    klass.name.camelize.constantize.reflections.values.select do |value|\n      value.macro == association_type\n    end\n  end\n\n  def self.exception_info(e)\n    \"#{e.class}: #{e.message}#$/#{e.backtrace.join($/)}\"\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/admin_data_date_validation.rb",
    "content": "require 'date'\n\nclass AdminDataDateValidation\n\n  def self.validate_with_operator(input)\n    return false if input.blank?\n\n    input.strip!\n\n    # replace multiple consecutive white spaces by one single whitespace\n    input.gsub!(/\\s+/,' ')\n    operator, date = input.split\n    return false if operator.nil?\n    return false unless %w(> < >= <= =).include? operator\n    validate(date)\n  end\n\n  # Usage:\n  #\n  # validate('13-feb-2008') # => time_object\n  # validate('13-February-2008') # => time_object\n  # validate('13-February-2008') # => time_object\n  # validate('30-Feb-2008') #=> false\n  #\n  def self.validate(input)\n    return false if input.nil?\n\n    input.strip!\n\n    # remove all the white space characters\n    input.gsub!(/\\s/,'')\n\n    return false if input.length < 9\n\n    dd,mm,yyyy = input.split('-')\n    return false if dd.nil?\n    return false if mm.nil?\n    return false if yyyy.nil?\n\n    # month must be of aleast three characters\n    return false if mm.length < 3\n\n    mm = mm.downcase\n\n    #get only the first three characters\n    mm = mm[0,3]\n\n    months = {'jan' => 1,\n      'feb' => 2,\n      'mar' => 3,\n      'apr' => 4,\n      'may' => 5,\n      'jun' => 6,\n      'jul' => 7,\n      'aug' => 8,\n      'sep' => 9,\n      'oct' => 10,\n      'nov' => 11,\n    'dec' => 12 }\n\n    return false unless months.keys.include? mm\n\n    mm = months[mm]\n    mm = mm.to_i\n    yyyy = yyyy.to_i\n    dd = dd.to_i\n\n    # validate date values\n    begin\n      Date.new(yyyy,mm,dd)\n    rescue  => e\n      return false\n    end\n\n    t = Time.now\n    t.change(:year => yyyy, :month => mm, :day => dd, :hour => 0)\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/css/app.css",
    "content": "#footer {\n  padding-left:30px;\n}\n\n.search_form { \n  margin:15px 5px 5px 5px;\n  padding:5px;\n}\n\n.breadcrum {\n  margin-bottom: 15px;\n  background: #fff;\n  padding: 10px 4px;\n}\n\n#quick_search_input { font-size: 15px; }\n\ntable.with_border td{\n\tborder:2px solid #DEDEDE;\n\tpadding:5px;\n}\n\ntable {\n\tborder-collapse: collapse;\n\tborder-spacing: 0;\n}\n\n.advtable {\n\tfont-size: 15px;\n}\n\n#advance_search_table select {\n\tfont-size: 15px;\n\twidth: 280px;\n\tpadding: 2px;\n\tmargin: 2px;\n}\n\n#advance_search_table select option {\n   padding: 2px 5px;\n}\n\n.advtable td {\n\tborder-bottom: 1px solid #F0F0EE;\n\tpadding: 10px;\n}\n\n.ram_input_field_col3 {\n\tfont-size: 15px;\n}\n\n/*IE6 will ignore this*/\ninput[disabled], input[readonly], select[disabled], select[readonly], checkbox[disabled], checkbox[readonly], textarea[disabled], textarea[readonly]\n{\n background-color: #dcdcdc;\n border:  1px solid gray;\n color: #000000;\n cursor: default;\n}\n\ninput.col3 {\n  height: 20px;\n  font-size: 16px;\n}\n\nspan.searching_message{\n  color: red;\n  font-size: 25px;\n  margin: 20px 0 20px 0;\n}\n\ntable#view_table {\n\tpadding: 0;\n  margin: 5px 0 5px 0;\n\tborder-collapse: collapse;\n\tborder-spacing: 0;\n}\n\ntable#view_table th {\n\tborder: 1px solid #ccc;\n\tletter-spacing: 2px;\n\ttext-align: left;\n\tpadding: 6px 6px 6px 12px;\n}\n\n\ntable#view_table td {\n\tborder: 1px solid #DEDEDE;\n\tpadding: 6px 6px 6px 12px;\n}\n\ntable#view_table tr:hover {\n  background: #FFFFC0;\n}\n\n\n#model_drop_down {\n float: right;\n margin: 0 10px;\n}\n\n.drop_down_value_klass {\n  width: 300px;\n  font-size: 14px;\n  padding: 5px;\n}\n\n.drop_down_value_klass option {\n  padding: 2px;\n}\n\n\n.klass_box { \n  margin: 15px 0 15px 0;\n  padding: 15px 20px 15px 0;\n  line-height: 40px;\n  font-size: 16px;\n}\n\n.klass_description {\n  font-size: 90%;\n}\n\n#footer p {\n  float: left;\n  font-size: 11px;\n  padding: 2px 10px 2px 2px;\n}\n\n#main {\n  width: 100%;\n}\n\n\n.main2 {\n  background-color: #FFF;\n  padding: 5px;\n  margin: 10px 2px 10px 2px;\n  float: left;\n}\n\n.error {\n   color: red;\n   font-size: 16px;\n}\n\n#noscript-warning {\n  background-color:#AE0000;\n  color:#FFFFFF;\n  font-family:Arial,Helvetica,sans-serif;\n  font-size:140%;\n  font-weight:bold;\n  left:0;\n  padding:5px 0;\n  position:fixed;\n  text-align:center;\n  top:0;\n  width:100%;\n  z-index:101;\n}\n\na:link, a:visited, a:active {\n  text-decoration: none;\n  color: green;\n}\n\na:hover {\n  text-decoration: underline;\n  color: #f03;\n}\n\n#footer a, .group a, .pagination a {\n  color: #36393d;\n}\n\n.association_info {\n  line-height: 20px;\n}\n\ntable#missing_index tr td {\n  height: 25px;\n}\n\n#main .block .content #validate_model_rhs_data p {\n   font-size: 16px;\n}\n\n.clear { clear: both; }\n\n.rounded {\n    -moz-border-radius: 5px; /* Firefox */\n    -webkit-border-radius: 5px; /* Safari */\n}\n\n.powered_by {\n  font-family: Arial;\n  font-size: 12px;\n}\n\n.submit_search { \n  float: left;\n  border: 2px solid #127BC4;\n  color: #fff;\n  background: #4F8AFF;\n  padding: 3px;\n  font-weight: bold;\n  font-size: 16px;\n}\n\n\n.add_row_link, .remove_row {\n  font-size: 30px;\n  text-decoration: none;\n  border: 1px solid #127BC4;\n  color: #fff;\n  background: #4F8AFF;\n  padding: 0 3px;\n  margin: 0;\n}\n\n#advance_search_table a {\n  color: #fff;\n}\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/css/base.css",
    "content": "* {\n  margin: 0;\n  padding:0\n}\n\n.clear { clear: both; height: 0; }\n\nh1 { margin: 15px 0; font-size: 22px; font-weight: normal; }\nh2 { font-size: 22px; margin: 15px 0; font-weight: normal;}\nh3 { font-size: 18px; margin: 10px 0; font-weight: normal;}\nh4 { font-size: 16px; margin: 10px 0; font-weight: normal;}\nhr {height: 1px; border: 0; }\np { margin: 15px 0;}\na img { border: none; }\n\nbody {\n  font-size: 15px;\n  font-family: sans-serif;  \n  background: #fff;\n}\n\n#container {\n  min-width: 940px;\n  margin: 0 10px;\n}\n\n#header, #wrapper {\n  padding: 0 20px;\n}\n\n#header {\n  position: relative;\n  padding-top: 0px;  \n  margin-top: 0px;\n  margin-bottom: 15px;\n  margin:0; \n  background: #ddd;\n  float: left;\n  width: 100%;\n  font-size: 20px;\n  background-color: #D5E9F6;\n}\n\n#header h1 {\n  margin: 0;\n  padding: 10px 0;  \n  font-size: 40px;\n  float: left;\n  padding: 15px 45px 15px 10px;\n  font-style: normal;\n  font-weight: bold;\n  text-transform: normal;\n  letter-spacing: 1px;\n  line-height: 1.2em;\n}\n\n#header h1 a:link, #header h1 a:active, #header h1 a:hover, #header h1 a:visited {\n  text-decoration: none;\n  font-family: \"Helvetica Neue Light\",\"HelveticaNeue-Light\",\"Helvetica Neue\",Calibri,Helvetica,Arial;\n  color: #000;\n}\n\n\n#main {  \n  width: 70%;\n  float: left;    \n}\n\n.actions-bar {\n  padding: 10px 1px;\n}\n\n.actions-bar .actions {\n  float: left;\n}\n\n\n.actions-bar .pagination {\n  float: right;\n  padding: 1px 0;\n}\n\n#sidebar {\n  width: 25%;\n  float: right;      \n}\n\n#sidebar h3 {  \n  padding: 10px 15px;\n  margin: 0;\n  font-size: 13px;\n}\n\n#sidebar .block {\n  margin-bottom: 20px;\n  padding-bottom: 10px;\n}\n\n#sidebar .block .content {\n  padding: 0 15px;\n}\n\n#sidebar ul.navigation li a:link, #sidebar ul.navigation li a:visited {\n  display: block;\n  padding: 10px 15px;\n}\n\n#sidebar .block .sidebar-block, #sidebar .notice {\n  padding:10px;\n}\n\n#wrapper {\n  padding-top: 20px;\n}\n\n#main .block {\n  margin-bottom: 20px;\n  padding-top: 1px;\n}\n\n#main .block .content .inner {\n  padding: 0 15px 15px;  \n}\n\n#main .main p.first {\n  margin-top: 0;\n}\n\n#user-navigation {\n  position: absolute;\n  top: 0px;\n  right: 20px;  \n}\n\n#main-navigation {\n  width: 100%;\n}\n\n#user-navigation ul, #main-navigation ul, .secondary-navigation ul, #sidebar ul.navigation {\n  margin: 0;\n  padding: 0;\n  list-style-type: none;\n}\n\n#user-navigation ul li, #main-navigation ul li, .secondary-navigation ul li {\n  float: left;  \n}\n\n#main-navigation ul li {\n  margin-right: 5px;\n}\n\n#user-navigation ul li {\n  padding: 5px 10px;\n}\n\n#main-navigation ul li a:link, #main-navigation ul li a:visited, #main-navigation ul li a:hover, #main-navigation ul li a:active,\n.secondary-navigation ul li a:link, .secondary-navigation ul li a:visited, .secondary-navigation ul li a:hover, .secondary-navigation ul li a:active,\n#user-navigation ul li a:link, #user-navigation ul li a:visited, #user-navigation ul li a:hover, #user-navigation ul li a:active {\n  text-decoration: none;\n}\n\n#main-navigation ul li a {\n  font-size: 15px;\n  display: block;\n  padding: 8px 15px;\n}\n\n.secondary-navigation {\n  font-size: 13px;  \n  border-bottom-width: 10px;\n  border-bottom-style: solid;\n}\n\n.secondary-navigation ul li a {\n  display: block;\n  padding: 10px 15px;  \n}\n\n#footer {\n  padding-bottom: 20px;\n}\n\n/* pagination */\n\n.pagination a, .pagination span {\n  padding: 2px 5px;\n  margin-right: 5px; \n  display: block;\n  float: left;\n  border-style: solid;\n  border-width: 1px;\n}\n\n.pagination span.current {\n  font-weight: bold;  \n}\n\n.pagination a {\n  text-decoration: none;  \n}\n\n/* tables */\n.table {\n  width: 100%;\n  border-collapse: collapse;  \n  margin-bottom: 15px;\n}\n\n.table th {\n  padding: 10px;\n  font-weight: bold;\n  text-align: left;\n}\n\n.table th.first {\n  width: 30px;\n}\n\n.table th.last {\n  width: 200px;  \n}\n\n.table .checkbox {\n  margin-left: 10px;\n}\n\n.table td {\n  padding: 10px;\n}\n\n.table td.last {\n  text-align: right;\n}\n\n/* forms */\n\ninput.checkbox {\n  margin: 0;\n  padding: 0;\n}\n\n.form .group {\n  margin-bottom: 15px;\n}\n\n.form div.left {\n  width: 20%;\n  float: left;\n}\n\n.form div.right {\n  width: 75%;\n  float: right;\n}\n\n.form .columns .column {\n  width: 48%;\n}\n\n.form .columns .left {\n  float: left;\n}\n\n.form .columns .right {\n  float: right;\n}\n\n.form label.label, .form input.text_field, .form textarea.text_area {\n  font-size: 1.2em;\n  padding: 1px 0;\n  margin: 0;\n}\n\n.form label.right {\n  text-align: right;\n}\n\n.form input.checkbox, .form input.radio {\n  margin-right: 5px;\n}\n\n.form label.checkbox, .form label.radio {\n  line-height: 1.5em;\n}\n\n.form label.label {\n  display: block;\n  padding-bottom: 2px;  \n  font-weight: bold;\n}\n\n.form div.fieldWithErrors label.label {\n  display: inline;\n}\n\n.form .fieldWithErrors .error {\n  color: red;\n}\n\n.form input.text_field, .form textarea.text_area {\n  width: 100%;\n  border-width: 1px;\n  border-style: solid;\n}\n\n/* lists */\n\nul.list {\n  margin: 0;\n  padding: 0;\n  list-style-type: none;\n}\n\nul.list li {\n  clear: left;\n  padding-bottom: 5px;\n}\n\nul.list li .left {\n  float: left;  \n}\n\nul.list li .left .avatar {\n  width: 50px;\n  height: 50px;\n}\n\nul.list li .item {\n  margin-left: 80px;\n}\n\nul.list li .item .avatar {\n  float: left;\n  margin: 0 5px 5px 0;\n  width: 30px;\n  height: 30px;\n}\n\n/* box */\n\n#box {\n  width: 500px;\n  margin: 50px auto;  \n}\n\n#box .block {\n  margin-bottom: 20px;\n}\n\n#box .block h2 {\n  padding: 10px 15px;\n  margin: 0;  \n}\n\n#box .block .content {\n  padding: 10px 20px;\n}\n\n\n/*\n\n    Drastic Dark\n    by Juan Maria Martinez Arce\n       juan[at]insignia4u.com\n\n    light grey:                 #ededec\n    medium grey:                #36393d\n    dark grey:                  #1a1a1a\n    interactive action yellow   #ffff88\n    red                         #cc0000\n    light blue                  #E6EEFC\n    dark blue                   #0B43A8\n\n*/\n\n.small {\n  font-size: 11px;\n  font-style: normal;\n  font-weight: normal;\n  text-transform: normal;\n  letter-spacing: normal;\n  line-height: 1.4em;\n}\n\n.gray {\n  color:#999999;\n  font-family: Georgia, serif;\n  font-size: 13px;\n  font-style: italic;\n  font-weight: normal;\n  text-transform: normal;\n  letter-spacing: normal;\n  line-height: 1.6em;\n}\n\n.hightlight {\n  background-color: #ffff88;\n  font-weight: bold;\n  color: #36393d;\n}\n\na:link, a:visited, a:hover, a:active, h1, h2, h3 { color: #36393d; }\na { -moz-outline: none; }\n\nbody {\n  color: #222;\n  background: #ededec;\n  font-family: helvetica, arial, sans-serif;\n}\n\nhr {\n  background: #f0f0ee;\n  color: #f0f0ee;\n}\n\n\n#user-navigation {\n  top: auto;\n  bottom: 5px;\n  right: 25px;\n}\n\n#user-navigation a.logout {\n  background: #cc0000;\n  padding: 1px 4px;\n  -moz-border-radius: 4px;\n\t-webkit-border-radius: 3px;\n}\n\n#main .block .content {\n  background: #FFF;\n  padding-top: 1px;\n}\n\n#main .block .content h2 {\n  margin-left: 15px;\n  font-size: 22px;\n  font-style: normal;\n  font-weight: bold;\n  text-transform: normal;\n  letter-spacing: -1px;\n  line-height: 1.2em;\n}\n\n#main .block .content p {\n  font-size: 13px;\n  font-style: normal;\n  font-weight: normal;\n  text-transform: normal;\n  letter-spacing: normal;\n  line-height: 1.45em;\n}\n\n#sidebar .block {\n  background: #FFF;\n}\n\n#sidebar .block h4 {\n  font-weight: bold;\n}\n\n#sidebar .notice {\n  background: #E6EEFC;\n}\n\n#sidebar .notice h4 {\n  color: #0B43A8;\n}\n\n#sidebar h3 {\n  background: #36393d;\n  color: #FFF;\n  border-bottom: 5px solid #1a1a1a;\n}\n\n#main-navigation ul li {\n  padding-left: 15px;\n}\n\n#main-navigation ul li a {\n  padding: 8px 0;\n}\n\n#main-navigation ul li.active {\n  padding: 0;\n  margin-left: 15px;\n}\n\n#main-navigation ul li.active {\n  margin-left: 15px;\n}\n\n#main-navigation ul li.active a {\n  padding: 8px 15px;\n}\n\n#sidebar ul li a:link, #sidebar ul li a:visited {\n  background: #FFF;\n  border-bottom: 1px solid #F0F0EE;\n  text-decoration: none;\n}\n\n#sidebar ul li a:hover, #sidebar ul li a:active {\n  background: #666666;\n  color: #ffffff;;\n}\n\n#main-navigation {\n  background: #1a1a1a;\n}\n\n#main-navigation ul li {\n  background: #1a1a1a;\n  margin-right: 0;\n}\n\n#main-navigation ul li.active {\n  background: #f0f0ee;\n}\n\n#main-navigation ul li a:link, #main-navigation ul li a:visited, #main-navigation ul li a:hover, #main-navigation ul li a:active,\n.secondary-navigation ul li a:link, .secondary-navigation ul li a:visited, .secondary-navigation ul li a:hover, .secondary-navigation ul li a:active,\n#user-navigation ul li a:link, #user-navigation ul li a:visited, #user-navigation ul li a:hover, #user-navigation ul li a:active {\n  text-decoration: none;\n  color: #FFF;\n}\n\n.secondary-navigation li a:hover {\n  background: #666666;\n}\n\n#main-navigation ul li.active a:link, #main-navigation ul li.active a:visited, #main-navigation ul li.active a:hover, #main-navigation ul li.active a:active {\n  color: #1a1a1a;\n}\n\n.secondary-navigation {\n  background: #36393d;\n  border-bottom-color: #4F8AFF;\n}\n\n.secondary-navigation ul li.active, .secondary-navigation ul li.active a:hover {\n  background: #1a1a1a;\n  background: #4F8AFF;\n}\n\n#footer .block {\n  color: #FFF;\n  background: #1a1a1a;\n}\n\n#footer .block p {\n  margin: 0;\n  padding: 10px;\n}\n\n/* pagination */\n\n.pagination a, .pagination span {\n  background: #ededec;\n  -moz-border-radius: 3px;\n  border: 1px solid #c1c1c1;\n}\n\n.pagination span.current {\n  background: #36393d;\n  color: #FFF;\n  border: 1px solid #36393d;\n}\n\n.pagination a {\n  color: #1a1a1a;\n}\n\n.pagination a:hover {\n  border: 1px solid #666;\n}\n\n/* tables */\n\n.table th {\n  background: #36393d;  \n  color: #FFF;\n}\n\n.table td {\n  border-bottom:1px solid #F0F0EE;\n}\n\n.table tr.even {\n  background: #ebebeb;\n}\n\n/* forms */\n\n.form label.label {\n  color: #666666;\n}\n\n.form input.text_field, .form textarea.text_area {\n  width: 100%;\n  border: 1px solid #ededec;\n}\n\n.form input.button {\n  background: #ededec;\n  -moz-border-radius: 5px;\n  border: 1px solid #c1c1c1;\n  padding: 2px 5px;\n  cursor: pointer;\n  color: #36393d;\n  font-weight: bold;\n  font-size: 11px;\n}\n\n.form input.button:hover {\n  border: 1px solid #666;\n}\n\n.form .description {\n  font-style: italic;\n  color: #8C8C8C;\n  font-size: .9em;\n}\n\n.form .navform a {\n  color: #cc0000;\n}\n\n/* flash-messages */\n.flash .message {\n  -moz-border-radius: 3px;\n  -webkit-border-radius: 3px;\n  text-align:center;\n  margin: 0 auto 15px;\n\n}\n\n.flash .message p {\n  margin:8px;\n}\n.flash .error {\n  border: 1px solid #fbb;\n  background-color: #fdd;\n}\n.flash .warning {\n  border: 1px solid #fffaaa;\n  background-color: #ffffcc;\n}\n.flash .notice {\n  border: 1px solid #1FDF00;\n  background-color: #BBFFB6;\n}\n\n/* lists */\n\nul.list li {\n  border-bottom-color: #F0F0EE;\n  border-bottom-width: 1px;\n  border-bottom-style: solid;\n}\n\nul.list li .item .avatar {\n  border-color: #F0F0EE;\n  border-width: 1px;\n  border-style: solid;\n  padding: 2px;\n}\n\n/* box */\n\n#box .block {\n  background: #FFF;\n}\n\n#box .block h2 {\n  background: #36393d;\n  color: #FFF;\n}\n\n\n/* rounded borders */\n\n#main, #main-navigation, #main-navigation li, .secondary-navigation, #main .block, #sidebar .block, #sidebar h3, ul.list li,\n#footer .block, .form input.button, #box .block, #box .block h2 {\n  -moz-border-radius-topleft: 4px;\n  -webkit-border-top-left-radius: 4px;\n  -moz-border-radius-topright: 4px;\n  -webkit-border-top-right-radius: 4px;\n}\n\n.secondary-navigation li.first a, .secondary-navigation ul li.first, .table th.first, .table th.first {\n  -moz-border-radius-topleft: 4px;\n  -webkit-border-top-left-radius: 4px;\n}\n\n.table th.last {\n  -moz-border-radius-topright: 4px;\n  -webkit-border-top-right-radius: 4px;\n}\n\n.secondary-navigation ul li.first {\n  -moz-border-radius-topleft: 4px;\n  -webkit-border-top-left-radius: 4px;\n}\n\n#sidebar, #sidebar .block, #main .block, #sidebar ul.navigation, ul.list li, #footer .block, .form input.button, #box .block {\n  -moz-border-radius-bottomleft: 4px;\n  -webkit-border-bottom-left-radius: 4px;\n  -moz-border-radius-bottomright: 4px;\n  -webkit-border-bottom-right-radius: 4px;\n}\n\n.secondary-navigation {\n  border-bottom-width: 5px;\n}\n\n.umbrella {\n  font-family:lucida grande,verdana;\n  font-size:12px;\n  text-align:left;\n  }\n  .umbrella h1 {\n    color:#000000;\n    font-size: 26px;\n    font-weight: bold;\n    border-bottom: 1px dotted #CCCCCC;\n  }\n  #main .block .umbrella h2 {\n    color:#000000;\n    font-size:16px;\n    margin: 10px 0 2px 0;\n    padding:0;\n    font-family:\"Lucida Grande\",arial,sans-serif;\n    }\n    .umbrella h2 span {\n      color: #666;\n      font-size: 12px;\n      font-weight: normal;\n      }\n  .umbrella input {\n    font-size:14px;\n    margin-bottom:10px;\n    padding:3px;\n    }\n    .umbrella input.button {\n      font-size:14px;\n      margin:10px 0 0;\n      padding:3px;\n      width:auto;\n      }\n\ninput[type=\"button\"] { cursor: pointer; }\ninput.button { cursor: pointer; }\n\n.element { border: 1px solid red; }\n\n.rounded{\n    -moz-border-radius: 5px; /* Firefox */\n    -webkit-border-radius: 5px; /* Safari */\n}\n\n.flash .error {\n   background: #c00;\n   color: #fff;\n}\n\n.flash .message {\n   text-align: left;\n}\n\n\n#iheader {\n  margin: 0 auto;\n  width: 950px;\n}\n\n#header ul {\n  list-style: none;\n  padding: 10px 0 0 20px;\n  margin: 0;\n}\n\n#header ul li {\n  float: left;\n  border: 1px solid;\n  border-bottom-width: 0;\n  margin: 0 0.5em 0 0;\n}\n\n#header ul li#selected {\n  position: relative;\n  top: 1px;\n}\n\n#header ul li a {\n  display: block;\n  padding: 5px 6px 0 6px;\n  text-decoration: none;\n  color: white;\n  background: #1a4f85;\n}\n\n#header ul li#selected a {\n  background: #fff;\n  color: #1a4f85;\n}\n\n#header ul li a:hover {\n  background: #539ADF;\n}\n\n\n\n#footer {\n  padding-left:30px;\n}\n\n.search_form { \n  margin:15px 5px 5px 5px;\n  padding:5px;\n}\n\n.breadcrum {\n  margin-bottom: 15px;\n  background: #fff;\n  padding: 10px 4px;\n}\n\n#quick_search_input { font-size: 15px; }\n\ntable.with_border td{\n\tborder:2px solid #DEDEDE;\n\tpadding:5px;\n}\n\ntable {\n\tborder-collapse: collapse;\n\tborder-spacing: 0;\n}\n\n.advtable {\n\tfont-size: 15px;\n}\n\n#advance_search_table select {\n\tfont-size: 15px;\n\twidth: 280px;\n\tpadding: 2px;\n\tmargin: 2px;\n}\n\n#advance_search_table select option {\n   padding: 2px 5px;\n}\n\n.advtable td {\n\tborder-bottom: 1px solid #F0F0EE;\n\tpadding: 10px;\n}\n\n.ram_input_field_col3 {\n\tfont-size: 15px;\n}\n\n/*IE6 will ignore this*/\ninput[disabled], input[readonly], select[disabled], select[readonly], checkbox[disabled], checkbox[readonly], textarea[disabled], textarea[readonly]\n{\n background-color: #dcdcdc;\n border:  1px solid gray;\n color: #000000;\n cursor: default;\n}\n\ninput.col3 {\n  height: 20px;\n  font-size: 16px;\n}\n\nspan.searching_message{\n  color: red;\n  font-size: 25px;\n  margin: 20px 0 20px 0;\n}\n\ntable#view_table {\n\tpadding: 0;\n  margin: 5px 0 5px 0;\n\tborder-collapse: collapse;\n\tborder-spacing: 0;\n}\n\ntable#view_table th {\n\tborder: 1px solid #ccc;\n\tletter-spacing: 2px;\n\ttext-align: left;\n\tpadding: 6px 6px 6px 12px;\n}\n\n\ntable#view_table td {\n\tborder: 1px solid #DEDEDE;\n\tpadding: 6px 6px 6px 12px;\n}\n\ntable#view_table tr:hover {\n  background: #FFFFC0;\n}\n\n\n#model_drop_down {\n  position: absolute;\n  top: 10px;\n  right: 600px;\n}\n\n.drop_down_value_klass {\n  width: 300px;\n  font-size: 14px;\n  padding: 5px;\n  height: 40px;\n  line-height: 40px;\n}\n\n.drop_down_value_klass option {\n  padding: 2px;\n}\n\n\n.klass_box { \n  margin: 15px 0 15px 0;\n  padding: 15px 20px 15px 0;\n  line-height: 40px;\n  font-size: 16px;\n}\n\n.klass_description {\n  font-size: 90%;\n}\n\n#footer p {\n  float: left;\n  font-size: 11px;\n  padding: 2px 10px 2px 2px;\n}\n\n#main {\n  width: 100%;\n}\n\n\n.main2 {\n  background-color: #FFF;\n  padding: 5px;\n  margin: 10px 2px 10px 2px;\n  float: left;\n}\n\n.error {\n   color: red;\n   font-size: 16px;\n}\n\n#noscript-warning {\n  background-color:#AE0000;\n  color:#FFFFFF;\n  font-family:Arial,Helvetica,sans-serif;\n  font-size:140%;\n  font-weight:bold;\n  left:0;\n  padding:5px 0;\n  position:fixed;\n  text-align:center;\n  top:0;\n  width:100%;\n  z-index:101;\n}\n\na:link, a:visited, a:active {\n  text-decoration: none;\n  color: green;\n}\n\na:hover {\n  text-decoration: underline;\n  color: #f03;\n}\n\n#footer a, .group a, .pagination a {\n  color: #36393d;\n}\n\n.association_info {\n  line-height: 20px;\n}\n\ntable#missing_index tr td {\n  height: 25px;\n}\n\n.clear { clear: both; }\n\n.rounded {\n    -moz-border-radius: 5px; /* Firefox */\n    -webkit-border-radius: 5px; /* Safari */\n}\n\n.powered_by {\n  font-family: Arial;\n  font-size: 12px;\n}\n\n.submit_search { \n  float: left;\n  border: 2px solid #127BC4;\n  color: #fff;\n  background: #4F8AFF;\n  padding: 3px;\n  font-weight: bold;\n  font-size: 16px;\n}\n\n\n.add_row_link, .remove_row {\n  font-size: 30px;\n  text-decoration: none;\n  border: 1px solid #127BC4;\n  color: #fff;\n  background: #4F8AFF;\n  padding: 0 3px;\n  margin: 0;\n}\n\n#advance_search_table a {\n  color: #fff;\n}\n\nul#subnav {\n   background: #fff9d8;\n   display: inline;\n   padding: 10px 6px;\n   position: absolute;\n   text-align: right;\n   top: 0;\n   right: 200px;\n\n}\n\nul#subnav li {\n  display: inline;\n  border: 0;\n}\n\nul#subnav li a, ul#subnav li a:hover {\n  color: #000;\n  background-color: #fff9d8;\n  font-size: 14px;\n  font-weight: bold;\n  margin-left: 10px;\n  margin-right: 5px;\n  text-decoration: none;\n}\n\nul#subnav li a:hover {\n  text-decoration: underline;\n}\n\n\n.col_box {\n  border-top: 1px dotted #efefef;\n}\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/css/header.css",
    "content": "#header {\n  float: left;\n  width: 100%;\n  background: #003366;\n  font-size: 20px;\n}\n\n#iheader {\n  margin: 0 auto;\n  width: 950px;\n}\n\n#logo {\n  float: left;\n  color: #fff;\n  font-size: 30px;\n  padding: 5px 35px 0 5px;\n}\n\n#logo a {\n  color: #fff;\n  text-decoration: none;\n}\n\n#logo a:hover {\n  text-decoration: underline;\n}\n\n#header ul {\n  list-style: none;\n  padding: 10px 0 0 20px;\n  margin: 0;\n}\n\n#header ul li {\n  float: left;\n  border: 1px solid;\n  border-bottom-width: 0;\n  margin: 0 0.5em 0 0;\n}\n\n#header ul li#selected {\n  position: relative;\n  top: 1px;\n}\n\n#header ul li a {\n  display: block;\n  padding: 5px 6px 0 6px;\n  text-decoration: none;\n  color: white;\n  background: #1a4f85;\n}\n\n#header ul li#selected a {\n  background: #fff;\n  color: #1a4f85;\n}\n\n#header ul li a:hover {\n  background: #539ADF;\n}\n\n\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/css/rounded.css",
    "content": "input[type=\"button\"] { cursor: pointer; }\ninput.button { cursor: pointer; }\n\n.element { border: 1px solid red; }\n\n.rounded{\n    -moz-border-radius: 5px; /* Firefox */\n    -webkit-border-radius: 5px; /* Safari */\n}\n\n.flash .error {\n   background: #c00;\n   color: #fff;\n}\n\n.flash .message {\n   text-align: left;\n}\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/css/themes/drastic-dark/style.css",
    "content": "/*\n\n    Drastic Dark\n    by Juan Maria Martinez Arce\n       juan[at]insignia4u.com\n\n    light grey:                 #ededec\n    medium grey:                #36393d\n    dark grey:                  #1a1a1a\n    interactive action yellow   #ffff88\n    red                         #cc0000\n    light blue                  #E6EEFC\n    dark blue                   #0B43A8\n\n*/\n\n.small {\n  font-size: 11px;\n  font-style: normal;\n  font-weight: normal;\n  text-transform: normal;\n  letter-spacing: normal;\n  line-height: 1.4em;\n}\n\n.gray {\n  color:#999999;\n  font-family: Georgia, serif;\n  font-size: 13px;\n  font-style: italic;\n  font-weight: normal;\n  text-transform: normal;\n  letter-spacing: normal;\n  line-height: 1.6em;\n}\n\n.hightlight {\n  background-color: #ffff88;\n  font-weight: bold;\n  color: #36393d;\n}\n\na:link, a:visited, a:hover, a:active, h1, h2, h3 { color: #36393d; }\na { -moz-outline: none; }\n\nbody {\n  color: #222;\n  background: #ededec;\n  font-family: helvetica, arial, sans-serif;\n}\n\nhr {\n  background: #f0f0ee;\n  color: #f0f0ee;\n}\n\n#header {\n  background: #36393d;\n}\n\n#header h1 {\n  padding: 15px 0;\n  font-size: 28px;\n  font-style: normal;\n  font-weight: bold;\n  text-transform: normal;\n  letter-spacing: -1px;\n  line-height: 1.2em;\n}\n\n#header h1 a:link, #header h1 a:active, #header h1 a:hover, #header h1 a:visited {\n  color: #FFF;\n}\n\n#user-navigation {\n  top: auto;\n  bottom: 5px;\n  right: 25px;\n}\n\n#user-navigation a.logout {\n  background: #cc0000;\n  padding: 1px 4px;\n  -moz-border-radius: 4px;\n\t-webkit-border-radius: 3px;\n}\n\n#main .block .content {\n  background: #FFF;\n  padding-top: 1px;\n}\n\n#main .block .content h2 {\n  margin-left: 15px;\n  font-size: 22px;\n  font-style: normal;\n  font-weight: bold;\n  text-transform: normal;\n  letter-spacing: -1px;\n  line-height: 1.2em;\n}\n\n#main .block .content p {\n  font-size: 13px;\n  font-style: normal;\n  font-weight: normal;\n  text-transform: normal;\n  letter-spacing: normal;\n  line-height: 1.45em;\n}\n\n#sidebar .block {\n  background: #FFF;\n}\n\n#sidebar .block h4 {\n  font-weight: bold;\n}\n\n#sidebar .notice {\n  background: #E6EEFC;\n}\n\n#sidebar .notice h4 {\n  color: #0B43A8;\n}\n\n#sidebar h3 {\n  background: #36393d;\n  color: #FFF;\n  border-bottom: 5px solid #1a1a1a;\n}\n\n#main-navigation ul li {\n  padding-left: 15px;\n}\n\n#main-navigation ul li a {\n  padding: 8px 0;\n}\n\n#main-navigation ul li.active {\n  padding: 0;\n  margin-left: 15px;\n}\n\n#main-navigation ul li.active {\n  margin-left: 15px;\n}\n\n#main-navigation ul li.active a {\n  padding: 8px 15px;\n}\n\n#sidebar ul li a:link, #sidebar ul li a:visited {\n  background: #FFF;\n  border-bottom: 1px solid #F0F0EE;\n  text-decoration: none;\n}\n\n#sidebar ul li a:hover, #sidebar ul li a:active {\n  background: #666666;\n  color: #ffffff;;\n}\n\n#main-navigation {\n  background: #1a1a1a;\n}\n\n#main-navigation ul li {\n  background: #1a1a1a;\n  margin-right: 0;\n}\n\n#main-navigation ul li.active {\n  background: #f0f0ee;\n}\n\n#main-navigation ul li a:link, #main-navigation ul li a:visited, #main-navigation ul li a:hover, #main-navigation ul li a:active,\n.secondary-navigation ul li a:link, .secondary-navigation ul li a:visited, .secondary-navigation ul li a:hover, .secondary-navigation ul li a:active,\n#user-navigation ul li a:link, #user-navigation ul li a:visited, #user-navigation ul li a:hover, #user-navigation ul li a:active {\n  text-decoration: none;\n  color: #FFF;\n}\n\n.secondary-navigation li a:hover {\n  background: #666666;\n}\n\n#main-navigation ul li.active a:link, #main-navigation ul li.active a:visited, #main-navigation ul li.active a:hover, #main-navigation ul li.active a:active {\n  color: #1a1a1a;\n}\n\n.secondary-navigation {\n  background: #36393d;\n  border-bottom-color: #4F8AFF;\n}\n\n.secondary-navigation ul li.active, .secondary-navigation ul li.active a:hover {\n  background: #1a1a1a;\n  background: #4F8AFF;\n}\n\n#footer .block {\n  color: #FFF;\n  background: #1a1a1a;\n}\n\n#footer .block p {\n  margin: 0;\n  padding: 10px;\n}\n\n/* pagination */\n\n.pagination a, .pagination span {\n  background: #ededec;\n  -moz-border-radius: 3px;\n  border: 1px solid #c1c1c1;\n}\n\n.pagination span.current {\n  background: #36393d;\n  color: #FFF;\n  border: 1px solid #36393d;\n}\n\n.pagination a {\n  color: #1a1a1a;\n}\n\n.pagination a:hover {\n  border: 1px solid #666;\n}\n\n/* tables */\n\n.table th {\n  background: #36393d;  \n  color: #FFF;\n}\n\n.table td {\n  border-bottom:1px solid #F0F0EE;\n}\n\n.table tr.even {\n  background: #ebebeb;\n}\n\n/* forms */\n\n.form label.label {\n  color: #666666;\n}\n\n.form input.text_field, .form textarea.text_area {\n  width: 100%;\n  border: 1px solid #ededec;\n}\n\n.form input.button {\n  background: #ededec;\n  -moz-border-radius: 5px;\n  border: 1px solid #c1c1c1;\n  padding: 2px 5px;\n  cursor: pointer;\n  color: #36393d;\n  font-weight: bold;\n  font-size: 11px;\n}\n\n.form input.button:hover {\n  border: 1px solid #666;\n}\n\n.form .description {\n  font-style: italic;\n  color: #8C8C8C;\n  font-size: .9em;\n}\n\n.form .navform a {\n  color: #cc0000;\n}\n\n/* flash-messages */\n.flash .message {\n  -moz-border-radius: 3px;\n  -webkit-border-radius: 3px;\n  text-align:center;\n  margin: 0 auto 15px;\n\n}\n\n.flash .message p {\n  margin:8px;\n}\n.flash .error {\n  border: 1px solid #fbb;\n  background-color: #fdd;\n}\n.flash .warning {\n  border: 1px solid #fffaaa;\n  background-color: #ffffcc;\n}\n.flash .notice {\n  border: 1px solid #1FDF00;\n  background-color: #BBFFB6;\n}\n\n/* lists */\n\nul.list li {\n  border-bottom-color: #F0F0EE;\n  border-bottom-width: 1px;\n  border-bottom-style: solid;\n}\n\nul.list li .item .avatar {\n  border-color: #F0F0EE;\n  border-width: 1px;\n  border-style: solid;\n  padding: 2px;\n}\n\n/* box */\n\n#box .block {\n  background: #FFF;\n}\n\n#box .block h2 {\n  background: #36393d;\n  color: #FFF;\n}\n\n\n/* rounded borders */\n\n#main, #main-navigation, #main-navigation li, .secondary-navigation, #main .block, #sidebar .block, #sidebar h3, ul.list li,\n#footer .block, .form input.button, #box .block, #box .block h2 {\n  -moz-border-radius-topleft: 4px;\n  -webkit-border-top-left-radius: 4px;\n  -moz-border-radius-topright: 4px;\n  -webkit-border-top-right-radius: 4px;\n}\n\n.secondary-navigation li.first a, .secondary-navigation ul li.first, .table th.first, .table th.first {\n  -moz-border-radius-topleft: 4px;\n  -webkit-border-top-left-radius: 4px;\n}\n\n.table th.last {\n  -moz-border-radius-topright: 4px;\n  -webkit-border-top-right-radius: 4px;\n}\n\n.secondary-navigation ul li.first {\n  -moz-border-radius-topleft: 4px;\n  -webkit-border-top-left-radius: 4px;\n}\n\n#sidebar, #sidebar .block, #main .block, #sidebar ul.navigation, ul.list li, #footer .block, .form input.button, #box .block {\n  -moz-border-radius-bottomleft: 4px;\n  -webkit-border-bottom-left-radius: 4px;\n  -moz-border-radius-bottomright: 4px;\n  -webkit-border-bottom-right-radius: 4px;\n}\n\n.secondary-navigation {\n  border-bottom-width: 5px;\n}\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/css/umbrella.css",
    "content": ".umbrella {\n  font-family:lucida grande,verdana;\n  font-size:12px;\n  text-align:left;\n  }\n  .umbrella h1 {\n    color:#000000;\n    font-size: 26px;\n    font-weight: bold;\n    border-bottom: 1px dotted #CCCCCC;\n  }\n  #main .block .umbrella h2 {\n    color:#000000;\n    font-size:16px;\n    margin: 10px 0 2px 0;\n    padding:0;\n    font-family:\"Lucida Grande\",arial,sans-serif;\n    }\n    .umbrella h2 span {\n      color: #666;\n      font-size: 12px;\n      font-weight: normal;\n      }\n  .umbrella input {\n    font-size:14px;\n    margin-bottom:10px;\n    padding:3px;\n    }\n    .umbrella input.button {\n      font-size:14px;\n      margin:10px 0 0;\n      padding:3px;\n      width:auto;\n      }\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/css/vendor/jquery-ui-1.7.2.custom.css",
    "content": "/*\n* jQuery UI CSS Framework\n* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.\n*/\n\n/* Layout helpers\n----------------------------------*/\n.ui-helper-hidden { display: none; }\n.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }\n.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }\n.ui-helper-clearfix:after { content: \".\"; display: block; height: 0; clear: both; visibility: hidden; }\n.ui-helper-clearfix { display: inline-block; }\n/* required comment for clearfix to work in Opera \\*/\n* html .ui-helper-clearfix { height:1%; }\n.ui-helper-clearfix { display:block; }\n/* end clearfix */\n.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }\n\n\n/* Interaction Cues\n----------------------------------*/\n.ui-state-disabled { cursor: default !important; }\n\n\n/* Icons\n----------------------------------*/\n\n/* states and images */\n.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }\n\n\n/* Misc visuals\n----------------------------------*/\n\n/* Overlays */\n.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }\n\n\n\n/*\n* jQuery UI CSS Framework\n* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.\n* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Arial,sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=6px&bgColorHeader=cc0000&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=15&borderColorHeader=e3a1a1&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=eeeeee&fcContent=333333&iconColorContent=cc0000&bgColorDefault=eeeeee&bgTextureDefault=04_highlight_hard.png&bgImgOpacityDefault=100&borderColorDefault=d8dcdf&fcDefault=004276&iconColorDefault=cc0000&bgColorHover=f6f6f6&bgTextureHover=04_highlight_hard.png&bgImgOpacityHover=100&borderColorHover=cdd5da&fcHover=111111&iconColorHover=cc0000&bgColorActive=ffffff&bgTextureActive=01_flat.png&bgImgOpacityActive=65&borderColorActive=eeeeee&fcActive=cc0000&iconColorActive=cc0000&bgColorHighlight=fbf8ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcd3a1&fcHighlight=444444&iconColorHighlight=004276&bgColorError=f3d8d8&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=75&borderColorError=cc0000&fcError=2e2e2e&iconColorError=cc0000&bgColorOverlay=a6a6a6&bgTextureOverlay=09_dots_small.png&bgImgOpacityOverlay=65&opacityOverlay=40&bgColorShadow=333333&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=10&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px\n*/\n\n\n/* Component containers\n----------------------------------*/\n.ui-widget { font-family: Arial,sans-serif; font-size: 1.1em; }\n.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Arial,sans-serif; font-size: 1em; }\n.ui-widget-content { border: 1px solid #eeeeee; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #333333; }\n.ui-widget-content a { color: #333333; }\n.ui-widget-header { border: 1px solid #e3a1a1; background: #cc0000 url(images/ui-bg_highlight-soft_15_cc0000_1x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }\n.ui-widget-header a { color: #ffffff; }\n\n/* Interaction states\n----------------------------------*/\n.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #d8dcdf; background: #eeeeee url(images/ui-bg_highlight-hard_100_eeeeee_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #004276; outline: none; }\n.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #004276; text-decoration: none; outline: none; }\n.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #cdd5da; background: #f6f6f6 url(images/ui-bg_highlight-hard_100_f6f6f6_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #111111; outline: none; }\n.ui-state-hover a, .ui-state-hover a:hover { color: #111111; text-decoration: none; outline: none; }\n.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #eeeeee; background: #ffffff url(images/ui-bg_flat_65_ffffff_40x100.png) 50% 50% repeat-x; font-weight: bold; color: #cc0000; outline: none; }\n.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #cc0000; outline: none; text-decoration: none; }\n\n/* Interaction Cues\n----------------------------------*/\n.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fcd3a1; background: #fbf8ee url(images/ui-bg_glass_55_fbf8ee_1x400.png) 50% 50% repeat-x; color: #444444; }\n.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #444444; }\n.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cc0000; background: #f3d8d8 url(images/ui-bg_diagonals-thick_75_f3d8d8_40x40.png) 50% 50% repeat; color: #2e2e2e; }\n.ui-state-error a, .ui-widget-content .ui-state-error a { color: #2e2e2e; }\n.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #2e2e2e; }\n.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }\n.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }\n.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }\n\n/* Icons\n----------------------------------*/\n\n/* states and images */\n.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_cc0000_256x240.png); }\n.ui-widget-content .ui-icon {background-image: url(images/ui-icons_cc0000_256x240.png); }\n.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }\n.ui-state-default .ui-icon { background-image: url(images/ui-icons_cc0000_256x240.png); }\n.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_cc0000_256x240.png); }\n.ui-state-active .ui-icon {background-image: url(images/ui-icons_cc0000_256x240.png); }\n.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_004276_256x240.png); }\n.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cc0000_256x240.png); }\n\n/* positioning */\n.ui-icon-carat-1-n { background-position: 0 0; }\n.ui-icon-carat-1-ne { background-position: -16px 0; }\n.ui-icon-carat-1-e { background-position: -32px 0; }\n.ui-icon-carat-1-se { background-position: -48px 0; }\n.ui-icon-carat-1-s { background-position: -64px 0; }\n.ui-icon-carat-1-sw { background-position: -80px 0; }\n.ui-icon-carat-1-w { background-position: -96px 0; }\n.ui-icon-carat-1-nw { background-position: -112px 0; }\n.ui-icon-carat-2-n-s { background-position: -128px 0; }\n.ui-icon-carat-2-e-w { background-position: -144px 0; }\n.ui-icon-triangle-1-n { background-position: 0 -16px; }\n.ui-icon-triangle-1-ne { background-position: -16px -16px; }\n.ui-icon-triangle-1-e { background-position: -32px -16px; }\n.ui-icon-triangle-1-se { background-position: -48px -16px; }\n.ui-icon-triangle-1-s { background-position: -64px -16px; }\n.ui-icon-triangle-1-sw { background-position: -80px -16px; }\n.ui-icon-triangle-1-w { background-position: -96px -16px; }\n.ui-icon-triangle-1-nw { background-position: -112px -16px; }\n.ui-icon-triangle-2-n-s { background-position: -128px -16px; }\n.ui-icon-triangle-2-e-w { background-position: -144px -16px; }\n.ui-icon-arrow-1-n { background-position: 0 -32px; }\n.ui-icon-arrow-1-ne { background-position: -16px -32px; }\n.ui-icon-arrow-1-e { background-position: -32px -32px; }\n.ui-icon-arrow-1-se { background-position: -48px -32px; }\n.ui-icon-arrow-1-s { background-position: -64px -32px; }\n.ui-icon-arrow-1-sw { background-position: -80px -32px; }\n.ui-icon-arrow-1-w { background-position: -96px -32px; }\n.ui-icon-arrow-1-nw { background-position: -112px -32px; }\n.ui-icon-arrow-2-n-s { background-position: -128px -32px; }\n.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }\n.ui-icon-arrow-2-e-w { background-position: -160px -32px; }\n.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }\n.ui-icon-arrowstop-1-n { background-position: -192px -32px; }\n.ui-icon-arrowstop-1-e { background-position: -208px -32px; }\n.ui-icon-arrowstop-1-s { background-position: -224px -32px; }\n.ui-icon-arrowstop-1-w { background-position: -240px -32px; }\n.ui-icon-arrowthick-1-n { background-position: 0 -48px; }\n.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }\n.ui-icon-arrowthick-1-e { background-position: -32px -48px; }\n.ui-icon-arrowthick-1-se { background-position: -48px -48px; }\n.ui-icon-arrowthick-1-s { background-position: -64px -48px; }\n.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }\n.ui-icon-arrowthick-1-w { background-position: -96px -48px; }\n.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }\n.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }\n.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }\n.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }\n.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }\n.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }\n.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }\n.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }\n.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }\n.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }\n.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }\n.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }\n.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }\n.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }\n.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }\n.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }\n.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }\n.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }\n.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }\n.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }\n.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }\n.ui-icon-arrow-4 { background-position: 0 -80px; }\n.ui-icon-arrow-4-diag { background-position: -16px -80px; }\n.ui-icon-extlink { background-position: -32px -80px; }\n.ui-icon-newwin { background-position: -48px -80px; }\n.ui-icon-refresh { background-position: -64px -80px; }\n.ui-icon-shuffle { background-position: -80px -80px; }\n.ui-icon-transfer-e-w { background-position: -96px -80px; }\n.ui-icon-transferthick-e-w { background-position: -112px -80px; }\n.ui-icon-folder-collapsed { background-position: 0 -96px; }\n.ui-icon-folder-open { background-position: -16px -96px; }\n.ui-icon-document { background-position: -32px -96px; }\n.ui-icon-document-b { background-position: -48px -96px; }\n.ui-icon-note { background-position: -64px -96px; }\n.ui-icon-mail-closed { background-position: -80px -96px; }\n.ui-icon-mail-open { background-position: -96px -96px; }\n.ui-icon-suitcase { background-position: -112px -96px; }\n.ui-icon-comment { background-position: -128px -96px; }\n.ui-icon-person { background-position: -144px -96px; }\n.ui-icon-print { background-position: -160px -96px; }\n.ui-icon-trash { background-position: -176px -96px; }\n.ui-icon-locked { background-position: -192px -96px; }\n.ui-icon-unlocked { background-position: -208px -96px; }\n.ui-icon-bookmark { background-position: -224px -96px; }\n.ui-icon-tag { background-position: -240px -96px; }\n.ui-icon-home { background-position: 0 -112px; }\n.ui-icon-flag { background-position: -16px -112px; }\n.ui-icon-calendar { background-position: -32px -112px; }\n.ui-icon-cart { background-position: -48px -112px; }\n.ui-icon-pencil { background-position: -64px -112px; }\n.ui-icon-clock { background-position: -80px -112px; }\n.ui-icon-disk { background-position: -96px -112px; }\n.ui-icon-calculator { background-position: -112px -112px; }\n.ui-icon-zoomin { background-position: -128px -112px; }\n.ui-icon-zoomout { background-position: -144px -112px; }\n.ui-icon-search { background-position: -160px -112px; }\n.ui-icon-wrench { background-position: -176px -112px; }\n.ui-icon-gear { background-position: -192px -112px; }\n.ui-icon-heart { background-position: -208px -112px; }\n.ui-icon-star { background-position: -224px -112px; }\n.ui-icon-link { background-position: -240px -112px; }\n.ui-icon-cancel { background-position: 0 -128px; }\n.ui-icon-plus { background-position: -16px -128px; }\n.ui-icon-plusthick { background-position: -32px -128px; }\n.ui-icon-minus { background-position: -48px -128px; }\n.ui-icon-minusthick { background-position: -64px -128px; }\n.ui-icon-close { background-position: -80px -128px; }\n.ui-icon-closethick { background-position: -96px -128px; }\n.ui-icon-key { background-position: -112px -128px; }\n.ui-icon-lightbulb { background-position: -128px -128px; }\n.ui-icon-scissors { background-position: -144px -128px; }\n.ui-icon-clipboard { background-position: -160px -128px; }\n.ui-icon-copy { background-position: -176px -128px; }\n.ui-icon-contact { background-position: -192px -128px; }\n.ui-icon-image { background-position: -208px -128px; }\n.ui-icon-video { background-position: -224px -128px; }\n.ui-icon-script { background-position: -240px -128px; }\n.ui-icon-alert { background-position: 0 -144px; }\n.ui-icon-info { background-position: -16px -144px; }\n.ui-icon-notice { background-position: -32px -144px; }\n.ui-icon-help { background-position: -48px -144px; }\n.ui-icon-check { background-position: -64px -144px; }\n.ui-icon-bullet { background-position: -80px -144px; }\n.ui-icon-radio-off { background-position: -96px -144px; }\n.ui-icon-radio-on { background-position: -112px -144px; }\n.ui-icon-pin-w { background-position: -128px -144px; }\n.ui-icon-pin-s { background-position: -144px -144px; }\n.ui-icon-play { background-position: 0 -160px; }\n.ui-icon-pause { background-position: -16px -160px; }\n.ui-icon-seek-next { background-position: -32px -160px; }\n.ui-icon-seek-prev { background-position: -48px -160px; }\n.ui-icon-seek-end { background-position: -64px -160px; }\n.ui-icon-seek-first { background-position: -80px -160px; }\n.ui-icon-stop { background-position: -96px -160px; }\n.ui-icon-eject { background-position: -112px -160px; }\n.ui-icon-volume-off { background-position: -128px -160px; }\n.ui-icon-volume-on { background-position: -144px -160px; }\n.ui-icon-power { background-position: 0 -176px; }\n.ui-icon-signal-diag { background-position: -16px -176px; }\n.ui-icon-signal { background-position: -32px -176px; }\n.ui-icon-battery-0 { background-position: -48px -176px; }\n.ui-icon-battery-1 { background-position: -64px -176px; }\n.ui-icon-battery-2 { background-position: -80px -176px; }\n.ui-icon-battery-3 { background-position: -96px -176px; }\n.ui-icon-circle-plus { background-position: 0 -192px; }\n.ui-icon-circle-minus { background-position: -16px -192px; }\n.ui-icon-circle-close { background-position: -32px -192px; }\n.ui-icon-circle-triangle-e { background-position: -48px -192px; }\n.ui-icon-circle-triangle-s { background-position: -64px -192px; }\n.ui-icon-circle-triangle-w { background-position: -80px -192px; }\n.ui-icon-circle-triangle-n { background-position: -96px -192px; }\n.ui-icon-circle-arrow-e { background-position: -112px -192px; }\n.ui-icon-circle-arrow-s { background-position: -128px -192px; }\n.ui-icon-circle-arrow-w { background-position: -144px -192px; }\n.ui-icon-circle-arrow-n { background-position: -160px -192px; }\n.ui-icon-circle-zoomin { background-position: -176px -192px; }\n.ui-icon-circle-zoomout { background-position: -192px -192px; }\n.ui-icon-circle-check { background-position: -208px -192px; }\n.ui-icon-circlesmall-plus { background-position: 0 -208px; }\n.ui-icon-circlesmall-minus { background-position: -16px -208px; }\n.ui-icon-circlesmall-close { background-position: -32px -208px; }\n.ui-icon-squaresmall-plus { background-position: -48px -208px; }\n.ui-icon-squaresmall-minus { background-position: -64px -208px; }\n.ui-icon-squaresmall-close { background-position: -80px -208px; }\n.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }\n.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }\n.ui-icon-grip-solid-vertical { background-position: -32px -224px; }\n.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }\n.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }\n.ui-icon-grip-diagonal-se { background-position: -80px -224px; }\n\n\n/* Misc visuals\n----------------------------------*/\n\n/* Corner radius */\n.ui-corner-tl { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; }\n.ui-corner-tr { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; }\n.ui-corner-bl { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; }\n.ui-corner-br { -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; }\n.ui-corner-top { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; }\n.ui-corner-bottom { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; }\n.ui-corner-right {  -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; }\n.ui-corner-left { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; }\n.ui-corner-all { -moz-border-radius: 6px; -webkit-border-radius: 6px; }\n\n/* Overlays */\n.ui-widget-overlay { background: #a6a6a6 url(images/ui-bg_dots-small_65_a6a6a6_2x2.png) 50% 50% repeat; opacity: .40;filter:Alpha(Opacity=40); }\n.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #333333 url(images/ui-bg_flat_0_333333_40x100.png) 50% 50% repeat-x; opacity: .10;filter:Alpha(Opacity=10); -moz-border-radius: 8px; -webkit-border-radius: 8px; }/* Accordion\n----------------------------------*/\n.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }\n.ui-accordion .ui-accordion-li-fix { display: inline; }\n.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }\n.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; }\n.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }\n.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; }\n.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker\n----------------------------------*/\n.ui-datepicker { width: 17em; padding: .2em .2em 0; }\n.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }\n.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }\n.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }\n.ui-datepicker .ui-datepicker-prev { left:2px; }\n.ui-datepicker .ui-datepicker-next { right:2px; }\n.ui-datepicker .ui-datepicker-prev-hover { left:1px; }\n.ui-datepicker .ui-datepicker-next-hover { right:1px; }\n.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }\n.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }\n.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }\n.ui-datepicker select.ui-datepicker-month-year {width: 100%;}\n.ui-datepicker select.ui-datepicker-month, \n.ui-datepicker select.ui-datepicker-year { width: 49%;}\n.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }\n.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }\n.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }\n.ui-datepicker td { border: 0; padding: 1px; }\n.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }\n.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }\n.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }\n.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }\n\n/* with multiple calendars */\n.ui-datepicker.ui-datepicker-multi { width:auto; }\n.ui-datepicker-multi .ui-datepicker-group { float:left; }\n.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }\n.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }\n.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }\n.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }\n.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }\n.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }\n.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }\n.ui-datepicker-row-break { clear:both; width:100%; }\n\n/* RTL support */\n.ui-datepicker-rtl { direction: rtl; }\n.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }\n.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }\n.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }\n.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }\n.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }\n.ui-datepicker-rtl .ui-datepicker-group { float:right; }\n.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }\n.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }\n\n/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */\n.ui-datepicker-cover {\n    display: none; /*sorry for IE5*/\n    display/**/: block; /*sorry for IE5*/\n    position: absolute; /*must have*/\n    z-index: -1; /*must have*/\n    filter: mask(); /*must have*/\n    top: -4px; /*must have*/\n    left: -4px; /*must have*/\n    width: 200px; /*must have*/\n    height: 200px; /*must have*/\n}/* Dialog\n----------------------------------*/\n.ui-dialog { position: relative; padding: .2em; width: 300px; }\n.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative;  }\n.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; } \n.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }\n.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }\n.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }\n.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }\n.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }\n.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }\n.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }\n.ui-draggable .ui-dialog-titlebar { cursor: move; }\n/* Progressbar\n----------------------------------*/\n.ui-progressbar { height:2em; text-align: left; }\n.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable\n----------------------------------*/\n.ui-resizable { position: relative;}\n.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}\n.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }\n.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; }\n.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; }\n.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; }\n.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; }\n.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }\n.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }\n.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }\n.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider\n----------------------------------*/\n.ui-slider { position: relative; text-align: left; }\n.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }\n.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }\n\n.ui-slider-horizontal { height: .8em; }\n.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }\n.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }\n.ui-slider-horizontal .ui-slider-range-min { left: 0; }\n.ui-slider-horizontal .ui-slider-range-max { right: 0; }\n\n.ui-slider-vertical { width: .8em; height: 100px; }\n.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }\n.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }\n.ui-slider-vertical .ui-slider-range-min { bottom: 0; }\n.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs\n----------------------------------*/\n.ui-tabs { padding: .2em; zoom: 1; }\n.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; }\n.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; }\n.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; }\n.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; }\n.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }\n.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */\n.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; }\n.ui-tabs .ui-tabs-hide { display: none !important; }\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/css/vendor/qunit.css",
    "content": "\nol#qunit-tests {\n\tfont-family:\"Helvetica Neue Light\", \"HelveticaNeue-Light\", \"Helvetica Neue\", Calibri, Helvetica, Arial;\n\tmargin:0;\n\tpadding:0;\n\tlist-style-position:inside;\n\n\tfont-size: smaller;\n}\nol#qunit-tests li{\n\tpadding:0.4em 0.5em 0.4em 2.5em;\n\tborder-bottom:1px solid #fff;\n\tfont-size:small;\n\tlist-style-position:inside;\n}\nol#qunit-tests li ol{\n\tbox-shadow: inset 0px 2px 13px #999;\n\t-moz-box-shadow: inset 0px 2px 13px #999;\n\t-webkit-box-shadow: inset 0px 2px 13px #999;\n\tmargin-top:0.5em;\n\tmargin-left:0;\n\tpadding:0.5em;\n\tbackground-color:#fff;\n\tborder-radius:15px;\n\t-moz-border-radius: 15px;\n\t-webkit-border-radius: 15px;\n}\nol#qunit-tests li li{\n\tborder-bottom:none;\n\tmargin:0.5em;\n\tbackground-color:#fff;\n\tlist-style-position: inside;\n\tpadding:0.4em 0.5em 0.4em 0.5em;\n}\n\nol#qunit-tests li li.pass{\n\tborder-left:26px solid #C6E746;\n\tbackground-color:#fff;\n\tcolor:#5E740B;\n\t}\nol#qunit-tests li li.fail{\n\tborder-left:26px solid #EE5757;\n\tbackground-color:#fff;\n\tcolor:#710909;\n}\nol#qunit-tests li.pass{\n\tbackground-color:#D2E0E6;\n\tcolor:#528CE0;\n}\nol#qunit-tests li.fail{\n\tbackground-color:#EE5757;\n\tcolor:#000;\n}\nol#qunit-tests li strong {\n\tcursor:pointer;\n}\nh1#qunit-header{\n\tbackground-color:#0d3349;\n\tmargin:0;\n\tpadding:0.5em 0 0.5em 1em;\n\tcolor:#fff;\n\tfont-family:\"Helvetica Neue Light\", \"HelveticaNeue-Light\", \"Helvetica Neue\", Calibri, Helvetica, Arial;\n\tborder-top-right-radius:15px;\n\tborder-top-left-radius:15px;\n\t-moz-border-radius-topright:15px;\n\t-moz-border-radius-topleft:15px;\n\t-webkit-border-top-right-radius:15px;\n\t-webkit-border-top-left-radius:15px;\n\ttext-shadow: rgba(0, 0, 0, 0.5) 4px 4px 1px;\n}\nh2#qunit-banner{\n\tfont-family:\"Helvetica Neue Light\", \"HelveticaNeue-Light\", \"Helvetica Neue\", Calibri, Helvetica, Arial;\n\theight:5px;\n\tmargin:0;\n\tpadding:0;\n}\nh2#qunit-banner.qunit-pass{\n\tbackground-color:#C6E746;\n}\nh2#qunit-banner.qunit-fail, #qunit-testrunner-toolbar {\n\tbackground-color:#EE5757;\n}\n#qunit-testrunner-toolbar {\n\tfont-family:\"Helvetica Neue Light\", \"HelveticaNeue-Light\", \"Helvetica Neue\", Calibri, Helvetica, Arial;\n\tpadding:0;\n\t/*width:80%;*/\n\tpadding:0em 0 0.5em 2em;\n\tfont-size: small;\n}\nh2#qunit-userAgent {\n\tfont-family:\"Helvetica Neue Light\", \"HelveticaNeue-Light\", \"Helvetica Neue\", Calibri, Helvetica, Arial;\n\tbackground-color:#2b81af;\n\tmargin:0;\n\tpadding:0;\n\tcolor:#fff;\n\tfont-size: small;\n\tpadding:0.5em 0 0.5em 2.5em;\n\ttext-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;\n}\np#qunit-testresult{\n\tfont-family:\"Helvetica Neue Light\", \"HelveticaNeue-Light\", \"Helvetica Neue\", Calibri, Helvetica, Arial;\n\tmargin:0;\n\tfont-size: small;\n\tcolor:#2b81af;\n\tborder-bottom-right-radius:15px;\n\tborder-bottom-left-radius:15px;\n\t-moz-border-radius-bottomright:15px;\n\t-moz-border-radius-bottomleft:15px;\n\t-webkit-border-bottom-right-radius:15px;\n\t-webkit-border-bottom-left-radius:15px;\n\tbackground-color:#D2E0E6;\n\tpadding:0.5em 0.5em 0.5em 2.5em;\n}\nstrong b.fail{\n\tcolor:#710909;\n\t}\nstrong b.pass{\n\tcolor:#5E740B;\n\t}\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/advance_search/act_on_result.js",
    "content": "var AdminData = AdminData || {};\n\nAdminData.actOnResult = {\n\n\taction: function(action_type) {\n\t\tvar formData = $('#advance_search_form').data('admin_data_form_array'),\n\t\tparameterizedData;\n\n\t\tformData.push({\n\t\t\t'name': 'admin_data_advance_search_action_type',\n\t\t\t'value': action_type\n\t\t});\n\n\t\tparameterizedData = $.param(formData);\n\n\t\t$.ajax({\n\t\t\turl: $('#advance_search_form').attr('action'),\n\t\t\ttype: 'post',\n\t\t\tdataType: 'json',\n\t\t\tdata: parameterizedData,\n\t\t\tsuccess: function(json) {\n\t\t\t\tAdminData.actOnResult.successCallback(json);\n\t\t\t}\n\t\t});\n\t},\n\n\tsuccessCallback: function(json) {\n\t\t$('#results').text(json.success);\n\t}\n\n};\n\n$('#advance_search_delete_all').live('click', function() {\n\tif (confirm('Are you sure?')) {\n\t\tAdminData.actOnResult.action('delete');\n\t}\n\treturn false;\n});\n\n$('#advance_search_destroy_all').live('click', function() {\n\tif (confirm('Are you sure?')) {\n\t\tAdminData.actOnResult.action('destroy');\n\t}\n\treturn false;\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/advance_search/adv_search.js",
    "content": "var AdminData = AdminData || {};\n\nAdminData.advanceSearch = {\n\n  buildFirstRow: function(){\n    $('#advance_search_table').\n      append(this.buildRow()).find('tr td:last a').text('+').removeClass('remove_row').addClass('add_row_link');\n  },\n\n  buildCol1: function() {\n    var col = $('<select />', {className: 'col1' }).append($('<option />')); \n    var tableStructure = $('#advance_search_table').data('table_structure');\n    for (var i in tableStructure) {\n      $('<option />').text(i).attr('value', i).appendTo(col);\n    }\n    return $('<td />').append(col);\n  },\n\n  buildCol2: function() {\n    return $('<td />').\n              append('<select />').\n                find('select').\n                append('<option />').\n                addClass('col2 disabled').\n                attr({ disabled: true }).\n              end();\n  },\n\n  buildCol3: function() {\n    return $('<td />').append($('<input />',{disabled: true, className: 'col3'}));\n  },\n\n  buildCol4: function() {\n    return $('<td />').append($('<a />', {text: 'x', href: '#', className: 'remove_row'}));\n  },\n\n  buildRow: function() {\n    var $tr = $('<tr />').append(this.buildCol1(), this.buildCol2(), this.buildCol3(), this.buildCol4());\n    var randomNumber = AdminData.jsUtil.randomNumber();\n    $tr.find('select.col1').attr({ name: 'adv_search[' + randomNumber + '_row][col1]'});\n    $tr.find('select.col2').attr({ name: 'adv_search[' + randomNumber + '_row][col2]'});\n    $tr.find('input.col3').attr({ name: 'adv_search[' + randomNumber + '_row][col3]'});\n    return $tr;\n  }\n\n};\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/advance_search/advance_search.js",
    "content": "var AdminData = AdminData || {};\n\nAdminData.advanceSearch = {\n\n  buildFirstRow: function(){\n    $('#advance_search_table')\n      .append(this.buildRow())\n      .find('tr td:last a')\n        .text('+')\n        .removeClass('remove_row')\n        .addClass('add_row_link');\n  },\n\n  buildCol1: function() {\n    var i, \n        col = $('<select />', {className: 'col1' }).append($('<option />')),\n        tableStructure = $('#advance_search_table').data('table_structure');\n\n    for (i in tableStructure) {\n      $('<option />', {text: i, value: i}).appendTo(col);\n    }\n    return $('<td />').append(col);\n  },\n\n  buildCol2: function() {\n    return $('<td />')\n              .append('<select />')\n              .find('select')\n                .append('<option />')\n                .addClass('col2 disabled')\n                .attr({ disabled: true }).\n              end();\n  },\n\n  buildCol3: function() {\n    return $('<td />').append($('<input />',{disabled: true, className: 'col3'}));\n  },\n\n  buildCol4: function() {\n    return $('<td />').append($('<a />', {text: 'x', href: '#', className: 'remove_row'}));\n  },\n\n  buildRow: function() {\n    var $tr = $('<tr />'),\n        that = this,\n        randomNumber = AdminData.jsUtil.randomNumber(),\n        build_array = ['buildCol1', 'buildCol2', 'buildCol3', 'buildCol4'];\n    \n    $.each(build_array, function(index, value) {\n      $tr.append(that[value]());\n    });\n\n    $tr.find('select.col1').attr({ name: 'adv_search[' + randomNumber + '_row][col1]'});\n    $tr.find('select.col2').attr({ name: 'adv_search[' + randomNumber + '_row][col2]'});\n    $tr.find('input.col3').attr({ name: 'adv_search[' + randomNumber + '_row][col3]'});\n\n    return $tr;\n  }\n\n};\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/advance_search/advance_search_structure.js",
    "content": "AdminData = AdminData || {};\n\nAdminData.mappings =  {\n\n      //JSLint complains if a hash has key named boolean. So I am changing the key to booleant  \n      booleant: {\n        options: [  \n          [\"is null\",     \"is_null\"], \n          [\"is not null\", \"is_not_null\"], \n          [\"is true\",     \"is_true\"], \n          [\"is false\",    \"is_false\"]\n        ]\n      },\n\n      string: {\n        options: [  \n          [\"is null\",         \"is_null\"], \n          [\"is not null\",     \"is_not_null\"], \n          [\"contains\",        \"contains\"], \n          [\"is exactly\",      \"is_exactly\"], \n          [\"doesn't contain\", \"does_not_contain\"]\n        ]\n      },\n\n      text: {\n        options: [  \n          [\"is null\",         \"is_null\"], \n          [\"is not null\",     \"is_not_null\"], \n          [\"Contains\",        \"contains\"], \n          [\"Doesn't Contain\", \"does_not_contain\"]\n        ]\n      },\n\n      datetime: {\n        options: [  \n          [\"is null\",       \"is_null\"], \n          [\"is not null\",   \"is_not_null\"],\n          ['on',            \"is_on\"], \n          ['on or before',  \"is_on_or_before_date\"], \n          ['on or after',   \"is_on_or_after_date\"]\n        ]\n      },\n\n      date: {\n        options: [  \n          [\"is null\",       \"is_null\"], \n          [\"is not null\",   \"is_not_null\"],\n          ['on',            \"is_on\"], \n          ['on or before',  \"is_on_or_before_date\"], \n          ['on or after',   \"is_on_or_after_date\"]\n        ]\n      },\n\n      time: {\n        options: [  \n          [\"is null\",       \"is_null\"], \n          [\"is not null\",   \"is_not_null\"],\n          [\"is exactly\",    \"is_exactly\"]\n        ]\n      },\n\n      decimal: {\n        options: [  \n          ['is equal to',     \"is_equal_to\"], \n          ['is less than',    \"less_than\"], \n          ['is greater than', \"greater_than\"]\n        ]\n      },\n\n      integer: {\n        options: [  \n          ['is equal to',     \"is_equal_to\"], \n          ['is less than',    \"less_than\"], \n          ['is greater than', \"greater_than\"]\n        ]\n      }\n};\n\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/advance_search/ajaxify_advance_search.js",
    "content": "var AdminData = AdminData || {};\n\nAdminData.ajaxifyAdvanceSearch = {\n\tsuccessCallback: function(responseText) {\n\t\t$('#results').html(responseText);\n\t},\n\n\tbeforeSubmitCallback: function(formArray, jqForm) {\n\t\t$('#results').html('<span class=\"searching_message\">searching...</span>');\n\t\t$('#advance_search_form').data('admin_data_form_array', formArray);\n\t}\n};\n\n$(function() {\n\n\tvar options = {\n\t\tsuccess: function(responseText) {\n\t\t\tAdminData.ajaxifyAdvanceSearch.successCallback(responseText);\n\t\t},\n\t\tbeforeSubmit: function(formArray, jqForm) {\n\t\t\tAdminData.ajaxifyAdvanceSearch.beforeSubmitCallback(formArray, jqForm);\n\t\t}\n\t};\n\n\t$('#advance_search_form').ajaxForm(options);\n\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/advance_search/build_first_row.js",
    "content": "$(function() {\n\n\t//TODO use $.parseJSON also use live method of jQuery 1.4.1\n\tvar table_structure_data_non_json = $('#admin_data_table_structure_data').html(),\n\ttable_structure_data_json = eval(table_structure_data_non_json);\n\n\t$('#advance_search_table').data('table_structure', table_structure_data_json[0]);\n\n\tAdminData.advanceSearch.buildFirstRow();\n\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/advance_search/event_bindings.js",
    "content": "var AdminData = AdminData || {};\n\nAdminData.bindings = {\n\tcol2_change: function(e) {\n\t\tvar arrayList = ['is_false', 'is_true', 'is_null', 'is_not_null'],\n\t\t$col2 = $(e.target).closest('select'),\n\t\tvalue = $col2.val(),\n\t\ttableStructure = $('#advance_search_table').data('table_structure'),\n\t\tcolumnType = tableStructure[$col2.val()],\n\t\tcol1ColumnType;\n\n\t\t$col3 = $col2.parents('tr').find('td input.col3');\n\t\t$col1 = $col2.parents('tr').find('td select.col1');\n\t\tcol1ColumnType = tableStructure[$col1.val()];\n\n\t\tif (value.length === 0 || ($.inArray(value, arrayList) > - 1)) {\n\t\t\t $col3.val('')\n            .attr('disabled', true)\n            .addClass('disabled');\n\n\t\t} else {\n\t\t\t$col3.attr('disabled', false)\n           .removeClass('disabled');\n\n\t\t\tif (col1ColumnType === 'datetime' || col1ColumnType === 'date') {\n\t\t\t\t$col3.val(AdminData.jsUtil.dateToString(new Date())).addClass('datepicker');\n\t\t\t\t\n        $('.datepicker').datepicker({\n\t\t\t\t\tdateFormat: 'dd-MM-yy',\n\t\t\t\t\tchangeYear: true,\n\t\t\t\t\tchangeMonth: true\n\t\t\t\t});\n\n\t\t\t} else {\n\t\t\t\t$('.datepicker').datepicker('destroy');\n\t\t\t\t$col3.removeClass('datepicker').focus(); // do not create focus for date pickers\n\t\t\t}\n\t\t}\n\t},\n\n\tpagination_click: function(e) {\n\t\tvar href = $(e.target).closest('a').attr('href');\n\n\t\t// usage of #results twice seems redundant\n\t\t$('#results').load(href, function(responseText) {\n\t\t\t$('#results').html(responseText);\n\t\t});\n\n\t\tAdminData.jsUtil.colorizeRows();\n\t},\n\n\tcol1_change: function(e) {\n\t\tvar $col1 = $(e.target).closest('select'),\n\t\ttableStructure = $('#advance_search_table').data('table_structure'),\n\t\tcolumnType = tableStructure[$col1.val()],\n\t\toptions = AdminData.mappings[columnType]['options'];\n\n\t\t$col2 = $col1.parents('tr').find('td select.col2');\n\t\t$col2.html('');\n\t\tAdminData.jsUtil.buildOptionsFromArray(options, $col2);\n\t\t$col2.trigger('change');\n\t}\n};\n\n$('.pagination a').live('click', function(e) {\n\tAdminData.bindings.pagination_click(e);\n\treturn false;\n});\n\n$('#advance_search_table a.add_row_link').live('click', function() {\n\t$('#advance_search_table').append(AdminData.advanceSearch.buildRow());\n\treturn false;\n});\n\n$('#advance_search_table a.remove_row').live('click', function(e) {\n\t$(e.target).closest('tr').remove();\n\treturn false;\n});\n\n$('#advance_search_table select.col1').live('change', function(e) {\n\tAdminData.bindings.col1_change(e);\n});\n\n$('#advance_search_table select.col2').live('change', function(e) {\n\tAdminData.bindings.col2_change(e);\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/advance_search/global_ajax_setting.js",
    "content": "$(function() {\n\n\t$.ajaxSetup({\n\t\t'beforeSend': function(xhr) {\n\t\t\txhr.setRequestHeader(\"Accept\", \"text/javascript\");\n\t\t}\n\t});\n\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/advance_search/trigger_submit_on_domready.js",
    "content": "$(function() {\n\n\t$('#advance_search_form').trigger('submit');\n\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/misc/drop_down_change.js",
    "content": "$(function() {\n\n\t$('.drop_down_value_klass').change(function() {\n\t\twindow.location = $(this).val();\n\t});\n\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/misc/js_util.js",
    "content": "var AdminData = AdminData || {};\n\nAdminData.jsUtil = {\n\n\tconfirm: function(arg) {\n\t\twindow.confirm(arg);\n\t},\n\n\tbuildOptionsFromArray: function(array, element) {\n\t\telement.append($('<option />'));\n\t\tfor (i in array) {\n\t\t\t$('<option />').text(array[i][0]).attr('value', array[i][1]).appendTo(element);\n\t\t}\n\t\telement.attr('disabled', false);\n\t},\n\n\tcolorizeRows: function() {\n\t\t$('.colorize tr:odd').addClass('odd');\n\t\t$('.colorize tr:even').addClass('even');\n\t},\n\n\t// returns date in string format. example: 07-September-2009  \n\tdateToString: function(date) {\n\t\tvar month = (date.getMonth() + 1).toString();\n\t\tvar day = date.getDate().toString();\n\t\t//days between 1 and 9 should have 0 before them\n\t\tif (day.length == 1) day = '0' + day;\n\t\tvar months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];\n\t\treturn day + \"-\" + months[month - 1] + \"-\" + date.getFullYear();\n\t},\n\n\trandomNumber: function() {\n\t\tvar maxVal = 100000000,\n\t\tminVal = 1;\n\t\tvar randVal = minVal + (Math.random() * (maxVal - minVal));\n\t\treturn Math.round(randVal);\n\t}\n\n};\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/misc/quick_search_input_focus.js",
    "content": "$(function() {\n\n\t$('#quick_search_input').focus();\n\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/test/act_on_result.js",
    "content": "module('act_on_result', {\n\tteardown: function() {\n\t\t$('#advance_search_delete_all').remove();\n\t\t$('#advance_search_destroy_all').remove();\n\t\t$('#results').remove();\n\t\t$('#advance_search_form').remove();\n\t},\n\tsetup: function() {\n\t\t$(document.body).append($('<a />', {\n\t\t\thref: '#',\n\t\t\tid: 'advance_search_delete_all'\n\t\t}));\n\n\t\t$(document.body).append($('<a />', {\n\t\t\thref: '#',\n\t\t\tid: 'advance_search_destroy_all'\n\t\t}));\n\n\t\t$(document.body).append($('<div />', {\n\t\t\tid: 'results'\n\t\t}));\n\n\t\t$(document.body).append($('<div />', {\n\t\t\tid: 'advance_search_form'\n\t\t}));\n\t}\n});\n\ntest('invoking success callback', function() {\n\texpect(1);\n\tAdminData.actOnResult.successCallback({\n\t\tsuccess: 'hello world'\n\t});\n\tequals('hello world', $('#results').text(), '#results should have text hello world');\n});\n\ntest('live clicking #advance_search_delete_all with cancel action', function() {\n\texpect(0);\n\tjack(function() {\n\t\tjack.expect('AdminData.jsUtil.confirm').once().mock(function() {\n\t\t\treturn false;\n\t\t});\n\t\t//TODO ensure that the value passed to action is delete\n\t\tjack.expect('AdminData.actOnResult.action').exactly('0 time');\n\t\t$('#advance_search_delete_all').trigger('click');\n\t});\n});\n\ntest('live clicking #advance_search_delete_all', function() {\n\texpect(0);\n\tvar args;\n\n\tjack(function() {\n\t\tjack.expect('AdminData.jsUtil.confirm').once().mock(function() {\n\t\t\treturn true;\n\t\t});\n\t\tjack.expect('AdminData.actOnResult.action').once().mock(function(action_type) {\n\t\t\targs = action_type;\n\t\t\treturn {};\n\t\t});\n\t\t$('#advance_search_delete_all').trigger('click');\n\t});\n  equals('delete', args, 'action_type should be delete');\n\n});\n\ntest('live clicking #advance_search_destroy_all with cancel action', function() {\n\texpect(0);\n\tjack(function() {\n\t\tjack.expect('AdminData.jsUtil.confirm').once().mock(function() {\n\t\t\treturn false;\n\t\t});\n\t\tjack.expect('AdminData.actOnResult.action').exactly('0 time');\n\t\t$('#advance_search_destroy_all').trigger('click');\n\t});\n});\n\ntest('live clicking #advance_search_destroy_all', function() {\n\texpect(0);\n\tvar args;\n\n\tjack(function() {\n\t\tjack.expect('AdminData.jsUtil.confirm').once().mock(function() {\n\t\t\treturn true;\n\t\t});\n\t\tjack.expect('AdminData.actOnResult.action').once().mock(function(action_type) {\n\t\t\targs = action_type;\n\t\t\treturn {};\n\t\t});\n\t\t$('#advance_search_destroy_all').trigger('click');\n\t});\n\tequals('destroy', args, 'action_type should be destroy');\n});\n\ntest('actOnResultAJAX', function() {\n\texpect(5);\n\t$('#advance_search_form').attr('action', 'http://localhost:3000');\n\t$('#advance_search_form').data('admin_data_form_array', [{\n\t\tname: 'foo',\n\t\tvalue: 'i_am_foo'\n\t}]);\n\n\tvar ajaxArgs;\n\n\tjack(function() {\n\t\tjack.expect('$.ajax').once().mock(function(args) {\n\t\t\tajaxArgs = args;\n\t\t});\n\t\tAdminData.actOnResult.action('delete');\n\t});\n\n\tequals('post', ajaxArgs.type, 'ajax arguments should have type as post');\n\tequals('json', ajaxArgs.dataType, 'ajax arguments should have json as dataType');\n\tequals('http://localhost:3000', ajaxArgs.url, 'ajax arguments should have valid url');\n\tvar data = ajaxArgs.data;\n\tok(data, 'ajax arguments should have value for key data');\n\tequals('foo=i_am_foo&admin_data_advance_search_action_type=delete', data, 'data should have parameterized value');\n\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/test/advance_search.js",
    "content": "module('advance_search');\n\ntest('buildFirstRow', function() {\n\texpect(2);\n\t$('#advance_search_table').html('');\n\tAdminData.advanceSearch.buildFirstRow();\n\tvar $a = $('#advance_search_table').find('a');\n\tok($a.hasClass('add_row_link'), 'first row should have anchor element with class remove_row');\n\tok('+', $a.text(), 'first row should have anchor element with text +');\n});\n\n\ntest(\"buildCol1\", function() {\n\texpect(3);\n\n\tvar $td = AdminData.advanceSearch.buildCol1();\n\tok($.isjQuery($td), \"buildCol1 should return an instance of jQuery\");\n\n\tvar className = $td.find('select').attr('className');\n\tequals('col1', className, 'buildCol1 should have select with class col1');\n\n\tvar countOfOptions = $td.find('select option').length;\n\tequals(12, countOfOptions, 'buildCol1 should have select with 12 options');\n});\n\ntest(\"buildCol2\", function() {\n\texpect(3);\n\n\tvar $td = AdminData.advanceSearch.buildCol2();\n\tok($.isjQuery($td), \"buildCol2 should return an instance of jQuery\");\n\n\tok($td.find('select').hasClass('col2'), 'buildCol2 should have class col2');\n\tok($td.find('select').hasClass('disabled'), 'buildCol2 should have class disabled');\n});\n\ntest(\"buildCol3\", function() {\n\texpect(3);\n\n\tvar $td = AdminData.advanceSearch.buildCol3();\n\tok($.isjQuery($td), \"buildCol3 should return an instance of jQuery\");\n\n\tok($td.find('input').hasClass('col3'), 'buildCol3 should have input element with class col3');\n\tok($td.find('input').attr('disabled'), 'buildCol3 should have input element with attribute disabled');\n});\n\ntest(\"buildCol4\", function() {\n\texpect(3);\n\n\tvar $td = AdminData.advanceSearch.buildCol4();\n\tok($.isjQuery($td), \"buildCol4 should return an instance of jQuery\");\n\n\tvar a = $td.find('a');\n\tok(a.hasClass('remove_row'), 'buildCol4 should have anchor element with class remove_row');\n\tequals('x', a.text(), 'buildCol4 should have anchor element with text x');\n});\n\ntest(\"buildRow\", function() {\n\texpect(8);\n\tjack(function() {\n\t\tjack.expect(\"AdminData.jsUtil.randomNumber\").exactly(\"1 time\").mock(function() {\n\t\t\treturn 100;\n\t\t});\n\n\t\tvar $tr = AdminData.advanceSearch.buildRow();\n\t\tok($.isjQuery($tr), \"buildCol4 should return an instance of jQuery\");\n\n\t\tequals(4, $tr.find('td').length, 'buildRow should have 4 td elements');\n\n\t\tok($tr.find('select.col1').attr('name'), 'buildRow should have select.col1 with attribute name');\n\t\tok($tr.find('select.col2').attr('name'), 'buildRow should have select.col1 with attribute name');\n\t\tok($tr.find('input.col3').attr('name'), 'buildRow should have input.col1 with attribute name');\n\n\t\tequals('adv_search[100_row][col1]', $tr.find('select.col1').attr('name'), 'select.col1 should have right name');\n\t\tequals('adv_search[100_row][col2]', $tr.find('select.col2').attr('name'), 'select.col2 should have right name');\n\t\tequals('adv_search[100_row][col3]', $tr.find('input.col3').attr('name'), 'input.col3 should have right name');\n\n\t});\n\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/test/ajaxify_advance_search.js",
    "content": "module('ajaxify advance search', {\n\tteardown: function() {\n\t\t$('#results').remove();\n\t\t$('#advance_search_form').remove();\n\t},\n\tsetup: function() {\n\t\t$(document.body).append($('<div />', {\n\t\t\tid: 'results'\n\t\t}));\n\t\t$(document.body).append($('<div />', {\n\t\t\tid: 'advance_search_form'\n\t\t}));\n\t}\n});\n\ntest('successCallback', function() {\n\texpect(1);\n\tAdminData.ajaxifyAdvanceSearch.successCallback('hello world');\n\tequals('hello world', $('#results').text(), '#results should have text hello world');\n});\n\ntest('beforeSubmitCallback', function() {\n\texpect(1);\n\tAdminData.ajaxifyAdvanceSearch.beforeSubmitCallback(['1', '2'], null);\n\n\tvar $results = $('#results');\n\tequals('searching...', $('#results').text(), '#results should have text searching');\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/test/build_first_row.js",
    "content": "module('build_first_row');\n\ntest('table structure', function() {\n\texpect(1);\n\n\tvar tableStructure = $('#advance_search_table').data('table_structure');\n  ok(tableStructure, 'tableStructure should not be blank');\n\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/test/event_bindings.js",
    "content": "module('event_bindings');\n\ntest('live click on a.add_row_link', function() {\n\texpect(3);\n\n\t$('#advance_search_table').html('');\n\tequals(0, $('#advance_search_table tr').length, 'there should be no row in the table');\n\n\tAdminData.advanceSearch.buildFirstRow();\n\tequals(1, $('#advance_search_table tr').length, 'there should be only first row in the table');\n\n\t$('#advance_search_table a.add_row_link').trigger('click');\n\tequals(2, $('#advance_search_table tr').length, 'additional row should be added to the table');\n});\n\ntest('live click on a.remove_row link', function() {\n\texpect(5);\n\n\t$('#advance_search_table').html('');\n\tequals(0, $('#advance_search_table tr').length, 'there should be no row in the table');\n\n\tAdminData.advanceSearch.buildFirstRow();\n\tequals(1, $('#advance_search_table tr').length, 'there should be only first row in the table');\n\n\t$('#advance_search_table').append(AdminData.advanceSearch.buildRow());\n\tequals(2, $('#advance_search_table tr').length, 'there should be two rows in the table');\n\n\tvar $a = $('#advance_search_table a.remove_row');\n\tequals(1, $a.length, 'there should be one anchor element with class remove_row');\n\n\t$('#advance_search_table a.remove_row').trigger('click');\n\tequals(1, $('#advance_search_table tr').length, 'there should be only one row in the table');\n});\n\ntest('live select.col1 change', function() {\n\texpect(10);\n\n\t$('#advance_search_table').html('');\n\tequals(0, $('#advance_search_table tr').length, 'there should be no row in the table');\n\n\tAdminData.advanceSearch.buildFirstRow();\n\tequals(1, $('#advance_search_table tr').length, 'there should be only first row in the table');\n\n\tok($('#advance_search_table select.col2').is(':disabled'), 'second column should be disabled');\n\n\t$('#advance_search_table select.col1').val('first_name');\n\t$('#advance_search_table select.col1').trigger('change');\n\n\tok(!$('#advance_search_table select.col2').is(':disabled'), 'second column should be enabled');\n\n\tvar s = $('#advance_search_table select.col2 option').eq(0).text();\n\tequals('', s, 'empty value should be the first option');\n\n\ts = $('#advance_search_table select.col2 option').eq(1).text();\n\tequals('is null', s, 'is null should be the second option');\n\n\ts = $('#advance_search_table select.col2 option').eq(2).text();\n\tequals('is not null', s, 'is null should be the third option');\n\n\ts = $('#advance_search_table select.col2 option').eq(3).text();\n\tequals('contains', s, 'contains should be the fourth option');\n\n\ts = $('#advance_search_table select.col2 option').eq(4).text();\n\tequals('is exactly', s, 'contains should be the fifth option');\n\n\ts = $('#advance_search_table select.col2 option').eq(5).text();\n\tequals(\"doesn't contain\", s, 'does not contain should be the sixth option');\n});\n\ntest('live select.col2 change', function() {\n\texpect(2);\n\n\t$('#advance_search_table').html('');\n\tAdminData.advanceSearch.buildFirstRow();\n\tok($('#advance_search_table input.col3').is(':disabled'), 'third column should be disabled');\n\n\t$('#advance_search_table select.col1').val('first_name');\n\t$('#advance_search_table select.col1').trigger('change');\n\t$('#advance_search_table select.col2').val('contains');\n\t$('#advance_search_table select.col2').trigger('change');\n\n\tok($('#advance_search_table input.col3').is(':enabled'), 'third column should be enabled');\n});\n\n\ntest('live select.col2 change for is_null input', function() {\n\texpect(2);\n\n\t$('#advance_search_table').html('');\n\tAdminData.advanceSearch.buildFirstRow();\n\tok($('#advance_search_table input.col3').is(':disabled'), 'third column should be disabled');\n\n\t$('#advance_search_table select.col1').val('first_name');\n\t$('#advance_search_table select.col1').trigger('change');\n\t$('#advance_search_table select.col2').val('is_null');\n\t$('#advance_search_table select.col2').trigger('change');\n\n\tok($('#advance_search_table input.col3').is(':disabled'), 'third column should be disabled');\n});\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/validate_model/ajaxify_form.js",
    "content": "jQuery(document).ready(function($) {\n\treturn function($) {\n\t\tfunction handleSuccess(json, statusText) {\n\t\t\t$('#spinner').hide();\n\t\t\tvar base_url;\n\n\t\t\tif (! (json.error === undefined)) {\n\t\t\t\t$('#submit').attr('value', 'Start validation');\n\t\t\t\t$('#validation_result').html('').hide();\n\t\t\t\t$('#error').html(json.error).show();\n\t\t\t} else if (json.still_processing === 'yes') {\n\t\t\t\tif (! (json.base_url === undefined)) {\n\t\t\t\t\tbase_url = json.base_url;\n\t\t\t\t}\n\t\t\t\tvar keep_checking = function() {\n\t\t\t\t\tvar url = base_url + '/admin_data/diagnostic/validate_model?still_processing=yes';\n\t\t\t\t\turl = url + '&tid=' + $('#tid').text();\n\t\t\t\t\tvar fn = function(json) {\n\t\t\t\t\t\tif (json.still_processing === 'no') {\n\t\t\t\t\t\t\tclearInterval(refreshID);\n\t\t\t\t\t\t\t$('#submit').attr('value', 'Start validation');\n\t\t\t\t\t\t\t$('#validation_result').html('').hide();\n\t\t\t\t\t\t\t$('#validation_result').html('Validation result').show();\n\t\t\t\t\t\t\t$('#validate_model_rhs_data').html(json.data);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar processed_info = json.currently_processing_klass;\n\t\t\t\t\t\t\tvar s = processed_info + ' ... ';\n\t\t\t\t\t\t\t$('#validation_result').html(s);\n\t\t\t\t\t\t\t$('#validate_model_rhs_data').html(json.data);\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\t$.getJSON(url, fn);\n\t\t\t\t};\n\t\t\t\tvar refreshID = setInterval(keep_checking, 4000);\n\t\t\t} else {\n\t\t\t\t$('#validation_result').html('Validation result').show();\n\t\t\t\t$('#validate_model_rhs_data').html(json.data);\n\t\t\t}\n\t\t}\n\n\t\tfunction preSubmit(formData, jqForm, options) {\n\t\t\t$('html,body').animate({\n\t\t\t\tscrollTop: 0\n\t\t\t},\n\t\t\t0);\n\t\t\t$('#validate_model_rhs_data').html('');\n\t\t\t$('#validation_result').html('Processing .... This page will refersh itself periodically.').show();\n\t\t\t$('#error').hide();\n\t\t\t$('#spinner').show();\n\t\t\t$('#submit').attr('value', 'processing ...');\n\t\t\treturn true;\n\t\t}\n\n\t\tvar options = {\n\t\t\tbeforeSubmit: preSubmit,\n\t\t\tsuccess: handleSuccess,\n\t\t\tdataType: 'json'\n\t\t};\n\n\t\t$('#validate_model_form').ajaxForm(options);\n\n\t};\n} (jQuery));\n\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/validate_model/select_all.js",
    "content": "jQuery(document).ready(function($) {\n\treturn function($) {\n\n\t\t$('input#validate_model_select_all').click(function() {\n\t\t\tif ($(this).attr('checked')) {\n\t\t\t\t$(\"input[type=checkbox]\").attr(\"checked\", true);\n\t\t\t} else {\n\t\t\t\t$(\"input[type=checkbox]\").attr(\"checked\", false);\n\t\t\t}\n\t\t});\n\n\t};\n} (jQuery));\n\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/vendor/jack.js",
    "content": "/**\n *\n *  JACK :: JavaScript Mocking.\n *  Version: $Id$\n *\n */\n\n\nfunction jack() {} // This needs to be here to make error reporting work correctly in IE.\n\n(function (){ // START HIDING FROM GLOBAL SCOPE\n\t/** EXPORT JACK **/\n\twindow.jack = new Jack();\n\twindow.jack.matchers = new Matchers();\n\twindow.jack.util = new Util();\n\twindow.jack.FunctionSpecification = FunctionSpecification;\n\twindow.jack.FunctionGrab = FunctionGrab;\n\treturn;\n\n\n\t/**\n\t * Constructor for object that will be exposed as the global jack\n\t */\n\tfunction Jack() {\n\t\tvar functionGrabs = {};\n\t\tvar objectGrabs = {};\n\t\tvar environment = new Environment();\n\t\tvar reportMessages = [];\n\t\tvar currentExpectation = null;\n\t\tvar publicApi = createPublicApi();\n\t\treturn publicApi;\n\n\t\tfunction createPublicApi() {\n\t\t\tvar api = jackFunction;\n\t\t\tapi.grab = grab;\n\t\t\tapi.create = create;\n\t\t\tapi.inspect = inspect;\n\t\t\tapi.expect = expect;\n\t\t\tapi.verify = verify;\n\t\t\tapi.report = report;\n\t\t\tapi.reportAll = reportAll;\n\t\t\tapi.env = environment;\n\t\t\treturn api;\n\t\t}\n\t\tfunction jackFunction(delegate) {\n\t\t\tbefore();\n\t\t\tfirstPass(delegate);\n\t\t\t// secondPass(delegate);\n\t\t\tafter();\n\t\t}\n\t\tfunction before() {\n\t\t\tfunctionGrabs = {};\n\t\t\tobjectGrabs = {};\n\t\t\tenvironment.reset();\n\t\t}\n\t\tfunction firstPass(delegate) {\n\t\t\tdelegate();\n\t\t}\n\t\tfunction secondPass(delegate) {\n\t\t\tvar oldExpect = publicApi.expect;\n\t\t\tpublicApi.expect = function(name) {\n\t\t\t\tvar fakeEx = {};\n\t\t\t\tvar grab = findGrab(name);\n\t\t\t\tif(grab._beenThroughSecondPass) {\n\t\t\t\t\tvar ex = grab.expect();\n\t\t\t\t\tfor(prop in ex) {\n\t\t\t\t\t\tif(typeof ex[prop] == \"function\") {\n\t\t\t\t\t\t\tfakeEx[prop] = function() { return fakeEx; }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tgrab._beenThroughSecondPass = true;\n\t\t\t\treturn fakeEx;\n\t\t\t};\n\t\t\tvar findMore = true;\n\t\t\tfor(var i=0; findMore && i<10; i++) {\n\t\t\t\ttry {\n\t\t\t\t\tdelegate();\n\t\t\t\t\tfindMore = false;\n\t\t\t\t} catch(exception) {\n\t\t\t\t\tvar line = -1;\n\t\t\t\t\tif(exception.lineNumber != null) {\n\t\t\t\t\t\tline = exception.lineNumber;\n\t\t\t\t\t} else if(exception['opera#sourceloc'] != null) {\n\t\t\t\t\t\tline = exception['opera#sourceloc'];\n\t\t\t\t\t}\n\t\t\t\t\tcurrentExpectation._lineNumber = line;\n\t\t\t\t}\n\t\t\t}\n\t\t\tpublicApi.expect = oldExpect;\n\t\t}\n\t\tfunction after() {\n\t\t\tvar reports = getTextReports();\n\t\t\tresetGrabs();\n\t\t\tif(reports.length > 0) {\n\t\t\t\tenvironment.report(reports[0]);\n\t\t\t}\n\t\t}\n\t\tfunction getTextReports() {\n\t\t\tvar failedReports = [];\n\t\t\tfor(var name in functionGrabs) {\n\t\t\t\tvar reports = functionGrabs[name].reportAll(name);\n\t\t\t\tfor(var i=0; i<reports.length; i++) {\n\t\t\t\t\tif(reports[i].fail) {\n\t\t\t\t\t\tfailedReports.push(reports[i].message);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor(var name in objectGrabs) {\n\t\t\t\tvar reports = objectGrabs[name].report(name);\n\t\t\t\tfor(var i=0; i<reports.length; i++) {\n\t\t\t\t\tif(reports[i].fail) {\n\t\t\t\t\t\tfailedReports.push(reports[i].message);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn failedReports;\n\t\t}\n\t\tfunction grab() {\n\t\t\tif(\"object\" == typeof arguments[0] && \"string\" == typeof arguments[1]) {\n\t\t\t\tvar parentObject = arguments[0];\n\t\t\t\tvar name = arguments[1];\n\t\t\t\tvar fullName = \"[local].\" + name;\n\t\t\t\treturn grabFunction(fullName, parentObject[name], parentObject);\n\t\t\t} else {\n\t\t\t\tvar grabbed = null;\n\t\t\t\teval(\"grabbed = \" + arguments[0]);\n\t\t\t\tif(\"function\" == typeof grabbed) {\n\t\t\t\t\tvar functionGrab = grabFunction(arguments[0], grabbed);\n\t\t\t\t\teval(\"grabbed = \" + arguments[0]);\n\t\t\t\t\tgrabObject(arguments[0], grabbed);\n\t\t\t\t\treturn functionGrab;\n\t\t\t\t} else if(\"object\" == typeof grabbed) {\n\t\t\t\t\treturn grabObject(arguments[0], grabbed);\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tfunction grabFunction(fullName, grabbed, parentObject) {\n\t\t\tif(parentObject == null) {\n\t\t\t\tparentObject = window;\n\t\t\t}\n\t\t\tvar functionName = fullName;\n\t\t\tvar nameParts = fullName.split(\".\");\n\t\t\tif(nameParts[0] == \"[local]\") {\n\t\t\t\tfunctionName = nameParts[1];\n\t\t\t} else if(nameParts.length > 1) {\n\t\t\t\tfunctionName = nameParts.pop();\n\t\t\t\tif(parentObject == window) {\n\t\t\t\t\tvar parentName = nameParts.join(\".\");\n\t\t\t\t\teval(\"parentObject = \" + parentName);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfunctionGrabs[fullName] = new FunctionGrab(functionName, grabbed, parentObject);\n\t\t\treturn functionGrabs[fullName];\n\t\t}\n\t\tfunction grabObject(name, grabbed) {\n\t\t\tobjectGrabs[name] = new ObjectGrab(name, grabbed);\n\t\t\treturn objectGrabs[name];\n\t\t}\n\t\tfunction create(objectName, functionNames) {\n\t\t\tvar mockObject = {};\n\t\t\tfor(var i=0; i<functionNames.length; i++) {\n\t\t\t\tmockObject[functionNames[i]] = function() {};\n\t\t\t\tvar fullName = objectName+\".\"+functionNames[i];\n\t\t\t\tgrabFunction(fullName, mockObject[functionNames[i]], mockObject);\n\t\t\t}\n\t\t\treturn mockObject;\n\t\t}\n\t\tfunction inspect(name) {\n\t\t\treturn findGrab(name);\n\t\t}\n\t\tfunction expect(name) {\n\t\t\tif(findGrab(name) == null) {\n\t\t\t\tgrab(name);\n\t\t\t}\n\t\t\tcurrentExpectation = findGrab(name).expect().once();\n\t\t\treturn currentExpectation;\n\t\t}\n\t\tfunction verify(name) {\n\t\t\tif(findGrab(name) == null) {\n\t\t\t\tgrab(name);\n\t\t\t}\n\t\t\tcurrentExpectation = findGrab(name).expect().once();\n\t\t\treturn currentExpectation;\n\t\t}\n\t\tfunction report(name, expectation) {\n\t\t\treturn findGrab(name).report(expectation, name);\n\t\t}\n\t\tfunction reportAll(name) {\n\t\t\treturn findGrab(name).reportAll(name);\n\t\t}\n\t\tfunction findGrab(name) {\n\t\t\tvar parts = name.split(\".\");\n\t\t\tif(parts.length == 1 && functionGrabs[name] != null) {\n\t\t\t\treturn functionGrabs[name];\n\t\t\t} else if(parts.length == 1 && objectGrabs[name] != null) {\n\t\t\t\treturn objectGrabs[name];\n\t\t\t} else {\n\t\t\t\tif(functionGrabs[name] != null) {\n\t\t\t\t\treturn functionGrabs[name];\n\t\t\t\t}\n\t\t\t\tif(objectGrabs[name] != null) {\n\t\t\t\t\treturn objectGrabs[name];\n\t\t\t\t}\n\t\t\t\tif(objectGrabs[parts[0]] != null) {\n\t\t\t\t\treturn objectGrabs[parts[0]].examine(parts[1]);\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\t\tfunction resetGrabs() {\n\t\t\tfor(var g in functionGrabs) {\n\t\t\t\tfunctionGrabs[g].reset();\n\t\t\t}\n\t\t\tfor(var g in objectGrabs) {\n\t\t\t\tobjectGrabs[g].reset();\n\t\t\t}\n\t\t}\n\t} // END Jack()\n\n\n\t/**\n\t * @functionName      Name of grabbed function\n\t * @grabbedFunction   Reference to grabbed function\n\t * @parentObject      The object the function was grabbed from\n\t */\n\tfunction FunctionGrab(functionName, grabbedFunction, parentObject) {\n\t\tvar invocations = [];\n\t\tvar specifications = [];\n\t\tvar emptyFunction = function(){};\n\n\t\tinit();\n\t\treturn {\n\t\t\t'times': function() { return invocations.length; },\n\t\t\t'reset': reset,\n\t\t\t'expect': expect,\n\t\t\t'specify': specify,\n\t\t\t'report': report,\n\t\t\t'reportAll': reportAll,\n\t\t\t'mock': mock,\n\t\t\t'stub': stub,\n\t\t\t'arguments': getArguments,\n\t\t\t'name': function() { return functionName }\n\t\t};\n\n\t\tfunction init() {\n\t\t\tvar original = parentObject[functionName];\n\t\t\tvar handler = function() {\n\t\t\t\treturn handleInvocation.apply(this,arguments);\n\t\t\t}\n\t\t\tfor(var prop in original) {\n\t\t\t\thandler[prop] = original[prop];\n\t\t\t}\n\t\t\tparentObject[functionName] = handler;\n\t\t}\n\t\tfunction handleInvocation() {\n\t\t\tvar invocation = new FunctionSpecification();\n\t\t\tfor(var i=0; i<arguments.length; i++) {\n\t\t\t\tinvocation.whereArgument(i).is(arguments[i]);\n\t\t\t}\n\t\t\tinvocations.push(invocation);\n\t\t\tvar specification = findSpecificationFor(invocation);\n\t\t\tif(specification == null) {\n\t\t\t\treturn grabbedFunction.apply(this, arguments);\n\t\t\t} else if(specification.hasMockImplementation()) {\n\t\t\t\treturn specification.invoke.apply(this, arguments);\n\t\t\t} else {\n\t\t\t\tspecification.invoke.apply(this, arguments);\n\t\t\t\treturn grabbedFunction.apply(this, arguments);\n\t\t\t}\n\t\t}\n\t\tfunction matchInvocationsToSpecifications() {\n\t\t\tfor(var i=0; i<invocations.length; i++) {\n\t\t\t\tvar spec = findSpecificationFor(invocations[i]);\n\t\t\t\tif(spec != null) {\n\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfunction findSpecificationFor(invocation) {\n\t\t\tfor(var i=0; i<specifications.length; i++) {\n\t\t\t\tvar specification = specifications[i];\n\t\t\t\tif(invocation.satisfies(specification)) {\n\t\t\t\t\treturn specification;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\tfunction isArgumentContstraintsMatching(invocation, expectation) {\n\t\t\tvar constr = expectation._argumentConstraints;\n\t\t\tvar arg = invocation.arguments;\n\t\t\tif(constr == null) {\n\t\t\t\treturn true;\n\t\t\t} else if(constr.length != arg.length) {\n\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\tfor(var i=0; i<constr.length; i++) {\n\t\t\t\t\tif(!constr[i]) { continue; }\n\t\t\t\t\tfor(var j=0; j<constr[i].length; j++) {\n\t\t\t\t\t\tif(typeof constr[i][j] == \"function\" && !constr[i][j](arg[i])) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tfunction reset() {\n\t\t\tparentObject[functionName] = grabbedFunction;\n\t\t}\n\t\tfunction specify() {\n\t\t\tvar spec = new FunctionSpecification();\n\t\t\tspec._id = specifications.length;\n\t\t\tspecifications.push(spec);\n\t\t\treturn spec;\n\t\t}\n\t\tfunction verify() {\n\n\t\t}\n\t\tfunction expect() {\n\t\t\treturn specify();\n\t\t}\n\t\tfunction mock(implementation) {\n\t\t\treturn expect().mock(implementation);\n\t\t}\n\t\tfunction stub() {\n\t\t\treturn expect();\n\t\t}\n\t\tfunction parseTimes(expression) {\n\t\t\tvar result = 0;\n\t\t\tif(\"number\" == typeof expression) {\n\t\t\t\tresult = expression;\n\t\t\t} else if(\"string\" == typeof expression) {\n\t\t\t\tvar parts = expression.split(\" \");\n\t\t\t\tresult = parseInt(parts[0]);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\tfunction reportAll(fullName) {\n\t\t\tvar reports = [];\n\t\t\tfor(var i=0; i<specifications.length; i++) {\n\t\t\t\treports.push(report(specifications[i], fullName));\n\t\t\t}\n\t\t\treturn reports;\n\t\t}\n\t\tfunction report(specification, fullName) {\n\t\t\tif(specification == null) {\n\t\t\t\tif(specifications.length == 0) {\n\t\t\t\t\tvar spec = specify().never();\n\t\t\t\t\tfor(var i=0; i<invocations.length; i++) {\n\t\t\t\t\t\tspec.invoke();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tspecification = specifications[0];\n\t\t\t}\n\t\t\tvar report = {};\n\t\t\treport.expected = specification.invocations().expected;\n\t\t\treport.actual = specification.invocations().actual;\n\t\t\treport.success = specification.testTimes(report.actual);\n\t\t\treport.fail = !report.success;\n\t\t\tif(report.fail) {\n\t\t\t\treport.message = \"Expectation failed: \" + specification.describe(fullName);\n\t\t\t}\n\t\t\treturn report;\n\t\t}\n\t\tfunction generateReportMessage(report, fullName, argumentsDisplay) {\n\t\t\treturn report.messageParts.template\n\t\t\t\t\t.replace(\"{name}\",fullName)\n\t\t\t\t\t.replace(\"{arguments}\",argumentsDisplay)\n\t\t\t\t\t.replace(\"{quantifier}\",report.messageParts.quantifier)\n\t\t\t\t\t.replace(\"{expected}\",report.expected)\n\t\t\t\t\t.replace(\"{actual}\",report.actual);\n\t\t}\n\t\tfunction getArgumentsDisplay(expectation) {\n\t\t\tif(expectation == null) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\tvar displayValues = [];\n\t\t\tvar constraints = expectation._argumentConstraints;\n\t\t\tif(constraints == null) {\n\t\t\t\treturn \"\";\n\t\t\t} else {\n\t\t\t\tfor(var i=0; i<constraints.length; i++) {\n\t\t\t\t\tif(constraints[i] != null) {\n\t\t\t\t\t\tdisplayValues.push(constraints[i][0].display);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdisplayValues.push('[any]');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn displayValues.join(', ');\n\t\t\t}\n\t\t}\n\t\tfunction getArguments() {\n\t\t\treturn invocations[0].getArgumentValues();\n\t\t}\n\t} // END FunctionGrab()\n\n\n\t/**\n\t *\n\t */\n\tfunction ObjectGrab(objectName, grabbedObject) {\n\t\tvar grabs = {};\n\n\t\tinit();\n\t\treturn {\n\t\t\t'examine': getGrab,\n\t\t\t'report': report,\n\t\t\t'getGrab': getGrab,\n\t\t\t'getGrabs': function() {  return grabs },\n\t\t\t'reset': reset\n\t\t};\n\n\t\tfunction init() {\n\t\t\tfor(key in grabbedObject) {\n\t\t\t\tvar property =  grabbedObject[key];\n\t\t\t\tif(\"function\" == typeof property) {\n\t\t\t\t\tgrabs[key] = new FunctionGrab(key, property, grabbedObject);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfunction report(name) {\n\t\t\tvar allReports = [];\n\t\t\tfor(var g in grabs) {\n\t\t\t\tvar reports = grabs[g].reportAll(name+\".\"+grabs[g].name());\n\t\t\t\tfor(var i=0; i<reports.length; i++) {\n\t\t\t\t\tallReports.push(reports[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn allReports;\n\t\t}\n\t\tfunction getGrab(name) {\n\t\t\treturn grabs[name];\n\t\t}\n\t\tfunction reset() {\n\t\t\tfor(var g in grabs) {\n\t\t\t\tgrabs[g].reset();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t *\n\t */\n\tfunction Environment() {\n\t\tvar reportingEnabled = true;\n\t\tinit();\n\t\treturn {\n\t\t\t'isJSSpec': isJSSpec,\n\t\t\t'isScriptaculous': isScriptaculous,\n\t\t\t'isQunit': isQunit,\n\t\t\t'isJsTestDriver': isJsTestDriver,\n\t\t\t'isYuiTest': isYuiTest,\n\t\t\t'report': report,\n\t\t\t'disableReporting': function() { reportingEnabled = false; },\n\t\t\t'enableReporting': function() { reportingEnabled = true; },\n\t\t\t'reset': function() {}\n\t\t}\n\t\tfunction init() {\n\n\t\t}\n\t\tfunction isJSSpec() {\n\t\t\treturn window.JSSpec != null;\n\t\t}\n\t\tfunction isScriptaculous() {\n\t\t\treturn window.Test != null && window.Test.Unit != null && window.Test.Unit.Runner != null;\n\t\t}\n\t\tfunction isQunit() {\n\t\t\treturn window.QUnit != null;\n\t\t}\n\t\tfunction isJsTestDriver() {\n\t\t\treturn window.jstestdriver != null;\n\t\t}\n\t\tfunction isYuiTest() {\n\t\t\tvar y = window.YAHOO;\n\t\t\treturn y != null && y.tool != null && y.tool.TestCase != null;\n\t\t}\n\t\tfunction report(message) {\n\t\t\tif(!reportingEnabled) { return; }\n\t\t\tif(isYuiTest()) {\n\t\t\t\tYAHOO.util.Assert.fail(message);\n\t\t\t} else if(isJsTestDriver()) {\n\t\t\t\tfail(message);\n\t\t\t} else if(isScriptaculous()) {\n\t\t\t\tthrow new Error(message);\n\t\t\t} else if(isQunit()) {\n\t\t\t\tok(false, message);\n\t\t\t} else if(isJSSpec()) {\n\t\t\t\tthrow new Error(message);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t *\n\t */\n\tfunction Util() {\n\t\treturn {\n\t\t\t'displayValue': displayValue\n\t\t}\n\n\t\tfunction displayValue() {\n\t\t\tvar value = arguments[0];\n\t\t\tvar prefix = \"\";\n\t\t\tif(arguments.length > 1) {\n\t\t\t\tvalue = arguments[1];\n\t\t\t\tprefix = arguments[0];\n\t\t\t}\n\t\t\tif(value == undefined) {\n\t\t\t\treturn displayValueNullOrUndefined(value);\n\t\t\t}\n\t\t\tvar display = displayValueDefault(value);\n\t\t\tif('string' == typeof value) {\n\t\t\t\tdisplay = displayValueString(value);\n\t\t\t} else if(value.constructor == Array) {\n\t\t\t\tdisplay = displayValueArray(value);\n\t\t\t} else if(value.constructor == RegExp) {\n\t\t\t\tdisplay = displayValueRegExp(value);\n\t\t\t} else if('object' == typeof value) {\n\t\t\t\tdisplay = displayValueObject(value);\n\t\t\t}\n\t\t\treturn prefix + display;\n\t\t}\n\t\tfunction displayValueDefault(value) {\n\t\t\treturn value.toString();\n\t\t}\n\t\tfunction displayValueString(value) {\n\t\t\treturn \"'\" + value + \"'\";\n\t\t}\n\t\tfunction displayValueArray(value) {\n\t\t\tvar displayValues = [];\n\t\t\tfor(var i=0; i<value.length; i++) {\n\t\t\t\tdisplayValues.push(displayValue(value[i]));\n\t\t\t}\n\t\t\treturn \"[\" + displayValues.join(\",\") + \"]\";\n\t\t}\n\t\tfunction displayValueNullOrUndefined(value) {\n\t\t\tif(value === undefined) {\n\t\t\t\treturn \"undefined\";\n\t\t\t} else if(value === null) {\n\t\t\t\treturn \"null\";\n\t\t\t}\n\t\t}\n\t\tfunction displayValueRegExp(value) {\n\t\t\treturn value.toString();\n\t\t}\n\t\tfunction displayValueObject(value) {\n\t\t\tvar keyValues = [];\n\t\t\tfor(var p in value) {\n\t\t\t\tkeyValues.push(p + ':' + displayValue(value[p]));\n\t\t\t}\n\t\t\treturn '{' + keyValues.join(',') + '}';\n\t\t}\n\t}\n\n\t/**\n\t *\n\t */\n\tfunction FunctionSpecification() {\n\t\tvar constraints = null;\n\t\tvar argumentValues = [];\n\t\tvar mockImplementation = null;\n\t\tvar timing = {actual: 0, expected: 1, modifier: 0};\n\n\t\tvar api = createApi();\n\t\treturn api;\n\n\t\tfunction createApi() {\n\t\t\tvar api = {};\n\t\t\tmixinMatchers(api);\n\t\t\tmixinTiming(api);\n\t\t\tapi.test = test;\n\t\t\tapi.testTimes = testTimes;\n\t\t\tapi.satisfies = satisfies;\n\t\t\tapi.invoke = invoke;\n\t\t\tapi.mock = mock;\n\t\t\tapi.stub = stub;\n\t\t\tapi.returnValue = returnValue;\n\t\t\tapi.returnValues = returnValues;\n\t\t\tapi.describe = describe;\n\t\t\tapi.invocations = invocations;\n\t\t\tapi.getArgumentValues = getArgumentValues;\n\t\t\tapi.hasMockImplementation = hasMockImplementation;\n\t\t\treturn api;\n\t\t}\n\t\tfunction mixinMatchers(api) {\n\t\t\tapi.whereArgument = function(argIndex) {\n\t\t\t\tvar collected = {};\n\t\t\t\tfor(var name in jack.matchers) {\n\t\t\t\t\taddMatcher(argIndex, name, collected)\n\t\t\t\t}\n\t\t\t\treturn collected;\n\t\t\t}\n\t\t\tapi.withArguments = function() {\n\t\t\t\tfor(var i=0; i<arguments.length; i++) {\n\t\t\t\t\tapi.whereArgument(i).is(arguments[i]);\n\t\t\t\t}\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\tapi.withNoArguments = function() { constraints = []; return api; }\n\t\t\treturn api;\n\n\t\t\tfunction addMatcher(argIndex, name, collection) {\n\t\t\t\tcollection[name] = function() {\n\t\t\t\t\taddConstraint(argIndex, jack.matchers[name], arguments);\n\t\t\t\t\tif(name == \"is\") {\n\t\t\t\t\t\taddArgumentValue(argIndex, arguments[0]);\n\t\t\t\t\t}\n\t\t\t\t\treturn api;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfunction mixinTiming(api) {\n\t\t\tapi.exactly = function(times) {\n\t\t\t\ttiming.expected = parseTimes(times);\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\tapi.once = function() {\n\t\t\t\ttiming.expected = 1;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\tapi.atLeast = function(times) {\n\t\t\t\ttiming.expected = parseTimes(times);\n\t\t\t\ttiming.modifier = 1;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\tapi.atMost = function(times) {\n\t\t\t\ttiming.expected = parseTimes(times);\n\t\t\t\ttiming.modifier = -1;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\tapi.never = function() {\n\t\t\t\ttiming.expected = 0;\n\t\t\t\treturn api;\n\t\t\t}\n\n\t\t\tfunction parseTimes(times) {\n\t\t\t\treturn parseInt(times);\n\t\t\t}\n\t\t}\n\t\tfunction addArgumentValue(index, value) {\n\t\t\targumentValues[index] = value;\n\t\t}\n\t\tfunction addConstraint(argIndex, matcher, matcherArguments) {\n\t\t\tcreateConstraintsArrayIfNull(argIndex);\n\t\t\tvar constraint = function(value) {\n\t\t\t\tvar allArguments = [value];\n\t\t\t\tfor(var i=0; i<matcherArguments.length; i++) {\n\t\t\t\t\tallArguments.push(matcherArguments[i]);\n\t\t\t\t}\n\t\t\t\tvar test = matcher.apply(null, allArguments);\n\t\t\t\treturn test.result;\n\t\t\t}\n\t\t\tconstraints[argIndex].push(constraint);\n\t\t\tconstraints[argIndex].describe = function() {\n\t\t\t\tvar allArguments = [\"\"];\n\t\t\t\tfor(var i=0; i<matcherArguments.length; i++) {\n\t\t\t\t\tallArguments.push(matcherArguments[i]);\n\t\t\t\t}\n\t\t\t\treturn matcher.apply(null, allArguments).expected;\n\t\t\t}\n\t\t}\n\t\tfunction createConstraintsArrayIfNull(argIndex) {\n\t\t\tif(constraints == null) {\n\t\t\t\tconstraints = [];\n\t\t\t}\n\t\t\tif(constraints[argIndex] == null) {\n\t\t\t\tconstraints[argIndex] = [];\n\t\t\t}\n\t\t}\n\t\tfunction test() {\n\t\t\tvar result = true;\n\t\t\tif(constraints != null) {\n\t\t\t\tif(constraints.length != arguments.length) {\n\t\t\t\t\tresult = false;\n\t\t\t\t} else {\n\t\t\t\t\tfor (var i = 0; i < constraints.length; i++) {\n\t\t\t\t\t\tvar oneArgumentsConstraints = constraints[i];\n\t\t\t\t\t\tif (oneArgumentsConstraints != null) {\n\t\t\t\t\t\t\tfor (var j = 0; j < oneArgumentsConstraints.length; j++) {\n\t\t\t\t\t\t\t\tvar constraint = oneArgumentsConstraints[j];\n\t\t\t\t\t\t\t\tif (constraint && !constraint(arguments[i])) {\n\t\t\t\t\t\t\t\t\tresult = false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\tfunction testTimes(times) {\n\t\t\tif(timing.modifier == 0) {\n\t\t\t\treturn times == timing.expected;\n\t\t\t} else if(timing.modifier == 1) {\n\t\t\t\treturn times >= timing.expected;\n\t\t\t} else if(timing.modifier == -1) {\n\t\t\t\treturn times <= timing.expected;\n\t\t\t}\n\t\t}\n\t\tfunction satisfies(other) {\n\t\t\treturn other.test.apply(this, argumentValues);\n\t\t}\n\t\tfunction invoke() {\n\t\t\ttiming.actual++;\n\t\t\tif(mockImplementation != null) {\n\t\t\t\treturn mockImplementation.apply(this, arguments);\n\t\t\t}\n\t\t}\n\t\tfunction mock(implementation) {\n\t\t\tmockImplementation = implementation;\n\t\t\treturn api;\n\t\t}\n\t\tfunction stub() {\n\t\t\tmockImplementation = function() {};\n\t\t\treturn api;\n\t\t}\n\t\tfunction returnValue(value) {\n\t\t\tmockImplementation = function() {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t\tfunction returnValues() {\n\t\t\tvar values = [], orig = this;\n\t\t\tfor (var i = 0, len = arguments.length; i < len; i++) { values.push(arguments[i]); }\n\t\t\tmockImplementation = function() {\n\t\t\t\treturn values.shift();\n\t\t\t};\n\t\t}\n\t\tfunction hasMockImplementation() {\n\t\t\treturn mockImplementation != null;\n\t\t}\n\t\tfunction invocations() {\n\t\t\treturn {\n\t\t\t\tactual: timing.actual,\n\t\t\t\texpected: timing.expected\n\t\t\t};\n\t\t}\n\t\tfunction getArgumentValues() {\n\t\t\treturn argumentValues;\n\t\t}\n\t\tfunction describe(name) {\n\t\t\treturn name +\"(\" + describeConstraints() + \") \" + describeTimes();\n\t\t}\n\t\tfunction describeConstraints() {\n\t\t\tif(constraints == null) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\tvar descriptions = [];\n\t\t\tfor(var i=0; i<constraints.length; i++) {\n\t\t\t\tif(constraints[i] != null) {\n\t\t\t\t\tdescriptions.push(constraints[i].describe());\n\t\t\t\t} else {\n\t\t\t\t\tdescriptions.push(\"[any]\");\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn descriptions.join(\", \");\n\t\t}\n\t\tfunction describeTimes() {\n\t\t\tvar description = timing.expected;\n\t\t\tif(timing.expected == 1) {\n\t\t\t\tdescription += \" time\";\n\t\t\t} else {\n\t\t\t\tdescription += \" times\";\n\t\t\t}\n\t\t\tif(timing.modifier == 0) {\n\t\t\t\tdescription = \"expected exactly \" + description;\n\t\t\t} else if(timing.modifier > 0) {\n\t\t\t\tdescription = \"expected at least \" + description;\n\t\t\t} else if(timing.modifier < 0) {\n\t\t\t\tdescription = \"expected at most \" + description;\n\t\t\t}\n\t\t\tdescription += \", called \" + timing.actual + \" time\";\n\t\t\tif(timing.actual != 1) {\n\t\t\t\tdescription += \"s\";\n\t\t\t}\n\t\t\treturn description;\n\t\t}\n\t}\n\n\n\t/**\n\t *\n\t */\n\tfunction Matchers() {\n\t\treturn {\n\t\t\t'is':\n\t\t\t\tfunction(a, b) {\n\t\t\t\t\treturn result(a==b, a, '', b);\n\t\t\t\t},\n\t\t\t'isNot':\n\t\t\t\tfunction(a, b) {\n\t\t\t\t\treturn result(a!=b, a, 'not:', b);\n\t\t\t\t},\n\t\t\t'isType':\n\t\t\t\tfunction(a, b) {\n\t\t\t\t\treturn result(b == typeof a, a, 'type:', b);\n\t\t\t\t},\n\t\t\t'matches':\n\t\t\t\tfunction(a, b) {\n\t\t\t\t\treturn result(b.test(a), a, 'matching:', b)\n\t\t\t\t},\n\t\t\t'hasProperty':\n\t\t\t\tfunction(a, b, c) {\n\t\t\t\t\tvar match = c ? a[b]==c : a[b]!=undefined;\n\t\t\t\t\tvar bDisplay = b;\n\t\t\t\t\tif(c != null) {\n\t\t\t\t\t\tbDisplay = {};\n\t\t\t\t\t\tbDisplay[b] = c;\n\t\t\t\t\t}\n\t\t\t\t\treturn result(match, a, 'property:', bDisplay)\n\t\t\t\t},\n\t\t\t'hasProperties':\n\t\t\t\tfunction(a, b) {\n\t\t\t\t\tvar match = true;\n\t\t\t\t\tfor(var p in b) {\n\t\t\t\t\t\tif(a[p] != b[p]) {\n\t\t\t\t\t\t\tmatch = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn result(match, a, 'properties:', b);\n\t\t\t\t},\n\t\t\t'isGreaterThan':\n\t\t\t\tfunction(a, b) {\n\t\t\t\t\treturn result(b < a, a, '>', b);\n\t\t\t\t},\n\t\t\t'isLessThan':\n\t\t\t\tfunction(a, b) {\n\t\t\t\t\treturn result(b > a, a, '<', b);\n\t\t\t\t},\n\t\t\t'isOneOf':\n\t\t\t\tfunction() {\n\t\t\t\t\tvar a = arguments[0];\n\t\t\t\t\tvar b = [];\n\t\t\t\t\tfor(var i=1; i<arguments.length; i++) {\n\t\t\t\t\t\tb.push(arguments[i]);\n\t\t\t\t\t}\n\t\t\t\t\tvar match = false;\n\t\t\t\t\tfor(var i=0; i<b.length; i++) {\n\t\t\t\t\t\tif(b[i] == a) {\n\t\t\t\t\t\t\tmatch = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn result(match, a, 'oneOf:', b);\n\t\t\t\t}\n\t\t}\n\n\t\tfunction result(match, actual, prefix, expected) {\n\t\t\treturn {\n\t\t\t\tresult: match,\n\t\t\t\tactual: jack.util.displayValue(actual),\n\t\t\t\texpected: jack.util.displayValue(prefix, expected)\n\t\t\t}\n\t\t}\n\t}\n\n})(); // END HIDING FROM GLOBAL SCOPE\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/vendor/jquery-1.4.1.js",
    "content": "/*!\n * jQuery JavaScript Library v1.4.1\n * http://jquery.com/\n *\n * Copyright 2010, John Resig\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n * Copyright 2010, The Dojo Foundation\n * Released under the MIT, BSD, and GPL Licenses.\n *\n * Date: Mon Jan 25 19:43:33 2010 -0500\n */\n(function( window, undefined ) {\n\n// Define a local copy of jQuery\nvar jQuery = function( selector, context ) {\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\treturn new jQuery.fn.init( selector, context );\n\t},\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$,\n\n\t// Use the correct document accordingly with window argument (sandbox)\n\tdocument = window.document,\n\n\t// A central reference to the root jQuery(document)\n\trootjQuery,\n\n\t// A simple way to check for HTML strings or ID strings\n\t// (both of which we optimize for)\n\tquickExpr = /^[^<]*(<[\\w\\W]+>)[^>]*$|^#([\\w-]+)$/,\n\n\t// Is it a simple selector\n\tisSimple = /^.[^:#\\[\\.,]*$/,\n\n\t// Check if a string has a non-whitespace character in it\n\trnotwhite = /\\S/,\n\n\t// Used for trimming whitespace\n\trtrim = /^(\\s|\\u00A0)+|(\\s|\\u00A0)+$/g,\n\n\t// Match a standalone tag\n\trsingleTag = /^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,\n\n\t// Keep a UserAgent string for use with jQuery.browser\n\tuserAgent = navigator.userAgent,\n\n\t// For matching the engine and version of the browser\n\tbrowserMatch,\n\t\n\t// Has the ready events already been bound?\n\treadyBound = false,\n\t\n\t// The functions to execute on DOM ready\n\treadyList = [],\n\n\t// The ready event handler\n\tDOMContentLoaded,\n\n\t// Save a reference to some core methods\n\ttoString = Object.prototype.toString,\n\thasOwnProperty = Object.prototype.hasOwnProperty,\n\tpush = Array.prototype.push,\n\tslice = Array.prototype.slice,\n\tindexOf = Array.prototype.indexOf;\n\njQuery.fn = jQuery.prototype = {\n\tinit: function( selector, context ) {\n\t\tvar match, elem, ret, doc;\n\n\t\t// Handle $(\"\"), $(null), or $(undefined)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle $(DOMElement)\n\t\tif ( selector.nodeType ) {\n\t\t\tthis.context = this[0] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\t// Are we dealing with HTML string or an ID?\n\t\t\tmatch = quickExpr.exec( selector );\n\n\t\t\t// Verify a match, and that no context was specified for #id\n\t\t\tif ( match && (match[1] || !context) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[1] ) {\n\t\t\t\t\tdoc = (context ? context.ownerDocument || context : document);\n\n\t\t\t\t\t// If a single string is passed in and it's a single tag\n\t\t\t\t\t// just do a createElement and skip the rest\n\t\t\t\t\tret = rsingleTag.exec( selector );\n\n\t\t\t\t\tif ( ret ) {\n\t\t\t\t\t\tif ( jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\t\tselector = [ document.createElement( ret[1] ) ];\n\t\t\t\t\t\t\tjQuery.fn.attr.call( selector, context, true );\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tselector = [ doc.createElement( ret[1] ) ];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tret = buildFragment( [ match[1] ], [ doc ] );\n\t\t\t\t\t\tselector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;\n\t\t\t\t\t}\n\n\t\t\t\t// HANDLE: $(\"#id\")\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[2] );\n\n\t\t\t\t\tif ( elem ) {\n\t\t\t\t\t\t// Handle the case where IE and Opera return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id !== match[2] ) {\n\t\t\t\t\t\t\treturn rootjQuery.find( selector );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Otherwise, we inject the element directly into the jQuery object\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t\tthis[0] = elem;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.context = document;\n\t\t\t\t\tthis.selector = selector;\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(\"TAG\")\n\t\t\t} else if ( !context && /^\\w+$/.test( selector ) ) {\n\t\t\t\tthis.selector = selector;\n\t\t\t\tthis.context = document;\n\t\t\t\tselector = document.getElementsByTagName( selector );\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn (context || rootjQuery).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn jQuery( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( jQuery.isFunction( selector ) ) {\n\t\t\treturn rootjQuery.ready( selector );\n\t\t}\n\n\t\tif (selector.selector !== undefined) {\n\t\t\tthis.selector = selector.selector;\n\t\t\tthis.context = selector.context;\n\t\t}\n\n\t\treturn jQuery.isArray( selector ) ?\n\t\t\tthis.setArray( selector ) :\n\t\t\tjQuery.makeArray( selector, this );\n\t},\n\n\t// Start with an empty selector\n\tselector: \"\",\n\n\t// The current version of jQuery being used\n\tjquery: \"1.4.1\",\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\t// The number of elements contained in the matched element set\n\tsize: function() {\n\t\treturn this.length;\n\t},\n\n\ttoArray: function() {\n\t\treturn slice.call( this, 0 );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\t\treturn num == null ?\n\n\t\t\t// Return a 'clean' array\n\t\t\tthis.toArray() :\n\n\t\t\t// Return just the object\n\t\t\t( num < 0 ? this.slice(num)[ 0 ] : this[ num ] );\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems, name, selector ) {\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery( elems || null );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\tret.context = this.context;\n\n\t\tif ( name === \"find\" ) {\n\t\t\tret.selector = this.selector + (this.selector ? \" \" : \"\") + selector;\n\t\t} else if ( name ) {\n\t\t\tret.selector = this.selector + \".\" + name + \"(\" + selector + \")\";\n\t\t}\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Force the current matched set of elements to become\n\t// the specified array of elements (destroying the stack in the process)\n\t// You should use pushStack() in order to do this, but maintain the stack\n\tsetArray: function( elems ) {\n\t\t// Resetting the length to 0, then using the native Array push\n\t\t// is a super-fast way to populate an object with array-like properties\n\t\tthis.length = 0;\n\t\tpush.apply( this, elems );\n\n\t\treturn this;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\t// (You can seed the arguments with an array of args, but this is\n\t// only used internally.)\n\teach: function( callback, args ) {\n\t\treturn jQuery.each( this, callback, args );\n\t},\n\t\n\tready: function( fn ) {\n\t\t// Attach the listeners\n\t\tjQuery.bindReady();\n\n\t\t// If the DOM is already ready\n\t\tif ( jQuery.isReady ) {\n\t\t\t// Execute the function immediately\n\t\t\tfn.call( document, jQuery );\n\n\t\t// Otherwise, remember the function for later\n\t\t} else if ( readyList ) {\n\t\t\t// Add the function to the wait list\n\t\t\treadyList.push( fn );\n\t\t}\n\n\t\treturn this;\n\t},\n\t\n\teq: function( i ) {\n\t\treturn i === -1 ?\n\t\t\tthis.slice( i ) :\n\t\t\tthis.slice( i, +i + 1 );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ),\n\t\t\t\"slice\", slice.call(arguments).join(\",\") );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map(this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t}));\n\t},\n\t\n\tend: function() {\n\t\treturn this.prevObject || jQuery(null);\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: [].sort,\n\tsplice: [].splice\n};\n\n// Give the init function the jQuery prototype for later instantiation\njQuery.fn.init.prototype = jQuery.fn;\n\njQuery.extend = jQuery.fn.extend = function() {\n\t// copy reference to target object\n\tvar target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\t\ttarget = arguments[1] || {};\n\t\t// skip the boolean and the target\n\t\ti = 2;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !jQuery.isFunction(target) ) {\n\t\ttarget = {};\n\t}\n\n\t// extend jQuery itself if only one argument is passed\n\tif ( length === i ) {\n\t\ttarget = this;\n\t\t--i;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\t\t// Only deal with non-null/undefined values\n\t\tif ( (options = arguments[ i ]) != null ) {\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging object literal values or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) {\n\t\t\t\t\tvar clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src\n\t\t\t\t\t\t: jQuery.isArray(copy) ? [] : {};\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend({\n\tnoConflict: function( deep ) {\n\t\twindow.$ = _$;\n\n\t\tif ( deep ) {\n\t\t\twindow.jQuery = _jQuery;\n\t\t}\n\n\t\treturn jQuery;\n\t},\n\t\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\t\n\t// Handle when the DOM is ready\n\tready: function() {\n\t\t// Make sure that the DOM is not already loaded\n\t\tif ( !jQuery.isReady ) {\n\t\t\t// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n\t\t\tif ( !document.body ) {\n\t\t\t\treturn setTimeout( jQuery.ready, 13 );\n\t\t\t}\n\n\t\t\t// Remember that the DOM is ready\n\t\t\tjQuery.isReady = true;\n\n\t\t\t// If there are functions bound, to execute\n\t\t\tif ( readyList ) {\n\t\t\t\t// Execute all of them\n\t\t\t\tvar fn, i = 0;\n\t\t\t\twhile ( (fn = readyList[ i++ ]) ) {\n\t\t\t\t\tfn.call( document, jQuery );\n\t\t\t\t}\n\n\t\t\t\t// Reset the list of functions\n\t\t\t\treadyList = null;\n\t\t\t}\n\n\t\t\t// Trigger any bound ready events\n\t\t\tif ( jQuery.fn.triggerHandler ) {\n\t\t\t\tjQuery( document ).triggerHandler( \"ready\" );\n\t\t\t}\n\t\t}\n\t},\n\t\n\tbindReady: function() {\n\t\tif ( readyBound ) {\n\t\t\treturn;\n\t\t}\n\n\t\treadyBound = true;\n\n\t\t// Catch cases where $(document).ready() is called after the\n\t\t// browser event has already occurred.\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\treturn jQuery.ready();\n\t\t}\n\n\t\t// Mozilla, Opera and webkit nightlies currently support this event\n\t\tif ( document.addEventListener ) {\n\t\t\t// Use the handy event callback\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n\t\t\t\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.addEventListener( \"load\", jQuery.ready, false );\n\n\t\t// If IE event model is used\n\t\t} else if ( document.attachEvent ) {\n\t\t\t// ensure firing before onload,\n\t\t\t// maybe late but safe also for iframes\n\t\t\tdocument.attachEvent(\"onreadystatechange\", DOMContentLoaded);\n\t\t\t\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.attachEvent( \"onload\", jQuery.ready );\n\n\t\t\t// If IE and not a frame\n\t\t\t// continually check to see if the document is ready\n\t\t\tvar toplevel = false;\n\n\t\t\ttry {\n\t\t\t\ttoplevel = window.frameElement == null;\n\t\t\t} catch(e) {}\n\n\t\t\tif ( document.documentElement.doScroll && toplevel ) {\n\t\t\t\tdoScrollCheck();\n\t\t\t}\n\t\t}\n\t},\n\n\t// See test/unit/core.js for details concerning isFunction.\n\t// Since version 1.3, DOM methods and functions like alert\n\t// aren't supported. They return false on IE (#2968).\n\tisFunction: function( obj ) {\n\t\treturn toString.call(obj) === \"[object Function]\";\n\t},\n\n\tisArray: function( obj ) {\n\t\treturn toString.call(obj) === \"[object Array]\";\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\t// Must be an Object.\n\t\t// Because of IE, we also have to check the presence of the constructor property.\n\t\t// Make sure that DOM nodes and window objects don't pass through, as well\n\t\tif ( !obj || toString.call(obj) !== \"[object Object]\" || obj.nodeType || obj.setInterval ) {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\t// Not own constructor property must be Object\n\t\tif ( obj.constructor\n\t\t\t&& !hasOwnProperty.call(obj, \"constructor\")\n\t\t\t&& !hasOwnProperty.call(obj.constructor.prototype, \"isPrototypeOf\") ) {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\t// Own properties are enumerated firstly, so to speed up,\n\t\t// if last one is own, then all properties are own.\n\t\n\t\tvar key;\n\t\tfor ( key in obj ) {}\n\t\t\n\t\treturn key === undefined || hasOwnProperty.call( obj, key );\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tfor ( var name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\t\n\terror: function( msg ) {\n\t\tthrow msg;\n\t},\n\t\n\tparseJSON: function( data ) {\n\t\tif ( typeof data !== \"string\" || !data ) {\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\t// Make sure the incoming data is actual JSON\n\t\t// Logic borrowed from http://json.org/json2.js\n\t\tif ( /^[\\],:{}\\s]*$/.test(data.replace(/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g, \"@\")\n\t\t\t.replace(/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g, \"]\")\n\t\t\t.replace(/(?:^|:|,)(?:\\s*\\[)+/g, \"\")) ) {\n\n\t\t\t// Try to use the native JSON parser first\n\t\t\treturn window.JSON && window.JSON.parse ?\n\t\t\t\twindow.JSON.parse( data ) :\n\t\t\t\t(new Function(\"return \" + data))();\n\n\t\t} else {\n\t\t\tjQuery.error( \"Invalid JSON: \" + data );\n\t\t}\n\t},\n\n\tnoop: function() {},\n\n\t// Evalulates a script in a global context\n\tglobalEval: function( data ) {\n\t\tif ( data && rnotwhite.test(data) ) {\n\t\t\t// Inspired by code by Andrea Giammarchi\n\t\t\t// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html\n\t\t\tvar head = document.getElementsByTagName(\"head\")[0] || document.documentElement,\n\t\t\t\tscript = document.createElement(\"script\");\n\n\t\t\tscript.type = \"text/javascript\";\n\n\t\t\tif ( jQuery.support.scriptEval ) {\n\t\t\t\tscript.appendChild( document.createTextNode( data ) );\n\t\t\t} else {\n\t\t\t\tscript.text = data;\n\t\t\t}\n\n\t\t\t// Use insertBefore instead of appendChild to circumvent an IE6 bug.\n\t\t\t// This arises when a base node is used (#2709).\n\t\t\thead.insertBefore( script, head.firstChild );\n\t\t\thead.removeChild( script );\n\t\t}\n\t},\n\n\tnodeName: function( elem, name ) {\n\t\treturn elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();\n\t},\n\n\t// args is for internal usage only\n\teach: function( object, callback, args ) {\n\t\tvar name, i = 0,\n\t\t\tlength = object.length,\n\t\t\tisObj = length === undefined || jQuery.isFunction(object);\n\n\t\tif ( args ) {\n\t\t\tif ( isObj ) {\n\t\t\t\tfor ( name in object ) {\n\t\t\t\t\tif ( callback.apply( object[ name ], args ) === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( ; i < length; ) {\n\t\t\t\t\tif ( callback.apply( object[ i++ ], args ) === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// A special, fast, case for the most common use of each\n\t\t} else {\n\t\t\tif ( isObj ) {\n\t\t\t\tfor ( name in object ) {\n\t\t\t\t\tif ( callback.call( object[ name ], name, object[ name ] ) === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( var value = object[0];\n\t\t\t\t\ti < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}\n\t\t\t}\n\t\t}\n\n\t\treturn object;\n\t},\n\n\ttrim: function( text ) {\n\t\treturn (text || \"\").replace( rtrim, \"\" );\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( array, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( array != null ) {\n\t\t\t// The window, strings (and functions) also have 'length'\n\t\t\t// The extra typeof function check is to prevent crashes\n\t\t\t// in Safari 2 (See: #3039)\n\t\t\tif ( array.length == null || typeof array === \"string\" || jQuery.isFunction(array) || (typeof array !== \"function\" && array.setInterval) ) {\n\t\t\t\tpush.call( ret, array );\n\t\t\t} else {\n\t\t\t\tjQuery.merge( ret, array );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, array ) {\n\t\tif ( array.indexOf ) {\n\t\t\treturn array.indexOf( elem );\n\t\t}\n\n\t\tfor ( var i = 0, length = array.length; i < length; i++ ) {\n\t\t\tif ( array[ i ] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar i = first.length, j = 0;\n\n\t\tif ( typeof second.length === \"number\" ) {\n\t\t\tfor ( var l = second.length; j < l; j++ ) {\n\t\t\t\tfirst[ i++ ] = second[ j ];\n\t\t\t}\n\t\t} else {\n\t\t\twhile ( second[j] !== undefined ) {\n\t\t\t\tfirst[ i++ ] = second[ j++ ];\n\t\t\t}\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, inv ) {\n\t\tvar ret = [];\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( var i = 0, length = elems.length; i < length; i++ ) {\n\t\t\tif ( !inv !== !callback( elems[ i ], i ) ) {\n\t\t\t\tret.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar ret = [], value;\n\n\t\t// Go through the array, translating each of the items to their\n\t\t// new value (or values).\n\t\tfor ( var i = 0, length = elems.length; i < length; i++ ) {\n\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\tif ( value != null ) {\n\t\t\t\tret[ ret.length ] = value;\n\t\t\t}\n\t\t}\n\n\t\treturn ret.concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\tproxy: function( fn, proxy, thisObject ) {\n\t\tif ( arguments.length === 2 ) {\n\t\t\tif ( typeof proxy === \"string\" ) {\n\t\t\t\tthisObject = fn;\n\t\t\t\tfn = thisObject[ proxy ];\n\t\t\t\tproxy = undefined;\n\n\t\t\t} else if ( proxy && !jQuery.isFunction( proxy ) ) {\n\t\t\t\tthisObject = proxy;\n\t\t\t\tproxy = undefined;\n\t\t\t}\n\t\t}\n\n\t\tif ( !proxy && fn ) {\n\t\t\tproxy = function() {\n\t\t\t\treturn fn.apply( thisObject || this, arguments );\n\t\t\t};\n\t\t}\n\n\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\t\tif ( fn ) {\n\t\t\tproxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;\n\t\t}\n\n\t\t// So proxy can be declared as an argument\n\t\treturn proxy;\n\t},\n\n\t// Use of jQuery.browser is frowned upon.\n\t// More details: http://docs.jquery.com/Utilities/jQuery.browser\n\tuaMatch: function( ua ) {\n\t\tua = ua.toLowerCase();\n\n\t\tvar match = /(webkit)[ \\/]([\\w.]+)/.exec( ua ) ||\n\t\t\t/(opera)(?:.*version)?[ \\/]([\\w.]+)/.exec( ua ) ||\n\t\t\t/(msie) ([\\w.]+)/.exec( ua ) ||\n\t\t\t!/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\\w.]+))?/.exec( ua ) ||\n\t\t  \t[];\n\n\t\treturn { browser: match[1] || \"\", version: match[2] || \"0\" };\n\t},\n\n\tbrowser: {}\n});\n\nbrowserMatch = jQuery.uaMatch( userAgent );\nif ( browserMatch.browser ) {\n\tjQuery.browser[ browserMatch.browser ] = true;\n\tjQuery.browser.version = browserMatch.version;\n}\n\n// Deprecated, use jQuery.browser.webkit instead\nif ( jQuery.browser.webkit ) {\n\tjQuery.browser.safari = true;\n}\n\nif ( indexOf ) {\n\tjQuery.inArray = function( elem, array ) {\n\t\treturn indexOf.call( array, elem );\n\t};\n}\n\n// All jQuery objects should point back to these\nrootjQuery = jQuery(document);\n\n// Cleanup functions for the document ready method\nif ( document.addEventListener ) {\n\tDOMContentLoaded = function() {\n\t\tdocument.removeEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n\t\tjQuery.ready();\n\t};\n\n} else if ( document.attachEvent ) {\n\tDOMContentLoaded = function() {\n\t\t// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\tdocument.detachEvent( \"onreadystatechange\", DOMContentLoaded );\n\t\t\tjQuery.ready();\n\t\t}\n\t};\n}\n\n// The DOM ready check for Internet Explorer\nfunction doScrollCheck() {\n\tif ( jQuery.isReady ) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\t// If IE is used, use the trick by Diego Perini\n\t\t// http://javascript.nwbox.com/IEContentLoaded/\n\t\tdocument.documentElement.doScroll(\"left\");\n\t} catch( error ) {\n\t\tsetTimeout( doScrollCheck, 1 );\n\t\treturn;\n\t}\n\n\t// and execute any waiting functions\n\tjQuery.ready();\n}\n\nfunction evalScript( i, elem ) {\n\tif ( elem.src ) {\n\t\tjQuery.ajax({\n\t\t\turl: elem.src,\n\t\t\tasync: false,\n\t\t\tdataType: \"script\"\n\t\t});\n\t} else {\n\t\tjQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || \"\" );\n\t}\n\n\tif ( elem.parentNode ) {\n\t\telem.parentNode.removeChild( elem );\n\t}\n}\n\n// Mutifunctional method to get and set values to a collection\n// The value/s can be optionally by executed if its a function\nfunction access( elems, key, value, exec, fn, pass ) {\n\tvar length = elems.length;\n\t\n\t// Setting many attributes\n\tif ( typeof key === \"object\" ) {\n\t\tfor ( var k in key ) {\n\t\t\taccess( elems, k, key[k], exec, fn, value );\n\t\t}\n\t\treturn elems;\n\t}\n\t\n\t// Setting one attribute\n\tif ( value !== undefined ) {\n\t\t// Optionally, function values get executed if exec is true\n\t\texec = !pass && exec && jQuery.isFunction(value);\n\t\t\n\t\tfor ( var i = 0; i < length; i++ ) {\n\t\t\tfn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );\n\t\t}\n\t\t\n\t\treturn elems;\n\t}\n\t\n\t// Getting an attribute\n\treturn length ? fn( elems[0], key ) : null;\n}\n\nfunction now() {\n\treturn (new Date).getTime();\n}\n(function() {\n\n\tjQuery.support = {};\n\n\tvar root = document.documentElement,\n\t\tscript = document.createElement(\"script\"),\n\t\tdiv = document.createElement(\"div\"),\n\t\tid = \"script\" + now();\n\n\tdiv.style.display = \"none\";\n\tdiv.innerHTML = \"   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>\";\n\n\tvar all = div.getElementsByTagName(\"*\"),\n\t\ta = div.getElementsByTagName(\"a\")[0];\n\n\t// Can't get basic test support\n\tif ( !all || !all.length || !a ) {\n\t\treturn;\n\t}\n\n\tjQuery.support = {\n\t\t// IE strips leading whitespace when .innerHTML is used\n\t\tleadingWhitespace: div.firstChild.nodeType === 3,\n\n\t\t// Make sure that tbody elements aren't automatically inserted\n\t\t// IE will insert them into empty tables\n\t\ttbody: !div.getElementsByTagName(\"tbody\").length,\n\n\t\t// Make sure that link elements get serialized correctly by innerHTML\n\t\t// This requires a wrapper element in IE\n\t\thtmlSerialize: !!div.getElementsByTagName(\"link\").length,\n\n\t\t// Get the style information from getAttribute\n\t\t// (IE uses .cssText insted)\n\t\tstyle: /red/.test( a.getAttribute(\"style\") ),\n\n\t\t// Make sure that URLs aren't manipulated\n\t\t// (IE normalizes it by default)\n\t\threfNormalized: a.getAttribute(\"href\") === \"/a\",\n\n\t\t// Make sure that element opacity exists\n\t\t// (IE uses filter instead)\n\t\t// Use a regex to work around a WebKit issue. See #5145\n\t\topacity: /^0.55$/.test( a.style.opacity ),\n\n\t\t// Verify style float existence\n\t\t// (IE uses styleFloat instead of cssFloat)\n\t\tcssFloat: !!a.style.cssFloat,\n\n\t\t// Make sure that if no value is specified for a checkbox\n\t\t// that it defaults to \"on\".\n\t\t// (WebKit defaults to \"\" instead)\n\t\tcheckOn: div.getElementsByTagName(\"input\")[0].value === \"on\",\n\n\t\t// Make sure that a selected-by-default option has a working selected property.\n\t\t// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)\n\t\toptSelected: document.createElement(\"select\").appendChild( document.createElement(\"option\") ).selected,\n\n\t\t// Will be defined later\n\t\tcheckClone: false,\n\t\tscriptEval: false,\n\t\tnoCloneEvent: true,\n\t\tboxModel: null\n\t};\n\n\tscript.type = \"text/javascript\";\n\ttry {\n\t\tscript.appendChild( document.createTextNode( \"window.\" + id + \"=1;\" ) );\n\t} catch(e) {}\n\n\troot.insertBefore( script, root.firstChild );\n\n\t// Make sure that the execution of code works by injecting a script\n\t// tag with appendChild/createTextNode\n\t// (IE doesn't support this, fails, and uses .text instead)\n\tif ( window[ id ] ) {\n\t\tjQuery.support.scriptEval = true;\n\t\tdelete window[ id ];\n\t}\n\n\troot.removeChild( script );\n\n\tif ( div.attachEvent && div.fireEvent ) {\n\t\tdiv.attachEvent(\"onclick\", function click() {\n\t\t\t// Cloning a node shouldn't copy over any\n\t\t\t// bound event handlers (IE does this)\n\t\t\tjQuery.support.noCloneEvent = false;\n\t\t\tdiv.detachEvent(\"onclick\", click);\n\t\t});\n\t\tdiv.cloneNode(true).fireEvent(\"onclick\");\n\t}\n\n\tdiv = document.createElement(\"div\");\n\tdiv.innerHTML = \"<input type='radio' name='radiotest' checked='checked'/>\";\n\n\tvar fragment = document.createDocumentFragment();\n\tfragment.appendChild( div.firstChild );\n\n\t// WebKit doesn't clone checked state correctly in fragments\n\tjQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;\n\n\t// Figure out if the W3C box model works as expected\n\t// document.body must exist before we can do this\n\tjQuery(function() {\n\t\tvar div = document.createElement(\"div\");\n\t\tdiv.style.width = div.style.paddingLeft = \"1px\";\n\n\t\tdocument.body.appendChild( div );\n\t\tjQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;\n\t\tdocument.body.removeChild( div ).style.display = 'none';\n\t\tdiv = null;\n\t});\n\n\t// Technique from Juriy Zaytsev\n\t// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/\n\tvar eventSupported = function( eventName ) { \n\t\tvar el = document.createElement(\"div\"); \n\t\teventName = \"on\" + eventName; \n\n\t\tvar isSupported = (eventName in el); \n\t\tif ( !isSupported ) { \n\t\t\tel.setAttribute(eventName, \"return;\"); \n\t\t\tisSupported = typeof el[eventName] === \"function\"; \n\t\t} \n\t\tel = null; \n\n\t\treturn isSupported; \n\t};\n\t\n\tjQuery.support.submitBubbles = eventSupported(\"submit\");\n\tjQuery.support.changeBubbles = eventSupported(\"change\");\n\n\t// release memory in IE\n\troot = script = div = all = a = null;\n})();\n\njQuery.props = {\n\t\"for\": \"htmlFor\",\n\t\"class\": \"className\",\n\treadonly: \"readOnly\",\n\tmaxlength: \"maxLength\",\n\tcellspacing: \"cellSpacing\",\n\trowspan: \"rowSpan\",\n\tcolspan: \"colSpan\",\n\ttabindex: \"tabIndex\",\n\tusemap: \"useMap\",\n\tframeborder: \"frameBorder\"\n};\nvar expando = \"jQuery\" + now(), uuid = 0, windowData = {};\nvar emptyObject = {};\n\njQuery.extend({\n\tcache: {},\n\t\n\texpando:expando,\n\n\t// The following elements throw uncatchable exceptions if you\n\t// attempt to add expando properties to them.\n\tnoData: {\n\t\t\"embed\": true,\n\t\t\"object\": true,\n\t\t\"applet\": true\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\tif ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {\n\t\t\treturn;\n\t\t}\n\n\t\telem = elem == window ?\n\t\t\twindowData :\n\t\t\telem;\n\n\t\tvar id = elem[ expando ], cache = jQuery.cache, thisCache;\n\n\t\t// Handle the case where there's no name immediately\n\t\tif ( !name && !id ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Compute a unique ID for the element\n\t\tif ( !id ) { \n\t\t\tid = ++uuid;\n\t\t}\n\n\t\t// Avoid generating a new cache unless none exists and we\n\t\t// want to manipulate it.\n\t\tif ( typeof name === \"object\" ) {\n\t\t\telem[ expando ] = id;\n\t\t\tthisCache = cache[ id ] = jQuery.extend(true, {}, name);\n\t\t} else if ( cache[ id ] ) {\n\t\t\tthisCache = cache[ id ];\n\t\t} else if ( typeof data === \"undefined\" ) {\n\t\t\tthisCache = emptyObject;\n\t\t} else {\n\t\t\tthisCache = cache[ id ] = {};\n\t\t}\n\n\t\t// Prevent overriding the named cache with undefined values\n\t\tif ( data !== undefined ) {\n\t\t\telem[ expando ] = id;\n\t\t\tthisCache[ name ] = data;\n\t\t}\n\n\t\treturn typeof name === \"string\" ? thisCache[ name ] : thisCache;\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tif ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {\n\t\t\treturn;\n\t\t}\n\n\t\telem = elem == window ?\n\t\t\twindowData :\n\t\t\telem;\n\n\t\tvar id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];\n\n\t\t// If we want to remove a specific section of the element's data\n\t\tif ( name ) {\n\t\t\tif ( thisCache ) {\n\t\t\t\t// Remove the section of cache data\n\t\t\t\tdelete thisCache[ name ];\n\n\t\t\t\t// If we've removed all the data, remove the element's cache\n\t\t\t\tif ( jQuery.isEmptyObject(thisCache) ) {\n\t\t\t\t\tjQuery.removeData( elem );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Otherwise, we want to remove all of the element's data\n\t\t} else {\n\t\t\t// Clean up the element expando\n\t\t\ttry {\n\t\t\t\tdelete elem[ expando ];\n\t\t\t} catch( e ) {\n\t\t\t\t// IE has trouble directly removing the expando\n\t\t\t\t// but it's ok with using removeAttribute\n\t\t\t\tif ( elem.removeAttribute ) {\n\t\t\t\t\telem.removeAttribute( expando );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Completely remove the data cache\n\t\t\tdelete cache[ id ];\n\t\t}\n\t}\n});\n\njQuery.fn.extend({\n\tdata: function( key, value ) {\n\t\tif ( typeof key === \"undefined\" && this.length ) {\n\t\t\treturn jQuery.data( this[0] );\n\n\t\t} else if ( typeof key === \"object\" ) {\n\t\t\treturn this.each(function() {\n\t\t\t\tjQuery.data( this, key );\n\t\t\t});\n\t\t}\n\n\t\tvar parts = key.split(\".\");\n\t\tparts[1] = parts[1] ? \".\" + parts[1] : \"\";\n\n\t\tif ( value === undefined ) {\n\t\t\tvar data = this.triggerHandler(\"getData\" + parts[1] + \"!\", [parts[0]]);\n\n\t\t\tif ( data === undefined && this.length ) {\n\t\t\t\tdata = jQuery.data( this[0], key );\n\t\t\t}\n\t\t\treturn data === undefined && parts[1] ?\n\t\t\t\tthis.data( parts[0] ) :\n\t\t\t\tdata;\n\t\t} else {\n\t\t\treturn this.trigger(\"setData\" + parts[1] + \"!\", [parts[0], value]).each(function() {\n\t\t\t\tjQuery.data( this, key, value );\n\t\t\t});\n\t\t}\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeData( this, key );\n\t\t});\n\t}\n});\njQuery.extend({\n\tqueue: function( elem, type, data ) {\n\t\tif ( !elem ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttype = (type || \"fx\") + \"queue\";\n\t\tvar q = jQuery.data( elem, type );\n\n\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\tif ( !data ) {\n\t\t\treturn q || [];\n\t\t}\n\n\t\tif ( !q || jQuery.isArray(data) ) {\n\t\t\tq = jQuery.data( elem, type, jQuery.makeArray(data) );\n\n\t\t} else {\n\t\t\tq.push( data );\n\t\t}\n\n\t\treturn q;\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ), fn = queue.shift();\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift(\"inprogress\");\n\t\t\t}\n\n\t\t\tfn.call(elem, function() {\n\t\t\t\tjQuery.dequeue(elem, type);\n\t\t\t});\n\t\t}\n\t}\n});\n\njQuery.fn.extend({\n\tqueue: function( type, data ) {\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t}\n\n\t\tif ( data === undefined ) {\n\t\t\treturn jQuery.queue( this[0], type );\n\t\t}\n\t\treturn this.each(function( i, elem ) {\n\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\tif ( type === \"fx\" && queue[0] !== \"inprogress\" ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t});\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t});\n\t},\n\n\t// Based off of the plugin by Clint Helfers, with permission.\n\t// http://blindsignals.com/index.php/2009/07/jquery-delay/\n\tdelay: function( time, type ) {\n\t\ttime = jQuery.fx ? jQuery.fx.speeds[time] || time : time;\n\t\ttype = type || \"fx\";\n\n\t\treturn this.queue( type, function() {\n\t\t\tvar elem = this;\n\t\t\tsetTimeout(function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t}, time );\n\t\t});\n\t},\n\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t}\n});\nvar rclass = /[\\n\\t]/g,\n\trspace = /\\s+/,\n\trreturn = /\\r/g,\n\trspecialurl = /href|src|style/,\n\trtype = /(button|input)/i,\n\trfocusable = /(button|input|object|select|textarea)/i,\n\trclickable = /^(a|area)$/i,\n\trradiocheck = /radio|checkbox/;\n\njQuery.fn.extend({\n\tattr: function( name, value ) {\n\t\treturn access( this, name, value, true, jQuery.attr );\n\t},\n\n\tremoveAttr: function( name, fn ) {\n\t\treturn this.each(function(){\n\t\t\tjQuery.attr( this, name, \"\" );\n\t\t\tif ( this.nodeType === 1 ) {\n\t\t\t\tthis.removeAttribute( name );\n\t\t\t}\n\t\t});\n\t},\n\n\taddClass: function( value ) {\n\t\tif ( jQuery.isFunction(value) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tvar self = jQuery(this);\n\t\t\t\tself.addClass( value.call(this, i, self.attr(\"class\")) );\n\t\t\t});\n\t\t}\n\n\t\tif ( value && typeof value === \"string\" ) {\n\t\t\tvar classNames = (value || \"\").split( rspace );\n\n\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\tvar elem = this[i];\n\n\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\tif ( !elem.className ) {\n\t\t\t\t\t\telem.className = value;\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar className = \" \" + elem.className + \" \";\n\t\t\t\t\t\tfor ( var c = 0, cl = classNames.length; c < cl; c++ ) {\n\t\t\t\t\t\t\tif ( className.indexOf( \" \" + classNames[c] + \" \" ) < 0 ) {\n\t\t\t\t\t\t\t\telem.className += \" \" + classNames[c];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tif ( jQuery.isFunction(value) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tvar self = jQuery(this);\n\t\t\t\tself.removeClass( value.call(this, i, self.attr(\"class\")) );\n\t\t\t});\n\t\t}\n\n\t\tif ( (value && typeof value === \"string\") || value === undefined ) {\n\t\t\tvar classNames = (value || \"\").split(rspace);\n\n\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\tvar elem = this[i];\n\n\t\t\t\tif ( elem.nodeType === 1 && elem.className ) {\n\t\t\t\t\tif ( value ) {\n\t\t\t\t\t\tvar className = (\" \" + elem.className + \" \").replace(rclass, \" \");\n\t\t\t\t\t\tfor ( var c = 0, cl = classNames.length; c < cl; c++ ) {\n\t\t\t\t\t\t\tclassName = className.replace(\" \" + classNames[c] + \" \", \" \");\n\t\t\t\t\t\t}\n\t\t\t\t\t\telem.className = className.substring(1, className.length - 1);\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\telem.className = \"\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value, isBool = typeof stateVal === \"boolean\";\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tvar self = jQuery(this);\n\t\t\t\tself.toggleClass( value.call(this, i, self.attr(\"class\"), stateVal), stateVal );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( type === \"string\" ) {\n\t\t\t\t// toggle individual class names\n\t\t\t\tvar className, i = 0, self = jQuery(this),\n\t\t\t\t\tstate = stateVal,\n\t\t\t\t\tclassNames = value.split( rspace );\n\n\t\t\t\twhile ( (className = classNames[ i++ ]) ) {\n\t\t\t\t\t// check each className given, space seperated list\n\t\t\t\t\tstate = isBool ? state : !self.hasClass( className );\n\t\t\t\t\tself[ state ? \"addClass\" : \"removeClass\" ]( className );\n\t\t\t\t}\n\n\t\t\t} else if ( type === \"undefined\" || type === \"boolean\" ) {\n\t\t\t\tif ( this.className ) {\n\t\t\t\t\t// store className if set\n\t\t\t\t\tjQuery.data( this, \"__className__\", this.className );\n\t\t\t\t}\n\n\t\t\t\t// toggle whole className\n\t\t\t\tthis.className = this.className || value === false ? \"\" : jQuery.data( this, \"__className__\" ) || \"\";\n\t\t\t}\n\t\t});\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className = \" \" + selector + \" \";\n\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\tif ( (\" \" + this[i].className + \" \").replace(rclass, \" \").indexOf( className ) > -1 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t},\n\n\tval: function( value ) {\n\t\tif ( value === undefined ) {\n\t\t\tvar elem = this[0];\n\n\t\t\tif ( elem ) {\n\t\t\t\tif ( jQuery.nodeName( elem, \"option\" ) ) {\n\t\t\t\t\treturn (elem.attributes.value || {}).specified ? elem.value : elem.text;\n\t\t\t\t}\n\n\t\t\t\t// We need to handle select boxes special\n\t\t\t\tif ( jQuery.nodeName( elem, \"select\" ) ) {\n\t\t\t\t\tvar index = elem.selectedIndex,\n\t\t\t\t\t\tvalues = [],\n\t\t\t\t\t\toptions = elem.options,\n\t\t\t\t\t\tone = elem.type === \"select-one\";\n\n\t\t\t\t\t// Nothing was selected\n\t\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Loop through all the selected options\n\t\t\t\t\tfor ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {\n\t\t\t\t\t\tvar option = options[ i ];\n\n\t\t\t\t\t\tif ( option.selected ) {\n\t\t\t\t\t\t\t// Get the specifc value for the option\n\t\t\t\t\t\t\tvalue = jQuery(option).val();\n\n\t\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn values;\n\t\t\t\t}\n\n\t\t\t\t// Handle the case where in Webkit \"\" is returned instead of \"on\" if a value isn't specified\n\t\t\t\tif ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {\n\t\t\t\t\treturn elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n\t\t\t\t}\n\t\t\t\t\n\n\t\t\t\t// Everything else, we just grab the value\n\t\t\t\treturn (elem.value || \"\").replace(rreturn, \"\");\n\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t}\n\n\t\tvar isFunction = jQuery.isFunction(value);\n\n\t\treturn this.each(function(i) {\n\t\t\tvar self = jQuery(this), val = value;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = value.call(this, i, self.val());\n\t\t\t}\n\n\t\t\t// Typecast each time if the value is a Function and the appended\n\t\t\t// value is therefore different each time.\n\t\t\tif ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\t\t\t}\n\n\t\t\tif ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {\n\t\t\t\tthis.checked = jQuery.inArray( self.val(), val ) >= 0;\n\n\t\t\t} else if ( jQuery.nodeName( this, \"select\" ) ) {\n\t\t\t\tvar values = jQuery.makeArray(val);\n\n\t\t\t\tjQuery( \"option\", this ).each(function() {\n\t\t\t\t\tthis.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;\n\t\t\t\t});\n\n\t\t\t\tif ( !values.length ) {\n\t\t\t\t\tthis.selectedIndex = -1;\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tattrFn: {\n\t\tval: true,\n\t\tcss: true,\n\t\thtml: true,\n\t\ttext: true,\n\t\tdata: true,\n\t\twidth: true,\n\t\theight: true,\n\t\toffset: true\n\t},\n\t\t\n\tattr: function( elem, name, value, pass ) {\n\t\t// don't set attributes on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif ( pass && name in jQuery.attrFn ) {\n\t\t\treturn jQuery(elem)[name](value);\n\t\t}\n\n\t\tvar notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),\n\t\t\t// Whether we are setting (or getting)\n\t\t\tset = value !== undefined;\n\n\t\t// Try to normalize/fix the name\n\t\tname = notxml && jQuery.props[ name ] || name;\n\n\t\t// Only do all the following if this is a node (faster for style)\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\t// These attributes require special treatment\n\t\t\tvar special = rspecialurl.test( name );\n\n\t\t\t// Safari mis-reports the default selected property of an option\n\t\t\t// Accessing the parent's selectedIndex property fixes it\n\t\t\tif ( name === \"selected\" && !jQuery.support.optSelected ) {\n\t\t\t\tvar parent = elem.parentNode;\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.selectedIndex;\n\t\n\t\t\t\t\t// Make sure that it also works with optgroups, see #5701\n\t\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If applicable, access the attribute via the DOM 0 way\n\t\t\tif ( name in elem && notxml && !special ) {\n\t\t\t\tif ( set ) {\n\t\t\t\t\t// We can't allow the type property to be changed (since it causes problems in IE)\n\t\t\t\t\tif ( name === \"type\" && rtype.test( elem.nodeName ) && elem.parentNode ) {\n\t\t\t\t\t\tjQuery.error( \"type property can't be changed\" );\n\t\t\t\t\t}\n\n\t\t\t\t\telem[ name ] = value;\n\t\t\t\t}\n\n\t\t\t\t// browsers index elements by id/name on forms, give priority to attributes.\n\t\t\t\tif ( jQuery.nodeName( elem, \"form\" ) && elem.getAttributeNode(name) ) {\n\t\t\t\t\treturn elem.getAttributeNode( name ).nodeValue;\n\t\t\t\t}\n\n\t\t\t\t// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set\n\t\t\t\t// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\tif ( name === \"tabIndex\" ) {\n\t\t\t\t\tvar attributeNode = elem.getAttributeNode( \"tabIndex\" );\n\n\t\t\t\t\treturn attributeNode && attributeNode.specified ?\n\t\t\t\t\t\tattributeNode.value :\n\t\t\t\t\t\trfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?\n\t\t\t\t\t\t\t0 :\n\t\t\t\t\t\t\tundefined;\n\t\t\t\t}\n\n\t\t\t\treturn elem[ name ];\n\t\t\t}\n\n\t\t\tif ( !jQuery.support.style && notxml && name === \"style\" ) {\n\t\t\t\tif ( set ) {\n\t\t\t\t\telem.style.cssText = \"\" + value;\n\t\t\t\t}\n\n\t\t\t\treturn elem.style.cssText;\n\t\t\t}\n\n\t\t\tif ( set ) {\n\t\t\t\t// convert the value to a string (all browsers do this but IE) see #1070\n\t\t\t\telem.setAttribute( name, \"\" + value );\n\t\t\t}\n\n\t\t\tvar attr = !jQuery.support.hrefNormalized && notxml && special ?\n\t\t\t\t\t// Some attributes require a special call on IE\n\t\t\t\t\telem.getAttribute( name, 2 ) :\n\t\t\t\t\telem.getAttribute( name );\n\n\t\t\t// Non-existent attributes return null, we normalize to undefined\n\t\t\treturn attr === null ? undefined : attr;\n\t\t}\n\n\t\t// elem is actually elem.style ... set the style\n\t\t// Using attr for specific style information is now deprecated. Use style insead.\n\t\treturn jQuery.style( elem, name, value );\n\t}\n});\nvar fcleanup = function( nm ) {\n\treturn nm.replace(/[^\\w\\s\\.\\|`]/g, function( ch ) {\n\t\treturn \"\\\\\" + ch;\n\t});\n};\n\n/*\n * A number of helper functions used for managing events.\n * Many of the ideas behind this code originated from\n * Dean Edwards' addEvent library.\n */\njQuery.event = {\n\n\t// Bind an event to an element\n\t// Original by Dean Edwards\n\tadd: function( elem, types, handler, data ) {\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// For whatever reason, IE has trouble passing the window object\n\t\t// around, causing it to be cloned in the process\n\t\tif ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {\n\t\t\telem = window;\n\t\t}\n\n\t\t// Make sure that the function being executed has a unique ID\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// if data is passed, bind to handler\n\t\tif ( data !== undefined ) {\n\t\t\t// Create temporary function pointer to original handler\n\t\t\tvar fn = handler;\n\n\t\t\t// Create unique handler function, wrapped around original handler\n\t\t\thandler = jQuery.proxy( fn );\n\n\t\t\t// Store data in unique handler\n\t\t\thandler.data = data;\n\t\t}\n\n\t\t// Init the element's event structure\n\t\tvar events = jQuery.data( elem, \"events\" ) || jQuery.data( elem, \"events\", {} ),\n\t\t\thandle = jQuery.data( elem, \"handle\" ), eventHandle;\n\n\t\tif ( !handle ) {\n\t\t\teventHandle = function() {\n\t\t\t\t// Handle the second event of a trigger and when\n\t\t\t\t// an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && !jQuery.event.triggered ?\n\t\t\t\t\tjQuery.event.handle.apply( eventHandle.elem, arguments ) :\n\t\t\t\t\tundefined;\n\t\t\t};\n\n\t\t\thandle = jQuery.data( elem, \"handle\", eventHandle );\n\t\t}\n\n\t\t// If no handle is found then we must be trying to bind to one of the\n\t\t// banned noData elements\n\t\tif ( !handle ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Add elem as a property of the handle function\n\t\t// This is to prevent a memory leak with non-native\n\t\t// event in IE.\n\t\thandle.elem = elem;\n\n\t\t// Handle multiple events separated by a space\n\t\t// jQuery(...).bind(\"mouseover mouseout\", fn);\n\t\ttypes = types.split( /\\s+/ );\n\n\t\tvar type, i = 0;\n\n\t\twhile ( (type = types[ i++ ]) ) {\n\t\t\t// Namespaced event handlers\n\t\t\tvar namespaces = type.split(\".\");\n\t\t\ttype = namespaces.shift();\n\n\t\t\tif ( i > 1 ) {\n\t\t\t\thandler = jQuery.proxy( handler );\n\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\thandler.data = data;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\thandler.type = namespaces.slice(0).sort().join(\".\");\n\n\t\t\t// Get the current list of functions bound to this event\n\t\t\tvar handlers = events[ type ],\n\t\t\t\tspecial = this.special[ type ] || {};\n\n\t\t\t// Init the event handler queue\n\t\t\tif ( !handlers ) {\n\t\t\t\thandlers = events[ type ] = {};\n\n\t\t\t\t// Check for a special event handler\n\t\t\t\t// Only use addEventListener/attachEvent if the special\n\t\t\t\t// events handler returns false\n\t\t\t\tif ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) {\n\t\t\t\t\t// Bind the global event handler to the element\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, handle, false );\n\t\t\t\t\t} else if ( elem.attachEvent ) {\n\t\t\t\t\t\telem.attachEvent( \"on\" + type, handle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif ( special.add ) { \n\t\t\t\tvar modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers ); \n\t\t\t\tif ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) { \n\t\t\t\t\tmodifiedHandler.guid = modifiedHandler.guid || handler.guid; \n\t\t\t\t\tmodifiedHandler.data = modifiedHandler.data || handler.data; \n\t\t\t\t\tmodifiedHandler.type = modifiedHandler.type || handler.type; \n\t\t\t\t\thandler = modifiedHandler; \n\t\t\t\t} \n\t\t\t} \n\t\t\t\n\t\t\t// Add the function to the element's handler list\n\t\t\thandlers[ handler.guid ] = handler;\n\n\t\t\t// Keep track of which events have been used, for global triggering\n\t\t\tthis.global[ type ] = true;\n\t\t}\n\n\t\t// Nullify elem to prevent memory leaks in IE\n\t\telem = null;\n\t},\n\n\tglobal: {},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler ) {\n\t\t// don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar events = jQuery.data( elem, \"events\" ), ret, type, fn;\n\n\t\tif ( events ) {\n\t\t\t// Unbind all events for the element\n\t\t\tif ( types === undefined || (typeof types === \"string\" && types.charAt(0) === \".\") ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tthis.remove( elem, type + (types || \"\") );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// types is actually an event object here\n\t\t\t\tif ( types.type ) {\n\t\t\t\t\thandler = types.handler;\n\t\t\t\t\ttypes = types.type;\n\t\t\t\t}\n\n\t\t\t\t// Handle multiple events separated by a space\n\t\t\t\t// jQuery(...).unbind(\"mouseover mouseout\", fn);\n\t\t\t\ttypes = types.split(/\\s+/);\n\t\t\t\tvar i = 0;\n\t\t\t\twhile ( (type = types[ i++ ]) ) {\n\t\t\t\t\t// Namespaced event handlers\n\t\t\t\t\tvar namespaces = type.split(\".\");\n\t\t\t\t\ttype = namespaces.shift();\n\t\t\t\t\tvar all = !namespaces.length,\n\t\t\t\t\t\tcleaned = jQuery.map( namespaces.slice(0).sort(), fcleanup ),\n\t\t\t\t\t\tnamespace = new RegExp(\"(^|\\\\.)\" + cleaned.join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\"),\n\t\t\t\t\t\tspecial = this.special[ type ] || {};\n\n\t\t\t\t\tif ( events[ type ] ) {\n\t\t\t\t\t\t// remove the given handler for the given type\n\t\t\t\t\t\tif ( handler ) {\n\t\t\t\t\t\t\tfn = events[ type ][ handler.guid ];\n\t\t\t\t\t\t\tdelete events[ type ][ handler.guid ];\n\n\t\t\t\t\t\t// remove all handlers for the given type\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfor ( var handle in events[ type ] ) {\n\t\t\t\t\t\t\t\t// Handle the removal of namespaced events\n\t\t\t\t\t\t\t\tif ( all || namespace.test( events[ type ][ handle ].type ) ) {\n\t\t\t\t\t\t\t\t\tdelete events[ type ][ handle ];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\t\tspecial.remove.call( elem, namespaces, fn);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// remove generic event handler if no more handlers exist\n\t\t\t\t\t\tfor ( ret in events[ type ] ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( !ret ) {\n\t\t\t\t\t\t\tif ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {\n\t\t\t\t\t\t\t\tif ( elem.removeEventListener ) {\n\t\t\t\t\t\t\t\t\telem.removeEventListener( type, jQuery.data( elem, \"handle\" ), false );\n\t\t\t\t\t\t\t\t} else if ( elem.detachEvent ) {\n\t\t\t\t\t\t\t\t\telem.detachEvent( \"on\" + type, jQuery.data( elem, \"handle\" ) );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tret = null;\n\t\t\t\t\t\t\tdelete events[ type ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove the expando if it's no longer used\n\t\t\tfor ( ret in events ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !ret ) {\n\t\t\t\tvar handle = jQuery.data( elem, \"handle\" );\n\t\t\t\tif ( handle ) {\n\t\t\t\t\thandle.elem = null;\n\t\t\t\t}\n\t\t\t\tjQuery.removeData( elem, \"events\" );\n\t\t\t\tjQuery.removeData( elem, \"handle\" );\n\t\t\t}\n\t\t}\n\t},\n\n\t// bubbling is internal\n\ttrigger: function( event, data, elem /*, bubbling */ ) {\n\t\t// Event object or event type\n\t\tvar type = event.type || event,\n\t\t\tbubbling = arguments[3];\n\n\t\tif ( !bubbling ) {\n\t\t\tevent = typeof event === \"object\" ?\n\t\t\t\t// jQuery.Event object\n\t\t\t\tevent[expando] ? event :\n\t\t\t\t// Object literal\n\t\t\t\tjQuery.extend( jQuery.Event(type), event ) :\n\t\t\t\t// Just the event type (string)\n\t\t\t\tjQuery.Event(type);\n\n\t\t\tif ( type.indexOf(\"!\") >= 0 ) {\n\t\t\t\tevent.type = type = type.slice(0, -1);\n\t\t\t\tevent.exclusive = true;\n\t\t\t}\n\n\t\t\t// Handle a global trigger\n\t\t\tif ( !elem ) {\n\t\t\t\t// Don't bubble custom events when global (to avoid too much overhead)\n\t\t\t\tevent.stopPropagation();\n\n\t\t\t\t// Only trigger if we've ever bound an event for it\n\t\t\t\tif ( this.global[ type ] ) {\n\t\t\t\t\tjQuery.each( jQuery.cache, function() {\n\t\t\t\t\t\tif ( this.events && this.events[type] ) {\n\t\t\t\t\t\t\tjQuery.event.trigger( event, data, this.handle.elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle triggering a single element\n\n\t\t\t// don't do events on text and comment nodes\n\t\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\t// Clean up in case it is reused\n\t\t\tevent.result = undefined;\n\t\t\tevent.target = elem;\n\n\t\t\t// Clone the incoming data, if any\n\t\t\tdata = jQuery.makeArray( data );\n\t\t\tdata.unshift( event );\n\t\t}\n\n\t\tevent.currentTarget = elem;\n\n\t\t// Trigger the event, it is assumed that \"handle\" is a function\n\t\tvar handle = jQuery.data( elem, \"handle\" );\n\t\tif ( handle ) {\n\t\t\thandle.apply( elem, data );\n\t\t}\n\n\t\tvar parent = elem.parentNode || elem.ownerDocument;\n\n\t\t// Trigger an inline bound script\n\t\ttry {\n\t\t\tif ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {\n\t\t\t\tif ( elem[ \"on\" + type ] && elem[ \"on\" + type ].apply( elem, data ) === false ) {\n\t\t\t\t\tevent.result = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t// prevent IE from throwing an error for some elements with some event types, see #3533\n\t\t} catch (e) {}\n\n\t\tif ( !event.isPropagationStopped() && parent ) {\n\t\t\tjQuery.event.trigger( event, data, parent, true );\n\n\t\t} else if ( !event.isDefaultPrevented() ) {\n\t\t\tvar target = event.target, old,\n\t\t\t\tisClick = jQuery.nodeName(target, \"a\") && type === \"click\";\n\n\t\t\tif ( !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {\n\t\t\t\ttry {\n\t\t\t\t\tif ( target[ type ] ) {\n\t\t\t\t\t\t// Make sure that we don't accidentally re-trigger the onFOO events\n\t\t\t\t\t\told = target[ \"on\" + type ];\n\n\t\t\t\t\t\tif ( old ) {\n\t\t\t\t\t\t\ttarget[ \"on\" + type ] = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis.triggered = true;\n\t\t\t\t\t\ttarget[ type ]();\n\t\t\t\t\t}\n\n\t\t\t\t// prevent IE from throwing an error for some elements with some event types, see #3533\n\t\t\t\t} catch (e) {}\n\n\t\t\t\tif ( old ) {\n\t\t\t\t\ttarget[ \"on\" + type ] = old;\n\t\t\t\t}\n\n\t\t\t\tthis.triggered = false;\n\t\t\t}\n\t\t}\n\t},\n\n\thandle: function( event ) {\n\t\t// returned undefined or false\n\t\tvar all, handlers;\n\n\t\tevent = arguments[0] = jQuery.event.fix( event || window.event );\n\t\tevent.currentTarget = this;\n\n\t\t// Namespaced event handlers\n\t\tvar namespaces = event.type.split(\".\");\n\t\tevent.type = namespaces.shift();\n\n\t\t// Cache this now, all = true means, any handler\n\t\tall = !namespaces.length && !event.exclusive;\n\n\t\tvar namespace = new RegExp(\"(^|\\\\.)\" + namespaces.slice(0).sort().join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\");\n\n\t\thandlers = ( jQuery.data(this, \"events\") || {} )[ event.type ];\n\n\t\tfor ( var j in handlers ) {\n\t\t\tvar handler = handlers[ j ];\n\n\t\t\t// Filter the functions by class\n\t\t\tif ( all || namespace.test(handler.type) ) {\n\t\t\t\t// Pass in a reference to the handler function itself\n\t\t\t\t// So that we can later remove it\n\t\t\t\tevent.handler = handler;\n\t\t\t\tevent.data = handler.data;\n\n\t\t\t\tvar ret = handler.apply( this, arguments );\n\n\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\tevent.result = ret;\n\t\t\t\t\tif ( ret === false ) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( event.isImmediatePropagationStopped() ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\tprops: \"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which\".split(\" \"),\n\n\tfix: function( event ) {\n\t\tif ( event[ expando ] ) {\n\t\t\treturn event;\n\t\t}\n\n\t\t// store a copy of the original event object\n\t\t// and \"clone\" to set read-only properties\n\t\tvar originalEvent = event;\n\t\tevent = jQuery.Event( originalEvent );\n\n\t\tfor ( var i = this.props.length, prop; i; ) {\n\t\t\tprop = this.props[ --i ];\n\t\t\tevent[ prop ] = originalEvent[ prop ];\n\t\t}\n\n\t\t// Fix target property, if necessary\n\t\tif ( !event.target ) {\n\t\t\tevent.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either\n\t\t}\n\n\t\t// check if target is a textnode (safari)\n\t\tif ( event.target.nodeType === 3 ) {\n\t\t\tevent.target = event.target.parentNode;\n\t\t}\n\n\t\t// Add relatedTarget, if necessary\n\t\tif ( !event.relatedTarget && event.fromElement ) {\n\t\t\tevent.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;\n\t\t}\n\n\t\t// Calculate pageX/Y if missing and clientX/Y available\n\t\tif ( event.pageX == null && event.clientX != null ) {\n\t\t\tvar doc = document.documentElement, body = document.body;\n\t\t\tevent.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);\n\t\t\tevent.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);\n\t\t}\n\n\t\t// Add which for key events\n\t\tif ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {\n\t\t\tevent.which = event.charCode || event.keyCode;\n\t\t}\n\n\t\t// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)\n\t\tif ( !event.metaKey && event.ctrlKey ) {\n\t\t\tevent.metaKey = event.ctrlKey;\n\t\t}\n\n\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\t// Note: button is not normalized, so don't use it\n\t\tif ( !event.which && event.button !== undefined ) {\n\t\t\tevent.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));\n\t\t}\n\n\t\treturn event;\n\t},\n\n\t// Deprecated, use jQuery.guid instead\n\tguid: 1E8,\n\n\t// Deprecated, use jQuery.proxy instead\n\tproxy: jQuery.proxy,\n\n\tspecial: {\n\t\tready: {\n\t\t\t// Make sure the ready event is setup\n\t\t\tsetup: jQuery.bindReady,\n\t\t\tteardown: jQuery.noop\n\t\t},\n\n\t\tlive: {\n\t\t\tadd: function( proxy, data, namespaces, live ) {\n\t\t\t\tjQuery.extend( proxy, data || {} );\n\n\t\t\t\tproxy.guid += data.selector + data.live; \n\t\t\t\tdata.liveProxy = proxy;\n\n\t\t\t\tjQuery.event.add( this, data.live, liveHandler, data ); \n\t\t\t\t\n\t\t\t},\n\n\t\t\tremove: function( namespaces ) {\n\t\t\t\tif ( namespaces.length ) {\n\t\t\t\t\tvar remove = 0, name = new RegExp(\"(^|\\\\.)\" + namespaces[0] + \"(\\\\.|$)\");\n\n\t\t\t\t\tjQuery.each( (jQuery.data(this, \"events\").live || {}), function() {\n\t\t\t\t\t\tif ( name.test(this.type) ) {\n\t\t\t\t\t\t\tremove++;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tif ( remove < 1 ) {\n\t\t\t\t\t\tjQuery.event.remove( this, namespaces[0], liveHandler );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tspecial: {}\n\t\t},\n\t\tbeforeunload: {\n\t\t\tsetup: function( data, namespaces, fn ) {\n\t\t\t\t// We only want to do this special case on windows\n\t\t\t\tif ( this.setInterval ) {\n\t\t\t\t\tthis.onbeforeunload = fn;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tteardown: function( namespaces, fn ) {\n\t\t\t\tif ( this.onbeforeunload === fn ) {\n\t\t\t\t\tthis.onbeforeunload = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\njQuery.Event = function( src ) {\n\t// Allow instantiation without the 'new' keyword\n\tif ( !this.preventDefault ) {\n\t\treturn new jQuery.Event( src );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// timeStamp is buggy for some events on Firefox(#3843)\n\t// So we won't rely on the native value\n\tthis.timeStamp = now();\n\n\t// Mark it as fixed\n\tthis[ expando ] = true;\n};\n\nfunction returnFalse() {\n\treturn false;\n}\nfunction returnTrue() {\n\treturn true;\n}\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tpreventDefault: function() {\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tvar e = this.originalEvent;\n\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// if preventDefault exists run it on the original event\n\t\tif ( e.preventDefault ) {\n\t\t\te.preventDefault();\n\t\t}\n\t\t// otherwise set the returnValue property of the original event to false (IE)\n\t\te.returnValue = false;\n\t},\n\tstopPropagation: function() {\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tvar e = this.originalEvent;\n\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\t\t// if stopPropagation exists run it on the original event\n\t\tif ( e.stopPropagation ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t\t// otherwise set the cancelBubble property of the original event to true (IE)\n\t\te.cancelBubble = true;\n\t},\n\tstopImmediatePropagation: function() {\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\t\tthis.stopPropagation();\n\t},\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse\n};\n\n// Checks if an event happened on an element within another element\n// Used in jQuery.event.special.mouseenter and mouseleave handlers\nvar withinElement = function( event ) {\n\t// Check if mouse(over|out) are still within the same parent element\n\tvar parent = event.relatedTarget;\n\n\t// Traverse up the tree\n\twhile ( parent && parent !== this ) {\n\t\t// Firefox sometimes assigns relatedTarget a XUL element\n\t\t// which we cannot access the parentNode property of\n\t\ttry {\n\t\t\tparent = parent.parentNode;\n\n\t\t// assuming we've left the element since we most likely mousedover a xul element\n\t\t} catch(e) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( parent !== this ) {\n\t\t// set the correct event type\n\t\tevent.type = event.data;\n\n\t\t// handle event if we actually just moused on to a non sub-element\n\t\tjQuery.event.handle.apply( this, arguments );\n\t}\n\n},\n\n// In case of event delegation, we only need to rename the event.type,\n// liveHandler will take care of the rest.\ndelegate = function( event ) {\n\tevent.type = event.data;\n\tjQuery.event.handle.apply( this, arguments );\n};\n\n// Create mouseenter and mouseleave events\njQuery.each({\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tsetup: function( data ) {\n\t\t\tjQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );\n\t\t},\n\t\tteardown: function( data ) {\n\t\t\tjQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );\n\t\t}\n\t};\n});\n\n// submit delegation\nif ( !jQuery.support.submitBubbles ) {\n\njQuery.event.special.submit = {\n\tsetup: function( data, namespaces, fn ) {\n\t\tif ( this.nodeName.toLowerCase() !== \"form\" ) {\n\t\t\tjQuery.event.add(this, \"click.specialSubmit.\" + fn.guid, function( e ) {\n\t\t\t\tvar elem = e.target, type = elem.type;\n\n\t\t\t\tif ( (type === \"submit\" || type === \"image\") && jQuery( elem ).closest(\"form\").length ) {\n\t\t\t\t\treturn trigger( \"submit\", this, arguments );\n\t\t\t\t}\n\t\t\t});\n\t \n\t\t\tjQuery.event.add(this, \"keypress.specialSubmit.\" + fn.guid, function( e ) {\n\t\t\t\tvar elem = e.target, type = elem.type;\n\n\t\t\t\tif ( (type === \"text\" || type === \"password\") && jQuery( elem ).closest(\"form\").length && e.keyCode === 13 ) {\n\t\t\t\t\treturn trigger( \"submit\", this, arguments );\n\t\t\t\t}\n\t\t\t});\n\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t},\n\n\tremove: function( namespaces, fn ) {\n\t\tjQuery.event.remove( this, \"click.specialSubmit\" + (fn ? \".\"+fn.guid : \"\") );\n\t\tjQuery.event.remove( this, \"keypress.specialSubmit\" + (fn ? \".\"+fn.guid : \"\") );\n\t}\n};\n\n}\n\n// change delegation, happens here so we have bind.\nif ( !jQuery.support.changeBubbles ) {\n\nvar formElems = /textarea|input|select/i;\n\nfunction getVal( elem ) {\n\tvar type = elem.type, val = elem.value;\n\n\tif ( type === \"radio\" || type === \"checkbox\" ) {\n\t\tval = elem.checked;\n\n\t} else if ( type === \"select-multiple\" ) {\n\t\tval = elem.selectedIndex > -1 ?\n\t\t\tjQuery.map( elem.options, function( elem ) {\n\t\t\t\treturn elem.selected;\n\t\t\t}).join(\"-\") :\n\t\t\t\"\";\n\n\t} else if ( elem.nodeName.toLowerCase() === \"select\" ) {\n\t\tval = elem.selectedIndex;\n\t}\n\n\treturn val;\n}\n\nfunction testChange( e ) {\n\t\tvar elem = e.target, data, val;\n\n\t\tif ( !formElems.test( elem.nodeName ) || elem.readOnly ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdata = jQuery.data( elem, \"_change_data\" );\n\t\tval = getVal(elem);\n\n\t\t// the current data will be also retrieved by beforeactivate\n\t\tif ( e.type !== \"focusout\" || elem.type !== \"radio\" ) {\n\t\t\tjQuery.data( elem, \"_change_data\", val );\n\t\t}\n\t\t\n\t\tif ( data === undefined || val === data ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( data != null || val ) {\n\t\t\te.type = \"change\";\n\t\t\treturn jQuery.event.trigger( e, arguments[1], elem );\n\t\t}\n}\n\njQuery.event.special.change = {\n\tfilters: {\n\t\tfocusout: testChange, \n\n\t\tclick: function( e ) {\n\t\t\tvar elem = e.target, type = elem.type;\n\n\t\t\tif ( type === \"radio\" || type === \"checkbox\" || elem.nodeName.toLowerCase() === \"select\" ) {\n\t\t\t\treturn testChange.call( this, e );\n\t\t\t}\n\t\t},\n\n\t\t// Change has to be called before submit\n\t\t// Keydown will be called before keypress, which is used in submit-event delegation\n\t\tkeydown: function( e ) {\n\t\t\tvar elem = e.target, type = elem.type;\n\n\t\t\tif ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== \"textarea\") ||\n\t\t\t\t(e.keyCode === 32 && (type === \"checkbox\" || type === \"radio\")) ||\n\t\t\t\ttype === \"select-multiple\" ) {\n\t\t\t\treturn testChange.call( this, e );\n\t\t\t}\n\t\t},\n\n\t\t// Beforeactivate happens also before the previous element is blurred\n\t\t// with this event you can't trigger a change event, but you can store\n\t\t// information/focus[in] is not needed anymore\n\t\tbeforeactivate: function( e ) {\n\t\t\tvar elem = e.target;\n\n\t\t\tif ( elem.nodeName.toLowerCase() === \"input\" && elem.type === \"radio\" ) {\n\t\t\t\tjQuery.data( elem, \"_change_data\", getVal(elem) );\n\t\t\t}\n\t\t}\n\t},\n\tsetup: function( data, namespaces, fn ) {\n\t\tfor ( var type in changeFilters ) {\n\t\t\tjQuery.event.add( this, type + \".specialChange.\" + fn.guid, changeFilters[type] );\n\t\t}\n\n\t\treturn formElems.test( this.nodeName );\n\t},\n\tremove: function( namespaces, fn ) {\n\t\tfor ( var type in changeFilters ) {\n\t\t\tjQuery.event.remove( this, type + \".specialChange\" + (fn ? \".\"+fn.guid : \"\"), changeFilters[type] );\n\t\t}\n\n\t\treturn formElems.test( this.nodeName );\n\t}\n};\n\nvar changeFilters = jQuery.event.special.change.filters;\n\n}\n\nfunction trigger( type, elem, args ) {\n\targs[0].type = type;\n\treturn jQuery.event.handle.apply( elem, args );\n}\n\n// Create \"bubbling\" focus and blur events\nif ( document.addEventListener ) {\n\tjQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tthis.addEventListener( orig, handler, true );\n\t\t\t}, \n\t\t\tteardown: function() { \n\t\t\t\tthis.removeEventListener( orig, handler, true );\n\t\t\t}\n\t\t};\n\n\t\tfunction handler( e ) { \n\t\t\te = jQuery.event.fix( e );\n\t\t\te.type = fix;\n\t\t\treturn jQuery.event.handle.call( this, e );\n\t\t}\n\t});\n}\n\njQuery.each([\"bind\", \"one\"], function( i, name ) {\n\tjQuery.fn[ name ] = function( type, data, fn ) {\n\t\t// Handle object literals\n\t\tif ( typeof type === \"object\" ) {\n\t\t\tfor ( var key in type ) {\n\t\t\t\tthis[ name ](key, data, type[key], fn);\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\t\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\tvar handler = name === \"one\" ? jQuery.proxy( fn, function( event ) {\n\t\t\tjQuery( this ).unbind( event, handler );\n\t\t\treturn fn.apply( this, arguments );\n\t\t}) : fn;\n\n\t\treturn type === \"unload\" && name !== \"one\" ?\n\t\t\tthis.one( type, data, fn ) :\n\t\t\tthis.each(function() {\n\t\t\t\tjQuery.event.add( this, type, handler, data );\n\t\t\t});\n\t};\n});\n\njQuery.fn.extend({\n\tunbind: function( type, fn ) {\n\t\t// Handle object literals\n\t\tif ( typeof type === \"object\" && !type.preventDefault ) {\n\t\t\tfor ( var key in type ) {\n\t\t\t\tthis.unbind(key, type[key]);\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.remove( this, type, fn );\n\t\t});\n\t},\n\ttrigger: function( type, data ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t});\n\t},\n\n\ttriggerHandler: function( type, data ) {\n\t\tif ( this[0] ) {\n\t\t\tvar event = jQuery.Event( type );\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t\tjQuery.event.trigger( event, data, this[0] );\n\t\t\treturn event.result;\n\t\t}\n\t},\n\n\ttoggle: function( fn ) {\n\t\t// Save reference to arguments for access in closure\n\t\tvar args = arguments, i = 1;\n\n\t\t// link all the functions, so any of them can unbind this click handler\n\t\twhile ( i < args.length ) {\n\t\t\tjQuery.proxy( fn, args[ i++ ] );\n\t\t}\n\n\t\treturn this.click( jQuery.proxy( fn, function( event ) {\n\t\t\t// Figure out which function to execute\n\t\t\tvar lastToggle = ( jQuery.data( this, \"lastToggle\" + fn.guid ) || 0 ) % i;\n\t\t\tjQuery.data( this, \"lastToggle\" + fn.guid, lastToggle + 1 );\n\n\t\t\t// Make sure that clicks stop\n\t\t\tevent.preventDefault();\n\n\t\t\t// and execute the function\n\t\t\treturn args[ lastToggle ].apply( this, arguments ) || false;\n\t\t}));\n\t},\n\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n});\n\njQuery.each([\"live\", \"die\"], function( i, name ) {\n\tjQuery.fn[ name ] = function( types, data, fn ) {\n\t\tvar type, i = 0;\n\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\ttypes = (types || \"\").split( /\\s+/ );\n\n\t\twhile ( (type = types[ i++ ]) != null ) {\n\t\t\ttype = type === \"focus\" ? \"focusin\" : // focus --> focusin\n\t\t\t\t\ttype === \"blur\" ? \"focusout\" : // blur --> focusout\n\t\t\t\t\ttype === \"hover\" ? types.push(\"mouseleave\") && \"mouseenter\" : // hover support\n\t\t\t\t\ttype;\n\t\t\t\n\t\t\tif ( name === \"live\" ) {\n\t\t\t\t// bind live handler\n\t\t\t\tjQuery( this.context ).bind( liveConvert( type, this.selector ), {\n\t\t\t\t\tdata: data, selector: this.selector, live: type\n\t\t\t\t}, fn );\n\n\t\t\t} else {\n\t\t\t\t// unbind live handler\n\t\t\t\tjQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn this;\n\t}\n});\n\nfunction liveHandler( event ) {\n\tvar stop, elems = [], selectors = [], args = arguments,\n\t\trelated, match, fn, elem, j, i, l, data,\n\t\tlive = jQuery.extend({}, jQuery.data( this, \"events\" ).live);\n\n\t// Make sure we avoid non-left-click bubbling in Firefox (#3861)\n\tif ( event.button && event.type === \"click\" ) {\n\t\treturn;\n\t}\n\n\tfor ( j in live ) {\n\t\tfn = live[j];\n\t\tif ( fn.live === event.type ||\n\t\t\t\tfn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {\n\n\t\t\tdata = fn.data;\n\t\t\tif ( !(data.beforeFilter && data.beforeFilter[event.type] && \n\t\t\t\t\t!data.beforeFilter[event.type](event)) ) {\n\t\t\t\tselectors.push( fn.selector );\n\t\t\t}\n\t\t} else {\n\t\t\tdelete live[j];\n\t\t}\n\t}\n\n\tmatch = jQuery( event.target ).closest( selectors, event.currentTarget );\n\n\tfor ( i = 0, l = match.length; i < l; i++ ) {\n\t\tfor ( j in live ) {\n\t\t\tfn = live[j];\n\t\t\telem = match[i].elem;\n\t\t\trelated = null;\n\n\t\t\tif ( match[i].selector === fn.selector ) {\n\t\t\t\t// Those two events require additional checking\n\t\t\t\tif ( fn.live === \"mouseenter\" || fn.live === \"mouseleave\" ) {\n\t\t\t\t\trelated = jQuery( event.relatedTarget ).closest( fn.selector )[0];\n\t\t\t\t}\n\n\t\t\t\tif ( !related || related !== elem ) {\n\t\t\t\t\telems.push({ elem: elem, fn: fn });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor ( i = 0, l = elems.length; i < l; i++ ) {\n\t\tmatch = elems[i];\n\t\tevent.currentTarget = match.elem;\n\t\tevent.data = match.fn.data;\n\t\tif ( match.fn.apply( match.elem, args ) === false ) {\n\t\t\tstop = false;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn stop;\n}\n\nfunction liveConvert( type, selector ) {\n\treturn \"live.\" + (type ? type + \".\" : \"\") + selector.replace(/\\./g, \"`\").replace(/ /g, \"&\");\n}\n\njQuery.each( (\"blur focus focusin focusout load resize scroll unload click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup error\").split(\" \"), function( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( fn ) {\n\t\treturn fn ? this.bind( name, fn ) : this.trigger( name );\n\t};\n\n\tif ( jQuery.attrFn ) {\n\t\tjQuery.attrFn[ name ] = true;\n\t}\n});\n\n// Prevent memory leaks in IE\n// Window isn't included so as not to unbind existing unload events\n// More info:\n//  - http://isaacschlueter.com/2006/10/msie-memory-leaks/\nif ( window.attachEvent && !window.addEventListener ) {\n\twindow.attachEvent(\"onunload\", function() {\n\t\tfor ( var id in jQuery.cache ) {\n\t\t\tif ( jQuery.cache[ id ].handle ) {\n\t\t\t\t// Try/Catch is to handle iframes being unloaded, see #4280\n\t\t\t\ttry {\n\t\t\t\t\tjQuery.event.remove( jQuery.cache[ id ].handle.elem );\n\t\t\t\t} catch(e) {}\n\t\t\t}\n\t\t}\n\t});\n}\n/*!\n * Sizzle CSS Selector Engine - v1.0\n *  Copyright 2009, The Dojo Foundation\n *  Released under the MIT, BSD, and GPL Licenses.\n *  More information: http://sizzlejs.com/\n */\n(function(){\n\nvar chunker = /((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^[\\]]*\\]|['\"][^'\"]*['\"]|[^[\\]'\"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,\n\tdone = 0,\n\ttoString = Object.prototype.toString,\n\thasDuplicate = false,\n\tbaseHasDuplicate = true;\n\n// Here we check if the JavaScript engine is using some sort of\n// optimization where it does not always call our comparision\n// function. If that is the case, discard the hasDuplicate value.\n//   Thus far that includes Google Chrome.\n[0, 0].sort(function(){\n\tbaseHasDuplicate = false;\n\treturn 0;\n});\n\nvar Sizzle = function(selector, context, results, seed) {\n\tresults = results || [];\n\tvar origContext = context = context || document;\n\n\tif ( context.nodeType !== 1 && context.nodeType !== 9 ) {\n\t\treturn [];\n\t}\n\t\n\tif ( !selector || typeof selector !== \"string\" ) {\n\t\treturn results;\n\t}\n\n\tvar parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context),\n\t\tsoFar = selector;\n\t\n\t// Reset the position of the chunker regexp (start from head)\n\twhile ( (chunker.exec(\"\"), m = chunker.exec(soFar)) !== null ) {\n\t\tsoFar = m[3];\n\t\t\n\t\tparts.push( m[1] );\n\t\t\n\t\tif ( m[2] ) {\n\t\t\textra = m[3];\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( parts.length > 1 && origPOS.exec( selector ) ) {\n\t\tif ( parts.length === 2 && Expr.relative[ parts[0] ] ) {\n\t\t\tset = posProcess( parts[0] + parts[1], context );\n\t\t} else {\n\t\t\tset = Expr.relative[ parts[0] ] ?\n\t\t\t\t[ context ] :\n\t\t\t\tSizzle( parts.shift(), context );\n\n\t\t\twhile ( parts.length ) {\n\t\t\t\tselector = parts.shift();\n\n\t\t\t\tif ( Expr.relative[ selector ] ) {\n\t\t\t\t\tselector += parts.shift();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tset = posProcess( selector, set );\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Take a shortcut and set the context if the root selector is an ID\n\t\t// (but not if it'll be faster if the inner selector is an ID)\n\t\tif ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&\n\t\t\t\tExpr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {\n\t\t\tvar ret = Sizzle.find( parts.shift(), context, contextXML );\n\t\t\tcontext = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];\n\t\t}\n\n\t\tif ( context ) {\n\t\t\tvar ret = seed ?\n\t\t\t\t{ expr: parts.pop(), set: makeArray(seed) } :\n\t\t\t\tSizzle.find( parts.pop(), parts.length === 1 && (parts[0] === \"~\" || parts[0] === \"+\") && context.parentNode ? context.parentNode : context, contextXML );\n\t\t\tset = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;\n\n\t\t\tif ( parts.length > 0 ) {\n\t\t\t\tcheckSet = makeArray(set);\n\t\t\t} else {\n\t\t\t\tprune = false;\n\t\t\t}\n\n\t\t\twhile ( parts.length ) {\n\t\t\t\tvar cur = parts.pop(), pop = cur;\n\n\t\t\t\tif ( !Expr.relative[ cur ] ) {\n\t\t\t\t\tcur = \"\";\n\t\t\t\t} else {\n\t\t\t\t\tpop = parts.pop();\n\t\t\t\t}\n\n\t\t\t\tif ( pop == null ) {\n\t\t\t\t\tpop = context;\n\t\t\t\t}\n\n\t\t\t\tExpr.relative[ cur ]( checkSet, pop, contextXML );\n\t\t\t}\n\t\t} else {\n\t\t\tcheckSet = parts = [];\n\t\t}\n\t}\n\n\tif ( !checkSet ) {\n\t\tcheckSet = set;\n\t}\n\n\tif ( !checkSet ) {\n\t\tSizzle.error( cur || selector );\n\t}\n\n\tif ( toString.call(checkSet) === \"[object Array]\" ) {\n\t\tif ( !prune ) {\n\t\t\tresults.push.apply( results, checkSet );\n\t\t} else if ( context && context.nodeType === 1 ) {\n\t\t\tfor ( var i = 0; checkSet[i] != null; i++ ) {\n\t\t\t\tif ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {\n\t\t\t\t\tresults.push( set[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( var i = 0; checkSet[i] != null; i++ ) {\n\t\t\t\tif ( checkSet[i] && checkSet[i].nodeType === 1 ) {\n\t\t\t\t\tresults.push( set[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tmakeArray( checkSet, results );\n\t}\n\n\tif ( extra ) {\n\t\tSizzle( extra, origContext, results, seed );\n\t\tSizzle.uniqueSort( results );\n\t}\n\n\treturn results;\n};\n\nSizzle.uniqueSort = function(results){\n\tif ( sortOrder ) {\n\t\thasDuplicate = baseHasDuplicate;\n\t\tresults.sort(sortOrder);\n\n\t\tif ( hasDuplicate ) {\n\t\t\tfor ( var i = 1; i < results.length; i++ ) {\n\t\t\t\tif ( results[i] === results[i-1] ) {\n\t\t\t\t\tresults.splice(i--, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n};\n\nSizzle.matches = function(expr, set){\n\treturn Sizzle(expr, null, null, set);\n};\n\nSizzle.find = function(expr, context, isXML){\n\tvar set, match;\n\n\tif ( !expr ) {\n\t\treturn [];\n\t}\n\n\tfor ( var i = 0, l = Expr.order.length; i < l; i++ ) {\n\t\tvar type = Expr.order[i], match;\n\t\t\n\t\tif ( (match = Expr.leftMatch[ type ].exec( expr )) ) {\n\t\t\tvar left = match[1];\n\t\t\tmatch.splice(1,1);\n\n\t\t\tif ( left.substr( left.length - 1 ) !== \"\\\\\" ) {\n\t\t\t\tmatch[1] = (match[1] || \"\").replace(/\\\\/g, \"\");\n\t\t\t\tset = Expr.find[ type ]( match, context, isXML );\n\t\t\t\tif ( set != null ) {\n\t\t\t\t\texpr = expr.replace( Expr.match[ type ], \"\" );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( !set ) {\n\t\tset = context.getElementsByTagName(\"*\");\n\t}\n\n\treturn {set: set, expr: expr};\n};\n\nSizzle.filter = function(expr, set, inplace, not){\n\tvar old = expr, result = [], curLoop = set, match, anyFound,\n\t\tisXMLFilter = set && set[0] && isXML(set[0]);\n\n\twhile ( expr && set.length ) {\n\t\tfor ( var type in Expr.filter ) {\n\t\t\tif ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {\n\t\t\t\tvar filter = Expr.filter[ type ], found, item, left = match[1];\n\t\t\t\tanyFound = false;\n\n\t\t\t\tmatch.splice(1,1);\n\n\t\t\t\tif ( left.substr( left.length - 1 ) === \"\\\\\" ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif ( curLoop === result ) {\n\t\t\t\t\tresult = [];\n\t\t\t\t}\n\n\t\t\t\tif ( Expr.preFilter[ type ] ) {\n\t\t\t\t\tmatch = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );\n\n\t\t\t\t\tif ( !match ) {\n\t\t\t\t\t\tanyFound = found = true;\n\t\t\t\t\t} else if ( match === true ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\tfor ( var i = 0; (item = curLoop[i]) != null; i++ ) {\n\t\t\t\t\t\tif ( item ) {\n\t\t\t\t\t\t\tfound = filter( item, match, i, curLoop );\n\t\t\t\t\t\t\tvar pass = not ^ !!found;\n\n\t\t\t\t\t\t\tif ( inplace && found != null ) {\n\t\t\t\t\t\t\t\tif ( pass ) {\n\t\t\t\t\t\t\t\t\tanyFound = true;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcurLoop[i] = false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( pass ) {\n\t\t\t\t\t\t\t\tresult.push( item );\n\t\t\t\t\t\t\t\tanyFound = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( found !== undefined ) {\n\t\t\t\t\tif ( !inplace ) {\n\t\t\t\t\t\tcurLoop = result;\n\t\t\t\t\t}\n\n\t\t\t\t\texpr = expr.replace( Expr.match[ type ], \"\" );\n\n\t\t\t\t\tif ( !anyFound ) {\n\t\t\t\t\t\treturn [];\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Improper expression\n\t\tif ( expr === old ) {\n\t\t\tif ( anyFound == null ) {\n\t\t\t\tSizzle.error( expr );\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\told = expr;\n\t}\n\n\treturn curLoop;\n};\n\nSizzle.error = function( msg ) {\n\tthrow \"Syntax error, unrecognized expression: \" + msg;\n};\n\nvar Expr = Sizzle.selectors = {\n\torder: [ \"ID\", \"NAME\", \"TAG\" ],\n\tmatch: {\n\t\tID: /#((?:[\\w\\u00c0-\\uFFFF-]|\\\\.)+)/,\n\t\tCLASS: /\\.((?:[\\w\\u00c0-\\uFFFF-]|\\\\.)+)/,\n\t\tNAME: /\\[name=['\"]*((?:[\\w\\u00c0-\\uFFFF-]|\\\\.)+)['\"]*\\]/,\n\t\tATTR: /\\[\\s*((?:[\\w\\u00c0-\\uFFFF-]|\\\\.)+)\\s*(?:(\\S?=)\\s*(['\"]*)(.*?)\\3|)\\s*\\]/,\n\t\tTAG: /^((?:[\\w\\u00c0-\\uFFFF\\*-]|\\\\.)+)/,\n\t\tCHILD: /:(only|nth|last|first)-child(?:\\((even|odd|[\\dn+-]*)\\))?/,\n\t\tPOS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^-]|$)/,\n\t\tPSEUDO: /:((?:[\\w\\u00c0-\\uFFFF-]|\\\\.)+)(?:\\((['\"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/\n\t},\n\tleftMatch: {},\n\tattrMap: {\n\t\t\"class\": \"className\",\n\t\t\"for\": \"htmlFor\"\n\t},\n\tattrHandle: {\n\t\thref: function(elem){\n\t\t\treturn elem.getAttribute(\"href\");\n\t\t}\n\t},\n\trelative: {\n\t\t\"+\": function(checkSet, part){\n\t\t\tvar isPartStr = typeof part === \"string\",\n\t\t\t\tisTag = isPartStr && !/\\W/.test(part),\n\t\t\t\tisPartStrNotTag = isPartStr && !isTag;\n\n\t\t\tif ( isTag ) {\n\t\t\t\tpart = part.toLowerCase();\n\t\t\t}\n\n\t\t\tfor ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {\n\t\t\t\tif ( (elem = checkSet[i]) ) {\n\t\t\t\t\twhile ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}\n\n\t\t\t\t\tcheckSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?\n\t\t\t\t\t\telem || false :\n\t\t\t\t\t\telem === part;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( isPartStrNotTag ) {\n\t\t\t\tSizzle.filter( part, checkSet, true );\n\t\t\t}\n\t\t},\n\t\t\">\": function(checkSet, part){\n\t\t\tvar isPartStr = typeof part === \"string\";\n\n\t\t\tif ( isPartStr && !/\\W/.test(part) ) {\n\t\t\t\tpart = part.toLowerCase();\n\n\t\t\t\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n\t\t\t\t\tvar elem = checkSet[i];\n\t\t\t\t\tif ( elem ) {\n\t\t\t\t\t\tvar parent = elem.parentNode;\n\t\t\t\t\t\tcheckSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n\t\t\t\t\tvar elem = checkSet[i];\n\t\t\t\t\tif ( elem ) {\n\t\t\t\t\t\tcheckSet[i] = isPartStr ?\n\t\t\t\t\t\t\telem.parentNode :\n\t\t\t\t\t\t\telem.parentNode === part;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( isPartStr ) {\n\t\t\t\t\tSizzle.filter( part, checkSet, true );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"\": function(checkSet, part, isXML){\n\t\t\tvar doneName = done++, checkFn = dirCheck;\n\n\t\t\tif ( typeof part === \"string\" && !/\\W/.test(part) ) {\n\t\t\t\tvar nodeCheck = part = part.toLowerCase();\n\t\t\t\tcheckFn = dirNodeCheck;\n\t\t\t}\n\n\t\t\tcheckFn(\"parentNode\", part, doneName, checkSet, nodeCheck, isXML);\n\t\t},\n\t\t\"~\": function(checkSet, part, isXML){\n\t\t\tvar doneName = done++, checkFn = dirCheck;\n\n\t\t\tif ( typeof part === \"string\" && !/\\W/.test(part) ) {\n\t\t\t\tvar nodeCheck = part = part.toLowerCase();\n\t\t\t\tcheckFn = dirNodeCheck;\n\t\t\t}\n\n\t\t\tcheckFn(\"previousSibling\", part, doneName, checkSet, nodeCheck, isXML);\n\t\t}\n\t},\n\tfind: {\n\t\tID: function(match, context, isXML){\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && !isXML ) {\n\t\t\t\tvar m = context.getElementById(match[1]);\n\t\t\t\treturn m ? [m] : [];\n\t\t\t}\n\t\t},\n\t\tNAME: function(match, context){\n\t\t\tif ( typeof context.getElementsByName !== \"undefined\" ) {\n\t\t\t\tvar ret = [], results = context.getElementsByName(match[1]);\n\n\t\t\t\tfor ( var i = 0, l = results.length; i < l; i++ ) {\n\t\t\t\t\tif ( results[i].getAttribute(\"name\") === match[1] ) {\n\t\t\t\t\t\tret.push( results[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn ret.length === 0 ? null : ret;\n\t\t\t}\n\t\t},\n\t\tTAG: function(match, context){\n\t\t\treturn context.getElementsByTagName(match[1]);\n\t\t}\n\t},\n\tpreFilter: {\n\t\tCLASS: function(match, curLoop, inplace, result, not, isXML){\n\t\t\tmatch = \" \" + match[1].replace(/\\\\/g, \"\") + \" \";\n\n\t\t\tif ( isXML ) {\n\t\t\t\treturn match;\n\t\t\t}\n\n\t\t\tfor ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {\n\t\t\t\tif ( elem ) {\n\t\t\t\t\tif ( not ^ (elem.className && (\" \" + elem.className + \" \").replace(/[\\t\\n]/g, \" \").indexOf(match) >= 0) ) {\n\t\t\t\t\t\tif ( !inplace ) {\n\t\t\t\t\t\t\tresult.push( elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if ( inplace ) {\n\t\t\t\t\t\tcurLoop[i] = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t},\n\t\tID: function(match){\n\t\t\treturn match[1].replace(/\\\\/g, \"\");\n\t\t},\n\t\tTAG: function(match, curLoop){\n\t\t\treturn match[1].toLowerCase();\n\t\t},\n\t\tCHILD: function(match){\n\t\t\tif ( match[1] === \"nth\" ) {\n\t\t\t\t// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'\n\t\t\t\tvar test = /(-?)(\\d*)n((?:\\+|-)?\\d*)/.exec(\n\t\t\t\t\tmatch[2] === \"even\" && \"2n\" || match[2] === \"odd\" && \"2n+1\" ||\n\t\t\t\t\t!/\\D/.test( match[2] ) && \"0n+\" + match[2] || match[2]);\n\n\t\t\t\t// calculate the numbers (first)n+(last) including if they are negative\n\t\t\t\tmatch[2] = (test[1] + (test[2] || 1)) - 0;\n\t\t\t\tmatch[3] = test[3] - 0;\n\t\t\t}\n\n\t\t\t// TODO: Move to normal caching system\n\t\t\tmatch[0] = done++;\n\n\t\t\treturn match;\n\t\t},\n\t\tATTR: function(match, curLoop, inplace, result, not, isXML){\n\t\t\tvar name = match[1].replace(/\\\\/g, \"\");\n\t\t\t\n\t\t\tif ( !isXML && Expr.attrMap[name] ) {\n\t\t\t\tmatch[1] = Expr.attrMap[name];\n\t\t\t}\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[4] = \" \" + match[4] + \" \";\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\t\tPSEUDO: function(match, curLoop, inplace, result, not){\n\t\t\tif ( match[1] === \"not\" ) {\n\t\t\t\t// If we're dealing with a complex expression, or a simple one\n\t\t\t\tif ( ( chunker.exec(match[3]) || \"\" ).length > 1 || /^\\w/.test(match[3]) ) {\n\t\t\t\t\tmatch[3] = Sizzle(match[3], null, null, curLoop);\n\t\t\t\t} else {\n\t\t\t\t\tvar ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);\n\t\t\t\t\tif ( !inplace ) {\n\t\t\t\t\t\tresult.push.apply( result, ret );\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\treturn match;\n\t\t},\n\t\tPOS: function(match){\n\t\t\tmatch.unshift( true );\n\t\t\treturn match;\n\t\t}\n\t},\n\tfilters: {\n\t\tenabled: function(elem){\n\t\t\treturn elem.disabled === false && elem.type !== \"hidden\";\n\t\t},\n\t\tdisabled: function(elem){\n\t\t\treturn elem.disabled === true;\n\t\t},\n\t\tchecked: function(elem){\n\t\t\treturn elem.checked === true;\n\t\t},\n\t\tselected: function(elem){\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\telem.parentNode.selectedIndex;\n\t\t\treturn elem.selected === true;\n\t\t},\n\t\tparent: function(elem){\n\t\t\treturn !!elem.firstChild;\n\t\t},\n\t\tempty: function(elem){\n\t\t\treturn !elem.firstChild;\n\t\t},\n\t\thas: function(elem, i, match){\n\t\t\treturn !!Sizzle( match[3], elem ).length;\n\t\t},\n\t\theader: function(elem){\n\t\t\treturn /h\\d/i.test( elem.nodeName );\n\t\t},\n\t\ttext: function(elem){\n\t\t\treturn \"text\" === elem.type;\n\t\t},\n\t\tradio: function(elem){\n\t\t\treturn \"radio\" === elem.type;\n\t\t},\n\t\tcheckbox: function(elem){\n\t\t\treturn \"checkbox\" === elem.type;\n\t\t},\n\t\tfile: function(elem){\n\t\t\treturn \"file\" === elem.type;\n\t\t},\n\t\tpassword: function(elem){\n\t\t\treturn \"password\" === elem.type;\n\t\t},\n\t\tsubmit: function(elem){\n\t\t\treturn \"submit\" === elem.type;\n\t\t},\n\t\timage: function(elem){\n\t\t\treturn \"image\" === elem.type;\n\t\t},\n\t\treset: function(elem){\n\t\t\treturn \"reset\" === elem.type;\n\t\t},\n\t\tbutton: function(elem){\n\t\t\treturn \"button\" === elem.type || elem.nodeName.toLowerCase() === \"button\";\n\t\t},\n\t\tinput: function(elem){\n\t\t\treturn /input|select|textarea|button/i.test(elem.nodeName);\n\t\t}\n\t},\n\tsetFilters: {\n\t\tfirst: function(elem, i){\n\t\t\treturn i === 0;\n\t\t},\n\t\tlast: function(elem, i, match, array){\n\t\t\treturn i === array.length - 1;\n\t\t},\n\t\teven: function(elem, i){\n\t\t\treturn i % 2 === 0;\n\t\t},\n\t\todd: function(elem, i){\n\t\t\treturn i % 2 === 1;\n\t\t},\n\t\tlt: function(elem, i, match){\n\t\t\treturn i < match[3] - 0;\n\t\t},\n\t\tgt: function(elem, i, match){\n\t\t\treturn i > match[3] - 0;\n\t\t},\n\t\tnth: function(elem, i, match){\n\t\t\treturn match[3] - 0 === i;\n\t\t},\n\t\teq: function(elem, i, match){\n\t\t\treturn match[3] - 0 === i;\n\t\t}\n\t},\n\tfilter: {\n\t\tPSEUDO: function(elem, match, i, array){\n\t\t\tvar name = match[1], filter = Expr.filters[ name ];\n\n\t\t\tif ( filter ) {\n\t\t\t\treturn filter( elem, i, match, array );\n\t\t\t} else if ( name === \"contains\" ) {\n\t\t\t\treturn (elem.textContent || elem.innerText || getText([ elem ]) || \"\").indexOf(match[3]) >= 0;\n\t\t\t} else if ( name === \"not\" ) {\n\t\t\t\tvar not = match[3];\n\n\t\t\t\tfor ( var i = 0, l = not.length; i < l; i++ ) {\n\t\t\t\t\tif ( not[i] === elem ) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tSizzle.error( \"Syntax error, unrecognized expression: \" + name );\n\t\t\t}\n\t\t},\n\t\tCHILD: function(elem, match){\n\t\t\tvar type = match[1], node = elem;\n\t\t\tswitch (type) {\n\t\t\t\tcase 'only':\n\t\t\t\tcase 'first':\n\t\t\t\t\twhile ( (node = node.previousSibling) )\t {\n\t\t\t\t\t\tif ( node.nodeType === 1 ) { \n\t\t\t\t\t\t\treturn false; \n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( type === \"first\" ) { \n\t\t\t\t\t\treturn true; \n\t\t\t\t\t}\n\t\t\t\t\tnode = elem;\n\t\t\t\tcase 'last':\n\t\t\t\t\twhile ( (node = node.nextSibling) )\t {\n\t\t\t\t\t\tif ( node.nodeType === 1 ) { \n\t\t\t\t\t\t\treturn false; \n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\tcase 'nth':\n\t\t\t\t\tvar first = match[2], last = match[3];\n\n\t\t\t\t\tif ( first === 1 && last === 0 ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar doneName = match[0],\n\t\t\t\t\t\tparent = elem.parentNode;\n\t\n\t\t\t\t\tif ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {\n\t\t\t\t\t\tvar count = 0;\n\t\t\t\t\t\tfor ( node = parent.firstChild; node; node = node.nextSibling ) {\n\t\t\t\t\t\t\tif ( node.nodeType === 1 ) {\n\t\t\t\t\t\t\t\tnode.nodeIndex = ++count;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} \n\t\t\t\t\t\tparent.sizcache = doneName;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tvar diff = elem.nodeIndex - last;\n\t\t\t\t\tif ( first === 0 ) {\n\t\t\t\t\t\treturn diff === 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tID: function(elem, match){\n\t\t\treturn elem.nodeType === 1 && elem.getAttribute(\"id\") === match;\n\t\t},\n\t\tTAG: function(elem, match){\n\t\t\treturn (match === \"*\" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;\n\t\t},\n\t\tCLASS: function(elem, match){\n\t\t\treturn (\" \" + (elem.className || elem.getAttribute(\"class\")) + \" \")\n\t\t\t\t.indexOf( match ) > -1;\n\t\t},\n\t\tATTR: function(elem, match){\n\t\t\tvar name = match[1],\n\t\t\t\tresult = Expr.attrHandle[ name ] ?\n\t\t\t\t\tExpr.attrHandle[ name ]( elem ) :\n\t\t\t\t\telem[ name ] != null ?\n\t\t\t\t\t\telem[ name ] :\n\t\t\t\t\t\telem.getAttribute( name ),\n\t\t\t\tvalue = result + \"\",\n\t\t\t\ttype = match[2],\n\t\t\t\tcheck = match[4];\n\n\t\t\treturn result == null ?\n\t\t\t\ttype === \"!=\" :\n\t\t\t\ttype === \"=\" ?\n\t\t\t\tvalue === check :\n\t\t\t\ttype === \"*=\" ?\n\t\t\t\tvalue.indexOf(check) >= 0 :\n\t\t\t\ttype === \"~=\" ?\n\t\t\t\t(\" \" + value + \" \").indexOf(check) >= 0 :\n\t\t\t\t!check ?\n\t\t\t\tvalue && result !== false :\n\t\t\t\ttype === \"!=\" ?\n\t\t\t\tvalue !== check :\n\t\t\t\ttype === \"^=\" ?\n\t\t\t\tvalue.indexOf(check) === 0 :\n\t\t\t\ttype === \"$=\" ?\n\t\t\t\tvalue.substr(value.length - check.length) === check :\n\t\t\t\ttype === \"|=\" ?\n\t\t\t\tvalue === check || value.substr(0, check.length + 1) === check + \"-\" :\n\t\t\t\tfalse;\n\t\t},\n\t\tPOS: function(elem, match, i, array){\n\t\t\tvar name = match[2], filter = Expr.setFilters[ name ];\n\n\t\t\tif ( filter ) {\n\t\t\t\treturn filter( elem, i, match, array );\n\t\t\t}\n\t\t}\n\t}\n};\n\nvar origPOS = Expr.match.POS;\n\nfor ( var type in Expr.match ) {\n\tExpr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\\[]*\\])(?![^\\(]*\\))/.source );\n\tExpr.leftMatch[ type ] = new RegExp( /(^(?:.|\\r|\\n)*?)/.source + Expr.match[ type ].source.replace(/\\\\(\\d+)/g, function(all, num){\n\t\treturn \"\\\\\" + (num - 0 + 1);\n\t}));\n}\n\nvar makeArray = function(array, results) {\n\tarray = Array.prototype.slice.call( array, 0 );\n\n\tif ( results ) {\n\t\tresults.push.apply( results, array );\n\t\treturn results;\n\t}\n\t\n\treturn array;\n};\n\n// Perform a simple check to determine if the browser is capable of\n// converting a NodeList to an array using builtin methods.\ntry {\n\tArray.prototype.slice.call( document.documentElement.childNodes, 0 );\n\n// Provide a fallback method if it does not work\n} catch(e){\n\tmakeArray = function(array, results) {\n\t\tvar ret = results || [];\n\n\t\tif ( toString.call(array) === \"[object Array]\" ) {\n\t\t\tArray.prototype.push.apply( ret, array );\n\t\t} else {\n\t\t\tif ( typeof array.length === \"number\" ) {\n\t\t\t\tfor ( var i = 0, l = array.length; i < l; i++ ) {\n\t\t\t\t\tret.push( array[i] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( var i = 0; array[i]; i++ ) {\n\t\t\t\t\tret.push( array[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t};\n}\n\nvar sortOrder;\n\nif ( document.documentElement.compareDocumentPosition ) {\n\tsortOrder = function( a, b ) {\n\t\tif ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {\n\t\t\tif ( a == b ) {\n\t\t\t\thasDuplicate = true;\n\t\t\t}\n\t\t\treturn a.compareDocumentPosition ? -1 : 1;\n\t\t}\n\n\t\tvar ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;\n\t\tif ( ret === 0 ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn ret;\n\t};\n} else if ( \"sourceIndex\" in document.documentElement ) {\n\tsortOrder = function( a, b ) {\n\t\tif ( !a.sourceIndex || !b.sourceIndex ) {\n\t\t\tif ( a == b ) {\n\t\t\t\thasDuplicate = true;\n\t\t\t}\n\t\t\treturn a.sourceIndex ? -1 : 1;\n\t\t}\n\n\t\tvar ret = a.sourceIndex - b.sourceIndex;\n\t\tif ( ret === 0 ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn ret;\n\t};\n} else if ( document.createRange ) {\n\tsortOrder = function( a, b ) {\n\t\tif ( !a.ownerDocument || !b.ownerDocument ) {\n\t\t\tif ( a == b ) {\n\t\t\t\thasDuplicate = true;\n\t\t\t}\n\t\t\treturn a.ownerDocument ? -1 : 1;\n\t\t}\n\n\t\tvar aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();\n\t\taRange.setStart(a, 0);\n\t\taRange.setEnd(a, 0);\n\t\tbRange.setStart(b, 0);\n\t\tbRange.setEnd(b, 0);\n\t\tvar ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);\n\t\tif ( ret === 0 ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn ret;\n\t};\n}\n\n// Utility function for retreiving the text value of an array of DOM nodes\nfunction getText( elems ) {\n\tvar ret = \"\", elem;\n\n\tfor ( var i = 0; elems[i]; i++ ) {\n\t\telem = elems[i];\n\n\t\t// Get the text from text nodes and CDATA nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 4 ) {\n\t\t\tret += elem.nodeValue;\n\n\t\t// Traverse everything else, except comment nodes\n\t\t} else if ( elem.nodeType !== 8 ) {\n\t\t\tret += getText( elem.childNodes );\n\t\t}\n\t}\n\n\treturn ret;\n}\n\n// Check to see if the browser returns elements by name when\n// querying by getElementById (and provide a workaround)\n(function(){\n\t// We're going to inject a fake input element with a specified name\n\tvar form = document.createElement(\"div\"),\n\t\tid = \"script\" + (new Date).getTime();\n\tform.innerHTML = \"<a name='\" + id + \"'/>\";\n\n\t// Inject it into the root element, check its status, and remove it quickly\n\tvar root = document.documentElement;\n\troot.insertBefore( form, root.firstChild );\n\n\t// The workaround has to do additional checks after a getElementById\n\t// Which slows things down for other browsers (hence the branching)\n\tif ( document.getElementById( id ) ) {\n\t\tExpr.find.ID = function(match, context, isXML){\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && !isXML ) {\n\t\t\t\tvar m = context.getElementById(match[1]);\n\t\t\t\treturn m ? m.id === match[1] || typeof m.getAttributeNode !== \"undefined\" && m.getAttributeNode(\"id\").nodeValue === match[1] ? [m] : undefined : [];\n\t\t\t}\n\t\t};\n\n\t\tExpr.filter.ID = function(elem, match){\n\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" && elem.getAttributeNode(\"id\");\n\t\t\treturn elem.nodeType === 1 && node && node.nodeValue === match;\n\t\t};\n\t}\n\n\troot.removeChild( form );\n\troot = form = null; // release memory in IE\n})();\n\n(function(){\n\t// Check to see if the browser returns only elements\n\t// when doing getElementsByTagName(\"*\")\n\n\t// Create a fake element\n\tvar div = document.createElement(\"div\");\n\tdiv.appendChild( document.createComment(\"\") );\n\n\t// Make sure no comments are found\n\tif ( div.getElementsByTagName(\"*\").length > 0 ) {\n\t\tExpr.find.TAG = function(match, context){\n\t\t\tvar results = context.getElementsByTagName(match[1]);\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( match[1] === \"*\" ) {\n\t\t\t\tvar tmp = [];\n\n\t\t\t\tfor ( var i = 0; results[i]; i++ ) {\n\t\t\t\t\tif ( results[i].nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( results[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tresults = tmp;\n\t\t\t}\n\n\t\t\treturn results;\n\t\t};\n\t}\n\n\t// Check to see if an attribute returns normalized href attributes\n\tdiv.innerHTML = \"<a href='#'></a>\";\n\tif ( div.firstChild && typeof div.firstChild.getAttribute !== \"undefined\" &&\n\t\t\tdiv.firstChild.getAttribute(\"href\") !== \"#\" ) {\n\t\tExpr.attrHandle.href = function(elem){\n\t\t\treturn elem.getAttribute(\"href\", 2);\n\t\t};\n\t}\n\n\tdiv = null; // release memory in IE\n})();\n\nif ( document.querySelectorAll ) {\n\t(function(){\n\t\tvar oldSizzle = Sizzle, div = document.createElement(\"div\");\n\t\tdiv.innerHTML = \"<p class='TEST'></p>\";\n\n\t\t// Safari can't handle uppercase or unicode characters when\n\t\t// in quirks mode.\n\t\tif ( div.querySelectorAll && div.querySelectorAll(\".TEST\").length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tSizzle = function(query, context, extra, seed){\n\t\t\tcontext = context || document;\n\n\t\t\t// Only use querySelectorAll on non-XML documents\n\t\t\t// (ID selectors don't work in non-HTML documents)\n\t\t\tif ( !seed && context.nodeType === 9 && !isXML(context) ) {\n\t\t\t\ttry {\n\t\t\t\t\treturn makeArray( context.querySelectorAll(query), extra );\n\t\t\t\t} catch(e){}\n\t\t\t}\n\t\t\n\t\t\treturn oldSizzle(query, context, extra, seed);\n\t\t};\n\n\t\tfor ( var prop in oldSizzle ) {\n\t\t\tSizzle[ prop ] = oldSizzle[ prop ];\n\t\t}\n\n\t\tdiv = null; // release memory in IE\n\t})();\n}\n\n(function(){\n\tvar div = document.createElement(\"div\");\n\n\tdiv.innerHTML = \"<div class='test e'></div><div class='test'></div>\";\n\n\t// Opera can't find a second classname (in 9.6)\n\t// Also, make sure that getElementsByClassName actually exists\n\tif ( !div.getElementsByClassName || div.getElementsByClassName(\"e\").length === 0 ) {\n\t\treturn;\n\t}\n\n\t// Safari caches class attributes, doesn't catch changes (in 3.2)\n\tdiv.lastChild.className = \"e\";\n\n\tif ( div.getElementsByClassName(\"e\").length === 1 ) {\n\t\treturn;\n\t}\n\t\n\tExpr.order.splice(1, 0, \"CLASS\");\n\tExpr.find.CLASS = function(match, context, isXML) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && !isXML ) {\n\t\t\treturn context.getElementsByClassName(match[1]);\n\t\t}\n\t};\n\n\tdiv = null; // release memory in IE\n})();\n\nfunction dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n\t\tvar elem = checkSet[i];\n\t\tif ( elem ) {\n\t\t\telem = elem[dir];\n\t\t\tvar match = false;\n\n\t\t\twhile ( elem ) {\n\t\t\t\tif ( elem.sizcache === doneName ) {\n\t\t\t\t\tmatch = checkSet[elem.sizset];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( elem.nodeType === 1 && !isXML ){\n\t\t\t\t\telem.sizcache = doneName;\n\t\t\t\t\telem.sizset = i;\n\t\t\t\t}\n\n\t\t\t\tif ( elem.nodeName.toLowerCase() === cur ) {\n\t\t\t\t\tmatch = elem;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\telem = elem[dir];\n\t\t\t}\n\n\t\t\tcheckSet[i] = match;\n\t\t}\n\t}\n}\n\nfunction dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n\tfor ( var i = 0, l = checkSet.length; i < l; i++ ) {\n\t\tvar elem = checkSet[i];\n\t\tif ( elem ) {\n\t\t\telem = elem[dir];\n\t\t\tvar match = false;\n\n\t\t\twhile ( elem ) {\n\t\t\t\tif ( elem.sizcache === doneName ) {\n\t\t\t\t\tmatch = checkSet[elem.sizset];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\tif ( !isXML ) {\n\t\t\t\t\t\telem.sizcache = doneName;\n\t\t\t\t\t\telem.sizset = i;\n\t\t\t\t\t}\n\t\t\t\t\tif ( typeof cur !== \"string\" ) {\n\t\t\t\t\t\tif ( elem === cur ) {\n\t\t\t\t\t\t\tmatch = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {\n\t\t\t\t\t\tmatch = elem;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\telem = elem[dir];\n\t\t\t}\n\n\t\t\tcheckSet[i] = match;\n\t\t}\n\t}\n}\n\nvar contains = document.compareDocumentPosition ? function(a, b){\n\treturn a.compareDocumentPosition(b) & 16;\n} : function(a, b){\n\treturn a !== b && (a.contains ? a.contains(b) : true);\n};\n\nvar isXML = function(elem){\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833) \n\tvar documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\nvar posProcess = function(selector, context){\n\tvar tmpSet = [], later = \"\", match,\n\t\troot = context.nodeType ? [context] : context;\n\n\t// Position selectors must be done after the filter\n\t// And so must :not(positional) so we move all PSEUDOs to the end\n\twhile ( (match = Expr.match.PSEUDO.exec( selector )) ) {\n\t\tlater += match[0];\n\t\tselector = selector.replace( Expr.match.PSEUDO, \"\" );\n\t}\n\n\tselector = Expr.relative[selector] ? selector + \"*\" : selector;\n\n\tfor ( var i = 0, l = root.length; i < l; i++ ) {\n\t\tSizzle( selector, root[i], tmpSet );\n\t}\n\n\treturn Sizzle.filter( later, tmpSet );\n};\n\n// EXPOSE\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[\":\"] = jQuery.expr.filters;\njQuery.unique = Sizzle.uniqueSort;\njQuery.getText = getText;\njQuery.isXMLDoc = isXML;\njQuery.contains = contains;\n\nreturn;\n\nwindow.Sizzle = Sizzle;\n\n})();\nvar runtil = /Until$/,\n\trparentsprev = /^(?:parents|prevUntil|prevAll)/,\n\t// Note: This RegExp should be improved, or likely pulled from Sizzle\n\trmultiselector = /,/,\n\tslice = Array.prototype.slice;\n\n// Implement the identical functionality for filter and not\nvar winnow = function( elements, qualifier, keep ) {\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep(elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) === keep;\n\t\t});\n\n\t} else if ( qualifier.nodeType ) {\n\t\treturn jQuery.grep(elements, function( elem, i ) {\n\t\t\treturn (elem === qualifier) === keep;\n\t\t});\n\n\t} else if ( typeof qualifier === \"string\" ) {\n\t\tvar filtered = jQuery.grep(elements, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t});\n\n\t\tif ( isSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter(qualifier, filtered, !keep);\n\t\t} else {\n\t\t\tqualifier = jQuery.filter( qualifier, filtered );\n\t\t}\n\t}\n\n\treturn jQuery.grep(elements, function( elem, i ) {\n\t\treturn (jQuery.inArray( elem, qualifier ) >= 0) === keep;\n\t});\n};\n\njQuery.fn.extend({\n\tfind: function( selector ) {\n\t\tvar ret = this.pushStack( \"\", \"find\", selector ), length = 0;\n\n\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\tlength = ret.length;\n\t\t\tjQuery.find( selector, this[i], ret );\n\n\t\t\tif ( i > 0 ) {\n\t\t\t\t// Make sure that the results are unique\n\t\t\t\tfor ( var n = length; n < ret.length; n++ ) {\n\t\t\t\t\tfor ( var r = 0; r < length; r++ ) {\n\t\t\t\t\t\tif ( ret[r] === ret[n] ) {\n\t\t\t\t\t\t\tret.splice(n--, 1);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\thas: function( target ) {\n\t\tvar targets = jQuery( target );\n\t\treturn this.filter(function() {\n\t\t\tfor ( var i = 0, l = targets.length; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[i] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t},\n\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, false), \"not\", selector);\n\t},\n\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, true), \"filter\", selector );\n\t},\n\t\n\tis: function( selector ) {\n\t\treturn !!selector && jQuery.filter( selector, this ).length > 0;\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tif ( jQuery.isArray( selectors ) ) {\n\t\t\tvar ret = [], cur = this[0], match, matches = {}, selector;\n\n\t\t\tif ( cur && selectors.length ) {\n\t\t\t\tfor ( var i = 0, l = selectors.length; i < l; i++ ) {\n\t\t\t\t\tselector = selectors[i];\n\n\t\t\t\t\tif ( !matches[selector] ) {\n\t\t\t\t\t\tmatches[selector] = jQuery.expr.match.POS.test( selector ) ? \n\t\t\t\t\t\t\tjQuery( selector, context || this.context ) :\n\t\t\t\t\t\t\tselector;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twhile ( cur && cur.ownerDocument && cur !== context ) {\n\t\t\t\t\tfor ( selector in matches ) {\n\t\t\t\t\t\tmatch = matches[selector];\n\n\t\t\t\t\t\tif ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {\n\t\t\t\t\t\t\tret.push({ selector: selector, elem: cur });\n\t\t\t\t\t\t\tdelete matches[selector];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcur = cur.parentNode;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ret;\n\t\t}\n\n\t\tvar pos = jQuery.expr.match.POS.test( selectors ) ? \n\t\t\tjQuery( selectors, context || this.context ) : null;\n\n\t\treturn this.map(function( i, cur ) {\n\t\t\twhile ( cur && cur.ownerDocument && cur !== context ) {\n\t\t\t\tif ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) {\n\t\t\t\t\treturn cur;\n\t\t\t\t}\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\treturn null;\n\t\t});\n\t},\n\t\n\t// Determine the position of an element within\n\t// the matched set of elements\n\tindex: function( elem ) {\n\t\tif ( !elem || typeof elem === \"string\" ) {\n\t\t\treturn jQuery.inArray( this[0],\n\t\t\t\t// If it receives a string, the selector is used\n\t\t\t\t// If it receives nothing, the siblings are used\n\t\t\t\telem ? jQuery( elem ) : this.parent().children() );\n\t\t}\n\t\t// Locate the position of the desired element\n\t\treturn jQuery.inArray(\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[0] : elem, this );\n\t},\n\n\tadd: function( selector, context ) {\n\t\tvar set = typeof selector === \"string\" ?\n\t\t\t\tjQuery( selector, context || this.context ) :\n\t\t\t\tjQuery.makeArray( selector ),\n\t\t\tall = jQuery.merge( this.get(), set );\n\n\t\treturn this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?\n\t\t\tall :\n\t\t\tjQuery.unique( all ) );\n\t},\n\n\tandSelf: function() {\n\t\treturn this.add( this.prevObject );\n\t}\n});\n\n// A painfully simple check to see if an element is disconnected\n// from a document (should be improved, where feasible).\nfunction isDisconnected( node ) {\n\treturn !node || !node.parentNode || node.parentNode.nodeType === 11;\n}\n\njQuery.each({\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn jQuery.dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn jQuery.nth( elem, 2, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn jQuery.nth( elem, 2, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn jQuery.sibling( elem.parentNode.firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn jQuery.sibling( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\treturn jQuery.nodeName( elem, \"iframe\" ) ?\n\t\t\telem.contentDocument || elem.contentWindow.document :\n\t\t\tjQuery.makeArray( elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar ret = jQuery.map( this, fn, until );\n\t\t\n\t\tif ( !runtil.test( name ) ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tret = jQuery.filter( selector, ret );\n\t\t}\n\n\t\tret = this.length > 1 ? jQuery.unique( ret ) : ret;\n\n\t\tif ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {\n\t\t\tret = ret.reverse();\n\t\t}\n\n\t\treturn this.pushStack( ret, name, slice.call(arguments).join(\",\") );\n\t};\n});\n\njQuery.extend({\n\tfilter: function( expr, elems, not ) {\n\t\tif ( not ) {\n\t\t\texpr = \":not(\" + expr + \")\";\n\t\t}\n\n\t\treturn jQuery.find.matches(expr, elems);\n\t},\n\t\n\tdir: function( elem, dir, until ) {\n\t\tvar matched = [], cur = elem[dir];\n\t\twhile ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {\n\t\t\tif ( cur.nodeType === 1 ) {\n\t\t\t\tmatched.push( cur );\n\t\t\t}\n\t\t\tcur = cur[dir];\n\t\t}\n\t\treturn matched;\n\t},\n\n\tnth: function( cur, result, dir, elem ) {\n\t\tresult = result || 1;\n\t\tvar num = 0;\n\n\t\tfor ( ; cur; cur = cur[dir] ) {\n\t\t\tif ( cur.nodeType === 1 && ++num === result ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn cur;\n\t},\n\n\tsibling: function( n, elem ) {\n\t\tvar r = [];\n\n\t\tfor ( ; n; n = n.nextSibling ) {\n\t\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\t\tr.push( n );\n\t\t\t}\n\t\t}\n\n\t\treturn r;\n\t}\n});\nvar rinlinejQuery = / jQuery\\d+=\"(?:\\d+|null)\"/g,\n\trleadingWhitespace = /^\\s+/,\n\trxhtmlTag = /(<([\\w:]+)[^>]*?)\\/>/g,\n\trselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,\n\trtagName = /<([\\w:]+)/,\n\trtbody = /<tbody/i,\n\trhtml = /<|&\\w+;/,\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,  // checked=\"checked\" or checked (html5)\n\tfcloseTag = function( all, front, tag ) {\n\t\treturn rselfClosing.test( tag ) ?\n\t\t\tall :\n\t\t\tfront + \"></\" + tag + \">\";\n\t},\n\twrapMap = {\n\t\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\t\tlegend: [ 1, \"<fieldset>\", \"</fieldset>\" ],\n\t\tthead: [ 1, \"<table>\", \"</table>\" ],\n\t\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\t\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\t\tcol: [ 2, \"<table><tbody></tbody><colgroup>\", \"</colgroup></table>\" ],\n\t\tarea: [ 1, \"<map>\", \"</map>\" ],\n\t\t_default: [ 0, \"\", \"\" ]\n\t};\n\nwrapMap.optgroup = wrapMap.option;\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// IE can't serialize <link> and <script> tags normally\nif ( !jQuery.support.htmlSerialize ) {\n\twrapMap._default = [ 1, \"div<div>\", \"</div>\" ];\n}\n\njQuery.fn.extend({\n\ttext: function( text ) {\n\t\tif ( jQuery.isFunction(text) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tvar self = jQuery(this);\n\t\t\t\tself.text( text.call(this, i, self.text()) );\n\t\t\t});\n\t\t}\n\n\t\tif ( typeof text !== \"object\" && text !== undefined ) {\n\t\t\treturn this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );\n\t\t}\n\n\t\treturn jQuery.getText( this );\n\t},\n\n\twrapAll: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tjQuery(this).wrapAll( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\tif ( this[0] ) {\n\t\t\t// The elements to wrap the target around\n\t\t\tvar wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);\n\n\t\t\tif ( this[0].parentNode ) {\n\t\t\t\twrap.insertBefore( this[0] );\n\t\t\t}\n\n\t\t\twrap.map(function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstChild && elem.firstChild.nodeType === 1 ) {\n\t\t\t\t\telem = elem.firstChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t}).append(this);\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tjQuery(this).wrapInner( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar self = jQuery( this ), contents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t});\n\t},\n\n\twrap: function( html ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery( this ).wrapAll( html );\n\t\t});\n\t},\n\n\tunwrap: function() {\n\t\treturn this.parent().each(function() {\n\t\t\tif ( !jQuery.nodeName( this, \"body\" ) ) {\n\t\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t\t}\n\t\t}).end();\n\t},\n\n\tappend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 ) {\n\t\t\t\tthis.appendChild( elem );\n\t\t\t}\n\t\t});\n\t},\n\n\tprepend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 ) {\n\t\t\t\tthis.insertBefore( elem, this.firstChild );\n\t\t\t}\n\t\t});\n\t},\n\n\tbefore: function() {\n\t\tif ( this[0] && this[0].parentNode ) {\n\t\t\treturn this.domManip(arguments, false, function( elem ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t});\n\t\t} else if ( arguments.length ) {\n\t\t\tvar set = jQuery(arguments[0]);\n\t\t\tset.push.apply( set, this.toArray() );\n\t\t\treturn this.pushStack( set, \"before\", arguments );\n\t\t}\n\t},\n\n\tafter: function() {\n\t\tif ( this[0] && this[0].parentNode ) {\n\t\t\treturn this.domManip(arguments, false, function( elem ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t});\n\t\t} else if ( arguments.length ) {\n\t\t\tvar set = this.pushStack( this, \"after\", arguments );\n\t\t\tset.push.apply( set, jQuery(arguments[0]).toArray() );\n\t\t\treturn set;\n\t\t}\n\t},\n\n\tclone: function( events ) {\n\t\t// Do the clone\n\t\tvar ret = this.map(function() {\n\t\t\tif ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {\n\t\t\t\t// IE copies events bound via attachEvent when\n\t\t\t\t// using cloneNode. Calling detachEvent on the\n\t\t\t\t// clone will also remove the events from the orignal\n\t\t\t\t// In order to get around this, we use innerHTML.\n\t\t\t\t// Unfortunately, this means some modifications to\n\t\t\t\t// attributes in IE that are actually only stored\n\t\t\t\t// as properties will not be copied (such as the\n\t\t\t\t// the name attribute on an input).\n\t\t\t\tvar html = this.outerHTML, ownerDocument = this.ownerDocument;\n\t\t\t\tif ( !html ) {\n\t\t\t\t\tvar div = ownerDocument.createElement(\"div\");\n\t\t\t\t\tdiv.appendChild( this.cloneNode(true) );\n\t\t\t\t\thtml = div.innerHTML;\n\t\t\t\t}\n\n\t\t\t\treturn jQuery.clean([html.replace(rinlinejQuery, \"\")\n\t\t\t\t\t.replace(rleadingWhitespace, \"\")], ownerDocument)[0];\n\t\t\t} else {\n\t\t\t\treturn this.cloneNode(true);\n\t\t\t}\n\t\t});\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( events === true ) {\n\t\t\tcloneCopyEvent( this, ret );\n\t\t\tcloneCopyEvent( this.find(\"*\"), ret.find(\"*\") );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn ret;\n\t},\n\n\thtml: function( value ) {\n\t\tif ( value === undefined ) {\n\t\t\treturn this[0] && this[0].nodeType === 1 ?\n\t\t\t\tthis[0].innerHTML.replace(rinlinejQuery, \"\") :\n\t\t\t\tnull;\n\n\t\t// See if we can take a shortcut and just use innerHTML\n\t\t} else if ( typeof value === \"string\" && !/<script/i.test( value ) &&\n\t\t\t(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&\n\t\t\t!wrapMap[ (rtagName.exec( value ) || [\"\", \"\"])[1].toLowerCase() ] ) {\n\n\t\t\tvalue = value.replace(rxhtmlTag, fcloseTag);\n\n\t\t\ttry {\n\t\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\tif ( this[i].nodeType === 1 ) {\n\t\t\t\t\t\tjQuery.cleanData( this[i].getElementsByTagName(\"*\") );\n\t\t\t\t\t\tthis[i].innerHTML = value;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t} catch(e) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\n\t\t} else if ( jQuery.isFunction( value ) ) {\n\t\t\tthis.each(function(i){\n\t\t\t\tvar self = jQuery(this), old = self.html();\n\t\t\t\tself.empty().append(function(){\n\t\t\t\t\treturn value.call( this, i, old );\n\t\t\t\t});\n\t\t\t});\n\n\t\t} else {\n\t\t\tthis.empty().append( value );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\treplaceWith: function( value ) {\n\t\tif ( this[0] && this[0].parentNode ) {\n\t\t\t// Make sure that the elements are removed from the DOM before they are inserted\n\t\t\t// this can help fix replacing a parent with child elements\n\t\t\tif ( !jQuery.isFunction( value ) ) {\n\t\t\t\tvalue = jQuery( value ).detach();\n\n\t\t\t} else {\n\t\t\t\treturn this.each(function(i) {\n\t\t\t\t\tvar self = jQuery(this), old = self.html();\n\t\t\t\t\tself.replaceWith( value.call( this, i, old ) );\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn this.each(function() {\n\t\t\t\tvar next = this.nextSibling, parent = this.parentNode;\n\n\t\t\t\tjQuery(this).remove();\n\n\t\t\t\tif ( next ) {\n\t\t\t\t\tjQuery(next).before( value );\n\t\t\t\t} else {\n\t\t\t\t\tjQuery(parent).append( value );\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\treturn this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), \"replaceWith\", value );\n\t\t}\n\t},\n\n\tdetach: function( selector ) {\n\t\treturn this.remove( selector, true );\n\t},\n\n\tdomManip: function( args, table, callback ) {\n\t\tvar results, first, value = args[0], scripts = [];\n\n\t\t// We can't cloneNode fragments that contain checked, in WebKit\n\t\tif ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === \"string\" && rchecked.test( value ) ) {\n\t\t\treturn this.each(function() {\n\t\t\t\tjQuery(this).domManip( args, table, callback, true );\n\t\t\t});\n\t\t}\n\n\t\tif ( jQuery.isFunction(value) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tvar self = jQuery(this);\n\t\t\t\targs[0] = value.call(this, i, table ? self.html() : undefined);\n\t\t\t\tself.domManip( args, table, callback );\n\t\t\t});\n\t\t}\n\n\t\tif ( this[0] ) {\n\t\t\t// If we're in a fragment, just use that instead of building a new one\n\t\t\tif ( args[0] && args[0].parentNode && args[0].parentNode.nodeType === 11 ) {\n\t\t\t\tresults = { fragment: args[0].parentNode };\n\t\t\t} else {\n\t\t\t\tresults = buildFragment( args, this, scripts );\n\t\t\t}\n\n\t\t\tfirst = results.fragment.firstChild;\n\n\t\t\tif ( first ) {\n\t\t\t\ttable = table && jQuery.nodeName( first, \"tr\" );\n\n\t\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\t\tcallback.call(\n\t\t\t\t\t\ttable ?\n\t\t\t\t\t\t\troot(this[i], first) :\n\t\t\t\t\t\t\tthis[i],\n\t\t\t\t\t\tresults.cacheable || this.length > 1 || i > 0 ?\n\t\t\t\t\t\t\tresults.fragment.cloneNode(true) :\n\t\t\t\t\t\t\tresults.fragment\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( scripts ) {\n\t\t\t\tjQuery.each( scripts, evalScript );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\n\t\tfunction root( elem, cur ) {\n\t\t\treturn jQuery.nodeName(elem, \"table\") ?\n\t\t\t\t(elem.getElementsByTagName(\"tbody\")[0] ||\n\t\t\t\telem.appendChild(elem.ownerDocument.createElement(\"tbody\"))) :\n\t\t\t\telem;\n\t\t}\n\t}\n});\n\nfunction cloneCopyEvent(orig, ret) {\n\tvar i = 0;\n\n\tret.each(function() {\n\t\tif ( this.nodeName !== (orig[i] && orig[i].nodeName) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar oldData = jQuery.data( orig[i++] ), curData = jQuery.data( this, oldData ), events = oldData && oldData.events;\n\n\t\tif ( events ) {\n\t\t\tdelete curData.handle;\n\t\t\tcurData.events = {};\n\n\t\t\tfor ( var type in events ) {\n\t\t\t\tfor ( var handler in events[ type ] ) {\n\t\t\t\t\tjQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction buildFragment( args, nodes, scripts ) {\n\tvar fragment, cacheable, cacheresults, doc;\n\n\t// webkit does not clone 'checked' attribute of radio inputs on cloneNode, so don't cache if string has a checked\n\tif ( args.length === 1 && typeof args[0] === \"string\" && args[0].length < 512 && args[0].indexOf(\"<option\") < 0 && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {\n\t\tcacheable = true;\n\t\tcacheresults = jQuery.fragments[ args[0] ];\n\t\tif ( cacheresults ) {\n\t\t\tif ( cacheresults !== 1 ) {\n\t\t\t\tfragment = cacheresults;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( !fragment ) {\n\t\tdoc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);\n\t\tfragment = doc.createDocumentFragment();\n\t\tjQuery.clean( args, doc, fragment, scripts );\n\t}\n\n\tif ( cacheable ) {\n\t\tjQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;\n\t}\n\n\treturn { fragment: fragment, cacheable: cacheable };\n}\n\njQuery.fragments = {};\n\njQuery.each({\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar ret = [], insert = jQuery( selector );\n\n\t\tfor ( var i = 0, l = insert.length; i < l; i++ ) {\n\t\t\tvar elems = (i > 0 ? this.clone(true) : this).get();\n\t\t\tjQuery.fn[ original ].apply( jQuery(insert[i]), elems );\n\t\t\tret = ret.concat( elems );\n\t\t}\n\t\treturn this.pushStack( ret, name, insert.selector );\n\t};\n});\n\njQuery.each({\n\t// keepData is for internal use only--do not document\n\tremove: function( selector, keepData ) {\n\t\tif ( !selector || jQuery.filter( selector, [ this ] ).length ) {\n\t\t\tif ( !keepData && this.nodeType === 1 ) {\n\t\t\t\tjQuery.cleanData( this.getElementsByTagName(\"*\") );\n\t\t\t\tjQuery.cleanData( [ this ] );\n\t\t\t}\n\n\t\t\tif ( this.parentNode ) {\n\t\t\t\t this.parentNode.removeChild( this );\n\t\t\t}\n\t\t}\n\t},\n\n\tempty: function() {\n\t\t// Remove element nodes and prevent memory leaks\n\t\tif ( this.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( this.getElementsByTagName(\"*\") );\n\t\t}\n\n\t\t// Remove any remaining nodes\n\t\twhile ( this.firstChild ) {\n\t\t\tthis.removeChild( this.firstChild );\n\t\t}\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function() {\n\t\treturn this.each( fn, arguments );\n\t};\n});\n\njQuery.extend({\n\tclean: function( elems, context, fragment, scripts ) {\n\t\tcontext = context || document;\n\n\t\t// !context.createElement fails in IE with an error but returns typeof 'object'\n\t\tif ( typeof context.createElement === \"undefined\" ) {\n\t\t\tcontext = context.ownerDocument || context[0] && context[0].ownerDocument || document;\n\t\t}\n\n\t\tvar ret = [];\n\n\t\tjQuery.each(elems, function( i, elem ) {\n\t\t\tif ( typeof elem === \"number\" ) {\n\t\t\t\telem += \"\";\n\t\t\t}\n\n\t\t\tif ( !elem ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Convert html string into DOM nodes\n\t\t\tif ( typeof elem === \"string\" && !rhtml.test( elem ) ) {\n\t\t\t\telem = context.createTextNode( elem );\n\n\t\t\t} else if ( typeof elem === \"string\" ) {\n\t\t\t\t// Fix \"XHTML\"-style tags in all browsers\n\t\t\t\telem = elem.replace(rxhtmlTag, fcloseTag);\n\n\t\t\t\t// Trim whitespace, otherwise indexOf won't work as expected\n\t\t\t\tvar tag = (rtagName.exec( elem ) || [\"\", \"\"])[1].toLowerCase(),\n\t\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default,\n\t\t\t\t\tdepth = wrap[0],\n\t\t\t\t\tdiv = context.createElement(\"div\");\n\n\t\t\t\t// Go to html and back, then peel off extra wrappers\n\t\t\t\tdiv.innerHTML = wrap[1] + elem + wrap[2];\n\n\t\t\t\t// Move to the right depth\n\t\t\t\twhile ( depth-- ) {\n\t\t\t\t\tdiv = div.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Remove IE's autoinserted <tbody> from table fragments\n\t\t\t\tif ( !jQuery.support.tbody ) {\n\n\t\t\t\t\t// String was a <table>, *may* have spurious <tbody>\n\t\t\t\t\tvar hasBody = rtbody.test(elem),\n\t\t\t\t\t\ttbody = tag === \"table\" && !hasBody ?\n\t\t\t\t\t\t\tdiv.firstChild && div.firstChild.childNodes :\n\n\t\t\t\t\t\t\t// String was a bare <thead> or <tfoot>\n\t\t\t\t\t\t\twrap[1] === \"<table>\" && !hasBody ?\n\t\t\t\t\t\t\t\tdiv.childNodes :\n\t\t\t\t\t\t\t\t[];\n\n\t\t\t\t\tfor ( var j = tbody.length - 1; j >= 0 ; --j ) {\n\t\t\t\t\t\tif ( jQuery.nodeName( tbody[ j ], \"tbody\" ) && !tbody[ j ].childNodes.length ) {\n\t\t\t\t\t\t\ttbody[ j ].parentNode.removeChild( tbody[ j ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// IE completely kills leading whitespace when innerHTML is used\n\t\t\t\tif ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {\n\t\t\t\t\tdiv.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );\n\t\t\t\t}\n\n\t\t\t\telem = jQuery.makeArray( div.childNodes );\n\t\t\t}\n\n\t\t\tif ( elem.nodeType ) {\n\t\t\t\tret.push( elem );\n\t\t\t} else {\n\t\t\t\tret = jQuery.merge( ret, elem );\n\t\t\t}\n\n\t\t});\n\n\t\tif ( fragment ) {\n\t\t\tfor ( var i = 0; ret[i]; i++ ) {\n\t\t\t\tif ( scripts && jQuery.nodeName( ret[i], \"script\" ) && (!ret[i].type || ret[i].type.toLowerCase() === \"text/javascript\") ) {\n\t\t\t\t\tscripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );\n\t\t\t\t} else {\n\t\t\t\t\tif ( ret[i].nodeType === 1 ) {\n\t\t\t\t\t\tret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName(\"script\"))) );\n\t\t\t\t\t}\n\t\t\t\t\tfragment.appendChild( ret[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\t\n\tcleanData: function( elems ) {\n\t\tfor ( var i = 0, elem, id; (elem = elems[i]) != null; i++ ) {\n\t\t\tjQuery.event.remove( elem );\n\t\t\tjQuery.removeData( elem );\n\t\t}\n\t}\n});\n// exclude the following css properties to add px\nvar rexclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,\n\tralpha = /alpha\\([^)]*\\)/,\n\tropacity = /opacity=([^)]*)/,\n\trfloat = /float/i,\n\trdashAlpha = /-([a-z])/ig,\n\trupper = /([A-Z])/g,\n\trnumpx = /^-?\\d+(?:px)?$/i,\n\trnum = /^-?\\d/,\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display:\"block\" },\n\tcssWidth = [ \"Left\", \"Right\" ],\n\tcssHeight = [ \"Top\", \"Bottom\" ],\n\n\t// cache check for defaultView.getComputedStyle\n\tgetComputedStyle = document.defaultView && document.defaultView.getComputedStyle,\n\t// normalize float css property\n\tstyleFloat = jQuery.support.cssFloat ? \"cssFloat\" : \"styleFloat\",\n\tfcamelCase = function( all, letter ) {\n\t\treturn letter.toUpperCase();\n\t};\n\njQuery.fn.css = function( name, value ) {\n\treturn access( this, name, value, true, function( elem, name, value ) {\n\t\tif ( value === undefined ) {\n\t\t\treturn jQuery.curCSS( elem, name );\n\t\t}\n\t\t\n\t\tif ( typeof value === \"number\" && !rexclude.test(name) ) {\n\t\t\tvalue += \"px\";\n\t\t}\n\n\t\tjQuery.style( elem, name, value );\n\t});\n};\n\njQuery.extend({\n\tstyle: function( elem, name, value ) {\n\t\t// don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// ignore negative width and height values #1599\n\t\tif ( (name === \"width\" || name === \"height\") && parseFloat(value) < 0 ) {\n\t\t\tvalue = undefined;\n\t\t}\n\n\t\tvar style = elem.style || elem, set = value !== undefined;\n\n\t\t// IE uses filters for opacity\n\t\tif ( !jQuery.support.opacity && name === \"opacity\" ) {\n\t\t\tif ( set ) {\n\t\t\t\t// IE has trouble with opacity if it does not have layout\n\t\t\t\t// Force it by setting the zoom level\n\t\t\t\tstyle.zoom = 1;\n\n\t\t\t\t// Set the alpha filter to set the opacity\n\t\t\t\tvar opacity = parseInt( value, 10 ) + \"\" === \"NaN\" ? \"\" : \"alpha(opacity=\" + value * 100 + \")\";\n\t\t\t\tvar filter = style.filter || jQuery.curCSS( elem, \"filter\" ) || \"\";\n\t\t\t\tstyle.filter = ralpha.test(filter) ? filter.replace(ralpha, opacity) : opacity;\n\t\t\t}\n\n\t\t\treturn style.filter && style.filter.indexOf(\"opacity=\") >= 0 ?\n\t\t\t\t(parseFloat( ropacity.exec(style.filter)[1] ) / 100) + \"\":\n\t\t\t\t\"\";\n\t\t}\n\n\t\t// Make sure we're using the right name for getting the float value\n\t\tif ( rfloat.test( name ) ) {\n\t\t\tname = styleFloat;\n\t\t}\n\n\t\tname = name.replace(rdashAlpha, fcamelCase);\n\n\t\tif ( set ) {\n\t\t\tstyle[ name ] = value;\n\t\t}\n\n\t\treturn style[ name ];\n\t},\n\n\tcss: function( elem, name, force, extra ) {\n\t\tif ( name === \"width\" || name === \"height\" ) {\n\t\t\tvar val, props = cssShow, which = name === \"width\" ? cssWidth : cssHeight;\n\n\t\t\tfunction getWH() {\n\t\t\t\tval = name === \"width\" ? elem.offsetWidth : elem.offsetHeight;\n\n\t\t\t\tif ( extra === \"border\" ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tjQuery.each( which, function() {\n\t\t\t\t\tif ( !extra ) {\n\t\t\t\t\t\tval -= parseFloat(jQuery.curCSS( elem, \"padding\" + this, true)) || 0;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( extra === \"margin\" ) {\n\t\t\t\t\t\tval += parseFloat(jQuery.curCSS( elem, \"margin\" + this, true)) || 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tval -= parseFloat(jQuery.curCSS( elem, \"border\" + this + \"Width\", true)) || 0;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif ( elem.offsetWidth !== 0 ) {\n\t\t\t\tgetWH();\n\t\t\t} else {\n\t\t\t\tjQuery.swap( elem, props, getWH );\n\t\t\t}\n\n\t\t\treturn Math.max(0, Math.round(val));\n\t\t}\n\n\t\treturn jQuery.curCSS( elem, name, force );\n\t},\n\n\tcurCSS: function( elem, name, force ) {\n\t\tvar ret, style = elem.style, filter;\n\n\t\t// IE uses filters for opacity\n\t\tif ( !jQuery.support.opacity && name === \"opacity\" && elem.currentStyle ) {\n\t\t\tret = ropacity.test(elem.currentStyle.filter || \"\") ?\n\t\t\t\t(parseFloat(RegExp.$1) / 100) + \"\" :\n\t\t\t\t\"\";\n\n\t\t\treturn ret === \"\" ?\n\t\t\t\t\"1\" :\n\t\t\t\tret;\n\t\t}\n\n\t\t// Make sure we're using the right name for getting the float value\n\t\tif ( rfloat.test( name ) ) {\n\t\t\tname = styleFloat;\n\t\t}\n\n\t\tif ( !force && style && style[ name ] ) {\n\t\t\tret = style[ name ];\n\n\t\t} else if ( getComputedStyle ) {\n\n\t\t\t// Only \"float\" is needed here\n\t\t\tif ( rfloat.test( name ) ) {\n\t\t\t\tname = \"float\";\n\t\t\t}\n\n\t\t\tname = name.replace( rupper, \"-$1\" ).toLowerCase();\n\n\t\t\tvar defaultView = elem.ownerDocument.defaultView;\n\n\t\t\tif ( !defaultView ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tvar computedStyle = defaultView.getComputedStyle( elem, null );\n\n\t\t\tif ( computedStyle ) {\n\t\t\t\tret = computedStyle.getPropertyValue( name );\n\t\t\t}\n\n\t\t\t// We should always get a number back from opacity\n\t\t\tif ( name === \"opacity\" && ret === \"\" ) {\n\t\t\t\tret = \"1\";\n\t\t\t}\n\n\t\t} else if ( elem.currentStyle ) {\n\t\t\tvar camelCase = name.replace(rdashAlpha, fcamelCase);\n\n\t\t\tret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];\n\n\t\t\t// From the awesome hack by Dean Edwards\n\t\t\t// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291\n\n\t\t\t// If we're not dealing with a regular pixel number\n\t\t\t// but a number that has a weird ending, we need to convert it to pixels\n\t\t\tif ( !rnumpx.test( ret ) && rnum.test( ret ) ) {\n\t\t\t\t// Remember the original values\n\t\t\t\tvar left = style.left, rsLeft = elem.runtimeStyle.left;\n\n\t\t\t\t// Put in the new values to get a computed value out\n\t\t\t\telem.runtimeStyle.left = elem.currentStyle.left;\n\t\t\t\tstyle.left = camelCase === \"fontSize\" ? \"1em\" : (ret || 0);\n\t\t\t\tret = style.pixelLeft + \"px\";\n\n\t\t\t\t// Revert the changed values\n\t\t\t\tstyle.left = left;\n\t\t\t\telem.runtimeStyle.left = rsLeft;\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\t// A method for quickly swapping in/out CSS properties to get correct calculations\n\tswap: function( elem, options, callback ) {\n\t\tvar old = {};\n\n\t\t// Remember the old values, and insert the new ones\n\t\tfor ( var name in options ) {\n\t\t\told[ name ] = elem.style[ name ];\n\t\t\telem.style[ name ] = options[ name ];\n\t\t}\n\n\t\tcallback.call( elem );\n\n\t\t// Revert the old values\n\t\tfor ( var name in options ) {\n\t\t\telem.style[ name ] = old[ name ];\n\t\t}\n\t}\n});\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.hidden = function( elem ) {\n\t\tvar width = elem.offsetWidth, height = elem.offsetHeight,\n\t\t\tskip = elem.nodeName.toLowerCase() === \"tr\";\n\n\t\treturn width === 0 && height === 0 && !skip ?\n\t\t\ttrue :\n\t\t\twidth > 0 && height > 0 && !skip ?\n\t\t\t\tfalse :\n\t\t\t\tjQuery.curCSS(elem, \"display\") === \"none\";\n\t};\n\n\tjQuery.expr.filters.visible = function( elem ) {\n\t\treturn !jQuery.expr.filters.hidden( elem );\n\t};\n}\nvar jsc = now(),\n\trscript = /<script(.|\\s)*?\\/script>/gi,\n\trselectTextarea = /select|textarea/i,\n\trinput = /color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,\n\tjsre = /=\\?(&|$)/,\n\trquery = /\\?/,\n\trts = /(\\?|&)_=.*?(&|$)/,\n\trurl = /^(\\w+:)?\\/\\/([^\\/?#]+)/,\n\tr20 = /%20/g;\n\njQuery.fn.extend({\n\t// Keep a copy of the old load\n\t_load: jQuery.fn.load,\n\n\tload: function( url, params, callback ) {\n\t\tif ( typeof url !== \"string\" ) {\n\t\t\treturn this._load( url );\n\n\t\t// Don't do a request if no elements are being requested\n\t\t} else if ( !this.length ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tvar off = url.indexOf(\" \");\n\t\tif ( off >= 0 ) {\n\t\t\tvar selector = url.slice(off, url.length);\n\t\t\turl = url.slice(0, off);\n\t\t}\n\n\t\t// Default to a GET request\n\t\tvar type = \"GET\";\n\n\t\t// If the second parameter was provided\n\t\tif ( params ) {\n\t\t\t// If it's a function\n\t\t\tif ( jQuery.isFunction( params ) ) {\n\t\t\t\t// We assume that it's the callback\n\t\t\t\tcallback = params;\n\t\t\t\tparams = null;\n\n\t\t\t// Otherwise, build a param string\n\t\t\t} else if ( typeof params === \"object\" ) {\n\t\t\t\tparams = jQuery.param( params, jQuery.ajaxSettings.traditional );\n\t\t\t\ttype = \"POST\";\n\t\t\t}\n\t\t}\n\n\t\tvar self = this;\n\n\t\t// Request the remote document\n\t\tjQuery.ajax({\n\t\t\turl: url,\n\t\t\ttype: type,\n\t\t\tdataType: \"html\",\n\t\t\tdata: params,\n\t\t\tcomplete: function( res, status ) {\n\t\t\t\t// If successful, inject the HTML into all the matched elements\n\t\t\t\tif ( status === \"success\" || status === \"notmodified\" ) {\n\t\t\t\t\t// See if a selector was specified\n\t\t\t\t\tself.html( selector ?\n\t\t\t\t\t\t// Create a dummy div to hold the results\n\t\t\t\t\t\tjQuery(\"<div />\")\n\t\t\t\t\t\t\t// inject the contents of the document in, removing the scripts\n\t\t\t\t\t\t\t// to avoid any 'Permission Denied' errors in IE\n\t\t\t\t\t\t\t.append(res.responseText.replace(rscript, \"\"))\n\n\t\t\t\t\t\t\t// Locate the specified elements\n\t\t\t\t\t\t\t.find(selector) :\n\n\t\t\t\t\t\t// If not, just inject the full result\n\t\t\t\t\t\tres.responseText );\n\t\t\t\t}\n\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tself.each( callback, [res.responseText, status, res] );\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn this;\n\t},\n\n\tserialize: function() {\n\t\treturn jQuery.param(this.serializeArray());\n\t},\n\tserializeArray: function() {\n\t\treturn this.map(function() {\n\t\t\treturn this.elements ? jQuery.makeArray(this.elements) : this;\n\t\t})\n\t\t.filter(function() {\n\t\t\treturn this.name && !this.disabled &&\n\t\t\t\t(this.checked || rselectTextarea.test(this.nodeName) ||\n\t\t\t\t\trinput.test(this.type));\n\t\t})\n\t\t.map(function( i, elem ) {\n\t\t\tvar val = jQuery(this).val();\n\n\t\t\treturn val == null ?\n\t\t\t\tnull :\n\t\t\t\tjQuery.isArray(val) ?\n\t\t\t\t\tjQuery.map( val, function( val, i ) {\n\t\t\t\t\t\treturn { name: elem.name, value: val };\n\t\t\t\t\t}) :\n\t\t\t\t\t{ name: elem.name, value: val };\n\t\t}).get();\n\t}\n});\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( \"ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend\".split(\" \"), function( i, o ) {\n\tjQuery.fn[o] = function( f ) {\n\t\treturn this.bind(o, f);\n\t};\n});\n\njQuery.extend({\n\n\tget: function( url, data, callback, type ) {\n\t\t// shift arguments if data argument was omited\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = null;\n\t\t}\n\n\t\treturn jQuery.ajax({\n\t\t\ttype: \"GET\",\n\t\t\turl: url,\n\t\t\tdata: data,\n\t\t\tsuccess: callback,\n\t\t\tdataType: type\n\t\t});\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get(url, null, callback, \"script\");\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get(url, data, callback, \"json\");\n\t},\n\n\tpost: function( url, data, callback, type ) {\n\t\t// shift arguments if data argument was omited\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = {};\n\t\t}\n\n\t\treturn jQuery.ajax({\n\t\t\ttype: \"POST\",\n\t\t\turl: url,\n\t\t\tdata: data,\n\t\t\tsuccess: callback,\n\t\t\tdataType: type\n\t\t});\n\t},\n\n\tajaxSetup: function( settings ) {\n\t\tjQuery.extend( jQuery.ajaxSettings, settings );\n\t},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\tglobal: true,\n\t\ttype: \"GET\",\n\t\tcontentType: \"application/x-www-form-urlencoded\",\n\t\tprocessData: true,\n\t\tasync: true,\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\ttraditional: false,\n\t\t*/\n\t\t// Create the request object; Microsoft failed to properly\n\t\t// implement the XMLHttpRequest in IE7 (can't request local files),\n\t\t// so we use the ActiveXObject when it is available\n\t\t// This function can be overriden by calling jQuery.ajaxSetup\n\t\txhr: window.XMLHttpRequest && (window.location.protocol !== \"file:\" || !window.ActiveXObject) ?\n\t\t\tfunction() {\n\t\t\t\treturn new window.XMLHttpRequest();\n\t\t\t} :\n\t\t\tfunction() {\n\t\t\t\ttry {\n\t\t\t\t\treturn new window.ActiveXObject(\"Microsoft.XMLHTTP\");\n\t\t\t\t} catch(e) {}\n\t\t\t},\n\t\taccepts: {\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\thtml: \"text/html\",\n\t\t\tscript: \"text/javascript, application/javascript\",\n\t\t\tjson: \"application/json, text/javascript\",\n\t\t\ttext: \"text/plain\",\n\t\t\t_default: \"*/*\"\n\t\t}\n\t},\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajax: function( origSettings ) {\n\t\tvar s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings);\n\t\t\n\t\tvar jsonp, status, data,\n\t\t\tcallbackContext = origSettings && origSettings.context || s,\n\t\t\ttype = s.type.toUpperCase();\n\n\t\t// convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Handle JSONP Parameter Callbacks\n\t\tif ( s.dataType === \"jsonp\" ) {\n\t\t\tif ( type === \"GET\" ) {\n\t\t\t\tif ( !jsre.test( s.url ) ) {\n\t\t\t\t\ts.url += (rquery.test( s.url ) ? \"&\" : \"?\") + (s.jsonp || \"callback\") + \"=?\";\n\t\t\t\t}\n\t\t\t} else if ( !s.data || !jsre.test(s.data) ) {\n\t\t\t\ts.data = (s.data ? s.data + \"&\" : \"\") + (s.jsonp || \"callback\") + \"=?\";\n\t\t\t}\n\t\t\ts.dataType = \"json\";\n\t\t}\n\n\t\t// Build temporary JSONP function\n\t\tif ( s.dataType === \"json\" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {\n\t\t\tjsonp = s.jsonpCallback || (\"jsonp\" + jsc++);\n\n\t\t\t// Replace the =? sequence both in the query string and the data\n\t\t\tif ( s.data ) {\n\t\t\t\ts.data = (s.data + \"\").replace(jsre, \"=\" + jsonp + \"$1\");\n\t\t\t}\n\n\t\t\ts.url = s.url.replace(jsre, \"=\" + jsonp + \"$1\");\n\n\t\t\t// We need to make sure\n\t\t\t// that a JSONP style response is executed properly\n\t\t\ts.dataType = \"script\";\n\n\t\t\t// Handle JSONP-style loading\n\t\t\twindow[ jsonp ] = window[ jsonp ] || function( tmp ) {\n\t\t\t\tdata = tmp;\n\t\t\t\tsuccess();\n\t\t\t\tcomplete();\n\t\t\t\t// Garbage collect\n\t\t\t\twindow[ jsonp ] = undefined;\n\n\t\t\t\ttry {\n\t\t\t\t\tdelete window[ jsonp ];\n\t\t\t\t} catch(e) {}\n\n\t\t\t\tif ( head ) {\n\t\t\t\t\thead.removeChild( script );\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tif ( s.dataType === \"script\" && s.cache === null ) {\n\t\t\ts.cache = false;\n\t\t}\n\n\t\tif ( s.cache === false && type === \"GET\" ) {\n\t\t\tvar ts = now();\n\n\t\t\t// try replacing _= if it is there\n\t\t\tvar ret = s.url.replace(rts, \"$1_=\" + ts + \"$2\");\n\n\t\t\t// if nothing was replaced, add timestamp to the end\n\t\t\ts.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? \"&\" : \"?\") + \"_=\" + ts : \"\");\n\t\t}\n\n\t\t// If data is available, append data to url for get requests\n\t\tif ( s.data && type === \"GET\" ) {\n\t\t\ts.url += (rquery.test(s.url) ? \"&\" : \"?\") + s.data;\n\t\t}\n\n\t\t// Watch for a new set of requests\n\t\tif ( s.global && ! jQuery.active++ ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Matches an absolute URL, and saves the domain\n\t\tvar parts = rurl.exec( s.url ),\n\t\t\tremote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);\n\n\t\t// If we're requesting a remote document\n\t\t// and trying to load JSON or Script with a GET\n\t\tif ( s.dataType === \"script\" && type === \"GET\" && remote ) {\n\t\t\tvar head = document.getElementsByTagName(\"head\")[0] || document.documentElement;\n\t\t\tvar script = document.createElement(\"script\");\n\t\t\tscript.src = s.url;\n\t\t\tif ( s.scriptCharset ) {\n\t\t\t\tscript.charset = s.scriptCharset;\n\t\t\t}\n\n\t\t\t// Handle Script loading\n\t\t\tif ( !jsonp ) {\n\t\t\t\tvar done = false;\n\n\t\t\t\t// Attach handlers for all browsers\n\t\t\t\tscript.onload = script.onreadystatechange = function() {\n\t\t\t\t\tif ( !done && (!this.readyState ||\n\t\t\t\t\t\t\tthis.readyState === \"loaded\" || this.readyState === \"complete\") ) {\n\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\tsuccess();\n\t\t\t\t\t\tcomplete();\n\n\t\t\t\t\t\t// Handle memory leak in IE\n\t\t\t\t\t\tscript.onload = script.onreadystatechange = null;\n\t\t\t\t\t\tif ( head && script.parentNode ) {\n\t\t\t\t\t\t\thead.removeChild( script );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Use insertBefore instead of appendChild  to circumvent an IE6 bug.\n\t\t\t// This arises when a base node is used (#2709 and #4378).\n\t\t\thead.insertBefore( script, head.firstChild );\n\n\t\t\t// We handle everything using the script element injection\n\t\t\treturn undefined;\n\t\t}\n\n\t\tvar requestDone = false;\n\n\t\t// Create the request object\n\t\tvar xhr = s.xhr();\n\n\t\tif ( !xhr ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Open the socket\n\t\t// Passing null username, generates a login popup on Opera (#2865)\n\t\tif ( s.username ) {\n\t\t\txhr.open(type, s.url, s.async, s.username, s.password);\n\t\t} else {\n\t\t\txhr.open(type, s.url, s.async);\n\t\t}\n\n\t\t// Need an extra try/catch for cross domain requests in Firefox 3\n\t\ttry {\n\t\t\t// Set the correct header, if data is being sent\n\t\t\tif ( s.data || origSettings && origSettings.contentType ) {\n\t\t\t\txhr.setRequestHeader(\"Content-Type\", s.contentType);\n\t\t\t}\n\n\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\tif ( s.ifModified ) {\n\t\t\t\tif ( jQuery.lastModified[s.url] ) {\n\t\t\t\t\txhr.setRequestHeader(\"If-Modified-Since\", jQuery.lastModified[s.url]);\n\t\t\t\t}\n\n\t\t\t\tif ( jQuery.etag[s.url] ) {\n\t\t\t\t\txhr.setRequestHeader(\"If-None-Match\", jQuery.etag[s.url]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set header so the called script knows that it's an XMLHttpRequest\n\t\t\t// Only send the header if it's not a remote XHR\n\t\t\tif ( !remote ) {\n\t\t\t\txhr.setRequestHeader(\"X-Requested-With\", \"XMLHttpRequest\");\n\t\t\t}\n\n\t\t\t// Set the Accepts header for the server, depending on the dataType\n\t\t\txhr.setRequestHeader(\"Accept\", s.dataType && s.accepts[ s.dataType ] ?\n\t\t\t\ts.accepts[ s.dataType ] + \", */*\" :\n\t\t\t\ts.accepts._default );\n\t\t} catch(e) {}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend && s.beforeSend.call(callbackContext, xhr, s) === false ) {\n\t\t\t// Handle the global AJAX counter\n\t\t\tif ( s.global && ! --jQuery.active ) {\n\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t}\n\n\t\t\t// close opended socket\n\t\t\txhr.abort();\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( s.global ) {\n\t\t\ttrigger(\"ajaxSend\", [xhr, s]);\n\t\t}\n\n\t\t// Wait for a response to come back\n\t\tvar onreadystatechange = xhr.onreadystatechange = function( isTimeout ) {\n\t\t\t// The request was aborted\n\t\t\tif ( !xhr || xhr.readyState === 0 || isTimeout === \"abort\" ) {\n\t\t\t\t// Opera doesn't call onreadystatechange before this point\n\t\t\t\t// so we simulate the call\n\t\t\t\tif ( !requestDone ) {\n\t\t\t\t\tcomplete();\n\t\t\t\t}\n\n\t\t\t\trequestDone = true;\n\t\t\t\tif ( xhr ) {\n\t\t\t\t\txhr.onreadystatechange = jQuery.noop;\n\t\t\t\t}\n\n\t\t\t// The transfer is complete and the data is available, or the request timed out\n\t\t\t} else if ( !requestDone && xhr && (xhr.readyState === 4 || isTimeout === \"timeout\") ) {\n\t\t\t\trequestDone = true;\n\t\t\t\txhr.onreadystatechange = jQuery.noop;\n\n\t\t\t\tstatus = isTimeout === \"timeout\" ?\n\t\t\t\t\t\"timeout\" :\n\t\t\t\t\t!jQuery.httpSuccess( xhr ) ?\n\t\t\t\t\t\t\"error\" :\n\t\t\t\t\t\ts.ifModified && jQuery.httpNotModified( xhr, s.url ) ?\n\t\t\t\t\t\t\t\"notmodified\" :\n\t\t\t\t\t\t\t\"success\";\n\n\t\t\t\tvar errMsg;\n\n\t\t\t\tif ( status === \"success\" ) {\n\t\t\t\t\t// Watch for, and catch, XML document parse errors\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// process the data (runs the xml through httpData regardless of callback)\n\t\t\t\t\t\tdata = jQuery.httpData( xhr, s.dataType, s );\n\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\tstatus = \"parsererror\";\n\t\t\t\t\t\terrMsg = err;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Make sure that the request was successful or notmodified\n\t\t\t\tif ( status === \"success\" || status === \"notmodified\" ) {\n\t\t\t\t\t// JSONP handles its own success callback\n\t\t\t\t\tif ( !jsonp ) {\n\t\t\t\t\t\tsuccess();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tjQuery.handleError(s, xhr, status, errMsg);\n\t\t\t\t}\n\n\t\t\t\t// Fire the complete handlers\n\t\t\t\tcomplete();\n\n\t\t\t\tif ( isTimeout === \"timeout\" ) {\n\t\t\t\t\txhr.abort();\n\t\t\t\t}\n\n\t\t\t\t// Stop memory leaks\n\t\t\t\tif ( s.async ) {\n\t\t\t\t\txhr = null;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Override the abort handler, if we can (IE doesn't allow it, but that's OK)\n\t\t// Opera doesn't fire onreadystatechange at all on abort\n\t\ttry {\n\t\t\tvar oldAbort = xhr.abort;\n\t\t\txhr.abort = function() {\n\t\t\t\tif ( xhr ) {\n\t\t\t\t\toldAbort.call( xhr );\n\t\t\t\t}\n\n\t\t\t\tonreadystatechange( \"abort\" );\n\t\t\t};\n\t\t} catch(e) { }\n\n\t\t// Timeout checker\n\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\tsetTimeout(function() {\n\t\t\t\t// Check to see if the request is still happening\n\t\t\t\tif ( xhr && !requestDone ) {\n\t\t\t\t\tonreadystatechange( \"timeout\" );\n\t\t\t\t}\n\t\t\t}, s.timeout);\n\t\t}\n\n\t\t// Send the data\n\t\ttry {\n\t\t\txhr.send( type === \"POST\" || type === \"PUT\" || type === \"DELETE\" ? s.data : null );\n\t\t} catch(e) {\n\t\t\tjQuery.handleError(s, xhr, null, e);\n\t\t\t// Fire the complete handlers\n\t\t\tcomplete();\n\t\t}\n\n\t\t// firefox 1.5 doesn't fire statechange for sync requests\n\t\tif ( !s.async ) {\n\t\t\tonreadystatechange();\n\t\t}\n\n\t\tfunction success() {\n\t\t\t// If a local callback was specified, fire it and pass it the data\n\t\t\tif ( s.success ) {\n\t\t\t\ts.success.call( callbackContext, data, status, xhr );\n\t\t\t}\n\n\t\t\t// Fire the global callback\n\t\t\tif ( s.global ) {\n\t\t\t\ttrigger( \"ajaxSuccess\", [xhr, s] );\n\t\t\t}\n\t\t}\n\n\t\tfunction complete() {\n\t\t\t// Process result\n\t\t\tif ( s.complete ) {\n\t\t\t\ts.complete.call( callbackContext, xhr, status);\n\t\t\t}\n\n\t\t\t// The request was completed\n\t\t\tif ( s.global ) {\n\t\t\t\ttrigger( \"ajaxComplete\", [xhr, s] );\n\t\t\t}\n\n\t\t\t// Handle the global AJAX counter\n\t\t\tif ( s.global && ! --jQuery.active ) {\n\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t}\n\t\t}\n\t\t\n\t\tfunction trigger(type, args) {\n\t\t\t(s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);\n\t\t}\n\n\t\t// return XMLHttpRequest to allow aborting the request etc.\n\t\treturn xhr;\n\t},\n\n\thandleError: function( s, xhr, status, e ) {\n\t\t// If a local callback was specified, fire it\n\t\tif ( s.error ) {\n\t\t\ts.error.call( s.context || s, xhr, status, e );\n\t\t}\n\n\t\t// Fire the global callback\n\t\tif ( s.global ) {\n\t\t\t(s.context ? jQuery(s.context) : jQuery.event).trigger( \"ajaxError\", [xhr, s, e] );\n\t\t}\n\t},\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Determines if an XMLHttpRequest was successful or not\n\thttpSuccess: function( xhr ) {\n\t\ttry {\n\t\t\t// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450\n\t\t\treturn !xhr.status && location.protocol === \"file:\" ||\n\t\t\t\t// Opera returns 0 when status is 304\n\t\t\t\t( xhr.status >= 200 && xhr.status < 300 ) ||\n\t\t\t\txhr.status === 304 || xhr.status === 1223 || xhr.status === 0;\n\t\t} catch(e) {}\n\n\t\treturn false;\n\t},\n\n\t// Determines if an XMLHttpRequest returns NotModified\n\thttpNotModified: function( xhr, url ) {\n\t\tvar lastModified = xhr.getResponseHeader(\"Last-Modified\"),\n\t\t\tetag = xhr.getResponseHeader(\"Etag\");\n\n\t\tif ( lastModified ) {\n\t\t\tjQuery.lastModified[url] = lastModified;\n\t\t}\n\n\t\tif ( etag ) {\n\t\t\tjQuery.etag[url] = etag;\n\t\t}\n\n\t\t// Opera returns 0 when status is 304\n\t\treturn xhr.status === 304 || xhr.status === 0;\n\t},\n\n\thttpData: function( xhr, type, s ) {\n\t\tvar ct = xhr.getResponseHeader(\"content-type\") || \"\",\n\t\t\txml = type === \"xml\" || !type && ct.indexOf(\"xml\") >= 0,\n\t\t\tdata = xml ? xhr.responseXML : xhr.responseText;\n\n\t\tif ( xml && data.documentElement.nodeName === \"parsererror\" ) {\n\t\t\tjQuery.error( \"parsererror\" );\n\t\t}\n\n\t\t// Allow a pre-filtering function to sanitize the response\n\t\t// s is checked to keep backwards compatibility\n\t\tif ( s && s.dataFilter ) {\n\t\t\tdata = s.dataFilter( data, type );\n\t\t}\n\n\t\t// The filter can actually parse the response\n\t\tif ( typeof data === \"string\" ) {\n\t\t\t// Get the JavaScript object, if JSON is used.\n\t\t\tif ( type === \"json\" || !type && ct.indexOf(\"json\") >= 0 ) {\n\t\t\t\tdata = jQuery.parseJSON( data );\n\n\t\t\t// If the type is \"script\", eval it in global context\n\t\t\t} else if ( type === \"script\" || !type && ct.indexOf(\"javascript\") >= 0 ) {\n\t\t\t\tjQuery.globalEval( data );\n\t\t\t}\n\t\t}\n\n\t\treturn data;\n\t},\n\n\t// Serialize an array of form elements or a set of\n\t// key/values into a query string\n\tparam: function( a, traditional ) {\n\t\tvar s = [];\n\t\t\n\t\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n\t\tif ( traditional === undefined ) {\n\t\t\ttraditional = jQuery.ajaxSettings.traditional;\n\t\t}\n\t\t\n\t\t// If an array was passed in, assume that it is an array of form elements.\n\t\tif ( jQuery.isArray(a) || a.jquery ) {\n\t\t\t// Serialize the form elements\n\t\t\tjQuery.each( a, function() {\n\t\t\t\tadd( this.name, this.value );\n\t\t\t});\n\t\t\t\n\t\t} else {\n\t\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t\t// did it), otherwise encode params recursively.\n\t\t\tfor ( var prefix in a ) {\n\t\t\t\tbuildParams( prefix, a[prefix] );\n\t\t\t}\n\t\t}\n\n\t\t// Return the resulting serialization\n\t\treturn s.join(\"&\").replace(r20, \"+\");\n\n\t\tfunction buildParams( prefix, obj ) {\n\t\t\tif ( jQuery.isArray(obj) ) {\n\t\t\t\t// Serialize array item.\n\t\t\t\tjQuery.each( obj, function( i, v ) {\n\t\t\t\t\tif ( traditional ) {\n\t\t\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\t\t\tadd( prefix, v );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If array item is non-scalar (array or object), encode its\n\t\t\t\t\t\t// numeric index to resolve deserialization ambiguity issues.\n\t\t\t\t\t\t// Note that rack (as of 1.0.0) can't currently deserialize\n\t\t\t\t\t\t// nested arrays properly, and attempting to do so may cause\n\t\t\t\t\t\t// a server error. Possible fixes are to modify rack's\n\t\t\t\t\t\t// deserialization algorithm or to provide an option or flag\n\t\t\t\t\t\t// to force array serialization to be shallow.\n\t\t\t\t\t\tbuildParams( prefix + \"[\" + ( typeof v === \"object\" || jQuery.isArray(v) ? i : \"\" ) + \"]\", v );\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\t\t\n\t\t\t} else if ( !traditional && obj != null && typeof obj === \"object\" ) {\n\t\t\t\t// Serialize object item.\n\t\t\t\tjQuery.each( obj, function( k, v ) {\n\t\t\t\t\tbuildParams( prefix + \"[\" + k + \"]\", v );\n\t\t\t\t});\n\t\t\t\t\t\n\t\t\t} else {\n\t\t\t\t// Serialize scalar item.\n\t\t\t\tadd( prefix, obj );\n\t\t\t}\n\t\t}\n\n\t\tfunction add( key, value ) {\n\t\t\t// If value is a function, invoke it and return its value\n\t\t\tvalue = jQuery.isFunction(value) ? value() : value;\n\t\t\ts[ s.length ] = encodeURIComponent(key) + \"=\" + encodeURIComponent(value);\n\t\t}\n\t}\n});\nvar elemdisplay = {},\n\trfxtypes = /toggle|show|hide/,\n\trfxnum = /^([+-]=)?([\\d+-.]+)(.*)$/,\n\ttimerId,\n\tfxAttrs = [\n\t\t// height animations\n\t\t[ \"height\", \"marginTop\", \"marginBottom\", \"paddingTop\", \"paddingBottom\" ],\n\t\t// width animations\n\t\t[ \"width\", \"marginLeft\", \"marginRight\", \"paddingLeft\", \"paddingRight\" ],\n\t\t// opacity animations\n\t\t[ \"opacity\" ]\n\t];\n\njQuery.fn.extend({\n\tshow: function( speed, callback ) {\n\t\tif ( speed || speed === 0) {\n\t\t\treturn this.animate( genFx(\"show\", 3), speed, callback);\n\n\t\t} else {\n\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\tvar old = jQuery.data(this[i], \"olddisplay\");\n\n\t\t\t\tthis[i].style.display = old || \"\";\n\n\t\t\t\tif ( jQuery.css(this[i], \"display\") === \"none\" ) {\n\t\t\t\t\tvar nodeName = this[i].nodeName, display;\n\n\t\t\t\t\tif ( elemdisplay[ nodeName ] ) {\n\t\t\t\t\t\tdisplay = elemdisplay[ nodeName ];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar elem = jQuery(\"<\" + nodeName + \" />\").appendTo(\"body\");\n\n\t\t\t\t\t\tdisplay = elem.css(\"display\");\n\n\t\t\t\t\t\tif ( display === \"none\" ) {\n\t\t\t\t\t\t\tdisplay = \"block\";\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\telem.remove();\n\n\t\t\t\t\t\telemdisplay[ nodeName ] = display;\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.data(this[i], \"olddisplay\", display);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the display of the elements in a second loop\n\t\t\t// to avoid the constant reflow\n\t\t\tfor ( var j = 0, k = this.length; j < k; j++ ) {\n\t\t\t\tthis[j].style.display = jQuery.data(this[j], \"olddisplay\") || \"\";\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t},\n\n\thide: function( speed, callback ) {\n\t\tif ( speed || speed === 0 ) {\n\t\t\treturn this.animate( genFx(\"hide\", 3), speed, callback);\n\n\t\t} else {\n\t\t\tfor ( var i = 0, l = this.length; i < l; i++ ) {\n\t\t\t\tvar old = jQuery.data(this[i], \"olddisplay\");\n\t\t\t\tif ( !old && old !== \"none\" ) {\n\t\t\t\t\tjQuery.data(this[i], \"olddisplay\", jQuery.css(this[i], \"display\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set the display of the elements in a second loop\n\t\t\t// to avoid the constant reflow\n\t\t\tfor ( var j = 0, k = this.length; j < k; j++ ) {\n\t\t\t\tthis[j].style.display = \"none\";\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t},\n\n\t// Save the old toggle function\n\t_toggle: jQuery.fn.toggle,\n\n\ttoggle: function( fn, fn2 ) {\n\t\tvar bool = typeof fn === \"boolean\";\n\n\t\tif ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {\n\t\t\tthis._toggle.apply( this, arguments );\n\n\t\t} else if ( fn == null || bool ) {\n\t\t\tthis.each(function() {\n\t\t\t\tvar state = bool ? fn : jQuery(this).is(\":hidden\");\n\t\t\t\tjQuery(this)[ state ? \"show\" : \"hide\" ]();\n\t\t\t});\n\n\t\t} else {\n\t\t\tthis.animate(genFx(\"toggle\", 3), fn, fn2);\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tfadeTo: function( speed, to, callback ) {\n\t\treturn this.filter(\":hidden\").css(\"opacity\", 0).show().end()\n\t\t\t\t\t.animate({opacity: to}, speed, callback);\n\t},\n\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar optall = jQuery.speed(speed, easing, callback);\n\n\t\tif ( jQuery.isEmptyObject( prop ) ) {\n\t\t\treturn this.each( optall.complete );\n\t\t}\n\n\t\treturn this[ optall.queue === false ? \"each\" : \"queue\" ](function() {\n\t\t\tvar opt = jQuery.extend({}, optall), p,\n\t\t\t\thidden = this.nodeType === 1 && jQuery(this).is(\":hidden\"),\n\t\t\t\tself = this;\n\n\t\t\tfor ( p in prop ) {\n\t\t\t\tvar name = p.replace(rdashAlpha, fcamelCase);\n\n\t\t\t\tif ( p !== name ) {\n\t\t\t\t\tprop[ name ] = prop[ p ];\n\t\t\t\t\tdelete prop[ p ];\n\t\t\t\t\tp = name;\n\t\t\t\t}\n\n\t\t\t\tif ( prop[p] === \"hide\" && hidden || prop[p] === \"show\" && !hidden ) {\n\t\t\t\t\treturn opt.complete.call(this);\n\t\t\t\t}\n\n\t\t\t\tif ( ( p === \"height\" || p === \"width\" ) && this.style ) {\n\t\t\t\t\t// Store display property\n\t\t\t\t\topt.display = jQuery.css(this, \"display\");\n\n\t\t\t\t\t// Make sure that nothing sneaks out\n\t\t\t\t\topt.overflow = this.style.overflow;\n\t\t\t\t}\n\n\t\t\t\tif ( jQuery.isArray( prop[p] ) ) {\n\t\t\t\t\t// Create (if needed) and add to specialEasing\n\t\t\t\t\t(opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1];\n\t\t\t\t\tprop[p] = prop[p][0];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( opt.overflow != null ) {\n\t\t\t\tthis.style.overflow = \"hidden\";\n\t\t\t}\n\n\t\t\topt.curAnim = jQuery.extend({}, prop);\n\n\t\t\tjQuery.each( prop, function( name, val ) {\n\t\t\t\tvar e = new jQuery.fx( self, opt, name );\n\n\t\t\t\tif ( rfxtypes.test(val) ) {\n\t\t\t\t\te[ val === \"toggle\" ? hidden ? \"show\" : \"hide\" : val ]( prop );\n\n\t\t\t\t} else {\n\t\t\t\t\tvar parts = rfxnum.exec(val),\n\t\t\t\t\t\tstart = e.cur(true) || 0;\n\n\t\t\t\t\tif ( parts ) {\n\t\t\t\t\t\tvar end = parseFloat( parts[2] ),\n\t\t\t\t\t\t\tunit = parts[3] || \"px\";\n\n\t\t\t\t\t\t// We need to compute starting value\n\t\t\t\t\t\tif ( unit !== \"px\" ) {\n\t\t\t\t\t\t\tself.style[ name ] = (end || 1) + unit;\n\t\t\t\t\t\t\tstart = ((end || 1) / e.cur(true)) * start;\n\t\t\t\t\t\t\tself.style[ name ] = start + unit;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If a +=/-= token was provided, we're doing a relative animation\n\t\t\t\t\t\tif ( parts[1] ) {\n\t\t\t\t\t\t\tend = ((parts[1] === \"-=\" ? -1 : 1) * end) + start;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\te.custom( start, end, unit );\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\te.custom( start, val, \"\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// For JS strict compliance\n\t\t\treturn true;\n\t\t});\n\t},\n\n\tstop: function( clearQueue, gotoEnd ) {\n\t\tvar timers = jQuery.timers;\n\n\t\tif ( clearQueue ) {\n\t\t\tthis.queue([]);\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// go in reverse order so anything added to the queue during the loop is ignored\n\t\t\tfor ( var i = timers.length - 1; i >= 0; i-- ) {\n\t\t\t\tif ( timers[i].elem === this ) {\n\t\t\t\t\tif (gotoEnd) {\n\t\t\t\t\t\t// force the next step to be the last\n\t\t\t\t\t\ttimers[i](true);\n\t\t\t\t\t}\n\n\t\t\t\t\ttimers.splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\t// start the next in the queue if the last step wasn't forced\n\t\tif ( !gotoEnd ) {\n\t\t\tthis.dequeue();\n\t\t}\n\n\t\treturn this;\n\t}\n\n});\n\n// Generate shortcuts for custom animations\njQuery.each({\n\tslideDown: genFx(\"show\", 1),\n\tslideUp: genFx(\"hide\", 1),\n\tslideToggle: genFx(\"toggle\", 1),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, callback ) {\n\t\treturn this.animate( props, speed, callback );\n\t};\n});\n\njQuery.extend({\n\tspeed: function( speed, easing, fn ) {\n\t\tvar opt = speed && typeof speed === \"object\" ? speed : {\n\t\t\tcomplete: fn || !fn && easing ||\n\t\t\t\tjQuery.isFunction( speed ) && speed,\n\t\t\tduration: speed,\n\t\t\teasing: fn && easing || easing && !jQuery.isFunction(easing) && easing\n\t\t};\n\n\t\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ? opt.duration :\n\t\t\tjQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;\n\n\t\t// Queueing\n\t\topt.old = opt.complete;\n\t\topt.complete = function() {\n\t\t\tif ( opt.queue !== false ) {\n\t\t\t\tjQuery(this).dequeue();\n\t\t\t}\n\t\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\t\topt.old.call( this );\n\t\t\t}\n\t\t};\n\n\t\treturn opt;\n\t},\n\n\teasing: {\n\t\tlinear: function( p, n, firstNum, diff ) {\n\t\t\treturn firstNum + diff * p;\n\t\t},\n\t\tswing: function( p, n, firstNum, diff ) {\n\t\t\treturn ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;\n\t\t}\n\t},\n\n\ttimers: [],\n\n\tfx: function( elem, options, prop ) {\n\t\tthis.options = options;\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\n\t\tif ( !options.orig ) {\n\t\t\toptions.orig = {};\n\t\t}\n\t}\n\n});\n\njQuery.fx.prototype = {\n\t// Simple function for setting a style value\n\tupdate: function() {\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\t(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );\n\n\t\t// Set display property to block for height/width animations\n\t\tif ( ( this.prop === \"height\" || this.prop === \"width\" ) && this.elem.style ) {\n\t\t\tthis.elem.style.display = \"block\";\n\t\t}\n\t},\n\n\t// Get the current size\n\tcur: function( force ) {\n\t\tif ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {\n\t\t\treturn this.elem[ this.prop ];\n\t\t}\n\n\t\tvar r = parseFloat(jQuery.css(this.elem, this.prop, force));\n\t\treturn r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;\n\t},\n\n\t// Start an animation from one number to another\n\tcustom: function( from, to, unit ) {\n\t\tthis.startTime = now();\n\t\tthis.start = from;\n\t\tthis.end = to;\n\t\tthis.unit = unit || this.unit || \"px\";\n\t\tthis.now = this.start;\n\t\tthis.pos = this.state = 0;\n\n\t\tvar self = this;\n\t\tfunction t( gotoEnd ) {\n\t\t\treturn self.step(gotoEnd);\n\t\t}\n\n\t\tt.elem = this.elem;\n\n\t\tif ( t() && jQuery.timers.push(t) && !timerId ) {\n\t\t\ttimerId = setInterval(jQuery.fx.tick, 13);\n\t\t}\n\t},\n\n\t// Simple 'show' function\n\tshow: function() {\n\t\t// Remember where we started, so that we can go back to it later\n\t\tthis.options.orig[this.prop] = jQuery.style( this.elem, this.prop );\n\t\tthis.options.show = true;\n\n\t\t// Begin the animation\n\t\t// Make sure that we start at a small width/height to avoid any\n\t\t// flash of content\n\t\tthis.custom(this.prop === \"width\" || this.prop === \"height\" ? 1 : 0, this.cur());\n\n\t\t// Start by showing the element\n\t\tjQuery( this.elem ).show();\n\t},\n\n\t// Simple 'hide' function\n\thide: function() {\n\t\t// Remember where we started, so that we can go back to it later\n\t\tthis.options.orig[this.prop] = jQuery.style( this.elem, this.prop );\n\t\tthis.options.hide = true;\n\n\t\t// Begin the animation\n\t\tthis.custom(this.cur(), 0);\n\t},\n\n\t// Each step of an animation\n\tstep: function( gotoEnd ) {\n\t\tvar t = now(), done = true;\n\n\t\tif ( gotoEnd || t >= this.options.duration + this.startTime ) {\n\t\t\tthis.now = this.end;\n\t\t\tthis.pos = this.state = 1;\n\t\t\tthis.update();\n\n\t\t\tthis.options.curAnim[ this.prop ] = true;\n\n\t\t\tfor ( var i in this.options.curAnim ) {\n\t\t\t\tif ( this.options.curAnim[i] !== true ) {\n\t\t\t\t\tdone = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( done ) {\n\t\t\t\tif ( this.options.display != null ) {\n\t\t\t\t\t// Reset the overflow\n\t\t\t\t\tthis.elem.style.overflow = this.options.overflow;\n\n\t\t\t\t\t// Reset the display\n\t\t\t\t\tvar old = jQuery.data(this.elem, \"olddisplay\");\n\t\t\t\t\tthis.elem.style.display = old ? old : this.options.display;\n\n\t\t\t\t\tif ( jQuery.css(this.elem, \"display\") === \"none\" ) {\n\t\t\t\t\t\tthis.elem.style.display = \"block\";\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Hide the element if the \"hide\" operation was done\n\t\t\t\tif ( this.options.hide ) {\n\t\t\t\t\tjQuery(this.elem).hide();\n\t\t\t\t}\n\n\t\t\t\t// Reset the properties, if the item has been hidden or shown\n\t\t\t\tif ( this.options.hide || this.options.show ) {\n\t\t\t\t\tfor ( var p in this.options.curAnim ) {\n\t\t\t\t\t\tjQuery.style(this.elem, p, this.options.orig[p]);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Execute the complete function\n\t\t\t\tthis.options.complete.call( this.elem );\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t} else {\n\t\t\tvar n = t - this.startTime;\n\t\t\tthis.state = n / this.options.duration;\n\n\t\t\t// Perform the easing function, defaults to swing\n\t\t\tvar specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop];\n\t\t\tvar defaultEasing = this.options.easing || (jQuery.easing.swing ? \"swing\" : \"linear\");\n\t\t\tthis.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration);\n\t\t\tthis.now = this.start + ((this.end - this.start) * this.pos);\n\n\t\t\t// Perform the next step of the animation\n\t\t\tthis.update();\n\t\t}\n\n\t\treturn true;\n\t}\n};\n\njQuery.extend( jQuery.fx, {\n\ttick: function() {\n\t\tvar timers = jQuery.timers;\n\n\t\tfor ( var i = 0; i < timers.length; i++ ) {\n\t\t\tif ( !timers[i]() ) {\n\t\t\t\ttimers.splice(i--, 1);\n\t\t\t}\n\t\t}\n\n\t\tif ( !timers.length ) {\n\t\t\tjQuery.fx.stop();\n\t\t}\n\t},\n\t\t\n\tstop: function() {\n\t\tclearInterval( timerId );\n\t\ttimerId = null;\n\t},\n\t\n\tspeeds: {\n\t\tslow: 600,\n \t\tfast: 200,\n \t\t// Default speed\n \t\t_default: 400\n\t},\n\n\tstep: {\n\t\topacity: function( fx ) {\n\t\t\tjQuery.style(fx.elem, \"opacity\", fx.now);\n\t\t},\n\n\t\t_default: function( fx ) {\n\t\t\tif ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {\n\t\t\t\tfx.elem.style[ fx.prop ] = (fx.prop === \"width\" || fx.prop === \"height\" ? Math.max(0, fx.now) : fx.now) + fx.unit;\n\t\t\t} else {\n\t\t\t\tfx.elem[ fx.prop ] = fx.now;\n\t\t\t}\n\t\t}\n\t}\n});\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.animated = function( elem ) {\n\t\treturn jQuery.grep(jQuery.timers, function( fn ) {\n\t\t\treturn elem === fn.elem;\n\t\t}).length;\n\t};\n}\n\nfunction genFx( type, num ) {\n\tvar obj = {};\n\n\tjQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {\n\t\tobj[ this ] = type;\n\t});\n\n\treturn obj;\n}\nif ( \"getBoundingClientRect\" in document.documentElement ) {\n\tjQuery.fn.offset = function( options ) {\n\t\tvar elem = this[0];\n\n\t\tif ( options ) { \n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t});\n\t\t}\n\n\t\tif ( !elem || !elem.ownerDocument ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( elem === elem.ownerDocument.body ) {\n\t\t\treturn jQuery.offset.bodyOffset( elem );\n\t\t}\n\n\t\tvar box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement,\n\t\t\tclientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,\n\t\t\ttop  = box.top  + (self.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop ) - clientTop,\n\t\t\tleft = box.left + (self.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;\n\n\t\treturn { top: top, left: left };\n\t};\n\n} else {\n\tjQuery.fn.offset = function( options ) {\n\t\tvar elem = this[0];\n\n\t\tif ( options ) { \n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t});\n\t\t}\n\n\t\tif ( !elem || !elem.ownerDocument ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( elem === elem.ownerDocument.body ) {\n\t\t\treturn jQuery.offset.bodyOffset( elem );\n\t\t}\n\n\t\tjQuery.offset.initialize();\n\n\t\tvar offsetParent = elem.offsetParent, prevOffsetParent = elem,\n\t\t\tdoc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,\n\t\t\tbody = doc.body, defaultView = doc.defaultView,\n\t\t\tprevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,\n\t\t\ttop = elem.offsetTop, left = elem.offsetLeft;\n\n\t\twhile ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {\n\t\t\tif ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === \"fixed\" ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcomputedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;\n\t\t\ttop  -= elem.scrollTop;\n\t\t\tleft -= elem.scrollLeft;\n\n\t\t\tif ( elem === offsetParent ) {\n\t\t\t\ttop  += elem.offsetTop;\n\t\t\t\tleft += elem.offsetLeft;\n\n\t\t\t\tif ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.nodeName)) ) {\n\t\t\t\t\ttop  += parseFloat( computedStyle.borderTopWidth  ) || 0;\n\t\t\t\t\tleft += parseFloat( computedStyle.borderLeftWidth ) || 0;\n\t\t\t\t}\n\n\t\t\t\tprevOffsetParent = offsetParent, offsetParent = elem.offsetParent;\n\t\t\t}\n\n\t\t\tif ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== \"visible\" ) {\n\t\t\t\ttop  += parseFloat( computedStyle.borderTopWidth  ) || 0;\n\t\t\t\tleft += parseFloat( computedStyle.borderLeftWidth ) || 0;\n\t\t\t}\n\n\t\t\tprevComputedStyle = computedStyle;\n\t\t}\n\n\t\tif ( prevComputedStyle.position === \"relative\" || prevComputedStyle.position === \"static\" ) {\n\t\t\ttop  += body.offsetTop;\n\t\t\tleft += body.offsetLeft;\n\t\t}\n\n\t\tif ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === \"fixed\" ) {\n\t\t\ttop  += Math.max( docElem.scrollTop, body.scrollTop );\n\t\t\tleft += Math.max( docElem.scrollLeft, body.scrollLeft );\n\t\t}\n\n\t\treturn { top: top, left: left };\n\t};\n}\n\njQuery.offset = {\n\tinitialize: function() {\n\t\tvar body = document.body, container = document.createElement(\"div\"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.curCSS(body, \"marginTop\", true) ) || 0,\n\t\t\thtml = \"<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>\";\n\n\t\tjQuery.extend( container.style, { position: \"absolute\", top: 0, left: 0, margin: 0, border: 0, width: \"1px\", height: \"1px\", visibility: \"hidden\" } );\n\n\t\tcontainer.innerHTML = html;\n\t\tbody.insertBefore( container, body.firstChild );\n\t\tinnerDiv = container.firstChild;\n\t\tcheckDiv = innerDiv.firstChild;\n\t\ttd = innerDiv.nextSibling.firstChild.firstChild;\n\n\t\tthis.doesNotAddBorder = (checkDiv.offsetTop !== 5);\n\t\tthis.doesAddBorderForTableAndCells = (td.offsetTop === 5);\n\n\t\tcheckDiv.style.position = \"fixed\", checkDiv.style.top = \"20px\";\n\t\t// safari subtracts parent border width here which is 5px\n\t\tthis.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);\n\t\tcheckDiv.style.position = checkDiv.style.top = \"\";\n\n\t\tinnerDiv.style.overflow = \"hidden\", innerDiv.style.position = \"relative\";\n\t\tthis.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);\n\n\t\tthis.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);\n\n\t\tbody.removeChild( container );\n\t\tbody = container = innerDiv = checkDiv = table = td = null;\n\t\tjQuery.offset.initialize = jQuery.noop;\n\t},\n\n\tbodyOffset: function( body ) {\n\t\tvar top = body.offsetTop, left = body.offsetLeft;\n\n\t\tjQuery.offset.initialize();\n\n\t\tif ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {\n\t\t\ttop  += parseFloat( jQuery.curCSS(body, \"marginTop\",  true) ) || 0;\n\t\t\tleft += parseFloat( jQuery.curCSS(body, \"marginLeft\", true) ) || 0;\n\t\t}\n\n\t\treturn { top: top, left: left };\n\t},\n\t\n\tsetOffset: function( elem, options, i ) {\n\t\t// set position first, in-case top/left are set even on static elem\n\t\tif ( /static/.test( jQuery.curCSS( elem, \"position\" ) ) ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\t\tvar curElem   = jQuery( elem ),\n\t\t\tcurOffset = curElem.offset(),\n\t\t\tcurTop    = parseInt( jQuery.curCSS( elem, \"top\",  true ), 10 ) || 0,\n\t\t\tcurLeft   = parseInt( jQuery.curCSS( elem, \"left\", true ), 10 ) || 0;\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\t\t\toptions = options.call( elem, i, curOffset );\n\t\t}\n\n\t\tvar props = {\n\t\t\ttop:  (options.top  - curOffset.top)  + curTop,\n\t\t\tleft: (options.left - curOffset.left) + curLeft\n\t\t};\n\t\t\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\n\njQuery.fn.extend({\n\tposition: function() {\n\t\tif ( !this[0] ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tvar elem = this[0],\n\n\t\t// Get *real* offsetParent\n\t\toffsetParent = this.offsetParent(),\n\n\t\t// Get correct offsets\n\t\toffset       = this.offset(),\n\t\tparentOffset = /^body|html$/i.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();\n\n\t\t// Subtract element margins\n\t\t// note: when an element has margin: auto the offsetLeft and marginLeft\n\t\t// are the same in Safari causing offset.left to incorrectly be 0\n\t\toffset.top  -= parseFloat( jQuery.curCSS(elem, \"marginTop\",  true) ) || 0;\n\t\toffset.left -= parseFloat( jQuery.curCSS(elem, \"marginLeft\", true) ) || 0;\n\n\t\t// Add offsetParent borders\n\t\tparentOffset.top  += parseFloat( jQuery.curCSS(offsetParent[0], \"borderTopWidth\",  true) ) || 0;\n\t\tparentOffset.left += parseFloat( jQuery.curCSS(offsetParent[0], \"borderLeftWidth\", true) ) || 0;\n\n\t\t// Subtract the two offsets\n\t\treturn {\n\t\t\ttop:  offset.top  - parentOffset.top,\n\t\t\tleft: offset.left - parentOffset.left\n\t\t};\n\t},\n\n\toffsetParent: function() {\n\t\treturn this.map(function() {\n\t\t\tvar offsetParent = this.offsetParent || document.body;\n\t\t\twhile ( offsetParent && (!/^body|html$/i.test(offsetParent.nodeName) && jQuery.css(offsetParent, \"position\") === \"static\") ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\t\t\treturn offsetParent;\n\t\t});\n\t}\n});\n\n\n// Create scrollLeft and scrollTop methods\njQuery.each( [\"Left\", \"Top\"], function( i, name ) {\n\tvar method = \"scroll\" + name;\n\n\tjQuery.fn[ method ] = function(val) {\n\t\tvar elem = this[0], win;\n\t\t\n\t\tif ( !elem ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( val !== undefined ) {\n\t\t\t// Set the scroll offset\n\t\t\treturn this.each(function() {\n\t\t\t\twin = getWindow( this );\n\n\t\t\t\tif ( win ) {\n\t\t\t\t\twin.scrollTo(\n\t\t\t\t\t\t!i ? val : jQuery(win).scrollLeft(),\n\t\t\t\t\t\t i ? val : jQuery(win).scrollTop()\n\t\t\t\t\t);\n\n\t\t\t\t} else {\n\t\t\t\t\tthis[ method ] = val;\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\twin = getWindow( elem );\n\n\t\t\t// Return the scroll offset\n\t\t\treturn win ? (\"pageXOffset\" in win) ? win[ i ? \"pageYOffset\" : \"pageXOffset\" ] :\n\t\t\t\tjQuery.support.boxModel && win.document.documentElement[ method ] ||\n\t\t\t\t\twin.document.body[ method ] :\n\t\t\t\telem[ method ];\n\t\t}\n\t};\n});\n\nfunction getWindow( elem ) {\n\treturn (\"scrollTo\" in elem && elem.document) ?\n\t\telem :\n\t\telem.nodeType === 9 ?\n\t\t\telem.defaultView || elem.parentWindow :\n\t\t\tfalse;\n}\n// Create innerHeight, innerWidth, outerHeight and outerWidth methods\njQuery.each([ \"Height\", \"Width\" ], function( i, name ) {\n\n\tvar type = name.toLowerCase();\n\n\t// innerHeight and innerWidth\n\tjQuery.fn[\"inner\" + name] = function() {\n\t\treturn this[0] ?\n\t\t\tjQuery.css( this[0], type, false, \"padding\" ) :\n\t\t\tnull;\n\t};\n\n\t// outerHeight and outerWidth\n\tjQuery.fn[\"outer\" + name] = function( margin ) {\n\t\treturn this[0] ?\n\t\t\tjQuery.css( this[0], type, false, margin ? \"margin\" : \"border\" ) :\n\t\t\tnull;\n\t};\n\n\tjQuery.fn[ type ] = function( size ) {\n\t\t// Get window width or height\n\t\tvar elem = this[0];\n\t\tif ( !elem ) {\n\t\t\treturn size == null ? null : this;\n\t\t}\n\t\t\n\t\tif ( jQuery.isFunction( size ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tvar self = jQuery( this );\n\t\t\t\tself[ type ]( size.call( this, i, self[ type ]() ) );\n\t\t\t});\n\t\t}\n\n\t\treturn (\"scrollTo\" in elem && elem.document) ? // does it walk and quack like a window?\n\t\t\t// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode\n\t\t\telem.document.compatMode === \"CSS1Compat\" && elem.document.documentElement[ \"client\" + name ] ||\n\t\t\telem.document.body[ \"client\" + name ] :\n\n\t\t\t// Get document width or height\n\t\t\t(elem.nodeType === 9) ? // is it a document\n\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height], whichever is greater\n\t\t\t\tMath.max(\n\t\t\t\t\telem.documentElement[\"client\" + name],\n\t\t\t\t\telem.body[\"scroll\" + name], elem.documentElement[\"scroll\" + name],\n\t\t\t\t\telem.body[\"offset\" + name], elem.documentElement[\"offset\" + name]\n\t\t\t\t) :\n\n\t\t\t\t// Get or set width or height on the element\n\t\t\t\tsize === undefined ?\n\t\t\t\t\t// Get width or height on the element\n\t\t\t\t\tjQuery.css( elem, type ) :\n\n\t\t\t\t\t// Set the width or height on the element (default to pixels if value is unitless)\n\t\t\t\t\tthis.css( type, typeof size === \"string\" ? size : size + \"px\" );\n\t};\n\n});\n// Expose jQuery to the global object\nwindow.jQuery = window.$ = jQuery;\n\n})(window);\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/vendor/jquery.ba-isjquery.js",
    "content": "/*!\n * jQuery isjQuery - v0.4 - 2/13/2010\n * http://benalman.com/projects/jquery-misc-plugins/\n * \n * Copyright (c) 2010 \"Cowboy\" Ben Alman\n * Dual licensed under the MIT and GPL licenses.\n * http://benalman.com/about/license/\n */\n\n// Since every jQuery object has a .jquery property, it's usually safe to test\n// the existence of that property. Of course, this only works as long as you\n// know that any non-jQuery object you might be testing has no .jquery property.\n// So.. what do you do when you need to test an external object whose properties\n// you don't know?\n// \n// If you currently use instanceof, read this Ajaxian article:\n// http://ajaxian.com/archives/working-aroung-the-instanceof-memory-leak\n\njQuery.isjQuery = function( obj ){\n  return obj && obj.hasOwnProperty && obj instanceof jQuery;\n};\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/vendor/jquery.form.js",
    "content": "/*\n *\n * jQuery Form Plugin\n * @requires jQuery v1.1 or later\n *\n * Examples at: http://malsup.com/jquery/form/\n * Dual licensed under the MIT and GPL licenses:\n *   http://www.opensource.org/licenses/mit-license.php\n *   http://www.gnu.org/licenses/gpl.html\n *\n * Revision: $Id: jquery.form.js 2884 2007-08-24 23:13:55Z malsup $\n */\n (function($) {\n/**\n * ajaxSubmit() provides a mechanism for submitting an HTML form using AJAX.\n *\n * ajaxSubmit accepts a single argument which can be either a success callback function\n * or an options Object.  If a function is provided it will be invoked upon successful\n * completion of the submit and will be passed the response from the server.\n * If an options Object is provided, the following attributes are supported:\n *\n *  target:   Identifies the element(s) in the page to be updated with the server response.\n *            This value may be specified as a jQuery selection string, a jQuery object,\n *            or a DOM element.\n *            default value: null\n *\n *  url:      URL to which the form data will be submitted.\n *            default value: value of form's 'action' attribute\n *\n *  type:     The method in which the form data should be submitted, 'GET' or 'POST'.\n *            default value: value of form's 'method' attribute (or 'GET' if none found)\n *\n *  beforeSubmit:  Callback method to be invoked before the form is submitted.\n *            default value: null\n *\n *  success:  Callback method to be invoked after the form has been successfully submitted\n *            and the response has been returned from the server\n *            default value: null\n *\n *  dataType: Expected dataType of the response.  One of: null, 'xml', 'script', or 'json'\n *            default value: null\n *\n *  semantic: Boolean flag indicating whether data must be submitted in semantic order (slower).\n *            default value: false\n *\n *  resetForm: Boolean flag indicating whether the form should be reset if the submit is successful\n *\n *  clearForm: Boolean flag indicating whether the form should be cleared if the submit is successful\n *\n *\n * The 'beforeSubmit' callback can be provided as a hook for running pre-submit logic or for\n * validating the form data.  If the 'beforeSubmit' callback returns false then the form will\n * not be submitted. The 'beforeSubmit' callback is invoked with three arguments: the form data\n * in array format, the jQuery object, and the options object passed into ajaxSubmit.\n * The form data array takes the following form:\n *\n *     [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]\n *\n * If a 'success' callback method is provided it is invoked after the response has been returned\n * from the server.  It is passed the responseText or responseXML value (depending on dataType).\n * See jQuery.ajax for further details.\n *\n *\n * The dataType option provides a means for specifying how the server response should be handled.\n * This maps directly to the jQuery.httpData method.  The following values are supported:\n *\n *      'xml':    if dataType == 'xml' the server response is treated as XML and the 'success'\n *                   callback method, if specified, will be passed the responseXML value\n *      'json':   if dataType == 'json' the server response will be evaluted and passed to\n *                   the 'success' callback, if specified\n *      'script': if dataType == 'script' the server response is evaluated in the global context\n *\n *\n * Note that it does not make sense to use both the 'target' and 'dataType' options.  If both\n * are provided the target will be ignored.\n *\n * The semantic argument can be used to force form serialization in semantic order.\n * This is normally true anyway, unless the form contains input elements of type='image'.\n * If your form must be submitted with name/value pairs in semantic order and your form\n * contains an input of type='image\" then pass true for this arg, otherwise pass false\n * (or nothing) to avoid the overhead for this logic.\n *\n *\n * When used on its own, ajaxSubmit() is typically bound to a form's submit event like this:\n *\n * $(\"#form-id\").submit(function() {\n *     $(this).ajaxSubmit(options);\n *     return false; // cancel conventional submit\n * });\n *\n * When using ajaxForm(), however, this is done for you.\n *\n * @example\n * $('#myForm').ajaxSubmit(function(data) {\n *     alert('Form submit succeeded! Server returned: ' + data);\n * });\n * @desc Submit form and alert server response\n *\n *\n * @example\n * var options = {\n *     target: '#myTargetDiv'\n * };\n * $('#myForm').ajaxSubmit(options);\n * @desc Submit form and update page element with server response\n *\n *\n * @example\n * var options = {\n *     success: function(responseText) {\n *         alert(responseText);\n *     }\n * };\n * $('#myForm').ajaxSubmit(options);\n * @desc Submit form and alert the server response\n *\n *\n * @example\n * var options = {\n *     beforeSubmit: function(formArray, jqForm) {\n *         if (formArray.length == 0) {\n *             alert('Please enter data.');\n *             return false;\n *         }\n *     }\n * };\n * $('#myForm').ajaxSubmit(options);\n * @desc Pre-submit validation which aborts the submit operation if form data is empty\n *\n *\n * @example\n * var options = {\n *     url: myJsonUrl.php,\n *     dataType: 'json',\n *     success: function(data) {\n *        // 'data' is an object representing the the evaluated json data\n *     }\n * };\n * $('#myForm').ajaxSubmit(options);\n * @desc json data returned and evaluated\n *\n *\n * @example\n * var options = {\n *     url: myXmlUrl.php,\n *     dataType: 'xml',\n *     success: function(responseXML) {\n *        // responseXML is XML document object\n *        var data = $('myElement', responseXML).text();\n *     }\n * };\n * $('#myForm').ajaxSubmit(options);\n * @desc XML data returned from server\n *\n *\n * @example\n * var options = {\n *     resetForm: true\n * };\n * $('#myForm').ajaxSubmit(options);\n * @desc submit form and reset it if successful\n *\n * @example\n * $('#myForm).submit(function() {\n *    $(this).ajaxSubmit();\n *    return false;\n * });\n * @desc Bind form's submit event to use ajaxSubmit\n *\n *\n * @name ajaxSubmit\n * @type jQuery\n * @param options  object literal containing options which control the form submission process\n * @cat Plugins/Form\n * @return jQuery\n */\n$.fn.ajaxSubmit = function(options) {\n    if (typeof options == 'function')\n        options = { success: options };\n\n    options = $.extend({\n        url:  this.attr('action') || window.location,\n        type: this.attr('method') || 'GET'\n    }, options || {});\n\n    // hook for manipulating the form data before it is extracted;\n    // convenient for use with rich editors like tinyMCE or FCKEditor\n    var veto = {};\n    $.event.trigger('form.pre.serialize', [this, options, veto]);\n    if (veto.veto) return this;\n\n    var a = this.formToArray(options.semantic);\n\n    // give pre-submit callback an opportunity to abort the submit\n    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) return this;\n\n    // fire vetoable 'validate' event\n    $.event.trigger('form.submit.validate', [a, this, options, veto]);\n    if (veto.veto) return this;\n\n    var q = $.param(a);//.replace(/%20/g,'+');\n\n    if (options.type.toUpperCase() == 'GET') {\n        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;\n        options.data = null;  // data is null for 'get'\n    }\n    else\n        options.data = q; // data is the query string for 'post'\n\n    var $form = this, callbacks = [];\n    if (options.resetForm) callbacks.push(function() { $form.resetForm(); });\n    if (options.clearForm) callbacks.push(function() { $form.clearForm(); });\n\n    // perform a load on the target only if dataType is not provided\n    if (!options.dataType && options.target) {\n        var oldSuccess = options.success || function(){};\n        callbacks.push(function(data) {\n            if (this.evalScripts)\n                $(options.target).attr(\"innerHTML\", data).evalScripts().each(oldSuccess, arguments);\n            else // jQuery v1.1.4\n                $(options.target).html(data).each(oldSuccess, arguments);\n        });\n    }\n    else if (options.success)\n        callbacks.push(options.success);\n\n    options.success = function(data, status) {\n        for (var i=0, max=callbacks.length; i < max; i++)\n            callbacks[i](data, status, $form);\n    };\n\n    // are there files to upload?\n    var files = $('input:file', this).fieldValue();\n    var found = false;\n    for (var j=0; j < files.length; j++)\n        if (files[j])\n            found = true;\n\n    if (options.iframe || found) // options.iframe allows user to force iframe mode\n        fileUpload();\n    else\n        $.ajax(options);\n\n    // fire 'notify' event\n    $.event.trigger('form.submit.notify', [this, options]);\n    return this;\n\n\n    // private function for handling file uploads (hat tip to YAHOO!)\n    function fileUpload() {\n        var form = $form[0];\n        var opts = $.extend({}, $.ajaxSettings, options);\n\n        var id = 'jqFormIO' + $.fn.ajaxSubmit.counter++;\n        var $io = $('<iframe id=\"' + id + '\" name=\"' + id + '\" />');\n        var io = $io[0];\n        var op8 = $.browser.opera && window.opera.version() < 9;\n        if ($.browser.msie || op8) io.src = 'javascript:false;document.write(\"\");';\n        $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });\n\n        var xhr = { // mock object\n            responseText: null,\n            responseXML: null,\n            status: 0,\n            statusText: 'n/a',\n            getAllResponseHeaders: function() {},\n            getResponseHeader: function() {},\n            setRequestHeader: function() {}\n        };\n\n        var g = opts.global;\n        // trigger ajax global events so that activity/block indicators work like normal\n        if (g && ! $.active++) $.event.trigger(\"ajaxStart\");\n        if (g) $.event.trigger(\"ajaxSend\", [xhr, opts]);\n\n        var cbInvoked = 0;\n        var timedOut = 0;\n\n        // take a breath so that pending repaints get some cpu time before the upload starts\n        setTimeout(function() {\n            $io.appendTo('body');\n            // jQuery's event binding doesn't work for iframe events in IE\n            io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);\n\n            // make sure form attrs are set\n            var encAttr = form.encoding ? 'encoding' : 'enctype';\n            var t = $form.attr('target');\n            $form.attr({\n                target:   id,\n                method:  'POST',\n                action:   opts.url\n            });\n            form[encAttr] = 'multipart/form-data';\n\n            // support timout\n            if (opts.timeout)\n                setTimeout(function() { timedOut = true; cb(); }, opts.timeout);\n\n            form.submit();\n            $form.attr('target', t); // reset target\n        }, 10);\n\n        function cb() {\n            if (cbInvoked++) return;\n\n            io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);\n\n            var ok = true;\n            try {\n                if (timedOut) throw 'timeout';\n                // extract the server response from the iframe\n                var data, doc;\n                doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;\n                xhr.responseText = doc.body ? doc.body.innerHTML : null;\n                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;\n\n                if (opts.dataType == 'json' || opts.dataType == 'script') {\n                    var ta = doc.getElementsByTagName('textarea')[0];\n                    data = ta ? ta.value : xhr.responseText;\n                    if (opts.dataType == 'json')\n                        eval(\"data = \" + data);\n                    else\n                        $.globalEval(data);\n                }\n                else if (opts.dataType == 'xml') {\n                    data = xhr.responseXML;\n                    if (!data && xhr.responseText != null)\n                        data = toXml(xhr.responseText);\n                }\n                else {\n                    data = xhr.responseText;\n                }\n            }\n            catch(e){\n                ok = false;\n                $.handleError(opts, xhr, 'error', e);\n            }\n\n            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it\n            if (ok) {\n                opts.success(data, 'success');\n                if (g) $.event.trigger(\"ajaxSuccess\", [xhr, opts]);\n            }\n            if (g) $.event.trigger(\"ajaxComplete\", [xhr, opts]);\n            if (g && ! --$.active) $.event.trigger(\"ajaxStop\");\n            if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');\n\n            // clean up\n            setTimeout(function() {\n                $io.remove();\n                xhr.responseXML = null;\n            }, 100);\n        };\n\n        function toXml(s, doc) {\n            if (window.ActiveXObject) {\n                doc = new ActiveXObject('Microsoft.XMLDOM');\n                doc.async = 'false';\n                doc.loadXML(s);\n            }\n            else\n                doc = (new DOMParser()).parseFromString(s, 'text/xml');\n            return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;\n        };\n    };\n};\n$.fn.ajaxSubmit.counter = 0; // used to create unique iframe ids\n\n/**\n * ajaxForm() provides a mechanism for fully automating form submission.\n *\n * The advantages of using this method instead of ajaxSubmit() are:\n *\n * 1: This method will include coordinates for <input type=\"image\" /> elements (if the element\n *    is used to submit the form).\n * 2. This method will include the submit element's name/value data (for the element that was\n *    used to submit the form).\n * 3. This method binds the submit() method to the form for you.\n *\n * Note that for accurate x/y coordinates of image submit elements in all browsers\n * you need to also use the \"dimensions\" plugin (this method will auto-detect its presence).\n *\n * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely\n * passes the options argument along after properly binding events for submit elements and\n * the form itself.  See ajaxSubmit for a full description of the options argument.\n *\n *\n * @example\n * var options = {\n *     target: '#myTargetDiv'\n * };\n * $('#myForm').ajaxSForm(options);\n * @desc Bind form's submit event so that 'myTargetDiv' is updated with the server response\n *       when the form is submitted.\n *\n *\n * @example\n * var options = {\n *     success: function(responseText) {\n *         alert(responseText);\n *     }\n * };\n * $('#myForm').ajaxSubmit(options);\n * @desc Bind form's submit event so that server response is alerted after the form is submitted.\n *\n *\n * @example\n * var options = {\n *     beforeSubmit: function(formArray, jqForm) {\n *         if (formArray.length == 0) {\n *             alert('Please enter data.');\n *             return false;\n *         }\n *     }\n * };\n * $('#myForm').ajaxSubmit(options);\n * @desc Bind form's submit event so that pre-submit callback is invoked before the form\n *       is submitted.\n *\n *\n * @name   ajaxForm\n * @param  options  object literal containing options which control the form submission process\n * @return jQuery\n * @cat    Plugins/Form\n * @type   jQuery\n */\n$.fn.ajaxForm = function(options) {\n    return this.ajaxFormUnbind().submit(submitHandler).each(function() {\n        // store options in hash\n        this.formPluginId = $.fn.ajaxForm.counter++;\n        $.fn.ajaxForm.optionHash[this.formPluginId] = options;\n        $(\":submit,input:image\", this).click(clickHandler);\n    });\n};\n\n$.fn.ajaxForm.counter = 1;\n$.fn.ajaxForm.optionHash = {};\n\nfunction clickHandler(e) {\n    var $form = this.form;\n    $form.clk = this;\n    if (this.type == 'image') {\n        if (e.offsetX != undefined) {\n            $form.clk_x = e.offsetX;\n            $form.clk_y = e.offsetY;\n        } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin\n            var offset = $(this).offset();\n            $form.clk_x = e.pageX - offset.left;\n            $form.clk_y = e.pageY - offset.top;\n        } else {\n            $form.clk_x = e.pageX - this.offsetLeft;\n            $form.clk_y = e.pageY - this.offsetTop;\n        }\n    }\n    // clear form vars\n    setTimeout(function() { $form.clk = $form.clk_x = $form.clk_y = null; }, 10);\n};\n\nfunction submitHandler() {\n    // retrieve options from hash\n    var id = this.formPluginId;\n    var options = $.fn.ajaxForm.optionHash[id];\n    $(this).ajaxSubmit(options);\n    return false;\n};\n\n/**\n * ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm\n *\n * @name   ajaxFormUnbind\n * @return jQuery\n * @cat    Plugins/Form\n * @type   jQuery\n */\n$.fn.ajaxFormUnbind = function() {\n    this.unbind('submit', submitHandler);\n    return this.each(function() {\n        $(\":submit,input:image\", this).unbind('click', clickHandler);\n    });\n\n};\n\n/**\n * formToArray() gathers form element data into an array of objects that can\n * be passed to any of the following ajax functions: $.get, $.post, or load.\n * Each object in the array has both a 'name' and 'value' property.  An example of\n * an array for a simple login form might be:\n *\n * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]\n *\n * It is this array that is passed to pre-submit callback functions provided to the\n * ajaxSubmit() and ajaxForm() methods.\n *\n * The semantic argument can be used to force form serialization in semantic order.\n * This is normally true anyway, unless the form contains input elements of type='image'.\n * If your form must be submitted with name/value pairs in semantic order and your form\n * contains an input of type='image\" then pass true for this arg, otherwise pass false\n * (or nothing) to avoid the overhead for this logic.\n *\n * @example var data = $(\"#myForm\").formToArray();\n * $.post( \"myscript.cgi\", data );\n * @desc Collect all the data from a form and submit it to the server.\n *\n * @name formToArray\n * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)\n * @type Array<Object>\n * @cat Plugins/Form\n */\n$.fn.formToArray = function(semantic) {\n    var a = [];\n    if (this.length == 0) return a;\n\n    var form = this[0];\n    var els = semantic ? form.getElementsByTagName('*') : form.elements;\n    if (!els) return a;\n    for(var i=0, max=els.length; i < max; i++) {\n        var el = els[i];\n        var n = el.name;\n        if (!n) continue;\n\n        if (semantic && form.clk && el.type == \"image\") {\n            // handle image inputs on the fly when semantic == true\n            if(!el.disabled && form.clk == el)\n                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});\n            continue;\n        }\n\n        var v = $.fieldValue(el, true);\n        if (v && v.constructor == Array) {\n            for(var j=0, jmax=v.length; j < jmax; j++)\n                a.push({name: n, value: v[j]});\n        }\n        else if (v !== null && typeof v != 'undefined')\n            a.push({name: n, value: v});\n    }\n\n    if (!semantic && form.clk) {\n        // input type=='image' are not found in elements array! handle them here\n        var inputs = form.getElementsByTagName(\"input\");\n        for(var i=0, max=inputs.length; i < max; i++) {\n            var input = inputs[i];\n            var n = input.name;\n            if(n && !input.disabled && input.type == \"image\" && form.clk == input)\n                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});\n        }\n    }\n    return a;\n};\n\n\n/**\n * Serializes form data into a 'submittable' string. This method will return a string\n * in the format: name1=value1&amp;name2=value2\n *\n * The semantic argument can be used to force form serialization in semantic order.\n * If your form must be submitted with name/value pairs in semantic order then pass\n * true for this arg, otherwise pass false (or nothing) to avoid the overhead for\n * this logic (which can be significant for very large forms).\n *\n * @example var data = $(\"#myForm\").formSerialize();\n * $.ajax('POST', \"myscript.cgi\", data);\n * @desc Collect all the data from a form into a single string\n *\n * @name formSerialize\n * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)\n * @type String\n * @cat Plugins/Form\n */\n$.fn.formSerialize = function(semantic) {\n    //hand off to jQuery.param for proper encoding\n    return $.param(this.formToArray(semantic));\n};\n\n\n/**\n * Serializes all field elements in the jQuery object into a query string.\n * This method will return a string in the format: name1=value1&amp;name2=value2\n *\n * The successful argument controls whether or not serialization is limited to\n * 'successful' controls (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).\n * The default value of the successful argument is true.\n *\n * @example var data = $(\"input\").formSerialize();\n * @desc Collect the data from all successful input elements into a query string\n *\n * @example var data = $(\":radio\").formSerialize();\n * @desc Collect the data from all successful radio input elements into a query string\n *\n * @example var data = $(\"#myForm :checkbox\").formSerialize();\n * @desc Collect the data from all successful checkbox input elements in myForm into a query string\n *\n * @example var data = $(\"#myForm :checkbox\").formSerialize(false);\n * @desc Collect the data from all checkbox elements in myForm (even the unchecked ones) into a query string\n *\n * @example var data = $(\":input\").formSerialize();\n * @desc Collect the data from all successful input, select, textarea and button elements into a query string\n *\n * @name fieldSerialize\n * @param successful true if only successful controls should be serialized (default is true)\n * @type String\n * @cat Plugins/Form\n */\n$.fn.fieldSerialize = function(successful) {\n    var a = [];\n    this.each(function() {\n        var n = this.name;\n        if (!n) return;\n        var v = $.fieldValue(this, successful);\n        if (v && v.constructor == Array) {\n            for (var i=0,max=v.length; i < max; i++)\n                a.push({name: n, value: v[i]});\n        }\n        else if (v !== null && typeof v != 'undefined')\n            a.push({name: this.name, value: v});\n    });\n    //hand off to jQuery.param for proper encoding\n    return $.param(a);\n};\n\n\n/**\n * Returns the value(s) of the element in the matched set.  For example, consider the following form:\n *\n *  <form><fieldset>\n *      <input name=\"A\" type=\"text\" />\n *      <input name=\"A\" type=\"text\" />\n *      <input name=\"B\" type=\"checkbox\" value=\"B1\" />\n *      <input name=\"B\" type=\"checkbox\" value=\"B2\"/>\n *      <input name=\"C\" type=\"radio\" value=\"C1\" />\n *      <input name=\"C\" type=\"radio\" value=\"C2\" />\n *  </fieldset></form>\n *\n *  var v = $(':text').fieldValue();\n *  // if no values are entered into the text inputs\n *  v == ['','']\n *  // if values entered into the text inputs are 'foo' and 'bar'\n *  v == ['foo','bar']\n *\n *  var v = $(':checkbox').fieldValue();\n *  // if neither checkbox is checked\n *  v === undefined\n *  // if both checkboxes are checked\n *  v == ['B1', 'B2']\n *\n *  var v = $(':radio').fieldValue();\n *  // if neither radio is checked\n *  v === undefined\n *  // if first radio is checked\n *  v == ['C1']\n *\n * The successful argument controls whether or not the field element must be 'successful'\n * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).\n * The default value of the successful argument is true.  If this value is false the value(s)\n * for each element is returned.\n *\n * Note: This method *always* returns an array.  If no valid value can be determined the\n *       array will be empty, otherwise it will contain one or more values.\n *\n * @example var data = $(\"#myPasswordElement\").fieldValue();\n * alert(data[0]);\n * @desc Alerts the current value of the myPasswordElement element\n *\n * @example var data = $(\"#myForm :input\").fieldValue();\n * @desc Get the value(s) of the form elements in myForm\n *\n * @example var data = $(\"#myForm :checkbox\").fieldValue();\n * @desc Get the value(s) for the successful checkbox element(s) in the jQuery object.\n *\n * @example var data = $(\"#mySingleSelect\").fieldValue();\n * @desc Get the value(s) of the select control\n *\n * @example var data = $(':text').fieldValue();\n * @desc Get the value(s) of the text input or textarea elements\n *\n * @example var data = $(\"#myMultiSelect\").fieldValue();\n * @desc Get the values for the select-multiple control\n *\n * @name fieldValue\n * @param Boolean successful true if only the values for successful controls should be returned (default is true)\n * @type Array<String>\n * @cat Plugins/Form\n */\n$.fn.fieldValue = function(successful) {\n    for (var val=[], i=0, max=this.length; i < max; i++) {\n        var el = this[i];\n        var v = $.fieldValue(el, successful);\n        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))\n            continue;\n        v.constructor == Array ? $.merge(val, v) : val.push(v);\n    }\n    return val;\n};\n\n/**\n * Returns the value of the field element.\n *\n * The successful argument controls whether or not the field element must be 'successful'\n * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).\n * The default value of the successful argument is true.  If the given element is not\n * successful and the successful arg is not false then the returned value will be null.\n *\n * Note: If the successful flag is true (default) but the element is not successful, the return will be null\n * Note: The value returned for a successful select-multiple element will always be an array.\n * Note: If the element has no value the return value will be undefined.\n *\n * @example var data = jQuery.fieldValue($(\"#myPasswordElement\")[0]);\n * @desc Gets the current value of the myPasswordElement element\n *\n * @name fieldValue\n * @param Element el The DOM element for which the value will be returned\n * @param Boolean successful true if value returned must be for a successful controls (default is true)\n * @type String or Array<String> or null or undefined\n * @cat Plugins/Form\n */\n$.fieldValue = function(el, successful) {\n    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();\n    if (typeof successful == 'undefined') successful = true;\n\n    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||\n        (t == 'checkbox' || t == 'radio') && !el.checked ||\n        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||\n        tag == 'select' && el.selectedIndex == -1))\n            return null;\n\n    if (tag == 'select') {\n        var index = el.selectedIndex;\n        if (index < 0) return null;\n        var a = [], ops = el.options;\n        var one = (t == 'select-one');\n        var max = (one ? index+1 : ops.length);\n        for(var i=(one ? index : 0); i < max; i++) {\n            var op = ops[i];\n            if (op.selected) {\n                // extra pain for IE...\n                var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;\n                if (one) return v;\n                a.push(v);\n            }\n        }\n        return a;\n    }\n    return el.value;\n};\n\n\n/**\n * Clears the form data.  Takes the following actions on the form's input fields:\n *  - input text fields will have their 'value' property set to the empty string\n *  - select elements will have their 'selectedIndex' property set to -1\n *  - checkbox and radio inputs will have their 'checked' property set to false\n *  - inputs of type submit, button, reset, and hidden will *not* be effected\n *  - button elements will *not* be effected\n *\n * @example $('form').clearForm();\n * @desc Clears all forms on the page.\n *\n * @name clearForm\n * @type jQuery\n * @cat Plugins/Form\n */\n$.fn.clearForm = function() {\n    return this.each(function() {\n        $('input,select,textarea', this).clearFields();\n    });\n};\n\n/**\n * Clears the selected form elements.  Takes the following actions on the matched elements:\n *  - input text fields will have their 'value' property set to the empty string\n *  - select elements will have their 'selectedIndex' property set to -1\n *  - checkbox and radio inputs will have their 'checked' property set to false\n *  - inputs of type submit, button, reset, and hidden will *not* be effected\n *  - button elements will *not* be effected\n *\n * @example $('.myInputs').clearFields();\n * @desc Clears all inputs with class myInputs\n *\n * @name clearFields\n * @type jQuery\n * @cat Plugins/Form\n */\n$.fn.clearFields = $.fn.clearInputs = function() {\n    return this.each(function() {\n        var t = this.type, tag = this.tagName.toLowerCase();\n        if (t == 'text' || t == 'password' || tag == 'textarea')\n            this.value = '';\n        else if (t == 'checkbox' || t == 'radio')\n            this.checked = false;\n        else if (tag == 'select')\n            this.selectedIndex = -1;\n    });\n};\n\n\n/**\n * Resets the form data.  Causes all form elements to be reset to their original value.\n *\n * @example $('form').resetForm();\n * @desc Resets all forms on the page.\n *\n * @name resetForm\n * @type jQuery\n * @cat Plugins/Form\n */\n$.fn.resetForm = function() {\n    return this.each(function() {\n        // guard against an input with the name of 'reset'\n        // note that IE reports the reset function as an 'object'\n        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))\n            this.reset();\n    });\n};\n\n})(jQuery);\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/vendor/jquery.lint.js",
    "content": "/**\n * jQuery Lint\n * ---\n * VERSION 0.2\n * ---\n * jQuery lint creates a thin blanket over jQuery that'll\n * report any potentially erroneous activity the console.\n * ---\n * Idea from:\n *      http://markmail.org/message/wzkosk2s5jklpkv4\n *      http://groups.google.com/group/jquery-dev/browse_thread/thread/9a15cca62ceb2444\n * ---\n * @author James Padolsey\n * @contributors ...\n * ---\n * Dual licensed under the MIT and GPL licenses.\n *    - http://www.opensource.org/licenses/mit-license.php\n *    - http://www.gnu.org/copyleft/gpl.html\n */\n\n(function(){\n    \n    var alias = 'jQuery',\n        \n        // Define console if not defined\n        // Feel free to edit this\n        _console = {\n            warn: window.console && console.warn || function(){},\n            group: window.console && console.group || function(){},\n            groupEnd: window.console && console.groupEnd || function(){},\n            groupCollapsed: window.console && console.groupCollapsed || function(){},\n            log: window.console && console.log || function(){}\n        },\n        \n        langs = {\n            en: {\n                incorrectCall: '%0(...) called incorrectly',\n                specialCheckFailed: '%0(...) special check failed',\n                moreInfo: 'More info:',\n                youPassed: 'You passed: ',\n                collection: 'Collection:',\n                availableSigsInclude: 'Available signatures include: ',\n                errorThrown: 'When I called %0(...) with your args, an error was thrown!',\n                repeatSelector: 'You\\'ve used the same selector more than once.',\n                info: 'Info',\n                selector: 'Selector: ',\n                selectorAdvice: 'You should only use the same selector more than once when you know the returned collection will be different. For example, if you\\'ve added more elements to the page that may comply with the selector',\n                noElementsFound: 'No elements were found with the selector: \"%0\"',\n                combineCalls: 'Why not combine these calls by passing an object? E.g. \\n%0(%1)',\n                methodTwice: 'You\\'ve called %0(...) more than once on the same jQuery object',\n                triggeredBy: 'Triggered by %0 event',\n                event: 'Event:',\n                handler: 'Handler:',\n                location: 'Location:'\n            }\n        },\n        \n        // Add specific checks\n        // This is the best place to bring up bad practices\n        specialChecks = [\n            {/* Level 0 */},\n            {/* Level 1 */},\n            {/* Level 2 */},\n            {/* Level 3 */}\n        ],\n        \n        // Local scope jQuery\n        _jQuery = window[alias],\n        \n        lint = {\n            level: 3,\n            special: specialChecks,\n            lang: 'en',\n            langs: langs,\n            console: _console\n        },\n        \n        // Only cover certain fns under the jQ namespace\n        jQNameSpace = /^(ajax|get|post|proxy|each|map|queue|ajax.+|removeData|data|pushStack)$/,\n        \n        // API data, only with what we need\n        api = {\"jQuery.proxy\":[{added:\"1.4\",arg:[{name:\"function\",type:\"Function\"},{name:\"scope\",type:\"Object\"}]},{added:\"1.4\",arg:[{name:\"scope\",type:\"Object\"},{name:\"name\",type:\"String\"}]}],focusout:[{added:\"1.4\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]}],focusin:[{added:\"1.4\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]}],has:[{added:\"1.4\",arg:[{name:\"selector\",type:\"String\"}]},{added:\"1.4\",arg:[{name:\"contained\",type:\"Element\"}]},{added:\"1.1.4\"}],\"jQuery.contains\":[{added:\"1.4\",arg:[{name:\"container\",type:\"Element\"},{name:\"contained\",type:\"Element\"}]}],\"jQuery.noop\":[{added:\"1.4\"}],delay:[{added:\"1.4\",arg:[{name:\"duration\",type:\"Integer\"},{name:\"queueName\",type:\"String\",optional:true}]}],parentsUntil:[{added:\"1.4\",arg:[{name:\"selector\",type:\"Selector\",optional:true}]}],prevUntil:[{added:\"1.4\",arg:[{name:\"selector\",type:\"Selector\",optional:true}]}],nextUntil:[{added:\"1.4\",arg:[{name:\"selector\",type:\"Selector\",optional:true}]}],\"event.isImmediatePropagationStopped\":[{added:\"1.3\"}],\"event.stopImmediatePropagation\":[{added:\"1.3\"}],\"event.isPropagationStopped\":[{added:\"1.3\"}],\"event.stopPropagation\":[{added:\"1.0\"}],\"event.isDefaultPrevented\":[{added:\"1.3\"}],\"event.preventDefault\":[{added:\"1.0\"}],\"event.timeStamp\":[{added:\"1.2.6\"}],\"event.result\":[{added:\"1.3\"}],\"event.which\":[{added:\"1.1.3\"}],\"event.pageY\":[{added:\"1.0.4\"}],\"event.pageX\":[{added:\"1.0.4\"}],\"event.currentTarget\":[{added:\"1.3\"}],\"event.relatedTarget\":[{added:\"1.1.4\"}],\"event.data\":[{added:\"1.1\"}],\"event.target\":[{added:\"1.0\"}],\"event.type\":[{added:\"1.0\"}],\"jQuery.fx.off\":[{added:\"1.3\"}],each:[{added:\"1.0\",arg:[{name:\"function(index, Element)\",type:\"Function\"}]}],\"jQuery.pushStack\":[{added:\"1.0\",arg:[{name:\"elements\",type:\"Array\"}]},{added:\"1.3\",arg:[{name:\"elements\",type:\"Array\"},{name:\"name\",type:\"String\"},{name:\"arguments\",type:\"Array\"}]}],\"jQuery.globalEval\":[{added:\"1.0.4\",arg:[{name:\"code\",type:\"String\"}]}],\"jQuery.isXMLDoc\":[{added:\"1.1.4\",arg:[{name:\"node\",type:\"Element\"}]}],\"jQuery.removeData\":[{added:\"1.2.3\",arg:[{name:\"name\",type:\"String\",optional:true}]}],\"jQuery.data\":[{added:\"1.2.3\",arg:[{name:\"element\",type:\"Element\"},{name:\"key\",type:\"String\"},{name:\"value\",type:\"Object\"}]},{added:\"1.2.3\",arg:[{name:\"element\",type:\"Element\"},{name:\"key\",type:\"String\"}]},{added:\"1.4\"}],\"jQuery.dequeue\":[{added:\"1.3\",arg:[{name:\"queueName\",type:\"String\",optional:true}]}],\"jQuery.queue\":[{added:\"1.3\",arg:[{name:\"queueName\",type:\"String\",optional:true}]},{added:\"1.3\",arg:[{name:\"queueName\",type:\"String\",optional:true},{name:\"newQueue\",type:\"Array\"}]},{added:\"1.3\",arg:[{name:\"queueName\",type:\"String\",optional:true},{name:\"callback()\",type:\"Function\"}]}],clearQueue:[{added:\"1.4\",arg:[{name:\"queueName\",type:\"String\",optional:true}]}],toArray:[{added:\"1.4\"}],\"jQuery.isEmptyObject\":[{added:\"1.4\",arg:[{name:\"object\",type:\"Object\"}]}],\"jQuery.isPlainObject\":[{added:\"1.4\",arg:[{name:\"object\",type:\"Object\"}]}],keydown:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],index:[{added:\"1.4\"},{added:\"1.4\",arg:[{name:\"selector\",type:\"Selector\"}]},{added:\"1.0\",arg:[{name:\"element\",type:\"Element, jQuery\"}]}],removeData:[{added:\"1.2.3\",arg:[{name:\"name\",type:\"String\",optional:true}]}],data:[{added:\"1.2.3\",arg:[{name:\"key\",type:\"String\"},{name:\"value\",type:\"Object\"}]},{added:\"1.4\",arg:[{name:\"obj\",type:\"Object\"}]},{added:\"1.2.3\",arg:[{name:\"key\",type:\"String\"}]},{added:\"1.4\"}],get:[{added:\"1.0\",arg:[{name:\"index\",type:\"Number\",optional:true}]}],size:[{added:\"1.0\"}],\"jQuery.noConflict\":[{added:\"1.0\",arg:[{name:\"removeAll\",type:\"Boolean\",optional:true}]}],selected:[{added:\"1.0\"}],checked:[{added:\"1.0\"}],disabled:[{added:\"1.0\"}],enabled:[{added:\"1.0\"}],file:[{added:\"1.0\"}],button:[{added:\"1.0\"}],reset:[{added:\"1.0\"}],image:[{added:\"1.0\"}],submit:[{added:\"1.0\"},{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],checkbox:[{added:\"1.0\"}],radio:[{added:\"1.0\"}],password:[{added:\"1.0\"}],text:[{added:\"1.0\"},{added:\"1.0\"},{added:\"1.0\",arg:[{name:\"textString\",type:\"String\"}]},{added:\"1.4\",arg:[{name:\"function(index, text)\",type:\"Function\"}]}],input:[{added:\"1.0\"}],\"only-child\":[{added:\"1.1.4\"}],\"last-child\":[{added:\"1.1.4\"}],\"first-child\":[{added:\"1.1.4\"}],\"nth-child\":[{added:\"1.1.4\",arg:[{name:\"index\",type:\"Number/String\"}]}],attributeContainsPrefix:[{added:\"1.0\",arg:[{name:\"attribute\",type:\"String\"},{name:\"value\",type:\"String\"}]}],attributeContainsWord:[{added:\"1.0\",arg:[{name:\"attribute\",type:\"String\"},{name:\"value\",type:\"String\"}]}],attributeMultiple:[{added:\"1.0\",arg:[{name:\"attributeFilter1\",type:\"Selector\"},{name:\"attributeFilter2\",type:\"Selector\"},{name:\"attributeFilterN\",type:\"Selector\",optional:true}]}],attributeContains:[{added:\"1.0\",arg:[{name:\"attribute\",type:\"String\"},{name:\"value\",type:\"String\"}]}],attributeEndsWith:[{added:\"1.0\",arg:[{name:\"attribute\",type:\"String\"},{name:\"value\",type:\"String\"}]}],attributeStartsWith:[{added:\"1.0\",arg:[{name:\"attribute\",type:\"String\"},{name:\"value\",type:\"String\"}]}],attributeNotEqual:[{added:\"1.0\",arg:[{name:\"attribute\",type:\"String\"},{name:\"value\",type:\"String\"}]}],attributeEquals:[{added:\"1.0\",arg:[{name:\"attribute\",type:\"String\"},{name:\"value\",type:\"String\"}]}],attributeHas:[{added:\"1.0\",arg:[{name:\"attribute\",type:\"String\"}]}],visible:[{added:\"1.0\"}],hidden:[{added:\"1.0\"}],parent:[{added:\"1.0\"},{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\",optional:true}]}],empty:[{added:\"1.0\"},{added:\"1.0\"}],contains:[{added:\"1.1.4\"}],animated:[{added:\"1.2\"}],header:[{added:\"1.2\"}],lt:[{added:\"1.0\",arg:[{name:\"index\",type:\"Number\"}]}],gt:[{added:\"1.0\"}],eq:[{added:\"1.0\",arg:[{name:\"index\",type:\"Number\"}]},{added:\"1.1.2\",arg:[{name:\"index\",type:\"Integer\"}]}],odd:[{added:\"1.0\"}],even:[{added:\"1.0\"}],not:[{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\"}]},{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\"}]},{added:\"1.0\",arg:[{name:\"elements\",type:\"Elements\"}]},{added:\"1.0\",arg:[{name:\"function(index)\",type:\"Function\"}]}],last:[{added:\"1.0\"},{added:\"1.2\"}],first:[{added:\"1.0\"},{added:\"1.2\"}],\"next siblings\":[{added:\"1.0\",arg:[{name:\"prev\",type:\"Selector\"},{name:\"siblings\",type:\"Selector\"}]}],\"next adjacent\":[{added:\"1.0\",arg:[{name:\"prev\",type:\"Selector\"},{name:\"next\",type:\"Selector\"}]}],child:[{added:\"1.0\",arg:[{name:\"parent\",type:\"Selector\"},{name:\"child\",type:\"Selector\"}]}],descendant:[{added:\"1.0\",arg:[{name:\"ancestor\",type:\"Selector\"},{name:\"descendant\",type:\"Selector\"}]}],multiple:[{added:\"1.0\",arg:[{name:\"selector1\",type:\"Selector\"},{name:\"selector2\",type:\"Selector\"},{name:\"selectorN\",type:\"Selector\",optional:true}]}],all:[{added:\"1.0\"}],\"class\":[{added:\"1.0\",arg:[{name:\"class\",type:\"String\"}]}],element:[{added:\"1.0\",arg:[{name:\"element\",type:\"String\"}]}],id:[{added:\"1.0\",arg:[{name:\"id\",type:\"String\"}]}],scroll:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],resize:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],dequeue:[{added:\"1.2\",arg:[{name:\"queueName\",type:\"String\",optional:true}]}],queue:[{added:\"1.2\",arg:[{name:\"queueName\",type:\"String\",optional:true}]},{added:\"1.2\",arg:[{name:\"queueName\",type:\"String\",optional:true},{name:\"newQueue\",type:\"Array\"}]},{added:\"1.2\",arg:[{name:\"queueName\",type:\"String\",optional:true},{name:\"callback( next )\",type:\"Function\"}]}],keyup:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],keypress:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],select:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],change:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],blur:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],focus:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],mousemove:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],hover:[{added:\"1.0\",arg:[{name:\"handlerIn(eventObject)\",type:\"Function\"},{name:\"handlerOut(eventObject)\",type:\"Function\"}]}],mouseleave:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],mouseenter:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],mouseout:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],mouseover:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],dblclick:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],click:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],mouseup:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],mousedown:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\"}],error:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]}],unload:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]}],load:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\",arg:[{name:\"url\",type:\"String\"},{name:\"data\",type:\"Map, String\",optional:true},{name:\"success(responseText, textStatus, XMLHttpRequest)\",type:\"Function\",optional:true}]}],ready:[{added:\"1.0\",arg:[{name:\"handler\",type:\"Function\"}]}],die:[{added:\"1.3\",arg:[{name:\"eventType\",type:\"String\"},{name:\"handler\",type:\"String\",optional:true}]}],\"jQuery.browser\":[{added:\"1.0\"}],\"jQuery.browser.version\":[{added:\"1.1.3\"}],live:[{added:\"1.3\",arg:[{name:\"eventType\",type:\"String\"},{name:\"handler\",type:\"Function\"}]},{added:\"1.4\",arg:[{name:\"eventType\",type:\"String\"},{name:\"eventData\",type:\"Object\",optional:true},{name:\"handler\",type:\"Function\"}]}],triggerHandler:[{added:\"1.2\",arg:[{name:\"eventType\",type:\"String\"},{name:\"extraParameters\",type:\"Array\",optional:true}]}],trigger:[{added:\"1.0\",arg:[{name:\"eventType\",type:\"String\"},{name:\"extraParameters\",type:\"Array\"}]}],ajaxComplete:[{added:\"1.0\",arg:[{name:\"handler(event, XMLHttpRequest, ajaxOptions)\",type:\"Function\"}]}],one:[{added:\"1.1\",arg:[{name:\"eventType\",type:\"String\"},{name:\"eventData\",type:\"Object\",optional:true},{name:\"handler(eventObject)\",type:\"Function\"}]}],serializeArray:[{added:\"1.2\"}],serialize:[{added:\"1.0\"}],\"jQuery.ajaxSetup\":[{added:\"1.1\",arg:[{name:\"options\",type:\"Options\"}]}],ajaxSuccess:[{added:\"1.0\",arg:[{name:\"handler(event, XMLHttpRequest, ajaxOptions)\",type:\"Function\"}]}],ajaxStop:[{added:\"1.0\",arg:[{name:\"handler()\",type:\"Function\"}]}],ajaxStart:[{added:\"1.0\",arg:[{name:\"handler()\",type:\"Function\"}]}],ajaxSend:[{added:\"1.0\",arg:[{name:\"handler(event, XMLHttpRequest, ajaxOptions)\",type:\"Function\"}]}],ajaxError:[{added:\"1.0\",arg:[{name:\"handler(event, XMLHttpRequest, ajaxOptions, thrownError)\",type:\"Function\"}]}],unbind:[{added:\"1.0\",arg:[{name:\"eventType\",type:\"String\"},{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.0\",arg:[{name:\"event\",type:\"Object\"}]}],bind:[{added:\"1.0\",arg:[{name:\"eventType\",type:\"String\"},{name:\"eventData\",type:\"Object\",optional:true},{name:\"handler(eventObject)\",type:\"Function\"}]},{added:\"1.4\",arg:[{name:\"events\",type:\"Object\"}]}],slice:[{added:\"1.1.4\",arg:[{name:\"start\",type:\"Integer\"}]},{added:\"1.1.4\",arg:[{name:\"end\",type:\"Integer\",optional:true}]}],jQuery:[{added:\"1.0\",arg:[{name:\"selector\",type:\"selector\"},{name:\"context\",type:\"Element, jQuery\",optional:true}]},{added:\"1.0\",arg:[{name:\"element\",type:\"Element\"}]},{added:\"1.0\",arg:[{name:\"elementArray\",type:\"Array\"}]},{added:\"1.0\",arg:[{name:\"jQuery object\",type:\"Object\"}]},{added:\"1.4\"},{added:\"1.0\",arg:[{name:\"html\",type:\"String\"},{name:\"ownerDocument\",type:\"document\",optional:true}]},{added:\"1.4\",arg:[{name:\"html\",type:\"String\"},{name:\"props\",type:\"Object\"}]},{added:\"1.0\",arg:[{name:\"callback\",type:\"Function\"}]}],stop:[{added:\"1.2\",arg:[{name:\"clearQueue\",type:\"Boolean\",optional:true},{name:\"jumpToEnd\",type:\"Boolean\",optional:true}]}],end:[{added:\"1.0\"}],andSelf:[{added:\"1.2\"}],siblings:[{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\",optional:true}]}],animate:[{added:\"1.0\",arg:[{name:\"properties\",type:\"Options\"},{name:\"duration\",type:\"String,Number\",optional:true},{name:\"easing\",type:\"String\",optional:true},{name:\"callback\",type:\"Callback\",optional:true}]},{added:\"1.0\",arg:[{name:\"properties\",type:\"Options\"},{name:\"options\",type:\"Options\"}]}],prevAll:[{added:\"1.2\",arg:[{name:\"selector\",type:\"Selector\",optional:true}]}],prev:[{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\",optional:true}]}],fadeTo:[{added:\"1.0\",arg:[{name:\"duration\",type:\"String,Number\"},{name:\"opacity\",type:\"Number\"},{name:\"callback\",type:\"Callback\",optional:true}]}],fadeOut:[{added:\"1.0\",arg:[{name:\"duration\",type:\"String,Number\",optional:true},{name:\"callback\",type:\"Callback\",optional:true}]}],parents:[{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\",optional:true}]}],fadeIn:[{added:\"1.0\",arg:[{name:\"duration\",type:\"String,Number\",optional:true},{name:\"callback\",type:\"Callback\",optional:true}]}],offsetParent:[{added:\"1.26\"}],slideToggle:[{added:\"1.0\",arg:[{name:\"duration\",type:\"String,Number\",optional:true},{name:\"callback\",type:\"Callback\",optional:true}]}],\"jQuery.post\":[{added:\"1.0\",arg:[{name:\"url\",type:\"String\"},{name:\"data\",type:\"Map, String\",optional:true},{name:\"success(data, textStatus)\",type:\"Function\",optional:true},{name:\"dataType\",type:\"String\",optional:true}]}],slideUp:[{added:\"1.0\",arg:[{name:\"duration\",type:\"String,Number\",optional:true},{name:\"callback\",type:\"Callback\",optional:true}]}],nextAll:[{added:\"1.2\",arg:[{name:\"selector\",type:\"String\",optional:true}]}],next:[{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\",optional:true}]}],slideDown:[{added:\"1.0\",arg:[{name:\"duration\",type:\"String,Number\",optional:true},{name:\"callback\",type:\"Callback\",optional:true}]}],find:[{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\"}]}],\"jQuery.getScript\":[{added:\"1.0\",arg:[{name:\"url\",type:\"String\"},{name:\"success(data, textStatus)\",type:\"Function\",optional:true}]}],contents:[{added:\"1.2\"}],closest:[{added:\"1.3\",arg:[{name:\"selector\",type:\"Selector\"}]},{added:\"1.4\",arg:[{name:\"selector\",type:\"Selector\"},{name:\"context\",type:\"Element\",optional:true}]},{added:\"1.4\",arg:[{name:\"selectors\",type:\"Array\"},{name:\"context\",type:\"Element\",optional:true}]}],\"jQuery.getJSON\":[{added:\"1.0\",arg:[{name:\"url\",type:\"String\"},{name:\"data\",type:\"Map\",optional:true},{name:\"callback(data, textStatus)\",type:\"Function\",optional:true}]}],\"jQuery.get\":[{added:\"1.0\",arg:[{name:\"url\",type:\"String\"},{name:\"data\",type:\"Map, String\",optional:true},{name:\"callback(data, textStatus, XMLHttpRequest)\",type:\"Function\",optional:true},{name:\"dataType\",type:\"String\",optional:true}]}],\"jQuery.ajax\":[{added:\"1.0\",arg:[{name:\"settings\",type:\"Map\"}]}],length:[{added:\"1.0\"}],children:[{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\",optional:true}]}],selector:[{added:\"1.3\"}],add:[{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\"}]},{added:\"1.0\",arg:[{name:\"elements\",type:\"Elements\"}]},{added:\"1.0\",arg:[{name:\"html\",type:\"HTML\"}]},{added:\"1.4\",arg:[{name:\"selector\",type:\"Selector\"},{name:\"context\",type:\"Element\"}]}],context:[{added:\"1.3\"}],outerWidth:[{added:\"1.2.6\",arg:[{name:\"includeMargin\",type:\"Boolean\",optional:true}]}],outerHeight:[{added:\"1.2.6\",arg:[{name:\"includeMargin\",type:\"Boolean\",optional:true}]}],toggle:[{added:\"1.0\",arg:[{name:\"handler(eventObject)\",type:\"Function\"},{name:\"handler(eventObject)\",type:\"Function\"},{name:\"handler(eventObject)\",type:\"Function\",optional:true}]},{added:\"1.0\",arg:[{name:\"duration\",type:\"String,Number\",optional:true},{name:\"callback\",type:\"Callback\",optional:true}]},{added:\"1.3\",arg:[{name:\"showOrHide\",type:\"Boolean\"}]}],innerWidth:[{added:\"1.2.6\"}],innerHeight:[{added:\"1.2.6\"}],\"jQuery.param\":[{added:\"1.2\",arg:[{name:\"obj\",type:\"Array, Object\"}]},{added:\"1.4\",arg:[{name:\"obj\",type:\"Array, Object\"},{name:\"traditional\",type:\"Boolean\"}]}],hide:[{added:\"1.0\"},{added:\"1.0\",arg:[{name:\"duration\",type:\"String,Number\"},{name:\"callback\",type:\"\",optional:true}]}],width:[{added:\"1.0\"},{added:\"1.0\",arg:[{name:\"value\",type:\"String, Number\"}]}],height:[{added:\"1.0\"},{added:\"1.0\",arg:[{name:\"value\",type:\"String, Number\"}]}],show:[{added:\"1.0\"},{added:\"1.0\",arg:[{name:\"duration\",type:\"String,Number\"},{name:\"callback\",type:\"Callback\",optional:true}]}],scrollLeft:[{added:\"1.2.6\"},{added:\"1.2.6\",arg:[{name:\"value\",type:\"Number\"}]}],\"jQuery.trim\":[{added:\"1.0\"}],\"jQuery.isFunction\":[{added:\"1.2\"}],\"jQuery.isArray\":[{added:\"1.3\",arg:[{name:\"obj\",type:\"Object\"}]}],\"jQuery.unique\":[{added:\"1.1.3\",arg:[{name:\"array\",type:\"Array\"}]}],\"jQuery.merge\":[{added:\"1.0\",arg:[{name:\"first\",type:\"Array\"},{name:\"second\",type:\"Array\"}]}],\"jQuery.inArray\":[{added:\"1.2\",arg:[{name:\"value\",type:\"Any\"},{name:\"array\",type:\"Array\"}]}],\"jQuery.map\":[{added:\"1.0\",arg:[{name:\"array\",type:\"Array\"},{name:\"callback(elementOfArray, indexInArray)\",type:\"Function\"}]}],\"jQuery.makeArray\":[{added:\"1.2\",arg:[{name:\"obj\",type:\"Object\"}]}],\"jQuery.grep\":[{added:\"1.0\",arg:[{name:\"array\",type:\"Array\"},{name:\"function(elementOfArray, indexInArray)\",type:\"Function\"},{name:\"invert\",type:\"Boolean\",optional:true}]}],\"jQuery.extend\":[{added:\"1.0\",arg:[{name:\"target\",type:\"Object\"},{name:\"object1\",type:\"Object\",optional:true},{name:\"objectN\",type:\"Object\",optional:true}]},{added:\"1.1.4\",arg:[{name:\"deep\",type:\"Boolean\",optional:true},{name:\"target\",type:\"Object\"},{name:\"object1\",type:\"Object\"},{name:\"objectN\",type:\"Object\",optional:true}]}],\"jQuery.each\":[{added:\"1.0\",arg:[{name:\"object\",type:\"Object\"},{name:\"callback(indexInArray, valueOfElement)\",type:\"Function\"}]}],\"jQuery.boxModel\":[{added:\"1.0\"}],scrollTop:[{added:\"1.2.6\"},{added:\"1.2.6\",arg:[{name:\"value\",type:\"Number\"}]}],\"jQuery.support\":[{added:\"1.3\"}],position:[{added:\"1.2\"}],offset:[{added:\"1.2\"},{added:\"1.4\",arg:[{name:\"coordinates\",type:\"Object\"}]},{added:\"1.4\",arg:[{name:\"function(index, coords)\",type:\"Function\"}]}],css:[{added:\"1.0\",arg:[{name:\"propertyName\",type:\"String\"}]},{added:\"1.0\",arg:[{name:\"propertyName\",type:\"String\"},{name:\"value\",type:\"String, Number\"}]},{added:\"1.4\",arg:[{name:\"propertyName\",type:\"String\"},{name:\"function(index, value)\",type:\"Function\"}]},{added:\"1.0\",arg:[{name:\"map\",type:\"Map\"}]}],unwrap:[{added:\"1.4\"}],detach:[{added:\"1.4\",arg:[{name:\"selector\",type:\"Selector\",optional:true}]}],clone:[{added:\"1.0\",arg:[{name:\"withDataAndEvents\",type:\"Boolean\",optional:true}]}],remove:[{added:\"1.0\",arg:[{name:\"selector\",type:\"String\",optional:true}]}],replaceAll:[{added:\"1.2\"}],replaceWith:[{added:\"1.2\",arg:[{name:\"newContent\",type:\"String, Element, jQuery\"}]},{added:\"1.4\",arg:[{name:\"function\",type:\"Function\"}]}],wrapInner:[{added:\"1.2\",arg:[{name:\"wrappingElement\",type:\"String\"}]},{added:\"1.4\",arg:[{name:\"wrappingFunction\",type:\"Function\"}]}],wrapAll:[{added:\"1.2\",arg:[{name:\"wrappingElement\",type:\"String, Selector, Element, jQuery\"}]}],wrap:[{added:\"1.0\",arg:[{name:\"wrappingElement\",type:\"String, Selector, Element, jQuery\"}]},{added:\"1.4\",arg:[{name:\"wrappingFunction\",type:\"Function\"}]}],insertBefore:[{added:\"1.0\",arg:[{name:\"target\",type:\"Selector, Element, jQuery\"}]}],before:[{added:\"1.0\",arg:[{name:\"content\",type:\"String, Element, jQuery\"}]},{added:\"1.4\",arg:[{name:\"function\",type:\"Function\"}]}],insertAfter:[{added:\"1.0\",arg:[{name:\"target\",type:\"Selector, Element, jQuery\"}]}],after:[{added:\"1.0\",arg:[{name:\"content\",type:\"String, Element, jQuery\"}]},{added:\"1.4\",arg:[{name:\"function\",type:\"Function\"}]}],prependTo:[{added:\"1.0\",arg:[{name:\"target\",type:\"Selector, Element, jQuery\"}]}],prepend:[{added:\"1.0\",arg:[{name:\"content\",type:\"String, Element, jQuery\"}]},{added:\"1.4\",arg:[{name:\"function(index, html)\",type:\"Function\"}]}],appendTo:[{added:\"1.0\",arg:[{name:\"target\",type:\"Selector, Element, jQuery\"}]}],append:[{added:\"1.0\",arg:[{name:\"content\",type:\"String, Element, jQuery\"}]},{added:\"1.4\",arg:[{name:\"function(index, html)\",type:\"Function\"}]}],val:[{added:\"1.0\"},{added:\"1.0\",arg:[{name:\"value\",type:\"String\"}]},{added:\"1.4\",arg:[{name:\"function\",type:\"Function\"}]}],html:[{added:\"1.0\"},{added:\"1.0\",arg:[{name:\"htmlString\",type:\"String\"}]},{added:\"1.4\",arg:[{name:\"function(index, html)\",type:\"Function\"}]}],map:[{added:\"1.2\",arg:[{name:\"callback(index, domElement)\",type:\"Function\"}]}],is:[{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\"}]}],filter:[{added:\"1.0\",arg:[{name:\"selector\",type:\"Selector\"}]},{added:\"1.0\",arg:[{name:\"function(index)\",type:\"Function\"}]}],toggleClass:[{added:\"1.0\",arg:[{name:\"className\",type:\"String\"}]},{added:\"1.3\",arg:[{name:\"className\",type:\"String\"},{name:\"switch\",type:\"Boolean\"}]},{added:\"1.4\",arg:[{name:\"function(index, class)\",type:\"Function\"},{name:\"switch\",type:\"Boolean\",optional:true}]}],removeClass:[{added:\"1.0\",arg:[{name:\"className\",type:\"String\",optional:true}]},{added:\"1.4\",arg:[{name:\"function(index, class)\",type:\"Function\"}]}],hasClass:[{added:\"1.2\",arg:[{name:\"className\",type:\"String\"}]}],removeAttr:[{added:\"1.0\",arg:[{name:\"attributeName\",type:\"String\"}]}],attr:[{added:\"1.0\",arg:[{name:\"attributeName\",type:\"String\"}]},{added:\"1.0\",arg:[{name:\"attributeName\",type:\"String\"},{name:\"value\",type:\"Object\"}]},{added:\"1.0\",arg:[{name:\"map\",type:\"Map\"}]},{added:\"1.1\",arg:[{name:\"attributeName\",type:\"String\"},{name:\"function(index, attr)\",type:\"Function\"}]}],addClass:[{added:\"1.0\",arg:[{name:\"className\",type:\"String\"}]},{added:\"1.4\",arg:[{name:\"function(index, class)\",type:\"Function\"}]}]};\n    \n    if ( !_jQuery ) {\n        return;\n    }\n    \n    lint.api = api;\n    \n    // Correct API\n    // Yes, it's ugly, but necessary...\n    api['jQuery.data'][1].arg[1].optional = true; // Making $.data(.,THIS) optional\n    api.each[0].arg[1] = api['jQuery.each'][0].arg[2] = {name:'args', type:'Array', optional:true};\n    api['jQuery.data'][0].arg[2].type = '*';\n    api.attr[1].arg[1].type = '*';\n    api['jQuery.each'][0].arg[0].type += ', Array';\n    // extraParam to trigger & triggerHandler IS optional\n    api.trigger[0].arg[1].optional = true;\n    api.triggerHandler[0].arg[1].optional = true;\n    api.slice[0].arg[1] = {name:'end',type:'Integer',optional:true};\n    // Add elem arg to start of args for jQuery.queue\n    var jQQueue = api['jQuery.queue'];\n    jQQueue[0].arg.unshift({type:'Element', name:'elem'});\n    jQQueue[1].arg.unshift({type:'Element', name:'elem'});\n    jQQueue[2].arg.unshift({type:'Element', name:'elem'}); \n    \n    \n    var version = _jQuery.fn.jquery,\n        map = _jQuery.map,\n        each = _jQuery.each,\n        extend = _jQuery.extend,\n        locale = langs[lint.lang],\n        undefined,\n        slice = function(a,s,e) {\n            return Array.prototype.slice.call(a, s || 0, e || a.length);\n        },\n        compare = function(a,b) {\n            \n            // Compare two arrays\n            \n            var i = a.length;\n            \n            if (a.length !== b.length) {\n                return false;\n            }\n            \n            while (i--) {\n                if (a[i] !== b[i]) {\n                    return false;\n                }\n            }\n            \n            return true;\n        \n        },\n        isFunction = function(obj) {\n            return toString.call(obj) === \"[object Function]\";\n        },\n        isArray = function(obj) {\n            return toString.call(obj) === \"[object Array]\";   \n        },\n        toString = Object.prototype.toString,\n        typeToString = function(o) {\n            \n            if (typeof o === 'string') {\n                return '\"' + o.replace(/\"/g,'\\\\\"') + '\"';\n            }\n            \n            if (isFunction(o)) {\n                return 'function(){...}';\n            }\n            \n            return o.toString();\n        },\n        shaveArray = function(arr) {\n            arr = Array.prototype.slice.call(arr);\n            // Shave \"undefined\" off the end of args\n            for (var i = arr.length; i--;) {\n                if (arr[i] === undefined) {\n                    arr.splice(i, 1);\n                } else {\n                    break;\n                }\n            }\n            return arr;\n        },\n        // type map\n        types = {\n            '*': function() {\n                return true;\n            },\n            selector: function(o) {\n                return this.String(o);\n            },\n            Selector: function(o) {\n                return this.selector(o);\n            },\n            Element: function(o) {\n                return o && (!!o.nodeName || o === window);\n            },\n            Elements: function(o) {\n                return this.jQuery(o) || this.Array(o);\n            },\n            Array: function(o) {\n                // Just check that it's \"array-like\"\n                return o && o.length !== undefined\n                        && typeof o !== 'string' && !isFunction(o);\n            },\n            jQuery: function(o) {\n                return o instanceof _jQuery;\n            },\n            Object: function(o) {\n                return toString.call(o) === '[object Object]';\n            },\n            Function: function(o) {\n                return isFunction(o);\n            },\n            Callback: function(o) {\n                return isFunction(o);\n            },\n            String: function(o) {\n                return typeof o === 'string';\n            },\n            Number: function(o) {\n                return typeof o === 'number' && !isNaN(o);\n            },\n            Integer: function(o) {\n                return this.Number(o) && ~~o === o;\n            },\n            Map: function(o) {\n                return this.Object(o);\n            },\n            Options: function(o) {\n                return this.Object(o);\n            },\n            'null': function(o) {\n                return o === null;\n            }\n        },\n        typeCheck = function typeCheck(type, arg) {\n            \n            // Check that argument is of the right type\n            // The types are specified within the API data\n            \n            if ( types[type] ) {\n                return arg !== undefined && types[type](arg);\n            }\n            \n            if ( type.indexOf(',') ) {\n                \n                var split = type.split(/,\\s?/g),\n                    i = split.length;\n                    \n                while (i--) {\n                    if (types[split[i]] && types[split[i]](arg)) {\n                        return true;\n                    }\n                }\n                \n                return false;\n            }\n            \n            return false;\n                \n        },\n        complies = function complies(args, sig) {\n            \n            // Determine if argument list complies with\n            // signature outlined in API.\n            \n            var matches = false,\n                sigArg,\n                argLength = args.length;\n            \n            if (version < sig.added) {\n                // Too new\n                return false;\n            }\n            \n            if (!sig.arg) {\n                return 0 === args.length;\n            }\n            \n            if (!sig.arg[0] && (args.length > 1)) {\n                return false;\n            }\n            \n            for (\n                    var sigIndex = 0,\n                        argIndex = 0,\n                        fullLength = Math.max(argLength,sig.arg.length||1);\n                    sigIndex < fullLength || argIndex < argLength;\n                    ++sigIndex\n                ) {\n                \n                sigArg = sigIndex === 0 ? sig.arg[0] || sig.arg : sig.arg[sigIndex];\n                \n                if (!sigArg) {\n                    // Too many args\n                    return false;\n                }\n                \n                matches = typeCheck(sigArg.type, args[argIndex]);\n                \n                if (!matches) {\n                    if (sigArg.optional) {\n                        if (args[argIndex] === undefined || args[argIndex] === null) {\n                            ++argIndex;\n                            matches = true;\n                        }\n                        continue;\n                    } else {\n                        // Sig isn't optional, return false\n                        return false;\n                    }\n                }\n                \n                ++argIndex;\n                \n            }\n            \n            return matches;\n            \n        },\n        logLocation = function() {\n            try {\n                throw new Error();\n            } catch(e) {\n                if (e.stack) {\n                    lint.console.groupCollapsed(locale.location);\n                    lint.console.log(e.stack.replace(\n                        /^.+?\\n|.+?(jquery\\.lint\\.js|http:\\/\\/ajax\\.googleapis\\.com\\/ajax\\/libs).+?(\\n|$)|.+?(?=@)/g, ''\n                    ));\n                    lint.console.groupEnd();\n                } else {\n                    return null;\n                }\n            }\n        },\n        selectorCache = {},\n        lastTriggeredEvent = {},\n        logEvent = function() {\n            if (lastTriggeredEvent && lastTriggeredEvent.event) {\n                _console.groupCollapsed(locale.triggeredBy.replace(/%0/, lastTriggeredEvent.event.type));\n                    _console.log(locale.event, lastTriggeredEvent.event);\n                    _console.groupCollapsed(locale.handler);\n                        _console.log(lastTriggeredEvent.handler);\n                    _console.groupEnd();\n                _console.groupEnd();\n            }\n        },\n        internal = false;\n    \n    function coverMethod(name, meth, args) {\n        \n        args = shaveArray(args);\n        \n        var sigs = api[name],\n            _console = lint.console,\n            i = 0,\n            sig,\n            specialCheckResults = (function(){\n                \n                // Perform special checks for current level and\n                // all levels below current level.\n                \n                var lvl = lint.level + 1,\n                    checks = [];\n                    \n                while (lvl--) {\n                    if (specialChecks[lvl] && specialChecks[lvl][name]) {\n                        checks.push(\n                            specialChecks[lvl][name].apply(this, args)\n                        )\n                    }\n                }\n                \n                return checks;\n                \n            })(),\n            signatureMatch = false,\n            self = this,\n            sliced = slice(this, 0, 10),\n            withinEvent = lastTriggeredEvent ? lastTriggeredEvent.type : null;\n        \n        if (!sigs || !lint.level || internal) {\n            return meth.apply(this, args);\n        }\n        \n        if (this.length > 10) {\n            sliced.push('...');\n        }\n        \n        // Check for calls like css().css().css()\n        // May as well use css({...})\n        if (lint.level > 2 && args[1] && !isFunction(args[1]) && /^(css|attr)$/.test(name) || (name === 'bind' && version >= '1.4')) {\n            \n            if (this._lastMethodCalled === name) {\n                _console.warn(locale.methodTwice.replace(/%0/, name));\n                _console.groupCollapsed(locale.moreInfo);\n                    logEvent();\n                    if (this instanceof _jQuery) {\n                        _console.log(locale.collection, sliced);\n                    }\n                    _console.log(\n                        locale.combineCalls\n                            .replace(/%0/, name)\n                            .replace(/%1/, '{\\n' +\n                                map([args, this._lastMethodArgs], function(a){\n                                    return '  \"' + a[0] + '\": ' + typeToString(a[1]);\n                                }).join(',\\n')\n                            + '\\n}')\n                    );\n                _console.groupEnd();\n            }\n            \n            this._lastMethodCalled = name;\n            this._lastMethodArgs = args;\n            setTimeout(function(){\n                self._lastMethodCalled = null;\n                self._lastMethodArgs = null;\n            });\n            \n        }\n        \n        // Check all arguments passed to method for compliance\n        // against the corresponding signature.\n        while ((sig = sigs[i++])) {\n            if ( complies(args, sig) ) {\n                signatureMatch = true;\n                break;\n            }\n        }\n        \n        if (!signatureMatch) {\n            \n            try {\n                \n                // Args !== signature\n                _console.warn(locale.incorrectCall.replace(/%0/, name));\n                _console.groupCollapsed(locale.moreInfo);\n                    logEvent();\n                    if (this instanceof _jQuery) {\n                        _console.log(locale.collection, sliced);\n                    }\n                    logLocation();\n                    _console.log(locale.youPassed, args);\n                    _console.group(locale.availableSigsInclude);\n                        each(sigs, function(i, sig){\n                            if (version < sig.added) {\n                                return;\n                            }\n                            var sigArgs = sig.arg;\n                            _console.log(\n                                name + '(' +\n                                (sigArgs ?\n                                     sigArgs[0] ?\n                                        map(sigArgs, function(sig){\n                                            return sig ? sig.optional ? '[' + sig.name + ']' : sig.name : [];\n                                        }).join(', ') :\n                                        sigArgs.name\n                                : '') + ')'\n                            );\n                        });\n                    _console.groupEnd();\n                _console.groupEnd();\n                \n            } catch(e) { }\n            \n        }\n        \n        try {\n            if (specialCheckResults.length) {\n                each(specialCheckResults, function(i, checkResult){\n                    if (checkResult && checkResult !== true) {\n                        _console.warn(locale.specialCheckFailed.replace(/%0/, name));\n                        _console.groupCollapsed(locale.moreInfo);\n                            if (this instanceof _jQuery) {\n                                _console.log(locale.collection, sliced);\n                            }\n                            logLocation();\n                            _console.log(checkResult);\n                        _console.groupEnd();\n                    }\n                });\n            }\n        } catch(e) { }\n        \n        \n        try {\n            return meth.apply(this, args);\n        } catch(e) {\n            try {\n                _console.warn(\n                    locale.errorThrown.replace(/%0/, name), e\n                );\n                _console.groupCollapsed(locale.moreInfo);\n                    logLocation();\n                    _console.log(locale.youPassed, args);\n                _console.groupEnd();\n            } catch(e) { }\n            return this;\n        }\n        \n    }\n    \n    // \"Cover\" init constructor\n    // Reports when no elements found, and when selector\n    // used more than once to no effect.\n    _jQuery.fn.init = (function(_init){\n        \n        return function(s,c) {\n            \n            var ret = coverMethod.call(this, 'jQuery', function(){\n                \n                    // Set internal flag to avoid incorrect internal method\n                    // calls being reported by Lint.\n                \n                    internal = true;\n                    var instance = new _init(s, c);\n                    internal = false;\n                    \n                    return instance\n                \n                }, arguments),\n                _console = lint.console;\n                \n            try{\n                if (typeof s === 'string' && lint.level > 1) {\n                    if (!ret[0]) {\n                        // No elements returned\n                        _console.warn(locale.noElementsFound.replace(/%0/, s));\n                    } else {\n                        // Check for identical collection already in cache.\n                        if ( selectorCache[s] && compare(selectorCache[s], ret) ) {\n                            \n                            _console.warn(locale.repeatSelector);\n                            _console.groupCollapsed(locale.info);\n                                logEvent();\n                                logLocation();\n                                _console.log(locale.selector + '\"' + s + '\"');\n                                _console.log(locale.selectorAdvice);\n                            _console.groupEnd();\n                            \n                        }\n                    }\n                    selectorCache[s] = ret;\n                }\n            } catch(e) { }\n            \n            return ret;\n        \n        };\n        \n    })(_jQuery.fn.init);\n    \n    // Cover all methods, except init\n    for (var i in _jQuery.fn) {\n        if (i === 'init' || !isFunction(_jQuery.fn[i])) {\n            continue;\n        }\n        _jQuery.fn[i] = (function(meth, name){\n            return function() {\n                return coverMethod.call(this, name, function(){\n                    \n                    // Set internal flag.\n                    // Any subsequent method calls before this\n                    // returns will be ignored. This is to stop\n                    // errors being reported from incorrect usage\n                    // of jQuery's API, internally.\n                    \n                    internal = true;\n                    var ret = meth.apply(this, arguments);\n                    internal = false;\n                    \n                    return ret;\n                \n                }, arguments);\n            };\n        })(_jQuery.fn[i], i);\n    }\n    \n    // Cover some helper function under jQ namespace\n    for (var i in _jQuery) {\n        \n        if ( !jQNameSpace.test(i) || !isFunction(_jQuery[i]) ) {\n            continue;\n        }\n        \n        _jQuery[i] = (function(meth, name){\n            return function() {\n                return coverMethod.call(this, 'jQuery.' + name, function(){\n                    internal = true;\n                    var ret = meth.apply(this, arguments);\n                    internal = false;\n                    return ret;\n                }, arguments);\n            };\n        })(_jQuery[i], i);\n    }\n    \n    _jQuery.LINT = lint;\n    \n    _jQuery.event.add = (function(_add){\n        \n        // Each triggered event gets assigned to lastTriggeredEvent,\n        // Which is immediately nulled after a zero timeout.\n        \n        return function(elem, types, handler, data) {\n            var _handler = handler;\n            handler = function(e) {\n                lastTriggeredEvent = {event: e, handler: _handler.toString()};\n                setTimeout(function(){\n                    lastTriggeredEvent = null\n                }, 0);\n                return _handler.apply(this, arguments);\n            };\n            return _add.call(this, elem, types, handler, data);\n        };\n        \n    })(_jQuery.event.add);\n    \n   \n})();"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/vendor/log.js",
    "content": "function log() {\n\ttry {\n\t\tconsole.log.apply(console, arguments);\n\t} catch(e) {\n\t\t//alert( Array.prototype.join.call( arguments, \" \"));\n\t}\n}\n\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/lib/js/vendor/qunit.js",
    "content": "/*\n * QUnit - A JavaScript Unit Testing Framework\n * \n * http://docs.jquery.com/QUnit\n *\n * Copyright (c) 2009 John Resig, Jörn Zaefferer\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n */\n\n(function(window) {\n\nvar QUnit = {\n\n\t// Initialize the configuration options\n\tinit: function() {\n\t\tconfig = {\n\t\t\tstats: { all: 0, bad: 0 },\n\t\t\tmoduleStats: { all: 0, bad: 0 },\n\t\t\tstarted: +new Date,\n\t\t\tblocking: false,\n\t\t\tautorun: false,\n\t\t\tassertions: [],\n\t\t\tfilters: [],\n\t\t\tqueue: []\n\t\t};\n\n\t\tvar tests = id(\"qunit-tests\"),\n\t\t\tbanner = id(\"qunit-banner\"),\n\t\t\tresult = id(\"qunit-testresult\");\n\n\t\tif ( tests ) {\n\t\t\ttests.innerHTML = \"\";\n\t\t}\n\n\t\tif ( banner ) {\n\t\t\tbanner.className = \"\";\n\t\t}\n\n\t\tif ( result ) {\n\t\t\tresult.parentNode.removeChild( result );\n\t\t}\n\t},\n\t\n\t// call on start of module test to prepend name to all tests\n\tmodule: function(name, testEnvironment) {\n\t\tconfig.currentModule = name;\n\n\t\tsynchronize(function() {\n\t\t\tif ( config.currentModule ) {\n\t\t\t\tQUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );\n\t\t\t}\n\n\t\t\tconfig.currentModule = name;\n\t\t\tconfig.moduleTestEnvironment = testEnvironment;\n\t\t\tconfig.moduleStats = { all: 0, bad: 0 };\n\n\t\t\tQUnit.moduleStart( name, testEnvironment );\n\t\t});\n\t},\n\n\tasyncTest: function(testName, expected, callback) {\n\t\tif ( arguments.length === 2 ) {\n\t\t\tcallback = expected;\n\t\t\texpected = 0;\n\t\t}\n\n\t\tQUnit.test(testName, expected, callback, true);\n\t},\n\t\n\ttest: function(testName, expected, callback, async) {\n\t\tvar name = testName, testEnvironment, testEnvironmentArg;\n\n\t\tif ( arguments.length === 2 ) {\n\t\t\tcallback = expected;\n\t\t\texpected = null;\n\t\t}\n\t\t// is 2nd argument a testEnvironment?\n\t\tif ( expected && typeof expected === 'object') {\n\t\t\ttestEnvironmentArg =  expected;\n\t\t\texpected = null;\n\t\t}\n\n\t\tif ( config.currentModule ) {\n\t\t\tname = config.currentModule + \" module: \" + name;\n\t\t}\n\n\t\tif ( !validTest(name) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tsynchronize(function() {\n\t\t\tQUnit.testStart( testName );\n\n\t\t\ttestEnvironment = extend({\n\t\t\t\tsetup: function() {},\n\t\t\t\tteardown: function() {}\n\t\t\t}, config.moduleTestEnvironment);\n\t\t\tif (testEnvironmentArg) {\n\t\t\t\textend(testEnvironment,testEnvironmentArg);\n\t\t\t}\n\n\t\t\t// allow utility functions to access the current test environment\n\t\t\tQUnit.current_testEnvironment = testEnvironment;\n\t\t\t\n\t\t\tconfig.assertions = [];\n\t\t\tconfig.expected = expected;\n\n\t\t\ttry {\n\t\t\t\tif ( !config.pollution ) {\n\t\t\t\t\tsaveGlobal();\n\t\t\t\t}\n\n\t\t\t\ttestEnvironment.setup.call(testEnvironment);\n\t\t\t} catch(e) {\n\t\t\t\tQUnit.ok( false, \"Setup failed on \" + name + \": \" + e.message );\n\t\t\t}\n\n\t\t\tif ( async ) {\n\t\t\t\tQUnit.stop();\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcallback.call(testEnvironment);\n\t\t\t} catch(e) {\n\t\t\t\tfail(\"Test \" + name + \" died, exception and test follows\", e, callback);\n\t\t\t\tQUnit.ok( false, \"Died on test #\" + (config.assertions.length + 1) + \": \" + e.message );\n\t\t\t\t// else next test will carry the responsibility\n\t\t\t\tsaveGlobal();\n\n\t\t\t\t// Restart the tests if they're blocking\n\t\t\t\tif ( config.blocking ) {\n\t\t\t\t\tstart();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tsynchronize(function() {\n\t\t\ttry {\n\t\t\t\tcheckPollution();\n\t\t\t\ttestEnvironment.teardown.call(testEnvironment);\n\t\t\t} catch(e) {\n\t\t\t\tQUnit.ok( false, \"Teardown failed on \" + name + \": \" + e.message );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tQUnit.reset();\n\t\t\t} catch(e) {\n\t\t\t\tfail(\"reset() failed, following Test \" + name + \", exception and reset fn follows\", e, reset);\n\t\t\t}\n\n\t\t\tif ( config.expected && config.expected != config.assertions.length ) {\n\t\t\t\tQUnit.ok( false, \"Expected \" + config.expected + \" assertions, but \" + config.assertions.length + \" were run\" );\n\t\t\t}\n\n\t\t\tvar good = 0, bad = 0,\n\t\t\t\ttests = id(\"qunit-tests\");\n\n\t\t\tconfig.stats.all += config.assertions.length;\n\t\t\tconfig.moduleStats.all += config.assertions.length;\n\n\t\t\tif ( tests ) {\n\t\t\t\tvar ol  = document.createElement(\"ol\");\n\t\t\t\tol.style.display = \"none\";\n\n\t\t\t\tfor ( var i = 0; i < config.assertions.length; i++ ) {\n\t\t\t\t\tvar assertion = config.assertions[i];\n\n\t\t\t\t\tvar li = document.createElement(\"li\");\n\t\t\t\t\tli.className = assertion.result ? \"pass\" : \"fail\";\n\t\t\t\t\tli.appendChild(document.createTextNode(assertion.message || \"(no message)\"));\n\t\t\t\t\tol.appendChild( li );\n\n\t\t\t\t\tif ( assertion.result ) {\n\t\t\t\t\t\tgood++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbad++;\n\t\t\t\t\t\tconfig.stats.bad++;\n\t\t\t\t\t\tconfig.moduleStats.bad++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar b = document.createElement(\"strong\");\n\t\t\t\tb.innerHTML = name + \" <b style='color:black;'>(<b class='fail'>\" + bad + \"</b>, <b class='pass'>\" + good + \"</b>, \" + config.assertions.length + \")</b>\";\n\t\t\t\t\n\t\t\t\taddEvent(b, \"click\", function() {\n\t\t\t\t\tvar next = b.nextSibling, display = next.style.display;\n\t\t\t\t\tnext.style.display = display === \"none\" ? \"block\" : \"none\";\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\taddEvent(b, \"dblclick\", function(e) {\n\t\t\t\t\tvar target = e && e.target ? e.target : window.event.srcElement;\n\t\t\t\t\tif ( target.nodeName.toLowerCase() === \"strong\" ) {\n\t\t\t\t\t\tvar text = \"\", node = target.firstChild;\n\n\t\t\t\t\t\twhile ( node.nodeType === 3 ) {\n\t\t\t\t\t\t\ttext += node.nodeValue;\n\t\t\t\t\t\t\tnode = node.nextSibling;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttext = text.replace(/(^\\s*|\\s*$)/g, \"\");\n\n\t\t\t\t\t\tif ( window.location ) {\n\t\t\t\t\t\t\twindow.location.href = window.location.href.match(/^(.+?)(\\?.*)?$/)[1] + \"?\" + encodeURIComponent(text);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tvar li = document.createElement(\"li\");\n\t\t\t\tli.className = bad ? \"fail\" : \"pass\";\n\t\t\t\tli.appendChild( b );\n\t\t\t\tli.appendChild( ol );\n\t\t\t\ttests.appendChild( li );\n\n\t\t\t\tif ( bad ) {\n\t\t\t\t\tvar toolbar = id(\"qunit-testrunner-toolbar\");\n\t\t\t\t\tif ( toolbar ) {\n\t\t\t\t\t\ttoolbar.style.display = \"block\";\n\t\t\t\t\t\tid(\"qunit-filter-pass\").disabled = null;\n\t\t\t\t\t\tid(\"qunit-filter-missing\").disabled = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tfor ( var i = 0; i < config.assertions.length; i++ ) {\n\t\t\t\t\tif ( !config.assertions[i].result ) {\n\t\t\t\t\t\tbad++;\n\t\t\t\t\t\tconfig.stats.bad++;\n\t\t\t\t\t\tconfig.moduleStats.bad++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tQUnit.testDone( testName, bad, config.assertions.length );\n\n\t\t\tif ( !window.setTimeout && !config.queue.length ) {\n\t\t\t\tdone();\n\t\t\t}\n\t\t});\n\n\t\tif ( window.setTimeout && !config.doneTimer ) {\n\t\t\tconfig.doneTimer = window.setTimeout(function(){\n\t\t\t\tif ( !config.queue.length ) {\n\t\t\t\t\tdone();\n\t\t\t\t} else {\n\t\t\t\t\tsynchronize( done );\n\t\t\t\t}\n\t\t\t}, 13);\n\t\t}\n\t},\n\t\n\t/**\n\t * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.\n\t */\n\texpect: function(asserts) {\n\t\tconfig.expected = asserts;\n\t},\n\n\t/**\n\t * Asserts true.\n\t * @example ok( \"asdfasdf\".length > 5, \"There must be at least 5 chars\" );\n\t */\n\tok: function(a, msg) {\n\t\tQUnit.log(a, msg);\n\n\t\tconfig.assertions.push({\n\t\t\tresult: !!a,\n\t\t\tmessage: msg\n\t\t});\n\t},\n\n\t/**\n\t * Checks that the first two arguments are equal, with an optional message.\n\t * Prints out both actual and expected values.\n\t *\n\t * Prefered to ok( actual == expected, message )\n\t *\n\t * @example equal( format(\"Received {0} bytes.\", 2), \"Received 2 bytes.\" );\n\t *\n\t * @param Object actual\n\t * @param Object expected\n\t * @param String message (optional)\n\t */\n\tequal: function(actual, expected, message) {\n\t\tpush(expected == actual, actual, expected, message);\n\t},\n\n\tnotEqual: function(actual, expected, message) {\n\t\tpush(expected != actual, actual, expected, message);\n\t},\n\t\n\tdeepEqual: function(a, b, message) {\n\t\tpush(QUnit.equiv(a, b), a, b, message);\n\t},\n\n\tnotDeepEqual: function(a, b, message) {\n\t\tpush(!QUnit.equiv(a, b), a, b, message);\n\t},\n\n\tstrictEqual: function(actual, expected, message) {\n\t\tpush(expected === actual, actual, expected, message);\n\t},\n\n\tnotStrictEqual: function(actual, expected, message) {\n\t\tpush(expected !== actual, actual, expected, message);\n\t},\n\t\n\tstart: function() {\n\t\t// A slight delay, to avoid any current callbacks\n\t\tif ( window.setTimeout ) {\n\t\t\twindow.setTimeout(function() {\n\t\t\t\tif ( config.timeout ) {\n\t\t\t\t\tclearTimeout(config.timeout);\n\t\t\t\t}\n\n\t\t\t\tconfig.blocking = false;\n\t\t\t\tprocess();\n\t\t\t}, 13);\n\t\t} else {\n\t\t\tconfig.blocking = false;\n\t\t\tprocess();\n\t\t}\n\t},\n\t\n\tstop: function(timeout) {\n\t\tconfig.blocking = true;\n\n\t\tif ( timeout && window.setTimeout ) {\n\t\t\tconfig.timeout = window.setTimeout(function() {\n\t\t\t\tQUnit.ok( false, \"Test timed out\" );\n\t\t\t\tQUnit.start();\n\t\t\t}, timeout);\n\t\t}\n\t},\n\t\n\t/**\n\t * Resets the test setup. Useful for tests that modify the DOM.\n\t */\n\treset: function() {\n\t\tif ( window.jQuery ) {\n\t\t\tjQuery(\"#main\").html( config.fixture );\n\t\t\tjQuery.event.global = {};\n\t\t\tjQuery.ajaxSettings = extend({}, config.ajaxSettings);\n\t\t}\n\t},\n\t\n\t/**\n\t * Trigger an event on an element.\n\t *\n\t * @example triggerEvent( document.body, \"click\" );\n\t *\n\t * @param DOMElement elem\n\t * @param String type\n\t */\n\ttriggerEvent: function( elem, type, event ) {\n\t\tif ( document.createEvent ) {\n\t\t\tevent = document.createEvent(\"MouseEvents\");\n\t\t\tevent.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,\n\t\t\t\t0, 0, 0, 0, 0, false, false, false, false, 0, null);\n\t\t\telem.dispatchEvent( event );\n\n\t\t} else if ( elem.fireEvent ) {\n\t\t\telem.fireEvent(\"on\"+type);\n\t\t}\n\t},\n\t\n\t// Safe object type checking\n\tis: function( type, obj ) {\n\t\treturn Object.prototype.toString.call( obj ) === \"[object \"+ type +\"]\";\n\t},\n\t\n\t// Logging callbacks\n\tdone: function(failures, total) {},\n\tlog: function(result, message) {},\n\ttestStart: function(name) {},\n\ttestDone: function(name, failures, total) {},\n\tmoduleStart: function(name, testEnvironment) {},\n\tmoduleDone: function(name, failures, total) {}\n};\n\n// Backwards compatibility, deprecated\nQUnit.equals = QUnit.equal;\nQUnit.same = QUnit.deepEqual;\n\n// Maintain internal state\nvar config = {\n\t// The queue of tests to run\n\tqueue: [],\n\n\t// block until document ready\n\tblocking: true\n};\n\n// Load paramaters\n(function() {\n\tvar location = window.location || { search: \"\", protocol: \"file:\" },\n\t\tGETParams = location.search.slice(1).split('&');\n\n\tfor ( var i = 0; i < GETParams.length; i++ ) {\n\t\tGETParams[i] = decodeURIComponent( GETParams[i] );\n\t\tif ( GETParams[i] === \"noglobals\" ) {\n\t\t\tGETParams.splice( i, 1 );\n\t\t\ti--;\n\t\t\tconfig.noglobals = true;\n\t\t} else if ( GETParams[i].search('=') > -1 ) {\n\t\t\tGETParams.splice( i, 1 );\n\t\t\ti--;\n\t\t}\n\t}\n\t\n\t// restrict modules/tests by get parameters\n\tconfig.filters = GETParams;\n\t\n\t// Figure out if we're running the tests from a server or not\n\tQUnit.isLocal = !!(location.protocol === 'file:');\n})();\n\n// Expose the API as global variables, unless an 'exports'\n// object exists, in that case we assume we're in CommonJS\nif ( typeof exports === \"undefined\" || typeof require === \"undefined\" ) {\n\textend(window, QUnit);\n\twindow.QUnit = QUnit;\n} else {\n\textend(exports, QUnit);\n\texports.QUnit = QUnit;\n}\n\nif ( typeof document === \"undefined\" || document.readyState === \"complete\" ) {\n\tconfig.autorun = true;\n}\n\naddEvent(window, \"load\", function() {\n\t// Initialize the config, saving the execution queue\n\tvar oldconfig = extend({}, config);\n\tQUnit.init();\n\textend(config, oldconfig);\n\n\tconfig.blocking = false;\n\n\tvar userAgent = id(\"qunit-userAgent\");\n\tif ( userAgent ) {\n\t\tuserAgent.innerHTML = navigator.userAgent;\n\t}\n\t\n\tvar toolbar = id(\"qunit-testrunner-toolbar\");\n\tif ( toolbar ) {\n\t\ttoolbar.style.display = \"none\";\n\t\t\n\t\tvar filter = document.createElement(\"input\");\n\t\tfilter.type = \"checkbox\";\n\t\tfilter.id = \"qunit-filter-pass\";\n\t\tfilter.disabled = true;\n\t\taddEvent( filter, \"click\", function() {\n\t\t\tvar li = document.getElementsByTagName(\"li\");\n\t\t\tfor ( var i = 0; i < li.length; i++ ) {\n\t\t\t\tif ( li[i].className.indexOf(\"pass\") > -1 ) {\n\t\t\t\t\tli[i].style.display = filter.checked ? \"none\" : \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\ttoolbar.appendChild( filter );\n\n\t\tvar label = document.createElement(\"label\");\n\t\tlabel.setAttribute(\"for\", \"qunit-filter-pass\");\n\t\tlabel.innerHTML = \"Hide passed tests\";\n\t\ttoolbar.appendChild( label );\n\n\t\tvar missing = document.createElement(\"input\");\n\t\tmissing.type = \"checkbox\";\n\t\tmissing.id = \"qunit-filter-missing\";\n\t\tmissing.disabled = true;\n\t\taddEvent( missing, \"click\", function() {\n\t\t\tvar li = document.getElementsByTagName(\"li\");\n\t\t\tfor ( var i = 0; i < li.length; i++ ) {\n\t\t\t\tif ( li[i].className.indexOf(\"fail\") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) {\n\t\t\t\t\tli[i].parentNode.parentNode.style.display = missing.checked ? \"none\" : \"block\";\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\ttoolbar.appendChild( missing );\n\n\t\tlabel = document.createElement(\"label\");\n\t\tlabel.setAttribute(\"for\", \"qunit-filter-missing\");\n\t\tlabel.innerHTML = \"Hide missing tests (untested code is broken code)\";\n\t\ttoolbar.appendChild( label );\n\t}\n\n\tvar main = id('main');\n\tif ( main ) {\n\t\tconfig.fixture = main.innerHTML;\n\t}\n\n\tif ( window.jQuery ) {\n\t\tconfig.ajaxSettings = window.jQuery.ajaxSettings;\n\t}\n\n\tQUnit.start();\n});\n\nfunction done() {\n\tif ( config.doneTimer && window.clearTimeout ) {\n\t\twindow.clearTimeout( config.doneTimer );\n\t\tconfig.doneTimer = null;\n\t}\n\n\tif ( config.queue.length ) {\n\t\tconfig.doneTimer = window.setTimeout(function(){\n\t\t\tif ( !config.queue.length ) {\n\t\t\t\tdone();\n\t\t\t} else {\n\t\t\t\tsynchronize( done );\n\t\t\t}\n\t\t}, 13);\n\n\t\treturn;\n\t}\n\n\tconfig.autorun = true;\n\n\t// Log the last module results\n\tif ( config.currentModule ) {\n\t\tQUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );\n\t}\n\n\tvar banner = id(\"qunit-banner\"),\n\t\ttests = id(\"qunit-tests\"),\n\t\thtml = ['Tests completed in ',\n\t\t+new Date - config.started, ' milliseconds.<br/>',\n\t\t'<span class=\"passed\">', config.stats.all - config.stats.bad, '</span> tests of <span class=\"total\">', config.stats.all, '</span> passed, <span class=\"failed\">', config.stats.bad,'</span> failed.'].join('');\n\n\tif ( banner ) {\n\t\tbanner.className = (config.stats.bad ? \"qunit-fail\" : \"qunit-pass\");\n\t}\n\n\tif ( tests ) {\t\n\t\tvar result = id(\"qunit-testresult\");\n\n\t\tif ( !result ) {\n\t\t\tresult = document.createElement(\"p\");\n\t\t\tresult.id = \"qunit-testresult\";\n\t\t\tresult.className = \"result\";\n\t\t\ttests.parentNode.insertBefore( result, tests.nextSibling );\n\t\t}\n\n\t\tresult.innerHTML = html;\n\t}\n\n\tQUnit.done( config.stats.bad, config.stats.all );\n}\n\nfunction validTest( name ) {\n\tvar i = config.filters.length,\n\t\trun = false;\n\n\tif ( !i ) {\n\t\treturn true;\n\t}\n\t\n\twhile ( i-- ) {\n\t\tvar filter = config.filters[i],\n\t\t\tnot = filter.charAt(0) == '!';\n\n\t\tif ( not ) {\n\t\t\tfilter = filter.slice(1);\n\t\t}\n\n\t\tif ( name.indexOf(filter) !== -1 ) {\n\t\t\treturn !not;\n\t\t}\n\n\t\tif ( not ) {\n\t\t\trun = true;\n\t\t}\n\t}\n\n\treturn run;\n}\n\nfunction push(result, actual, expected, message) {\n\tmessage = message || (result ? \"okay\" : \"failed\");\n\tQUnit.ok( result, result ? message + \": \" + expected : message + \", expected: \" + QUnit.jsDump.parse(expected) + \" result: \" + QUnit.jsDump.parse(actual) );\n}\n\nfunction synchronize( callback ) {\n\tconfig.queue.push( callback );\n\n\tif ( config.autorun && !config.blocking ) {\n\t\tprocess();\n\t}\n}\n\nfunction process() {\n\twhile ( config.queue.length && !config.blocking ) {\n\t\tconfig.queue.shift()();\n\t}\n}\n\nfunction saveGlobal() {\n\tconfig.pollution = [];\n\t\n\tif ( config.noglobals ) {\n\t\tfor ( var key in window ) {\n\t\t\tconfig.pollution.push( key );\n\t\t}\n\t}\n}\n\nfunction checkPollution( name ) {\n\tvar old = config.pollution;\n\tsaveGlobal();\n\t\n\tvar newGlobals = diff( old, config.pollution );\n\tif ( newGlobals.length > 0 ) {\n\t\tok( false, \"Introduced global variable(s): \" + newGlobals.join(\", \") );\n\t\tconfig.expected++;\n\t}\n\n\tvar deletedGlobals = diff( config.pollution, old );\n\tif ( deletedGlobals.length > 0 ) {\n\t\tok( false, \"Deleted global variable(s): \" + deletedGlobals.join(\", \") );\n\t\tconfig.expected++;\n\t}\n}\n\n// returns a new Array with the elements that are in a but not in b\nfunction diff( a, b ) {\n\tvar result = a.slice();\n\tfor ( var i = 0; i < result.length; i++ ) {\n\t\tfor ( var j = 0; j < b.length; j++ ) {\n\t\t\tif ( result[i] === b[j] ) {\n\t\t\t\tresult.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction fail(message, exception, callback) {\n\tif ( typeof console !== \"undefined\" && console.error && console.warn ) {\n\t\tconsole.error(message);\n\t\tconsole.error(exception);\n\t\tconsole.warn(callback.toString());\n\n\t} else if ( window.opera && opera.postError ) {\n\t\topera.postError(message, exception, callback.toString);\n\t}\n}\n\nfunction extend(a, b) {\n\tfor ( var prop in b ) {\n\t\ta[prop] = b[prop];\n\t}\n\n\treturn a;\n}\n\nfunction addEvent(elem, type, fn) {\n\tif ( elem.addEventListener ) {\n\t\telem.addEventListener( type, fn, false );\n\t} else if ( elem.attachEvent ) {\n\t\telem.attachEvent( \"on\" + type, fn );\n\t} else {\n\t\tfn();\n\t}\n}\n\nfunction id(name) {\n\treturn !!(typeof document !== \"undefined\" && document && document.getElementById) &&\n\t\tdocument.getElementById( name );\n}\n\n// Test for equality any JavaScript type.\n// Discussions and reference: http://philrathe.com/articles/equiv\n// Test suites: http://philrathe.com/tests/equiv\n// Author: Philippe Rathé <prathe@gmail.com>\nQUnit.equiv = function () {\n\n    var innerEquiv; // the real equiv function\n    var callers = []; // stack to decide between skip/abort functions\n\n\n    // Determine what is o.\n    function hoozit(o) {\n        if (QUnit.is(\"String\", o)) {\n            return \"string\";\n            \n        } else if (QUnit.is(\"Boolean\", o)) {\n            return \"boolean\";\n\n        } else if (QUnit.is(\"Number\", o)) {\n\n            if (isNaN(o)) {\n                return \"nan\";\n            } else {\n                return \"number\";\n            }\n\n        } else if (typeof o === \"undefined\") {\n            return \"undefined\";\n\n        // consider: typeof null === object\n        } else if (o === null) {\n            return \"null\";\n\n        // consider: typeof [] === object\n        } else if (QUnit.is( \"Array\", o)) {\n            return \"array\";\n        \n        // consider: typeof new Date() === object\n        } else if (QUnit.is( \"Date\", o)) {\n            return \"date\";\n\n        // consider: /./ instanceof Object;\n        //           /./ instanceof RegExp;\n        //          typeof /./ === \"function\"; // => false in IE and Opera,\n        //                                          true in FF and Safari\n        } else if (QUnit.is( \"RegExp\", o)) {\n            return \"regexp\";\n\n        } else if (typeof o === \"object\") {\n            return \"object\";\n\n        } else if (QUnit.is( \"Function\", o)) {\n            return \"function\";\n        } else {\n            return undefined;\n        }\n    }\n\n    // Call the o related callback with the given arguments.\n    function bindCallbacks(o, callbacks, args) {\n        var prop = hoozit(o);\n        if (prop) {\n            if (hoozit(callbacks[prop]) === \"function\") {\n                return callbacks[prop].apply(callbacks, args);\n            } else {\n                return callbacks[prop]; // or undefined\n            }\n        }\n    }\n    \n    var callbacks = function () {\n\n        // for string, boolean, number and null\n        function useStrictEquality(b, a) {\n            if (b instanceof a.constructor || a instanceof b.constructor) {\n                // to catch short annotaion VS 'new' annotation of a declaration\n                // e.g. var i = 1;\n                //      var j = new Number(1);\n                return a == b;\n            } else {\n                return a === b;\n            }\n        }\n\n        return {\n            \"string\": useStrictEquality,\n            \"boolean\": useStrictEquality,\n            \"number\": useStrictEquality,\n            \"null\": useStrictEquality,\n            \"undefined\": useStrictEquality,\n\n            \"nan\": function (b) {\n                return isNaN(b);\n            },\n\n            \"date\": function (b, a) {\n                return hoozit(b) === \"date\" && a.valueOf() === b.valueOf();\n            },\n\n            \"regexp\": function (b, a) {\n                return hoozit(b) === \"regexp\" &&\n                    a.source === b.source && // the regex itself\n                    a.global === b.global && // and its modifers (gmi) ...\n                    a.ignoreCase === b.ignoreCase &&\n                    a.multiline === b.multiline;\n            },\n\n            // - skip when the property is a method of an instance (OOP)\n            // - abort otherwise,\n            //   initial === would have catch identical references anyway\n            \"function\": function () {\n                var caller = callers[callers.length - 1];\n                return caller !== Object &&\n                        typeof caller !== \"undefined\";\n            },\n\n            \"array\": function (b, a) {\n                var i;\n                var len;\n\n                // b could be an object literal here\n                if ( ! (hoozit(b) === \"array\")) {\n                    return false;\n                }\n\n                len = a.length;\n                if (len !== b.length) { // safe and faster\n                    return false;\n                }\n                for (i = 0; i < len; i++) {\n                    if ( ! innerEquiv(a[i], b[i])) {\n                        return false;\n                    }\n                }\n                return true;\n            },\n\n            \"object\": function (b, a) {\n                var i;\n                var eq = true; // unless we can proove it\n                var aProperties = [], bProperties = []; // collection of strings\n\n                // comparing constructors is more strict than using instanceof\n                if ( a.constructor !== b.constructor) {\n                    return false;\n                }\n\n                // stack constructor before traversing properties\n                callers.push(a.constructor);\n\n                for (i in a) { // be strict: don't ensures hasOwnProperty and go deep\n\n                    aProperties.push(i); // collect a's properties\n\n                    if ( ! innerEquiv(a[i], b[i])) {\n                        eq = false;\n                        break;\n                    }\n                }\n\n                callers.pop(); // unstack, we are done\n\n                for (i in b) {\n                    bProperties.push(i); // collect b's properties\n                }\n\n                // Ensures identical properties name\n                return eq && innerEquiv(aProperties.sort(), bProperties.sort());\n            }\n        };\n    }();\n\n    innerEquiv = function () { // can take multiple arguments\n        var args = Array.prototype.slice.apply(arguments);\n        if (args.length < 2) {\n            return true; // end transition\n        }\n\n        return (function (a, b) {\n            if (a === b) {\n                return true; // catch the most you can\n            } else if (a === null || b === null || typeof a === \"undefined\" || typeof b === \"undefined\" || hoozit(a) !== hoozit(b)) {\n                return false; // don't lose time with error prone cases\n            } else {\n                return bindCallbacks(a, callbacks, [b, a]);\n            }\n\n        // apply transition with (1..n) arguments\n        })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));\n    };\n\n    return innerEquiv;\n\n}();\n\n/**\n * jsDump\n * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com\n * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)\n * Date: 5/15/2008\n * @projectDescription Advanced and extensible data dumping for Javascript.\n * @version 1.0.0\n * @author Ariel Flesler\n * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}\n */\nQUnit.jsDump = (function() {\n\tfunction quote( str ) {\n\t\treturn '\"' + str.toString().replace(/\"/g, '\\\\\"') + '\"';\n\t};\n\tfunction literal( o ) {\n\t\treturn o + '';\t\n\t};\n\tfunction join( pre, arr, post ) {\n\t\tvar s = jsDump.separator(),\n\t\t\tbase = jsDump.indent(),\n\t\t\tinner = jsDump.indent(1);\n\t\tif ( arr.join )\n\t\t\tarr = arr.join( ',' + s + inner );\n\t\tif ( !arr )\n\t\t\treturn pre + post;\n\t\treturn [ pre, inner + arr, base + post ].join(s);\n\t};\n\tfunction array( arr ) {\n\t\tvar i = arr.length,\tret = Array(i);\t\t\t\t\t\n\t\tthis.up();\n\t\twhile ( i-- )\n\t\t\tret[i] = this.parse( arr[i] );\t\t\t\t\n\t\tthis.down();\n\t\treturn join( '[', ret, ']' );\n\t};\n\t\n\tvar reName = /^function (\\w+)/;\n\t\n\tvar jsDump = {\n\t\tparse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance\n\t\t\tvar\tparser = this.parsers[ type || this.typeOf(obj) ];\n\t\t\ttype = typeof parser;\t\t\t\n\t\t\t\n\t\t\treturn type == 'function' ? parser.call( this, obj ) :\n\t\t\t\t   type == 'string' ? parser :\n\t\t\t\t   this.parsers.error;\n\t\t},\n\t\ttypeOf:function( obj ) {\n\t\t\tvar type;\n\t\t\tif ( obj === null ) {\n\t\t\t\ttype = \"null\";\n\t\t\t} else if (typeof obj === \"undefined\") {\n\t\t\t\ttype = \"undefined\";\n\t\t\t} else if (QUnit.is(\"RegExp\", obj)) {\n\t\t\t\ttype = \"regexp\";\n\t\t\t} else if (QUnit.is(\"Date\", obj)) {\n\t\t\t\ttype = \"date\";\n\t\t\t} else if (QUnit.is(\"Function\", obj)) {\n\t\t\t\ttype = \"function\";\n\t\t\t} else if (QUnit.is(\"Array\", obj)) {\n\t\t\t\ttype = \"array\";\n\t\t\t} else if (QUnit.is(\"Window\", obj) || QUnit.is(\"global\", obj)) {\n\t\t\t\ttype = \"window\";\n\t\t\t} else if (QUnit.is(\"HTMLDocument\", obj)) {\n\t\t\t\ttype = \"document\";\n\t\t\t} else if (QUnit.is(\"HTMLCollection\", obj) || QUnit.is(\"NodeList\", obj)) {\n\t\t\t\ttype = \"nodelist\";\n\t\t\t} else if (/^\\[object HTML/.test(Object.prototype.toString.call( obj ))) {\n\t\t\t\ttype = \"node\";\n\t\t\t} else {\n\t\t\t\ttype = typeof obj;\n\t\t\t}\n\t\t\treturn type;\n\t\t},\n\t\tseparator:function() {\n\t\t\treturn this.multiline ?\tthis.HTML ? '<br />' : '\\n' : this.HTML ? '&nbsp;' : ' ';\n\t\t},\n\t\tindent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing\n\t\t\tif ( !this.multiline )\n\t\t\t\treturn '';\n\t\t\tvar chr = this.indentChar;\n\t\t\tif ( this.HTML )\n\t\t\t\tchr = chr.replace(/\\t/g,'   ').replace(/ /g,'&nbsp;');\n\t\t\treturn Array( this._depth_ + (extra||0) ).join(chr);\n\t\t},\n\t\tup:function( a ) {\n\t\t\tthis._depth_ += a || 1;\n\t\t},\n\t\tdown:function( a ) {\n\t\t\tthis._depth_ -= a || 1;\n\t\t},\n\t\tsetParser:function( name, parser ) {\n\t\t\tthis.parsers[name] = parser;\n\t\t},\n\t\t// The next 3 are exposed so you can use them\n\t\tquote:quote, \n\t\tliteral:literal,\n\t\tjoin:join,\n\t\t//\n\t\t_depth_: 1,\n\t\t// This is the list of parsers, to modify them, use jsDump.setParser\n\t\tparsers:{\n\t\t\twindow: '[Window]',\n\t\t\tdocument: '[Document]',\n\t\t\terror:'[ERROR]', //when no parser is found, shouldn't happen\n\t\t\tunknown: '[Unknown]',\n\t\t\t'null':'null',\n\t\t\tundefined:'undefined',\n\t\t\t'function':function( fn ) {\n\t\t\t\tvar ret = 'function',\n\t\t\t\t\tname = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE\n\t\t\t\tif ( name )\n\t\t\t\t\tret += ' ' + name;\n\t\t\t\tret += '(';\n\t\t\t\t\n\t\t\t\tret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');\n\t\t\t\treturn join( ret, this.parse(fn,'functionCode'), '}' );\n\t\t\t},\n\t\t\tarray: array,\n\t\t\tnodelist: array,\n\t\t\targuments: array,\n\t\t\tobject:function( map ) {\n\t\t\t\tvar ret = [ ];\n\t\t\t\tthis.up();\n\t\t\t\tfor ( var key in map )\n\t\t\t\t\tret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );\n\t\t\t\tthis.down();\n\t\t\t\treturn join( '{', ret, '}' );\n\t\t\t},\n\t\t\tnode:function( node ) {\n\t\t\t\tvar open = this.HTML ? '&lt;' : '<',\n\t\t\t\t\tclose = this.HTML ? '&gt;' : '>';\n\t\t\t\t\t\n\t\t\t\tvar tag = node.nodeName.toLowerCase(),\n\t\t\t\t\tret = open + tag;\n\t\t\t\t\t\n\t\t\t\tfor ( var a in this.DOMAttrs ) {\n\t\t\t\t\tvar val = node[this.DOMAttrs[a]];\n\t\t\t\t\tif ( val )\n\t\t\t\t\t\tret += ' ' + a + '=' + this.parse( val, 'attribute' );\n\t\t\t\t}\n\t\t\t\treturn ret + close + open + '/' + tag + close;\n\t\t\t},\n\t\t\tfunctionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function\n\t\t\t\tvar l = fn.length;\n\t\t\t\tif ( !l ) return '';\t\t\t\t\n\t\t\t\t\n\t\t\t\tvar args = Array(l);\n\t\t\t\twhile ( l-- )\n\t\t\t\t\targs[l] = String.fromCharCode(97+l);//97 is 'a'\n\t\t\t\treturn ' ' + args.join(', ') + ' ';\n\t\t\t},\n\t\t\tkey:quote, //object calls it internally, the key part of an item in a map\n\t\t\tfunctionCode:'[code]', //function calls it internally, it's the content of the function\n\t\t\tattribute:quote, //node calls it internally, it's an html attribute value\n\t\t\tstring:quote,\n\t\t\tdate:quote,\n\t\t\tregexp:literal, //regex\n\t\t\tnumber:literal,\n\t\t\t'boolean':literal\n\t\t},\n\t\tDOMAttrs:{//attributes to dump from nodes, name=>realName\n\t\t\tid:'id',\n\t\t\tname:'name',\n\t\t\t'class':'className'\n\t\t},\n\t\tHTML:true,//if true, entities are escaped ( <, >, \\t, space and \\n )\n\t\tindentChar:'   ',//indentation unit\n\t\tmultiline:true //if true, items in a collection, are separated by a \\n, else just a space.\n\t};\n\n\treturn jsDump;\n})();\n\n})(this);\n"
  },
  {
    "path": "vendor/plugins/admin_data/tasks/admin_data_tasks.rake",
    "content": "namespace :admin_data do\n  desc \"Copy views from the admin_data plugin into your application (so you can customize them)\"\n  task :localize_views do\n    require \"#{File.dirname(__FILE__)}/../lib/admin_data/admin_data_tasks\"\n    AdminDataTasks.copy_views_to_app\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/tasks/validate_models_bg.rake",
    "content": "#\n# Usage :\n# rake admin_data:validate_models_bg RAILS_ENV='development' KLASSES='Country,PhoneNumber,Website' TID='20100107095100'\n#\nrequire 'fileutils'\nnamespace :admin_data do\n  desc \"Run model valiations\"\n  task :validate_models_bg => :environment do\n    begin\n      usage = %Q{ rake admin_data:validate_models_bg RAILS_ENV='development' KLASSES='Country,EeeSociety,PhoneNumber,Website,Car,User' TID='20100107095100' }\n      usage = ' Usage: ' + usage\n      tid = ENV['TID'].try(:to_s)\n      raise \"tid is blank. #{usage} \" if tid.blank?\n\n      klasses = ENV['KLASSES']\n      klasses.split(',').compact.each { |klasss| AdminData::RakeUtil.process_klass(klasss, tid) }\n\n      AdminData::Util.write_to_validation_file('', 'a', tid,'done.txt')\n    rescue Exception => e\n      AdminData::Util.write_to_validation_file(AdminData::Util.exception_info(e), 'a', 'rake_errors.txt')\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/factories/article.rb",
    "content": "Factory.define :article do |f|\n  f.title 'this is a dummy title'\n  f.body 'this is a dummy body'\n  f.short_desc 'this is a dummy short_desc'\n  f.status 'published'\n  f.approved false\n  f.hits_count 1\n  f.published_at\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/factories/car.rb",
    "content": "Factory.define :car, :class => Vehicle::Car do |f|\n  f.year 1990\n  f.brand 'bmw'\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/factories/city.rb",
    "content": "Factory.define :city do |f|\n  f.name 'mumbai'\nend\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/factories/comment.rb",
    "content": "Factory.define :comment do |f|\n  f.association(:article)\n  f.body 'this is a dummy body'\n  f.author_name 'this is dummy author name'\n  f.author_website 'http://www.example.org'\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/factories/door.rb",
    "content": "Factory.define :door, :class => Vehicle::Door do |f|\n  f.color 'black'\n  f.car { |u| u.association(:car) }\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/factories/engine.rb",
    "content": "Factory.define :engine, :class => Vehicle::Engine do |f|\n  f.cylinders 6\n  f.car { |u| u.association(:car) }\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/functional/base_controller_test.rb",
    "content": "require File.join(File.dirname(__FILE__) , '..', 'test_helper')\n\nclass AdminData::BaseControllerTest < ActionController::TestCase\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/functional/feed_controller_test.rb",
    "content": "pwd = File.dirname(__FILE__)\nrequire File.join(pwd, '..', 'test_helper')\n\nf = File.join(pwd, '..', '..', 'app', 'views')\nAdminData::FeedController.prepend_view_path(f)\n\nrequire 'nokogiri'\n\nclass AdminData::FeedControllerTest < ActionController::TestCase\n\n  context 'filters list' do\n    setup do\n      @before_filters = @controller.class.before_filter.select do |filter|\n        filter.kind_of?(ActionController::Filters::BeforeFilter)\n      end\n      @filter = @before_filters.detect {|filter| filter.method == :ensure_is_allowed_to_view_feed}\n    end\n    should 'have filter called ensure_is_allowed_to_view_feed' do\n      assert @filter\n    end\n    should 'have no options for the filter' do\n      assert @filter.options.blank?\n    end\n  end\n\n  context 'GET index' do\n    setup do\n      Article.delete_all\n      @article = Factory(:article)\n      get :index, :format => :rss, :klasss => 'article'\n      @feed = Nokogiri::XML(@response.body)\n    end\n    should_respond_with :success\n    should 'have RSS feed 2.0' do\n      assert_equal '2.0', @feed.at('rss')['version']\n    end\n    should 'have title' do\n      assert_equal \"Feeds from admin_data Article id: #{@article.id}\", @feed.css('channel title').text\n    end\n    should 'have guid' do\n      guid = @feed.css('channel item guid').text\n      assert Regexp.new(\"/admin_data/klass/Article/#{@article.id}-\").match(guid)\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/functional/main_controller_test.rb",
    "content": "pwd = File.dirname(__FILE__)\n\nrequire File.join(pwd, '..', 'test_helper')\n\nf = File.join(pwd, '..', '..', 'app', 'views')\nAdminData::MainController.prepend_view_path(f)\n\nclass AdminData::MainControllerTest < ActionController::TestCase\n\n  def setup\n    @controller = AdminData::MainController.new\n    @request = ActionController::TestRequest.new\n    @response = ActionController::TestResponse.new\n    @article = Factory(:article)\n    @car = Factory(:car, :year => 2000, :brand => 'bmw')\n    grant_read_only_access\n    grant_update_access\n  end\n\n  should_route :get, '/admin_data', :controller => 'admin_data/main', :action => :all_models\n\n  should_route :get, '/admin_data/klass/article/1', :controller => 'admin_data/main', :action => :show, :klass => 'article', :id => 1\n\n  should_route :delete, '/admin_data/klass/article/1', :controller => 'admin_data/main', :action => :destroy, :klass => 'article', :id => 1\n\n  should_route :delete, '/admin_data/klass/article/1/del', :controller => 'admin_data/main', :action => :del, :klass => 'article', :id => 1\n\n  should_route :get, '/admin_data/klass/article/1/edit', :controller => 'admin_data/main', :action => :edit, :klass => 'article', :id => 1\n\n  should_route :put, '/admin_data/klass/article/1', :controller => 'admin_data/main', :action => :update, :klass => 'article', :id => 1\n\n  should_route :get, '/admin_data/klass/article/new', :controller => 'admin_data/main', :action => :new, :klass => 'article'\n\n  should_route :post, '/admin_data/klass/article', :controller => 'admin_data/main', :action => :create, :klass => 'article'\n\n  should_route :get, '/admin_data/klass/article/table_structure', :controller => 'admin_data/main', :action => :table_structure, :klass => 'article'\n\n  context 'filters list testing' do\n    setup do\n      @before_filters = @controller.class.before_filter.select do |filter|\n        filter.kind_of?(ActionController::Filters::BeforeFilter)\n      end\n    end\n    context 'for ensure_is_allowed_to_view filter' do\n      setup do\n        @filter = @before_filters.detect {|filter| filter.method == :ensure_is_allowed_to_view}\n      end\n      should 'have filter called ensure_is_allowed_to_view' do\n        assert @filter\n      end\n      should 'have no option for the filter' do\n        assert @filter.options.blank?\n      end\n    end\n\n    context 'for ensure_is_allowed_to_view_model filter' do\n      setup do\n        @filter = @before_filters.detect {|filter| filter.method == :ensure_is_allowed_to_view_model}\n      end\n      should 'have filter called ensure_is_allowed_to_view_model' do\n        assert @filter\n      end\n      should 'have except option for all_models' do\n        assert @filter.options[:except].include?('all_models')\n      end\n      should 'have except option for index' do\n        assert @filter.options[:except].include?('index')\n      end\n    end\n\n    context 'for ensure_is_allowed_to_update filter' do\n      setup do\n        @filter = @before_filters.detect do |filter|\n          filter.method == :ensure_is_allowed_to_update\n        end\n      end\n      should 'have filter called ensure_is_allowed_to_update' do\n        assert @filter\n      end\n      should 'have only option for destroy' do\n        assert @filter.options[:only].include?('destroy')\n      end\n      should 'have only option for del' do\n        assert @filter.options[:only].include?('del')\n      end\n      should 'have only option for edit' do\n        assert @filter.options[:only].include?('edit')\n      end\n      should 'have only option for update' do\n        assert @filter.options[:only].include?('update')\n      end\n      should 'have only option for crate' do\n        assert @filter.options[:only].include?('create')\n      end\n    end\n\n    context 'for ensure_is_allowed_to_update_model filter' do\n      setup do\n        @filter = @before_filters.detect do |filter|\n          filter.method == :ensure_is_allowed_to_update_model\n        end\n      end\n      should 'have filter called ensure_is_allowed_to_update_model' do\n        assert @filter\n      end\n      should 'have only option for destroy' do\n        assert @filter.options[:only].include?('destroy')\n      end\n      should 'have only option for del' do\n        assert @filter.options[:only].include?('del')\n      end\n      should 'have only option for edit' do\n        assert @filter.options[:only].include?('edit')\n      end\n      should 'have only option for update' do\n        assert @filter.options[:only].include?('update')\n      end\n      should 'have only option for create' do\n        assert @filter.options[:only].include?('create')\n      end\n    end\n\n  end\n\n  context 'get table_structure' do\n    setup do\n      get :table_structure, {:klass => Article.name.underscore}\n    end\n    should_respond_with :success\n    should 'have text index' do\n      assert_tag(:content => 'Index')\n    end\n    should 'have table name' do\n      assert_tag(:tag => 'h1', :content => \"Table name : articles\", :attributes => {:class => 'table_name'})\n    end\n  end\n\n  context 'get all_models' do\n    setup do\n      get :all_models\n    end\n    should_respond_with :success\n    should_assign_to :klasses\n    should 'have xx number of models' do\n      assert_equal 7, assigns(:klasses).size\n    end\n  end\n\n  context 'get show for article which belongs to tech_magazine' do\n    setup do\n      @article.magazine = TechMagazine.create\n      @article.save\n      get :show, {:id => @article, :klass => @article.class.name.underscore }\n    end\n    should_respond_with :success\n    should 'have belongs to association with magazine' do\n      assert @article.magazine\n    end\n    should 'have association link for comments' do\n      s2 = ERB::Util.html_escape('&')\n      url = \"/admin_data/klass/tech_magazine/#{@article.magazine.id}\"\n      assert_tag(:tag => 'a', :attributes => {:href => url})\n    end\n  end\n\n  context 'get show for article which has many comments' do\n    setup do\n      @comment1 = Factory(:comment, :article => @article)\n      @comment2 = Factory(:comment, :article => @article)\n      get :show, {:id => @article.id, :klass => @article.class.name.underscore }\n    end\n    should_respond_with :success\n    should 'have association link for comments' do\n      s2 = ERB::Util.html_escape('&')\n      url = \"/admin_data/quick_search/comment?base=article#{s2}children=comments#{s2}model_id=#{@article.id}\"\n      assert_tag(:tag => 'a', :attributes => {:href => url})\n    end\n  end\n\n  context 'get show for car' do\n    setup do\n      @engine = Factory(:engine, :car => @car, :cylinders => 4)\n      get :show, {:id => @car.id, :klass => @car.class.name.underscore }\n    end\n    should_respond_with :success\n    should 'have one association link for engine' do\n      s2 = ERB::Util.html_escape('&')\n      url = \"/admin_data/klass/engine/#{@engine.id}\"\n      assert_tag(:tag => 'a', :content => /engine/, :attributes => {:href => url})\n    end\n  end\n\n  context 'get show for city' do\n    setup do\n      AdminData::Config.set = { :find_conditions => { 'City' =>  lambda { |params| {:conditions => [\"permanent_name =?\", params[:id]] } } } }\n      @city = Factory(:city, :name => 'New Delhi')\n      get :show, {:id => 'new-delhi', :klass => @city.class.name.underscore }\n    end\n    should_respond_with :success\n  end\n\n  context 'get show for comment which belongs to another class' do\n    setup do\n      @comment = Factory(:comment, :article => @article)\n      get :show, {:id => @comment.id, :klass => @comment.class.name.underscore }\n    end\n    should_respond_with :success\n    should 'have belongs_to message' do\n      assert_tag( :tag => 'p', :attributes => {:class => 'belongs_to'}, :descendant => {:tag => 'a', :child => /article/})\n    end\n    should 'have link to belongs_to association' do\n      s2 = ERB::Util.html_escape('&')\n      url = \"/admin_data/klass/article/#{@article.to_param}\"\n      assert_tag(:tag => 'a', :attributes => {:href => url})\n    end\n  end\n\n  context 'get show for door which belongs to another class' do\n    setup do\n      @door = Factory(:door, :color => 'blue', :car_id => @car.id)\n      get :show, {:id => @door.id, :klass => @door.class.name.underscore }\n    end\n    should_respond_with :success\n    should 'have belongs_to message' do\n      assert_tag( :tag => 'p',\n      :attributes => {:class => 'belongs_to'},\n      :descendant => {:tag => 'a', :child => /car/})\n    end\n  end\n\n  context 'destroy an article' do\n    setup do\n      grant_update_access\n      @comment = Factory(:comment, :article => @article)\n      delete :destroy, {:id => @article.id, :klass => @article.class.name.underscore}\n    end\n    should_respond_with :redirect\n    should_change('article count', :by => -1) {Article.count}\n    # a comment is being created in setup which should be deleted because of destroy\n    should_not_change('comment count') { Comment.count }\n  end\n\n  context 'destroy a car' do\n    setup do\n      grant_update_access\n      @door = Factory(:door, :color => 'blue', :car => @car)\n      delete :destroy, {:id => @car.id, :klass => @car.class.name.underscore}\n    end\n    should_respond_with :redirect\n    should_change('car count', :by => -1) {Vehicle::Car.count}\n    # a comment is being created in setup which should be deleted because of destroy\n    should_not_change('door count') { Vehicle::Door.count }\n  end\n\n  context 'delete an article' do\n    setup do\n      grant_update_access\n      @comment = Factory(:comment, :article => @article)\n      delete :del, {:id => @article.id, :klass => @article.class.name.underscore }\n    end\n    should_respond_with :redirect\n    should_change('article count', :by => -1) {Article.count}\n    should_change('comment count', :by => 1) {Comment.count}\n  end\n\n  context 'delete a car' do\n    setup do\n      grant_update_access\n      @door = Factory(:door, :color => 'blue', :car => @car)\n      delete :del, {:id => @car.id, :klass => @car.class.name.underscore }\n    end\n    should_respond_with :redirect\n    should_change('car count', :by => -1) {Vehicle::Car.count}\n    should_change('door count since del does not call callbacks', :by => 1) do\n      Vehicle::Door.count\n    end\n  end\n\n  context 'get edit article with attr' do\n    setup do\n      get :edit, {:id => @article.id, :klass => @article.class.name, :attr => 'title', :data => 'Hello World' }\n    end\n    should 'have input field for title' do\n      assert_select('#article_title')\n    end\n    should 'not have input field for body' do\n      assert_select('#article_body', false)\n    end\n  end\n\n  context 'get edit article' do\n    context 'with ignore column limit' do\n      setup do\n        AdminData::Config.set = ({:ignore_column_limit => true})\n        get :edit, {:id => @article.id, :klass => @article.class.name }\n      end\n      teardown do\n        AdminData::Config.set = ({:ignore_column_limit => false})\n      end\n\n      should 'have size 60 for title and maxlenght 255' do\n        assert_tag(:tag => 'input', :attributes => {:id=> 'article_title', :size => '60', :maxlength => '255'})\n      end\n\n      should 'have size 60 for status and maxlenght 200' do\n        assert_tag(:tag => 'input', :attributes => {:id=> 'article_status', :size => '60', :maxlength => '255'})\n      end\n    end\n\n    context 'with enforced column limit' do\n\n      setup do\n        get :edit, {:id => @article.id, :klass => @article.class.name }\n      end\n      should_respond_with :success\n\n      should \"not have input for primary key\" do\n        assert_select 'form' do\n          assert_select \"input[name='comment[id]']\", false\n        end\n      end\n\n      should \"have dropdowns for published_at datetime column\" do\n        assert_select 'form' do\n          assert_select \"select[name='article[published_at(1i)]']\"\n          assert_select \"select[name='article[published_at(2i)]']\"\n          assert_select \"select[name='article[published_at(3i)]']\"\n          assert_select \"select[name='article[published_at(4i)]']\"\n          assert_select \"select[name='article[published_at(5i)]']\"\n        end\n      end\n\n      should 'have input field for title' do\n        assert_select('#article_title')\n      end\n\n      should 'have size 60 for title and maxlenght 200' do\n        assert_tag(:tag => 'input', :attributes => {:id=> 'article_title', :size => '60', :maxlength => '200'})\n      end\n\n      should 'have size 60 for status and maxlenght 200' do\n        assert_tag(:tag => 'input', :attributes => {:id=> 'article_status', :size => '50', :maxlength => '50'})\n      end\n\n      should 'have input field for body' do\n        assert_select('#article_body')\n      end\n    end\n\n  end\n\n  context 'get edit comment' do\n    context 'without drop down for associations' do\n      setup do\n        AdminData::Config.set = ({:drop_down_for_associations => false})\n        @comment = Factory(:comment, :article => @article)\n        get :edit, {:id => @comment.id, :klass => @comment.class.name.underscore }\n      end\n      teardown do\n        AdminData::Config.set = ({:drop_down_for_associations => true})\n      end\n\n      should_respond_with :success\n\n      should \"have input text field for belongs_to article\" do\n        assert_select 'form' do\n          assert_tag(:tag => 'input', :attributes => {:id => 'comment_article_id', :name => 'comment[article_id]'})\n        end\n      end\n    end\n    context 'with drop down for associations' do\n      setup do\n        @comment = Factory(:comment, :article => @article)\n        get :edit, {:id => @comment.id, :klass => @comment.class.name.underscore }\n      end\n\n      should_respond_with :success\n\n      should \"have dropdowns for belongs_to article\" do\n        assert_select 'form' do\n          assert_select \"select[name='comment[article_id]']\"\n        end\n      end\n    end\n  end\n\n\n  context 'get edit car' do\n    setup do\n      get :edit, {:id => @car.id, :klass => @car.class.name.underscore }\n    end\n    should_respond_with :success\n  end\n\n  context 'get new article' do\n    setup do\n      get :new, {:klass => Article.name.underscore }\n    end\n    should_respond_with :success\n  end\n\n  context 'get new car' do\n    setup do\n      get :new, {:klass => Vehicle::Car.name.underscore}\n    end\n    should_respond_with :success\n  end\n\n  context 'update article successful' do\n    setup do\n      grant_update_access\n      post :update, { :klass => Article.name.underscore, :id => @article, :article => {:title => 'new title'}}\n    end\n    should_respond_with :redirect\n    should_redirect_to('show page') { admin_data_on_k_path( :id => Article.last, :klass => Article.name.underscore) }\n    should_set_the_flash_to /Record was updated/\n    should_not_change('article count') { Article.count }\n  end\n\n  context 'update car successful' do\n    setup do\n      grant_update_access\n      post :update, { :klass => Vehicle::Car.name.underscore, :id => @car.id, 'vehicle/car' => {:brand => 'honda'}}\n    end\n    should_respond_with :redirect\n    should_redirect_to('show page') { admin_data_on_k_path(:id => Vehicle::Car.last.id, :klass => @car.class.name.underscore) }\n    should_set_the_flash_to /Record was updated/\n    should_not_change('car count') { Vehicle::Car.count }\n  end\n\n  context 'update failure' do\n    setup do\n      grant_update_access\n      post :update, { :klass => 'article', :id => @article.id, :article => {:body => ''}}\n    end\n    should_respond_with :success\n    should_not_set_the_flash\n    should_not_change('article count') { Article.count }\n    should 'contain the error message' do\n      assert_tag(:content => \"Body can't be blank\")\n    end\n  end\n\n  context 'create article successful' do\n    setup do\n      grant_update_access\n      post :create, { :klass => Article.name.underscore, 'article' => {:title => 'hello', :body => 'hello world'}}\n    end\n    should_respond_with :redirect\n    should_redirect_to('show page') { admin_data_on_k_path(:id => Article.last, :klass => @article.class.name.underscore) }\n    should_set_the_flash_to /Record was created/\n    should_change('article count', :by => 1) { Article.count }\n  end\n\n  context 'create car successful' do\n    setup do\n      grant_update_access\n      post :create, { :klass => Vehicle::Car.name.underscore, 'vehicle/car' => {:brand => 'hello'}}\n    end\n    should_respond_with :redirect\n    should_redirect_to('show page') { admin_data_on_k_path(:id => Vehicle::Car.last.id, :klass => @car.class.name.underscore) }\n    should_set_the_flash_to /Record was created/\n    should_change('vehicle count', :by => 1) { Vehicle::Car.count }\n  end\n\n  context 'create failure' do\n    setup do\n      grant_update_access\n      post :create, { :klass => Article.name.underscore, :article => {:body => '', :title => 'hello'}}\n    end\n    should_respond_with :success\n    should_not_set_the_flash\n    should_not_change('article count') { Article.count }\n    should 'contain the error message' do\n      assert_tag(:content => \"Body can't be blank\")\n    end\n  end\n\n  context 'filter get_model_and_verify_if failure case' do\n    setup do\n      get :show, {:id => 999999999999994533, :klass => Article.name.underscore }\n    end\n    should_respond_with :not_found\n    should 'contain the error message' do\n      assert_tag(:tag => 'h2', :content => \"Article not found: 999999999999994533\")\n    end\n  end\n\n  context 'filter is_allowed_to_view failure case' do\n    setup do\n      revoke_read_only_access\n      get :show, {:id => @article.id, :klass => Article.name.underscore }\n    end\n    should_respond_with :unauthorized\n    should 'contain the  message' do\n      assert_tag(:tag => 'h2', :content => 'not authorized')\n    end\n  end\n\n  context 'fine grained access control' do\n    teardown do\n      AdminData::Config.initialize_defaults\n    end\n    context 'allows view security check to access klass' do\n      setup do\n        AdminData::Config.set = { :is_allowed_to_view_model => Proc.new { |controller| assert_equal(Article, controller.klass); true } }\n        get :show, {:id => @article.id, :klass => Article.name.underscore }\n      end\n      should_respond_with :success\n    end\n    context 'allows update security check to access klass' do\n      setup do\n        AdminData::Config.set = { :is_allowed_to_update => Proc.new { |controller| assert_equal(Article, controller.klass); true } }\n        get :edit, {:id => @article.id, :klass => Article.name.underscore }\n      end\n      should_respond_with :success\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/functional/migration_controller_test.rb",
    "content": "pwd = File.dirname(__FILE__)\n\nrequire File.join(pwd,'..', 'test_helper')\n\nf = File.join(pwd, '..', '..', 'app', 'views')\nAdminData::MainController.prepend_view_path(f)\nAdminData::MigrationController.prepend_view_path(f)\n\nclass AdminData::MigrationControllerTest < ActionController::TestCase\n\n  def setup\n    @controller = AdminData::MigrationController.new\n    @request = ActionController::TestRequest.new\n    @response = ActionController::TestResponse.new\n    grant_read_only_access\n  end\n\n  should_route :get, '/admin_data/migration',    :controller => 'admin_data/migration', :action => :index\n\n  context 'GET index' do\n    setup do\n      get :index\n    end\n    should_respond_with :success\n    should_assign_to :data\n    should 'contain title' do\n      assert_tag(:tag => 'h2', :content => 'Migration Information from schema_migrations table')\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/functional/search_controller_test.rb",
    "content": "pwd = File.dirname(__FILE__)\n\nrequire File.join(pwd , '..', 'test_helper')\n\nf = File.join(pwd, '..', '..', 'app', 'views')\nAdminData::MainController.prepend_view_path(f)\nAdminData::SearchController.prepend_view_path(f)\n\nclass AdminData::SearchControllerTest < ActionController::TestCase\n\n  def setup\n    @controller = AdminData::SearchController.new\n    @request = ActionController::TestRequest.new\n    @response = ActionController::TestResponse.new\n    @article = Factory(:article)\n    @car = Factory(:car, :year => 2000, :brand => 'bmw')\n    grant_read_only_access\n  end\n\n  should_route :get, '/admin_data/quick_search/article', :controller => 'admin_data/search', :action => :quick_search, :klass => 'article'\n\n  should_route :get, '/admin_data/advance_search/article', :controller => 'admin_data/search', :action => :advance_search, :klass => 'article'\n\n  context 'filters list' do\n    setup do\n      @before_filters = @controller.class.before_filter.select do |filter|\n        filter.kind_of?(ActionController::Filters::BeforeFilter)\n      end\n    end\n    context 'for ensure_is_allowed_to_view filter' do\n      setup do\n        @filter = @before_filters.detect {|filter| filter.method == :ensure_is_allowed_to_view }\n      end\n      should 'have filter called ensure_is_allowed_to_view' do\n        assert @filter\n      end\n      should 'have no options for the filter' do\n        assert @filter.options.blank?\n      end\n    end\n    context 'for ensure_is_allowed_to_view_model filter' do\n      setup do\n        @filter = @before_filters.detect {|filter| filter.method == :ensure_is_allowed_to_view_model }\n      end\n      should 'have filter called ensure_is_allowed_to_view_model' do\n        assert @filter\n      end\n      should 'have no option for filter' do\n        assert @filter.options.blank?\n      end\n    end\n  end\n\n  context 'GET quick_search' do\n    context 'GET quick_search with wrong children class' do\n      setup do\n        get :quick_search, { :base => 'article', :klass => 'comment', :model_id => @article.id, :children => 'wrong_children_name' }\n      end\n      should_respond_with :not_found\n    end\n\n    context 'with no klass param' do\n      setup do\n        assert_raises ActionController::RoutingError do\n          get :quick_search\n        end\n      end\n    end\n\n    context 'with no search query' do\n      setup do\n        get :quick_search, {:klass => Article.name.underscore}\n      end\n      should_respond_with :success\n      should_assign_to :records\n    end\n    context 'with has_many association' do\n      context 'for a nested model' do\n        setup do\n          Vehicle::Door.delete_all\n          @door1 = Factory(:door, :color => 'black', :car => @car)\n          @door2 = Factory(:door, :color => 'green', :car => @car)\n          get :quick_search, {  :klass => @door1.class.name.underscore, :base => @car.class.name.underscore, :model_id => @car.id, :children => 'doors'}\n        end\n        should_respond_with :success\n        should_assign_to :records\n        should 'have 2 records' do\n          assert_equal 2, assigns(:records).size\n        end\n        should 'have 2 as total number of children' do\n          assert_equal 2, assigns(:total_num_of_children)\n        end\n        should 'contain text' do\n          assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /has 2/m)\n        end\n      end\n\n      context 'for a standard model' do\n        setup do\n          @comment1 = Factory(:comment, :article => @article)\n          @comment2 = Factory(:comment, :article => @article)\n          get :quick_search, { :klass => Comment.name.underscore, :base => 'article', :model_id => @article.id, :children => 'comments' }\n        end\n        should_respond_with :success\n        should_assign_to :records\n        should 'have 2 records' do\n          assert_equal 2, assigns(:records).size\n        end\n        should 'contain text' do\n          assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /has 2 comments/ )\n        end\n      end\n    end\n  end\n\n\n  context 'GET quick_search' do\n    context 'for a standard model' do\n      setup do\n        @comment = Factory(:comment)\n        @comment = Factory(:comment)\n        get :quick_search, {:klass => @comment.class.name.underscore}\n      end\n      should_respond_with :success\n      should 'contain valid link at header breadcrum' do\n        assert_tag( :tag => 'div', :attributes => {:class => 'breadcrum rounded'}, :descendant => {:tag => 'a', :attributes => {:href => '/admin_data/quick_search/comment'}})\n      end\n      should 'contain proper link at table listing' do\n        url = \"/admin_data/klass/comment/#{Comment.last.id}\"\n        assert_tag( :tag => 'td', :descendant => {:tag => 'a', :attributes => {:href => url}})\n      end\n    end\n\n    context 'for a nested model' do\n      setup do\n        get :quick_search, {:klass => @car.class.name.underscore}\n      end\n      should_respond_with :success\n      should 'contain proper link at header breadcum' do\n        s = CGI.escape('vehicle/car')\n        assert_tag(:tag => 'div', :attributes => {:class => 'breadcrum rounded'}, :descendant => {:tag => 'a', :attributes => {:href => \"/admin_data/quick_search/#{s}\" }})\n      end\n      should 'contain proper link at table listing' do\n        s = CGI.escape(\"vehicle/car\")\n        url = \"/admin_data/klass/#{s}/#{@car.class.last.id}\"\n        assert_tag(:tag => 'td', :descendant => {:tag => 'a', :attributes => {:href => url}})\n      end\n      should 'have proper action name for search form' do\n        url = admin_data_search_path(:klass=>Vehicle::Car)\n        assert_tag( :tag => 'form', :attributes => {:action => url})\n      end\n    end\n  end\n\n  context 'GET quick_search with search term' do\n    setup do\n      Article.delete_all\n      @python_beginner_book = Factory(:article, :title => 'python for beginners')\n      @python_book = Factory(:article, :title => 'python')\n      @java_book = Factory(:article, :title => 'java')\n      @clojure_book = Factory(:article, :title => 'clojure')\n    end\n    context 'with default order' do\n      setup do\n        get :quick_search, {:klass => 'Article', :query => 'python'}\n      end\n      should_respond_with :success\n      should_assign_to :records\n      should 'have only two records' do\n        assert_equal 2, assigns(:records).size\n      end\n      should 'have python beginner book as the first book' do\n        assert_equal @python_beginner_book.id, assigns(:records).last.id\n      end\n      should 'have python book as the last book' do\n        assert_equal @python_book.id, assigns(:records).first.id\n      end\n    end\n\n    context 'with article_id ascending order' do\n      setup do\n        get :quick_search, { :klass => 'Article', :query => 'python', :sortby => 'article_id asc'}\n      end\n      should_respond_with :success\n      should_assign_to :records\n      should 'have only two records' do\n        assert_equal 2, assigns(:records).size\n      end\n      should 'have python beginner book as the first book' do\n        assert_equal @python_beginner_book.id, assigns(:records).first.id\n      end\n      should 'have python book as the last book' do\n        assert_equal @python_book.id, assigns(:records).last.id\n      end\n    end\n  end\n\n  context 'GET advance_search' do\n    context 'with no klass param' do\n      setup do\n        assert_raises ActionController::RoutingError do\n          get :advance_search\n        end\n      end\n    end\n\n    context 'with klass param' do\n      setup do\n        get :advance_search, {:klass => Article.name.underscore}\n      end\n      should_respond_with :success\n      should_not_assign_to :records\n      should 'have proper action for advance search form' do\n        url = admin_data_advance_search_path(:klass => Article)\n        assert_tag( :tag => 'form', :attributes => {:action => url})\n      end\n    end\n  end\n\n\n  context 'xhr advance_search with does_not_contain first one' do\n    setup do\n      Article.delete_all\n      AdminData::Config.set = ({ :is_allowed_to_update => lambda {|controller| return false} })\n      Factory(:article, :short_desc => 'ruby')\n      Factory(:article, :short_desc => 'rails')\n      Factory(:article, :short_desc => nil)\n      xml_http_request  :post, :advance_search, {:klass => Article.name.underscore, :sortby => 'article_id desc', :adv_search => {'1_row' => {:col1 => 'short_desc', :col2 => 'does_not_contain', :col3 => 'ruby'} } }\n    end\n    should_respond_with :success\n    should 'contain text' do\n      assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 2 records found/ )\n    end\n    should 'not contain delete all link' do\n      assert_no_tag( :tag => 'a', :attributes => {:id => 'advance_search_delete_all'})\n    end\n    should 'not contain destroy all link' do\n      assert_no_tag( :tag => 'a', :attributes => {:id => 'advance_search_destroy_all'})\n    end\n  end\n\n  context 'xhr advance_search with delete_all action' do\n    setup do\n      Article.delete_all\n      AdminData::Config.set = ({ :is_allowed_to_update => lambda {|controller| return true} })\n      Factory(:article, :short_desc => 'ruby')\n      Factory(:article, :short_desc => 'rails')\n      so   = {'1_row' => {:col1 => 'short_desc', :col2 => 'contains', :col3 => 'ruby'} }\n      h = { :klass => Article.name.underscore,\n        :sortby => 'article_id desc',\n      :admin_data_advance_search_action_type => 'delete', :adv_search => so }\n      xml_http_request  :post, :advance_search, h\n      @json = JSON.parse(@response.body)\n    end\n    should_respond_with :success\n    should 'have only one record' do\n      assert_equal 1, Article.count\n    end\n    should 'have success key in the response message' do\n      assert @json.has_key?('success')\n    end\n    should 'have success message in the response message' do\n      assert_equal @json.fetch('success'), '1 record deleted'\n    end\n  end\n\n  context 'xhr advance_search with destroy_all action' do\n    setup do\n      Article.delete_all\n      AdminData::Config.set = ({ :is_allowed_to_update => lambda {|controller| return true} })\n      Factory(:article, :short_desc => 'ruby')\n      Factory(:article, :short_desc => 'rails')\n      xml_http_request  :post,\n      :advance_search, {:klass => Article.name.underscore, :sortby => 'article_id desc', :admin_data_advance_search_action_type => 'destroy', :adv_search => {'1_row' => {:col1 => 'short_desc', :col2 => 'contains', :col3 => 'ruby'} } }\n      @json = JSON.parse(@response.body)\n    end\n    should_respond_with :success\n    should 'have only one record' do\n      assert_equal 1, Article.count\n    end\n    should 'have success key in the response message' do\n      assert @json.has_key?('success')\n    end\n    should 'have success message in the response message' do\n      assert_equal @json.fetch('success'), '1 record destroyed'\n    end\n  end\n\n  context 'xhr advance_search with does_not_contain' do\n    setup do\n      AdminData::Config.set = ({ :is_allowed_to_update => lambda {|controller| return true } })\n      Article.delete_all\n      Factory(:article, :short_desc => 'ruby')\n      Factory(:article, :short_desc => 'rails')\n      Factory(:article, :short_desc => nil)\n      xml_http_request  :post, :advance_search, {:klass => Article.name.underscore, :sortby => 'article_id desc', :adv_search => {'1_row' => {:col1 => 'short_desc', :col2 => 'does_not_contain', :col3 => 'ruby'} } }\n    end\n    should_respond_with :success\n    should 'contain search result' do\n      assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 2 records found/ )\n    end\n    should 'contain delete all link' do\n      assert_tag( :tag => 'a', :attributes => {:id => 'advance_search_delete_all'})\n    end\n    should 'contain destroy all link' do\n      assert_tag( :tag => 'a', :attributes => {:id => 'advance_search_destroy_all'})\n    end\n  end\n\n  context 'xhr advance_search with contains option with 2 records' do\n    setup do\n      Article.delete_all\n      @python_book = Factory(:article, :title => 'python')\n      @python_beginner_book = Factory(:article, :title => 'python for beginners')\n      @java_book = Factory(:article, :title => 'java')\n      @clojure_book = Factory(:article, :title => 'clojure')\n      xml_http_request  :post, :advance_search, {:klass => Article.name.underscore, :sortby => 'article_id desc', :adv_search => {'1_row' => {:col1 => 'title', :col2 => 'contains', :col3 => 'python'} } }\n    end\n    should_respond_with :success\n    should 'contain text' do\n      assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 2 records found/ )\n    end\n  end\n\n  context 'xhr advance_search with 1 result' do\n    setup do\n      Article.delete_all\n      @python_book = Factory(:article, :title => 'python')\n      @python_beginner_book = Factory(:article, :title => 'python for beginners')\n      @java_book = Factory(:article, :title => 'java')\n      @clojure_book = Factory(:article, :title => 'clojure')\n      xml_http_request  :post, :advance_search, { :klass => Article.name.underscore, :sortby => 'article_id desc', :adv_search => {'1_row' => {:col1 => 'title', :col2 => 'contains', :col3 => 'clojure'} } }\n    end\n    should_respond_with :success\n    should 'contain text' do\n      assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 1 record found/ )\n    end\n  end\n\n  context 'xhr advance_search with empty query term with contains option' do\n    setup do\n      Article.delete_all\n      @python_book = Factory(:article, :title => 'python')\n      @python_beginner_book = Factory(:article, :title => 'python for beginners')\n      @java_book = Factory(:article, :title => 'java')\n      @clojure_book = Factory(:article, :title => 'clojure')\n      xml_http_request  :post, :advance_search, { :klass => Article.name.underscore, :sortby => 'article_id desc', :adv_search => {'1_row' => {:col1 => 'title', :col2 => 'contains', :col3 => ''} } }\n    end\n    should_respond_with :success\n    should 'contain text' do\n      assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 4 records found/ )\n    end\n  end\n\n  context 'xhr advance_search with empty col2' do\n    setup do\n      Article.delete_all\n      @python_book = Factory(:article, :title => 'python')\n      @python_beginner_book = Factory(:article, :title => 'python for beginners')\n      xml_http_request  :post, :advance_search, { :klass => Article.name.underscore, :sortby => 'article_id desc', :adv_search => {'1_row' => {:col1 => 'title', :col2 => nil, :col3 => nil} } }\n    end\n    should_respond_with :success\n    should 'contain text' do\n      assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 2 records found/ )\n    end\n  end\n\n  context 'xhr advance_search with two search terms' do\n    setup do\n      Article.delete_all\n      @python_book = Factory(:article, :title => 'python')\n      @python_beginner_book = Factory(:article, :title => 'python for beginners',\n      :body => 'for beginners')\n      @java_book = Factory(:article, :title => 'java')\n      @clojure_book = Factory(:article, :title => 'clojure', :body => 'not for beginners')\n      adv_search = { '1_row' => {:col1 => 'title', :col2 => 'contains', :col3 => 'python'}, '2_row' => {:col1 => 'body', :col2 => 'contains', :col3 => 'beginners'} }\n      xml_http_request  :post, :advance_search, { :klass => Article.name.underscore, :sortby => 'article_id desc', :adv_search => adv_search }\n    end\n    should_respond_with :success\n    should 'contain text' do\n      assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 1 record found/ )\n    end\n  end\n\n  context 'advance search conditions' do\n    setup do\n      @klass = Object.const_get('Article')\n      @proc = Proc.new do\n        @controller.send(:build_advance_search_conditions, @klass, { '429440_row' => @hash })\n      end\n    end\n\n    context 'with col2 as null' do\n      should 'have sql as body is not null' do\n        @hash = { :col1 => 'body', :col2 => 'is_not_null'}\n        output = @proc.call\n        assert_equal '(articles.body IS NOT NULL)', output[:cond]\n      end\n    end\n\n    context 'with col2 contains' do\n      should 'have sql with like' do\n        @hash = { :col1 => 'body', :col2 => 'contains', :col3 => 'python'}\n        output = @proc.call\n        assert_equal \"(articles.body LIKE '%python%')\", output[:cond]\n      end\n    end\n\n    context 'with col2 as exactly' do\n      should 'have sql as body equals' do\n        @hash = { :col1 => 'body', :col2 => 'is_exactly', :col3 => 'python'}\n        output = @proc.call\n        assert_equal \"(articles.body = 'python')\", output[:cond]\n      end\n    end\n\n    context 'with does not contain' do\n      should 'have sql as body is null or not like' do\n        @hash = { :col1 => 'body', :col2 => 'does_not_contain', :col3 => 'python'}\n        output = @proc.call\n        assert_equal \"(articles.body IS NULL OR articles.body NOT LIKE '%python%')\", output[:cond]\n      end\n    end\n\n    context 'with col2 as false' do\n      should 'have sql with body as false' do\n        @hash = { :col1 => 'body', :col2 => 'is_false', :col3 => 'python'}\n        output = @proc.call\n        assert_equal \"(articles.body = 'f')\", output[:cond]\n      end\n    end\n  end\n\n\n  context 'XHR advance_search' do\n    setup do\n      Article.delete_all\n      @proc = Proc.new do\n        @hash_big = { :klass => Article.name.underscore, :adv_search => {'2_row' => @hash } }\n      end\n    end\n    context 'with col2 contains' do\n      setup do\n        Factory(:article, :title => 'python')\n        @hash = {:col1 => 'title', :col2 => 'contains', :col3 => 'python'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should_respond_with :success\n      should 'contain content' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title'}, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 contains with no search result' do\n      setup do\n        Factory(:article, :title => 'ruby')\n        @hash = { :col1 => 'title', :col2 => 'contains', :col3 => 'python'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title' }, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 is_exactly' do\n      setup do\n        Factory(:article, :title => 'python')\n        @hash = { :col1 => 'title', :col2 => 'is_exactly', :col3 => 'python'}\n        xml_http_request :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title'}, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 is_exactly negative case' do\n      setup do\n        Factory(:article, :title => 'ruby')\n        @hash = {:col1 => 'title', :col2 => 'is_exactly', :col3 => 'python'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :id => 'search_result_title'}, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 does_not_contain' do\n      setup do\n        Factory(:article, :title => 'python')\n        @hash = {:col1 => 'title', :col2 => 'does_not_contain', :col3 => 'ruby'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title'}, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 does_not_conatin negative case' do\n      setup do\n        Factory(:article, :title => 'ruby')\n        @hash = {:col1 => 'title', :col2 => 'does_not_contain', :col3 => 'ruby'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes =>{ :class => 'title'}, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 is_false' do\n      setup do\n        Factory(:article, :approved => false)\n        @hash = {:col1 => 'approved', :col2 => 'is_false'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 is_false negative case' do\n      setup do\n        Factory(:article, :approved => true)\n        @hash = {:col1 => 'approved', :col2 => 'is_false'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 is_true' do\n      setup do\n        Factory(:article, :approved => true)\n        @hash = {:col1 => 'approved', :col2 => 'is_true'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title'}, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 is_true negative case' do\n      setup do\n        Factory(:article, :approved => false)\n        @hash = {:col1 => 'approved', :col2 => 'is_true'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 is_null' do\n      setup do\n        Factory(:article, :status => nil)\n        @hash = {:col1 => 'status', :col2 => 'is_null'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title' }, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 is_null negative case' do\n      setup do\n        Factory(:article, :status => 'something')\n        @hash = {:col1 => 'status', :col2 => 'is_null'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 is_not_null' do\n      setup do\n        Factory(:article, :status => 'something')\n        @hash = {:col1 => 'status', :col2 => 'is_not_null'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title'}, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 is_not_null negative case' do\n      setup do\n        Factory(:article, :status => nil)\n        @hash = {:col1 => 'status', :col2 => 'is_not_null'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title'}, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 is_equal_to' do\n      setup do\n        Factory(:article, :hits_count => 100)\n        @hash = {:col1 => 'hits_count', :col2 => 'is_equal_to', :col3 => 100.to_s}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title' }, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 is_equal_to negative case' do\n      setup do\n        Factory(:article, :hits_count => 100)\n        @hash = {:col1 => 'hits_count', :col2 => 'is_equal_to', :col3 => 101.to_s}\n        xml_http_request :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title' }, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 greater_than' do\n      setup do\n        Factory(:article, :hits_count => 100)\n        @hash = {:col1 => 'hits_count', :col2 => 'greater_than', :col3 => 99.to_s}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title'}, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 greater_than negative case' do\n      setup do\n        Factory(:article, :hits_count => 100)\n        @hash = {:col1 => 'hits_count', :col2 => 'greater_than', :col3 => 101.to_s}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title'}, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 less_than' do\n      setup do\n        Factory(:article, :hits_count => 100)\n        @hash = {:col1 => 'hits_count', :col2 => 'less_than', :col3 => 101.to_s}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title' }, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 less_than negative case' do\n      setup do\n        Factory(:article, :hits_count => 100)\n        @hash = {:col1 => 'hits_count', :col2 => 'less_than', :col3 => 99.to_s}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title' }, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 is_on' do\n      setup do\n        Factory(:article, :published_at => Time.now)\n        d = Time.now.strftime('%d-%B-%Y')\n        @hash = {:col1 => 'published_at', :col2 => 'is_on', :col3 => d}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes =>{ :class => 'title'}, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 is_on negative case' do\n      setup do\n        Factory(:article, :published_at => Time.now)\n        d = 1.year.ago.strftime('%d-%B-%Y')\n        @hash = {:col1 => 'published_at', :col2 => 'is_on', :col3 => d}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title'}, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 is_on_or_after_date' do\n      setup do\n        Factory(:article, :published_at => Time.now)\n        @hash = {:col1 => 'published_at', :col2 => 'is_on_or_after_date', :col3 => 1.month.ago.strftime('%d-%B-%Y') }\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title'}, :descendant => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 is_on_or_after_date negative case' do\n      setup do\n        Factory(:article, :published_at => Time.now)\n        @hash = {:col1 => 'published_at', :col2 => 'is_on_or_after_date', :col3 => 1.month.from_now.strftime('%d-%B-%Y') }\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title' }, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 is_on_or_before_date' do\n      setup do\n        Factory(:article, :published_at => Time.now)\n        @hash = {:col1 => 'published_at', :col2 => 'is_on_or_before_date', :col3 => 1.month.from_now.strftime('%d-%B-%Y') }\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag( :tag => 'h2', :attributes => { :class => 'title'}, :content => /Search result: 1 record found/ )\n      end\n    end\n\n    context 'with col2 is_on_or_before_date negative case' do\n      setup do\n        @hash = {:col1 => 'published_at', :col2 => 'is_on_or_before_date', :col3 => 1.year.ago.strftime('%d-%B-%Y') }\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'does contain text' do\n        assert_tag(:tag => 'h2', :attributes => {:class => 'title'}, :content => /Search result: 0 records found/ )\n      end\n    end\n\n    context 'with col2 is_on_or_before_date with invalid_date input' do\n      setup do\n        @hash = {:col1 => 'published_at', :col2 => 'is_on_or_before_date', :col3 => 'invalid_date'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag(:tag => 'p', :attributes => {:class => 'error'}, :content => /is not a valid date/ )\n      end\n    end\n\n    context 'with col2 is_on_or_after_date with invalid_date input' do\n      setup do\n        @hash = {:col1 => 'published_at', :col2 => 'is_on_or_after_date', :col3 => 'invalid_date'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag(:tag => 'p', :attributes => {:class => 'error'}, :content => /is not a valid date/ )\n      end\n    end\n\n    context 'is_on invalid date' do\n      setup do\n        @hash = {:col1 => 'published_at', :col2 => 'is_on', :col3 => 'invalid_date'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag(:tag => 'p', :attributes => {:class => 'error'}, :content => /is not a valid date/ )\n      end\n    end\n\n    context 'with col2 is_equal_to with invalid input' do\n      setup do\n        @hash = {:col1 => 'hits_count', :col2 => 'is_equal_to', :col3 => 'invalid_integer'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag(:tag => 'p', :attributes => {:class => 'error'}, :content => /is not a valid integer/ )\n      end\n    end\n\n    context 'with col2 less_than invalid_integer' do\n      setup do\n        @hash = {:col1 => 'hits_count', :col2 => 'less_than', :col3 => 'invalid_integer'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag(:tag => 'p', :attributes => {:class => 'error'}, :content => /is not a valid integer/ )\n      end\n    end\n\n    context 'with col2 greater_than invalid integer' do\n      setup do\n        @hash = {:col1 => 'hits_count', :col2 => 'greater_than', :col3 => 'invalid_integer'}\n        xml_http_request  :post, :advance_search, @proc.call\n      end\n      should 'contain text' do\n        assert_tag(:tag => 'p', :attributes => {:class => 'error'}, :content => /is not a valid integer/ )\n      end\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/helper/view_helper_test.rb",
    "content": "require File.expand_path(File.dirname(__FILE__) + \"/../test_helper\")\n\nclass ViewHelperTest < ActionView::TestCase\n\n  include FlexMock::TestCase\n\n  self.helper_class = AdminData::Helpers\n\n  def setup\n    @f = flexmock\n  end\n\n  context 'admin_data_form_field_id' do\n    context 'for primary key article_id' do\n      setup do\n        article = Factory(:article)\n        col = Article.columns.detect {|col| col.name == 'article_id'}\n        @output = admin_data_form_field(Article, article, col, @f)\n      end\n      should 'have value auto for id' do\n        assert_equal \"(auto)\", @output\n      end\n    end\n\n    context 'for primary key id' do\n      setup do\n        comment = Factory(:comment)\n        col = Comment.columns.detect {|col| col.name == 'id'}\n        @output = admin_data_form_field(Comment, comment, col, @f)\n      end\n      should 'have value auto for id' do\n        assert_equal \"(auto)\", @output\n      end\n    end\n\n    context 'for text_field' do\n      setup do\n        article = Factory(:article)\n        col = Article.columns.detect {|col| col.name == 'hits_count'}\n        @expected = '<input> for hits_count'\n        @f.should_receive(:text_field).with('hits_count', {:class => \"nice-field\", :size => 60}).and_return(@expected)\n        @output = admin_data_form_field(Article, article, col, @f)\n      end\n      should 'have input text' do\n        assert_equal @expected, @output\n      end\n    end\n  end\n\n  context 'for datetime_select' do\n    setup do\n      col = Article.columns_hash['published_at']\n      @article = Factory(:article, :published_at => Time.parse('Aug 31, 1999 1:23:45'))\n      initial_dropdowns  = '<input type=\"hidden\">for year and <select>s for month and day and <select>s for time'\n      @expected_html  = '<input type=\"text\" size=\"4\" class=\"nice-field\">for year and <select>s for month and day and <select>s for time'\n      flexmock(self).should_receive(:params).and_return({:action => 'edit'})\n      @f.should_receive(:datetime_select).with('published_at', {:include_blank => true}).and_return(initial_dropdowns)\n      @output = admin_data_form_field(Article, @article, col, @f)\n    end\n    should 'have expected output' do\n      assert_equal @expected_html, @output\n    end\n  end\n\n  context 'for date_select' do\n    setup do\n      col = Article.columns_hash['published_at']\n      flexmock(col).should_receive(:type).and_return(:date)\n      @article = Factory(:article, :published_at => Date.parse('Aug 31, 1999'))\n      initial_dropdowns  = '<input type=\"hidden\">for year and <select>s for month and day'\n      @expected_html  = '<input type=\"text\" size=\"4\" class=\"nice-field\">for year and <select>s for month and day'\n      flexmock(self).should_receive(:params).and_return({:action => 'edit'})\n      @f.should_receive(:date_select).with('published_at', {:discard_year => true, :include_blank => true}).and_return(initial_dropdowns)\n      @output = admin_data_form_field(Article, @article, col, @f)\n    end\n    should 'have expected value' do\n      assert_equal @expected_html, @output\n    end\n  end\n\n  context 'for collection_select' do\n    setup do\n      @article = Factory(:article)\n      @comment = Factory(:comment, :article => @article)\n      col = Comment.columns.detect {|col| col.name == 'article_id'}\n      @expected  = '<select> for articles'\n      all_articles = flexmock\n      flexmock(Article).should_receive(:all).with(:order => \"article_id asc\").and_return(all_articles)\n      @f.should_receive(:collection_select).with('article_id', all_articles, :id, 'article_id', {:include_blank => true} ).and_return(@expected)\n      @output = admin_data_form_field(Comment, @comment, col, @f)\n    end\n    should 'have expected value' do\n      assert_equal @expected, @output\n    end\n  end\n\n  context 'invoke admin_data_get_value_for_column'  do\n    context 'for text column' do\n      context 'untrucated case' do\n        setup do\n          column = Article.columns.select {|column| column.name.to_s == 'title'}.first\n          @article = Factory(:article)\n          @output = admin_data_get_value_for_column(column, @article, {})\n        end\n        should 'have untruncated title' do\n          assert_equal 'this is a dummy title', @output\n        end\n      end\n\n      context 'truncated case' do\n        setup do\n          column = Article.columns.select {|column| column.name.to_s == 'title'}.first\n          @article = Factory(:article, :title => 'this is a very very very long long long title')\n          options = {}\n\n          @output = admin_data_get_value_for_column(column,@article,{:limit => 15})\n        end\n        should 'should have truncated title' do\n          assert_equal 'this is a ve...', @output\n        end\n      end\n    end\n\n    context 'for integer column' do\n      setup do\n        @article = Factory(:article, :hits_count => 100)\n        column = Article.columns.select {|column| column.name.to_s == 'hits_count'}.first\n        @output = admin_data_get_value_for_column(column, @article)\n      end\n      should 'have right value' do\n        assert_equal 100, @output\n      end\n    end\n\n    context 'for integer column with truncate option should not cause any problem' do\n      setup do\n        @article = Factory(:article, :hits_count => 100)\n        column = Article.columns.select {|column| column.name.to_s == 'hits_count'}.first\n        @output = admin_data_get_value_for_column(column, @article, {:limit => 10})\n      end\n      should 'have right value' do\n        assert_equal 100, @output\n      end\n    end\n\n    context 'for text column which should raise exception' do\n      setup do\n        column = Article.columns.select {|column| column.name.to_s == 'title'}.first\n        @article = Factory(:article, :title => 'this is a very very very long long long title')\n        options = {}\n\n        #truncate method should raise exception\n        flexmock(self).should_receive('truncate').with('any_args').and_raise(Exception)\n\n        @output = admin_data_get_value_for_column(column,@article,{:limit => 15})\n      end\n      should 'have rescued message' do\n        assert_equal '<actual data is not being shown because truncate method failed.>', @output\n      end\n    end\n\n    context 'for text column which is serialized' do\n      setup do\n        column = Article.columns.select {|column| column.name.to_s == 'data'}.first\n        @article = Factory(:article, :data => { :key => 123456789 }.to_yaml)\n        options = {}\n\n        @output = admin_data_get_value_for_column(column,@article,{:limit => 15})\n      end\n      should 'show inspected value' do\n        assert_equal \"{:key=>12345...\", @output\n      end\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/misc_tests/date_validation_test.rb",
    "content": "require File.join(File.dirname(__FILE__) , '..', 'test_helper')\n\nrequire File.expand_path(File.join(File.dirname(__FILE__), '../../../admin_data/lib/admin_data_date_validation'))\n\n# FIXME why this one is not working\n#require File.expand_path(File.join(File.dirname(__FILE__) + '..' + '..' + '..' + 'admin_data' + 'lib' + 'admin_data_date_validation'))\n\nclass AdminDataTest < Test::Unit::TestCase\n\n  def test_date_validation\n\n    assert ::AdminDataDateValidation.validate('13-feb-2009')\n    assert ::AdminDataDateValidation.validate('13-FEB-2009')\n    assert ::AdminDataDateValidation.validate('13-feb -2009')    # extra white space should not hurt\n\n    # only the first three characters of the month should be checked\n    assert ::AdminDataDateValidation.validate('13-FEBfoo-2009')\n\n    assert !::AdminDataDateValidation.validate('13-foo-2009')    # month name is wrong\n    assert !::AdminDataDateValidation.validate('13 foo 2009')    # there must be two occurences of -\n    assert !::AdminDataDateValidation.validate('32-jan-2009')    # day is wrong\n    assert !::AdminDataDateValidation.validate('32-jan- -2009')  # there should be only two occurences of -\n    assert !::AdminDataDateValidation.validate('32-jan-09')      # year must be greater than 1900\n  end\n\n  def test_date_validation_with_operator\n    assert ::AdminDataDateValidation.validate_with_operator('> 13-feb-2009')\n    assert ::AdminDataDateValidation.validate_with_operator('>= 13-feb-2009')\n    assert ::AdminDataDateValidation.validate_with_operator('< 13-feb-2009')\n    assert ::AdminDataDateValidation.validate_with_operator('<= 13-feb-2009')\n\n    assert !::AdminDataDateValidation.validate_with_operator('<=13-feb-2009')  # no white space\n    assert !::AdminDataDateValidation.validate_with_operator('| 13-feb-2009')   # invalid operator\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/misc_tests/settings_test.rb",
    "content": "require 'test/test_helper'\n\nclass AdminData::AdminDataConfigTest < ActionController::TestCase\n  context 'setting configuration parameters' do\n    teardown do\n      AdminData::Config.initialize_defaults\n    end\n\n    %w(\n    find_conditions\n    plugin_dir\n    will_paginate_per_page\n    is_allowed_to_view\n    is_allowed_to_update\n    ).each do |valid_key|\n      should \"store #{valid_key} setting\" do\n        AdminData::Config.set = { valid_key.to_sym => \"some value for #{valid_key}\" }\n        assert_equal \"some value for #{valid_key}\", AdminData::Config.setting[valid_key.to_sym]\n      end\n    end\n\n    context \"get an error with a bad key\" do\n      should \"raise error when attempting to set bad key\" do\n        assert_raises(RuntimeError) { AdminData::Config.set = { :a_bad_key => \"some value\" }}\n      end\n    end\n\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/misc_tests/util_test.rb",
    "content": "require File.join(File.dirname(__FILE__) ,'..', 'test_helper')\n\nrequire File.expand_path(File.join(File.dirname(__FILE__), '../../../admin_data/lib/admin_data/util.rb'))\n\nclass AdminDataUtilTest < Test::Unit::TestCase\n\n  context 'has_one' do\n    subject { AdminData::Util.has_one_what(Vehicle::Car) }\n    setup { @instance = Vehicle::Car.create(:year => 2000, :brand => 'bmw') }\n    should 'be engine' do\n      assert subject\n      assert subject.size,1\n      assert_equal 'engine', subject[0] \n    end\n    should 'respond_to? has_one' do\n      assert @instance.respond_to?(subject[0])\n    end\n  end\n\n  context 'columns_order default order' do\n    setup do\n      AdminData::Config.set = {:columns_order => nil }\n      @output = AdminData::Util.columns_order('Article')\n    end\n    should 'have created_at and updated_at at the very end' do\n      assert_equal %w(article_id title body body_html short_desc status published_at approved hits_count\n      magazine_type magazine_id data created_at updated_at\n      ), @output\n    end\n  end\n\n  context 'columns_order custom order' do\n    setup do\n      AdminData::Config.set = {:columns_order => {'Article' => [:article_id, :body, :published_at] }}\n      @output = AdminData::Util.columns_order('Article')\n    end\n    should 'have right order' do\n      assert_equal %w(article_id body published_at title body_html short_desc status approved hits_count\n      magazine_type created_at updated_at magazine_id data\n      ),\n      @output\n    end\n  end\n\n  context 'oracle test' do\n    setup do\n      AdminData::Config.setting.merge!(:adapter_name => 'Oracle')\n      @term = Search::Term.new(Article,{:col1 => 'body_html', :col2 => 'contains', :col3 => 'foo'}, 'quick_search')\n    end\n    teardown do\n      AdminData::Config.setting.merge!(:adapter => 'MySQL')\n    end\n    should 'have proper sql' do\n      assert_equal [\"upper(articles.body_html) LIKE ?\", \"%FOO%\"], @term.attribute_condition\n    end\n  end\n\n  context 'postgresql test' do\n    setup do\n      AdminData::Config.setting.merge!(:adapter_name => 'PostgreSql')\n      @term = Search::Term.new(Article,{:col1 => 'body_html', :col2 => 'contains', :col3 => 'foo'}, 'quick_search')\n    end\n    teardown do\n      AdminData::Config.setting.merge!(:adapter => 'MySQL')\n    end\n    should 'have proper sql' do\n      assert_equal [\"articles.body_html ILIKE ?\", \"%foo%\"], @term.attribute_condition\n    end\n  end\n\n  context 'mysql test' do\n    setup do\n      AdminData::Config.setting.merge!(:adapter_name => 'MySQL')\n      @term = Search::Term.new(Article,{:col1 => 'body_html', :col2 => 'contains', :col3 => 'foo'}, 'quick_search')\n    end\n    teardown do\n      AdminData::Config.setting.merge!(:adapter => 'MySQL')\n    end\n    should 'have proper sql' do\n      assert_equal [\"articles.body_html LIKE ?\", \"%foo%\"], @term.attribute_condition\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/Rakefile",
    "content": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.\n\nrequire(File.join(File.dirname(__FILE__), 'config', 'boot'))\n\nrequire 'rake'\nrequire 'rake/testtask'\nrequire 'rake/rdoctask'\n\nrequire 'tasks/rails'\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/app/controllers/application_controller.rb",
    "content": "# Filters added to this controller apply to all controllers in the application.\n# Likewise, all the methods added will be available for all controllers.\n\nclass ApplicationController < ActionController::Base\n  helper :all # include all helpers, all the time\n  protect_from_forgery # See ActionController::RequestForgeryProtection for details\n\n  # Scrub sensitive parameters from your log\n  # filter_parameter_logging :password\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/app/controllers/articles_controller.rb",
    "content": "#class ArticlesController < ApplicationController\n\n#  def index\n#    render :text => 'hello world'\n#  end\n\n#end\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/app/models/article.rb",
    "content": "class Article < ActiveRecord::Base\n\n  set_primary_key 'article_id'\n\n  has_many :comments, :dependent => :destroy\n  \n  belongs_to :magazine, :polymorphic => true\n\n  before_save :set_body_html\n\n  validates_presence_of :title,:body\n\n  serialize :data\n\n  def to_param\n    \"#{id}-#{title.gsub(' ', '_').camelize}\"\n  end\n\n  private\n\n  def set_body_html\n    self.body_html = self.body\n  end\n  \nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/app/models/city.rb",
    "content": "class City < ActiveRecord::Base\n\n  before_create :set_permanent_name\n\n  def to_param\n    self.name.parameterize\n  end\n\n  private\n\n  def set_permanent_name\n    self.permanent_name = self.to_param\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/app/models/comment.rb",
    "content": "class Comment < ActiveRecord::Base\n  \n  belongs_to :article\n  \n  before_save :set_body_html\n\n  private\n\n  def set_body_html\n    self.body_html = self.body\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/app/models/tech_magazine.rb",
    "content": "class TechMagazine < ActiveRecord::Base\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/app/models/vehicle/car.rb",
    "content": "class Vehicle::Car < ActiveRecord::Base\n  has_many :doors, :class_name => 'Vehicle::Door', :dependent => :destroy\n  has_one :engine, :class_name => 'Vehicle::Engine', :dependent => :destroy\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/app/models/vehicle/door.rb",
    "content": "class Vehicle::Door < ActiveRecord::Base\n  belongs_to :car, :class_name => 'Vehicle::Car'\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/app/models/vehicle/engine.rb",
    "content": "class Vehicle::Engine < ActiveRecord::Base\n  belongs_to :car, :class_name => 'Vehicle::Car'\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/config/boot.rb",
    "content": "# Don't change this file!\n# Configure your app in config/environment.rb and config/environments/*.rb\n\nRAILS_ROOT = \"#{File.dirname(__FILE__)}/..\" unless defined?(RAILS_ROOT)\n\nmodule Rails\n  class << self\n    def boot!\n      unless booted?\n        preinitialize\n        pick_boot.run\n      end\n    end\n\n    def booted?\n      defined? Rails::Initializer\n    end\n\n    def pick_boot\n      (vendor_rails? ? VendorBoot : GemBoot).new\n    end\n\n    def vendor_rails?\n      File.exist?(\"#{RAILS_ROOT}/vendor/rails\")\n    end\n\n    def preinitialize\n      load(preinitializer_path) if File.exist?(preinitializer_path)\n    end\n\n    def preinitializer_path\n      \"#{RAILS_ROOT}/config/preinitializer.rb\"\n    end\n  end\n\n  class Boot\n    def run\n      load_initializer\n      Rails::Initializer.run(:set_load_path)\n    end\n  end\n\n  class VendorBoot < Boot\n    def load_initializer\n      require \"#{RAILS_ROOT}/vendor/rails/railties/lib/initializer\"\n      Rails::Initializer.run(:install_gem_spec_stubs)\n      Rails::GemDependency.add_frozen_gem_path\n    end\n  end\n\n  class GemBoot < Boot\n    def load_initializer\n      self.class.load_rubygems\n      load_rails_gem\n      require 'initializer'\n    end\n\n    def load_rails_gem\n      if version = self.class.gem_version\n        gem 'rails', version\n      else\n        gem 'rails'\n      end\n    rescue Gem::LoadError => load_error\n      $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)\n      exit 1\n    end\n\n    class << self\n      def rubygems_version\n        Gem::RubyGemsVersion rescue nil\n      end\n\n      def gem_version\n        if defined? RAILS_GEM_VERSION\n          RAILS_GEM_VERSION\n        elsif ENV.include?('RAILS_GEM_VERSION')\n          ENV['RAILS_GEM_VERSION']\n        else\n          parse_gem_version(read_environment_rb)\n        end\n      end\n\n      def load_rubygems\n        require 'rubygems'\n        min_version = '1.3.1'\n        unless rubygems_version >= min_version\n          $stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)\n          exit 1\n        end\n\n      rescue LoadError\n        $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)\n        exit 1\n      end\n\n      def parse_gem_version(text)\n        $1 if text =~ /^[^#]*RAILS_GEM_VERSION\\s*=\\s*[\"']([!~<>=]*\\s*[\\d.]+)[\"']/\n      end\n\n      private\n        def read_environment_rb\n          File.read(\"#{RAILS_ROOT}/config/environment.rb\")\n        end\n    end\n  end\nend\n\n# All that for this:\nRails.boot!\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/config/database.yml",
    "content": "development:\n  adapter: sqlite3\n  database: db/sqlite3.db\n  #:dbfile: \":memory:\"\n\ntest:\n  :adapter: sqlite3\n  database: \":memory:\"\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/config/environment.rb",
    "content": "old_verbose, $VERBOSE = $VERBOSE, nil\nRAILS_GEM_VERSION = '= 2.3.5' unless defined? RAILS_GEM_VERSION\n$VERBOSE = old_verbose\n\nrequire File.join(File.dirname(__FILE__), 'boot')\n\nRails::Initializer.run do |config|\n  config.log_level = :debug\n  config.cache_classes = false\n  config.whiny_nils = true\n  config.action_controller.session = {\n    :key    => 'admin_data_test_session',\n    :secret => 'ceae6058a816b1446e09ce90d8372511'\n  }\nend\n\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/config/environments/development.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/config/environments/test.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/config/initializers/new_rails_defaults.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# These settings change the behavior of Rails 2 apps and will be defaults\n# for Rails 3. You can remove this initializer when Rails 3 is released.\n\nif defined?(ActiveRecord)\n  # Include Active Record class name as root for JSON serialized output.\n  ActiveRecord::Base.include_root_in_json = true\n\n  # Store the full class name (including module namespace) in STI type column.\n  ActiveRecord::Base.store_full_sti_class = true\nend\n\n# Use ISO 8601 format for JSON serialized times and dates.\nActiveSupport.use_standard_json_time_format = true\n\n# Don't escape HTML entities in JSON, leave that for the #json_escape helper.\n# if you're including raw json in an HTML page.\nActiveSupport.escape_html_entities_in_json = false"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/config/routes.rb",
    "content": "ActionController::Routing::Routes.draw do |map|\n\n  #map.resources :articles\n\nend\n\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/db/migrate/20090809061114_create_tables.rb",
    "content": "class CreateTables < ActiveRecord::Migration\n  def self.up\n\n    create_table(:articles, :primary_key => 'article_id') do |t|\n      t.string :title ,           :null => false, :limit => 200\n      t.text :body,               :null => false\n      t.text :body_html,          :null => false\n      t.text :short_desc\n      t.string :status,           :default => 'draft', :limit => 50\n      t.datetime :published_at,   :null => true\n      t.boolean :approved\n      t.integer :hits_count\n      t.string :magazine_type\n      t.timestamps\n      t.integer :magazine_id # so that created_at and updated_at are not at the end\n      t.text :data\n    end\n\n    create_table :tech_magazines do |t|\n      t.timestamps\n    end\n\n    create_table :comments do |t|\n      t.integer :article_id,      :null => false\n      t.text :body,               :null => false\n      t.text :body_html,          :null => false\n      t.string :author_name,      :null => false\n      t.string :author_website,   :null => true\n      t.boolean :posted_by_admin, :default => false\n\n      t.timestamps\n    end\n\n    create_table :cars do |t|\n      t.integer :year\n      t.string :brand\n      t.timestamps\n    end\n\n    create_table :doors do |t|\n      t.string :color\n      t.integer :car_id\n      t.timestamps\n    end\n\n    create_table :cities do |t|\n      t.string :name\n      t.string :permanent_name\n      t.timestamps\n    end\n\n    create_table :engines do |t|\n      t.integer :cylinders\n      t.integer :car_id\n      t.timestamps\n    end\n\n  end\n\n  def self.down\n    drop_table :comments\n    drop_table :tech_magaznines\n    drop_table :articles\n    drop_table :cars\n    drop_table :doors\n    drop_table :cities\n    drop_table :engines\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/db/schema.rb",
    "content": "# This file is auto-generated from the current state of the database. Instead of editing this file, \n# please use the migrations feature of Active Record to incrementally modify your database, and\n# then regenerate this schema definition.\n#\n# Note that this schema.rb definition is the authoritative source for your database schema. If you need\n# to create the application database on another system, you should be using db:schema:load, not running\n# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations\n# you'll amass, the slower it'll run and the greater likelihood for issues).\n#\n# It's strongly recommended to check this file into your version control system.\n\nActiveRecord::Schema.define(:version => 20090809061114) do\n\n  create_table \"articles\", :primary_key => \"article_id\", :force => true do |t|\n    t.string   \"title\",                              :null => false, :limit => 200\n    t.text     \"body\",                               :null => false\n    t.text     \"body_html\",                          :null => false\n    t.text     \"short_desc\"\n    t.string   \"status\",        :default => \"draft\", :limit => 50\n    t.datetime \"published_at\"\n    t.boolean  \"approved\"\n    t.integer  \"hits_count\"\n    t.string   \"magazine_type\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n    t.integer  \"magazine_id\"\n    t.text     \"data\"\n  end\n\n  create_table \"cars\", :force => true do |t|\n    t.integer  \"year\"\n    t.string   \"brand\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"cities\", :force => true do |t|\n    t.string   \"name\"\n    t.string   \"permanent_name\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"comments\", :force => true do |t|\n    t.integer  \"article_id\",                         :null => false\n    t.text     \"body\",                               :null => false\n    t.text     \"body_html\",                          :null => false\n    t.string   \"author_name\",                        :null => false\n    t.string   \"author_website\"\n    t.boolean  \"posted_by_admin\", :default => false\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"doors\", :force => true do |t|\n    t.string   \"color\"\n    t.integer  \"car_id\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"engines\", :force => true do |t|\n    t.integer  \"cylinders\"\n    t.integer  \"car_id\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"tech_magazines\", :force => true do |t|\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/public/tmp/response.txt",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\">\n  <head>\n\t  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n\t  <title>admin_data</title>\n    \n    <link href=\"http://ajax.googleapis.com/ajax/libs/jqueryui/1.7/themes/ui-lightness/ui.all.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" /> \n    <style>* {margin:0;padding:0}\n.clear { clear: both; height: 0; }\n\nh1 { margin: 15px 0; font-size: 22px; font-weight: normal; }\nh2 { font-size: 22px; margin: 15px 0; font-weight: normal;}\nh3 { font-size: 18px; margin: 10px 0; font-weight: normal;}\nh4 { font-size: 16px; margin: 10px 0; font-weight: normal;}\nhr {height: 1px; border: 0; }\np { margin: 15px 0;}\na img { border: none; }\n\nbody {\n  font-size: 12px;\n  font-family: sans-serif;  \n}\n\n#container {\n  min-width: 960px;\n}\n\n#header, #wrapper {\n  padding: 0 20px;\n}\n\n#header {\n  position: relative;\n  padding-top: 1px;  \n}\n\n#header h1 {\n  margin: 0;\n  padding: 10px 0;  \n  font-size: 30px;\n}\n\n#header h1 a:link, #header h1 a:active, #header h1 a:hover, #header h1 a:visited {\n  text-decoration: none;\n}\n\n#main {  \n  width: 70%;\n  float: left;    \n}\n\n.actions-bar {\n  padding: 10px 1px;\n}\n\n.actions-bar .actions {\n  float: left;\n}\n\n\n.actions-bar .pagination {\n  float: right;\n  padding: 1px 0;\n}\n\n#sidebar {\n  width: 25%;\n  float: right;      \n}\n\n#sidebar h3 {  \n  padding: 10px 15px;\n  margin: 0;\n  font-size: 13px;\n}\n\n#sidebar .block {\n  margin-bottom: 20px;\n  padding-bottom: 10px;\n}\n\n#sidebar .block .content {\n  padding: 0 15px;\n}\n\n#sidebar ul.navigation li a:link, #sidebar ul.navigation li a:visited {\n  display: block;\n  padding: 10px 15px;\n}\n\n#sidebar .block .sidebar-block, #sidebar .notice {\n  padding:10px;\n}\n\n#wrapper {\n  padding-top: 20px;\n}\n\n#main .block {\n  margin-bottom: 20px;\n  padding-top: 1px;\n}\n\n#main .block .content .inner {\n  padding: 0 15px 15px;  \n}\n\n#main .main p.first {\n  margin-top: 0;\n}\n\n#user-navigation {\n  position: absolute;\n  top: 0px;\n  right: 20px;  \n}\n\n#main-navigation {\n  width: 100%;\n}\n\n#user-navigation ul, #main-navigation ul, .secondary-navigation ul, #sidebar ul.navigation {\n  margin: 0;\n  padding: 0;\n  list-style-type: none;\n}\n\n#user-navigation ul li, #main-navigation ul li, .secondary-navigation ul li {\n  float: left;  \n}\n\n#main-navigation ul li {\n  margin-right: 5px;\n}\n\n#user-navigation ul li {\n  padding: 5px 10px;\n}\n\n#main-navigation ul li a:link, #main-navigation ul li a:visited, #main-navigation ul li a:hover, #main-navigation ul li a:active,\n.secondary-navigation ul li a:link, .secondary-navigation ul li a:visited, .secondary-navigation ul li a:hover, .secondary-navigation ul li a:active,\n#user-navigation ul li a:link, #user-navigation ul li a:visited, #user-navigation ul li a:hover, #user-navigation ul li a:active {\n  text-decoration: none;\n}\n\n#main-navigation ul li a {\n  font-size: 15px;\n  display: block;\n  padding: 8px 15px;\n}\n\n.secondary-navigation {\n  font-size: 13px;  \n  border-bottom-width: 10px;\n  border-bottom-style: solid;\n}\n\n.secondary-navigation ul li a {\n  display: block;\n  padding: 10px 15px;  \n}\n\n#footer {\n  padding-bottom: 20px;\n}\n\n/* pagination */\n\n.pagination a, .pagination span {\n  padding: 2px 5px;\n  margin-right: 5px; \n  display: block;\n  float: left;\n  border-style: solid;\n  border-width: 1px;\n}\n\n.pagination span.current {\n  font-weight: bold;  \n}\n\n.pagination a {\n  text-decoration: none;  \n}\n\n/* tables */\n.table {\n  width: 100%;\n  border-collapse: collapse;  \n  margin-bottom: 15px;\n}\n\n.table th {\n  padding: 10px;\n  font-weight: bold;\n  text-align: left;\n}\n\n.table th.first {\n  width: 30px;\n}\n\n.table th.last {\n  width: 200px;  \n}\n\n.table .checkbox {\n  margin-left: 10px;\n}\n\n.table td {\n  padding: 10px;\n}\n\n.table td.last {\n  text-align: right;\n}\n\n/* forms */\n\ninput.checkbox {\n  margin: 0;\n  padding: 0;\n}\n\n.form .group {\n  margin-bottom: 15px;\n}\n\n.form div.left {\n  width: 20%;\n  float: left;\n}\n\n.form div.right {\n  width: 75%;\n  float: right;\n}\n\n.form .columns .column {\n  width: 48%;\n}\n\n.form .columns .left {\n  float: left;\n}\n\n.form .columns .right {\n  float: right;\n}\n\n.form label.label, .form input.text_field, .form textarea.text_area {\n  font-size: 1.2em;\n  padding: 1px 0;\n  margin: 0;\n}\n\n.form label.right {\n  text-align: right;\n}\n\n.form input.checkbox, .form input.radio {\n  margin-right: 5px;\n}\n\n.form label.checkbox, .form label.radio {\n  line-height: 1.5em;\n}\n\n.form label.label {\n  display: block;\n  padding-bottom: 2px;  \n  font-weight: bold;\n}\n\n.form div.fieldWithErrors label.label {\n  display: inline;\n}\n\n.form .fieldWithErrors .error {\n  color: red;\n}\n\n.form input.text_field, .form textarea.text_area {\n  width: 100%;\n  border-width: 1px;\n  border-style: solid;\n}\n\n/* lists */\n\nul.list {\n  margin: 0;\n  padding: 0;\n  list-style-type: none;\n}\n\nul.list li {\n  clear: left;\n  padding-bottom: 5px;\n}\n\nul.list li .left {\n  float: left;  \n}\n\nul.list li .left .avatar {\n  width: 50px;\n  height: 50px;\n}\n\nul.list li .item {\n  margin-left: 80px;\n}\n\nul.list li .item .avatar {\n  float: left;\n  margin: 0 5px 5px 0;\n  width: 30px;\n  height: 30px;\n}\n\n/* box */\n\n#box {\n  width: 500px;\n  margin: 50px auto;  \n}\n\n#box .block {\n  margin-bottom: 20px;\n}\n\n#box .block h2 {\n  padding: 10px 15px;\n  margin: 0;  \n}\n\n#box .block .content {\n  padding: 10px 20px;\n}\n\n\na:link, a:visited { color: #07b; text-decoration: none; }\na, a:hover, a:active { color: #d30; }\nh1, h2, h3 {color: #444}\n\nbody {\n  color: #333;\n  background: #EBEBEB;\n  font: normal 12px/1.5em \"Lucida Grande\", \"Helvetica Neue\", Arial, sans-serif;\n}\n\nhr {\n  background: #aaa; \n}\n\np {\n  font-size: 12px;\n  line-height: 20px;\n}\n\ninput.checkbox {\n  vertical-align:middle;\n}\n\n#header h1 {\n  font-size: 28px;\n  padding: 5px 0;\n  margin: 5px 0;\n}\n\n.hightlight {\n  background-color: #ffc;\n}\n.small {\n  font-size: 11px;\n}\n.gray {\n  color: #999;\n}\n#header {\n  background: #232C30;\n}\n\n#header h1 a:link, #header h1 a:active, #header h1 a:hover, #header h1 a:visited {\n  color: #eaeaea;\n}\n\n#main {\n  background: #EBEBEB;\n  width: 73%;\n}\n\n#main .block {\n  -moz-border-radius-topleft: 4px;\n  -moz-border-radius-topright: 4px;\n  padding: 0;\n  margin-bottom:20px;\n  padding-bottom: 20px;\n  background: transparent;\n}\n\n#main .block .content {\n  border-left: 1px solid #ddd;\n  border-top: 1px solid #ddd;\n  border-bottom: 1px solid #ccc;\n  border-right: 1px solid #ccc;\n  background: #fff;\n}\n\n#main .block h2.title {\n  margin: 10px 0 5px 0;\n  background-color: none;\n  padding: 5px 5px 5px 15px;\n  font-size:18px;\n  color: #456;\n}\n\n.main_container {\n  padding:10px;\n}\n\n#footer {\n  background-color: #ddd;\n  border-top: 1px solid #bbb;\n}\n\n#footer .block {\n  font-size:11px;\n  background-color: #ddd;\n  padding: 0 10px;\n  text-align: right;\n}\n\n/* #sidebar .block { background: #FFF; padding-bottom:0px; } */\n\n#sidebar .notice {\n  background-color: #ffc;\n  padding: 0 10px;\n  border-bottom:1px solid #ddd;\n  border-right:1px solid #ddd;\n  border-top:1px solid #fff;\n  border-left:1px solid #fff;\n}\n#sidebar .notice h2 {\n  font-size:16px;\n  margin: 5px 0;\n  border-bottom:1px solid #456;\n}\n#sidebar .notice p {\n  font-size:12px;\n}\n\n#sidebar .block {\n  padding-bottom: 0;\n}\n\n#sidebar .block .content {\n  padding: 0 10px;\n}\n\n\n#sidebar h3 {  \n  background: #fff;\n  border-bottom:1px solid #ccc;\n  border-right:1px solid #ccc;\n  border-left:1px solid #ddd;\n  border-top:1px solid #ddd;\n  padding: 5px 10px;\n  color: #333;\n  font-weight: bold;\n}\n\n#sidebar ul li a:link, #sidebar ul li a:visited {\n  font-size:12px;\n}\n\n#sidebar ul li a:hover, #sidebar ul li a:active {\n  background: none;\n  color: #444;\n  font-size:12px;\n  text-decoration:underline;\n}\n#sidebar ul.navigation li.last a {\n  border-bottom: none;\n}\n\n#sidebar ul.navigation li a:link,#sidebar ul.navigation li a:visited {\n  padding: 5px 10px;\n  color:#6a6a6a;\n  text-decoration: none;\n}\n#sidebar ul.navigation li a:hover {\n  text-decoration:underline;\n}\n#sidebar .block .sidebar-block h4 {\n  border-bottom: 1px dotted #aaa;\n}\n#main-navigation ul li {\n  background: #456;\n  border-top: 1px solid #5C738A;\n  color: #eee;\n  border-top-left-radius: 5px;\n  border-top-right-radius: 5px;\n}\n\n#main-navigation ul li:hover {\n  border-top-color: #7593B0;\n  background-color: #576C82 !important;\n  color: #fff;\n}\n\n#main-navigation ul li.active {\n  border-top: 1px solid #fff;\n  background-color: #eee !important;\n  color: #333;\n}\n\n#main-navigation ul li a:link, #main-navigation ul li a:visited, #main-navigation ul li a:hover, #main-navigation ul li a:active,\n.secondary-navigation ul li a:link, .secondary-navigation ul li a:visited, .secondary-navigation ul li a:hover, .secondary-navigation ul li a:active,\n#user-navigation ul li a:link, #user-navigation ul li a:visited, #user-navigation ul li a:hover, #user-navigation ul li a:active {\n  text-decoration: none;\n  color: #FFF;\n}\n\n#user-navigation ul li a:link, #user-navigation ul li a:visited {\n  color: #CDE;\n  border-bottom: 1px dotted #345;\n}\n\n#user-navigation ul li a:hover {\n  color: #fff;\n  border-bottom: 1px dotted #CDE;\n  text-decoration: none;\n}\n\n#main-navigation ul li a {\n  font-size: 12px;\n  padding: 3px 10px;\n}\n\n#main-navigation ul li.active a:link, #main-navigation ul li.active a:visited, #main-navigation ul li.active a:hover, #main-navigation ul li.active a:active {\n  color: #364b69;\n}\n\n.secondary-navigation {\n  background: #eaeaea;\n  border-bottom: 0px;\n}\n\n.secondary-navigation ul li {\n  background: #456;\n  border-top: 1px solid #5C738A;\n  color: #eee;\n  margin-right: 5px;\n  border-top-left-radius: 5px;\n  border-top-right-radius: 5px;\n}\n\n.secondary-navigation ul li a {\n  padding: 3px 10px;\n}\n\n.secondary-navigation ul li.active:hover {\n  background: #fff !important;\n  border-top: 1px solid #ccc;\n  border-right: 1px solid #ccc;\n}\n\n.secondary-navigation ul li.active {\n  border-top: 1px solid #ddd;\n  border-left: 1px solid #ddd;\n  border-right: 1px solid #ccc;\n  border-bottom: 1px solid #fff;\n  margin-bottom: -1px;\n  background-color: #fff !important;\n  color: #333;\n}\n\n.secondary-navigation ul li.active a {\n  color: #333;\n}\n\n.secondary-navigation ul li:hover {\n  border-top-color: #7593B0;\n  background-color: #576C82 !important;\n  color: #fff;\n}\n\n/* pagination */\n\n.pagination span.current {\n  background: #576C82;\n  color: #FFF;\n  border: 1px solid #7593B0;\n  -moz-border-radius:5px;\n}\n\n.pagination span.disabled {\n  background: #eee;\n  color: #aaa;\n  border: 1px solid #ddd;\n  -moz-border-radius:5px;\n}\n\n.pagination a {\n  color: #364B69;\n  border: 1px solid #ddd;\n  -moz-border-radius:5px;\n  font-size:11px;\n}\n\n.pagination a:hover {\n  color: #444;\n  background: #eaeaea;\n  border: 1px solid #576C82;\n}\n\n/* tables */\n\n.table th {\n  background: #576C82;\n  color: #FFF;\n  font-weight:normal;\n  padding:3px;\n}\n\n.table th a.toggle {\n  display: block;\n  width: 12px;\n  height: 12px;\n  background: transparent url('images/tick.png') center no-repeat;\n  text-indent: -9999px;\n  -moz-outline: none;\n}\n\n.table th.first {\n  width: 30px;\n  text-align: center;\n}\n\n.table td {\n  border-bottom: 1px solid #AAA;\n}\n\n/* forms */\n\n.form input.text, .form textarea.textarea {\n  border: 1px solid #ddd;\n  padding: 5px;\n  width:99%;\n}\n\n.form input.text_field, .form textarea.text_area {\n  border-right: 1px solid #ddd;\n  border-bottom: 1px solid #ddd;\n  border-top: 2px solid #ccc;\n  border-left: 2px solid #ccc;\n  width:99%;\n}\n\n.form .navform {\n  padding:10px;\n  background-color: #eee;\n  font-size:14px;\n  border-bottom:1px solid #ddd;\n  border-right:1px solid #ddd;\n  border-top:1px solid #eee;\n  border-left:1px solid #eee;\n}\n\n.form .navform input {\n  font-size:14px;\n}\n\n.description {\n  color:#aaa;\n  font-family:Georgia, serif;\n}\n\n/* flash-messages */\n.flash .message {\n  -moz-border-radius: 3px;\n  -webkit-border-radius: 3px;\n  text-align:center;\n  margin:0 auto 5px;\n  width:80%;\n}\n.flash .message p {\n  margin:8px;\n}\n.flash .error {\n  border: 1px solid #fbb;\n  background-color: #fdd;\n}\n.flash .warning {\n  border: 1px solid #fffaaa;\n  background-color: #ffffcc;\n}\n.flash .notice {\n  border: 1px solid #ddf;\n  background-color: #eef;\n}\n\n/* lists */\n\nul.list li {\n  border-bottom-color: #F0F0EE;\n}\n\nul.list li .item .avatar {\n  border-color: #F0F0EE;\n  margin: 3px 10px 0 0;\n}\n\nul.list li .left  {\n  padding: 5px 5px;\n}\n\n/* box */\n\n#box .block {\n  background: #FFF;\n  border: 1px solid #ddd;\n  border-radius: 10px;\n}\n\n#box .block h2 {\n  background: #576C82;  \n  color: #FFF;\n  border-top-left-radius: 5px;\n  border-top-right-radius: 5px;\n}\n/* Selectmenu\n----------------------------------*/\n.ui-selectmenu { display: block; position:relative; height:2em; text-decoration: none; overflow:hidden;}\n.ui-selectmenu-icon { position:absolute; right:6px; margin-top:-8px; top: 50%; }\n.ui-selectmenu-menu { padding:0; margin:0; list-style:none; position:absolute; top: 0; visibility: hidden; overflow: auto; }\n.ui-selectmenu-open { visibility: visible; }\n.ui-selectmenu-menu-popup { margin-top: -1px; }\n.ui-selectmenu-menu-dropdown { }\n.ui-selectmenu-menu li { padding:0; margin:0; display: block; border-top: 1px dotted transparent; border-bottom: 1px dotted transparent; border-right-width: 0 !important; border-left-width: 0 !important; font-weight: normal !important; }\n.ui-selectmenu-menu li a,.ui-selectmenu-status {line-height: 1.4em; display:block; padding:.3em 1em; outline:none; text-decoration:none; }\n.ui-selectmenu-menu li.ui-selectmenu-hasIcon a,\n.ui-selectmenu-hasIcon .ui-selectmenu-status { padding-left: 20px; position: relative; margin-left: 5px; }\n.ui-selectmenu-menu li .ui-icon, .ui-selectmenu-status .ui-icon { position: absolute; top: 1em; margin-top: -8px; left: 0; }\n.ui-selectmenu-status { line-height: 1.4em; }\n.ui-selectmenu-open li.ui-selectmenu-item-focus a {  }\n.ui-selectmenu-open li.ui-selectmenu-item-selected { }\n.ui-selectmenu-menu li span,.ui-selectmenu-status span { display:block; margin-bottom: .2em; }\n.ui-selectmenu-menu li .ui-selectmenu-item-header { font-weight: bold; }\n.ui-selectmenu-menu li .ui-selectmenu-item-content {  }\n.ui-selectmenu-menu li .ui-selectmenu-item-footer { opacity: .8; }\n/*for optgroups*/\n.ui-selectmenu-menu .ui-selectmenu-group { font-size: 1em; }\n.ui-selectmenu-menu .ui-selectmenu-group .ui-selectmenu-group-label { line-height: 1.4em; display:block; padding:.6em .5em 0; font-weight: bold; }\n.ui-selectmenu-menu .ui-selectmenu-group ul { margin: 0; padding: 0; }#footer {\n  padding-left:30px;\n}\n\n.search_form { \n  margin:15px 5px 5px 5px;\n  padding:5px;\n}\n\n.breadcrum {\n  margin-bottom: 15px;\n}\n\n#quick_search_input { font-size:15px; }\n\ntable.with_border td{\n\tborder:2px solid #DEDEDE;\n\tpadding:5px;\n}\n\ntable {\n\tborder-collapse:collapse;\n\tborder-spacing:0;\n}\n\n.advtable {\n\tfont-size:15px;\n}\n\n.ram_drop_down {\n\tfont-size:15px;\n\twidth:180px;\n\tpadding:2px;\n\tmargin:2px;\n}\n.advtable td {\n\tborder-bottom:1px solid #F0F0EE;\n\tpadding:10px;\n}\n\n.ram_input_field_col3 {\n\tfont-size:15px;\n}\n\n/*IE6 will ignore this*/\ninput[disabled], input[readonly], select[disabled], select[readonly], checkbox[disabled], checkbox[readonly], textarea[disabled], textarea[readonly]\n{\n background-color: #dcdcdc;\n border:  1px solid gray;\n color: #000000;\n cursor: default;\n}\n\n/*span.title {*/\n  /*font-weight: bold;*/\n  /*font-size: 20px;*/\n/*}*/\n\nspan.searching_message{\n  color: red;\n  font-size: 25px;\n  margin: 20px 0 20px 0;\n}\n\n\n\ntable#view_table {\n\tpadding: 0;\n  margin:5px 0 5px 0;\n\tborder-collapse:collapse;\n\tborder-spacing:0;\n}\n\ntable#view_table th {\n\tborder: 1px solid #ccc;\n\tletter-spacing: 2px;\n\ttext-align: left;\n\tpadding: 6px 6px 6px 12px;\n}\n\n\ntable#view_table td {\n\tborder: 1px solid #DEDEDE;\n\tpadding: 6px 6px 6px 12px;\n}\n\n</style>\n\n    <script src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js\" type=\"text/javascript\"></script>\n    <script src=\"http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js\" type=\"text/javascript\"></script>\n    <script> /*\n * jQuery UI selectmenu\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI\n */\n\n(function($) {\n\n$.widget(\"ui.selectmenu\", {\n\t_init: function() {\n\t\tvar self = this, o = this.options;\n\t\t\n\t\t//quick array of button and menu id's\n\t\tvar num = Math.round(Math.random() * 1000);\n\t\tthis.ids = [this.element.attr('id') + '_' + 'button' + '_' + num, this.element.attr('id') + '_' + 'menu' + '_' + num];\n\t\t\n\t\t//define safe mouseup for future toggling\n\t\tthis._safemouseup = true;\n\t\t\n\t\t//create menu button wrapper\n\t\tthis.newelement = $('<a class=\"'+ this.widgetBaseClass +' ui-widget ui-state-default ui-corner-all\" id=\"'+this.ids[0]+'\" role=\"button\" href=\"#\" aria-haspopup=\"true\" aria-owns=\"'+this.ids[1]+'\" aria-expanded=\"false\"></a>')\n\t\t\t.insertAfter(this.element);\n\t\t\n\t\t//transfer tabindex\n\t\tvar tabindex = this.element.attr('tabindex') || '0'; \n\t\tthis.newelement.attr('tabindex', tabindex);\n\t\t\n\t\t//save reference to select in data for ease in calling methods\n\t\tthis.newelement.data('selectelement', this.element);\n\t\t\n\t\t//menu icon\n\t\tthis.selectmenuIcon = $('<span class=\"'+ this.widgetBaseClass +'-icon ui-icon\"></span>')\n\t\t\t.prependTo(this.newelement)\n\t\t\t.addClass( (o.style == \"popup\")? 'ui-icon-triangle-2-n-s' : 'ui-icon-triangle-1-s' );\t\n\n\t\t\t\n\t\t//make associated form label trigger focus\n\t\t$('label[for='+this.element.attr('id')+']')\n\t\t\t.attr('for', this.ids[0])\n\t\t\t.bind('click', function(){\n\t\t\t\tself.newelement.focus();\n\t\t\t\treturn false;\n\t\t\t});\t\n\n\t\t//click toggle for menu visibility\n\t\tthis.newelement\n\t\t\t.bind('mousedown', function(event){\n\t\t\t\tself._toggle(event);\n\t\t\t\t//make sure a click won't open/close instantly\n\t\t\t\tif(o.style == \"popup\"){\n\t\t\t\t\tself._safemouseup = false;\n\t\t\t\t\tsetTimeout(function(){self._safemouseup = true;}, 300);\n\t\t\t\t}\t\n\t\t\t\treturn false;\n\t\t\t})\n\t\t\t.bind('click',function(){\n\t\t\t\treturn false;\n\t\t\t})\n\t\t\t.keydown(function(event){\n\t\t\t\tvar ret = true;\n\t\t\t\tswitch (event.keyCode) {\n\t\t\t\t\tcase $.ui.keyCode.ENTER:\n\t\t\t\t\t\tret = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase $.ui.keyCode.SPACE:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself._toggle(event);\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase $.ui.keyCode.UP:\n\t\t\t\t\tcase $.ui.keyCode.LEFT:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself._moveSelection(-1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase $.ui.keyCode.DOWN:\n\t\t\t\t\tcase $.ui.keyCode.RIGHT:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself._moveSelection(1);\n\t\t\t\t\t\tbreak;\t\n\t\t\t\t\tcase $.ui.keyCode.TAB:\n\t\t\t\t\t\tret = true;\n\t\t\t\t\t\tbreak;\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself._typeAhead(event.keyCode, 'mouseup');\n\t\t\t\t\t\tbreak;\t\n\t\t\t\t}\n\t\t\t\treturn ret;\n\t\t\t})\n\t\t\t.bind('mouseover focus', function(){ \n\t\t\t\t$(this).addClass(self.widgetBaseClass+'-focus ui-state-hover'); \n\t\t\t})\n\t\t\t.bind('mouseout blur', function(){  \n\t\t\t\t$(this).removeClass(self.widgetBaseClass+'-focus ui-state-hover'); \n\t\t\t});\n\t\t\n\t\t//document click closes menu\n\t\t$(document)\n\t\t\t.mousedown(function(event){\n\t\t\t\tself.close(event);\n\t\t\t});\n\n\t\t//change event on original selectmenu\n\t\tthis.element\n\t\t\t.click(function(){ this._refreshValue(); })\n\t\t\t.focus(function(){ this.newelement.focus(); });\n\t\t\n\t\t//create menu portion, append to body\n\t\tvar cornerClass = (o.style == \"dropdown\")? \" ui-corner-bottom\" : \" ui-corner-all\"\n\t\tthis.list = $('<ul class=\"' + self.widgetBaseClass + '-menu ui-widget ui-widget-content'+cornerClass+'\" aria-hidden=\"true\" role=\"listbox\" aria-multiselectable=\"false\" aria-labelledby=\"'+this.ids[0]+'\" id=\"'+this.ids[1]+'\"></ul>').appendTo('body');\t\t\t\t\n\t\t\n\t\t//serialize selectmenu element options\t\n\t\tvar selectOptionData = [];\n\t\tthis.element\n\t\t\t.find('option')\n\t\t\t.each(function(){\n\t\t\t\tselectOptionData.push({\n\t\t\t\t\tvalue: $(this).attr('value'),\n\t\t\t\t\ttext: self._formatText(jQuery(this).text()),\n\t\t\t\t\tselected: $(this).attr('selected'),\n\t\t\t\t\tclasses: $(this).attr('class'),\n\t\t\t\t\tparentOptGroup: $(this).parent('optgroup').attr('label')\n\t\t\t\t});\n\t\t\t});\t\t\n\t\t\t\t\n\t\t//active state class is only used in popup style\n\t\tvar activeClass = (self.options.style == \"popup\") ? \" ui-state-active\" : \"\";\n\t\t\n\t\t//write li's\n\t\tfor(var i in selectOptionData){\n\t\t\tvar thisLi = $('<li><a href=\"#\" tabindex=\"-1\" role=\"option\" aria-selected=\"false\">'+ selectOptionData[i].text +'</a></li>')\n\t\t\t\t.data('index',i)\n\t\t\t\t.addClass(selectOptionData[i].classes)\n\t\t\t\t.data('optionClasses', selectOptionData[i].classes)\n\t\t\t\t.mouseup(function(event){\n\t\t\t\t\t\tif(self._safemouseup){\n\t\t\t\t\t\t\tvar changed = $(this).data('index') != self._selectedIndex();\n\t\t\t\t\t\t\tself.value($(this).data('index'));\n\t\t\t\t\t\t\tself.select(event);\n\t\t\t\t\t\t\tif(changed){ self.change(event); }\n\t\t\t\t\t\t\tself.close(event,true);\n\t\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t})\n\t\t\t\t.click(function(){\n\t\t\t\t\treturn false;\n\t\t\t\t})\n\t\t\t\t.bind('mouseover focus', function(){ \n\t\t\t\t\tself._selectedOptionLi().addClass(activeClass); \n\t\t\t\t\tself._focusedOptionLi().removeClass(self.widgetBaseClass+'-item-focus ui-state-hover'); \n\t\t\t\t\t$(this).removeClass('ui-state-active').addClass(self.widgetBaseClass + '-item-focus ui-state-hover'); \n\t\t\t\t})\n\t\t\t\t.bind('mouseout blur', function(){ \n\t\t\t\t\tif($(this).is( self._selectedOptionLi() )){ $(this).addClass(activeClass); }\n\t\t\t\t\t$(this).removeClass(self.widgetBaseClass + '-item-focus ui-state-hover'); \n\t\t\t\t});\n\t\t\t\t\n\t\t\t//optgroup or not...\n\t\t\tif(selectOptionData[i].parentOptGroup){\n\t\t\t\tvar optGroupName = self.widgetBaseClass + '-group-' + selectOptionData[i].parentOptGroup;\n\t\t\t\tif(this.list.find('li.' + optGroupName).size()){\n\t\t\t\t\tthis.list.find('li.' + optGroupName + ':last ul').append(thisLi);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\t$('<li class=\"'+self.widgetBaseClass+'-group '+optGroupName+'\"><span class=\"'+self.widgetBaseClass+'-group-label\">'+selectOptionData[i].parentOptGroup+'</span><ul></ul></li>')\n\t\t\t\t\t\t.appendTo(this.list)\n\t\t\t\t\t\t.find('ul')\n\t\t\t\t\t\t.append(thisLi);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse{\n\t\t\t\tthisLi.appendTo(this.list);\n\t\t\t}\n\t\t\t\n\t\t\t//this allows for using the scrollbar in an overflowed list\n\t\t\tthis.list.bind('mousedown mouseup', function(){return false;});\n\t\t\t\n\t\t\t//append icon if option is specified\n\t\t\tif(o.icons){\n\t\t\t\tfor(var j in o.icons){\n\t\t\t\t\tif(thisLi.is(o.icons[j].find)){\n\t\t\t\t\t\tthisLi\n\t\t\t\t\t\t\t.data('optionClasses', selectOptionData[i].classes + ' ' + self.widgetBaseClass + '-hasIcon')\n\t\t\t\t\t\t\t.addClass(self.widgetBaseClass + '-hasIcon');\n\t\t\t\t\t\tvar iconClass = o.icons[j].icon || \"\";\n\t\t\t\t\t\t\n\t\t\t\t\t\tthisLi\n\t\t\t\t\t\t\t.find('a:eq(0)')\n\t\t\t\t\t\t\t.prepend('<span class=\"'+self.widgetBaseClass+'-item-icon ui-icon '+iconClass + '\"></span>');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\t\n\t\t\n\t\t//add corners to top and bottom menu items\n\t\tthis.list.find('li:last').addClass(\"ui-corner-bottom\");\n\t\tif(o.style == 'popup'){ this.list.find('li:first').addClass(\"ui-corner-top\"); }\n\t\t\n\t\t//transfer classes to selectmenu and list\n\t\tif(o.transferClasses){\n\t\t\tvar transferClasses = this.element.attr('class') || ''; \n\t\t\tthis.newelement.add(this.list).addClass(transferClasses);\n\t\t}\n\t\t\n\t\t//original selectmenu width\n\t\tvar selectWidth = this.element.width();\n\t\t\n\t\t//set menu button width\n\t\tthis.newelement.width( (o.width) ? o.width : selectWidth);\n\t\t\n\t\t//set menu width to either menuWidth option value, width option value, or select width \n\t\tif(o.style == 'dropdown'){ this.list.width( (o.menuWidth) ? o.menuWidth : ((o.width) ? o.width : selectWidth)); }\n\t\telse { this.list.width( (o.menuWidth) ? o.menuWidth : ((o.width) ? o.width - o.handleWidth : selectWidth - o.handleWidth)); }\t\n\t\t\n\t\t//set max height from option \n\t\tif(o.maxHeight && o.maxHeight < this.list.height()){ this.list.height(o.maxHeight); }\t\n\t\t\n\t\t//save reference to actionable li's (not group label li's)\n\t\tthis._optionLis = this.list.find('li:not(.'+ self.widgetBaseClass +'-group)');\n\t\t\t\t\n\t\t//transfer menu click to menu button\n\t\tthis.list\n\t\t\t.keydown(function(event){\n\t\t\t\tvar ret = true;\n\t\t\t\tswitch (event.keyCode) {\n\t\t\t\t\tcase $.ui.keyCode.UP:\n\t\t\t\t\tcase $.ui.keyCode.LEFT:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself._moveFocus(-1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase $.ui.keyCode.DOWN:\n\t\t\t\t\tcase $.ui.keyCode.RIGHT:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself._moveFocus(1);\n\t\t\t\t\t\tbreak;\t\n\t\t\t\t\tcase $.ui.keyCode.HOME:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself._moveFocus(':first');\n\t\t\t\t\t\tbreak;\t\n\t\t\t\t\tcase $.ui.keyCode.PAGE_UP:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself._scrollPage('up');\n\t\t\t\t\t\tbreak;\t\n\t\t\t\t\tcase $.ui.keyCode.PAGE_DOWN:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself._scrollPage('down');\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase $.ui.keyCode.END:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself._moveFocus(':last');\n\t\t\t\t\t\tbreak;\t\t\t\n\t\t\t\t\tcase $.ui.keyCode.ENTER:\n\t\t\t\t\tcase $.ui.keyCode.SPACE:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself.close(event,true);\n\t\t\t\t\t\t$(event.target).parents('li:eq(0)').trigger('mouseup');\n\t\t\t\t\t\tbreak;\t\t\n\t\t\t\t\tcase $.ui.keyCode.TAB:\n\t\t\t\t\t\tret = true;\n\t\t\t\t\t\tself.close(event);\n\t\t\t\t\t\tbreak;\t\n\t\t\t\t\tcase $.ui.keyCode.ESCAPE:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself.close(event,true);\n\t\t\t\t\t\tbreak;\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tret = false;\n\t\t\t\t\t\tself._typeAhead(event.keyCode,'focus');\n\t\t\t\t\t\tbreak;\t\t\n\t\t\t\t}\n\t\t\t\treturn ret;\n\t\t\t});\n\t\t\t\n\t\t//selectmenu style\n\t\tif(o.style == 'dropdown'){\n\t\t\tthis.newelement\n\t\t\t\t.addClass(self.widgetBaseClass+\"-dropdown\");\n\t\t\tthis.list\n\t\t\t\t.addClass(self.widgetBaseClass+\"-menu-dropdown\");\t\n\t\t}\n\t\telse {\n\t\t\tthis.newelement\n\t\t\t\t.addClass(self.widgetBaseClass+\"-popup\");\n\t\t\tthis.list\n\t\t\t\t.addClass(self.widgetBaseClass+\"-menu-popup\");\t\n\t\t}\n\t\t\n\t\t//append status span to button\n\t\tthis.newelement.prepend('<span class=\"'+self.widgetBaseClass+'-status\">'+ selectOptionData[this._selectedIndex()].text +'</span>');\n\t\t\n\t\t//hide original selectmenu element\n\t\tthis.element.hide();\n\t\t\n\t\t//transfer disabled state\n\t\tif(this.element.attr('disabled') == true){ this.disable(); }\n\t\t\n\t\t//update value\n\t\tthis.value(this._selectedIndex());\n\t},\n\tdestroy: function() {\n\t\tthis.element.removeData(this.widgetName)\n\t\t\t.removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled')\n\t\t\t.removeAttr('aria-disabled');\n\t\n\t\t//unbind click on label, reset its for attr\n\t\t$('label[for='+this.newelement.attr('id')+']')\n\t\t\t.attr('for',this.element.attr('id'))\n\t\t\t.unbind('click');\n\t\tthis.newelement.remove();\n\t\tthis.list.remove();\n\t\tthis.element.show();\t\n\t},\n\t_typeAhead: function(code, eventType){\n\t\tvar self = this;\n\t\t//define self._prevChar if needed\n\t\tif(!self._prevChar){ self._prevChar = ['',0]; }\n\t\tvar C = String.fromCharCode(code);\n\t\tc = C.toLowerCase();\n\t\tvar focusFound = false;\n\t\tfunction focusOpt(elem, ind){\n\t\t\tfocusFound = true;\n\t\t\t$(elem).trigger(eventType);\n\t\t\tself._prevChar[1] = ind;\n\t\t};\n\t\tthis.list.find('li a').each(function(i){\t\n\t\t\tif(!focusFound){\n\t\t\t\tvar thisText = $(this).text();\n\t\t\t\tif( thisText.indexOf(C) == 0 || thisText.indexOf(c) == 0){\n\t\t\t\t\t\tif(self._prevChar[0] == C){\n\t\t\t\t\t\t\tif(self._prevChar[1] < i){ focusOpt(this,i); }\t\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse{ focusOpt(this,i); }\t\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tthis._prevChar[0] = C;\n\t},\n\t_uiHash: function(){\n\t\treturn {\n\t\t\tvalue: this.value()\n\t\t};\n\t},\n\topen: function(event){\n\t\tvar self = this;\n\t\tthis._refreshPosition();\n\t\tthis._closeOthers(event);\n\t\tthis.newelement\n\t\t\t.attr('aria-expanded', true)\n\t\t\t.addClass('ui-state-active');\n\t\t\n\t\tthis.list\n\t\t\t.appendTo('body')\n\t\t\t.addClass(self.widgetBaseClass + '-open')\n\t\t\t.attr('aria-hidden', false)\n\t\t\t.find('li:not(.'+ self.widgetBaseClass +'-group):eq('+ this._selectedIndex() +') a').focus();\t\n\t\tif(this.options.style == \"dropdown\"){ this.newelement.removeClass('ui-corner-all').addClass('ui-corner-top'); }\t\n\t\tthis._refreshPosition();\n\t\tthis._trigger(\"open\", event, this._uiHash());\n\t},\n\tclose: function(event, retainFocus){\n\t\tif(this.newelement.is('.ui-state-active')){\n\t\t\tthis.newelement\n\t\t\t\t.attr('aria-expanded', false)\n\t\t\t\t.removeClass('ui-state-active');\n\t\t\tthis.list\n\t\t\t\t.attr('aria-hidden', true)\n\t\t\t\t.removeClass(this.widgetBaseClass+'-open');\n\t\t\tif(this.options.style == \"dropdown\"){ this.newelement.removeClass('ui-corner-top').addClass('ui-corner-all'); }\n\t\t\tif(retainFocus){this.newelement.focus();}\t\n\t\t\tthis._trigger(\"close\", event, this._uiHash());\n\t\t}\n\t},\n\tchange: function(event) {\n\t\tthis.element.trigger('change');\n\t\tthis._trigger(\"change\", event, this._uiHash());\n\t},\n\tselect: function(event) {\n\t\tthis._trigger(\"select\", event, this._uiHash());\n\t},\n\t_closeOthers: function(event){\n\t\t$('.'+ this.widgetBaseClass +'.ui-state-active').not(this.newelement).each(function(){\n\t\t\t$(this).data('selectelement').selectmenu('close',event);\n\t\t});\n\t\t$('.'+ this.widgetBaseClass +'.ui-state-hover').trigger('mouseout');\n\t},\n\t_toggle: function(event,retainFocus){\n\t\tif(this.list.is('.'+ this.widgetBaseClass +'-open')){ this.close(event,retainFocus); }\n\t\telse { this.open(event); }\n\t},\n\t_formatText: function(text){\n\t\treturn this.options.format ? this.options.format(text) : text;\n\t},\n\t_selectedIndex: function(){\n\t\treturn this.element[0].selectedIndex;\n\t},\n\t_selectedOptionLi: function(){\n\t\treturn this._optionLis.eq(this._selectedIndex());\n\t},\n\t_focusedOptionLi: function(){\n\t\treturn this.list.find('.'+ this.widgetBaseClass +'-item-focus');\n\t},\n\t_moveSelection: function(amt){\n\t\tvar currIndex = parseInt(this._selectedOptionLi().data('index'), 10);\n\t\tvar newIndex = currIndex + amt;\n\t\treturn this._optionLis.eq(newIndex).trigger('mouseup');\n\t},\n\t_moveFocus: function(amt){\n\t\tif(!isNaN(amt)){\n\t\t\tvar currIndex = parseInt(this._focusedOptionLi().data('index'), 10);\n\t\t\tvar newIndex = currIndex + amt;\n\t\t}\n\t\telse { var newIndex = parseInt(this._optionLis.filter(amt).data('index'), 10); }\n\t\t\n\t\tif(newIndex < 0){ newIndex = 0; }\n\t\tif(newIndex > this._optionLis.size()-1){\n\t\t\tnewIndex =  this._optionLis.size()-1;\n\t\t}\n\t\tthis._focusedOptionLi().find('a:eq(0)').blur();\n\t\tthis._optionLis.eq(newIndex).find('a:eq(0)').focus();\n\t},\n\t_scrollPage: function(direction){\n\t\tvar numPerPage = Math.floor(this.list.outerHeight() / this.list.find('li:first').outerHeight());\n\t\tnumPerPage = (direction == 'up') ? -numPerPage : numPerPage;\n\t\tthis._moveFocus(numPerPage);\n\t},\n\t_setData: function(key, value) {\n\t\tthis.options[key] = value;\n\t\tif (key == 'disabled') {\n\t\t\tthis.element\n\t\t\t\t.add(this.newelement)\n\t\t\t\t.add(this.list)\n\t\t\t\t\t[value ? 'addClass' : 'removeClass'](\n\t\t\t\t\t\tthis.widgetBaseClass + '-disabled' + ' ' +\n\t\t\t\t\t\tthis.namespace + '-state-disabled')\n\t\t\t\t\t.attr(\"aria-disabled\", value);\n\t\t}\n\t},\n\tvalue: function(newValue) {\n\t\tif (arguments.length) {\n\t\t\tthis.element[0].selectedIndex = newValue;\n\t\t\tthis._refreshValue();\n\t\t\tthis._refreshPosition();\n\t\t}\n\t\treturn this.element[0].selectedIndex;\n\t},\n\t_refreshValue: function() {\n\t\tvar activeClass = (this.options.style == \"popup\") ? \" ui-state-active\" : \"\";\n\t\t//deselect previous\n\t\tthis.list\n\t\t\t.find('.'+ this.widgetBaseClass +'-item-selected')\n\t\t\t.removeClass(this.widgetBaseClass + \"-item-selected\" + activeClass)\n\t\t\t.find('a')\n\t\t\t.attr('aria-selected', 'false');\n\t\t//select new\n\t\tthis._selectedOptionLi()\n\t\t\t.addClass(this.widgetBaseClass + \"-item-selected\"+activeClass)\n\t\t\t.find('a')\n\t\t\t.attr('aria-selected', 'true');\n\t\t//toggle any class brought in from option\n\t\tvar currentOptionClasses = this.newelement.data('optionClasses') ? this.newelement.data('optionClasses') : \"\";\n\t\tvar newOptionClasses = this._selectedOptionLi().data('optionClasses') ? this._selectedOptionLi().data('optionClasses') : \"\";\n\t\tthis.newelement\n\t\t\t.removeClass(currentOptionClasses)\n\t\t\t.data('optionClasses', newOptionClasses)\n\t\t\t.addClass( newOptionClasses )\n\t\t\t.find('.'+this.widgetBaseClass+'-status')\n\t\t\t.html( \n\t\t\t\tthis._selectedOptionLi()\n\t\t\t\t\t.find('a:eq(0)')\n\t\t\t\t\t.html() \n\t\t\t);\n\t},\n\t_refreshPosition: function(){\t\n\t\t//set left value\n\t\tthis.list.css('left', this.newelement.offset().left);\n\t\t\n\t\t//set top value\n\t\tvar menuTop = this.newelement.offset().top;\n\t\tvar scrolledAmt = this.list[0].scrollTop;\n\t\tthis.list.find('li:lt('+this._selectedIndex()+')').each(function(){\n\t\t\tscrolledAmt -= $(this).outerHeight();\n\t\t});\n\t\t\n\t\tif(this.newelement.is('.'+this.widgetBaseClass+'-popup')){\n\t\t\tmenuTop+=scrolledAmt; \n\t\t\tthis.list.css('top', menuTop); \n\t\t}\t\n\t\telse { \n\t\t\tmenuTop += this.newelement.height();\n\t\t\tthis.list.css('top', menuTop); \n\t\t}\n\t}\n});\n\n$.extend($.ui.selectmenu, {\n\tgetter: \"value\",\n\tversion: \"@VERSION\",\n\teventPrefix: \"selectmenu\",\n\tdefaults: {\n\t\ttransferClasses: true,\n\t\tstyle: 'popup', \n\t\twidth: null, \n\t\tmenuWidth: null, \n\t\thandleWidth: 26, \n\t\tmaxHeight: null,\n\t\ticons: null, \n\t\tformat: null\n\t}\n});\n\n})(jQuery);</script>\n\n    \n  \n    <script>\n      $(document).ready(function(){\n        function colorize_table(){\n            $('.colorize tr:odd').addClass('odd'); \n            $('.colorize tr:even').addClass('even'); \n        };\n        colorize_table();\n\n        $('#drop_down_value_klass').selectmenu();\n        $('#sortby').selectmenu();\n      });\n    </script>\n\t\n\n  </head>\n\n  <body>\n    <div id=\"container\">\n      <div id=\"header\">\n  <h1 style='float:left;'>\n    <a href=\"/admin_data\">admin_data</a>\n  </h1>\n  <div id='model_drop_down' style='float:right;margin:10px;'>\n    <select id='drop_down_value_klass' style='width:300px;font-size:14px;' \n            onchange=\"window.location.href=this.options[this.selectedIndex].value\">\n      <option></option>      \n      <option value=\"http://test.host/admin_data/search?klass=Article\">Article</option>\n<option value=\"http://test.host/admin_data/search?klass=Comment\">Comment</option>\n<option value=\"http://test.host/admin_data/search?klass=Vehicle%3A%3ACar\">Vehicle::Car</option>\n<option value=\"http://test.host/admin_data/search?klass=Vehicle%3A%3ADoor\">Vehicle::Door</option>\n<option value=\"http://test.host/admin_data/search?klass=Vehicle%3A%3AEngine\">Vehicle::Engine</option>\n    </select>\n  </div>\n  <div style='clear:both;'></div>\n  <div id=\"main-navigation\">\n    <ul>\n      <li class=\"first active\">\n        <a href=\"/admin_data\">Home</a>\n      </li>\n      <li class=\"\">\n        <a href=\"/admin_data/migration\">Migration Information</a>\n      </li>\n      <li class=\"\">\n        <a href=\"/admin_data/diagnostic\">Diagnostic</a>\n      </li>\n    </ul>\n    <div class=\"clear\"></div>\n  </div>\n</div>    \n\n      <div id=\"wrapper\">\n        <div id='main'>\n    <div class='breadcrum'>\n  <a href=\"/admin_data\">Home</a>\n  >\n  \n    <a href=\"/admin_data/search?klass=vehicle%2Fcar\">Vehicle::Car</a> \n  \n  \n    <span class='description'>\n      (1 record ) \n    </span>  \n    \n</div>\n  \n\n  <div class=\"block\" id=\"block-text\">\n    <div class=\"secondary-navigation\">\n      <ul>\n  <li class=\"first active\">\n    <a href=\"/admin_data/search?klass=vehicle%2Fcar\">Quick Search</a> \n  </li>\n  <li class=\"\">\n    <a href=\"/admin_data/advance_search?klass=vehicle%2Fcar\">Advance Search</a>\n  </li>\n  <li class=\"\">\n    <a href=\"/admin_data/table_structure?klass=vehicle%2Fcar\">Table Structure</a>\n  </li>\n  \n    \n  \n</ul>\n\n      <div class=\"clear\"></div>\n    </div>          \n\n    <div class=\"content\">         \n      \n        <form action=\"/admin_data/search\" class=\"form search_form\" id=\"search\" method=\"get\">   \n\n  <input type=\"hidden\" name=\"klass\" value=\"Vehicle::Car\" />     \n  <div class='search_box'>\n    <div id='quick_search'>\n      <div class='group'>\n        <label class='label'>search keyword</label>\n        <input type=\"text\" id=\"quick_search_input\" name=\"query\" value=\"\"/>\n      </div>\n\n     <div class='group'>\n  <label class='label'>sort by</label>\n  <select name='sortby' id='sortby' style='width:200px;display:inline;'>\n    <option value='id desc' >&nbsp;id desc</option><option value='id asc' >&nbsp;id asc</option><option value='year desc' >&nbsp;year desc</option><option value='year asc' >&nbsp;year asc</option><option value='brand desc' >&nbsp;brand desc</option><option value='brand asc' >&nbsp;brand asc</option><option value='created_at desc' >&nbsp;created_at desc</option><option value='created_at asc' >&nbsp;created_at asc</option><option value='updated_at desc' >&nbsp;updated_at desc</option><option value='updated_at asc' >&nbsp;updated_at asc</option>\n  </select>\n</div>  \n\n\n\n   </div>\n   <div style='margin-top:10px;'>\n     <input onclick=\"if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='searching ...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;\" type=\"submit\" value=\"Search\" />\n   </div>  \n </div>\n</form>\n<br />\n\n<script type=\"text/javascript\">\n  document.getElementById(\"quick_search_input\").focus();\n</script>\n\n        \n    </div>\n  </div>\n\n  <div class=\"block\" id=\"block-tables\">\n    <div class=\"content\">          \n      <div class='inner'>\n        <div id='results'>\n              <h2 class='title'> \n\n  \n    All Vehicle::Car records \n    \n\n</h2>\n\n\n    <div class=\"pagination\">\n      \n    </div>\n    <div class='clear'></div>\n\n    <table cellspacing=\"3\" cellpadding=\"3\" id=\"view_table\" class='table colorize'>\n\n    <tbody>\n      <tr>\n      \n        <th> id </th>\n      \n        <th> year </th>\n      \n        <th> brand </th>\n      \n        <th> created_at </th>\n      \n        <th> updated_at </th>\n      \n    </tr>\n    </tbody>\n\n    \n      <tr>\n        \n          <td>\n            \n              <a href=\"/admin_data/show?klass=vehicle%2Fcar&amp;model_id=1\">1</a>\n              \n            \n          </td>\n        \n          <td>\n            \n              \n              \n            \n          </td>\n        \n          <td>\n            \n              bmw\n              \n            \n          </td>\n        \n          <td>\n            \n              09/25/2009 13:03:27 PM\n              \n            \n          </td>\n        \n          <td>\n            \n              09/25/2009 13:03:27 PM\n              \n            \n          </td>\n        \n      </tr>\n      \n    </table>\n\n    <div class=\"pagination\">\n      \n    </div>\n    <div class='clear'></div>\n\n\n        </div>\n      </div>\n    </div>\n  </div>\n\n</div>  \n\n        <div class=\"clear\"></div>      \n      </div>    \n      <div id=\"footer\">\n  <p style='float:left;font-size:11px;padding:2px 10px 2px 2px;'>\n    Powered by \n    <a href='http://github.com/neerajdotname/admin_data/tree/master' class='powered_by'>\n      admin_data\n    </a>\n  </p>\n\n  <p style='float:left;font-size:11px;padding:2px 10px 2px 2px;'> \n    <a href='http://github.com/neerajdotname/admin_data/issues' class='powered_by'>\n      Report Bug\n    </a>\n  </p>\n  <div class='clear'></div>\n</div>\n\n    </div>\n  </body>\n  \n</html>\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/script/about",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\n$LOAD_PATH.unshift \"#{RAILTIES_PATH}/builtin/rails_info\"\nrequire 'commands/about'"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/script/console",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/console'\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/script/dbconsole",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/dbconsole'\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/script/destroy",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/destroy'\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/script/generate",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/generate'\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/script/performance/benchmarker",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../../config/boot'\nrequire 'commands/performance/benchmarker'\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/script/performance/profiler",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../../config/boot'\nrequire 'commands/performance/profiler'\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/script/plugin",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/plugin'\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/script/runner",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/runner'\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/rails_root/script/server",
    "content": "#!/usr/bin/env ruby\nrequire File.dirname(__FILE__) + '/../config/boot'\nrequire 'commands/server'\n"
  },
  {
    "path": "vendor/plugins/admin_data/test/test_helper.rb",
    "content": "pwd = File.dirname(__FILE__)\n\n$:.unshift File.join(pwd + '..', 'lib')\n$:.unshift File.join(pwd + '..', 'app')\n$:.unshift File.join(pwd + '..', 'app', 'controllers')\n$:.unshift File.join(pwd + '..', 'app', 'controllers', 'admin_data')\n\nmodule AdminData\nend\n\nENV['RAILS_ENV'] = 'test'\n\nrails_root = File.join(pwd , 'rails_root')\n\n# start rails\nrequire \"#{rails_root}/config/environment.rb\"\n\n#require all the lib files plugin needs\nDir[File.join(pwd, '..', 'lib', '**', '*.rb')].each {|f| require f}\n\n# initialize defaults\nAdminData::Config.initialize_defaults\n\n#require all the controllers plugins needs\nDir[File.join(pwd, '..', 'app', 'controllers', 'admin_data', '*.rb')].each {|f| require f}\n\n# make sure that plugin views have access to helpers\nActionView::Base.send :include, AdminData::Helpers\n\n#require plugin routes\nrequire \"#{rails_root}/../../config/routes.rb\"\n\n#require all the controllers from the test controllers\n#Dir[File.join(pwd, 'rails_root', 'app', 'controllers', '*.rb')].each {|controller| require controller }\n\nrequire 'test/unit'\nrequire 'test_help'\nsilence_warnings { RAILS_ENV = ENV['RAILS_ENV'] }\n\n# Run the migrations\nActiveRecord::Migration.verbose = false\nActiveRecord::Migrator.migrate(\"#{Rails.root}/db/migrate\")\n\n\ngem 'shoulda','>= 2.10.2'\nrequire 'shoulda'\n\ngem 'will_paginate', '>= 2.3.11'\nrequire 'will_paginate'\n\ngem 'factory_girl', '= 1.2.4'\nrequire 'factory_girl'\n\ngem 'flexmock', '>= 0.8.6'\nrequire 'flexmock'\n\ngem 'redgreen', '>= 1.2.2'\nrequire 'RedGreen'\n\n# for helper tests\nrequire 'action_view/test_case'\n\nDir[File.join(pwd, 'factories', '*.rb')].each { |f| require File.expand_path(f) }\n\nclass ActiveSupport::TestCase\n\n  def revoke_read_only_access\n    AdminData::Config.set = ({:is_allowed_to_view => Proc.new { |controller| false } })\n  end\n\n  def grant_read_only_access\n    AdminData::Config.set = ({:is_allowed_to_view => Proc.new { |controller| true } })\n  end\n\n  def grant_update_access\n    AdminData::Config.set = ({:is_allowed_to_update => Proc.new { |controller| true } })\n  end\n\n  def revoke_update_access\n    AdminData::Config.set = ({:is_allowed_to_update => Proc.new { |controller| false } })\n  end\n\n  def show_response\n    Dir.mkdir(File.join(Rails.root, 'tmp')) unless File.directory?(File.join(Rails.root, 'tmp'))\n    response_html = File.join(Rails.root, 'tmp', 'response.html')\n    File.open(response_html, 'w') { |f| f.write(@response.body) }\n    system 'open ' + File.expand_path(response_html) rescue nil\n  end\n\nend\n\n"
  },
  {
    "path": "vendor/plugins/annotate_models/History.txt",
    "content": "== 2.1 2009-10-18\n\n* New options\n  * -R to require additional files before loading the models\n  * -i to show database indexes in annotations\n  * -e to exclude annotating tests or fixtures\n  * -m to include the migration version number in the annotation\n  * --model-dir to annotate model files stored a different place than app/models  \n* Ignore unknown macros ('acts_as_whatever')\n\n== 2.0 2009-02-03\n\n* Add annotate_models plugin fork additions\n  * Annotates Rspec and Test Unit models\n  * Annotates Object Daddy exemplars\n  * Annotates geometrical columns\n* Add AnnotateRoutes rake task\n* Up gem structure to newgem defaults\n\n== 1.0.4 2008-09-04\n\n* Only update modified models since last run, thanks to sant0sk1\n\n== 1.0.3 2008-05-02\n\n* Add misc changes from Dustin Sallings and Henrik N\n  * Remove trailing whitespace\n  * More intuitive info messages\n  * Update README file with update-to-date example\n\n== 1.0.2 2008-03-22\n\n* Add contributions from Michael Bumann (http://github.com/bumi)\n  * added an option \"position\" to choose to put the annotation,\n  * spec/fixtures now also get annotated\n  * added a task to remove the annotations\n  * these options can be specified from command line as -d and -p [before|after]\n"
  },
  {
    "path": "vendor/plugins/annotate_models/README.rdoc",
    "content": "== Annotate (aka AnnotateModels)\n\nAdd a comment summarizing the current schema to the top or bottom of each of your...\n\n  * ActiveRecord models\n  * Fixture files\n  * Tests and Specs\n  * Object Daddy exemplars\n  * Machinist blueprints\n\nThe schema comment looks like this:\n\n   # == Schema Info\n   #\n   # Table name: line_items\n   #\n   #  id                  :integer(11)    not null, primary key\n   #  quantity            :integer(11)    not null\n   #  product_id          :integer(11)    not null\n   #  unit_price          :float\n   #  order_id            :integer(11)\n   #\n\n    class LineItem < ActiveRecord::Base\n      belongs_to :product\n     . . .\n\nIt also annotates geometrical columns, geom type and srid, when using SpatialAdapter or PostgisAdapter:\n\n   # == Schema Info\n   #\n   # Table name: trips\n   #\n   #  local           :geometry        point, 4326\n   #  path            :geometry        line_string, 4326\n\nAlso, if you pass the -r option, it'll annotate routes.rb with the output of \"rake routes\".\n\n== INSTALL\n\nFrom rubyforge:\n\n  sudo gem install annotate\n\nFrom github:\n\n  git clone git://github.com/ctran/annotate_models.git annotate\n  cd annotate\n  rake gem\n  sudo gem install pkg/annotate-*.gem\n\n== USAGE\n\nTo annotate all your models, tests, fixtures, etc.:\n\n  cd /path/to/app\n  annotate\n\nTo annotate your models and tests:\n\n  annotate --exclude fixtures\n\nTo annotate just your models:\n\n  annotate --exclude tests,fixtures\n\nTo annotate routes.rb:\n\n  annotate -r\n\nTo automatically annotate after running 'rake db:migrate':\n  \n  [needs more clarity] unpack the gem into vendor/plugins, or maybe vendor/gems, or maybe just require tasks/migrate.rake.\n\nIf you install annotate_models as a plugin, it will automatically\nadjust your <tt>rake db:migrate</tt> tasks so that they update the\nannotations in your model files for you once the migration is\ncompleted.\n\n== OPTIONS\n\n    Usage: annotate [options] [model_file]*\n        -d, --delete                     Remove annotations from all model files\n        -p, --position [before|after]    Place the annotations at the top (before) or the bottom (after) of the model file\n        -r, --routes                     Annotate routes.rb with the output of 'rake routes'\n        -v, --version                    Show the current version of this gem\n        -m, --show-migration             Include the migration version number in the annotation\n        -i, --show-indexes               List the table's database indexes in the annotation\n        -s, --simple-indexes             Concat the column's related indexes in the annotation\n            --model-dir dir              Annotate model files stored in dir rather than app/models\n        -R, --require path               Additional files to require before loading models\n        -e, --exclude [tests,fixtures]   Do not annotate fixtures, test files, or both\n\n\n== WARNING\n\nNote that this code will blow away the initial/final comment\nblock in your models if it looks like it was previously added\nby annotate models, so you don't want to add additional text\nto an automatically created comment block.\n\n        * * Back up your model files before using... * *\n\n== LINKS\n\n* Factory Girl => http://github.com/thoughtbot/factory_girl (NOT IMPLEMENTED)\n* Object Daddy => http://github.com/flogic/object_daddy\n* SpatialAdapter => http://github.com/pdeffendol/spatial_adapter\n* PostgisAdapter => http://github.com/nofxx/postgis_adapter\n\n== LICENSE:\n\nReleased under the same license as Ruby. No Support. No Warranty.\n\n== AUTHOR:\n\nOriginal code by: Dave Thomas -- Pragmatic Programmers, LLC\nOverhauled by: Alex Chaffee\nGemmed by: Cuong Tran\nMaintained by: Alex Chaffee and Cuong Tran\n\nModifications by:\n\n - Alex Chaffee - http://github.com/alexch - alex@pivotallabs.com\n - Cuong Tran - http://github.com/ctran - ctran@pragmaquest.com\n - Jack Danger - http://github.com/JackDanger\n - Michael Bumann - http://github.com/bumi\n - Henrik Nyh - http://github.com/henrik\n - Marcos Piccinini - http://github.com/nofxx\n - Neal Clark - http://github.com/nclark\n - Jacqui Maher - http://github.com/jacqui\n - Nick Plante - http://github.com/zapnap - http://blog.zerosum.org\n - Pedro Visintin - http://github.com/peterpunk - http://www.pedrovisintin.com\n - Bob Potter - http://github.com/bpot\n - Gavin Montague - http://github.com/govan/\n - Alexander Semyonov - http://github.com/rotuka/\n \nand many others that I may have missed to add.\n"
  },
  {
    "path": "vendor/plugins/annotate_models/Rakefile",
    "content": "require 'rubygems'\nrequire 'rake'\nrequire 'lib/annotate'\n\n# want other tests/tasks run by default? Add them to the list\ntask :default => [:spec]\n\nbegin\n  require 'jeweler'\n  Jeweler::Tasks.new do |gem|\n    gem.name = \"annotate\"\n    gem.executables = \"annotate\"\n    gem.summary = \"Annotates Rails Models, routes, fixtures, and others based on the database schema.\"\n    gem.description = gem.summary\n    gem.email = [\"alex@stinky.com\", 'ctran@pragmaquest.com', \"x@nofxx.com\"]\n    gem.homepage = \"http://github.com/ctran/annotate\"\n    gem.authors = ['Cuong Tran', \"Alex Chaffee\", \"Marcos Piccinini\"]\n    gem.files =  FileList[\"[A-Z]*.*\", \"{bin,lib,tasks,spec}/**/*\"]\n    gem.rubyforge_project = \"annotate\"\n    \n    # note that Jeweler automatically reads the version from VERSION.yml\n    # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings\n  end\n  \n  Jeweler::RubyforgeTasks.new do |rubyforge|\n    rubyforge.doc_task = \"rdoc\"\n  end\n  \nrescue LoadError\n  puts \"Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler\"\nend\n\nrequire 'spec/rake/spectask'\nSpec::Rake::SpecTask.new(:spec) do |spec|\n  spec.libs << 'lib' << 'spec'\n  spec.spec_files = FileList['spec/**/*_spec.rb']\nend\n\nSpec::Rake::SpecTask.new(:rcov) do |spec|\n  spec.libs << 'lib' << 'spec'\n  spec.pattern = 'spec/**/*_spec.rb'\n  spec.rcov = true\nend\n\nrequire 'rake/rdoctask'\nRake::RDocTask.new do |rdoc|\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title = \"annotate #{Annotate.version}\"\n  rdoc.rdoc_files.include('README*')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n"
  },
  {
    "path": "vendor/plugins/annotate_models/VERSION.yml",
    "content": "--- \n  :major: 2\n  :minor: 4\n  :patch: 0\n"
  },
  {
    "path": "vendor/plugins/annotate_models/annotate.gemspec",
    "content": "# Generated by jeweler\n# DO NOT EDIT THIS FILE\n# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`\n# -*- encoding: utf-8 -*-\n\nGem::Specification.new do |s|\n  s.name = %q{annotate}\n  s.version = \"2.4.0\"\n\n  s.required_rubygems_version = Gem::Requirement.new(\">= 0\") if s.respond_to? :required_rubygems_version=\n  s.authors = [\"Cuong Tran\", \"Alex Chaffee\", \"Marcos Piccinini\"]\n  s.date = %q{2009-10-23}\n  s.default_executable = %q{annotate}\n  s.description = %q{Annotates Rails Models, routes, fixtures, and others based on the database schema.}\n  s.email = [\"alex@stinky.com\", \"ctran@pragmaquest.com\", \"x@nofxx.com\"]\n  s.executables = [\"annotate\"]\n  s.extra_rdoc_files = [\n    \"README.rdoc\"\n  ]\n  s.files = [\n    \"History.txt\",\n     \"README.rdoc\",\n     \"VERSION.yml\",\n     \"bin/annotate\",\n     \"lib/annotate.rb\",\n     \"lib/annotate/annotate_models.rb\",\n     \"lib/annotate/annotate_routes.rb\",\n     \"lib/tasks/annotate_models.rake\",\n     \"lib/tasks/annotate_routes.rake\",\n     \"spec/annotate/annotate_models_spec.rb\",\n     \"spec/annotate/annotate_routes_spec.rb\",\n     \"spec/annotate_spec.rb\",\n     \"spec/spec.opts\",\n     \"spec/spec_helper.rb\",\n     \"tasks/migrate.rake\"\n  ]\n  s.homepage = %q{http://github.com/ctran/annotate}\n  s.rdoc_options = [\"--charset=UTF-8\"]\n  s.require_paths = [\"lib\"]\n  s.rubygems_version = %q{1.3.5}\n  s.summary = %q{Annotates Rails Models, routes, fixtures, and others based on the database schema.}\n  s.test_files = [\n    \"spec/annotate/annotate_models_spec.rb\",\n     \"spec/annotate/annotate_routes_spec.rb\",\n     \"spec/annotate_spec.rb\",\n     \"spec/spec_helper.rb\"\n  ]\n\n  if s.respond_to? :specification_version then\n    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION\n    s.specification_version = 3\n\n    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then\n    else\n    end\n  else\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/annotate_models/bin/annotate",
    "content": "#!/usr/bin/env ruby\n\nrequire 'optparse'\nrequire 'annotate'\n\ntask = :annotate_models\n\nOptionParser.new do |opts|\n  opts.banner = \"Usage: annotate [options] [model_file]*\"\n\n  opts.on('-d', '--delete', \n  \"Remove annotations from all model files\") do\n    task = :remove_annotation\n  end\n\n  opts.on('-p', '--position [before|after]', ['before', 'after'], \n  \"Place the annotations at the top (before) or the bottom (after) of the model file\") do |p| \n    ENV['position'] = p\n  end\n\n  opts.on('-r', '--routes', \n  \"Annotate routes.rb with the output of 'rake routes'\") do\n    task = :annotate_routes\n  end\n\n  opts.on('-v', '--version', \n  \"Show the current version of this gem\") do \n    puts \"annotate v#{Annotate.version}\"; exit\n  end\n\n  opts.on('-m', '--show-migration', \n  \"Include the migration version number in the annotation\") do\n    ENV['include_version'] = \"yes\"\n  end\n\n  opts.on('-i', '--show-indexes', \n  \"List the table's database indexes in the annotation\") do   \n    ENV['show_indexes'] = \"yes\"\n  end\n\n  opts.on('-s', '--simple-indexes',\n  \"Concat the column's related indexes in the annotation\") do\n    ENV['simple_indexes'] = \"yes\"\n  end\n\n  opts.on('--model-dir dir', \n  \"Annotate model files stored in dir rather than app/models\") do |dir|\n    ENV['model_dir'] = dir\n  end\n\n  opts.on('-R', '--require path',\n  \"Additional files to require before loading models\") do |path|\n    if ENV['require']\n      ENV['require'] = ENV['require'] + \",#{path}\"\n    else\n      ENV['require'] = path\n    end\n  end\n\n  opts.on('-e', '--exclude [tests,fixtures]', Array, \"Do not annotate fixtures, test files, or both\") do |exclusions|\n    exclusions.each { |exclusion| ENV[\"exclude_#{exclusion}\"] = \"yes\" }\n  end\n\nend.parse!\n\nif Annotate.load_tasks\n  Rake::Task[task].invoke\nelse\n  STDERR.puts \"Can't find Rakefile. Are we in a Rails folder?\"\nend\n"
  },
  {
    "path": "vendor/plugins/annotate_models/lib/annotate/annotate_models.rb",
    "content": "module AnnotateModels\n  class << self\n    # Annotate Models plugin use this header\n    COMPAT_PREFIX = \"== Schema Info\"\n    PREFIX = \"== Schema Information\"\n\n    FIXTURE_DIRS = [\"test/fixtures\",\"spec/fixtures\"]\n    # File.join for windows reverse bar compat?\n    # I dont use windows, can`t test\n    UNIT_TEST_DIR     = File.join(\"test\", \"unit\"  )\n    SPEC_MODEL_DIR    = File.join(\"spec\", \"models\")\n    # Object Daddy http://github.com/flogic/object_daddy/tree/master\n    EXEMPLARS_TEST_DIR     = File.join(\"test\", \"exemplars\")\n    EXEMPLARS_SPEC_DIR     = File.join(\"spec\", \"exemplars\")\n    # Machinist http://github.com/notahat/machinist\n    BLUEPRINTS_DIR         = File.join(\"test\", \"blueprints\")\n\n    def model_dir\n      @model_dir || \"app/models\"\n    end\n\n    def model_dir=(dir)\n      @model_dir = dir\n    end\n\n    # Simple quoting for the default column value\n    def quote(value)\n      case value\n        when NilClass                 then \"NULL\"\n        when TrueClass                then \"TRUE\"\n        when FalseClass               then \"FALSE\"\n        when Float, Fixnum, Bignum    then value.to_s\n        # BigDecimals need to be output in a non-normalized form and quoted.\n        when BigDecimal               then value.to_s('F')\n        else\n          value.inspect\n      end\n    end\n\n    # Use the column information in an ActiveRecord class\n    # to create a comment block containing a line for\n    # each column. The line contains the column name,\n    # the type (and length), and any optional attributes\n    def get_schema_info(klass, header, options = {})\n      info = \"# #{header}\\n#\\n\"\n      info << \"# Table name: #{klass.table_name}\\n#\\n\"\n\n      max_size = klass.column_names.collect{|name| name.size}.max + 1\n      klass.columns.each do |col|\n        attrs = []\n        attrs << \"default(#{quote(col.default)})\" unless col.default.nil?\n        attrs << \"not null\" unless col.null\n        attrs << \"primary key\" if col.name == klass.primary_key\n\n        col_type = col.type.to_s\n        if col_type == \"decimal\"\n          col_type << \"(#{col.precision}, #{col.scale})\"\n        else\n          col_type << \"(#{col.limit})\" if col.limit\n        end\n\n        # Check out if we got a geometric column\n        # and print the type and SRID\n        if col.respond_to?(:geometry_type)\n          attrs << \"#{col.geometry_type}, #{col.srid}\"\n        end\n\n        # Check if the column has indices and print \"indexed\" if true\n        # If the indice include another colum, print it too.\n        if options[:simple_indexes] # Check out if this column is indexed\n          indices = klass.connection.indexes(klass.table_name)\n          if indices = indices.select { |ind| ind.columns.include? col.name }\n            indices.each do |ind|\n              ind = ind.columns.reject! { |i| i == col.name }\n              attrs << (ind.length == 0 ? \"indexed\" : \"indexed => [#{ind.join(\", \")}]\")\n            end\n          end\n        end\n\n        info << sprintf(\"#  %-#{max_size}.#{max_size}s:%-15.15s %s\", col.name, col_type, attrs.join(\", \")).rstrip + \"\\n\"\n      end\n\n      if options[:show_indexes]\n        info << get_index_info(klass)\n      end\n\n      info << \"#\\n\\n\"\n    end\n\n    def get_index_info(klass)\n      index_info = \"#\\n# Indexes\\n#\\n\"\n\n      indexes = klass.connection.indexes(klass.table_name)\n      return \"\" if indexes.empty?\n\n      max_size = indexes.collect{|index| index.name.size}.max + 1\n      indexes.each do |index|\n        index_info << sprintf(\"#  %-#{max_size}.#{max_size}s %s %s\", index.name, \"(#{index.columns.join(\",\")})\", index.unique ? \"UNIQUE\" : \"\").rstrip + \"\\n\"\n      end\n      return index_info\n    end\n\n    # Add a schema block to a file. If the file already contains\n    # a schema info block (a comment starting with \"== Schema Information\"), check if it\n    # matches the block that is already there. If so, leave it be. If not, remove the old\n    # info block and write a new one.\n    # Returns true or false depending on whether the file was modified.\n    #\n    # === Options (opts)\n    #  :position<Symbol>:: where to place the annotated section in fixture or model file,\n    #                      \"before\" or \"after\". Default is \"before\".\n    #  :position_in_class<Symbol>:: where to place the annotated section in model file\n    #  :position_in_fixture<Symbol>:: where to place the annotated section in fixture file\n    #  :position_in_others<Symbol>:: where to place the annotated section in the rest of\n    #                      supported files\n    #\n    def annotate_one_file(file_name, info_block, options={})\n      if File.exist?(file_name)\n        old_content = File.read(file_name)\n\n        # Ignore the Schema version line because it changes with each migration\n        header = Regexp.new(/(^# Table name:.*?\\n(#.*\\n)*\\n)/)\n        old_header = old_content.match(header).to_s\n        new_header = info_block.match(header).to_s\n\n        if old_header == new_header\n          false\n        else\n          # Remove old schema info\n          old_content.sub!(/^# #{COMPAT_PREFIX}.*?\\n(#.*\\n)*\\n/, '')\n\n          # Write it back\n          new_content = options[:position] == 'before' ?  (info_block + old_content) : (old_content + \"\\n\" + info_block)\n\n          File.open(file_name, \"wb\") { |f| f.puts new_content }\n          true\n        end\n      end\n    end\n\n    def remove_annotation_of_file(file_name)\n      if File.exist?(file_name)\n        content = File.read(file_name)\n\n        content.sub!(/^# #{COMPAT_PREFIX}.*?\\n(#.*\\n)*\\n/, '')\n\n        File.open(file_name, \"wb\") { |f| f.puts content }\n      end\n    end\n\n    # Given the name of an ActiveRecord class, create a schema\n    # info block (basically a comment containing information\n    # on the columns and their types) and put it at the front\n    # of the model and fixture source files.\n    # Returns true or false depending on whether the source\n    # files were modified.\n    def annotate(klass, file, header,options={})\n      info = get_schema_info(klass, header, options)\n      annotated = false\n      model_name = klass.name.underscore\n      model_file_name = File.join(model_dir, file)\n\n      if annotate_one_file(model_file_name, info, options_with_position(options, :position_in_class))\n        annotated = true\n      end\n \n      unless ENV['exclude_tests']\n        [\n          File.join(UNIT_TEST_DIR,      \"#{model_name}_test.rb\"), # test\n          File.join(SPEC_MODEL_DIR,     \"#{model_name}_spec.rb\"), # spec\n        ].each do |file| \n          # todo: add an option \"position_in_test\" -- or maybe just ask if anyone ever wants different positions for model vs. test vs. fixture\n          annotate_one_file(file, info, options_with_position(options, :position_in_fixture))\n        end\n      end\n\n      unless ENV['exclude_fixtures']\n        [\n        File.join(EXEMPLARS_TEST_DIR, \"#{model_name}_exemplar.rb\"),  # Object Daddy\n        File.join(EXEMPLARS_SPEC_DIR, \"#{model_name}_exemplar.rb\"),  # Object Daddy\n        File.join(BLUEPRINTS_DIR,     \"#{model_name}_blueprint.rb\"), # Machinist Blueprints\n        ].each do |file| \n          annotate_one_file(file, info, options_with_position(options, :position_in_fixture))\n        end\n\n        FIXTURE_DIRS.each do |dir|\n          fixture_file_name = File.join(dir,klass.table_name + \".yml\")\n          if File.exist?(fixture_file_name)\n            annotate_one_file(fixture_file_name, info, options_with_position(options, :position_in_fixture))         \n          end\n        end\n      end\n      \n      annotated\n    end\n    \n    # position = :position_in_fixture or :position_in_class\n    def options_with_position(options, position_in)\n      options.merge(:position=>(options[position_in] || options[:position]))\n    end\n\n    # Return a list of the model files to annotate. If we have\n    # command line arguments, they're assumed to be either\n    # the underscore or CamelCase versions of model names.\n    # Otherwise we take all the model files in the\n    # model_dir directory.\n    def get_model_files\n      models = ARGV.dup\n      models.shift\n      models.reject!{|m| m.match(/^(.*)=/)}\n      if models.empty?\n        begin\n          Dir.chdir(model_dir) do\n            models = Dir[\"**/*.rb\"]\n          end\n        rescue SystemCallError\n          puts \"No models found in directory '#{model_dir}'.\"\n          puts \"Either specify models on the command line, or use the --model-dir option.\"\n          puts \"Call 'annotate --help' for more info.\"\n          exit 1;\n        end\n      end\n      models\n    end\n\n    # Retrieve the classes belonging to the model names we're asked to process\n    # Check for namespaced models in subdirectories as well as models\n    # in subdirectories without namespacing.\n    def get_model_class(file)\n      require File.expand_path(\"#{model_dir}/#{file}\") # this is for non-rails projects, which don't get Rails auto-require magic\n      model = file.gsub(/\\.rb$/, '').camelize\n      parts = model.split('::')\n      begin\n        parts.inject(Object) {|klass, part| klass.const_get(part) }\n      rescue LoadError, NameError\n        Object.const_get(parts.last)\n      end\n    end\n\n    # We're passed a name of things that might be\n    # ActiveRecord models. If we can find the class, and\n    # if its a subclass of ActiveRecord::Base,\n    # then pass it to the associated block\n    def do_annotations(options={})\n      if options[:require]\n        options[:require].each do |path|\n          require path\n        end\n      end\n\n      header = PREFIX.dup\n\n      if options[:include_version]\n        version = ActiveRecord::Migrator.current_version rescue 0\n        if version > 0\n          header << \"\\n# Schema version: #{version}\"\n        end\n      end\n\n      if options[:model_dir]\n        self.model_dir = options[:model_dir]\n      end\n\n      annotated = []\n      get_model_files.each do |file|\n        begin\n          klass = get_model_class(file)\n          if klass < ActiveRecord::Base && !klass.abstract_class?\n            if annotate(klass, file, header, options)\n              annotated << klass\n            end\n          end\n        rescue Exception => e\n          puts \"Unable to annotate #{file}: #{e.inspect}\"\n          puts \"\"\n# todo: check if all backtrace lines are in \"gems\" -- if so, it's an annotate bug, so print the whole stack trace.\n#          puts e.backtrace.join(\"\\n\\t\")  \n        end\n      end\n      if annotated.empty?\n        puts \"Nothing annotated.\"\n      else\n        puts \"Annotated (#{annotated.length}): #{annotated.join(', ')}\"\n      end\n    end\n\n    def remove_annotations(options={})\n      if options[:model_dir]\n        puts \"removing\"\n        self.model_dir = options[:model_dir]\n      end\n      deannotated = []\n      get_model_files.each do |file|\n        begin\n          klass = get_model_class(file)\n          if klass < ActiveRecord::Base && !klass.abstract_class?\n            deannotated << klass\n\n            model_file_name = File.join(model_dir, file)\n            remove_annotation_of_file(model_file_name)\n\n            FIXTURE_DIRS.each do |dir|\n              fixture_file_name = File.join(dir,klass.table_name + \".yml\")\n              remove_annotation_of_file(fixture_file_name) if File.exist?(fixture_file_name)\n            end\n            \n            [ File.join(UNIT_TEST_DIR, \"#{klass.name.underscore}_test.rb\"),\n              File.join(SPEC_MODEL_DIR,\"#{klass.name.underscore}_spec.rb\")].each do |file|\n              remove_annotation_of_file(file) if File.exist?(file)\n            end\n            \n          end\n        rescue Exception => e\n          puts \"Unable to annotate #{file}: #{e.message}\"\n        end\n      end\n      puts \"Removed annotation from: #{deannotated.join(', ')}\"\n    end\n  end\nend\n\n# monkey patches\n\nmodule ::ActiveRecord\n  class Base\n    def self.method_missing(name, *args)\n      # ignore this, so unknown/unloaded macros won't cause parsing to fail\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/annotate_models/lib/annotate/annotate_routes.rb",
    "content": "# == Annotate Routes\n# \n# Based on:\n# \n# \n#\n# Prepends the output of \"rake routes\" to the top of your routes.rb file.\n# Yes, it's simple but I'm thick and often need a reminder of what my routes mean.\n# \n# Running this task will replace any exising route comment generated by the task.\n# Best to back up your routes file before running:\n# \n# Author:\n#  Gavin Montague\n#  gavin@leftbrained.co.uk\n#   \n# Released under the same license as Ruby. No Support. No Warranty.module AnnotateRoutes\n#\nmodule AnnotateRoutes \n  PREFIX = \"#== Route Map\"\n  \n  def self.do_annotate \n    routes_rb = File.join(\"config\", \"routes.rb\")\n    header = PREFIX + \"\\n# Generated on #{Time.now.strftime(\"%d %b %Y %H:%M\")}\\n#\"\n    if File.exists? routes_rb\n      routes_map = `rake routes`\n      routes_map = routes_map.split(\"\\n\")\n      routes_map.shift # remove the first line of rake routes which is just a file path\n      routes_map = routes_map.inject(header){|sum, line| sum<<\"\\n# \"<<line}\n      content = File.read(routes_rb)\n      content, old = content.split(/^#== Route .*?\\n/)\n      File.open(routes_rb, \"wb\") do |f| \n        f.puts content.sub!(/\\n?\\z/, \"\\n\") + routes_map \n      end\n      puts \"Route file annotated.\"\n    else\n      puts \"Can`t find routes.rb\"\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/annotate_models/lib/annotate/tasks/migrate.rake",
    "content": "# These tasks are added to the project if you install annotate as a Rails plugin.\n# (They are not used to build annotate itself.)\n\n# Append annotations to Rake tasks for ActiveRecord, so annotate automatically gets\n# run after doing db:migrate. \n# Unfortunately it relies on ENV for options; it'd be nice to be able to set options\n# in a per-project config file so this task can read them.\nnamespace :db do\n  task :migrate do\n    Annotate::Migration.update_annotations\n  end\n\n  namespace :migrate do\n    [:up, :down, :reset, :redo].each do |t|\n      task t do\n        Annotate::Migration.update_annotations\n      end\n    end\n  end\nend\n\nmodule Annotate\n  class Migration\n    @@working = false\n\n    def self.update_annotations\n      unless @@working\n        @@working = true\n        Rake::Task['annotate_models'].invoke\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/annotate_models/lib/annotate/tasks/migrate.rake~HEAD",
    "content": "# These tasks are added to the project if you install annotate as a Rails plugin.\n# (They are not used to build annotate itself.)\n\n# Append annotations to Rake tasks for ActiveRecord, so annotate automatically gets\n# run after doing db:migrate. \n# Unfortunately it relies on ENV for options; it'd be nice to be able to set options\n# in a per-project config file so this task can read them.\nnamespace :db do\n  task :migrate do\n    Annotate::Migration.update_annotations\n  end\n\n  namespace :migrate do\n    [:up, :down, :reset, :redo].each do |t|\n      task t do\n        Annotate::Migration.update_annotations\n      end\n    end\n  end\nend\n\nmodule Annotate\n  class Migration\n    @@working = false\n\n    def self.update_annotations\n      unless @@working\n        @@working = true\n        Rake::Task['annotate_models'].invoke\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/annotate_models/lib/annotate.rb",
    "content": "$:.unshift(File.dirname(__FILE__)) unless\n  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))\n\nmodule Annotate\n  def self.version\n    version_file = File.dirname(__FILE__) + \"/../VERSION.yml\"\n    if File.exist?(version_file)\n      config = YAML.load(File.read(version_file))\n      version = \"#{config[:major]}.#{config[:minor]}.#{config[:patch]}\"\n    else\n      version = \"0.0.0\"\n    end\n  end\n  \n  def self.load_tasks\n    if File.exists?('Rakefile')\n      load 'Rakefile'\n      Dir[File.join(File.dirname(__FILE__), 'tasks', '**/*.rake')].each { |rake| load rake }\n      return true\n    else\n      return false\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/annotate_models/spec/annotate/annotate_models_spec.rb",
    "content": "require File.dirname(__FILE__) + '/../spec_helper.rb'\nrequire 'annotate/annotate_models'\nrequire 'rubygems'\nrequire 'activesupport'\n\ndescribe AnnotateModels do\n\n  def mock_klass(stubs={})\n    @mock_file ||= mock(\"Klass\", stubs)\n  end\n\n  def mock_column(stubs={})\n    @mock_column ||= mock(\"Column\", stubs)\n  end\n\n  it { AnnotateModels.quote(nil).should eql(\"NULL\") }\n  it { AnnotateModels.quote(true).should eql(\"TRUE\") }\n  it { AnnotateModels.quote(false).should eql(\"FALSE\") }\n  it { AnnotateModels.quote(25).should eql(\"25\") }\n  it { AnnotateModels.quote(25.6).should eql(\"25.6\") }\n  it { AnnotateModels.quote(1e-20).should eql(\"1.0e-20\") }\n\n  it \"should get schema info\" do\n\n    AnnotateModels.get_schema_info(mock_klass(\n      :connection => mock(\"Conn\", :indexes => []),\n      :table_name => \"users\",\n      :primary_key => \"id\",\n      :column_names => [\"id\",\"login\"],\n      :columns => [\n        mock_column(:type => \"integer\", :default => nil, :null => false, :name => \"id\", :limit => nil),\n        mock_column(:type => \"string\", :default => nil, :null => false, :name => \"name\", :limit => 50)\n      ]), \"Schema Info\").should eql(<<-EOS)\n# Schema Info\n#\n# Table name: users\n#\n#  id    :integer         not null, primary key\n#  id    :integer         not null, primary key\n#\n\nEOS\n\n  end\n\n  describe \"#get_model_class\" do\n    module ::ActiveRecord\n      class Base\n      end\n    end\n\n    def create(file, body=\"hi\")\n      File.open(@dir + '/' + file, \"w\") do |f|\n        f.puts(body)\n      end\n    end\n\n    before :all do\n      require \"tmpdir\"\n      @dir = Dir.tmpdir + \"/#{Time.now.to_i}\" + \"/annotate_models\"\n      FileUtils.mkdir_p(@dir)\n      AnnotateModels.model_dir = @dir\n      create('foo.rb', <<-EOS)\n        class Foo < ActiveRecord::Base\n        end\n      EOS\n      create('foo_with_macro.rb', <<-EOS)\n        class FooWithMacro < ActiveRecord::Base\n          acts_as_awesome :yah\n        end\n      EOS\n    end\n    it \"should work\" do\n      klass = AnnotateModels.get_model_class(\"foo.rb\")\n      klass.name.should == \"Foo\"\n    end\n    it \"should not care about unknown macros\" do\n      klass = AnnotateModels.get_model_class(\"foo_with_macro.rb\")\n      klass.name.should == \"FooWithMacro\"\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/annotate_models/spec/annotate/annotate_routes_spec.rb",
    "content": "require File.dirname(__FILE__) + '/../spec_helper.rb'\nrequire 'annotate/annotate_routes'\n\ndescribe AnnotateRoutes do\n\n  def mock_file(stubs={})\n    @mock_file ||= mock(File, stubs)\n  end\n\n  describe \"Annotate Job\" do\n\n    before(:each) do\n      File.should_receive(:join).with(\"config\", \"routes.rb\").and_return(\"config/routes.rb\")\n    end\n\n    it \"should check if routes.rb exists\" do\n      File.should_receive(:exists?).with(\"config/routes.rb\").and_return(false)\n      AnnotateRoutes.should_receive(:puts).with(\"Can`t find routes.rb\")\n      AnnotateRoutes.do_annotate\n    end\n\n    describe \"When Annotating\" do\n\n      before(:each) do\n        File.should_receive(:exists?).with(\"config/routes.rb\").and_return(true)\n        AnnotateRoutes.should_receive(:`).with(\"rake routes\").and_return(\"bad line\\ngood line\")\n        File.should_receive(:open).with(\"config/routes.rb\", \"wb\").and_yield(mock_file)\n        AnnotateRoutes.should_receive(:puts).with(\"Route file annotated.\")\n      end\n\n      it \"should annotate and add a newline!\" do\n        File.should_receive(:read).with(\"config/routes.rb\").and_return(\"ActionController::Routing...\\nfoo\")\n        @mock_file.should_receive(:puts).with(/ActionController::Routing...\\nfoo\\n#== Route Map\\n# Generated on .*\\n#\\n# good line/)\n        AnnotateRoutes.do_annotate\n      end\n\n      it \"should not add a newline if there are empty lines\" do\n        File.should_receive(:read).with(\"config/routes.rb\").and_return(\"ActionController::Routing...\\nfoo\\n\")\n        @mock_file.should_receive(:puts).with(/ActionController::Routing...\\nfoo\\n#== Route Map\\n# Generated on .*\\n#\\n# good line/)\n        AnnotateRoutes.do_annotate\n      end\n\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/annotate_models/spec/annotate_spec.rb",
    "content": "require File.dirname(__FILE__) + '/spec_helper.rb'\n\ndescribe Annotate do\n\n  it \"should have a version\" do\n    Annotate.version.should be_instance_of(String)\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/annotate_models/spec/spec.opts",
    "content": "--colour"
  },
  {
    "path": "vendor/plugins/annotate_models/spec/spec_helper.rb",
    "content": "begin\n  require 'spec'\nrescue LoadError\n  require 'rubygems'\n  gem 'rspec'\n  require 'spec'\nend\n\n$:.unshift(File.dirname(__FILE__) + '/../lib')\nrequire 'annotate'\n"
  },
  {
    "path": "vendor/plugins/annotate_models/todo.txt",
    "content": "TODO\n-----\nchange default position back to \"top\" for all\nadd \"top\" and \"bottom\" as synonyms for \"before\" and \"after\"\nchange 'exclude' to 'only' (double negatives are not unconfusing)\n"
  },
  {
    "path": "vendor/plugins/auto_complete/README",
    "content": "Example:\n\n  # Controller\n  class BlogController < ApplicationController\n    auto_complete_for :post, :title\n  end\n\n  # View\n  <%= text_field_with_auto_complete :post, title %>\n\nBy default, auto_complete_for limits the results to 10 entries,\nand sorts by the given field.\n\nauto_complete_for takes a third parameter, an options hash to\nthe find method used to search for the records:\n\n  auto_complete_for :post, :title, :limit => 15, :order => 'created_at DESC'\n\nFor more examples, see script.aculo.us:\n* http://script.aculo.us/demos/ajax/autocompleter\n* http://script.aculo.us/demos/ajax/autocompleter_customized\n\nCopyright (c) 2007 David Heinemeier Hansson, released under the MIT license   \n"
  },
  {
    "path": "vendor/plugins/auto_complete/Rakefile",
    "content": "require 'rake' \nrequire 'rake/testtask' \nrequire 'rake/rdoctask' \n \ndesc 'Default: run unit tests.' \ntask :default => :test \n \ndesc 'Test auto_complete plugin.' \nRake::TestTask.new(:test) do |t| \n  t.libs << 'lib' \n  t.pattern = 'test/**/*_test.rb' \n  t.verbose = true \nend \n \ndesc 'Generate documentation for auto_complete plugin.' \nRake::RDocTask.new(:rdoc) do |rdoc| \n  rdoc.rdoc_dir = 'rdoc' \n  rdoc.title    = 'Auto Complete' \n  rdoc.options << '--line-numbers' << '--inline-source' \n  rdoc.rdoc_files.include('README') \n  rdoc.rdoc_files.include('lib/**/*.rb') \nend\n"
  },
  {
    "path": "vendor/plugins/auto_complete/init.rb",
    "content": "ActionController::Base.send :include, AutoComplete\nActionController::Base.helper AutoCompleteMacrosHelper"
  },
  {
    "path": "vendor/plugins/auto_complete/lib/auto_complete.rb",
    "content": "module AutoComplete      \n  \n  def self.included(base)\n    base.extend(ClassMethods)\n  end\n\n  #\n  # Example:\n  #\n  #   # Controller\n  #   class BlogController < ApplicationController\n  #     auto_complete_for :post, :title\n  #   end\n  #\n  #   # View\n  #   <%= text_field_with_auto_complete :post, title %>\n  #\n  # By default, auto_complete_for limits the results to 10 entries,\n  # and sorts by the given field.\n  # \n  # auto_complete_for takes a third parameter, an options hash to\n  # the find method used to search for the records:\n  #\n  #   auto_complete_for :post, :title, :limit => 15, :order => 'created_at DESC'\n  #\n  # For help on defining text input fields with autocompletion, \n  # see ActionView::Helpers::JavaScriptHelper.\n  #\n  # For more examples, see script.aculo.us:\n  # * http://script.aculo.us/demos/ajax/autocompleter\n  # * http://script.aculo.us/demos/ajax/autocompleter_customized\n  module ClassMethods\n    def auto_complete_for(object, method, options = {})\n      define_method(\"auto_complete_for_#{object}_#{method}\") do\n        find_options = { \n          :conditions => [ \"LOWER(#{method}) LIKE ?\", '%' + params[object][method].downcase + '%' ], \n          :order => \"#{method} ASC\",\n          :limit => 10 }.merge!(options)\n        \n        @items = object.to_s.camelize.constantize.find(:all, find_options)\n\n        render :inline => \"<%= auto_complete_result @items, '#{method}' %>\"\n      end\n    end\n  end\n  \nend"
  },
  {
    "path": "vendor/plugins/auto_complete/lib/auto_complete_macros_helper.rb",
    "content": "module AutoCompleteMacrosHelper      \n  # Adds AJAX autocomplete functionality to the text input field with the \n  # DOM ID specified by +field_id+.\n  #\n  # This function expects that the called action returns an HTML <ul> list,\n  # or nothing if no entries should be displayed for autocompletion.\n  #\n  # You'll probably want to turn the browser's built-in autocompletion off,\n  # so be sure to include an <tt>autocomplete=\"off\"</tt> attribute with your text\n  # input field.\n  #\n  # The autocompleter object is assigned to a Javascript variable named <tt>field_id</tt>_auto_completer.\n  # This object is useful if you for example want to trigger the auto-complete suggestions through\n  # other means than user input (for that specific case, call the <tt>activate</tt> method on that object). \n  # \n  # Required +options+ are:\n  # <tt>:url</tt>::                  URL to call for autocompletion results\n  #                                  in url_for format.\n  # \n  # Addtional +options+ are:\n  # <tt>:update</tt>::               Specifies the DOM ID of the element whose \n  #                                  innerHTML should be updated with the autocomplete\n  #                                  entries returned by the AJAX request. \n  #                                  Defaults to <tt>field_id</tt> + '_auto_complete'\n  # <tt>:with</tt>::                 A JavaScript expression specifying the\n  #                                  parameters for the XMLHttpRequest. This defaults\n  #                                  to 'fieldname=value'.\n  # <tt>:frequency</tt>::            Determines the time to wait after the last keystroke\n  #                                  for the AJAX request to be initiated.\n  # <tt>:indicator</tt>::            Specifies the DOM ID of an element which will be\n  #                                  displayed while autocomplete is running.\n  # <tt>:tokens</tt>::               A string or an array of strings containing\n  #                                  separator tokens for tokenized incremental \n  #                                  autocompletion. Example: <tt>:tokens => ','</tt> would\n  #                                  allow multiple autocompletion entries, separated\n  #                                  by commas.\n  # <tt>:min_chars</tt>::            The minimum number of characters that should be\n  #                                  in the input field before an Ajax call is made\n  #                                  to the server.\n  # <tt>:on_hide</tt>::              A Javascript expression that is called when the\n  #                                  autocompletion div is hidden. The expression\n  #                                  should take two variables: element and update.\n  #                                  Element is a DOM element for the field, update\n  #                                  is a DOM element for the div from which the\n  #                                  innerHTML is replaced.\n  # <tt>:on_show</tt>::              Like on_hide, only now the expression is called\n  #                                  then the div is shown.\n  # <tt>:after_update_element</tt>:: A Javascript expression that is called when the\n  #                                  user has selected one of the proposed values. \n  #                                  The expression should take two variables: element and value.\n  #                                  Element is a DOM element for the field, value\n  #                                  is the value selected by the user.\n  # <tt>:select</tt>::               Pick the class of the element from which the value for \n  #                                  insertion should be extracted. If this is not specified,\n  #                                  the entire element is used.\n  # <tt>:method</tt>::               Specifies the HTTP verb to use when the autocompletion\n  #                                  request is made. Defaults to POST.\n  def auto_complete_field(field_id, options = {})\n    function =  \"var #{field_id}_auto_completer = new Ajax.Autocompleter(\"\n    function << \"'#{field_id}', \"\n    function << \"'\" + (options[:update] || \"#{field_id}_auto_complete\") + \"', \"\n    function << \"'#{url_for(options[:url])}'\"\n    \n    js_options = {}\n    js_options[:tokens] = array_or_string_for_javascript(options[:tokens]) if options[:tokens]\n    js_options[:callback]   = \"function(element, value) { return #{options[:with]} }\" if options[:with]\n    js_options[:indicator]  = \"'#{options[:indicator]}'\" if options[:indicator]\n    js_options[:select]     = \"'#{options[:select]}'\" if options[:select]\n    js_options[:paramName]  = \"'#{options[:param_name]}'\" if options[:param_name]\n    js_options[:frequency]  = \"#{options[:frequency]}\" if options[:frequency]\n    js_options[:method]     = \"'#{options[:method].to_s}'\" if options[:method]\n\n    { :after_update_element => :afterUpdateElement, \n      :on_show => :onShow, :on_hide => :onHide, :min_chars => :minChars }.each do |k,v|\n      js_options[v] = options[k] if options[k]\n    end\n\n    function << (', ' + options_for_javascript(js_options) + ')')\n\n    javascript_tag(function)\n  end\n  \n  # Use this method in your view to generate a return for the AJAX autocomplete requests.\n  #\n  # Example action:\n  #\n  #   def auto_complete_for_item_title\n  #     @items = Item.find(:all, \n  #       :conditions => [ 'LOWER(description) LIKE ?', \n  #       '%' + request.raw_post.downcase + '%' ])\n  #     render :inline => \"<%= auto_complete_result(@items, 'description') %>\"\n  #   end\n  #\n  # The auto_complete_result can of course also be called from a view belonging to the \n  # auto_complete action if you need to decorate it further.\n  def auto_complete_result(entries, field, phrase = nil)\n    return unless entries\n    items = entries.map { |entry| content_tag(\"li\", phrase ? highlight(entry[field], phrase) : h(entry[field])) }\n    content_tag(\"ul\", items.uniq)\n  end\n  \n  # Wrapper for text_field with added AJAX autocompletion functionality.\n  #\n  # In your controller, you'll need to define an action called\n  # auto_complete_for to respond the AJAX calls,\n  # \n  def text_field_with_auto_complete(object, method, tag_options = {}, completion_options = {})\n    (completion_options[:skip_style] ? \"\" : auto_complete_stylesheet) +\n    text_field(object, method, tag_options) +\n    content_tag(\"div\", \"\", :id => \"#{object}_#{method}_auto_complete\", :class => \"auto_complete\") +\n    auto_complete_field(\"#{object}_#{method}\", { :url => { :action => \"auto_complete_for_#{object}_#{method}\" } }.update(completion_options))\n  end\n\n  private\n    def auto_complete_stylesheet\n      content_tag('style', <<-EOT, :type => Mime::CSS)\n        div.auto_complete {\n          width: 350px;\n          background: #fff;\n        }\n        div.auto_complete ul {\n          border:1px solid #888;\n          margin:0;\n          padding:0;\n          width:100%;\n          list-style-type:none;\n        }\n        div.auto_complete ul li {\n          margin:0;\n          padding:3px;\n        }\n        div.auto_complete ul li.selected {\n          background-color: #ffb;\n        }\n        div.auto_complete ul strong.highlight {\n          color: #800; \n          margin:0;\n          padding:0;\n        }\n      EOT\n    end\n\nend   \n"
  },
  {
    "path": "vendor/plugins/auto_complete/test/auto_complete_test.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '../../../../test/test_helper')) \n\nclass AutoCompleteTest < Test::Unit::TestCase\n  include AutoComplete\n  include AutoCompleteMacrosHelper\n  \n  include ActionView::Helpers::UrlHelper\n  include ActionView::Helpers::TagHelper\n  include ActionView::Helpers::TextHelper\n  include ActionView::Helpers::FormHelper\n  include ActionView::Helpers::CaptureHelper\n  \n  def setup\n    @controller = Class.new do\n      def url_for(options)\n        url =  \"http://www.example.com/\"\n        url << options[:action].to_s if options and options[:action]\n        url\n      end\n    end\n    @controller = @controller.new\n  end\n\n\n  def test_auto_complete_field\n    assert_dom_equal %(<script type=\\\"text/javascript\\\">\\n//<![CDATA[\\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {})\\n//]]>\\n</script>),\n      auto_complete_field(\"some_input\", :url => { :action => \"autocomplete\" });\n    assert_dom_equal %(<script type=\\\"text/javascript\\\">\\n//<![CDATA[\\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {tokens:','})\\n//]]>\\n</script>),\n      auto_complete_field(\"some_input\", :url => { :action => \"autocomplete\" }, :tokens => ',');\n    assert_dom_equal %(<script type=\\\"text/javascript\\\">\\n//<![CDATA[\\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {tokens:[',']})\\n//]]>\\n</script>),\n      auto_complete_field(\"some_input\", :url => { :action => \"autocomplete\" }, :tokens => [',']);  \n    assert_dom_equal %(<script type=\\\"text/javascript\\\">\\n//<![CDATA[\\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {minChars:3})\\n//]]>\\n</script>),\n      auto_complete_field(\"some_input\", :url => { :action => \"autocomplete\" }, :min_chars => 3);\n    assert_dom_equal %(<script type=\\\"text/javascript\\\">\\n//<![CDATA[\\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {onHide:function(element, update){alert('me');}})\\n//]]>\\n</script>),\n      auto_complete_field(\"some_input\", :url => { :action => \"autocomplete\" }, :on_hide => \"function(element, update){alert('me');}\");\n    assert_dom_equal %(<script type=\\\"text/javascript\\\">\\n//<![CDATA[\\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {frequency:2})\\n//]]>\\n</script>),\n      auto_complete_field(\"some_input\", :url => { :action => \"autocomplete\" }, :frequency => 2);\n    assert_dom_equal %(<script type=\\\"text/javascript\\\">\\n//<![CDATA[\\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {afterUpdateElement:function(element,value){alert('You have chosen: '+value)}})\\n//]]>\\n</script>),\n      auto_complete_field(\"some_input\", :url => { :action => \"autocomplete\" }, \n        :after_update_element => \"function(element,value){alert('You have chosen: '+value)}\");\n    assert_dom_equal %(<script type=\\\"text/javascript\\\">\\n//<![CDATA[\\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {paramName:'huidriwusch'})\\n//]]>\\n</script>),\n      auto_complete_field(\"some_input\", :url => { :action => \"autocomplete\" }, :param_name => 'huidriwusch');\n    assert_dom_equal %(<script type=\\\"text/javascript\\\">\\n//<![CDATA[\\nvar some_input_auto_completer = new Ajax.Autocompleter('some_input', 'some_input_auto_complete', 'http://www.example.com/autocomplete', {method:'get'})\\n//]]>\\n</script>),\n      auto_complete_field(\"some_input\", :url => { :action => \"autocomplete\" }, :method => :get);\n  end\n  \n  def test_auto_complete_result\n    result = [ { :title => 'test1'  }, { :title => 'test2'  } ]\n    assert_equal %(<ul><li>test1</li><li>test2</li></ul>), \n      auto_complete_result(result, :title)\n    assert_equal %(<ul><li>t<strong class=\\\"highlight\\\">est</strong>1</li><li>t<strong class=\\\"highlight\\\">est</strong>2</li></ul>), \n      auto_complete_result(result, :title, \"est\")\n    \n    resultuniq = [ { :title => 'test1'  }, { :title => 'test1'  } ]\n    assert_equal %(<ul><li>t<strong class=\\\"highlight\\\">est</strong>1</li></ul>), \n      auto_complete_result(resultuniq, :title, \"est\")\n  end\n  \n  def test_text_field_with_auto_complete\n    assert_match %(<style type=\"text/css\">),\n      text_field_with_auto_complete(:message, :recipient)\n\n    assert_dom_equal %(<input id=\\\"message_recipient\\\" name=\\\"message[recipient]\\\" size=\\\"30\\\" type=\\\"text\\\" /><div class=\\\"auto_complete\\\" id=\\\"message_recipient_auto_complete\\\"></div><script type=\\\"text/javascript\\\">\\n//<![CDATA[\\nvar message_recipient_auto_completer = new Ajax.Autocompleter('message_recipient', 'message_recipient_auto_complete', 'http://www.example.com/auto_complete_for_message_recipient', {})\\n//]]>\\n</script>),\n      text_field_with_auto_complete(:message, :recipient, {}, :skip_style => true)\n  end\n  \nend\n"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/MIT-LICENSE",
    "content": "Copyright (c) 2007 [name of plugin creator]\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/README.rdoc",
    "content": "= AwesomeNestedSet\n\nAwesome Nested Set is an implementation of the nested set pattern for ActiveRecord models. It is replacement for acts_as_nested_set and BetterNestedSet, but awesomer.\n\n== What makes this so awesome?\n\nThis is a new implementation of nested set based off of BetterNestedSet that fixes some bugs, removes tons of duplication, adds a few useful methods, and adds STI support.\n\n== Installation\n\nIf you are on Rails 2.1 or later:\n\n  script/plugin install git://github.com/collectiveidea/awesome_nested_set.git\n  \n== Usage\n\nTo make use of awesome_nested_set, your model needs to have 3 fields: lft, rgt, and parent_id:\n\n  class CreateCategories < ActiveRecord::Migration\n    def self.up\n      create_table :categories do |t|\n        t.string :name\n        t.integer :parent_id\n        t.integer :lft\n        t.integer :rgt\n      end\n    end\n\n    def self.down\n      drop_table :categories\n    end\n  end\n\nEnable the nested set functionality by declaring acts_as_nested_set on your model\n\n  class Category < ActiveRecord::Base\n    acts_as_nested_set\n  end\n  \nRun `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet::SingletonMethods for more info.\n\n== View Helper\n\nThe view helper is called #nested_set_options. \n\nExample usage:\n\n  <%= f.select :parent_id, nested_set_options(Category, @category) {|i| \"#{'-' * i.level} #{i.name}\" } %>\n\n  <%= select_tag 'parent_id', options_for_select(nested_set_options(Category) {|i| \"#{'-' * i.level} #{i.name}\" } ) %>\n\nSee CollectiveIdea::Acts::NestedSet::Helper for more information about the helpers.\n\n== References\n\nYou can learn more about nested sets at:\n\n  http://www.dbmsmag.com/9603d06.html\n  http://threebit.net/tutorials/nestedset/tutorial1.html\n  http://api.rubyonrails.com/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html\n  http://opensource.symetrie.com/trac/better_nested_set/\n\n\nCopyright (c) 2008 Collective Idea, released under the MIT license"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/Rakefile",
    "content": "require 'rake'\nrequire 'rake/testtask'\nrequire 'rake/rdoctask'\nrequire 'rake/gempackagetask'\nrequire 'rcov/rcovtask'\nrequire \"load_multi_rails_rake_tasks\" \n\nspec = eval(File.read(\"#{File.dirname(__FILE__)}/awesome_nested_set.gemspec\"))\nPKG_NAME = spec.name\nPKG_VERSION = spec.version\n \nRake::GemPackageTask.new(spec) do |pkg|\n  pkg.need_zip = true\n  pkg.need_tar = true\nend\n\n\ndesc 'Default: run unit tests.'\ntask :default => :test\n\ndesc 'Test the awesome_nested_set plugin.'\nRake::TestTask.new(:test) do |t|\n  t.libs << 'lib'\n  t.pattern = 'test/**/*_test.rb'\n  t.verbose = true\nend\n\ndesc 'Generate documentation for the awesome_nested_set plugin.'\nRake::RDocTask.new(:rdoc) do |rdoc|\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title    = 'AwesomeNestedSet'\n  rdoc.options << '--line-numbers' << '--inline-source'\n  rdoc.rdoc_files.include('README.rdoc')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n\nnamespace :test do\n  desc \"just rcov minus html output\"\n  Rcov::RcovTask.new(:coverage) do |t|\n    # t.libs << 'test'\n    t.test_files = FileList['test/**/*_test.rb']\n    t.output_dir = 'coverage'\n    t.verbose = true\n    t.rcov_opts = %w(--exclude test,/usr/lib/ruby,/Library/Ruby,lib/awesome_nested_set/named_scope.rb --sort coverage)\n  end\nend"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec",
    "content": "Gem::Specification.new do |s|\n  s.name = \"awesome_nested_set\"\n  s.version = \"1.1.1\"\n  s.summary = \"An awesome replacement for acts_as_nested_set and better_nested_set.\"\n  s.description = s.summary\n \n  s.files = %w(init.rb MIT-LICENSE Rakefile README.rdoc lib/awesome_nested_set.rb lib/awesome_nested_set/compatability.rb lib/awesome_nested_set/helper.rb lib/awesome_nested_set/named_scope.rb rails/init.rb test/awesome_nested_set_test.rb test/test_helper.rb test/awesome_nested_set/helper_test.rb test/db/database.yml test/db/schema.rb test/fixtures/categories.yml test/fixtures/category.rb test/fixtures/departments.yml test/fixtures/notes.yml)\n \n  s.add_dependency \"activerecord\", ['>= 1.1']\n \n  s.has_rdoc = true\n  s.extra_rdoc_files = [ \"README.rdoc\"]\n  s.rdoc_options = [\"--main\", \"README.rdoc\", \"--inline-source\", \"--line-numbers\"]\n \n  s.test_files = %w(test/awesome_nested_set_test.rb test/test_helper.rb test/awesome_nested_set/helper_test.rb test/db/database.yml test/db/schema.rb test/fixtures/categories.yml test/fixtures/category.rb test/fixtures/departments.yml test/fixtures/notes.yml)\n  s.require_path = 'lib'\n  s.author = \"Collective Idea\"\n  s.email = \"info@collectiveidea.com\"\n  s.homepage = \"http://collectiveidea.com\"\nend\n"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/init.rb",
    "content": "require File.dirname(__FILE__) + \"/rails/init\"  \n"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/lib/awesome_nested_set/compatability.rb",
    "content": "# Rails <2.x doesn't define #except\nclass Hash #:nodoc:\n  # Returns a new hash without the given keys.\n  def except(*keys)\n    clone.except!(*keys)\n  end unless method_defined?(:except)\n\n  # Replaces the hash without the given keys.\n  def except!(*keys)\n    keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)\n    keys.each { |key| delete(key) }\n    self\n  end unless method_defined?(:except!)\nend\n\n# NamedScope is new to Rails 2.1\nunless defined? ActiveRecord::NamedScope\n  require 'awesome_nested_set/named_scope'\n  ActiveRecord::Base.class_eval do\n    include CollectiveIdea::NamedScope\n  end\nend\n\n# Rails 1.2.x doesn't define #quoted_table_name\nclass ActiveRecord::Base  #:nodoc:\n  def self.quoted_table_name\n    self.connection.quote_column_name(self.table_name)\n  end unless methods.include?('quoted_table_name')\nend"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb",
    "content": "module CollectiveIdea #:nodoc:\n  module Acts #:nodoc:\n    module NestedSet #:nodoc:\n      # This module provides some helpers for the model classes using acts_as_nested_set.\n      # It is included by default in all views.\n      #\n      module Helper\n        # Returns options for select.\n        # You can exclude some items from the tree.\n        # You can pass a block receiving an item and returning the string displayed in the select.\n        #\n        # == Params\n        #  * +class_or_item+ - Class name or top level times\n        #  * +mover+ - The item that is being move, used to exlude impossible moves\n        #  * +&block+ - a block that will be used to display: { |item| ... item.name }\n        #\n        # == Usage\n        #\n        #   <%= f.select :parent_id, nested_set_options(Category, @category) {|i|\n        #       \"#{'–' * i.level} #{i.name}\"\n        #     }) %>\n        #\n        def nested_set_options(class_or_item, mover = nil)\n          class_or_item = class_or_item.roots if class_or_item.is_a?(Class)\n          items = Array(class_or_item)\n          result = []\n          items.each do |root|\n            result += root.self_and_descendants.map do |i|\n              if mover.nil? || mover.new_record? || mover.move_possible?(i)\n                [yield(i), i.id]\n              end\n            end.compact\n          end\n          result\n        end  \n        \n      end\n    end  \n  end\nend"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/lib/awesome_nested_set/named_scope.rb",
    "content": "# Taken from Rails 2.1\nmodule CollectiveIdea #:nodoc:\n  module NamedScope #:nodoc:\n    # All subclasses of ActiveRecord::Base have two named_scopes:\n    # * <tt>all</tt>, which is similar to a <tt>find(:all)</tt> query, and\n    # * <tt>scoped</tt>, which allows for the creation of anonymous scopes, on the fly:\n    #\n    #   Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)\n    #\n    # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing\n    # intermediate values (scopes) around as first-class objects is convenient.\n    def self.included(base)\n      base.class_eval do\n        extend ClassMethods\n        named_scope :scoped, lambda { |scope| scope }\n      end\n    end\n\n    module ClassMethods #:nodoc:\n      def scopes\n        read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})\n      end\n\n      # Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query,\n      # such as <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>.\n      #\n      #   class Shirt < ActiveRecord::Base\n      #     named_scope :red, :conditions => {:color => 'red'}\n      #     named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true]\n      #   end\n      # \n      # The above calls to <tt>named_scope</tt> define class methods <tt>Shirt.red</tt> and <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>, \n      # in effect, represents the query <tt>Shirt.find(:all, :conditions => {:color => 'red'})</tt>.\n      #\n      # Unlike Shirt.find(...), however, the object returned by <tt>Shirt.red</tt> is not an Array; it resembles the association object\n      # constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.find(:first)</tt>, <tt>Shirt.red.count</tt>,\n      # <tt>Shirt.red.find(:all, :conditions => {:size => 'small'})</tt>. Also, just\n      # as with the association objects, name scopes acts like an Array, implementing Enumerable; <tt>Shirt.red.each(&block)</tt>,\n      # <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if Shirt.red really were an Array.\n      #\n      # These named scopes are composable. For instance, <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are both red and dry clean only.\n      # Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments\n      # for which these criteria obtain. Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>.\n      #\n      # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to\n      # <tt>has_many</tt> associations. If,\n      #\n      #   class Person < ActiveRecord::Base\n      #     has_many :shirts\n      #   end\n      #\n      # then <tt>elton.shirts.red.dry_clean_only</tt> will return all of Elton's red, dry clean\n      # only shirts.\n      #\n      # Named scopes can also be procedural.\n      #\n      #   class Shirt < ActiveRecord::Base\n      #     named_scope :colored, lambda { |color|\n      #       { :conditions => { :color => color } }\n      #     }\n      #   end\n      #\n      # In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts.\n      #\n      # Named scopes can also have extensions, just as with <tt>has_many</tt> declarations:\n      #\n      #   class Shirt < ActiveRecord::Base\n      #     named_scope :red, :conditions => {:color => 'red'} do\n      #       def dom_id\n      #         'red_shirts'\n      #       end\n      #     end\n      #   end\n      #\n      #\n      # For testing complex named scopes, you can examine the scoping options using the\n      # <tt>proxy_options</tt> method on the proxy itself.\n      #\n      #   class Shirt < ActiveRecord::Base\n      #     named_scope :colored, lambda { |color|\n      #       { :conditions => { :color => color } }\n      #     }\n      #   end\n      #\n      #   expected_options = { :conditions => { :colored => 'red' } }\n      #   assert_equal expected_options, Shirt.colored('red').proxy_options\n      def named_scope(name, options = {}, &block)\n        scopes[name] = lambda do |parent_scope, *args|\n          Scope.new(parent_scope, case options\n            when Hash\n              options\n            when Proc\n              options.call(*args)\n          end, &block)\n        end\n        (class << self; self end).instance_eval do\n          define_method name do |*args|\n            scopes[name].call(self, *args)\n          end\n        end\n      end\n    end\n\n    class Scope #:nodoc:\n      attr_reader :proxy_scope, :proxy_options\n      [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ }\n      delegate :scopes, :with_scope, :to => :proxy_scope\n\n      def initialize(proxy_scope, options, &block)\n        [options[:extend]].flatten.each { |extension| extend extension } if options[:extend]\n        extend Module.new(&block) if block_given?\n        @proxy_scope, @proxy_options = proxy_scope, options.except(:extend)\n      end\n\n      def reload\n        load_found; self\n      end\n\n      protected\n      def proxy_found\n        @found || load_found\n      end\n\n      private\n      def method_missing(method, *args, &block)\n        if scopes.include?(method)\n          scopes[method].call(self, *args)\n        else\n          with_scope :find => proxy_options do\n            proxy_scope.send(method, *args, &block)\n          end\n        end\n      end\n\n      def load_found\n        @found = find(:all)\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb",
    "content": "module CollectiveIdea #:nodoc:\n  module Acts #:nodoc:\n    module NestedSet #:nodoc:\n      def self.included(base)\n        base.extend(SingletonMethods)\n      end\n\n      # This acts provides Nested Set functionality. Nested Set is a smart way to implement\n      # an _ordered_ tree, with the added feature that you can select the children and all of their\n      # descendants with a single query. The drawback is that insertion or move need some complex\n      # sql queries. But everything is done here by this module!\n      #\n      # Nested sets are appropriate each time you want either an orderd tree (menus,\n      # commercial categories) or an efficient way of querying big trees (threaded posts).\n      #\n      # == API\n      #\n      # Methods names are aligned with acts_as_tree as much as possible, to make replacment from one\n      # by another easier, except for the creation:\n      #\n      # in acts_as_tree:\n      #   item.children.create(:name => \"child1\")\n      #\n      # in acts_as_nested_set:\n      #   # adds a new item at the \"end\" of the tree, i.e. with child.left = max(tree.right)+1\n      #   child = MyClass.new(:name => \"child1\")\n      #   child.save\n      #   # now move the item to its right place\n      #   child.move_to_child_of my_item\n      #\n      # You can pass an id or an object to:\n      # * <tt>#move_to_child_of</tt>\n      # * <tt>#move_to_right_of</tt>\n      # * <tt>#move_to_left_of</tt>\n      #\n      module SingletonMethods\n        # Configuration options are:\n        #\n        # * +:parent_column+ - specifies the column name to use for keeping the position integer (default: parent_id)\n        # * +:left_column+ - column name for left boundry data, default \"lft\"\n        # * +:right_column+ - column name for right boundry data, default \"rgt\"\n        # * +:scope+ - restricts what is to be considered a list. Given a symbol, it'll attach \"_id\"\n        #   (if it hasn't been already) and use that as the foreign key restriction. You\n        #   can also pass an array to scope by multiple attributes.\n        #   Example: <tt>acts_as_nested_set :scope => [:notable_id, :notable_type]</tt>\n        # * +:dependent+ - behavior for cascading destroy. If set to :destroy, all the\n        #   child objects are destroyed alongside this object by calling their destroy\n        #   method. If set to :delete_all (default), all the child objects are deleted\n        #   without calling their destroy method.\n        #\n        # See CollectiveIdea::Acts::NestedSet::ClassMethods for a list of class methods and\n        # CollectiveIdea::Acts::NestedSet::InstanceMethods for a list of instance methods added \n        # to acts_as_nested_set models\n        def acts_as_nested_set(options = {})\n          options = {\n            :parent_column => 'parent_id',\n            :left_column => 'lft',\n            :right_column => 'rgt',\n            :order => 'id',\n            :dependent => :delete_all, # or :destroy\n          }.merge(options)\n          \n          if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/\n            options[:scope] = \"#{options[:scope]}_id\".intern\n          end\n\n          write_inheritable_attribute :acts_as_nested_set_options, options\n          class_inheritable_reader :acts_as_nested_set_options\n          \n          include Comparable\n          include Columns\n          include InstanceMethods\n          extend Columns\n          extend ClassMethods\n\n          # no bulk assignment\n          attr_protected  left_column_name.intern,\n                          right_column_name.intern, \n                          parent_column_name.intern\n                          \n          before_create :set_default_left_and_right\n          before_destroy :prune_from_tree\n                          \n          # no assignment to structure fields\n          [left_column_name, right_column_name, parent_column_name].each do |column|\n            module_eval <<-\"end_eval\", __FILE__, __LINE__\n              def #{column}=(x)\n                raise ActiveRecord::ActiveRecordError, \"Unauthorized assignment to #{column}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead.\"\n              end\n            end_eval\n          end\n          \n          named_scope :roots, :conditions => {parent_column_name => nil}, :order => quoted_left_column_name\n          named_scope :leaves, :conditions => \"#{quoted_right_column_name} - #{quoted_left_column_name} = 1\", :order => quoted_left_column_name\n          if self.respond_to?(:define_callbacks)\n            define_callbacks(\"before_move\", \"after_move\")              \n          end\n\n          \n        end\n        \n      end\n      \n      module ClassMethods\n        \n        # Returns the first root\n        def root\n          roots.find(:first)\n        end\n        \n        def valid?\n          left_and_rights_valid? && no_duplicates_for_columns? && all_roots_valid?\n        end\n        \n        def left_and_rights_valid?\n          count(\n            :joins => \"LEFT OUTER JOIN #{quoted_table_name} AS parent ON \" +\n              \"#{quoted_table_name}.#{quoted_parent_column_name} = parent.#{primary_key}\",\n            :conditions =>\n              \"#{quoted_table_name}.#{quoted_left_column_name} IS NULL OR \" +\n              \"#{quoted_table_name}.#{quoted_right_column_name} IS NULL OR \" +\n              \"#{quoted_table_name}.#{quoted_left_column_name} >= \" +\n                \"#{quoted_table_name}.#{quoted_right_column_name} OR \" +\n              \"(#{quoted_table_name}.#{quoted_parent_column_name} IS NOT NULL AND \" +\n                \"(#{quoted_table_name}.#{quoted_left_column_name} <= parent.#{quoted_left_column_name} OR \" +\n                \"#{quoted_table_name}.#{quoted_right_column_name} >= parent.#{quoted_right_column_name}))\"\n          ) == 0\n        end\n        \n        def no_duplicates_for_columns?\n          scope_string = Array(acts_as_nested_set_options[:scope]).map do |c|\n            connection.quote_column_name(c)\n          end.push(nil).join(\", \")\n          [quoted_left_column_name, quoted_right_column_name].all? do |column|\n            # No duplicates\n            find(:first, \n              :select => \"#{scope_string}#{column}, COUNT(#{column})\", \n              :group => \"#{scope_string}#{column} \n                HAVING COUNT(#{column}) > 1\").nil?\n          end\n        end\n        \n        # Wrapper for each_root_valid? that can deal with scope.\n        def all_roots_valid?\n          if acts_as_nested_set_options[:scope]\n            roots(:group => scope_column_names).group_by{|record| scope_column_names.collect{|col| record.send(col.to_sym)}}.all? do |scope, grouped_roots|\n              each_root_valid?(grouped_roots)\n            end\n          else\n            each_root_valid?(roots)\n          end\n        end\n        \n        def each_root_valid?(roots_to_validate)\n          left = right = 0\n          roots_to_validate.all? do |root|\n            returning(root.left > left && root.right > right) do\n              left = root.left\n              right = root.right\n            end\n          end\n        end\n                \n        # Rebuilds the left & rights if unset or invalid.  Also very useful for converting from acts_as_tree.\n        def rebuild!\n          # Don't rebuild a valid tree.\n          return true if valid?\n          \n          scope = lambda{|node|}\n          if acts_as_nested_set_options[:scope]\n            scope = lambda{|node| \n              scope_column_names.inject(\"\"){|str, column_name|\n                str << \"AND #{connection.quote_column_name(column_name)} = #{connection.quote(node.send(column_name.to_sym))} \"\n              }\n            }\n          end\n          indices = {}\n          \n          set_left_and_rights = lambda do |node|\n            # set left\n            node[left_column_name] = indices[scope.call(node)] += 1\n            # find\n            find(:all, :conditions => [\"#{quoted_parent_column_name} = ? #{scope.call(node)}\", node], :order => \"#{quoted_left_column_name}, #{quoted_right_column_name}, #{acts_as_nested_set_options[:order]}\").each{|n| set_left_and_rights.call(n) }\n            # set right\n            node[right_column_name] = indices[scope.call(node)] += 1    \n            node.save!    \n          end\n                              \n          # Find root node(s)\n          root_nodes = find(:all, :conditions => \"#{quoted_parent_column_name} IS NULL\", :order => \"#{quoted_left_column_name}, #{quoted_right_column_name}, #{acts_as_nested_set_options[:order]}\").each do |root_node|\n            # setup index for this scope\n            indices[scope.call(root_node)] ||= 0\n            set_left_and_rights.call(root_node)\n          end\n        end\n      end\n      \n      # Mixed into both classes and instances to provide easy access to the column names\n      module Columns\n        def left_column_name\n          acts_as_nested_set_options[:left_column]\n        end\n        \n        def right_column_name\n          acts_as_nested_set_options[:right_column]\n        end\n        \n        def parent_column_name\n          acts_as_nested_set_options[:parent_column]\n        end\n        \n        def scope_column_names\n          Array(acts_as_nested_set_options[:scope])\n        end\n        \n        def quoted_left_column_name\n          connection.quote_column_name(left_column_name)\n        end\n        \n        def quoted_right_column_name\n          connection.quote_column_name(right_column_name)\n        end\n        \n        def quoted_parent_column_name\n          connection.quote_column_name(parent_column_name)\n        end\n        \n        def quoted_scope_column_names\n          scope_column_names.collect {|column_name| connection.quote_column_name(column_name) }\n        end\n      end\n\n      # Any instance method that returns a collection makes use of Rails 2.1's named_scope (which is bundled for Rails 2.0), so it can be treated as a finder.\n      #\n      #   category.self_and_descendants.count\n      #   category.ancestors.find(:all, :conditions => \"name like '%foo%'\")\n      module InstanceMethods\n        # Value of the parent column\n        def parent_id\n          self[parent_column_name]\n        end\n        \n        # Value of the left column\n        def left\n          self[left_column_name]\n        end\n        \n        # Value of the right column\n        def right\n          self[right_column_name]\n        end\n\n        # Returns true if this is a root node.\n        def root?\n          parent_id.nil?\n        end\n        \n        def leaf?\n          right - left == 1\n        end\n\n        # Returns true is this is a child node\n        def child?\n          !parent_id.nil?\n        end\n\n        # order by left column\n        def <=>(x)\n          left <=> x.left\n        end\n        \n        # Redefine to act like active record\n        def ==(comparison_object)\n          comparison_object.equal?(self) ||\n            (comparison_object.instance_of?(self.class) &&\n              comparison_object.id == id &&\n              !comparison_object.new_record?)\n        end\n\n        # Returns root\n        def root\n          self_and_ancestors.find(:first)\n        end\n\n        # Returns the immediate parent\n        def parent\n          nested_set_scope.find_by_id(parent_id) if parent_id\n        end\n\n        # Returns the array of all parents and self\n        def self_and_ancestors\n          nested_set_scope.scoped :conditions => [\n            \"#{self.class.table_name}.#{quoted_left_column_name} <= ? AND #{self.class.table_name}.#{quoted_right_column_name} >= ?\", left, right\n          ]\n        end\n\n        # Returns an array of all parents\n        def ancestors\n          without_self self_and_ancestors\n        end\n\n        # Returns the array of all children of the parent, including self\n        def self_and_siblings\n          nested_set_scope.scoped :conditions => {parent_column_name => parent_id}\n        end\n\n        # Returns the array of all children of the parent, except self\n        def siblings\n          without_self self_and_siblings\n        end\n\n        # Returns a set of all of its nested children which do not have children  \n        def leaves\n          descendants.scoped :conditions => \"#{self.class.table_name}.#{quoted_right_column_name} - #{self.class.table_name}.#{quoted_left_column_name} = 1\"\n        end    \n\n        # Returns the level of this object in the tree\n        # root level is 0\n        def level\n          parent_id.nil? ? 0 : ancestors.count\n        end\n\n        # Returns a set of itself and all of its nested children\n        def self_and_descendants\n          nested_set_scope.scoped :conditions => [\n            \"#{self.class.table_name}.#{quoted_left_column_name} >= ? AND #{self.class.table_name}.#{quoted_right_column_name} <= ?\", left, right\n          ]\n        end\n\n        # Returns a set of all of its children and nested children\n        def descendants\n          without_self self_and_descendants\n        end\n\n        # Returns a set of only this entry's immediate children\n        def children\n          nested_set_scope.scoped :conditions => {parent_column_name => self}\n        end\n\n        def is_descendant_of?(other)\n          other.left < self.left && self.left < other.right && same_scope?(other)\n        end\n        \n        def is_or_is_descendant_of?(other)\n          other.left <= self.left && self.left < other.right && same_scope?(other)\n        end\n\n        def is_ancestor_of?(other)\n          self.left < other.left && other.left < self.right && same_scope?(other)\n        end\n        \n        def is_or_is_ancestor_of?(other)\n          self.left <= other.left && other.left < self.right && same_scope?(other)\n        end\n        \n        # Check if other model is in the same scope\n        def same_scope?(other)\n          Array(acts_as_nested_set_options[:scope]).all? do |attr|\n            self.send(attr) == other.send(attr)\n          end\n        end\n\n        # Find the first sibling to the left\n        def left_sibling\n          siblings.find(:first, :conditions => [\"#{self.class.table_name}.#{quoted_left_column_name} < ?\", left],\n            :order => \"#{self.class.table_name}.#{quoted_left_column_name} DESC\")\n        end\n\n        # Find the first sibling to the right\n        def right_sibling\n          siblings.find(:first, :conditions => [\"#{self.class.table_name}.#{quoted_left_column_name} > ?\", left])\n        end\n\n        # Shorthand method for finding the left sibling and moving to the left of it.\n        def move_left\n          move_to_left_of left_sibling\n        end\n\n        # Shorthand method for finding the right sibling and moving to the right of it.\n        def move_right\n          move_to_right_of right_sibling\n        end\n\n        # Move the node to the left of another node (you can pass id only)\n        def move_to_left_of(node)\n          move_to node, :left\n        end\n\n        # Move the node to the left of another node (you can pass id only)\n        def move_to_right_of(node)\n          move_to node, :right\n        end\n\n        # Move the node to the child of another node (you can pass id only)\n        def move_to_child_of(node)\n          move_to node, :child\n        end\n        \n        # Move the node to root nodes\n        def move_to_root\n          move_to nil, :root\n        end\n        \n        def move_possible?(target)\n          self != target && # Can't target self\n          same_scope?(target) && # can't be in different scopes\n          # !(left..right).include?(target.left..target.right) # this needs tested more\n          # detect impossible move\n          !((left <= target.left && right >= target.left) or (left <= target.right && right >= target.right))\n        end\n        \n        def to_text\n          self_and_descendants.map do |node|\n            \"#{'*'*(node.level+1)} #{node.id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})\"\n          end.join(\"\\n\")\n        end\n        \n      protected\n      \n        def without_self(scope)\n          scope.scoped :conditions => [\"#{self.class.table_name}.#{self.class.primary_key} != ?\", self]\n        end\n        \n        # All nested set queries should use this nested_set_scope, which performs finds on\n        # the base ActiveRecord class, using the :scope declared in the acts_as_nested_set\n        # declaration.\n        def nested_set_scope\n          options = {:order => quoted_left_column_name}\n          scopes = Array(acts_as_nested_set_options[:scope])\n          options[:conditions] = scopes.inject({}) do |conditions,attr|\n            conditions.merge attr => self[attr]\n          end unless scopes.empty?\n          self.class.base_class.scoped options\n        end\n        \n        # on creation, set automatically lft and rgt to the end of the tree\n        def set_default_left_and_right\n          maxright = nested_set_scope.maximum(right_column_name) || 0\n          # adds the new node to the right of all existing nodes\n          self[left_column_name] = maxright + 1\n          self[right_column_name] = maxright + 2\n        end\n      \n        # Prunes a branch off of the tree, shifting all of the elements on the right\n        # back to the left so the counts still work.\n        def prune_from_tree\n          return if right.nil? || left.nil?\n          diff = right - left + 1\n\n          delete_method = acts_as_nested_set_options[:dependent] == :destroy ?\n            :destroy_all : :delete_all\n\n          self.class.base_class.transaction do\n            nested_set_scope.send(delete_method,\n              [\"#{quoted_left_column_name} > ? AND #{quoted_right_column_name} < ?\",\n                left, right]\n            )\n            nested_set_scope.update_all(\n              [\"#{quoted_left_column_name} = (#{quoted_left_column_name} - ?)\", diff],\n              [\"#{quoted_left_column_name} >= ?\", right]\n            )\n            nested_set_scope.update_all(\n              [\"#{quoted_right_column_name} = (#{quoted_right_column_name} - ?)\", diff],\n              [\"#{quoted_right_column_name} >= ?\", right]\n            )\n          end\n        end\n\n        # reload left, right, and parent\n        def reload_nested_set\n          reload(:select => \"#{quoted_left_column_name}, \" +\n            \"#{quoted_right_column_name}, #{quoted_parent_column_name}\")\n        end\n        \n        def move_to(target, position)\n          raise ActiveRecord::ActiveRecordError, \"You cannot move a new node\" if self.new_record?\n          return if callback(:before_move) == false\n          transaction do\n            if target.is_a? self.class.base_class\n              target.reload_nested_set\n            elsif position != :root\n              # load object if node is not an object\n              target = nested_set_scope.find(target)\n            end\n            self.reload_nested_set\n          \n            unless position == :root || move_possible?(target)\n              raise ActiveRecord::ActiveRecordError, \"Impossible move, target node cannot be inside moved tree.\"\n            end\n            \n            bound = case position\n              when :child;  target[right_column_name]\n              when :left;   target[left_column_name]\n              when :right;  target[right_column_name] + 1\n              when :root;   1\n              else raise ActiveRecord::ActiveRecordError, \"Position should be :child, :left, :right or :root ('#{position}' received).\"\n            end\n          \n            if bound > self[right_column_name]\n              bound = bound - 1\n              other_bound = self[right_column_name] + 1\n            else\n              other_bound = self[left_column_name] - 1\n            end\n\n            # there would be no change\n            return if bound == self[right_column_name] || bound == self[left_column_name]\n          \n            # we have defined the boundaries of two non-overlapping intervals, \n            # so sorting puts both the intervals and their boundaries in order\n            a, b, c, d = [self[left_column_name], self[right_column_name], bound, other_bound].sort\n\n            new_parent = case position\n              when :child;  target.id\n              when :root;   nil\n              else          target[parent_column_name]\n            end\n\n            self.class.base_class.update_all([\n              \"#{quoted_left_column_name} = CASE \" +\n                \"WHEN #{quoted_left_column_name} BETWEEN :a AND :b \" +\n                  \"THEN #{quoted_left_column_name} + :d - :b \" +\n                \"WHEN #{quoted_left_column_name} BETWEEN :c AND :d \" +\n                  \"THEN #{quoted_left_column_name} + :a - :c \" +\n                \"ELSE #{quoted_left_column_name} END, \" +\n              \"#{quoted_right_column_name} = CASE \" +\n                \"WHEN #{quoted_right_column_name} BETWEEN :a AND :b \" +\n                  \"THEN #{quoted_right_column_name} + :d - :b \" +\n                \"WHEN #{quoted_right_column_name} BETWEEN :c AND :d \" +\n                  \"THEN #{quoted_right_column_name} + :a - :c \" +\n                \"ELSE #{quoted_right_column_name} END, \" +\n              \"#{quoted_parent_column_name} = CASE \" +\n                \"WHEN #{self.class.base_class.primary_key} = :id THEN :new_parent \" +\n                \"ELSE #{quoted_parent_column_name} END\",\n              {:a => a, :b => b, :c => c, :d => d, :id => self.id, :new_parent => new_parent}\n            ], nested_set_scope.proxy_options[:conditions])\n          end\n          target.reload_nested_set if target\n          self.reload_nested_set\n          callback(:after_move)\n        end\n\n      end\n      \n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/rails/init.rb",
    "content": "require 'awesome_nested_set/compatability'\nrequire 'awesome_nested_set'\n\nActiveRecord::Base.class_eval do\n  include CollectiveIdea::Acts::NestedSet\nend\n\nif defined?(ActionView)\n  require 'awesome_nested_set/helper'\n  ActionView::Base.class_eval do\n    include CollectiveIdea::Acts::NestedSet::Helper\n  end\nend"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nmodule CollectiveIdea\n  module Acts #:nodoc:\n    module NestedSet #:nodoc:\n      class AwesomeNestedSetTest < Test::Unit::TestCase\n        include Helper\n        fixtures :categories\n        \n        def test_nested_set_options\n          expected = [\n            [\" Top Level\", 1],\n            [\"- Child 1\", 2],\n            ['- Child 2', 3],\n            ['-- Child 2.1', 4],\n            ['- Child 3', 5],\n            [\" Top Level 2\", 6]\n          ]\n          actual = nested_set_options(Category) do |c|\n            \"#{'-' * c.level} #{c.name}\"\n          end\n          assert_equal expected, actual\n        end\n        \n        def test_nested_set_options_with_mover\n          expected = [\n            [\" Top Level\", 1],\n            [\"- Child 1\", 2],\n            ['- Child 3', 5],\n            [\" Top Level 2\", 6]\n          ]\n          actual = nested_set_options(Category, categories(:child_2)) do |c|\n            \"#{'-' * c.level} #{c.name}\"\n          end\n          assert_equal expected, actual\n        end\n        \n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\n\nclass Note < ActiveRecord::Base\n  acts_as_nested_set :scope => [:notable_id, :notable_type]\nend\n\nclass AwesomeNestedSetTest < Test::Unit::TestCase\n\n  class Default < ActiveRecord::Base\n    acts_as_nested_set\n    set_table_name 'categories'\n  end\n  class Scoped < ActiveRecord::Base\n    acts_as_nested_set :scope => :organization\n    set_table_name 'categories'\n  end\n\n  def test_left_column_default\n    assert_equal 'lft', Default.acts_as_nested_set_options[:left_column]\n  end\n\n  def test_right_column_default\n    assert_equal 'rgt', Default.acts_as_nested_set_options[:right_column]\n  end\n\n  def test_parent_column_default\n    assert_equal 'parent_id', Default.acts_as_nested_set_options[:parent_column]\n  end\n\n  def test_scope_default\n    assert_nil Default.acts_as_nested_set_options[:scope]\n  end\n  \n  def test_left_column_name\n    assert_equal 'lft', Default.left_column_name\n    assert_equal 'lft', Default.new.left_column_name\n  end\n\n  def test_right_column_name\n    assert_equal 'rgt', Default.right_column_name\n    assert_equal 'rgt', Default.new.right_column_name\n  end\n\n  def test_parent_column_name\n    assert_equal 'parent_id', Default.parent_column_name\n    assert_equal 'parent_id', Default.new.parent_column_name\n  end\n  \n  def test_quoted_left_column_name\n    quoted = Default.connection.quote_column_name('lft')\n    assert_equal quoted, Default.quoted_left_column_name\n    assert_equal quoted, Default.new.quoted_left_column_name\n  end\n\n  def test_quoted_right_column_name\n    quoted = Default.connection.quote_column_name('rgt')\n    assert_equal quoted, Default.quoted_right_column_name\n    assert_equal quoted, Default.new.quoted_right_column_name\n  end\n\n  def test_left_column_protected_from_assignment\n    assert_raises(ActiveRecord::ActiveRecordError) { Category.new.lft = 1 }\n  end\n  \n  def test_right_column_protected_from_assignment\n    assert_raises(ActiveRecord::ActiveRecordError) { Category.new.rgt = 1 }\n  end\n  \n  def test_parent_column_protected_from_assignment\n    assert_raises(ActiveRecord::ActiveRecordError) { Category.new.parent_id = 1 }\n  end\n  \n  def test_colums_protected_on_initialize\n    c = Category.new(:lft => 1, :rgt => 2, :parent_id => 3)\n    assert_nil c.lft\n    assert_nil c.rgt\n    assert_nil c.parent_id\n  end\n  \n  def test_scoped_appends_id\n    assert_equal :organization_id, Scoped.acts_as_nested_set_options[:scope]\n  end\n  \n  def test_roots_class_method\n    assert_equal Category.find_all_by_parent_id(nil), Category.roots\n  end\n    \n  def test_root_class_method\n    assert_equal categories(:top_level), Category.root\n  end\n  \n  def test_root\n    assert_equal categories(:top_level), categories(:child_3).root\n  end\n  \n  def test_root?\n    assert categories(:top_level).root?\n    assert categories(:top_level_2).root?\n  end\n  \n  def test_leaves_class_method\n    assert_equal Category.find(:all, :conditions => \"#{Category.right_column_name} - #{Category.left_column_name} = 1\"), Category.leaves\n    assert_equal Category.leaves.count, 4\n    assert (Category.leaves.include? categories(:child_1))\n    assert (Category.leaves.include? categories(:child_2_1))\n    assert (Category.leaves.include? categories(:child_3))\n    assert (Category.leaves.include? categories(:top_level_2))\n  end\n  \n  def test_leaf\n    assert categories(:child_1).leaf?\n    assert categories(:child_2_1).leaf?\n    assert categories(:child_3).leaf?\n    assert categories(:top_level_2).leaf?\n    \n    assert !categories(:top_level).leaf?\n    assert !categories(:child_2).leaf?\n  end\n    \n  def test_parent\n    assert_equal categories(:child_2), categories(:child_2_1).parent\n  end\n  \n  def test_self_and_ancestors\n    child = categories(:child_2_1)\n    self_and_ancestors = [categories(:top_level), categories(:child_2), child]\n    assert_equal self_and_ancestors, child.self_and_ancestors\n  end\n\n  def test_ancestors\n    child = categories(:child_2_1)\n    ancestors = [categories(:top_level), categories(:child_2)]\n    assert_equal ancestors, child.ancestors\n  end\n  \n  def test_self_and_siblings\n    child = categories(:child_2)\n    self_and_siblings = [categories(:child_1), child, categories(:child_3)]\n    assert_equal self_and_siblings, child.self_and_siblings\n    assert_nothing_raised do\n      tops = [categories(:top_level), categories(:top_level_2)]\n      assert_equal tops, categories(:top_level).self_and_siblings\n    end\n  end\n\n  def test_siblings\n    child = categories(:child_2)\n    siblings = [categories(:child_1), categories(:child_3)]\n    assert_equal siblings, child.siblings\n  end\n  \n  def test_leaves\n    leaves = [categories(:child_1), categories(:child_2_1), categories(:child_3), categories(:top_level_2)]\n    assert categories(:top_level).leaves, leaves\n  end\n  \n  def test_level\n    assert_equal 0, categories(:top_level).level\n    assert_equal 1, categories(:child_1).level\n    assert_equal 2, categories(:child_2_1).level\n  end\n  \n  def test_has_children?\n    assert categories(:child_2_1).children.empty?\n    assert !categories(:child_2).children.empty?\n    assert !categories(:top_level).children.empty?\n  end\n  \n  def test_self_and_descendents\n    parent = categories(:top_level)\n    self_and_descendants = [parent, categories(:child_1), categories(:child_2),\n      categories(:child_2_1), categories(:child_3)]\n    assert_equal self_and_descendants, parent.self_and_descendants\n    assert_equal self_and_descendants, parent.self_and_descendants.count\n  end\n  \n  def test_descendents\n    lawyers = Category.create!(:name => \"lawyers\")\n    us = Category.create!(:name => \"United States\")\n    us.move_to_child_of(lawyers)\n    patent = Category.create!(:name => \"Patent Law\")\n    patent.move_to_child_of(us)\n    lawyers.reload\n\n    assert_equal 1, lawyers.children.size\n    assert_equal 1, us.children.size\n    assert_equal 2, lawyers.descendants.size\n  end\n  \n  def test_self_and_descendents\n    parent = categories(:top_level)\n    descendants = [categories(:child_1), categories(:child_2),\n      categories(:child_2_1), categories(:child_3)]\n    assert_equal descendants, parent.descendants\n  end\n  \n  def test_children\n    category = categories(:top_level)\n    category.children.each {|c| assert_equal category.id, c.parent_id }\n  end\n  \n  def test_is_or_is_ancestor_of?\n    assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_1))\n    assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_2_1))\n    assert categories(:child_2).is_or_is_ancestor_of?(categories(:child_2_1))\n    assert !categories(:child_2_1).is_or_is_ancestor_of?(categories(:child_2))\n    assert !categories(:child_1).is_or_is_ancestor_of?(categories(:child_2))\n    assert categories(:child_1).is_or_is_ancestor_of?(categories(:child_1))\n  end\n  \n  def test_is_ancestor_of?\n    assert categories(:top_level).is_ancestor_of?(categories(:child_1))\n    assert categories(:top_level).is_ancestor_of?(categories(:child_2_1))\n    assert categories(:child_2).is_ancestor_of?(categories(:child_2_1))\n    assert !categories(:child_2_1).is_ancestor_of?(categories(:child_2))\n    assert !categories(:child_1).is_ancestor_of?(categories(:child_2))\n    assert !categories(:child_1).is_ancestor_of?(categories(:child_1))\n  end\n\n  def test_is_or_is_ancestor_of_with_scope\n    root = Scoped.root\n    child = root.children.first\n    assert root.is_or_is_ancestor_of?(child)\n    child.update_attribute :organization_id, 'different'\n    assert !root.is_or_is_ancestor_of?(child)\n  end\n\n  def test_is_or_is_descendant_of?\n    assert categories(:child_1).is_or_is_descendant_of?(categories(:top_level))\n    assert categories(:child_2_1).is_or_is_descendant_of?(categories(:top_level))\n    assert categories(:child_2_1).is_or_is_descendant_of?(categories(:child_2))\n    assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_2_1))\n    assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_1))\n    assert categories(:child_1).is_or_is_descendant_of?(categories(:child_1))\n  end\n  \n  def test_is_descendant_of?\n    assert categories(:child_1).is_descendant_of?(categories(:top_level))\n    assert categories(:child_2_1).is_descendant_of?(categories(:top_level))\n    assert categories(:child_2_1).is_descendant_of?(categories(:child_2))\n    assert !categories(:child_2).is_descendant_of?(categories(:child_2_1))\n    assert !categories(:child_2).is_descendant_of?(categories(:child_1))\n    assert !categories(:child_1).is_descendant_of?(categories(:child_1))\n  end\n  \n  def test_is_or_is_descendant_of_with_scope\n    root = Scoped.root\n    child = root.children.first\n    assert child.is_or_is_descendant_of?(root)\n    child.update_attribute :organization_id, 'different'\n    assert !child.is_or_is_descendant_of?(root)\n  end\n  \n  def test_same_scope?\n    root = Scoped.root\n    child = root.children.first\n    assert child.same_scope?(root)\n    child.update_attribute :organization_id, 'different'\n    assert !child.same_scope?(root)\n  end\n  \n  def test_left_sibling\n    assert_equal categories(:child_1), categories(:child_2).left_sibling\n    assert_equal categories(:child_2), categories(:child_3).left_sibling\n  end\n\n  def test_left_sibling_of_root\n    assert_nil categories(:top_level).left_sibling\n  end\n\n  def test_left_sibling_without_siblings\n    assert_nil categories(:child_2_1).left_sibling\n  end\n\n  def test_left_sibling_of_leftmost_node\n    assert_nil categories(:child_1).left_sibling\n  end\n\n  def test_right_sibling\n    assert_equal categories(:child_3), categories(:child_2).right_sibling\n    assert_equal categories(:child_2), categories(:child_1).right_sibling\n  end\n\n  def test_right_sibling_of_root\n    assert_equal categories(:top_level_2), categories(:top_level).right_sibling\n    assert_nil categories(:top_level_2).right_sibling\n  end\n\n  def test_right_sibling_without_siblings\n    assert_nil categories(:child_2_1).right_sibling\n  end\n\n  def test_right_sibling_of_rightmost_node\n    assert_nil categories(:child_3).right_sibling\n  end\n  \n  def test_move_left\n    categories(:child_2).move_left\n    assert_nil categories(:child_2).left_sibling\n    assert_equal categories(:child_1), categories(:child_2).right_sibling\n    assert Category.valid?\n  end\n\n  def test_move_right\n    categories(:child_2).move_right\n    assert_nil categories(:child_2).right_sibling\n    assert_equal categories(:child_3), categories(:child_2).left_sibling\n    assert Category.valid?\n  end\n\n  def test_move_to_left_of\n    categories(:child_3).move_to_left_of(categories(:child_1))\n    assert_nil categories(:child_3).left_sibling\n    assert_equal categories(:child_1), categories(:child_3).right_sibling\n    assert Category.valid?\n  end\n\n  def test_move_to_right_of\n    categories(:child_1).move_to_right_of(categories(:child_3))\n    assert_nil categories(:child_1).right_sibling\n    assert_equal categories(:child_3), categories(:child_1).left_sibling\n    assert Category.valid?\n  end\n  \n  def test_move_to_root\n    categories(:child_2).move_to_root\n    assert_nil categories(:child_2).parent\n    assert_equal 0, categories(:child_2).level\n    assert_equal 1, categories(:child_2_1).level\n    assert_equal 1, categories(:child_2).left\n    assert_equal 4, categories(:child_2).right\n    assert Category.valid?\n  end\n\n  def test_move_to_child_of\n    categories(:child_1).move_to_child_of(categories(:child_3))\n    assert_equal categories(:child_3).id, categories(:child_1).parent_id\n    assert Category.valid?\n  end\n  \n  def test_move_to_child_of_appends_to_end\n    child = Category.create! :name => 'New Child'\n    child.move_to_child_of categories(:top_level)\n    assert_equal child, categories(:top_level).children.last\n  end\n  \n  def test_subtree_move_to_child_of\n    assert_equal 4, categories(:child_2).left\n    assert_equal 7, categories(:child_2).right\n    \n    assert_equal 2, categories(:child_1).left\n    assert_equal 3, categories(:child_1).right\n    \n    categories(:child_2).move_to_child_of(categories(:child_1))\n    assert Category.valid?\n    assert_equal categories(:child_1).id, categories(:child_2).parent_id\n    \n    assert_equal 3, categories(:child_2).left\n    assert_equal 6, categories(:child_2).right\n    assert_equal 2, categories(:child_1).left\n    assert_equal 7, categories(:child_1).right    \n  end\n  \n  def test_slightly_difficult_move_to_child_of\n    assert_equal 11, categories(:top_level_2).left\n    assert_equal 12, categories(:top_level_2).right\n    \n    # create a new top-level node and move single-node top-level tree inside it.\n    new_top = Category.create(:name => 'New Top')\n    assert_equal 13, new_top.left\n    assert_equal 14, new_top.right\n    \n    categories(:top_level_2).move_to_child_of(new_top)\n    \n    assert Category.valid?\n    assert_equal new_top.id, categories(:top_level_2).parent_id\n    \n    assert_equal 12, categories(:top_level_2).left\n    assert_equal 13, categories(:top_level_2).right\n    assert_equal 11, new_top.left\n    assert_equal 14, new_top.right    \n  end\n  \n  def test_difficult_move_to_child_of\n    assert_equal 1, categories(:top_level).left\n    assert_equal 10, categories(:top_level).right\n    assert_equal 5, categories(:child_2_1).left\n    assert_equal 6, categories(:child_2_1).right\n    \n    # create a new top-level node and move an entire top-level tree inside it.\n    new_top = Category.create(:name => 'New Top')\n    categories(:top_level).move_to_child_of(new_top)\n    categories(:child_2_1).reload\n    assert Category.valid?  \n    assert_equal new_top.id, categories(:top_level).parent_id\n    \n    assert_equal 4, categories(:top_level).left\n    assert_equal 13, categories(:top_level).right\n    assert_equal 8, categories(:child_2_1).left\n    assert_equal 9, categories(:child_2_1).right    \n  end\n\n  #rebuild swaps the position of the 2 children when added using move_to_child twice onto same parent\n  def test_move_to_child_more_than_once_per_parent_rebuild\n    root1 = Category.create(:name => 'Root1')\n    root2 = Category.create(:name => 'Root2')\n    root3 = Category.create(:name => 'Root3')\n    \n    root2.move_to_child_of root1\n    root3.move_to_child_of root1\n      \n    output = Category.roots.last.to_text\n    Category.update_all('lft = null, rgt = null')\n    Category.rebuild!\n    \n    assert_equal Category.roots.last.to_text, output\n  end\n  \n  # doing move_to_child twice onto same parent from the furthest right first\n  def test_move_to_child_more_than_once_per_parent_outside_in\n    node1 = Category.create(:name => 'Node-1')\n    node2 = Category.create(:name => 'Node-2')\n    node3 = Category.create(:name => 'Node-3')\n    \n    node2.move_to_child_of node1\n    node3.move_to_child_of node1\n      \n    output = Category.roots.last.to_text\n    Category.update_all('lft = null, rgt = null')\n    Category.rebuild!\n    \n    assert_equal Category.roots.last.to_text, output\n  end\n\n\n  def test_valid_with_null_lefts\n    assert Category.valid?\n    Category.update_all('lft = null')\n    assert !Category.valid?\n  end\n\n  def test_valid_with_null_rights\n    assert Category.valid?\n    Category.update_all('rgt = null')\n    assert !Category.valid?\n  end\n  \n  def test_valid_with_missing_intermediate_node\n    # Even though child_2_1 will still exist, it is a sign of a sloppy delete, not an invalid tree.\n    assert Category.valid?\n    Category.delete(categories(:child_2).id)\n    assert Category.valid?\n  end\n  \n  def test_valid_with_overlapping_and_rights\n    assert Category.valid?\n    categories(:top_level_2)['lft'] = 0\n    categories(:top_level_2).save\n    assert !Category.valid?\n  end\n  \n  def test_rebuild\n    assert Category.valid?\n    before_text = Category.root.to_text\n    Category.update_all('lft = null, rgt = null')\n    Category.rebuild!\n    assert Category.valid?\n    assert_equal before_text, Category.root.to_text\n  end\n  \n  def test_move_possible_for_sibling\n    assert categories(:child_2).move_possible?(categories(:child_1))\n  end\n  \n  def test_move_not_possible_to_self\n    assert !categories(:top_level).move_possible?(categories(:top_level))\n  end\n  \n  def test_move_not_possible_to_parent\n    categories(:top_level).descendants.each do |descendant|\n      assert !categories(:top_level).move_possible?(descendant)\n      assert descendant.move_possible?(categories(:top_level))\n    end\n  end\n  \n  def test_is_or_is_ancestor_of?\n    [:child_1, :child_2, :child_2_1, :child_3].each do |c|\n      assert categories(:top_level).is_or_is_ancestor_of?(categories(c))\n    end\n    assert !categories(:top_level).is_or_is_ancestor_of?(categories(:top_level_2))\n  end\n  \n  def test_left_and_rights_valid_with_blank_left\n    assert Category.left_and_rights_valid?\n    categories(:child_2)[:lft] = nil\n    categories(:child_2).save(false)\n    assert !Category.left_and_rights_valid?\n  end\n\n  def test_left_and_rights_valid_with_blank_right\n    assert Category.left_and_rights_valid?\n    categories(:child_2)[:rgt] = nil\n    categories(:child_2).save(false)\n    assert !Category.left_and_rights_valid?\n  end\n\n  def test_left_and_rights_valid_with_equal\n    assert Category.left_and_rights_valid?\n    categories(:top_level_2)[:lft] = categories(:top_level_2)[:rgt]\n    categories(:top_level_2).save(false)\n    assert !Category.left_and_rights_valid?\n  end\n\n  def test_left_and_rights_valid_with_left_equal_to_parent\n    assert Category.left_and_rights_valid?\n    categories(:child_2)[:lft] = categories(:top_level)[:lft]\n    categories(:child_2).save(false)\n    assert !Category.left_and_rights_valid?\n  end\n\n  def test_left_and_rights_valid_with_right_equal_to_parent\n    assert Category.left_and_rights_valid?\n    categories(:child_2)[:rgt] = categories(:top_level)[:rgt]\n    categories(:child_2).save(false)\n    assert !Category.left_and_rights_valid?\n  end\n  \n  def test_moving_dirty_objects_doesnt_invalidate_tree\n    r1 = Category.create\n    r2 = Category.create\n    r3 = Category.create\n    r4 = Category.create\n    nodes = [r1, r2, r3, r4]\n    \n    r2.move_to_child_of(r1)\n    assert Category.valid?\n    \n    r3.move_to_child_of(r1)\n    assert Category.valid?\n    \n    r4.move_to_child_of(r2)\n    assert Category.valid?\n  end\n  \n  def test_multi_scoped_no_duplicates_for_columns?\n    assert_nothing_raised do\n      Note.no_duplicates_for_columns?\n    end\n  end\n\n  def test_multi_scoped_all_roots_valid?\n    assert_nothing_raised do\n      Note.all_roots_valid?\n    end\n  end\n\n  def test_multi_scoped\n    note1 = Note.create!(:body => \"A\", :notable_id => 2, :notable_type => 'Category')\n    note2 = Note.create!(:body => \"B\", :notable_id => 2, :notable_type => 'Category')\n    note3 = Note.create!(:body => \"C\", :notable_id => 2, :notable_type => 'Default')\n    \n    assert_equal [note1, note2], note1.self_and_siblings\n    assert_equal [note3], note3.self_and_siblings\n  end\n  \n  def test_multi_scoped_rebuild\n    root = Note.create!(:body => \"A\", :notable_id => 3, :notable_type => 'Category')\n    child1 = Note.create!(:body => \"B\", :notable_id => 3, :notable_type => 'Category')\n    child2 = Note.create!(:body => \"C\", :notable_id => 3, :notable_type => 'Category')\n    \n    child1.move_to_child_of root\n    child2.move_to_child_of root\n          \n    Note.update_all('lft = null, rgt = null')\n    Note.rebuild!\n    \n    assert_equal Note.roots.find_by_body('A'), root\n    assert_equal [child1, child2], Note.roots.find_by_body('A').children\n  end\n  \n  def test_same_scope_with_multi_scopes\n    assert_nothing_raised do\n      notes(:scope1).same_scope?(notes(:child_1))\n    end\n    assert notes(:scope1).same_scope?(notes(:child_1))\n    assert notes(:child_1).same_scope?(notes(:scope1))\n    assert !notes(:scope1).same_scope?(notes(:scope2))\n  end\n  \n  def test_quoting_of_multi_scope_column_names\n    assert_equal [\"\\\"notable_id\\\"\", \"\\\"notable_type\\\"\"], Note.quoted_scope_column_names\n  end\n  \n  def test_equal_in_same_scope\n    assert_equal notes(:scope1), notes(:scope1)\n    assert_not_equal notes(:scope1), notes(:child_1)\n  end\n  \n  def test_equal_in_different_scopes\n    assert_not_equal notes(:scope1), notes(:scope2)\n  end\n  \nend\n"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/test/db/database.yml",
    "content": "sqlite3:\n  adapter: sqlite3\n  dbfile: awesome_nested_set.sqlite3.db\nsqlite3mem:\n  :adapter: sqlite3\n  :dbfile: \":memory:\"\npostgresql:\n  :adapter: postgresql\n  :username: postgres\n  :password: postgres\n  :database: awesome_nested_set_plugin_test\n  :min_messages: ERROR\nmysql:\n  :adapter: mysql\n  :host: localhost\n  :username: root\n  :password:\n  :database: awesome_nested_set_plugin_test"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/test/db/schema.rb",
    "content": "ActiveRecord::Schema.define(:version => 0) do\n\n  create_table :categories, :force => true do |t|\n    t.column :name, :string\n    t.column :parent_id, :integer\n    t.column :lft, :integer\n    t.column :rgt, :integer\n    t.column :organization_id, :integer\n  end\n\n  create_table :departments, :force => true do |t|\n    t.column :name, :string\n  end\n  \n  create_table :notes, :force => true do |t|\n    t.column :body, :text\n    t.column :parent_id, :integer\n    t.column :lft, :integer\n    t.column :rgt, :integer\n    t.column :notable_id, :integer\n    t.column :notable_type, :string\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/test/fixtures/categories.yml",
    "content": "top_level:\n  id: 1\n  name: Top Level\n  lft: 1\n  rgt: 10\nchild_1:\n  id: 2\n  name: Child 1\n  parent_id: 1\n  lft: 2\n  rgt: 3\nchild_2:\n  id: 3\n  name: Child 2\n  parent_id: 1\n  lft: 4\n  rgt: 7\nchild_2_1:\n  id: 4\n  name: Child 2.1\n  parent_id: 3\n  lft: 5\n  rgt: 6\nchild_3:\n  id: 5\n  name: Child 3\n  parent_id: 1\n  lft: 8\n  rgt: 9\ntop_level_2:\n  id: 6\n  name: Top Level 2\n  lft: 11\n  rgt: 12\n"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/test/fixtures/category.rb",
    "content": "class Category < ActiveRecord::Base\n  acts_as_nested_set\n  \n  def to_s\n    name\n  end\n  \n  def recurse &block\n    block.call self, lambda{\n      self.children.each do |child|\n        child.recurse &block\n      end\n    }\n  end\nend"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/test/fixtures/departments.yml",
    "content": "top:\n  id: 1\n  name: Top"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/test/fixtures/notes.yml",
    "content": "scope1:\n  id: 1\n  body: Top Level\n  lft: 1\n  rgt: 10\n  notable_id: 1\n  notable_type: Category\nchild_1:\n  id: 2\n  body: Child 1\n  parent_id: 1\n  lft: 2\n  rgt: 3\n  notable_id: 1\n  notable_type: Category\nchild_2:\n  id: 3\n  body: Child 2\n  parent_id: 1\n  lft: 4\n  rgt: 7\n  notable_id: 1\n  notable_type: Category\nchild_3:\n  id: 4\n  body: Child 3\n  parent_id: 1\n  lft: 8\n  rgt: 9\n  notable_id: 1\n  notable_type: Category\nscope2:\n  id: 5\n  body: Top Level 2\n  lft: 1\n  rgt: 2\n  notable_id: 1\n  notable_type: Departments\n"
  },
  {
    "path": "vendor/plugins/awesome_nested_set/test/test_helper.rb",
    "content": "$:.unshift(File.dirname(__FILE__) + '/../lib')\nplugin_test_dir = File.dirname(__FILE__)\n\nrequire 'rubygems'\nrequire 'test/unit'\nrequire 'multi_rails_init'\n# gem 'activerecord', '>= 2.0'\nrequire 'active_record' \nrequire 'action_controller'\nrequire 'action_view'\nrequire 'active_record/fixtures'\n\nrequire plugin_test_dir + '/../init.rb'\n\nActiveRecord::Base.logger = Logger.new(plugin_test_dir + \"/debug.log\")\n\nActiveRecord::Base.configurations = YAML::load(IO.read(plugin_test_dir + \"/db/database.yml\"))\nActiveRecord::Base.establish_connection(ENV[\"DB\"] || \"sqlite3mem\")\nActiveRecord::Migration.verbose = false\nload(File.join(plugin_test_dir, \"db\", \"schema.rb\"))\n\nDir[\"#{plugin_test_dir}/fixtures/*.rb\"].each {|file| require file }\n\n\nclass Test::Unit::TestCase #:nodoc:\n  self.fixture_path = File.dirname(__FILE__) + \"/fixtures/\"\n  self.use_transactional_fixtures = true\n  self.use_instantiated_fixtures  = false\n  \n  fixtures :categories, :notes, :departments\nend"
  },
  {
    "path": "vendor/plugins/classic_pagination/CHANGELOG",
    "content": "* Exported the changelog of Pagination code for historical reference.\n\n* Imported some patches from Rails Trac (others closed as \"wontfix\"):\n  #8176, #7325, #7028, #4113. Documentation is much cleaner now and there\n  are some new unobtrusive features!\n\n* Extracted Pagination from Rails trunk (r6795)\n\n#\n# ChangeLog for /trunk/actionpack/lib/action_controller/pagination.rb \n# \n# Generated by Trac 0.10.3\n# 05/20/07 23:48:02\n#\n\n09/03/06 23:28:54 david [4953]\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\tDocs and deprecation\n\n08/07/06 12:40:14 bitsweat [4715]\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\tDeprecate direct usage of @params. Update ActionView::Base for\n\tinstance var deprecation.\n\n06/21/06 02:16:11 rick [4476]\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\tFix indent in pagination documentation. Closes #4990.  [Kevin Clark]\n\n04/25/06 17:42:48 marcel [4268]\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\tRemove all remaining references to @params in the documentation.\n\n03/16/06 06:38:08 rick [3899]\n\t* trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified)\n\ttrivial documentation patch for #pagination_links [Francois\n\tBeausoleil] closes #4258\n\n02/20/06 03:15:22 david [3620]\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\t* trunk/actionpack/test/activerecord/pagination_test.rb (modified)\n\t* trunk/activerecord/CHANGELOG (modified)\n\t* trunk/activerecord/lib/active_record/base.rb (modified)\n\t* trunk/activerecord/test/base_test.rb (modified)\n\tAdded :count option to pagination that'll make it possible for the\n\tActiveRecord::Base.count call to using something else than * for the\n\tcount. Especially important for count queries using DISTINCT #3839\n\t[skaes]. Added :select option to Base.count that'll allow you to\n\tselect something else than * to be counted on. Especially important\n\tfor count queries using DISTINCT (closes #3839) [skaes].\n\n02/09/06 09:17:40 nzkoz [3553]\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\t* trunk/actionpack/test/active_record_unit.rb (added)\n\t* trunk/actionpack/test/activerecord (added)\n\t* trunk/actionpack/test/activerecord/active_record_assertions_test.rb (added)\n\t* trunk/actionpack/test/activerecord/pagination_test.rb (added)\n\t* trunk/actionpack/test/controller/active_record_assertions_test.rb (deleted)\n\t* trunk/actionpack/test/fixtures/companies.yml (added)\n\t* trunk/actionpack/test/fixtures/company.rb (added)\n\t* trunk/actionpack/test/fixtures/db_definitions (added)\n\t* trunk/actionpack/test/fixtures/db_definitions/sqlite.sql (added)\n\t* trunk/actionpack/test/fixtures/developer.rb (added)\n\t* trunk/actionpack/test/fixtures/developers_projects.yml (added)\n\t* trunk/actionpack/test/fixtures/developers.yml (added)\n\t* trunk/actionpack/test/fixtures/project.rb (added)\n\t* trunk/actionpack/test/fixtures/projects.yml (added)\n\t* trunk/actionpack/test/fixtures/replies.yml (added)\n\t* trunk/actionpack/test/fixtures/reply.rb (added)\n\t* trunk/actionpack/test/fixtures/topic.rb (added)\n\t* trunk/actionpack/test/fixtures/topics.yml (added)\n\t* Fix pagination problems when using include\n\t* Introduce Unit Tests for pagination\n\t* Allow count to work with :include by using count distinct.\n\n\t[Kevin Clark &amp; Jeremy Hopple]\n\n11/05/05 02:10:29 bitsweat [2878]\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\tUpdate paginator docs.  Closes #2744.\n\n10/16/05 15:42:03 minam [2649]\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\tUpdate/clean up AP documentation (rdoc)\n\n08/31/05 00:13:10 ulysses [2078]\n\t* trunk/actionpack/CHANGELOG (modified)\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\tAdd option to specify the singular name used by pagination. Closes\n\t#1960\n\n08/23/05 14:24:15 minam [2041]\n\t* trunk/actionpack/CHANGELOG (modified)\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\tAdd support for :include with pagination (subject to existing\n\tconstraints for :include with :limit and :offset) #1478\n\t[michael@schubert.cx]\n\n07/15/05 20:27:38 david [1839]\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\t* trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified)\n\tMore pagination speed #1334 [Stefan Kaes]\n\n07/14/05 08:02:01 david [1832]\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\t* trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified)\n\t* trunk/actionpack/test/controller/addresses_render_test.rb (modified)\n\tMade pagination faster #1334 [Stefan Kaes]\n\n04/13/05 05:40:22 david [1159]\n\t* trunk/actionpack/CHANGELOG (modified)\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\t* trunk/activerecord/lib/active_record/base.rb (modified)\n\tFixed pagination to work with joins #1034 [scott@sigkill.org]\n\n04/02/05 09:11:17 david [1067]\n\t* trunk/actionpack/CHANGELOG (modified)\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\t* trunk/actionpack/lib/action_controller/scaffolding.rb (modified)\n\t* trunk/actionpack/lib/action_controller/templates/scaffolds/list.rhtml (modified)\n\t* trunk/railties/lib/rails_generator/generators/components/scaffold/templates/controller.rb (modified)\n\t* trunk/railties/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml (modified)\n\tAdded pagination for scaffolding (10 items per page) #964\n\t[mortonda@dgrmm.net]\n\n03/31/05 14:46:11 david [1048]\n\t* trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified)\n\tImproved the message display on the exception handler pages #963\n\t[Johan Sorensen]\n\n03/27/05 00:04:07 david [1017]\n\t* trunk/actionpack/CHANGELOG (modified)\n\t* trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified)\n\tFixed that pagination_helper would ignore :params #947 [Sebastian\n\tKanthak]\n\n03/22/05 13:09:44 david [976]\n\t* trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified)\n\tFixed documentation and prepared for 0.11.0 release\n\n03/21/05 14:35:36 david [967]\n\t* trunk/actionpack/lib/action_controller/pagination.rb (modified)\n\t* trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (modified)\n\tTweaked the documentation\n\n03/20/05 23:12:05 david [949]\n\t* trunk/actionpack/CHANGELOG (modified)\n\t* trunk/actionpack/lib/action_controller.rb (modified)\n\t* trunk/actionpack/lib/action_controller/pagination.rb (added)\n\t* trunk/actionpack/lib/action_view/helpers/pagination_helper.rb (added)\n\t* trunk/activesupport/lib/active_support/core_ext/kernel.rb (added)\n\tAdded pagination support through both a controller and helper add-on\n\t#817 [Sam Stephenson]\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/README",
    "content": "Pagination\n==========\n\nTo install:\n\n  script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination\n\nThis code was extracted from Rails trunk after the release 1.2.3.\nWARNING: this code is dead. It is unmaintained, untested and full of cruft.\n\nThere is a much better pagination plugin called will_paginate.\nInstall it like this and glance through the README:\n\n  script/plugin install svn://errtheblog.com/svn/plugins/will_paginate\n\nIt doesn't have the same API, but is in fact much nicer. You can\nhave both plugins installed until you change your controller/view code that\nhandles pagination. Then, simply uninstall classic_pagination.\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/Rakefile",
    "content": "require 'rake'\nrequire 'rake/testtask'\nrequire 'rake/rdoctask'\n\ndesc 'Default: run unit tests.'\ntask :default => :test\n\ndesc 'Test the classic_pagination plugin.'\nRake::TestTask.new(:test) do |t|\n  t.libs << 'lib'\n  t.pattern = 'test/**/*_test.rb'\n  t.verbose = true\nend\n\ndesc 'Generate documentation for the classic_pagination plugin.'\nRake::RDocTask.new(:rdoc) do |rdoc|\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title    = 'Pagination'\n  rdoc.options << '--line-numbers' << '--inline-source'\n  rdoc.rdoc_files.include('README')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/init.rb",
    "content": "#--\n# Copyright (c) 2004-2006 David Heinemeier Hansson\n#\n# Permission is hereby granted, free of charge, to any person obtaining\n# a copy of this software and associated documentation files (the\n# \"Software\"), to deal in the Software without restriction, including\n# without limitation the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the Software, and to\n# permit persons to whom the Software is furnished to do so, subject to\n# the following conditions:\n#\n# The above copyright notice and this permission notice shall be\n# included in all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n#++\n\nrequire 'pagination'\nrequire 'pagination_helper'\n\nActionController::Base.class_eval do\n  include ActionController::Pagination\nend\n\nActionView::Base.class_eval do\n  include ActionView::Helpers::PaginationHelper\nend\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/install.rb",
    "content": "puts \"\\n\\n\" + File.read(File.dirname(__FILE__) + '/README')\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/lib/pagination.rb",
    "content": "module ActionController\n  # === Action Pack pagination for Active Record collections\n  #\n  # The Pagination module aids in the process of paging large collections of\n  # Active Record objects. It offers macro-style automatic fetching of your\n  # model for multiple views, or explicit fetching for single actions. And if\n  # the magic isn't flexible enough for your needs, you can create your own\n  # paginators with a minimal amount of code.\n  #\n  # The Pagination module can handle as much or as little as you wish. In the\n  # controller, have it automatically query your model for pagination; or,\n  # if you prefer, create Paginator objects yourself.\n  #\n  # Pagination is included automatically for all controllers.\n  #\n  # For help rendering pagination links, see \n  # ActionView::Helpers::PaginationHelper.\n  #\n  # ==== Automatic pagination for every action in a controller\n  #\n  #   class PersonController < ApplicationController   \n  #     model :person\n  #\n  #     paginate :people, :order => 'last_name, first_name',\n  #              :per_page => 20\n  #     \n  #     # ...\n  #   end\n  #\n  # Each action in this controller now has access to a <tt>@people</tt>\n  # instance variable, which is an ordered collection of model objects for the\n  # current page (at most 20, sorted by last name and first name), and a \n  # <tt>@person_pages</tt> Paginator instance. The current page is determined\n  # by the <tt>params[:page]</tt> variable.\n  #\n  # ==== Pagination for a single action\n  #\n  #   def list\n  #     @person_pages, @people =\n  #       paginate :people, :order => 'last_name, first_name'\n  #   end\n  #\n  # Like the previous example, but explicitly creates <tt>@person_pages</tt>\n  # and <tt>@people</tt> for a single action, and uses the default of 10 items\n  # per page.\n  #\n  # ==== Custom/\"classic\" pagination \n  #\n  #   def list\n  #     @person_pages = Paginator.new self, Person.count, 10, params[:page]\n  #     @people = Person.find :all, :order => 'last_name, first_name', \n  #                           :limit  =>  @person_pages.items_per_page,\n  #                           :offset =>  @person_pages.current.offset\n  #   end\n  # \n  # Explicitly creates the paginator from the previous example and uses \n  # Paginator#to_sql to retrieve <tt>@people</tt> from the model.\n  #\n  module Pagination\n    unless const_defined?(:OPTIONS)\n      # A hash holding options for controllers using macro-style pagination\n      OPTIONS = Hash.new\n  \n      # The default options for pagination\n      DEFAULT_OPTIONS = {\n        :class_name => nil,\n        :singular_name => nil,\n        :per_page   => 10,\n        :conditions => nil,\n        :order_by   => nil,\n        :order      => nil,\n        :join       => nil,\n        :joins      => nil,\n        :count      => nil,\n        :include    => nil,\n        :select     => nil,\n        :group      => nil,\n        :parameter  => 'page'\n      }\n    else\n      DEFAULT_OPTIONS[:group] = nil\n    end\n      \n    def self.included(base) #:nodoc:\n      super\n      base.extend(ClassMethods)\n    end\n  \n    def self.validate_options!(collection_id, options, in_action) #:nodoc:\n      options.merge!(DEFAULT_OPTIONS) {|key, old, new| old}\n\n      valid_options = DEFAULT_OPTIONS.keys\n      valid_options << :actions unless in_action\n    \n      unknown_option_keys = options.keys - valid_options\n      raise ActionController::ActionControllerError,\n            \"Unknown options: #{unknown_option_keys.join(', ')}\" unless\n              unknown_option_keys.empty?\n\n      options[:singular_name] ||= ActiveSupport::Inflector.singularize(collection_id.to_s)\n      options[:class_name]  ||= ActiveSupport::Inflector.camelize(options[:singular_name])\n    end\n\n    # Returns a paginator and a collection of Active Record model instances\n    # for the paginator's current page. This is designed to be used in a\n    # single action; to automatically paginate multiple actions, consider\n    # ClassMethods#paginate.\n    #\n    # +options+ are:\n    # <tt>:singular_name</tt>:: the singular name to use, if it can't be inferred by singularizing the collection name\n    # <tt>:class_name</tt>:: the class name to use, if it can't be inferred by\n    #                        camelizing the singular name\n    # <tt>:per_page</tt>::   the maximum number of items to include in a \n    #                        single page. Defaults to 10\n    # <tt>:conditions</tt>:: optional conditions passed to Model.find(:all, *params) and\n    #                        Model.count\n    # <tt>:order</tt>::      optional order parameter passed to Model.find(:all, *params)\n    # <tt>:order_by</tt>::   (deprecated, used :order) optional order parameter passed to Model.find(:all, *params)\n    # <tt>:joins</tt>::      optional joins parameter passed to Model.find(:all, *params)\n    #                        and Model.count\n    # <tt>:join</tt>::       (deprecated, used :joins or :include) optional join parameter passed to Model.find(:all, *params)\n    #                        and Model.count\n    # <tt>:include</tt>::    optional eager loading parameter passed to Model.find(:all, *params)\n    #                        and Model.count\n    # <tt>:select</tt>::     :select parameter passed to Model.find(:all, *params)\n    #\n    # <tt>:count</tt>::      parameter passed as :select option to Model.count(*params)\n    #\n    # <tt>:group</tt>::     :group parameter passed to Model.find(:all, *params). It forces the use of DISTINCT instead of plain COUNT to come up with the total number of records\n    #\n    def paginate(collection_id, options={})\n      Pagination.validate_options!(collection_id, options, true)\n      paginator_and_collection_for(collection_id, options)\n    end\n\n    # These methods become class methods on any controller \n    module ClassMethods\n      # Creates a +before_filter+ which automatically paginates an Active\n      # Record model for all actions in a controller (or certain actions if\n      # specified with the <tt>:actions</tt> option).\n      #\n      # +options+ are the same as PaginationHelper#paginate, with the addition \n      # of:\n      # <tt>:actions</tt>:: an array of actions for which the pagination is\n      #                     active. Defaults to +nil+ (i.e., every action)\n      def paginate(collection_id, options={})\n        Pagination.validate_options!(collection_id, options, false)\n        module_eval do\n          before_filter :create_paginators_and_retrieve_collections\n          OPTIONS[self] ||= Hash.new\n          OPTIONS[self][collection_id] = options\n        end\n      end\n    end\n\n    def create_paginators_and_retrieve_collections #:nodoc:\n      Pagination::OPTIONS[self.class].each do |collection_id, options|\n        next unless options[:actions].include? action_name if\n          options[:actions]\n\n        paginator, collection = \n          paginator_and_collection_for(collection_id, options)\n\n        paginator_name = \"@#{options[:singular_name]}_pages\"\n        self.instance_variable_set(paginator_name, paginator)\n\n        collection_name = \"@#{collection_id.to_s}\"\n        self.instance_variable_set(collection_name, collection)     \n      end\n    end\n  \n    # Returns the total number of items in the collection to be paginated for\n    # the +model+ and given +conditions+. Override this method to implement a\n    # custom counter.\n    def count_collection_for_pagination(model, options)\n      model.count(:conditions => options[:conditions],\n                  :joins => options[:join] || options[:joins],\n                  :include => options[:include],\n                  :select => (options[:group] ? \"DISTINCT #{options[:group]}\" : options[:count]))\n    end\n    \n    # Returns a collection of items for the given +model+ and +options[conditions]+,\n    # ordered by +options[order]+, for the current page in the given +paginator+.\n    # Override this method to implement a custom finder.\n    def find_collection_for_pagination(model, options, paginator)\n      model.find(:all, :conditions => options[:conditions],\n                 :order => options[:order_by] || options[:order],\n                 :joins => options[:join] || options[:joins], :include => options[:include],\n                 :select => options[:select], :limit => options[:per_page],\n                 :group => options[:group], :offset => paginator.current.offset)\n    end\n  \n    protected :create_paginators_and_retrieve_collections,\n              :count_collection_for_pagination,\n              :find_collection_for_pagination\n\n    def paginator_and_collection_for(collection_id, options) #:nodoc:\n      klass = options[:class_name].constantize\n      page  = params[options[:parameter]]\n      count = count_collection_for_pagination(klass, options)\n      paginator = Paginator.new(self, count, options[:per_page], page)\n      collection = find_collection_for_pagination(klass, options, paginator)\n    \n      return paginator, collection \n    end\n      \n    private :paginator_and_collection_for\n\n    # A class representing a paginator for an Active Record collection.\n    class Paginator\n      include Enumerable\n\n      # Creates a new Paginator on the given +controller+ for a set of items\n      # of size +item_count+ and having +items_per_page+ items per page.\n      # Raises ArgumentError if items_per_page is out of bounds (i.e., less\n      # than or equal to zero). The page CGI parameter for links defaults to\n      # \"page\" and can be overridden with +page_parameter+.\n      def initialize(controller, item_count, items_per_page, current_page=1)\n        raise ArgumentError, 'must have at least one item per page' if\n          items_per_page <= 0\n\n        @controller = controller\n        @item_count = item_count || 0\n        @items_per_page = items_per_page\n        @pages = {}\n        \n        self.current_page = current_page\n      end\n      attr_reader :controller, :item_count, :items_per_page\n      \n      # Sets the current page number of this paginator. If +page+ is a Page\n      # object, its +number+ attribute is used as the value; if the page does \n      # not belong to this Paginator, an ArgumentError is raised.\n      def current_page=(page)\n        if page.is_a? Page\n          raise ArgumentError, 'Page/Paginator mismatch' unless\n            page.paginator == self\n        end\n        page = page.to_i\n        @current_page_number = has_page_number?(page) ? page : 1\n      end\n\n      # Returns a Page object representing this paginator's current page.\n      def current_page\n        @current_page ||= self[@current_page_number]\n      end\n      alias current :current_page\n\n      # Returns a new Page representing the first page in this paginator.\n      def first_page\n        @first_page ||= self[1]\n      end\n      alias first :first_page\n\n      # Returns a new Page representing the last page in this paginator.\n      def last_page\n        @last_page ||= self[page_count] \n      end\n      alias last :last_page\n\n      # Returns the number of pages in this paginator.\n      def page_count\n        @page_count ||= @item_count.zero? ? 1 :\n                          (q,r=@item_count.divmod(@items_per_page); r==0? q : q+1)\n      end\n\n      alias length :page_count\n\n      # Returns true if this paginator contains the page of index +number+.\n      def has_page_number?(number)\n        number >= 1 and number <= page_count\n      end\n\n      # Returns a new Page representing the page with the given index\n      # +number+.\n      def [](number)\n        @pages[number] ||= Page.new(self, number)\n      end\n\n      # Successively yields all the paginator's pages to the given block.\n      def each(&block)\n        page_count.times do |n|\n          yield self[n+1]\n        end\n      end\n\n      # A class representing a single page in a paginator.\n      class Page\n        include Comparable\n\n        # Creates a new Page for the given +paginator+ with the index\n        # +number+. If +number+ is not in the range of valid page numbers or\n        # is not a number at all, it defaults to 1.\n        def initialize(paginator, number)\n          @paginator = paginator\n          @number = number.to_i\n          @number = 1 unless @paginator.has_page_number? @number\n        end\n        attr_reader :paginator, :number\n        alias to_i :number\n\n        # Compares two Page objects and returns true when they represent the \n        # same page (i.e., their paginators are the same and they have the\n        # same page number).\n        def ==(page)\n          return false if page.nil?\n          @paginator == page.paginator and \n            @number == page.number\n        end\n\n        # Compares two Page objects and returns -1 if the left-hand page comes\n        # before the right-hand page, 0 if the pages are equal, and 1 if the\n        # left-hand page comes after the right-hand page. Raises ArgumentError\n        # if the pages do not belong to the same Paginator object.\n        def <=>(page)\n          raise ArgumentError unless @paginator == page.paginator\n          @number <=> page.number\n        end\n\n        # Returns the item offset for the first item in this page.\n        def offset\n          @paginator.items_per_page * (@number - 1)\n        end\n        \n        # Returns the number of the first item displayed.\n        def first_item\n          offset + 1\n        end\n        \n        # Returns the number of the last item displayed.\n        def last_item\n          [@paginator.items_per_page * @number, @paginator.item_count].min\n        end\n\n        # Returns true if this page is the first page in the paginator.\n        def first?\n          self == @paginator.first\n        end\n\n        # Returns true if this page is the last page in the paginator.\n        def last?\n          self == @paginator.last\n        end\n\n        # Returns a new Page object representing the page just before this\n        # page, or nil if this is the first page.\n        def previous\n          if first? then nil else @paginator[@number - 1] end\n        end\n\n        # Returns a new Page object representing the page just after this\n        # page, or nil if this is the last page.\n        def next\n          if last? then nil else @paginator[@number + 1] end\n        end\n\n        # Returns a new Window object for this page with the specified \n        # +padding+.\n        def window(padding=2)\n          Window.new(self, padding)\n        end\n\n        # Returns the limit/offset array for this page.\n        def to_sql\n          [@paginator.items_per_page, offset]\n        end\n        \n        def to_param #:nodoc:\n          @number.to_s\n        end\n      end\n\n      # A class for representing ranges around a given page.\n      class Window\n        # Creates a new Window object for the given +page+ with the specified\n        # +padding+.\n        def initialize(page, padding=2)\n          @paginator = page.paginator\n          @page = page\n          self.padding = padding\n        end\n        attr_reader :paginator, :page\n\n        # Sets the window's padding (the number of pages on either side of the\n        # window page).\n        def padding=(padding)\n          @padding = padding < 0 ? 0 : padding\n          # Find the beginning and end pages of the window\n          @first = @paginator.has_page_number?(@page.number - @padding) ?\n            @paginator[@page.number - @padding] : @paginator.first\n          @last =  @paginator.has_page_number?(@page.number + @padding) ?\n            @paginator[@page.number + @padding] : @paginator.last\n        end\n        attr_reader :padding, :first, :last\n\n        # Returns an array of Page objects in the current window.\n        def pages\n          (@first.number..@last.number).to_a.collect! {|n| @paginator[n]}\n        end\n        alias to_a :pages\n      end\n    end\n\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/lib/pagination_helper.rb",
    "content": "module ActionView\n  module Helpers\n    # Provides methods for linking to ActionController::Pagination objects using a simple generator API.  You can optionally\n    # also build your links manually using ActionView::Helpers::AssetHelper#link_to like so:\n    #\n    # <%= link_to \"Previous page\", { :page => paginator.current.previous } if paginator.current.previous %>\n    # <%= link_to \"Next page\", { :page => paginator.current.next } if paginator.current.next %>\n    module PaginationHelper\n      unless const_defined?(:DEFAULT_OPTIONS)\n        DEFAULT_OPTIONS = {\n          :name => :page,\n          :window_size => 2,\n          :always_show_anchors => true,\n          :link_to_current_page => false,\n          :params => {}\n        }\n      end\n\n      # Creates a basic HTML link bar for the given +paginator+.  Links will be created\n      # for the next and/or previous page and for a number of other pages around the current\n      # pages position. The +html_options+ hash is passed to +link_to+ when the links are created.\n      #\n      # ==== Options\n      # <tt>:name</tt>::                 the routing name for this paginator\n      #                                  (defaults to +page+)\n      # <tt>:prefix</tt>::               prefix for pagination links\n      #                                  (i.e. Older Pages: 1 2 3 4)\n      # <tt>:suffix</tt>::               suffix for pagination links\n      #                                  (i.e. 1 2 3 4 <- Older Pages)\n      # <tt>:window_size</tt>::          the number of pages to show around \n      #                                  the current page (defaults to <tt>2</tt>)\n      # <tt>:always_show_anchors</tt>::  whether or not the first and last\n      #                                  pages should always be shown\n      #                                  (defaults to +true+)\n      # <tt>:link_to_current_page</tt>:: whether or not the current page\n      #                                  should be linked to (defaults to\n      #                                  +false+)\n      # <tt>:params</tt>::               any additional routing parameters\n      #                                  for page URLs\n      #\n      # ==== Examples\n      #  # We'll assume we have a paginator setup in @person_pages...\n      #\n      #  pagination_links(@person_pages)\n      #  # => 1 <a href=\"/?page=2/\">2</a> <a href=\"/?page=3/\">3</a>  ... <a href=\"/?page=10/\">10</a>\n      #\n      #  pagination_links(@person_pages, :link_to_current_page => true)\n      #  # => <a href=\"/?page=1/\">1</a> <a href=\"/?page=2/\">2</a> <a href=\"/?page=3/\">3</a>  ... <a href=\"/?page=10/\">10</a>\n      #\n      #  pagination_links(@person_pages, :always_show_anchors => false)\n      #  # => 1 <a href=\"/?page=2/\">2</a> <a href=\"/?page=3/\">3</a> \n      #\n      #  pagination_links(@person_pages, :window_size => 1)\n      #  # => 1 <a href=\"/?page=2/\">2</a>  ... <a href=\"/?page=10/\">10</a>\n      #\n      #  pagination_links(@person_pages, :params => { :viewer => \"flash\" })\n      #  # => 1 <a href=\"/?page=2&amp;viewer=flash/\">2</a> <a href=\"/?page=3&amp;viewer=flash/\">3</a>  ... \n      #  #    <a href=\"/?page=10&amp;viewer=flash/\">10</a>\n      def pagination_links(paginator, options={}, html_options={})\n        name = options[:name] || DEFAULT_OPTIONS[:name]\n        params = (options[:params] || DEFAULT_OPTIONS[:params]).clone\n        \n        prefix = options[:prefix] || ''\n        suffix = options[:suffix] || ''\n\n        pagination_links_each(paginator, options, prefix, suffix) do |n|\n          params[name] = n\n          link_to(n.to_s, params, html_options)\n        end\n      end\n\n      # Iterate through the pages of a given +paginator+, invoking a\n      # block for each page number that needs to be rendered as a link.\n      # \n      # ==== Options\n      # <tt>:window_size</tt>::          the number of pages to show around \n      #                                  the current page (defaults to +2+)\n      # <tt>:always_show_anchors</tt>::  whether or not the first and last\n      #                                  pages should always be shown\n      #                                  (defaults to +true+)\n      # <tt>:link_to_current_page</tt>:: whether or not the current page\n      #                                  should be linked to (defaults to\n      #                                  +false+)\n      #\n      # ==== Example\n      #  # Turn paginated links into an Ajax call\n      #  pagination_links_each(paginator, page_options) do |link|\n      #    options = { :url => {:action => 'list'}, :update => 'results' }\n      #    html_options = { :href => url_for(:action => 'list') }\n      #\n      #    link_to_remote(link.to_s, options, html_options)\n      #  end\n      def pagination_links_each(paginator, options, prefix = nil, suffix = nil)\n        options = DEFAULT_OPTIONS.merge(options)\n        link_to_current_page = options[:link_to_current_page]\n        always_show_anchors = options[:always_show_anchors]\n\n        current_page = paginator.current_page\n        window_pages = current_page.window(options[:window_size]).pages\n        return if window_pages.length <= 1 unless link_to_current_page\n        \n        first, last = paginator.first, paginator.last\n        \n        html = ''\n\n        html << prefix if prefix\n\n        if always_show_anchors and not (wp_first = window_pages[0]).first?\n          html << yield(first.number)\n          html << ' ... ' if wp_first.number - first.number > 1\n          html << ' '\n        end\n          \n        window_pages.each do |page|\n          if current_page == page && !link_to_current_page\n            html << page.number.to_s\n          else\n            html << yield(page.number)\n          end\n          html << ' '\n        end\n        \n        if always_show_anchors and not (wp_last = window_pages[-1]).last? \n          html << ' ... ' if last.number - wp_last.number > 1\n          html << yield(last.number)\n        end\n\n        html << suffix if suffix\n\n        html\n      end\n      \n    end # PaginationHelper\n  end # Helpers\nend # ActionView\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/companies.yml",
    "content": "thirty_seven_signals:\n  id: 1\n  name: 37Signals\n  rating: 4\n\nTextDrive:\n  id: 2\n  name: TextDrive\n  rating: 4\n\nPlanetArgon:\n  id: 3\n  name: Planet Argon\n  rating: 4\n\nGoogle:\n  id: 4\n  name: Google\n  rating: 4\n  \nIonist:\n  id: 5\n  name: Ioni.st\n  rating: 4"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/company.rb",
    "content": "class Company < ActiveRecord::Base\n  attr_protected :rating\n  set_sequence_name :companies_nonstd_seq\n\n  validates_presence_of :name\n  def validate\n    errors.add('rating', 'rating should not be 2') if rating == 2\n  end  \nend"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/developer.rb",
    "content": "class Developer < ActiveRecord::Base\n  has_and_belongs_to_many :projects\nend\n\nclass DeVeLoPeR < ActiveRecord::Base\n  set_table_name \"developers\"\nend\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/developers.yml",
    "content": "david:\n  id: 1\n  name: David\n  salary: 80000\n\njamis:\n  id: 2\n  name: Jamis\n  salary: 150000\n\n<% for digit in 3..10 %>\ndev_<%= digit %>:\n  id: <%= digit %>\n  name: fixture_<%= digit %>\n  salary: 100000\n<% end %>\n\npoor_jamis:\n  id: 11\n  name: Jamis\n  salary: 9000"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/developers_projects.yml",
    "content": "david_action_controller:\n  developer_id: 1\n  project_id: 2\n  joined_on: 2004-10-10\n\ndavid_active_record:\n  developer_id: 1\n  project_id: 1\n  joined_on: 2004-10-10\n\njamis_active_record:\n  developer_id: 2\n  project_id: 1"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/project.rb",
    "content": "class Project < ActiveRecord::Base\n  has_and_belongs_to_many :developers, :uniq => true\nend\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/projects.yml",
    "content": "action_controller:\n  id: 2\n  name: Active Controller\n\nactive_record:\n  id: 1\n  name: Active Record\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/replies.yml",
    "content": "witty_retort:\n  id: 1\n  topic_id: 1\n  content: Birdman is better!\n  created_at: <%= 6.hours.ago.to_s(:db) %>\n  updated_at: nil\n  \nanother:\n  id: 2\n  topic_id: 2\n  content: Nuh uh!\n  created_at: <%= 1.hour.ago.to_s(:db) %>\n  updated_at: nil"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/reply.rb",
    "content": "class Reply < ActiveRecord::Base\n  belongs_to :topic, :include => [:replies]\n  \n  validates_presence_of :content\nend\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/schema.sql",
    "content": "CREATE TABLE 'companies' (\n  'id' INTEGER PRIMARY KEY NOT NULL,\n  'name' TEXT DEFAULT NULL,\n  'rating' INTEGER DEFAULT 1\n);\n\nCREATE TABLE 'replies' (\n  'id' INTEGER PRIMARY KEY NOT NULL, \n  'content' text, \n  'created_at' datetime, \n  'updated_at' datetime, \n  'topic_id' integer\n);\n\nCREATE TABLE 'topics' (\n  'id' INTEGER PRIMARY KEY NOT NULL, \n  'title' varchar(255), \n  'subtitle' varchar(255), \n  'content' text, \n  'created_at' datetime, \n  'updated_at' datetime\n);\n\nCREATE TABLE 'developers' (\n  'id' INTEGER PRIMARY KEY NOT NULL,\n  'name' TEXT DEFAULT NULL,\n  'salary' INTEGER DEFAULT 70000,\n  'created_at' DATETIME DEFAULT NULL,\n  'updated_at' DATETIME DEFAULT NULL\n);\n\nCREATE TABLE 'projects' (\n  'id' INTEGER PRIMARY KEY NOT NULL,\n  'name' TEXT DEFAULT NULL\n);\n\nCREATE TABLE 'developers_projects' (\n  'developer_id' INTEGER NOT NULL,\n  'project_id' INTEGER NOT NULL,\n  'joined_on' DATE DEFAULT NULL,\n  'access_level' INTEGER DEFAULT 1\n);\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/topic.rb",
    "content": "class Topic < ActiveRecord::Base\n  has_many :replies, :include => [:user], :dependent => :destroy\nend\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/fixtures/topics.yml",
    "content": "futurama:\n  id: 1\n  title: Isnt futurama awesome?\n  subtitle: It really is, isnt it.\n  content: I like futurama\n  created_at: <%= 1.day.ago.to_s(:db) %>\n  updated_at:\n  \nharvey_birdman:\n  id: 2\n  title: Harvey Birdman is the king of all men\n  subtitle: yup\n  content: It really is\n  created_at: <%= 2.hours.ago.to_s(:db) %>\n  updated_at:\n\nrails:\n  id: 3\n  title: Rails is nice\n  subtitle: It makes me happy\n  content: except when I have to hack internals to fix pagination. even then really.\n  created_at: <%= 20.minutes.ago.to_s(:db) %>\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/helper.rb",
    "content": "require 'test/unit'\n\nunless defined?(ActiveRecord)\n  plugin_root = File.join(File.dirname(__FILE__), '..')\n\n  # first look for a symlink to a copy of the framework\n  if framework_root = [\"#{plugin_root}/rails\", \"#{plugin_root}/../../rails\"].find { |p| File.directory? p }\n    puts \"found framework root: #{framework_root}\"\n    # this allows for a plugin to be tested outside an app\n    $:.unshift \"#{framework_root}/activesupport/lib\", \"#{framework_root}/activerecord/lib\", \"#{framework_root}/actionpack/lib\"\n  else\n    # is the plugin installed in an application?\n    app_root = plugin_root + '/../../..'\n\n    if File.directory? app_root + '/config'\n      puts 'using config/boot.rb'\n      ENV['RAILS_ENV'] = 'test'\n      require File.expand_path(app_root + '/config/boot')\n    else\n      # simply use installed gems if available\n      puts 'using rubygems'\n      require 'rubygems'\n      gem 'actionpack'; gem 'activerecord'\n    end\n  end\n\n  %w(action_pack active_record action_controller active_record/fixtures action_controller/test_process).each {|f| require f}\n\n  Dependencies.load_paths.unshift \"#{plugin_root}/lib\"\nend\n\n# Define the connector\nclass ActiveRecordTestConnector\n  cattr_accessor :able_to_connect\n  cattr_accessor :connected\n\n  # Set our defaults\n  self.connected = false\n  self.able_to_connect = true\n\n  class << self\n    def setup\n      unless self.connected || !self.able_to_connect\n        setup_connection\n        load_schema\n        require_fixture_models\n        self.connected = true\n      end\n    rescue Exception => e  # errors from ActiveRecord setup\n      $stderr.puts \"\\nSkipping ActiveRecord assertion tests: #{e}\"\n      #$stderr.puts \"  #{e.backtrace.join(\"\\n  \")}\\n\"\n      self.able_to_connect = false\n    end\n\n    private\n\n    def setup_connection\n      if Object.const_defined?(:ActiveRecord)\n        defaults = { :database => ':memory:' }\n        begin\n          options = defaults.merge :adapter => 'sqlite3', :timeout => 500\n          ActiveRecord::Base.establish_connection(options)\n          ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options }\n          ActiveRecord::Base.connection\n        rescue Exception  # errors from establishing a connection\n          $stderr.puts 'SQLite 3 unavailable; trying SQLite 2.'\n          options = defaults.merge :adapter => 'sqlite'\n          ActiveRecord::Base.establish_connection(options)\n          ActiveRecord::Base.configurations = { 'sqlite2_ar_integration' => options }\n          ActiveRecord::Base.connection\n        end\n\n        Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE)\n      else\n        raise \"Can't setup connection since ActiveRecord isn't loaded.\"\n      end\n    end\n\n    # Load actionpack sqlite tables\n    def load_schema\n      File.read(File.dirname(__FILE__) + \"/fixtures/schema.sql\").split(';').each do |sql|\n        ActiveRecord::Base.connection.execute(sql) unless sql.blank?\n      end\n    end\n\n    def require_fixture_models\n      Dir.glob(File.dirname(__FILE__) + \"/fixtures/*.rb\").each {|f| require f}\n    end\n  end\nend\n\n# Test case for inheritance\nclass ActiveRecordTestCase < Test::Unit::TestCase\n  # Set our fixture path\n  if ActiveRecordTestConnector.able_to_connect\n    self.fixture_path = \"#{File.dirname(__FILE__)}/fixtures/\"\n    self.use_transactional_fixtures = false\n  end\n\n  def self.fixtures(*args)\n    super if ActiveRecordTestConnector.connected\n  end\n\n  def run(*args)\n    super if ActiveRecordTestConnector.connected\n  end\n\n  # Default so Test::Unit::TestCase doesn't complain\n  def test_truth\n  end\nend\n\nActiveRecordTestConnector.setup\nActionController::Routing::Routes.reload rescue nil\nActionController::Routing::Routes.draw do |map|\n  map.connect ':controller/:action/:id'\nend\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/pagination_helper_test.rb",
    "content": "require File.dirname(__FILE__) + '/helper'\nrequire File.dirname(__FILE__) + '/../init'\n\nclass PaginationHelperTest < Test::Unit::TestCase\n  include ActionController::Pagination\n  include ActionView::Helpers::PaginationHelper\n  include ActionView::Helpers::UrlHelper\n  include ActionView::Helpers::TagHelper\n\n  def setup\n    @controller = Class.new do\n      attr_accessor :url, :request\n      def url_for(options, *parameters_for_method_reference)\n        url\n      end\n    end\n    @controller = @controller.new\n    @controller.url = \"http://www.example.com\"\n  end\n\n  def test_pagination_links\n    total, per_page, page = 30, 10, 1\n    output = pagination_links Paginator.new(@controller, total, per_page, page)\n    assert_equal \"1 <a href=\\\"http://www.example.com\\\">2</a> <a href=\\\"http://www.example.com\\\">3</a> \", output\n  end\n\n  def test_pagination_links_with_prefix\n    total, per_page, page = 30, 10, 1\n    output = pagination_links Paginator.new(@controller, total, per_page, page), :prefix => 'Newer '\n    assert_equal \"Newer 1 <a href=\\\"http://www.example.com\\\">2</a> <a href=\\\"http://www.example.com\\\">3</a> \", output\n  end\n\n  def test_pagination_links_with_suffix\n    total, per_page, page = 30, 10, 1\n    output = pagination_links Paginator.new(@controller, total, per_page, page), :suffix => 'Older'\n    assert_equal \"1 <a href=\\\"http://www.example.com\\\">2</a> <a href=\\\"http://www.example.com\\\">3</a> Older\", output\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/classic_pagination/test/pagination_test.rb",
    "content": "require File.dirname(__FILE__) + '/helper'\nrequire File.dirname(__FILE__) + '/../init'\n\nclass PaginationTest < ActiveRecordTestCase\n  fixtures :topics, :replies, :developers, :projects, :developers_projects\n  \n  class PaginationController < ActionController::Base\n    if respond_to? :view_paths=\n      self.view_paths = [ \"#{File.dirname(__FILE__)}/../fixtures/\" ]\n    else\n      self.template_root = [ \"#{File.dirname(__FILE__)}/../fixtures/\" ]\n    end\n    \n    def simple_paginate\n      @topic_pages, @topics = paginate(:topics)\n      render :nothing => true\n    end\n    \n    def paginate_with_per_page\n      @topic_pages, @topics = paginate(:topics, :per_page => 1)\n      render :nothing => true\n    end\n    \n    def paginate_with_order\n      @topic_pages, @topics = paginate(:topics, :order => 'created_at asc')\n      render :nothing => true\n    end\n    \n    def paginate_with_order_by\n      @topic_pages, @topics = paginate(:topics, :order_by => 'created_at asc')\n      render :nothing => true\n    end\n    \n    def paginate_with_include_and_order\n      @topic_pages, @topics = paginate(:topics, :include => :replies, :order => 'replies.created_at asc, topics.created_at asc')\n      render :nothing => true\n    end\n    \n    def paginate_with_conditions\n      @topic_pages, @topics = paginate(:topics, :conditions => [\"created_at > ?\", 30.minutes.ago])\n      render :nothing => true\n    end\n    \n    def paginate_with_class_name\n      @developer_pages, @developers = paginate(:developers, :class_name => \"DeVeLoPeR\")\n      render :nothing => true\n    end\n    \n    def paginate_with_singular_name\n      @developer_pages, @developers = paginate()\n      render :nothing => true\n    end\n    \n    def paginate_with_joins\n      @developer_pages, @developers = paginate(:developers, \n                                             :joins => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id',\n                                             :conditions => 'project_id=1')        \n      render :nothing => true\n    end\n    \n    def paginate_with_join\n      @developer_pages, @developers = paginate(:developers, \n                                             :join => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id',\n                                             :conditions => 'project_id=1')        \n      render :nothing => true\n    end\n     \n    def paginate_with_join_and_count\n      @developer_pages, @developers = paginate(:developers, \n                                             :join => 'd LEFT JOIN developers_projects ON d.id = developers_projects.developer_id',\n                                             :conditions => 'project_id=1',\n                                             :count => \"d.id\")        \n      render :nothing => true\n    end\n\n    def paginate_with_join_and_group\n      @developer_pages, @developers = paginate(:developers, \n                                             :join => 'INNER JOIN developers_projects ON developers.id = developers_projects.developer_id',\n                                             :group => 'developers.id')\n      render :nothing => true\n    end\n    \n    def rescue_errors(e) raise e end\n\n    def rescue_action(e) raise end\n    \n  end\n  \n  def setup\n    @controller = PaginationController.new\n    @request    = ActionController::TestRequest.new\n    @response   = ActionController::TestResponse.new\n    super\n  end\n\n  # Single Action Pagination Tests\n\n  def test_simple_paginate\n    get :simple_paginate\n    assert_equal 1, assigns(:topic_pages).page_count\n    assert_equal 3, assigns(:topics).size\n  end\n  \n  def test_paginate_with_per_page\n    get :paginate_with_per_page\n    assert_equal 1, assigns(:topics).size\n    assert_equal 3, assigns(:topic_pages).page_count\n  end\n  \n  def test_paginate_with_order\n    get :paginate_with_order\n    expected = [topics(:futurama),\n               topics(:harvey_birdman),\n               topics(:rails)]\n    assert_equal expected, assigns(:topics)\n    assert_equal 1, assigns(:topic_pages).page_count\n  end\n  \n  def test_paginate_with_order_by\n    get :paginate_with_order\n    expected = assigns(:topics)\n    get :paginate_with_order_by\n    assert_equal expected, assigns(:topics)  \n    assert_equal 1, assigns(:topic_pages).page_count    \n  end\n  \n  def test_paginate_with_conditions\n    get :paginate_with_conditions\n    expected = [topics(:rails)]\n    assert_equal expected, assigns(:topics)\n    assert_equal 1, assigns(:topic_pages).page_count\n  end\n  \n  def test_paginate_with_class_name\n    get :paginate_with_class_name\n    \n    assert assigns(:developers).size > 0\n    assert_equal DeVeLoPeR, assigns(:developers).first.class\n  end\n      \n  def test_paginate_with_joins\n    get :paginate_with_joins\n    assert_equal 2, assigns(:developers).size\n    developer_names = assigns(:developers).map { |d| d.name }\n    assert developer_names.include?('David')\n    assert developer_names.include?('Jamis')\n  end\n  \n  def test_paginate_with_join_and_conditions\n    get :paginate_with_joins\n    expected = assigns(:developers)\n    get :paginate_with_join\n    assert_equal expected, assigns(:developers)\n  end\n  \n  def test_paginate_with_join_and_count\n    get :paginate_with_joins\n    expected = assigns(:developers)\n    get :paginate_with_join_and_count\n    assert_equal expected, assigns(:developers)\n  end\n  \n  def test_paginate_with_include_and_order\n    get :paginate_with_include_and_order\n    expected = Topic.find(:all, :include => 'replies', :order => 'replies.created_at asc, topics.created_at asc', :limit => 10)\n    assert_equal expected, assigns(:topics)\n  end\n\n  def test_paginate_with_join_and_group\n    get :paginate_with_join_and_group\n    assert_equal 2, assigns(:developers).size\n    assert_equal 2, assigns(:developer_pages).item_count\n    developer_names = assigns(:developers).map { |d| d.name }\n    assert developer_names.include?('David')\n    assert developer_names.include?('Jamis')\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/FOLDERS",
    "content": "= CodeRay - Trunk folder structure\n\n== bench - Benchmarking system\n\nAll benchmarking stuff goes here.\n\nTest inputs are stored in files named <code>example.<lang></code>.\nTest outputs go to <code>bench/test.<encoder-default-file-extension></code>.\n\nRun <code>bench/bench.rb</code> to get a usage description.\n\nRun <code>rake bench</code> to perform an example benchmark.\n\n\n== bin - Scripts\n\nExecutional files for CodeRay.\n\n\n== demo - Demos and functional tests\n\nDemonstrational scripts to show of CodeRay's features.\n\nRun them as functional tests with <code>rake test:demos</code>.\n\n\n== etc - Lots of stuff\n\nSome addidtional files for CodeRay, mainly graphics and Vim scripts.\n\n\n== gem_server - Gem output folder\n\nFor <code>rake gem</code>.\n\n\n== lib - CodeRay library code\n\nThis is the base directory for the CodeRay library.\n\n\n== rake_helpers - Rake helper libraries\n\nSome files to enhance Rake, including the Autumnal Rdoc template and some scripts.\n\n\n== test - Tests\n\nTests for the scanners.\n\nEach language has its own subfolder and sub-suite.\n\nRun with <code>rake test</code>.\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/LICENSE",
    "content": "                  GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 2.1, February 1999\n\n Copyright (C) 1991, 1999 Free Software Foundation, Inc.\n 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the Lesser GPL.  It also counts\n as the successor of the GNU Library Public License, version 2, hence\n the version number 2.1.]\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n  This license, the Lesser General Public License, applies to some\nspecially designated software packages--typically libraries--of the\nFree Software Foundation and other authors who decide to use it.  You\ncan use it too, but we suggest you first think carefully about whether\nthis license or the ordinary General Public License is the better\nstrategy to use in any particular case, based on the explanations below.\n\n  When we speak of free software, we are referring to freedom of use,\nnot price.  Our General Public Licenses are designed to make sure that\nyou have the freedom to distribute copies of free software (and charge\nfor this service if you wish); that you receive source code or can get\nit if you want it; that you can change the software and use pieces of\nit in new free programs; and that you are informed that you can do\nthese things.\n\n  To protect your rights, we need to make restrictions that forbid\ndistributors to deny you these rights or to ask you to surrender these\nrights.  These restrictions translate to certain responsibilities for\nyou if you distribute copies of the library or if you modify it.\n\n  For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou.  You must make sure that they, too, receive or can get the source\ncode.  If you link other code with the library, you must provide\ncomplete object files to the recipients, so that they can relink them\nwith the library after making changes to the library and recompiling\nit.  And you must show them these terms so they know their rights.\n\n  We protect your rights with a two-step method: (1) we copyright the\nlibrary, and (2) we offer you this license, which gives you legal\npermission to copy, distribute and/or modify the library.\n\n  To protect each distributor, we want to make it very clear that\nthere is no warranty for the free library.  Also, if the library is\nmodified by someone else and passed on, the recipients should know\nthat what they have is not the original version, so that the original\nauthor's reputation will not be affected by problems that might be\nintroduced by others.\n\f\n  Finally, software patents pose a constant threat to the existence of\nany free program.  We wish to make sure that a company cannot\neffectively restrict the users of a free program by obtaining a\nrestrictive license from a patent holder.  Therefore, we insist that\nany patent license obtained for a version of the library must be\nconsistent with the full freedom of use specified in this license.\n\n  Most GNU software, including some libraries, is covered by the\nordinary GNU General Public License.  This license, the GNU Lesser\nGeneral Public License, applies to certain designated libraries, and\nis quite different from the ordinary General Public License.  We use\nthis license for certain libraries in order to permit linking those\nlibraries into non-free programs.\n\n  When a program is linked with a library, whether statically or using\na shared library, the combination of the two is legally speaking a\ncombined work, a derivative of the original library.  The ordinary\nGeneral Public License therefore permits such linking only if the\nentire combination fits its criteria of freedom.  The Lesser General\nPublic License permits more lax criteria for linking other code with\nthe library.\n\n  We call this license the \"Lesser\" General Public License because it\ndoes Less to protect the user's freedom than the ordinary General\nPublic License.  It also provides other free software developers Less\nof an advantage over competing non-free programs.  These disadvantages\nare the reason we use the ordinary General Public License for many\nlibraries.  However, the Lesser license provides advantages in certain\nspecial circumstances.\n\n  For example, on rare occasions, there may be a special need to\nencourage the widest possible use of a certain library, so that it becomes\na de-facto standard.  To achieve this, non-free programs must be\nallowed to use the library.  A more frequent case is that a free\nlibrary does the same job as widely used non-free libraries.  In this\ncase, there is little to gain by limiting the free library to free\nsoftware only, so we use the Lesser General Public License.\n\n  In other cases, permission to use a particular library in non-free\nprograms enables a greater number of people to use a large body of\nfree software.  For example, permission to use the GNU C Library in\nnon-free programs enables many more people to use the whole GNU\noperating system, as well as its variant, the GNU/Linux operating\nsystem.\n\n  Although the Lesser General Public License is Less protective of the\nusers' freedom, it does ensure that the user of a program that is\nlinked with the Library has the freedom and the wherewithal to run\nthat program using a modified version of the Library.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.  Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\".  The\nformer contains code derived from the library, whereas the latter must\nbe combined with the library in order to run.\n\f\n                  GNU LESSER GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License Agreement applies to any software library or other\nprogram which contains a notice placed by the copyright holder or\nother authorized party saying it may be distributed under the terms of\nthis Lesser General Public License (also called \"this License\").\nEach licensee is addressed as \"you\".\n\n  A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n  The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms.  A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language.  (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n  \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it.  For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n  Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it).  Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n  \n  1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n  You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\f\n  2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) The modified work must itself be a software library.\n\n    b) You must cause the files modified to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    c) You must cause the whole of the work to be licensed at no\n    charge to all third parties under the terms of this License.\n\n    d) If a facility in the modified Library refers to a function or a\n    table of data to be supplied by an application program that uses\n    the facility, other than as an argument passed when the facility\n    is invoked, then you must make a good faith effort to ensure that,\n    in the event an application does not supply such function or\n    table, the facility still operates, and performs whatever part of\n    its purpose remains meaningful.\n\n    (For example, a function in a library to compute square roots has\n    a purpose that is entirely well-defined independent of the\n    application.  Therefore, Subsection 2d requires that any\n    application-supplied function or table used by this function must\n    be optional: if the application does not supply it, the square\n    root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library.  To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License.  (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.)  Do not make any other change in\nthese notices.\n\f\n  Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n  This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n  4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n  If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\".  Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n  However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\".  The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n  When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library.  The\nthreshold for this to be true is not precisely defined by law.\n\n  If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork.  (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n  Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\f\n  6. As an exception to the Sections above, you may also combine or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n  You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License.  You must supply a copy of this License.  If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License.  Also, you must do one\nof these things:\n\n    a) Accompany the work with the complete corresponding\n    machine-readable source code for the Library including whatever\n    changes were used in the work (which must be distributed under\n    Sections 1 and 2 above); and, if the work is an executable linked\n    with the Library, with the complete machine-readable \"work that\n    uses the Library\", as object code and/or source code, so that the\n    user can modify the Library and then relink to produce a modified\n    executable containing the modified Library.  (It is understood\n    that the user who changes the contents of definitions files in the\n    Library will not necessarily be able to recompile the application\n    to use the modified definitions.)\n\n    b) Use a suitable shared library mechanism for linking with the\n    Library.  A suitable mechanism is one that (1) uses at run time a\n    copy of the library already present on the user's computer system,\n    rather than copying library functions into the executable, and (2)\n    will operate properly with a modified version of the library, if\n    the user installs one, as long as the modified version is\n    interface-compatible with the version that the work was made with.\n\n    c) Accompany the work with a written offer, valid for at\n    least three years, to give the same user the materials\n    specified in Subsection 6a, above, for a charge no more\n    than the cost of performing this distribution.\n\n    d) If distribution of the work is made by offering access to copy\n    from a designated place, offer equivalent access to copy the above\n    specified materials from the same place.\n\n    e) Verify that the user has already received a copy of these\n    materials or that you have already sent this user a copy.\n\n  For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it.  However, as a special exception,\nthe materials to be distributed need not include anything that is\nnormally distributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n  It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system.  Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\f\n  7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n    a) Accompany the combined library with a copy of the same work\n    based on the Library, uncombined with any other library\n    facilities.  This must be distributed under the terms of the\n    Sections above.\n\n    b) Give prominent notice with the combined library of the fact\n    that part of it is a work based on the Library, and explaining\n    where to find the accompanying uncombined form of the same work.\n\n  8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License.  Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License.  However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n  9. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n  10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties with\nthis License.\n\f\n  11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded.  In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n  13. The Free Software Foundation may publish revised and/or new\nversions of the Lesser General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation.  If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\f\n  14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission.  For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this.  Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n                            NO WARRANTY\n\n  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\f\n           How to Apply These Terms to Your New Libraries\n\n  If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change.  You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n  To apply these terms, attach the following notices to the library.  It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the library's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Lesser General Public\n    License as published by the Free Software Foundation; either\n    version 2.1 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Lesser General Public License for more details.\n\n    You should have received a copy of the GNU Lesser General Public\n    License along with this library; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the\n  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n  <signature of Ty Coon>, 1 April 1990\n  Ty Coon, President of Vice\n\nThat's all there is to it!\n\n\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/README",
    "content": "= CodeRay\n\n[- Tired of blue'n'gray? Try the original version of this documentation on\nhttp://rd.cYcnus.de/coderay/doc (use Ctrl+Click to open it in its own frame.) -]\n\n== About\nCodeRay is a Ruby library for syntax highlighting.\n\nSyntax highlighting means: You put your code in, and you get it back colored;\nKeywords, strings, floats, comments - all in different colors.\nAnd with line numbers.\n\n*Syntax* *Highlighting*...\n* makes code easier to read and maintain\n* lets you detect syntax errors faster\n* helps you to understand the syntax of a language\n* looks nice\n* is what everybody should have on their website\n* solves all your problems and makes the girls run after you\n\nVersion: 0.7.4 (2006.october.20)\nAuthor:: murphy (Kornelius Kalnbach)\nContact:: murphy rubychan de\nWebsite:: coderay.rubychan.de[http://coderay.rubychan.de]\nLicense:: GNU LGPL; see LICENSE file in the main directory.\nSubversion:: $Id: README 219 2006-10-20 15:52:25Z murphy $\n\n-----\n\n== Installation\n\nYou need RubyGems[http://rubyforge.org/frs/?group_id=126].\n\n % gem install coderay\n\nSince CodeRay is still in beta stage, nightly buildy may be useful:\n\n % gem install coderay -rs rd.cYcnus.de/coderay\n\n\n=== Dependencies\n\nCodeRay needs Ruby 1.8 and the\nstrscan[http://www.ruby-doc.org/stdlib/libdoc/strscan/rdoc/index.htm]\nlibrary (part of the standard library.)  It should also run with Ruby 1.9 and\nyarv.\n\n\n== Example Usage\n(Forgive me, but this is not highlighted.)\n\n require 'coderay'\n \n tokens = CodeRay.scan \"puts 'Hello, world!'\", :ruby\n page = tokens.html :line_numbers => :inline, :wrap => :page\n puts page\n\n\n== Documentation\n\nSee CodeRay.\n\nPlease report errors in this documentation to <coderay cycnus de>.\n\n\n-----\n\n== Credits\n\n=== Special Thanks to\n\n* licenser (Heinz N. Gies) for ending my QBasic career, inventing the Coder\n  project and the input/output plugin system.\n  CodeRay would not exist without him.\n\n=== Thanks to\n\n* Caleb Clausen for writing RubyLexer (see\n  http://rubyforge.org/projects/rubylexer) and lots of very interesting mail\n  traffic\n* birkenfeld (Georg Brandl) and mitsuhiku (Arnim Ronacher) for PyKleur. You\n  guys rock!\n* Jamis Buck for writing Syntax (see http://rubyforge.org/projects/syntax)\n  I got some useful ideas from it.\n* Doug Kearns and everyone else who worked on ruby.vim - it not only helped me\n  coding CodeRay, but also gave me a wonderful target to reach for the Ruby\n  scanner.\n* everyone who used CodeBB on http://www.rubyforen.de and\n  http://www.infhu.de/mx\n* iGEL, magichisoka, manveru, WoNDo and everyone I forgot from rubyforen.de\n* Daniel and Dethix from ruby-mine.de\n* Dookie (who is no longer with us...) and Leonidas from\n  http://www.python-forum.de\n* Andreas Schwarz for finding out that CaseIgnoringWordList was not case\n  ignoring! Such things really make you write tests.\n* matz and all Ruby gods and gurus\n* The inventors of: the computer, the internet, the true color display, HTML &\n  CSS, VIM, RUBY, pizza, microwaves, guitars, scouting, programming, anime, \n  manga, coke and green ice tea.\n\nWhere would we be without all those people?\n\n=== Created using\n\n* Ruby[http://ruby-lang.org/]\n* Chihiro (my Sony VAIO laptop), Henrietta (my new MacBook) and\n  Seras (my Athlon 2200+ tower)\n* VIM[http://vim.org] and TextMate[http://macromates.com]\n* RDE[http://homepage2.nifty.com/sakazuki/rde_e.html]\n* Microsoft Windows (yes, I confess!) and MacOS X\n* Firefox[http://www.mozilla.org/products/firefox/] and\n  Thunderbird[http://www.mozilla.org/products/thunderbird/]\n* Rake[http://rake.rubyforge.org/]\n* RubyGems[http://docs.rubygems.org/]\n* {Subversion/TortoiseSVN}[http://tortoisesvn.tigris.org/] using Apache via\n  XAMPP[http://www.apachefriends.org/en/xampp.html]\n* RDoc (though I'm quite unsatisfied with it)\n* GNUWin32, MinGW and some other tools to make the shell under windows a bit\n  more useful\n* Term::ANSIColor[http://term-ansicolor.rubyforge.org/]\n\n---\n\n* As you can see, CodeRay was created under heavy use of *free* software.\n* So CodeRay is also *free*.\n* If you use CodeRay to create software, think about making this software\n  *free*, too.\n* Thanks :)\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/bin/coderay",
    "content": "#!/usr/bin/env ruby\n# CodeRay Executable\n#\n# Version: 0.1\n# Author: murphy\n\ndef err msg\n  $stderr.puts msg\nend\n\nbegin\n  require 'coderay'\n\n  if ARGV.empty?\n    puts <<-USAGE\nCodeRay #{CodeRay::VERSION} (http://rd.cYcnus.de/coderay)\nUsage:\n  coderay -<lang> [-<format>] < file > output\n  coderay file [-<format>]\nExample:\n  coderay -ruby -statistic < foo.rb\n  coderay codegen.c  # generates codegen.c.html\n    USAGE\n  end\n\n  first, second = ARGV\n\n  if first\n    if first[/-(\\w+)/] == first\n      lang = $1.to_sym\n      input = $stdin.read\n      tokens = :scan\n    elsif first == '-'\n      lang = $1.to_sym\n      input = $stdin.read\n      tokens = :scan\n    else\n      file = first\n      tokens = CodeRay.scan_file file\n      output_filename, output_ext = file, /#{Regexp.escape(File.extname(file))}$/\n    end\n  else\n    puts 'No lang/file given.'\n    exit 1\n  end\n\n  if second\n    if second[/-(\\w+)/] == second\n      format = $1.to_sym\n    else\n      raise 'Invalid format (must be -xxx).'\n    end\n  else\n    $stderr.puts 'No format given; setting to default (HTML Page)'\n    format = :page\n  end\n  \n  # TODO: allow streaming\n  if tokens == :scan\n    output = CodeRay::Duo[lang => format].highlight input  #, :stream => true\n  else\n    output = tokens.encode format\n  end\n  out = $stdout\n  if output_filename\n    output_filename += '.' + CodeRay::Encoders[format]::FILE_EXTENSION\n    if File.exist? output_filename\n      err 'File %s already exists.' % output_filename\n      exit\n    else\n      out = File.open output_filename, 'w'\n    end\n  end\n  out.print output\n\nrescue => boom\n  err \"Error: #{boom.message}\\n\"\n  err boom.backtrace\n  err '-' * 50\n  err ARGV\n  exit 1\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/bin/coderay_stylesheet",
    "content": "#!/usr/bin/env ruby\nrequire 'coderay'\n\nputs CodeRay::Encoders[:html]::CSS.new.stylesheet\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/duo.rb",
    "content": "module CodeRay\n  \n  # = Duo\n  #\n  # $Id: scanner.rb 123 2006-03-21 14:46:34Z murphy $\n  #\n  # A Duo is a convenient way to use CodeRay. You just create a Duo,\n  # giving it a lang (language of the input code) and a format (desired\n  # output format), and call Duo#highlight with the code.\n  # \n  # Duo makes it easy to re-use both scanner and encoder for a repetitive\n  # task. It also provides a very easy interface syntax:\n  # \n  #   require 'coderay'\n  #   CodeRay::Duo[:python, :div].highlight 'import this'\n  # \n  # Until you want to do uncommon things with CodeRay, I recommend to use\n  # this method, since it takes care of everything.\n  class Duo\n\n    attr_accessor :lang, :format, :options\n    \n    # Create a new Duo, holding a lang and a format to highlight code.\n    # \n    # simple:\n    #   CodeRay::Duo[:ruby, :page].highlight 'bla 42'\n    # \n    # streaming:\n    #   CodeRay::Duo[:ruby, :page].highlight 'bar 23', :stream => true\n    # \n    # with options:\n    #   CodeRay::Duo[:ruby, :html, :hint => :debug].highlight '????::??'\n    # \n    # alternative syntax without options:\n    #   CodeRay::Duo[:ruby => :statistic].encode 'class << self; end'\n    # \n    # alternative syntax with options:\n    #   CodeRay::Duo[{ :ruby => :statistic }, :do => :something].encode 'abc'\n    # \n    # The options are forwarded to scanner and encoder\n    # (see CodeRay.get_scanner_options).\n    def initialize lang = nil, format = nil, options = {}\n      if format == nil and lang.is_a? Hash and lang.size == 1\n        @lang = lang.keys.first\n        @format = lang[@lang]\n      else\n        @lang = lang\n        @format = format\n      end\n      @options = options\n    end\n\n    class << self\n      # To allow calls like Duo[:ruby, :html].highlight.\n      alias [] new\n    end\n\n    # The scanner of the duo. Only created once.\n    def scanner\n      @scanner ||= CodeRay.scanner @lang, CodeRay.get_scanner_options(@options)\n    end\n    \n    # The encoder of the duo. Only created once.\n    def encoder\n      @encoder ||= CodeRay.encoder @format, @options\n    end\n    \n    # Tokenize and highlight the code using +scanner+ and +encoder+.\n    #\n    # If the :stream option is set, the Duo will go into streaming mode,\n    # saving memory for the cost of time.\n    def encode code, options = { :stream => false }\n      stream = options.delete :stream\n      options = @options.merge options\n      if stream\n        encoder.encode_stream(code, @lang, options)\n      else\n        scanner.code = code\n        encoder.encode_tokens(scanner.tokenize, options)\n      end\n    end\n    alias highlight encode\n\n  end\n\nend\n\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoder.rb",
    "content": "require \"stringio\"\n\nmodule CodeRay\n\n  # This module holds the Encoder class and its subclasses.\n  # For example, the HTML encoder is named CodeRay::Encoders::HTML\n  # can be found in coderay/encoders/html.\n  #\n  # Encoders also provides methods and constants for the register\n  # mechanism and the [] method that returns the Encoder class\n  # belonging to the given format.\n  module Encoders\n    extend PluginHost\n    plugin_path File.dirname(__FILE__), 'encoders'\n\n    # = Encoder\n    #\n    # The Encoder base class. Together with Scanner and\n    # Tokens, it forms the highlighting triad.\n    #\n    # Encoder instances take a Tokens object and do something with it.\n    #\n    # The most common Encoder is surely the HTML encoder\n    # (CodeRay::Encoders::HTML). It highlights the code in a colorful\n    # html page.\n    # If you want the highlighted code in a div or a span instead,\n    # use its subclasses Div and Span.\n    class Encoder\n      extend Plugin\n      plugin_host Encoders\n\n      attr_reader :token_stream\n\n      class << self\n\n        # Returns if the Encoder can be used in streaming mode.\n        def streamable?\n          is_a? Streamable\n        end\n\n        # If FILE_EXTENSION isn't defined, this method returns the\n        # downcase class name instead.\n        def const_missing sym\n          if sym == :FILE_EXTENSION\n            plugin_id\n          else\n            super\n          end\n        end\n\n      end\n\n      # Subclasses are to store their default options in this constant.\n      DEFAULT_OPTIONS = { :stream => false }\n\n      # The options you gave the Encoder at creating.\n      attr_accessor :options\n\n      # Creates a new Encoder.\n      # +options+ is saved and used for all encode operations, as long\n      # as you don't overwrite it there by passing additional options.\n      #\n      # Encoder objects provide three encode methods:\n      # - encode simply takes a +code+ string and a +lang+\n      # - encode_tokens expects a +tokens+ object instead\n      # - encode_stream is like encode, but uses streaming mode.\n      #\n      # Each method has an optional +options+ parameter. These are\n      # added to the options you passed at creation.\n      def initialize options = {}\n        @options = self.class::DEFAULT_OPTIONS.merge options\n        raise \"I am only the basic Encoder class. I can't encode \"\\\n          \"anything. :( Use my subclasses.\" if self.class == Encoder\n      end\n\n      # Encode a Tokens object.\n      def encode_tokens tokens, options = {}\n        options = @options.merge options\n        setup options\n        compile tokens, options\n        finish options\n      end\n\n      # Encode the given +code+ after tokenizing it using the Scanner\n      # for +lang+.\n      def encode code, lang, options = {}\n        options = @options.merge options\n        scanner_options = CodeRay.get_scanner_options(options)\n        tokens = CodeRay.scan code, lang, scanner_options\n        encode_tokens tokens, options\n      end\n\n      # You can use highlight instead of encode, if that seems\n      # more clear to you.\n      alias highlight encode\n\n      # Encode the given +code+ using the Scanner for +lang+ in\n      # streaming mode.\n      def encode_stream code, lang, options = {}\n        raise NotStreamableError, self unless kind_of? Streamable\n        options = @options.merge options\n        setup options\n        scanner_options = CodeRay.get_scanner_options options\n        @token_stream =\n          CodeRay.scan_stream code, lang, scanner_options, &self\n        finish options\n      end\n\n      # Behave like a proc. The token method is converted to a proc.\n      def to_proc\n        method(:token).to_proc\n      end\n\n      # Return the default file extension for outputs of this encoder.\n      def file_extension\n        self.class::FILE_EXTENSION\n      end\n\n    protected\n\n      # Called with merged options before encoding starts.\n      # Sets @out to an empty string.\n      #\n      # See the HTML Encoder for an example of option caching.\n      def setup options\n        @out = ''\n      end\n\n      # Called with +text+ and +kind+ of the currently scanned token.\n      # For simple scanners, it's enougth to implement this method.\n      #\n      # By default, it calls text_token or block_token, depending on\n      # whether +text+ is a String.\n      def token text, kind\n        out =\n          if text.is_a? ::String  # Ruby 1.9: :open.is_a? String\n            text_token text, kind\n          elsif text.is_a? ::Symbol\n            block_token text, kind\n          else\n            raise 'Unknown token text type: %p' % text\n          end\n        @out << out if @out\n      end\n\n      def text_token text, kind\n      end\n\n      def block_token action, kind\n        case action\n        when :open\n          open_token kind\n        when :close\n          close_token kind\n        else\n          raise 'unknown block action: %p' % action\n        end\n      end\n\n      # Called with merged options after encoding starts.\n      # The return value is the result of encoding, typically @out.\n      def finish options\n        @out\n      end\n\n      # Do the encoding.\n      #\n      # The already created +tokens+ object must be used; it can be a\n      # TokenStream or a Tokens object.\n      def compile tokens, options\n        tokens.each(&self)\n      end\n\n    end\n\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/_map.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  map :stats => :statistic,\n    :plain => :text,\n    :tex => :latex\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/count.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  class Count < Encoder\n\n    include Streamable\n    register_for :count\n\n    protected\n\n    def setup options\n      @out = 0\n    end\n\n    def token text, kind\n      @out += 1\n    end\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/debug.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  # = Debug Encoder\n  #\n  # Fast encoder producing simple debug output.\n  #\n  # It is readable and diff-able and is used for testing.\n  #\n  # You cannot fully restore the tokens information from the\n  # output, because consecutive :space tokens are merged.\n  # Use Tokens#dump for caching purposes.\n  class Debug < Encoder\n\n    include Streamable\n    register_for :debug\n\n    FILE_EXTENSION = 'raydebug'\n\n  protected\n    def text_token text, kind\n      if kind == :space\n        text\n      else\n        text = text.gsub(/[)\\\\]/, '\\\\\\\\\\0')  # escape ) and \\\n        \"#{kind}(#{text})\"\n      end\n    end\n\n    def open_token kind\n      \"#{kind}<\"\n    end\n\n    def close_token kind\n      \">\"\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/div.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  load :html\n\n  class Div < HTML\n\n    FILE_EXTENSION = 'div.html'\n\n    register_for :div\n\n    DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge({\n      :css => :style,\n      :wrap => :div,\n    })\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/html/css.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  class HTML\n    class CSS\n\n      attr :stylesheet\n\n      def CSS.load_stylesheet style = nil\n        CodeRay::Styles[style]\n      end\n\n      def initialize style = :default\n        @classes = Hash.new\n        style = CSS.load_stylesheet style\n        @stylesheet = [\n          style::CSS_MAIN_STYLES,\n          style::TOKEN_COLORS.gsub(/^(?!$)/, '.CodeRay ')\n        ].join(\"\\n\")\n        parse style::TOKEN_COLORS\n      end\n\n      def [] *styles\n        cl = @classes[styles.first]\n        return '' unless cl\n        style = ''\n        1.upto(styles.size) do |offset|\n          break if style = cl[styles[offset .. -1]]\n        end\n        raise 'Style not found: %p' % [styles] if $DEBUG and style.empty?\n        return style\n      end\n\n    private\n\n      CSS_CLASS_PATTERN = /\n        ( (?:                # $1 = classes\n          \\s* \\. [-\\w]+\n        )+ )\n        \\s* \\{ \\s*\n        ( [^\\}]+ )?          # $2 = style\n        \\s* \\} \\s*\n      |\n        ( . )                # $3 = error\n      /mx\n      def parse stylesheet\n        stylesheet.scan CSS_CLASS_PATTERN do |classes, style, error|\n          raise \"CSS parse error: '#{error.inspect}' not recognized\" if error\n          styles = classes.scan(/[-\\w]+/)\n          cl = styles.pop\n          @classes[cl] ||= Hash.new\n          @classes[cl][styles] = style.to_s.strip\n        end\n      end\n\n    end\n  end\n\nend\nend\n\nif $0 == __FILE__\n  require 'pp'\n  pp CodeRay::Encoders::HTML::CSS.new\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/html/numerization.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  class HTML\n\n    module Output\n\n      def numerize *args\n        clone.numerize!(*args)\n      end\n\n=begin      NUMERIZABLE_WRAPPINGS = {\n        :table => [:div, :page, nil],\n        :inline => :all,\n        :list => [:div, :page, nil]\n      }\n      NUMERIZABLE_WRAPPINGS.default = :all\n=end\n      def numerize! mode = :table, options = {}\n        return self unless mode\n\n        options = DEFAULT_OPTIONS.merge options\n\n        start = options[:line_number_start]\n        unless start.is_a? Integer\n          raise ArgumentError, \"Invalid value %p for :line_number_start; Integer expected.\" % start\n        end\n\n        #allowed_wrappings = NUMERIZABLE_WRAPPINGS[mode]\n        #unless allowed_wrappings == :all or allowed_wrappings.include? options[:wrap]\n        #  raise ArgumentError, \"Can't numerize, :wrap must be in %p, but is %p\" % [NUMERIZABLE_WRAPPINGS, options[:wrap]]\n        #end\n\n        bold_every = options[:bold_every]\n        bolding =\n          if bold_every == false\n            proc { |line| line.to_s }\n          elsif bold_every.is_a? Integer\n            raise ArgumentError, \":bolding can't be 0.\" if bold_every == 0\n            proc do |line|\n              if line % bold_every == 0\n                \"<strong>#{line}</strong>\"  # every bold_every-th number in bold\n              else\n                line.to_s\n              end\n            end\n          else\n            raise ArgumentError, 'Invalid value %p for :bolding; false or Integer expected.' % bold_every\n          end\n\n        case mode\n        when :inline\n          max_width = (start + line_count).to_s.size\n          line = start\n          gsub!(/^/) do\n            line_number = bolding.call line\n            indent = ' ' * (max_width - line.to_s.size)\n            res = \"<span class=\\\"no\\\">#{indent}#{line_number}</span> \"\n            line += 1\n            res\n          end\n\n        when :table\n          # This is really ugly.\n          # Because even monospace fonts seem to have different heights when bold,\n          # I make the newline bold, both in the code and the line numbers.\n          # FIXME Still not working perfect for Mr. Internet Exploder\n          # FIXME Firefox struggles with very long codes (> 200 lines)\n          line_numbers = (start ... start + line_count).to_a.map(&bolding).join(\"\\n\")\n          line_numbers << \"\\n\"  # also for Mr. MS Internet Exploder :-/\n          line_numbers.gsub!(/\\n/) { \"<tt>\\n</tt>\" }\n\n          line_numbers_table_tpl = TABLE.apply('LINE_NUMBERS', line_numbers)\n          gsub!(/\\n/) { \"<tt>\\n</tt>\" }\n          wrap_in! line_numbers_table_tpl\n          @wrapped_in = :div\n\n        when :list\n          opened_tags = []\n          gsub!(/^.*$\\n?/) do |line|\n            line.chomp!\n\n            open = opened_tags.join\n            line.scan(%r!<(/)?span[^>]*>?!) do |close,|\n              if close\n                opened_tags.pop\n              else\n                opened_tags << $&\n              end\n            end\n            close = '</span>' * opened_tags.size\n\n            \"<li>#{open}#{line}#{close}</li>\"\n          end\n          wrap_in! LIST\n          @wrapped_in = :div\n\n        else\n          raise ArgumentError, 'Unknown value %p for mode: expected one of %p' %\n            [mode, [:table, :list, :inline]]\n        end\n\n        self\n      end\n\n      def line_count\n        line_count = count(\"\\n\")\n        position_of_last_newline = rindex(?\\n)\n        if position_of_last_newline\n          after_last_newline = self[position_of_last_newline + 1 .. -1]\n          ends_with_newline = after_last_newline[/\\A(?:<\\/span>)*\\z/]\n          line_count += 1 if not ends_with_newline\n        end\n        line_count\n      end\n\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/html/output.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  class HTML\n\n    # This module is included in the output String from thew HTML Encoder.\n    #\n    # It provides methods like wrap, div, page etc.\n    #\n    # Remember to use #clone instead of #dup to keep the modules the object was\n    # extended with.\n    #\n    # TODO: more doc.\n    module Output\n\n      require 'coderay/encoders/html/numerization.rb'\n\n      attr_accessor :css\n\n      class << self\n\n        # This makes Output look like a class.\n        #\n        # Example:\n        #\n        #  a = Output.new '<span class=\"co\">Code</span>'\n        #  a.wrap! :page\n        def new string, css = CSS.new, element = nil\n          output = string.clone.extend self\n          output.wrapped_in = element\n          output.css = css\n          output\n        end\n\n        # Raises an exception if an object that doesn't respond to to_str is extended by Output,\n        # to prevent users from misuse. Use Module#remove_method to disable.\n        def extended o\n          warn \"The Output module is intended to extend instances of String, not #{o.class}.\" unless o.respond_to? :to_str\n        end\n\n        def make_stylesheet css, in_tag = false\n          sheet = css.stylesheet\n          sheet = <<-CSS if in_tag\n<style type=\"text/css\">\n#{sheet}\n</style>\n          CSS\n          sheet\n        end\n\n        def page_template_for_css css\n          sheet = make_stylesheet css\n          PAGE.apply 'CSS', sheet\n        end\n\n        # Define a new wrapper. This is meta programming.\n        def wrapper *wrappers\n          wrappers.each do |wrapper|\n            define_method wrapper do |*args|\n              wrap wrapper, *args\n            end\n            define_method \"#{wrapper}!\".to_sym do |*args|\n              wrap! wrapper, *args\n            end\n          end\n        end\n\n      end\n\n      wrapper :div, :span, :page\n\n      def wrapped_in? element\n        wrapped_in == element\n      end\n\n      def wrapped_in\n        @wrapped_in ||= nil\n      end\n      attr_writer :wrapped_in\n\n      def wrap_in template\n        clone.wrap_in! template\n      end\n\n      def wrap_in! template\n        Template.wrap! self, template, 'CONTENT'\n        self\n      end\n\n      def wrap! element, *args\n        return self if not element or element == wrapped_in\n        case element\n        when :div\n          raise \"Can't wrap %p in %p\" % [wrapped_in, element] unless wrapped_in? nil\n          wrap_in! DIV\n        when :span\n          raise \"Can't wrap %p in %p\" % [wrapped_in, element] unless wrapped_in? nil\n          wrap_in! SPAN\n        when :page\n          wrap! :div if wrapped_in? nil\n          raise \"Can't wrap %p in %p\" % [wrapped_in, element] unless wrapped_in? :div\n          wrap_in! Output.page_template_for_css(@css)\n        when nil\n          return self\n        else\n          raise \"Unknown value %p for :wrap\" % element\n        end\n        @wrapped_in = element\n        self\n      end\n\n      def wrap *args\n        clone.wrap!(*args)\n      end\n\n      def stylesheet in_tag = false\n        Output.make_stylesheet @css, in_tag\n      end\n\n      class Template < String\n\n        def self.wrap! str, template, target\n          target = Regexp.new(Regexp.escape(\"<%#{target}%>\"))\n          if template =~ target\n            str[0,0] = $`\n            str << $'\n          else\n            raise \"Template target <%%%p%%> not found\" % target\n          end\n        end\n\n        def apply target, replacement\n          target = Regexp.new(Regexp.escape(\"<%#{target}%>\"))\n          if self =~ target\n            Template.new($` + replacement + $')\n          else\n            raise \"Template target <%%%p%%> not found\" % target\n          end\n        end\n\n        module Simple\n          def ` str  #` <-- for stupid editors\n            Template.new str\n          end\n        end\n      end\n\n      extend Template::Simple\n\n#-- don't include the templates in docu\n\n      SPAN = `<span class=\"CodeRay\"><%CONTENT%></span>`\n\n      DIV = <<-`DIV`\n<div class=\"CodeRay\">\n  <div class=\"code\"><pre><%CONTENT%></pre></div>\n</div>\n      DIV\n\n      TABLE = <<-`TABLE`\n<table class=\"CodeRay\"><tr>\n  <td class=\"line_numbers\" title=\"click to toggle\" onclick=\"with (this.firstChild.style) { display = (display == '') ? 'none' : '' }\"><pre><%LINE_NUMBERS%></pre></td>\n  <td class=\"code\"><pre ondblclick=\"with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }\"><%CONTENT%></pre></td>\n</tr></table>\n      TABLE\n      # title=\"double click to expand\"\n\n      LIST = <<-`LIST`\n<ol class=\"CodeRay\"><%CONTENT%></ol>\n      LIST\n\n      PAGE = <<-`PAGE`\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"de\">\n<head>\n  <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n  <title>CodeRay HTML Encoder Example</title>\n  <style type=\"text/css\">\n<%CSS%>\n  </style>\n</head>\n<body style=\"background-color: white;\">\n\n<%CONTENT%>\n</body>\n</html>\n      PAGE\n\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/html.rb",
    "content": "require \"set\"\n\nmodule CodeRay\nmodule Encoders\n\n  # = HTML Encoder\n  #\n  # This is CodeRay's most important highlighter:\n  # It provides save, fast XHTML generation and CSS support.\n  #\n  # == Usage\n  #\n  #  require 'coderay'\n  #  puts CodeRay.scan('Some /code/', :ruby).html  #-> a HTML page\n  #  puts CodeRay.scan('Some /code/', :ruby).html(:wrap => :span)\n  #  #-> <span class=\"CodeRay\"><span class=\"co\">Some</span> /code/</span>\n  #  puts CodeRay.scan('Some /code/', :ruby).span  #-> the same\n  #  \n  #  puts CodeRay.scan('Some code', :ruby).html(\n  #    :wrap => nil,\n  #    :line_numbers => :inline,\n  #    :css => :style\n  #  )\n  #  #-> <span class=\"no\">1</span>  <span style=\"color:#036; font-weight:bold;\">Some</span> code\n  #\n  # == Options\n  #\n  # === :escape\n  # Escape html entities\n  # Default: true\n  #\n  # === :tab_width\n  # Convert \\t characters to +n+ spaces (a number.)\n  # Default: 8\n  #\n  # === :css\n  # How to include the styles; can be :class or :style.\n  #\n  # Default: :class\n  #\n  # === :wrap\n  # Wrap in :page, :div, :span or nil.\n  #\n  # You can also use Encoders::Div and Encoders::Span.\n  #\n  # Default: nil\n  #\n  # === :line_numbers\n  # Include line numbers in :table, :inline, :list or nil (no line numbers)\n  #\n  # Default: nil\n  #\n  # === :line_number_start\n  # Where to start with line number counting.\n  #\n  # Default: 1\n  #\n  # === :bold_every\n  # Make every +n+-th number appear bold.\n  #\n  # Default: 10\n  #\n  # === :hint\n  # Include some information into the output using the title attribute.\n  # Can be :info (show token type on mouse-over), :info_long (with full path)\n  # or :debug (via inspect).\n  #\n  # Default: false\n  class HTML < Encoder\n\n    include Streamable\n    register_for :html\n\n    FILE_EXTENSION = 'html'\n\n    DEFAULT_OPTIONS = {\n      :escape => true,\n      :tab_width => 8,\n\n      :level => :xhtml,\n      :css => :class,\n\n      :style => :cycnus,\n\n      :wrap => nil,\n\n      :line_numbers => nil,\n      :line_number_start => 1,\n      :bold_every => 10,\n\n      :hint => false,\n    }\n\n    helper :output, :css\n\n    attr_reader :css\n\n  protected\n\n    HTML_ESCAPE = {  #:nodoc:\n      '&' => '&amp;',\n      '\"' => '&quot;',\n      '>' => '&gt;',\n      '<' => '&lt;',\n    }\n\n    # This was to prevent illegal HTML.\n    # Strange chars should still be avoided in codes.\n    evil_chars = Array(0x00...0x20) - [?\\n, ?\\t, ?\\s]\n    evil_chars.each { |i| HTML_ESCAPE[i.chr] = ' ' }\n    #ansi_chars = Array(0x7f..0xff)\n    #ansi_chars.each { |i| HTML_ESCAPE[i.chr] = '&#%d;' % i }\n    # \\x9 (\\t) and \\xA (\\n) not included\n    #HTML_ESCAPE_PATTERN = /[\\t&\"><\\0-\\x8\\xB-\\x1f\\x7f-\\xff]/\n    HTML_ESCAPE_PATTERN = /[\\t\"&><\\0-\\x8\\xB-\\x1f]/\n\n    TOKEN_KIND_TO_INFO = Hash.new { |h, kind|\n      h[kind] =\n        case kind\n        when :pre_constant\n          'Predefined constant'\n        else\n          kind.to_s.gsub(/_/, ' ').gsub(/\\b\\w/) { $&.capitalize }\n        end\n    }\n\n    TRANSPARENT_TOKEN_KINDS = [\n      :delimiter, :modifier, :content, :escape, :inline_delimiter,\n    ].to_set\n\n    # Generate a hint about the given +classes+ in a +hint+ style.\n    #\n    # +hint+ may be :info, :info_long or :debug.\n    def self.token_path_to_hint hint, classes\n      title =\n        case hint\n        when :info\n          TOKEN_KIND_TO_INFO[classes.first]\n        when :info_long\n          classes.reverse.map { |kind| TOKEN_KIND_TO_INFO[kind] }.join('/')\n        when :debug\n          classes.inspect\n        end\n      \" title=\\\"#{title}\\\"\"\n    end\n\n    def setup options\n      super\n\n      @HTML_ESCAPE = HTML_ESCAPE.dup\n      @HTML_ESCAPE[\"\\t\"] = ' ' * options[:tab_width]\n\n      @escape = options[:escape]\n      @opened = [nil]\n      @css = CSS.new options[:style]\n\n      hint = options[:hint]\n      if hint and not [:debug, :info, :info_long].include? hint\n        raise ArgumentError, \"Unknown value %p for :hint; \\\n          expected :info, :debug, false, or nil.\" % hint\n      end\n\n      case options[:css]\n\n      when :class\n        @css_style = Hash.new do |h, k|\n          c = Tokens::ClassOfKind[k.first]\n          if c == :NO_HIGHLIGHT and not hint\n            h[k.dup] = false\n          else\n            title = if hint\n              HTML.token_path_to_hint(hint, k[1..-1] << k.first)\n            else\n              ''\n            end\n            if c == :NO_HIGHLIGHT\n              h[k.dup] = '<span%s>' % [title]\n            else\n              h[k.dup] = '<span%s class=\"%s\">' % [title, c]\n            end\n          end\n        end\n\n      when :style\n        @css_style = Hash.new do |h, k|\n          if k.is_a? ::Array\n            styles = k.dup\n          else\n            styles = [k]\n          end\n          type = styles.first\n          classes = styles.map { |c| Tokens::ClassOfKind[c] }\n          if classes.first == :NO_HIGHLIGHT and not hint\n            h[k] = false\n          else\n            styles.shift if TRANSPARENT_TOKEN_KINDS.include? styles.first\n            title = HTML.token_path_to_hint hint, styles\n            style = @css[*classes]\n            h[k] =\n              if style\n                '<span%s style=\"%s\">' % [title, style]\n              else\n                false\n              end\n          end\n        end\n\n      else\n        raise ArgumentError, \"Unknown value %p for :css.\" % options[:css]\n\n      end\n    end\n\n    def finish options\n      not_needed = @opened.shift\n      @out << '</span>' * @opened.size\n      unless @opened.empty?\n        warn '%d tokens still open: %p' % [@opened.size, @opened]\n      end\n\n      @out.extend Output\n      @out.css = @css\n      @out.numerize! options[:line_numbers], options\n      @out.wrap! options[:wrap]\n\n      super\n    end\n\n    def token text, type\n      if text.is_a? ::String\n        if @escape && (text =~ /#{HTML_ESCAPE_PATTERN}/o)\n          text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] }\n        end\n        @opened[0] = type\n        if style = @css_style[@opened]\n          @out << style << text << '</span>'\n        else\n          @out << text\n        end\n      else\n        case text\n        when :open\n          @opened[0] = type\n          @out << (@css_style[@opened] || '<span>')\n          @opened << type\n        when :close\n          if @opened.empty?\n            # nothing to close\n          else\n            if $DEBUG and (@opened.size == 1 or @opened.last != type)\n              raise 'Malformed token stream: Trying to close a token (%p) \\\n                that is not open. Open are: %p.' % [type, @opened[1..-1]]\n            end\n            @out << '</span>'\n            @opened.pop\n          end\n        when nil\n          raise 'Token with nil as text was given: %p' % [[text, type]]\n        else\n          raise 'unknown token kind: %p' % text\n        end\n      end\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/null.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  # = Null Encoder\n  #\n  # Does nothing and returns an empty string.\n  class Null < Encoder\n\n    include Streamable\n    register_for :null\n\n    # Defined for faster processing\n    def to_proc\n      proc {}\n    end\n\n  protected\n\n    def token(*)\n      # do nothing\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/page.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  load :html\n\n  class Page < HTML\n\n    FILE_EXTENSION = 'html'\n\n    register_for :page\n\n    DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge({\n      :css => :class,\n      :wrap => :page,\n      :line_numbers => :table\n    })\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/span.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  load :html\n\n  class Span < HTML\n\n    FILE_EXTENSION = 'span.html'\n\n    register_for :span\n\n    DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge({\n      :css => :style,\n      :wrap => :span,\n    })\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/statistic.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  # Makes a statistic for the given tokens.\n  class Statistic < Encoder\n\n    include Streamable\n    register_for :stats, :statistic\n\n    attr_reader :type_stats, :real_token_count\n\n  protected\n\n    TypeStats = Struct.new :count, :size\n\n    def setup options\n      @type_stats = Hash.new { |h, k| h[k] = TypeStats.new 0, 0 }\n      @real_token_count = 0\n    end\n\n    def generate tokens, options\n      @tokens = tokens\n      super\n    end\n\n    def text_token text, kind\n      @real_token_count += 1 unless kind == :space\n      @type_stats[kind].count += 1\n      @type_stats[kind].size += text.size\n      @type_stats['TOTAL'].size += text.size\n      @type_stats['TOTAL'].count += 1\n    end\n\n    # TODO Hierarchy handling\n    def block_token action, kind\n      @type_stats['TOTAL'].count += 1\n      @type_stats['open/close'].count += 1\n    end\n\n    STATS = <<-STATS\n\nCode Statistics\n\nTokens            %8d\n  Non-Whitespace  %8d\nBytes Total       %8d\n\nToken Types (%d):\n  type                     count     ratio    size (average)\n-------------------------------------------------------------\n%s\n      STATS\n# space                    12007   33.81 %     1.7\n    TOKEN_TYPES_ROW = <<-TKR\n  %-20s  %8d  %6.2f %%   %5.1f\n      TKR\n\n    def finish options\n      all = @type_stats['TOTAL']\n      all_count, all_size = all.count, all.size\n      @type_stats.each do |type, stat|\n        stat.size /= stat.count.to_f\n      end\n      types_stats = @type_stats.sort_by { |k, v| [-v.count, k.to_s] }.map do |k, v|\n        TOKEN_TYPES_ROW % [k, v.count, 100.0 * v.count / all_count, v.size]\n      end.join\n      STATS % [\n        all_count, @real_token_count, all_size,\n        @type_stats.delete_if { |k, v| k.is_a? String }.size,\n        types_stats\n      ]\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/text.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  class Text < Encoder\n\n    include Streamable\n    register_for :text\n\n    FILE_EXTENSION = 'txt'\n\n    DEFAULT_OPTIONS = {\n      :separator => ''\n    }\n\n  protected\n    def setup options\n      @out = ''\n      @sep = options[:separator]\n    end\n\n    def token text, kind\n      @out << text + @sep if text.is_a? ::String\n    end\n\n    def finish options\n      @out.chomp @sep\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/tokens.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  # The Tokens encoder converts the tokens to a simple\n  # readable format. It doesn't use colors and is mainly\n  # intended for console output.\n  #\n  # The tokens are converted with Tokens.write_token.\n  #\n  # The format is:\n  #\n  #   <token-kind> \\t <escaped token-text> \\n\n  #\n  # Example:\n  #\n  #   require 'coderay'\n  #   puts CodeRay.scan(\"puts 3 + 4\", :ruby).tokens\n  #\n  # prints:\n  #\n  #   ident   puts\n  #   space\n  #   integer 3\n  #   space\n  #   operator        +\n  #   space\n  #   integer 4\n  #\n  class Tokens < Encoder\n\n    include Streamable\n    register_for :tokens\n\n    FILE_EXTENSION = 'tok'\n\n  protected\n    def token text, kind\n      @out << CodeRay::Tokens.write_token(text, kind)\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/xml.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  # = XML Encoder\n  #\n  # Uses REXML. Very slow.\n  class XML < Encoder\n\n    include Streamable\n    register_for :xml\n\n    FILE_EXTENSION = 'xml'\n\n    require 'rexml/document'\n\n    DEFAULT_OPTIONS = {\n      :tab_width => 8,\n      :pretty => -1,\n      :transitive => false,\n    }\n\n  protected\n\n    def setup options\n      @doc = REXML::Document.new\n      @doc << REXML::XMLDecl.new\n      @tab_width = options[:tab_width]\n      @root = @node = @doc.add_element('coderay-tokens')\n    end\n\n    def finish options\n      @doc.write @out, options[:pretty], options[:transitive], true\n      @out\n    end\n    \n    def text_token text, kind\n      if kind == :space\n        token = @node\n      else\n        token = @node.add_element kind.to_s\n      end\n      text.scan(/(\\x20+)|(\\t+)|(\\n)|[^\\x20\\t\\n]+/) do |space, tab, nl|\n        case\n        when space\n          token << REXML::Text.new(space, true)\n        when tab\n          token << REXML::Text.new(tab, true)\n        when nl\n          token << REXML::Text.new(nl, true)\n        else\n          token << REXML::Text.new($&)\n        end\n      end\n    end\n\n    def open_token kind\n      @node = @node.add_element kind.to_s\n    end\n\n    def close_token kind\n      if @node == @root\n        raise 'no token to close!'\n      end\n      @node = @node.parent\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/encoders/yaml.rb",
    "content": "module CodeRay\nmodule Encoders\n\n  # = YAML Encoder\n  #\n  # Slow.\n  class YAML < Encoder\n\n    register_for :yaml\n\n    FILE_EXTENSION = 'yaml'\n\n  protected\n    def compile tokens, options\n      require 'yaml'\n      @out = tokens.to_a.to_yaml\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/helpers/file_type.rb",
    "content": "module CodeRay\n\n# = FileType\n#\n# A simple filetype recognizer.\n#\n# Copyright (c) 2006 by murphy (Kornelius Kalnbach) <murphy rubychan de>\n#\n# License:: LGPL / ask the author\n# Version:: 0.1 (2005-09-01)\n#\n# == Documentation\n#\n#  # determine the type of the given\n#   lang = FileType[ARGV.first]\n#  \n#   # return :plaintext if the file type is unknown\n#   lang = FileType.fetch ARGV.first, :plaintext\n#  \n#   # try the shebang line, too\n#   lang = FileType.fetch ARGV.first, :plaintext, true\nmodule FileType\n\n  UnknownFileType = Class.new Exception\n\n  class << self\n\n    # Try to determine the file type of the file.\n    #\n    # +filename+ is a relative or absolute path to a file.\n    #\n    # The file itself is only accessed when +read_shebang+ is set to true.\n    # That means you can get filetypes from files that don't exist.\n    def [] filename, read_shebang = false\n      name = File.basename filename\n      ext = File.extname name\n      ext.sub!(/^\\./, '')  # delete the leading dot\n\n      type =\n        TypeFromExt[ext] ||\n        TypeFromExt[ext.downcase] ||\n        TypeFromName[name] ||\n        TypeFromName[name.downcase]\n      type ||= shebang(filename) if read_shebang\n\n      type\n    end\n\n    def shebang filename\n      begin\n        File.open filename, 'r' do |f|\n          first_line = f.gets\n          first_line[TypeFromShebang]\n        end\n      rescue IOError\n        nil\n      end\n    end\n\n    # This works like Hash#fetch.\n    #\n    # If the filetype cannot be found, the +default+ value\n    # is returned.\n    def fetch filename, default = nil, read_shebang = false\n      if default and block_given?\n        warn 'block supersedes default value argument'\n      end\n\n      unless type = self[filename, read_shebang]\n        return yield if block_given?\n        return default if default\n        raise UnknownFileType, 'Could not determine type of %p.' % filename\n      end\n      type\n    end\n\n  end\n\n  TypeFromExt = {\n    'rb' => :ruby,\n    'rbw' => :ruby,\n    'rake' => :ruby,\n    'mab' => :ruby,\n    'cpp' => :c,\n    'c' => :c,\n    'h' => :c,\n    'java' => :java,\n    'js' => :javascript,\n    'xml' => :xml,\n    'htm' => :html,\n    'html' => :html,\n    'php' => :php,\n    'php3' => :php,\n    'php4' => :php,\n    'php5' => :php,\n    'xhtml' => :xhtml,\n    'raydebug' => :debug,\n    'rhtml' => :rhtml,\n    'ss' => :scheme,\n    'sch' => :scheme,\n    'yaml' => :yaml,\n    'yml' => :yaml,\n  }\n\n  TypeFromShebang = /\\b(?:ruby|perl|python|sh)\\b/\n\n  TypeFromName = {\n    'Rakefile' => :ruby,\n    'Rantfile' => :ruby,\n  }\n\nend\n\nend\n\nif $0 == __FILE__\n  $VERBOSE = true\n  eval DATA.read, nil, $0, __LINE__+4\nend\n\n__END__\n\nrequire 'test/unit'\n\nclass TC_FileType < Test::Unit::TestCase\n\n  def test_fetch\n    assert_raise FileType::UnknownFileType do\n      FileType.fetch ''\n    end\n\n    assert_throws :not_found do\n      FileType.fetch '.' do\n        throw :not_found\n      end\n    end\n\n    assert_equal :default, FileType.fetch('c', :default)\n\n    stderr, fake_stderr = $stderr, Object.new\n    $err = ''\n    def fake_stderr.write x\n      $err << x\n    end\n    $stderr = fake_stderr\n    FileType.fetch('c', :default) { }\n    assert_equal \"block supersedes default value argument\\n\", $err\n    $stderr = stderr\n  end\n\n  def test_ruby\n    assert_equal :ruby, FileType['test.rb']\n    assert_equal :ruby, FileType['C:\\\\Program Files\\\\x\\\\y\\\\c\\\\test.rbw']\n    assert_equal :ruby, FileType['/usr/bin/something/Rakefile']\n    assert_equal :ruby, FileType['~/myapp/gem/Rantfile']\n    assert_equal :ruby, FileType['./lib/tasks\\repository.rake']\n    assert_not_equal :ruby, FileType['test_rb']\n    assert_not_equal :ruby, FileType['Makefile']\n    assert_not_equal :ruby, FileType['set.rb/set']\n    assert_not_equal :ruby, FileType['~/projects/blabla/rb']\n  end\n\n  def test_c\n    assert_equal :c, FileType['test.c']\n    assert_equal :c, FileType['C:\\\\Program Files\\\\x\\\\y\\\\c\\\\test.h']\n    assert_not_equal :c, FileType['test_c']\n    assert_not_equal :c, FileType['Makefile']\n    assert_not_equal :c, FileType['set.h/set']\n    assert_not_equal :c, FileType['~/projects/blabla/c']\n  end\n\n  def test_html\n    assert_equal :html, FileType['test.htm']\n    assert_equal :xhtml, FileType['test.xhtml']\n    assert_equal :xhtml, FileType['test.html.xhtml']\n    assert_equal :rhtml, FileType['_form.rhtml']\n  end\n\n  def test_yaml\n    assert_equal :yaml, FileType['test.yml']\n    assert_equal :yaml, FileType['test.yaml']\n    assert_equal :yaml, FileType['my.html.yaml']\n    assert_not_equal :yaml, FileType['YAML']\n  end\n\n  def test_shebang\n    dir = './test'\n    if File.directory? dir\n      Dir.chdir dir do\n        assert_equal :c, FileType['test.c']\n      end\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/helpers/gzip_simple.rb",
    "content": "# =GZip Simple\n#\n# A simplified interface to the gzip library +zlib+ (from the Ruby Standard Library.)\n#\n# Author: murphy (mail to murphy cYcnus de)\n#\n# Version: 0.2 (2005.may.28)\n#\n# ==Documentation\n#\n# See +GZip+ module and the +String+ extensions.\n#\nmodule GZip\n\n  require 'zlib'\n\n  # The default zipping level. 7 zips good and fast.\n  DEFAULT_GZIP_LEVEL = 7\n\n  # Unzips the given string +s+.\n  #\n  # Example:\n  #   require 'gzip_simple'\n  #   print GZip.gunzip(File.read('adresses.gz'))\n  def GZip.gunzip s\n    Zlib::Inflate.inflate s\n  end\n\n  # Zips the given string +s+.\n  #\n  # Example:\n  #   require 'gzip_simple'\n  #   File.open('adresses.gz', 'w') do |file\n  #     file.write GZip.gzip('Mum: 0123 456 789', 9)\n  #   end\n  #\n  # If you provide a +level+, you can control how strong\n  # the string is compressed:\n  # - 0: no compression, only convert to gzip format\n  # - 1: compress fast\n  # - 7: compress more, but still fast (default)\n  # - 8: compress more, slower\n  # - 9: compress best, very slow\n  def GZip.gzip s, level = DEFAULT_GZIP_LEVEL\n    Zlib::Deflate.new(level).deflate s, Zlib::FINISH\n  end\nend\n\n\n# String extensions to use the GZip module.\n#\n# The methods gzip and gunzip provide an even more simple\n# interface to the ZLib:\n#\n#   # create a big string\n#   x = 'a' * 1000\n#   \n#   # zip it\n#   x_gz = x.gzip\n#   \n#   # test the result\n#   puts 'Zipped %d bytes to %d bytes.' % [x.size, x_gz.size]\n#   #-> Zipped 1000 bytes to 19 bytes.\n#   \n#   # unzipping works\n#   p x_gz.gunzip == x  #-> true\nclass String\n  # Returns the string, unzipped.\n  # See GZip.gunzip\n  def gunzip\n    GZip.gunzip self\n  end\n  # Replaces the string with its unzipped value.\n  # See GZip.gunzip\n  def gunzip!\n    replace gunzip\n  end\n\n  # Returns the string, zipped.\n  # +level+ is the gzip compression level, see GZip.gzip.\n  def gzip level = GZip::DEFAULT_GZIP_LEVEL\n    GZip.gzip self, level\n  end\n  # Replaces the string with its zipped value.\n  # See GZip.gzip.\n  def gzip!(*args)\n    replace gzip(*args)\n  end\nend\n\nif $0 == __FILE__\n  eval DATA.read, nil, $0, __LINE__+4\nend\n\n__END__\n#CODE\n\n# Testing / Benchmark\nx = 'a' * 1000\nx_gz = x.gzip\nputs 'Zipped %d bytes to %d bytes.' % [x.size, x_gz.size]  #-> Zipped 1000 bytes to 19 bytes.\np x_gz.gunzip == x  #-> true\n\nrequire 'benchmark'\n\nINFO = 'packed to %0.3f%%'  # :nodoc:\n\nx = Array.new(100000) { rand(255).chr + 'aaaaaaaaa' + rand(255).chr }.join\nBenchmark.bm(10) do |bm|\n  for level in 0..9\n    bm.report \"zip #{level}\" do\n      $x = x.gzip level\n    end\n    puts INFO % [100.0 * $x.size / x.size]\n  end\n  bm.report 'zip' do\n    $x = x.gzip\n  end\n  puts INFO % [100.0 * $x.size / x.size]\n  bm.report 'unzip' do\n    $x.gunzip\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/helpers/plugin.rb",
    "content": "module CodeRay\n  \n# = PluginHost\n#\n# $Id: plugin.rb 220 2007-01-01 02:58:58Z murphy $\n#\n# A simple subclass plugin system.\n#\n#  Example:\n#    class Generators < PluginHost\n#      plugin_path 'app/generators'\n#    end\n#    \n#    class Generator\n#      extend Plugin\n#      PLUGIN_HOST = Generators\n#    end\n#    \n#    class FancyGenerator < Generator\n#      register_for :fancy\n#    end\n#\n#    Generators[:fancy]  #-> FancyGenerator\n#    # or\n#    require_plugin 'Generators/fancy'\nmodule PluginHost\n\n  # Raised if Encoders::[] fails because:\n  # * a file could not be found\n  # * the requested Encoder is not registered\n  PluginNotFound = Class.new Exception\n  HostNotFound = Class.new Exception\n\n  PLUGIN_HOSTS = []\n  PLUGIN_HOSTS_BY_ID = {}  # dummy hash\n\n  # Loads all plugins using list and load.\n  def load_all\n    for plugin in list\n      load plugin\n    end\n  end\n\n  # Returns the Plugin for +id+.\n  #\n  # Example:\n  #  yaml_plugin = MyPluginHost[:yaml]\n  def [] id, *args, &blk\n    plugin = validate_id(id)\n    begin\n      plugin = plugin_hash.[] plugin, *args, &blk\n    end while plugin.is_a? Symbol\n    plugin\n  end\n\n  # Alias for +[]+.\n  alias load []\n\n  def require_helper plugin_id, helper_name\n    path = path_to File.join(plugin_id, helper_name)\n    require path\n  end\n\n  class << self\n\n    # Adds the module/class to the PLUGIN_HOSTS list.\n    def extended mod\n      PLUGIN_HOSTS << mod\n    end\n\n    # Warns you that you should not #include this module.\n    def included mod\n      warn \"#{name} should not be included. Use extend.\"\n    end\n\n    # Find the PluginHost for host_id.\n    def host_by_id host_id\n      unless PLUGIN_HOSTS_BY_ID.default_proc\n        ph = Hash.new do |h, a_host_id|\n          for host in PLUGIN_HOSTS\n            h[host.host_id] = host\n          end\n          h.fetch a_host_id, nil\n        end\n        PLUGIN_HOSTS_BY_ID.replace ph\n      end\n      PLUGIN_HOSTS_BY_ID[host_id]\n    end\n\n  end\n\n  # The path where the plugins can be found.\n  def plugin_path *args\n    unless args.empty?\n      @plugin_path = File.expand_path File.join(*args)\n      load_map\n    end\n    @plugin_path\n  end\n\n  # The host's ID.\n  #\n  # If PLUGIN_HOST_ID is not set, it is simply the class name.\n  def host_id\n    if self.const_defined? :PLUGIN_HOST_ID\n      self::PLUGIN_HOST_ID\n    else\n      name\n    end\n  end\n\n  # Map a plugin_id to another.\n  #\n  # Usage: Put this in a file plugin_path/_map.rb.\n  #\n  #  class MyColorHost < PluginHost\n  #    map :navy => :dark_blue,\n  #      :maroon => :brown,\n  #      :luna => :moon\n  #  end\n  def map hash\n    for from, to in hash\n      from = validate_id from\n      to = validate_id to\n      plugin_hash[from] = to unless plugin_hash.has_key? from\n    end\n  end\n\n  # Define the default plugin to use when no plugin is found\n  # for a given id.\n  #\n  # See also map.\n  #\n  #  class MyColorHost < PluginHost\n  #    map :navy => :dark_blue\n  #    default :gray\n  #  end\n  def default id\n    id = validate_id id\n    plugin_hash[nil] = id\n  end\n\n  # Every plugin must register itself for one or more\n  # +ids+ by calling register_for, which calls this method.\n  #\n  # See Plugin#register_for.\n  def register plugin, *ids\n    for id in ids\n      unless id.is_a? Symbol\n        raise ArgumentError,\n          \"id must be a Symbol, but it was a #{id.class}\"\n      end\n      plugin_hash[validate_id(id)] = plugin\n    end\n  end\n\n  # A Hash of plugion_id => Plugin pairs.\n  def plugin_hash\n    @plugin_hash ||= create_plugin_hash\n  end\n\n  # Returns an array of all .rb files in the plugin path.\n  #\n  # The extension .rb is not included.\n  def list\n    Dir[path_to('*')].select do |file|\n      File.basename(file)[/^(?!_)\\w+\\.rb$/]\n    end.map do |file|\n      File.basename file, '.rb'\n    end\n  end\n\n  # Makes a map of all loaded plugins.\n  def inspect\n    map = plugin_hash.dup\n    map.each do |id, plugin|\n      map[id] = plugin.to_s[/(?>[\\w_]+)$/]\n    end\n    \"#{name}[#{host_id}]#{map.inspect}\"\n  end\n\nprotected\n  # Created a new plugin list and stores it to @plugin_hash.\n  def create_plugin_hash\n    @plugin_hash =\n      Hash.new do |h, plugin_id|\n        id = validate_id(plugin_id)\n        path = path_to id\n        begin\n          require path\n        rescue LoadError => boom\n          if h.has_key? nil  # default plugin\n            h[id] = h[nil]\n          else\n            raise PluginNotFound, 'Could not load plugin %p: %s' % [id, boom]\n          end\n        else\n          # Plugin should have registered by now\n          unless h.has_key? id\n            raise PluginNotFound,\n              \"No #{self.name} plugin for #{id.inspect} found in #{path}.\"\n          end\n        end\n        h[id]\n      end\n  end\n\n  # Loads the map file (see map).\n  #\n  # This is done automatically when plugin_path is called.\n  def load_map\n    mapfile = path_to '_map'\n    if File.exist? mapfile\n      require mapfile\n    elsif $DEBUG\n      warn 'no _map.rb found for %s' % name\n    end\n  end\n\n  # Returns the Plugin for +id+.\n  # Use it like Hash#fetch.\n  #\n  # Example:\n  #  yaml_plugin = MyPluginHost[:yaml, :default]\n  def fetch id, *args, &blk\n    plugin_hash.fetch validate_id(id), *args, &blk\n  end\n\n  # Returns the expected path to the plugin file for the given id.\n  def path_to plugin_id\n    File.join plugin_path, \"#{plugin_id}.rb\"\n  end\n\n  # Converts +id+ to a Symbol if it is a String,\n  # or returns +id+ if it already is a Symbol.\n  #\n  # Raises +ArgumentError+ for all other objects, or if the\n  # given String includes non-alphanumeric characters (\\W).\n  def validate_id id\n    if id.is_a? Symbol or id.nil?\n      id\n    elsif id.is_a? String\n      if id[/\\w+/] == id\n        id.to_sym\n      else\n        raise ArgumentError, \"Invalid id: '#{id}' given.\"\n      end\n    else\n      raise ArgumentError,\n        \"String or Symbol expected, but #{id.class} given.\"\n    end\n  end\n\nend\n\n\n# = Plugin\n#\n#  Plugins have to include this module.\n#\n#  IMPORTANT: use extend for this module.\n#\n#  Example: see PluginHost.\nmodule Plugin\n\n  def included mod\n    warn \"#{name} should not be included. Use extend.\"\n  end\n\n  # Register this class for the given langs.\n  # Example:\n  #   class MyPlugin < PluginHost::BaseClass\n  #     register_for :my_id\n  #     ...\n  #   end\n  #\n  # See PluginHost.register.\n  def register_for *ids\n    plugin_host.register self, *ids\n  end\n\n  # The host for this Plugin class.\n  def plugin_host host = nil\n    if host and not host.is_a? PluginHost\n      raise ArgumentError,\n        \"PluginHost expected, but #{host.class} given.\"\n    end\n    self.const_set :PLUGIN_HOST, host if host\n    self::PLUGIN_HOST\n  end\n\n  # Require some helper files.\n  #\n  # Example:\n  #\n  #  class MyPlugin < PluginHost::BaseClass\n  #     register_for :my_id\n  #     helper :my_helper\n  #\n  # The above example loads the file myplugin/my_helper.rb relative to the\n  # file in which MyPlugin was defined.\n  def helper *helpers\n    for helper in helpers\n      self::PLUGIN_HOST.require_helper plugin_id, helper.to_s\n    end\n  end\n\n  # Returns the pulgin id used by the engine.\n  def plugin_id\n    name[/[\\w_]+$/].downcase\n  end\n\nend\n\n# Convenience method for plugin loading.\n# The syntax used is:\n#\n#  CodeRay.require_plugin '<Host ID>/<Plugin ID>'\n#\n# Returns the loaded plugin.\ndef require_plugin path\n  host_id, plugin_id = path.split '/', 2\n  host = PluginHost.host_by_id(host_id)\n  raise PluginHost::HostNotFound,\n    \"No host for #{host_id.inspect} found.\" unless host\n  host.load plugin_id\nend\n\nend"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/helpers/word_list.rb",
    "content": "module CodeRay\n\n# = WordList\n# \n# <b>A Hash subclass designed for mapping word lists to token types.</b>\n# \n# Copyright (c) 2006 by murphy (Kornelius Kalnbach) <murphy rubychan de>\n#\n# License:: LGPL / ask the author\n# Version:: 1.1 (2006-Oct-19)\n#\n# A WordList is a Hash with some additional features.\n# It is intended to be used for keyword recognition.\n#\n# WordList is highly optimized to be used in Scanners,\n# typically to decide whether a given ident is a special token.\n#\n# For case insensitive words use CaseIgnoringWordList.\n#\n# Example:\n#\n#  # define word arrays\n#  RESERVED_WORDS = %w[\n#    asm break case continue default do else\n#    ...\n#  ]\n#  \n#  PREDEFINED_TYPES = %w[\n#    int long short char void\n#    ...\n#  ]\n#  \n#  PREDEFINED_CONSTANTS = %w[\n#    EOF NULL ...\n#  ]\n#  \n#  # make a WordList\n#  IDENT_KIND = WordList.new(:ident).\n#    add(RESERVED_WORDS, :reserved).\n#    add(PREDEFINED_TYPES, :pre_type).\n#    add(PREDEFINED_CONSTANTS, :pre_constant)\n#\n#  ...\n#\n#  def scan_tokens tokens, options\n#    ...\n#    \n#    elsif scan(/[A-Za-z_][A-Za-z_0-9]*/)\n#      # use it\n#      kind = IDENT_KIND[match]\n#      ...\nclass WordList < Hash\n\n  # Creates a new WordList with +default+ as default value.\n  # \n  # You can activate +caching+ to store the results for every [] request.\n  # \n  # With caching, methods like +include?+ or +delete+ may no longer behave\n  # as you expect. Therefore, it is recommended to use the [] method only.\n  def initialize default = false, caching = false, &block\n    if block\n      raise ArgumentError, 'Can\\'t combine block with caching.' if caching\n      super(&block)\n    else\n      if caching\n        super() do |h, k|\n          h[k] = h.fetch k, default\n        end\n      else\n        super default\n      end\n    end\n  end\n\n  # Add words to the list and associate them with +kind+.\n  # \n  # Returns +self+, so you can concat add calls.\n  def add words, kind = true\n    words.each do |word|\n      self[word] = kind\n    end\n    self\n  end\n\nend\n\n\n# A CaseIgnoringWordList is like a WordList, only that\n# keys are compared case-insensitively.\n# \n# Ignoring the text case is realized by sending the +downcase+ message to\n# all keys.\n# \n# Caching usually makes a CaseIgnoringWordList faster, but it has to be\n# activated explicitely.\nclass CaseIgnoringWordList < WordList\n\n  # Creates a new case-insensitive WordList with +default+ as default value.\n  # \n  # You can activate caching to store the results for every [] request.\n  def initialize default = false, caching = false\n    if caching\n      super(default, false) do |h, k|\n        h[k] = h.fetch k.downcase, default\n      end\n    else\n      def self.[] key  # :nodoc:\n        super(key.downcase)\n      end\n    end\n  end\n\n  # Add +words+ to the list and associate them with +kind+.\n  def add words, kind = true\n    words.each do |word|\n      self[word.downcase] = kind\n    end\n    self\n  end\n\nend\n\nend"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanner.rb",
    "content": "module CodeRay\n\n  require 'coderay/helpers/plugin'\n\n  # = Scanners\n  #\n  # $Id: scanner.rb 222 2007-01-01 16:26:17Z murphy $\n  #\n  # This module holds the Scanner class and its subclasses.\n  # For example, the Ruby scanner is named CodeRay::Scanners::Ruby\n  # can be found in coderay/scanners/ruby.\n  #\n  # Scanner also provides methods and constants for the register\n  # mechanism and the [] method that returns the Scanner class\n  # belonging to the given lang.\n  #\n  # See PluginHost.\n  module Scanners\n    extend PluginHost\n    plugin_path File.dirname(__FILE__), 'scanners'\n\n    require 'strscan'\n\n    # = Scanner\n    #\n    # The base class for all Scanners.\n    #\n    # It is a subclass of Ruby's great +StringScanner+, which\n    # makes it easy to access the scanning methods inside.\n    #\n    # It is also +Enumerable+, so you can use it like an Array of\n    # Tokens:\n    #\n    #   require 'coderay'\n    #   \n    #   c_scanner = CodeRay::Scanners[:c].new \"if (*p == '{') nest++;\"\n    #   \n    #   for text, kind in c_scanner\n    #     puts text if kind == :operator\n    #   end\n    #   \n    #   # prints: (*==)++;\n    #\n    # OK, this is a very simple example :)\n    # You can also use +map+, +any?+, +find+ and even +sort_by+,\n    # if you want.\n    class Scanner < StringScanner\n      extend Plugin\n      plugin_host Scanners\n\n      # Raised if a Scanner fails while scanning\n      ScanError = Class.new(Exception)\n\n      require 'coderay/helpers/word_list'\n\n      # The default options for all scanner classes.\n      #\n      # Define @default_options for subclasses.\n      DEFAULT_OPTIONS = { :stream => false }\n\n      class << self\n\n        # Returns if the Scanner can be used in streaming mode.\n        def streamable?\n          is_a? Streamable\n        end\n\n        def normify code\n          code = code.to_s.to_unix\n        end\n        \n        def file_extension extension = nil\n          if extension\n            @file_extension = extension.to_s\n          else\n            @file_extension ||= plugin_id.to_s\n          end\n        end        \n\n      end\n\n=begin\n## Excluded for speed reasons; protected seems to make methods slow.\n\n  # Save the StringScanner methods from being called.\n  # This would not be useful for highlighting.\n  strscan_public_methods =\n    StringScanner.instance_methods -\n    StringScanner.ancestors[1].instance_methods\n  protected(*strscan_public_methods)\n=end\n\n      # Create a new Scanner.\n      #\n      # * +code+ is the input String and is handled by the superclass\n      #   StringScanner.\n      # * +options+ is a Hash with Symbols as keys.\n      #   It is merged with the default options of the class (you can\n      #   overwrite default options here.)\n      # * +block+ is the callback for streamed highlighting.\n      #\n      # If you set :stream to +true+ in the options, the Scanner uses a\n      # TokenStream with the +block+ as callback to handle the tokens.\n      #\n      # Else, a Tokens object is used.\n      def initialize code='', options = {}, &block\n        @options = self.class::DEFAULT_OPTIONS.merge options\n        raise \"I am only the basic Scanner class. I can't scan \"\\\n          \"anything. :( Use my subclasses.\" if self.class == Scanner\n\n        super Scanner.normify(code)\n\n        @tokens = options[:tokens]\n        if @options[:stream]\n          warn \"warning in CodeRay::Scanner.new: :stream is set, \"\\\n            \"but no block was given\" unless block_given?\n          raise NotStreamableError, self unless kind_of? Streamable\n          @tokens ||= TokenStream.new(&block)\n        else\n          warn \"warning in CodeRay::Scanner.new: Block given, \"\\\n            \"but :stream is #{@options[:stream]}\" if block_given?\n          @tokens ||= Tokens.new\n        end\n\n        setup\n      end\n\n      def reset\n        super\n        reset_instance\n      end\n\n      def string= code\n        code = Scanner.normify(code)\n        super code\n        reset_instance\n      end\n\n      # More mnemonic accessor name for the input string.\n      alias code string\n      alias code= string=\n\n      # Scans the code and returns all tokens in a Tokens object.\n      def tokenize new_string=nil, options = {}\n        options = @options.merge(options)\n        self.string = new_string if new_string\n        @cached_tokens =\n          if @options[:stream]  # :stream must have been set already\n            reset unless new_string\n            scan_tokens @tokens, options\n            @tokens\n          else\n            scan_tokens @tokens, options\n          end\n      end\n\n      def tokens\n        @cached_tokens ||= tokenize\n      end\n      \n      # Whether the scanner is in streaming mode.\n      def streaming?\n        !!@options[:stream]\n      end\n\n      # Traverses the tokens.\n      def each &block\n        raise ArgumentError,\n          'Cannot traverse TokenStream.' if @options[:stream]\n        tokens.each(&block)\n      end\n      include Enumerable\n\n      # The current line position of the scanner.\n      #\n      # Beware, this is implemented inefficiently. It should be used\n      # for debugging only.\n      def line\n        string[0..pos].count(\"\\n\") + 1\n      end\n\n    protected\n\n      # Can be implemented by subclasses to do some initialization\n      # that has to be done once per instance.\n      #\n      # Use reset for initialization that has to be done once per\n      # scan.\n      def setup\n      end\n\n      # This is the central method, and commonly the only one a\n      # subclass implements.\n      #\n      # Subclasses must implement this method; it must return +tokens+\n      # and must only use Tokens#<< for storing scanned tokens!\n      def scan_tokens tokens, options\n        raise NotImplementedError,\n          \"#{self.class}#scan_tokens not implemented.\"\n      end\n\n      def reset_instance\n        @tokens.clear unless @options[:keep_tokens]\n        @cached_tokens = nil\n      end\n\n      # Scanner error with additional status information\n      def raise_inspect msg, tokens, state = 'No state given!', ambit = 30\n        raise ScanError, <<-EOE % [\n\n\n***ERROR in %s: %s (after %d tokens)\n\ntokens:\n%s\n\ncurrent line: %d  pos = %d\nmatched: %p  state: %p\nbol? = %p,  eos? = %p\n\nsurrounding code:\n%p  ~~  %p\n\n\n***ERROR***\n\n        EOE\n          File.basename(caller[0]),\n          msg,\n          tokens.size,\n          tokens.last(10).map { |t| t.inspect }.join(\"\\n\"),\n          line, pos,\n          matched, state, bol?, eos?,\n          string[pos-ambit,ambit],\n          string[pos,ambit],\n        ]\n      end\n\n    end\n\n  end\nend\n\nclass String\n  # I love this hack. It seems to silence all dos/unix/mac newline problems.\n  def to_unix\n    if index ?\\r\n      gsub(/\\r\\n?/, \"\\n\")\n    else\n      self\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/_map.rb",
    "content": "module CodeRay\nmodule Scanners\n\n  map :cpp => :c,\n    :plain => :plaintext,\n    :pascal => :delphi,\n    :irb => :ruby,\n    :xml => :html,\n    :xhtml => :nitro_xhtml,\n    :nitro => :nitro_xhtml\n\n  default :plain\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/c.rb",
    "content": "module CodeRay\nmodule Scanners\n\n  class C < Scanner\n\n    register_for :c\n    \n    include Streamable\n\n    RESERVED_WORDS = [\n      'asm', 'break', 'case', 'continue', 'default', 'do', 'else',\n      'for', 'goto', 'if', 'return', 'switch', 'while',\n      'struct', 'union', 'enum', 'typedef',\n      'static', 'register', 'auto', 'extern',\n      'sizeof',\n      'volatile', 'const',  # C89\n      'inline', 'restrict', # C99\n    ]\n\n    PREDEFINED_TYPES = [\n      'int', 'long', 'short', 'char', 'void',\n      'signed', 'unsigned', 'float', 'double',\n      'bool', 'complex',  # C99\n    ]\n\n    PREDEFINED_CONSTANTS = [\n      'EOF', 'NULL',\n      'true', 'false',  # C99\n    ]\n\n    IDENT_KIND = WordList.new(:ident).\n      add(RESERVED_WORDS, :reserved).\n      add(PREDEFINED_TYPES, :pre_type).\n      add(PREDEFINED_CONSTANTS, :pre_constant)\n\n    ESCAPE = / [rbfnrtv\\n\\\\'\"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x\n    UNICODE_ESCAPE =  / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x\n\n    def scan_tokens tokens, options\n\n      state = :initial\n\n      until eos?\n\n        kind = nil\n        match = nil\n        \n        case state\n\n        when :initial\n\n          if scan(/ \\s+ | \\\\\\n /x)\n            kind = :space\n\n          elsif scan(%r! // [^\\n\\\\]* (?: \\\\. [^\\n\\\\]* )* | /\\* (?: .*? \\*/ | .* ) !mx)\n            kind = :comment\n\n          elsif match = scan(/ \\# \\s* if \\s* 0 /x)\n            match << scan_until(/ ^\\# (?:elif|else|endif) .*? $ | \\z /xm) unless eos?\n            kind = :comment\n\n          elsif scan(/ [-+*\\/=<>?:;,!&^|()\\[\\]{}~%]+ | \\.(?!\\d) /x)\n            kind = :operator\n\n          elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x)\n            kind = IDENT_KIND[match]\n            if kind == :ident and check(/:(?!:)/)\n              match << scan(/:/)\n              kind = :label\n            end\n\n          elsif match = scan(/L?\"/)\n            tokens << [:open, :string]\n            if match[0] == ?L\n              tokens << ['L', :modifier]\n              match = '\"'\n            end\n            state = :string\n            kind = :delimiter\n\n          elsif scan(/#\\s*(\\w*)/)\n            kind = :preprocessor  # FIXME multiline preprocs\n            state = :include_expected if self[1] == 'include'\n\n          elsif scan(/ L?' (?: [^\\'\\n\\\\] | \\\\ #{ESCAPE} )? '? /ox)\n            kind = :char\n\n          elsif scan(/0[xX][0-9A-Fa-f]+/)\n            kind = :hex\n\n          elsif scan(/(?:0[0-7]+)(?![89.eEfF])/)\n            kind = :oct\n\n          elsif scan(/(?:\\d+)(?![.eEfF])/)\n            kind = :integer\n\n          elsif scan(/\\d[fF]?|\\d*\\.\\d+(?:[eE][+-]?\\d+)?[fF]?|\\d+[eE][+-]?\\d+[fF]?/)\n            kind = :float\n\n          else\n            getch\n            kind = :error\n\n          end\n\n        when :string\n          if scan(/[^\\\\\\n\"]+/)\n            kind = :content\n          elsif scan(/\"/)\n            tokens << ['\"', :delimiter]\n            tokens << [:close, :string]\n            state = :initial\n            next\n          elsif scan(/ \\\\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)\n            kind = :char\n          elsif scan(/ \\\\ | $ /x)\n            tokens << [:close, :string]\n            kind = :error\n            state = :initial\n          else\n            raise_inspect \"else case \\\" reached; %p not handled.\" % peek(1), tokens\n          end\n\n        when :include_expected\n          if scan(/[^\\n]+/)\n            kind = :include\n            state = :initial\n\n          elsif match = scan(/\\s+/)\n            kind = :space\n            state = :initial if match.index ?\\n\n\n          else\n            getch\n            kind = :error\n\n          end\n\n        else\n          raise_inspect 'Unknown state', tokens\n\n        end\n\n        match ||= matched\n        if $DEBUG and not kind\n          raise_inspect 'Error token %p in line %d' %\n            [[match, kind], line], tokens\n        end\n        raise_inspect 'Empty token', tokens unless match\n\n        tokens << [match, kind]\n\n      end\n\n      if state == :string\n        tokens << [:close, :string]\n      end\n\n      tokens\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/debug.rb",
    "content": "module CodeRay\nmodule Scanners\n\n  # = Debug Scanner\n  class Debug < Scanner\n\n    include Streamable\n    register_for :debug\n\n  protected\n    def scan_tokens tokens, options\n\n      opened_tokens = []\n\n      until eos?\n\n        kind = nil\n        match = nil\n\n          if scan(/\\s+/)\n            tokens << [matched, :space]\n            next\n            \n          elsif scan(/ (\\w+) \\( ( [^\\)\\\\]* ( \\\\. [^\\)\\\\]* )* ) \\) /x)\n            kind = self[1].to_sym\n            match = self[2].gsub(/\\\\(.)/, '\\1')\n            \n          elsif scan(/ (\\w+) < /x)\n            kind = self[1].to_sym\n            opened_tokens << kind\n            match = :open\n            \n          elsif scan(/ > /x)\n            kind = opened_tokens.pop\n            match = :close\n            \n          else\n            kind = :error\n            getch\n\n          end\n                  \n        match ||= matched\n        if $DEBUG and not kind\n          raise_inspect 'Error token %p in line %d' %\n            [[match, kind], line], tokens\n        end\n        raise_inspect 'Empty token', tokens unless match\n\n        tokens << [match, kind]\n        \n      end\n      \n      tokens\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/delphi.rb",
    "content": "module CodeRay\nmodule Scanners\n  \n  class Delphi < Scanner\n\n    register_for :delphi\n    \n    RESERVED_WORDS = [\n      'and', 'array', 'as', 'at', 'asm', 'at', 'begin', 'case', 'class',\n      'const', 'constructor', 'destructor', 'dispinterface', 'div', 'do',\n      'downto', 'else', 'end', 'except', 'exports', 'file', 'finalization',\n      'finally', 'for', 'function', 'goto', 'if', 'implementation', 'in',\n      'inherited', 'initialization', 'inline', 'interface', 'is', 'label',\n      'library', 'mod', 'nil', 'not', 'object', 'of', 'or', 'out', 'packed',\n      'procedure', 'program', 'property', 'raise', 'record', 'repeat',\n      'resourcestring', 'set', 'shl', 'shr', 'string', 'then', 'threadvar',\n      'to', 'try', 'type', 'unit', 'until', 'uses', 'var', 'while', 'with',\n      'xor', 'on'\n    ]\n\n    DIRECTIVES = [\n      'absolute', 'abstract', 'assembler', 'at', 'automated', 'cdecl',\n      'contains', 'deprecated', 'dispid', 'dynamic', 'export',\n      'external', 'far', 'forward', 'implements', 'local', \n      'near', 'nodefault', 'on', 'overload', 'override',\n      'package', 'pascal', 'platform', 'private', 'protected', 'public',\n      'published', 'read', 'readonly', 'register', 'reintroduce',\n      'requires', 'resident', 'safecall', 'stdcall', 'stored', 'varargs',\n      'virtual', 'write', 'writeonly'\n    ]\n\n    IDENT_KIND = CaseIgnoringWordList.new(:ident, caching=true).\n      add(RESERVED_WORDS, :reserved).\n      add(DIRECTIVES, :directive)\n    \n    NAME_FOLLOWS = CaseIgnoringWordList.new(false, caching=true).\n      add(%w(procedure function .))\n\n  private\n    def scan_tokens tokens, options\n\n      state = :initial\n      last_token = ''\n\n      until eos?\n\n        kind = nil\n        match = nil\n\n        if state == :initial\n          \n          if scan(/ \\s+ /x)\n            tokens << [matched, :space]\n            next\n            \n          elsif scan(%r! \\{ \\$ [^}]* \\}? | \\(\\* \\$ (?: .*? \\*\\) | .* ) !mx)\n            tokens << [matched, :preprocessor]\n            next\n            \n          elsif scan(%r! // [^\\n]* | \\{ [^}]* \\}? | \\(\\* (?: .*? \\*\\) | .* ) !mx)\n            tokens << [matched, :comment]\n            next\n            \n          elsif match = scan(/ <[>=]? | >=? | :=? | [-+=*\\/;,@\\^|\\(\\)\\[\\]] | \\.\\. /x)\n            kind = :operator\n          \n          elsif match = scan(/\\./)\n            kind = :operator\n            if last_token == 'end'\n              tokens << [match, kind]\n              next\n            end\n            \n          elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x)\n            kind = NAME_FOLLOWS[last_token] ? :ident : IDENT_KIND[match]\n            \n          elsif match = scan(/ ' ( [^\\n']|'' ) (?:'|$) /x)\n            tokens << [:open, :char]\n            tokens << [\"'\", :delimiter]\n            tokens << [self[1], :content]\n            tokens << [\"'\", :delimiter]\n            tokens << [:close, :char]\n            next\n            \n          elsif match = scan(/ ' /x)\n            tokens << [:open, :string]\n            state = :string\n            kind = :delimiter\n            \n          elsif scan(/ \\# (?: \\d+ | \\$[0-9A-Fa-f]+ ) /x)\n            kind = :char\n            \n          elsif scan(/ \\$ [0-9A-Fa-f]+ /x)\n            kind = :hex\n            \n          elsif scan(/ (?: \\d+ ) (?![eE]|\\.[^.]) /x)\n            kind = :integer\n            \n          elsif scan(/ \\d+ (?: \\.\\d+ (?: [eE][+-]? \\d+ )? | [eE][+-]? \\d+ ) /x)\n            kind = :float\n\n          else\n            kind = :error\n            getch\n\n          end\n          \n        elsif state == :string\n          if scan(/[^\\n']+/)\n            kind = :content\n          elsif scan(/''/)\n            kind = :char\n          elsif scan(/'/)\n            tokens << [\"'\", :delimiter]\n            tokens << [:close, :string]\n            state = :initial\n            next\n          elsif scan(/\\n/)\n            tokens << [:close, :string]\n            kind = :error\n            state = :initial\n          else\n            raise \"else case \\' reached; %p not handled.\" % peek(1), tokens\n          end\n          \n        else\n          raise 'else-case reached', tokens\n          \n        end\n        \n        match ||= matched\n        if $DEBUG and not kind\n          raise_inspect 'Error token %p in line %d' %\n            [[match, kind], line], tokens, state\n        end\n        raise_inspect 'Empty token', tokens unless match\n\n        last_token = match\n        tokens << [match, kind]\n        \n      end\n      \n      tokens\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/html.rb",
    "content": "module CodeRay\nmodule Scanners\n\n  # HTML Scanner\n  #\n  # $Id$\n  class HTML < Scanner\n\n    include Streamable\n    register_for :html\n\n    ATTR_NAME = /[\\w.:-]+/\n    ATTR_VALUE_UNQUOTED = ATTR_NAME\n    TAG_END = /\\/?>/\n    HEX = /[0-9a-fA-F]/\n    ENTITY = /\n      &\n      (?:\n        \\w+\n      |\n        \\#\n        (?:\n          \\d+\n        |\n          x#{HEX}+\n        )\n      )\n      ;\n    /ox\n\n    PLAIN_STRING_CONTENT = {\n      \"'\" => /[^&'>\\n]+/,\n      '\"' => /[^&\">\\n]+/,\n    }\n\n    def reset\n      super\n      @state = :initial\n    end\n\n  private\n    def setup\n      @state = :initial\n      @plain_string_content = nil\n    end\n\n    def scan_tokens tokens, options\n\n      state = @state\n      plain_string_content = @plain_string_content\n\n      until eos?\n\n        kind = nil\n        match = nil\n\n        if scan(/\\s+/m)\n          kind = :space\n\n        else\n\n          case state\n\n          when :initial\n            if scan(/<!--.*?-->/m)\n              kind = :comment\n            elsif scan(/<!DOCTYPE.*?>/m)\n              kind = :preprocessor\n            elsif scan(/<\\?xml.*?\\?>/m)\n              kind = :preprocessor\n            elsif scan(/<\\?.*?\\?>|<%.*?%>/m)\n              kind = :comment\n            elsif scan(/<\\/[-\\w_.:]*>/m)\n              kind = :tag\n            elsif match = scan(/<[-\\w_.:]+>?/m)\n              kind = :tag\n              state = :attribute unless match[-1] == ?>\n            elsif scan(/[^<>&]+/)\n              kind = :plain\n            elsif scan(/#{ENTITY}/ox)\n              kind = :entity\n            elsif scan(/[<>&]/)\n              kind = :error\n            else\n              raise_inspect '[BUG] else-case reached with state %p' % [state], tokens\n            end\n\n          when :attribute\n            if scan(/#{TAG_END}/)\n              kind = :tag\n              state = :initial\n            elsif scan(/#{ATTR_NAME}/o)\n              kind = :attribute_name\n              state = :attribute_equal\n            else\n              kind = :error\n              getch\n            end\n\n          when :attribute_equal\n            if scan(/=/)\n              kind = :operator\n              state = :attribute_value\n            elsif scan(/#{ATTR_NAME}/o)\n              kind = :attribute_name\n            elsif scan(/#{TAG_END}/o)\n              kind = :tag\n              state = :initial\n            elsif scan(/./)\n              kind = :error\n              state = :attribute\n            end\n\n          when :attribute_value\n            if scan(/#{ATTR_VALUE_UNQUOTED}/o)\n              kind = :attribute_value\n              state = :attribute\n            elsif match = scan(/[\"']/)\n              tokens << [:open, :string]\n              state = :attribute_value_string\n              plain_string_content = PLAIN_STRING_CONTENT[match]\n              kind = :delimiter\n            elsif scan(/#{TAG_END}/o)\n              kind = :tag\n              state = :initial\n            else\n              kind = :error\n              getch\n            end\n\n          when :attribute_value_string\n            if scan(plain_string_content)\n              kind = :content\n            elsif scan(/['\"]/)\n              tokens << [matched, :delimiter]\n              tokens << [:close, :string]\n              state = :attribute\n              next\n            elsif scan(/#{ENTITY}/ox)\n              kind = :entity\n            elsif scan(/&/)\n              kind = :content\n            elsif scan(/[\\n>]/)\n              tokens << [:close, :string]\n              kind = :error\n              state = :initial\n            end\n\n          else\n            raise_inspect 'Unknown state: %p' % [state], tokens\n\n          end\n\n        end\n\n        match ||= matched\n        if $DEBUG and not kind\n          raise_inspect 'Error token %p in line %d' %\n            [[match, kind], line], tokens, state\n        end\n        raise_inspect 'Empty token', tokens unless match\n\n        tokens << [match, kind]\n      end\n\n      if options[:keep_state]\n        @state = state\n        @plain_string_content = plain_string_content\n      end\n\n      tokens\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/java.rb",
    "content": "module CodeRay\n  module Scanners\n    class Java < Scanner\n    \n      register_for :java\n    \n      RESERVED_WORDS = %w(abstract assert break case catch class\n      const continue default do else enum extends final finally for\n      goto if implements import instanceof interface native new\n      package private protected public return static strictfp super switch\n      synchronized this throw throws transient try void volatile while)\n    \n      PREDEFINED_TYPES = %w(boolean byte char double float int long short)\n    \n      PREDEFINED_CONSTANTS = %w(true false null)\n    \n      IDENT_KIND = WordList.new(:ident).\n        add(RESERVED_WORDS, :reserved).\n        add(PREDEFINED_TYPES, :pre_type).\n        add(PREDEFINED_CONSTANTS, :pre_constant)\n    \n      ESCAPE = / [rbfnrtv\\n\\\\'\"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x\n      UNICODE_ESCAPE =  / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x\n    \n      def scan_tokens tokens, options\n        state = :initial\n  \n        until eos?\n          kind = nil\n          match = nil\n  \n          case state\n          when :initial\n  \n            if scan(/ \\s+ | \\\\\\n /x)\n              kind = :space\n              \n            elsif scan(%r! // [^\\n\\\\]* (?: \\\\. [^\\n\\\\]* )* | /\\* (?: .*? \\*/ | .* ) !mx)\n              kind = :comment\n  \n            elsif match = scan(/ \\# \\s* if \\s* 0 /x)\n              match << scan_until(/ ^\\# (?:elif|else|endif) .*? $ | \\z /xm) unless eos?\n              kind = :comment\n  \n            elsif scan(/ [-+*\\/=<>?:;,!&^|()\\[\\]{}~%]+ | \\.(?!\\d) /x)\n              kind = :operator\n  \n            elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x)\n              kind = IDENT_KIND[match]\n              if kind == :ident and check(/:(?!:)/)\n                match << scan(/:/)\n                kind = :label\n              end\n  \n            elsif match = scan(/L?\"/)\n              tokens << [:open, :string]\n              if match[0] == ?L\n                tokens << ['L', :modifier]\n                match = '\"'\n              end\n              state = :string\n              kind = :delimiter\n  \n            elsif scan(%r! \\@ .* !x)\n              kind = :preprocessor\n  \n            elsif scan(/ L?' (?: [^\\'\\n\\\\] | \\\\ #{ESCAPE} )? '? /ox)\n              kind = :char\n  \n            elsif scan(/0[xX][0-9A-Fa-f]+/)\n              kind = :hex\n  \n            elsif scan(/(?:0[0-7]+)(?![89.eEfF])/)\n              kind = :oct\n  \n            elsif scan(/(?:\\d+)(?![.eEfF])/)\n              kind = :integer\n  \n            elsif scan(/\\d[fF]?|\\d*\\.\\d+(?:[eE][+-]?\\d+)?[fF]?|\\d+[eE][+-]?\\d+[fF]?/)\n              kind = :float\n  \n            else\n              getch\n              kind = :error\n  \n            end\n  \n          when :string\n            if scan(/[^\\\\\\n\"]+/)\n              kind = :content\n            elsif scan(/\"/)\n              tokens << ['\"', :delimiter]\n              tokens << [:close, :string]\n              state = :initial\n              next\n            elsif scan(/ \\\\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)\n              kind = :char\n            elsif scan(/ \\\\ | $ /x)\n              tokens << [:close, :string]\n              kind = :error\n              state = :initial\n            else\n              raise_inspect \"else case \\\" reached; %p not handled.\" % peek(1), tokens\n            end\n  \n          else\n            raise_inspect 'Unknown state', tokens\n  \n          end\n  \n          match ||= matched\n          if $DEBUG and not kind\n            raise_inspect 'Error token %p in line %d' %\n              [[match, kind], line], tokens\n          end\n          raise_inspect 'Empty token', tokens unless match\n  \n          tokens << [match, kind]\n  \n        end\n  \n        if state == :string\n          tokens << [:close, :string]\n        end\n  \n        tokens\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/javascript.rb",
    "content": "# http://pastie.textmate.org/50774/\nmodule CodeRay module Scanners\n\t\n\tclass JavaScript < Scanner\n\n\t\tregister_for :javascript\n\t\t\n\t\tRESERVED_WORDS = [\n\t\t\t'asm', 'break', 'case', 'continue', 'default', 'do', 'else',\n\t\t\t'for', 'goto', 'if', 'return', 'switch', 'while',\n#\t\t\t'struct', 'union', 'enum', 'typedef',\n#\t\t\t'static', 'register', 'auto', 'extern',\n#\t\t\t'sizeof',\n      'typeof',\n#\t\t\t'volatile', 'const',  # C89\n#\t\t\t'inline', 'restrict', # C99\t\t\t\n\t\t\t'var', 'function','try','new','in',\n\t\t\t'instanceof','throw','catch'\n\t\t]\n\n\t\tPREDEFINED_CONSTANTS = [\n\t\t\t'void', 'null', 'this',\n\t\t\t'true', 'false','undefined',\n\t\t]\n\n\t\tIDENT_KIND = WordList.new(:ident).\n\t\t\tadd(RESERVED_WORDS, :reserved).\n\t\t\tadd(PREDEFINED_CONSTANTS, :pre_constant)\n\n\t\tESCAPE = / [rbfnrtv\\n\\\\\\/'\"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x\n\t\tUNICODE_ESCAPE =  / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x\n\n\t\tdef scan_tokens tokens, options\n\n\t\t\tstate = :initial\n\t\t\tstring_type = nil\n\t\t\tregexp_allowed = true\n\n\t\t\tuntil eos?\n\n\t\t\t\tkind = :error\n\t\t\t\tmatch = nil\n\n\t\t\t\tif state == :initial\n\t\t\t\t\t\n\t\t\t\t\tif scan(/ \\s+ | \\\\\\n /x)\n\t\t\t\t\t\tkind = :space\n\t\t\t\t\t\t\n\t\t\t\t\telsif scan(%r! // [^\\n\\\\]* (?: \\\\. [^\\n\\\\]* )* | /\\* (?: .*? \\*/ | .* ) !mx)\n\t\t\t\t\t\tkind = :comment\n\t\t\t\t\t\tregexp_allowed = false\n\n\t\t\t\t\telsif match = scan(/ \\# \\s* if \\s* 0 /x)\n\t\t\t\t\t\tmatch << scan_until(/ ^\\# (?:elif|else|endif) .*? $ | \\z /xm) unless eos?\n\t\t\t\t\t\tkind = :comment\n\t\t\t\t\t\tregexp_allowed = false\n\n\t\t\t\t  elsif regexp_allowed and scan(/\\//)\n\t\t\t\t    tokens << [:open, :regexp]\n\t\t\t\t    state = :regex\n\t\t\t\t\t\tkind = :delimiter\n\t\t\t\t\t\t\n\t\t\t\t\telsif scan(/ [-+*\\/=<>?:;,!&^|()\\[\\]{}~%] | \\.(?!\\d) /x)\n\t\t\t\t\t\tkind = :operator\n\t\t\t\t\t\tregexp_allowed=true\n\t\t\t\t\t\t\n\t\t\t\t\telsif match = scan(/ [$A-Za-z_][A-Za-z_0-9]* /x)\n\t\t\t\t\t\tkind = IDENT_KIND[match]\n#\t\t\t\t\t\tif kind == :ident and check(/:(?!:)/)\n#\t\t\t\t\t\t\tmatch << scan(/:/)\n#\t\t\t\t\t\t\tkind = :label\n#\t\t\t\t\t\tend\n\t\t\t\t\t\tregexp_allowed=false\n\t\t\t\t\t\t\n\t\t\t\t\telsif match = scan(/[\"']/)\n\t\t\t\t\t\ttokens << [:open, :string]\n            string_type = matched\n\t\t\t\t\t\tstate = :string\n\t\t\t\t\t\tkind = :delimiter\n\t\t\t\t\t\t\n#\t\t\t\t\telsif scan(/#\\s*(\\w*)/)\n#\t\t\t\t\t\tkind = :preprocessor  # FIXME multiline preprocs\n#\t\t\t\t\t\tstate = :include_expected if self[1] == 'include'\n#\t\t\t\t\t\t\n#\t\t\t\t\telsif scan(/ L?' (?: [^\\'\\n\\\\] | \\\\ #{ESCAPE} )? '? /ox)\n#\t\t\t\t\t\tkind = :char\n\t\t\t\t\n\t\t\t\t\telsif scan(/0[xX][0-9A-Fa-f]+/)\n\t\t\t\t\t\tkind = :hex\n\t\t\t\t\t\tregexp_allowed=false\n\t\t\t\t\t\t\n\t\t\t\t\telsif scan(/(?:0[0-7]+)(?![89.eEfF])/)\n\t\t\t\t\t\tkind = :oct\n\t\t\t\t\t\tregexp_allowed=false\n\t\t\t\t\t\t\n\t\t\t\t\telsif scan(/(?:\\d+)(?![.eEfF])/)\n\t\t\t\t\t\tkind = :integer\n\t\t\t\t\t\tregexp_allowed=false\n\t\t\t\t\t\t\n\t\t\t\t\telsif scan(/\\d[fF]?|\\d*\\.\\d+(?:[eE][+-]?\\d+)?[fF]?|\\d+[eE][+-]?\\d+[fF]?/)\n\t\t\t\t\t\tkind = :float\n\t\t\t\t\t\tregexp_allowed=false\n\n\t\t\t\t\telse\n\t\t\t\t\t\tgetch\n\t\t\t\t\tend\n\t\t\t\t\t\n\t\t\t\telsif state == :regex\n\t\t\t\t\tif scan(/[^\\\\\\/]+/)\n\t\t\t\t\t\tkind = :content\n\t\t\t\t  elsif scan(/\\\\\\/|\\\\\\\\/)\n\t\t\t\t\t\tkind = :content\n\t\t\t\t  elsif scan(/\\//)\n\t\t\t\t\t  tokens << [matched, :delimiter]\n\t\t\t\t    tokens << [:close, :regexp]\n\t\t\t\t    state = :initial\n\t\t\t\t    next\n\t\t\t\t  else\n\t\t\t\t    getch\n\t\t\t\t    kind = :content\n\t\t\t\t\tend\n\t\t\t\t  \n\t\t\t\telsif state == :string\n\t\t\t\t\tif scan(/[^\\\\\"']+/)\n\t\t\t\t\t\tkind = :content\n\t\t\t\t\telsif scan(/[\"']/)\n\t\t\t\t\t\tif string_type==matched\n\t\t\t\t\t\t  tokens << [matched, :delimiter]\n\t\t\t\t\t\t  tokens << [:close, :string]\n\t\t\t\t\t\t  state = :initial\n\t\t\t\t\t\t  string_type=nil\n\t\t\t\t\t\t  next\n\t\t\t\t\t\telse\n\t\t\t\t\t\t  kind = :content\n\t\t\t\t\t\tend\n\t\t\t\t\telsif scan(/ \\\\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)\n\t\t\t\t\t\tkind = :char\n\t\t\t\t\telsif scan(/ \\\\ | $ /x)\n\t\t\t\t\t\tkind = :error\n\t\t\t\t\t\tstate = :initial\n\t\t\t\t\telse\n\t\t\t\t\t\traise \"else case \\\" reached; %p not handled.\" % peek(1), tokens\n\t\t\t\t\tend\n\t\t\t\t\t\n#\t\t\t\telsif state == :include_expected\n#\t\t\t\t\tif scan(/<[^>\\n]+>?|\"[^\"\\n\\\\]*(?:\\\\.[^\"\\n\\\\]*)*\"?/)\n#\t\t\t\t\t\tkind = :include\n#\t\t\t\t\t\tstate = :initial\n#\t\t\t\t\t\t\n#\t\t\t\t\telsif match = scan(/\\s+/)\n#\t\t\t\t\t\tkind = :space\n#\t\t\t\t\t\tstate = :initial if match.index ?\\n\n#\t\t\t\t\t\t\n#\t\t\t\t\telse\n#\t\t\t\t\t\tgetch\n#\t\t\t\t\t\t\n#\t\t\t\t\tend\n#\t\t\t\t\t\n\t\t\t\telse\n\t\t\t\t\traise 'else-case reached', tokens\n\t\t\t\t\t\n\t\t\t\tend\n\t\t\t\t\n\t\t\t\tmatch ||= matched\n#\t\t\t\traise [match, kind], tokens if kind == :error\n        \n\t\t\t\ttokens << [match, kind]\n\t\t\t\t\n\t\t\tend\n\t\t  tokens\n\t\t\t\n\t\tend\n\n\tend\n\nend end"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/nitro_xhtml.rb",
    "content": "module CodeRay\nmodule Scanners\n\n  load :html\n  load :ruby\n\n  # Nitro XHTML Scanner\n  #\n  # $Id$\n  class NitroXHTML < Scanner\n\n    include Streamable\n    register_for :nitro_xhtml\n\n    NITRO_RUBY_BLOCK = /\n      <\\?r\n      (?>\n        [^\\?]*\n        (?> \\?(?!>) [^\\?]* )*\n      )\n      (?: \\?> )?\n    |\n      <ruby>\n      (?>\n        [^<]*\n        (?> <(?!\\/ruby>) [^<]* )*\n      )\n      (?: <\\/ruby> )?\n    |\n      <%\n      (?>\n        [^%]*\n        (?> %(?!>) [^%]* )*\n      )\n      (?: %> )?\n    /mx\n\n    NITRO_VALUE_BLOCK = /\n      \\#\n      (?:\n        \\{\n        [^{}]*\n        (?>\n          \\{ [^}]* \\}\n          (?> [^{}]* )\n        )*\n        \\}?\n      | \\| [^|]* \\|?\n      | \\( [^)]* \\)?\n      | \\[ [^\\]]* \\]?\n      | \\\\ [^\\\\]* \\\\?\n      )\n    /x\n\n    NITRO_ENTITY = /\n      % (?: \\#\\d+ | \\w+ ) ;\n    /\n\n    START_OF_RUBY = /\n      (?=[<\\#%])\n      < (?: \\?r | % | ruby> )\n    | \\# [{(|]\n    | % (?: \\#\\d+ | \\w+ ) ;\n    /x\n\n    CLOSING_PAREN = Hash.new do |h, p|\n      h[p] = p\n    end.update( {\n      '(' => ')',\n      '[' => ']',\n      '{' => '}',\n    } )\n\n  private\n\n    def setup\n      @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true\n      @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true\n    end\n\n    def reset_instance\n      super\n      @html_scanner.reset\n    end\n\n    def scan_tokens tokens, options\n\n      until eos?\n\n        if (match = scan_until(/(?=#{START_OF_RUBY})/o) || scan_until(/\\z/)) and not match.empty?\n          @html_scanner.tokenize match\n\n        elsif match = scan(/#{NITRO_VALUE_BLOCK}/o)\n          start_tag = match[0,2]\n          delimiter = CLOSING_PAREN[start_tag[1,1]]\n          end_tag = match[-1,1] == delimiter ? delimiter : ''\n          tokens << [:open, :inline]\n          tokens << [start_tag, :inline_delimiter]\n          code = match[start_tag.size .. -1 - end_tag.size]\n          @ruby_scanner.tokenize code\n          tokens << [end_tag, :inline_delimiter] unless end_tag.empty?\n          tokens << [:close, :inline]\n\n        elsif match = scan(/#{NITRO_RUBY_BLOCK}/o)\n          start_tag = '<?r'\n          end_tag = match[-2,2] == '?>' ? '?>' : ''\n          tokens << [:open, :inline]\n          tokens << [start_tag, :inline_delimiter]\n          code = match[start_tag.size .. -(end_tag.size)-1]\n          @ruby_scanner.tokenize code\n          tokens << [end_tag, :inline_delimiter] unless end_tag.empty?\n          tokens << [:close, :inline]\n\n        elsif entity = scan(/#{NITRO_ENTITY}/o)\n          tokens << [entity, :entity]\n        \n        elsif scan(/%/)\n          tokens << [matched, :error]\n\n        else\n          raise_inspect 'else-case reached!', tokens\n        end\n\n      end\n\n      tokens\n\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/php.rb",
    "content": "module CodeRay module Scanners\n\t\n\tclass PHP < Scanner\n\n\t\tregister_for :php\n\t\t\n\t\tRESERVED_WORDS = [\n          'and', 'or', 'xor', '__FILE__', 'exception', '__LINE__', 'array', 'as', 'break', 'case',\n          'class', 'const', 'continue', 'declare', 'default',\n          'die', 'do', 'echo', 'else', 'elseif',\n          'empty', 'enddeclare', 'endfor', 'endforeach', 'endif',\n          'endswitch', 'endwhile', 'eval', 'exit', 'extends',\n          'for', 'foreach', 'function', 'global', 'if',\n          'include', 'include_once', 'isset', 'list', 'new',\n          'print', 'require', 'require_once', 'return', 'static',\n          'switch', 'unset', 'use', 'var', 'while',\n          '__FUNCTION__', '__CLASS__', '__METHOD__', 'final', 'php_user_filter',\n          'interface', 'implements', 'extends', 'public', 'private',\n          'protected', 'abstract', 'clone', 'try', 'catch',\n          'throw', 'cfunction', 'old_function' \n\t\t]\n\n\t\tPREDEFINED_CONSTANTS = [\n\t\t\t'null', '$this', 'true', 'false'\n\t\t]\n\n\t\tIDENT_KIND = WordList.new(:ident).\n\t\t\tadd(RESERVED_WORDS, :reserved).\n\t\t\tadd(PREDEFINED_CONSTANTS, :pre_constant)\n\n\t\tESCAPE = / [\\$\\wrbfnrtv\\n\\\\\\/'\"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x\n\t\tUNICODE_ESCAPE =  / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x\n\n\t\tdef scan_tokens tokens, options\n\n\t\t\tstate = :waiting_php\n\t\t\tstring_type = nil\n\t\t\tregexp_allowed = true\n\n\t\t\tuntil eos?\n\n\t\t\t\tkind = :error\n\t\t\t\tmatch = nil\n\n\t\t\t\tif state == :initial\n\t\t\t\t\t\n\t\t\t\t\tif scan(/ \\s+ | \\\\\\n /x)\n\t\t\t\t\t\tkind = :space\n\t\t\t\t\t\t\n\t\t\t\t    elsif scan(/\\?>/)\n    \t\t\t\t    kind = :char\n    \t\t\t\t    state = :waiting_php\n\t\t\t\t\t\t\n\t\t\t\t\telsif scan(%r{ (//|\\#) [^\\n\\\\]* (?: \\\\. [^\\n\\\\]* )* | /\\* (?: .*? \\*/ | .* ) }mx)\n\t\t\t\t\t\tkind = :comment\n\t\t\t\t\t\tregexp_allowed = false\n\n\t\t\t\t\telsif match = scan(/ \\# \\s* if \\s* 0 /x)\n\t\t\t\t\t\tmatch << scan_until(/ ^\\# (?:elif|else|endif) .*? $ | \\z /xm) unless eos?\n\t\t\t\t\t\tkind = :comment\n\t\t\t\t\t\tregexp_allowed = false\n\n\t\t\t\t  elsif regexp_allowed and scan(/\\//)\n\t\t\t\t    tokens << [:open, :regexp]\n\t\t\t\t    state = :regex\n\t\t\t\t\t\tkind = :delimiter\n\t\t\t\t\t\t\n\t\t\t\t\telsif scan(/ [-+*\\/=<>?:;,!&^|()\\[\\]{}~%] | \\.(?!\\d) /x)\n\t\t\t\t\t\tkind = :operator\n\t\t\t\t\t\tregexp_allowed=true\n\t\t\t\t\t\t\n\t\t\t\t\telsif match = scan(/ [$@A-Za-z_][A-Za-z_0-9]* /x)\n\t\t\t\t\t\tkind = IDENT_KIND[match]\n\t\t\t\t\t\tregexp_allowed=false\n\t\t\t\t\t\t\n\t\t\t\t\telsif match = scan(/[\"']/)\n\t\t\t\t\t\ttokens << [:open, :string]\n                        string_type = matched\n\t\t\t\t\t\tstate = :string\n\t\t\t\t\t\tkind = :delimiter\n\t\t\t\t\n\t\t\t\t\telsif scan(/0[xX][0-9A-Fa-f]+/)\n\t\t\t\t\t\tkind = :hex\n\t\t\t\t\t\tregexp_allowed=false\n\t\t\t\t\t\t\n\t\t\t\t\telsif scan(/(?:0[0-7]+)(?![89.eEfF])/)\n\t\t\t\t\t\tkind = :oct\n\t\t\t\t\t\tregexp_allowed=false\n\t\t\t\t\t\t\n\t\t\t\t\telsif scan(/(?:\\d+)(?![.eEfF])/)\n\t\t\t\t\t\tkind = :integer\n\t\t\t\t\t\tregexp_allowed=false\n\t\t\t\t\t\t\n\t\t\t\t\telsif scan(/\\d[fF]?|\\d*\\.\\d+(?:[eE][+-]?\\d+)?[fF]?|\\d+[eE][+-]?\\d+[fF]?/)\n\t\t\t\t\t\tkind = :float\n\t\t\t\t\t\tregexp_allowed=false\n\n\t\t\t\t\telse\n\t\t\t\t\t\tgetch\n\t\t\t\t\tend\n\t\t\t\t\t\n\t\t\t\telsif state == :regex\n\t\t\t\t\tif scan(/[^\\\\\\/]+/)\n\t\t\t\t\t\tkind = :content\n\t\t\t\t  elsif scan(/\\\\\\/|\\\\/)\n\t\t\t\t\t\tkind = :content\n\t\t\t\t  elsif scan(/\\//)\n\t\t\t\t\t  tokens << [matched, :delimiter]\n\t\t\t\t    tokens << [:close, :regexp]\n\t\t\t\t    state = :initial\n\t\t\t\t    next\n\t\t\t\t  else\n\t\t\t\t    getch\n\t\t\t\t    kind = :content\n\t\t\t\t\tend\n\t\t\t\t  \n\t\t\t\telsif state == :string\n\t\t\t\t\tif scan(/[^\\\\\"']+/)\n\t\t\t\t\t\tkind = :content\n\t\t\t\t\telsif scan(/[\"']/)\n\t\t\t\t\t\tif string_type==matched\n\t\t\t\t\t\t  tokens << [matched, :delimiter]\n\t\t\t\t\t\t  tokens << [:close, :string]\n\t\t\t\t\t\t  state = :initial\n\t\t\t\t\t\t  string_type=nil\n\t\t\t\t\t\t  next\n\t\t\t\t\t\telse\n\t\t\t\t\t\t  kind = :content\n\t\t\t\t\t\tend\n\t\t\t\t\telsif scan(/ \\\\ (?: \\S ) /mox)\n\t\t\t\t\t\tkind = :char\n\t\t\t\t\telsif scan(/ \\\\ | $ /x)\n\t\t\t\t\t\tkind = :error\n\t\t\t\t\t\tstate = :initial\n\t\t\t\t\telse\n\t\t\t\t\t\traise \"else case \\\" reached; %p not handled.\" % peek(1), tokens\n\t\t\t\t\tend\t\t\n\t\t\t\t\t\t\n\t\t\t\telsif state == :waiting_php\n                  if scan(/<\\?php/m)\n\t\t\t\t    kind = :char\n\t\t\t\t    state = :initial\n\t\t\t\t  elsif scan(/[^<]+/)\n\t\t\t\t    kind = :comment\n                  else\n                    kind = :comment\n                    getch\n\t\t\t\t  end\n\t\t\t\telse\n\t\t\t\t\traise 'else-case reached', tokens\n\t\t\t\t\t\n\t\t\t\tend\n\t\t\t\t\n\t\t\t\tmatch ||= matched\n        \n\t\t\t\ttokens << [match, kind]\n\t\t\t\t\n\t\t\tend\n\t\t  tokens\n\t\t\t\n\t\tend\n\n\tend\n\nend end"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/plaintext.rb",
    "content": "module CodeRay\nmodule Scanners\n\n  class Plaintext < Scanner\n\n    register_for :plaintext, :plain\n    \n    include Streamable\n\n    def scan_tokens tokens, options\n      text = (scan_until(/\\z/) || '')\n      tokens << [text, :plain]\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/rhtml.rb",
    "content": "module CodeRay\nmodule Scanners\n\n  load :html\n  load :ruby\n\n  # RHTML Scanner\n  #\n  # $Id$\n  class RHTML < Scanner\n\n    include Streamable\n    register_for :rhtml\n\n    ERB_RUBY_BLOCK = /\n      <%(?!%)[=-]?\n      (?>\n        [^\\-%]*    # normal*\n        (?>        # special\n          (?: %(?!>) | -(?!%>) )\n          [^\\-%]*  # normal*\n        )*\n      )\n      (?: -?%> )?\n    /x\n\n    START_OF_ERB = /\n      <%(?!%)\n    /x\n\n  private\n\n    def setup\n      @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true\n      @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true\n    end\n\n    def reset_instance\n      super\n      @html_scanner.reset\n    end\n\n    def scan_tokens tokens, options\n\n      until eos?\n\n        if (match = scan_until(/(?=#{START_OF_ERB})/o) || scan_until(/\\z/)) and not match.empty?\n          @html_scanner.tokenize match\n\n        elsif match = scan(/#{ERB_RUBY_BLOCK}/o)\n          start_tag = match[/\\A<%[-=]?/]\n          end_tag = match[/-?%?>?\\z/]\n          tokens << [:open, :inline]\n          tokens << [start_tag, :inline_delimiter]\n          code = match[start_tag.size .. -1 - end_tag.size]\n          @ruby_scanner.tokenize code\n          tokens << [end_tag, :inline_delimiter] unless end_tag.empty?\n          tokens << [:close, :inline]\n\n        else\n          raise_inspect 'else-case reached!', tokens\n        end\n\n      end\n\n      tokens\n\n    end\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/ruby/patterns.rb",
    "content": "module CodeRay\nmodule Scanners\n\n  module Ruby::Patterns  # :nodoc:\n\n    RESERVED_WORDS = %w[\n      and def end in or unless begin\n      defined? ensure module redo super until\n      BEGIN break do next rescue then\n      when END case else for retry\n      while alias class elsif if not return\n      undef yield\n    ]\n\n    DEF_KEYWORDS = %w[ def ]\n    UNDEF_KEYWORDS = %w[ undef ]\n    MODULE_KEYWORDS = %w[class module]\n    DEF_NEW_STATE = WordList.new(:initial).\n      add(DEF_KEYWORDS, :def_expected).\n      add(UNDEF_KEYWORDS, :undef_expected).\n      add(MODULE_KEYWORDS, :module_expected)\n\n    IDENTS_ALLOWING_REGEXP = %w[\n      and or not while until unless if then elsif when sub sub! gsub gsub!\n      scan slice slice! split\n    ]\n    REGEXP_ALLOWED = WordList.new(false).\n      add(IDENTS_ALLOWING_REGEXP, :set)\n\n    PREDEFINED_CONSTANTS = %w[\n      nil true false self\n      DATA ARGV ARGF __FILE__ __LINE__\n    ]\n\n    IDENT_KIND = WordList.new(:ident).\n      add(RESERVED_WORDS, :reserved).\n      add(PREDEFINED_CONSTANTS, :pre_constant)\n\n    IDENT = /[a-z_][\\w_]*/i\n\n    METHOD_NAME = / #{IDENT} [?!]? /ox\n    METHOD_NAME_OPERATOR = /\n      \\*\\*?           # multiplication and power\n      | [-+]@?        # plus, minus\n      | [\\/%&|^`~]    # division, modulo or format strings, &and, |or, ^xor, `system`, tilde\n      | \\[\\]=?        # array getter and setter\n      | << | >>       # append or shift left, shift right\n      | <=?>? | >=?   # comparison, rocket operator\n      | ===?          # simple equality and case equality\n    /ox\n    METHOD_NAME_EX = / #{IDENT} (?:[?!]|=(?!>))? | #{METHOD_NAME_OPERATOR} /ox\n    INSTANCE_VARIABLE = / @ #{IDENT} /ox\n    CLASS_VARIABLE = / @@ #{IDENT} /ox\n    OBJECT_VARIABLE = / @@? #{IDENT} /ox\n    GLOBAL_VARIABLE = / \\$ (?: #{IDENT} | [1-9]\\d* | 0\\w* | [~&+`'=\\/,;_.<>!@$?*\":\\\\] | -[a-zA-Z_0-9] ) /ox\n    PREFIX_VARIABLE = / #{GLOBAL_VARIABLE} |#{OBJECT_VARIABLE} /ox\n    VARIABLE = / @?@? #{IDENT} | #{GLOBAL_VARIABLE} /ox\n\n    QUOTE_TO_TYPE = {\n      '`' => :shell,\n      '/'=> :regexp,\n    }\n    QUOTE_TO_TYPE.default = :string\n\n    REGEXP_MODIFIERS = /[mixounse]*/\n    REGEXP_SYMBOLS = /[|?*+?(){}\\[\\].^$]/\n\n    DECIMAL = /\\d+(?:_\\d+)*/\n    OCTAL = /0_?[0-7]+(?:_[0-7]+)*/\n    HEXADECIMAL = /0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*/\n    BINARY = /0b[01]+(?:_[01]+)*/\n\n    EXPONENT = / [eE] [+-]? #{DECIMAL} /ox\n    FLOAT_SUFFIX = / #{EXPONENT} | \\. #{DECIMAL} #{EXPONENT}? /ox\n    FLOAT_OR_INT = / #{DECIMAL} (?: #{FLOAT_SUFFIX} () )? /ox\n    NUMERIC = / [-+]? (?: (?=0) (?: #{OCTAL} | #{HEXADECIMAL} | #{BINARY} ) | #{FLOAT_OR_INT} ) /ox\n\n    SYMBOL = /\n      :\n      (?:\n        #{METHOD_NAME_EX}\n      | #{PREFIX_VARIABLE}\n      | ['\"]\n      )\n    /ox\n\n    # TODO investigste \\M, \\c and \\C escape sequences\n    # (?: M-\\\\C-|C-\\\\M-|M-\\\\c|c\\\\M-|c|C-|M-)? (?: \\\\ (?: [0-7]{3} | x[0-9A-Fa-f]{2} | . ) )\n    # assert_equal(225, ?\\M-a)\n    # assert_equal(129, ?\\M-\\C-a)\n    ESCAPE = /\n        [abefnrstv]\n      | M-\\\\C-|C-\\\\M-|M-\\\\c|c\\\\M-|c|C-|M-\n      |  [0-7]{1,3}\n      | x[0-9A-Fa-f]{1,2}\n      | .\n    /mx\n\n    CHARACTER = /\n      \\?\n      (?:\n        [^\\s\\\\]\n      | \\\\ #{ESCAPE}\n      )\n    /mx\n\n    # NOTE: This is not completely correct, but\n    # nobody needs heredoc delimiters ending with \\n.\n    HEREDOC_OPEN = /\n      << (-)?              # $1 = float\n      (?:\n        ( [A-Za-z_0-9]+ )  # $2 = delim\n      |\n        ( [\"'`\\/] )        # $3 = quote, type\n        ( [^\\n]*? ) \\3     # $4 = delim\n      )\n    /mx\n\n    RUBYDOC = /\n      =begin (?!\\S)\n      .*?\n      (?: \\Z | ^=end (?!\\S) [^\\n]* )\n    /mx\n\n    DATA = /\n      __END__$\n      .*?\n      (?: \\Z | (?=^\\#CODE) )\n    /mx\n    \n    # Checks for a valid value to follow. This enables\n    # fancy_allowed in method calls.\n    VALUE_FOLLOWS = /\n      \\s+\n      (?:\n        [%\\/][^\\s=]\n      |\n        <<-?\\S\n      |\n        #{CHARACTER}\n      )\n    /x\n\n    RUBYDOC_OR_DATA = / #{RUBYDOC} | #{DATA} /xo\n\n    RDOC_DATA_START = / ^=begin (?!\\S) | ^__END__$ /x\n\n    # FIXME: \\s and = are only a workaround, they are still allowed\n    # as delimiters.\n    FANCY_START_SAVE = / % ( [qQwWxsr] | (?![a-zA-Z0-9\\s=]) ) ([^a-zA-Z0-9]) /mx\n    FANCY_START_CORRECT = / % ( [qQwWxsr] | (?![a-zA-Z0-9]) ) ([^a-zA-Z0-9]) /mx\n\n    FancyStringType = {\n      'q' => [:string, false],\n      'Q' => [:string, true],\n      'r' => [:regexp, true],\n      's' => [:symbol, false],\n      'x' => [:shell, true]\n    }\n    FancyStringType['w'] = FancyStringType['q']\n    FancyStringType['W'] = FancyStringType[''] = FancyStringType['Q']\n\n    class StringState < Struct.new :type, :interpreted, :delim, :heredoc,\n      :paren, :paren_depth, :pattern, :next_state\n\n      CLOSING_PAREN = Hash[ *%w[\n        ( )\n        [ ]\n        < >\n        { }\n      ] ]\n\n      CLOSING_PAREN.values.each { |o| o.freeze }  # debug, if I try to change it with <<\n      OPENING_PAREN = CLOSING_PAREN.invert\n\n      STRING_PATTERN = Hash.new { |h, k|\n        delim, interpreted = *k\n        delim_pattern = Regexp.escape(delim.dup)\n        if closing_paren = CLOSING_PAREN[delim]\n          delim_pattern << Regexp.escape(closing_paren)\n        end\n\n\n        special_escapes =\n          case interpreted\n          when :regexp_symbols\n            '| ' + REGEXP_SYMBOLS.source\n          when :words\n            '| \\s'\n          end\n\n        h[k] =\n          if interpreted and not delim == '#'\n            / (?= [#{delim_pattern}\\\\] | \\# [{$@] #{special_escapes} ) /mx\n          else\n            / (?= [#{delim_pattern}\\\\] #{special_escapes} ) /mx\n          end\n      }\n\n      HEREDOC_PATTERN = Hash.new { |h, k|\n        delim, interpreted, indented = *k\n        delim_pattern = Regexp.escape(delim.dup)\n        delim_pattern = / \\n #{ '(?>[\\ \\t]*)' if indented } #{ Regexp.new delim_pattern } $ /x\n        h[k] =\n          if interpreted\n            / (?= #{delim_pattern}() | \\\\ | \\# [{$@] ) /mx  # $1 set == end of heredoc\n          else\n            / (?= #{delim_pattern}() | \\\\ ) /mx\n          end\n      }\n\n      def initialize kind, interpreted, delim, heredoc = false\n        if heredoc\n          pattern = HEREDOC_PATTERN[ [delim, interpreted, heredoc == :indented] ]\n          delim  = nil\n        else\n          pattern = STRING_PATTERN[ [delim, interpreted] ]\n          if paren = CLOSING_PAREN[delim]\n            delim, paren = paren, delim\n            paren_depth = 1\n          end\n        end\n        super kind, interpreted, delim, heredoc, paren, paren_depth, pattern, :initial\n      end\n    end unless defined? StringState\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/ruby.rb",
    "content": "module CodeRay\nmodule Scanners\n\n  # This scanner is really complex, since Ruby _is_ a complex language!\n  #\n  # It tries to highlight 100% of all common code,\n  # and 90% of strange codes.\n  #\n  # It is optimized for HTML highlighting, and is not very useful for\n  # parsing or pretty printing.\n  #\n  # For now, I think it's better than the scanners in VIM or Syntax, or\n  # any highlighter I was able to find, except Caleb's RubyLexer.\n  #\n  # I hope it's also better than the rdoc/irb lexer.\n  class Ruby < Scanner\n\n    include Streamable\n\n    register_for :ruby\n    file_extension 'rb'\n\n    helper :patterns\n\n  private\n    def scan_tokens tokens, options\n      last_token_dot = false\n      value_expected = true\n      heredocs = nil\n      last_state = nil\n      state = :initial\n      depth = nil\n      inline_block_stack = []\n\n      patterns = Patterns  # avoid constant lookup\n\n      until eos?\n        match = nil\n        kind = nil\n\n        if state.instance_of? patterns::StringState\n# {{{\n          match = scan_until(state.pattern) || scan_until(/\\z/)\n          tokens << [match, :content] unless match.empty?\n          break if eos?\n\n          if state.heredoc and self[1]  # end of heredoc\n            match = getch.to_s\n            match << scan_until(/$/) unless eos?\n            tokens << [match, :delimiter]\n            tokens << [:close, state.type]\n            state = state.next_state\n            next\n          end\n\n          case match = getch\n\n          when state.delim\n            if state.paren\n              state.paren_depth -= 1\n              if state.paren_depth > 0\n                tokens << [match, :nesting_delimiter]\n                next\n              end\n            end\n            tokens << [match, :delimiter]\n            if state.type == :regexp and not eos?\n              modifiers = scan(/#{patterns::REGEXP_MODIFIERS}/ox)\n              tokens << [modifiers, :modifier] unless modifiers.empty?\n            end\n            tokens << [:close, state.type]\n            value_expected = false\n            state = state.next_state\n\n          when '\\\\'\n            if state.interpreted\n              if esc = scan(/ #{patterns::ESCAPE} /ox)\n                tokens << [match + esc, :char]\n              else\n                tokens << [match, :error]\n              end\n            else\n              case m = getch\n              when state.delim, '\\\\'\n                tokens << [match + m, :char]\n              when nil\n                tokens << [match, :error]\n              else\n                tokens << [match + m, :content]\n              end\n            end\n\n          when '#'\n            case peek(1)\n            when '{'\n              inline_block_stack << [state, depth, heredocs]\n              value_expected = true\n              state = :initial\n              depth = 1\n              tokens << [:open, :inline]\n              tokens << [match + getch, :inline_delimiter]\n            when '$', '@'\n              tokens << [match, :escape]\n              last_state = state  # scan one token as normal code, then return here\n              state = :initial\n            else\n              raise_inspect 'else-case # reached; #%p not handled' % peek(1), tokens\n            end\n\n          when state.paren\n            state.paren_depth += 1\n            tokens << [match, :nesting_delimiter]\n\n          when /#{patterns::REGEXP_SYMBOLS}/ox\n            tokens << [match, :function]\n\n          else\n            raise_inspect 'else-case \" reached; %p not handled, state = %p' % [match, state], tokens\n\n          end\n          next\n# }}}\n        else\n# {{{\n          if match = scan(/[ \\t\\f]+/)\n            kind = :space\n            match << scan(/\\s*/) unless eos? or heredocs\n            tokens << [match, kind]\n            next\n            \n          elsif match = scan(/\\\\?\\n/)\n            kind = :space\n            if match == \"\\n\"\n              value_expected = true  # FIXME not quite true\n              state = :initial if state == :undef_comma_expected\n            end\n            if heredocs\n              unscan  # heredoc scanning needs \\n at start\n              state = heredocs.shift\n              tokens << [:open, state.type]\n              heredocs = nil if heredocs.empty?\n              next\n            else\n              match << scan(/\\s*/) unless eos?\n            end\n            tokens << [match, kind]\n            next\n          \n          elsif match = scan(/\\#.*/) or\n            ( bol? and match = scan(/#{patterns::RUBYDOC_OR_DATA}/o) )\n              kind = :comment\n              value_expected = true\n              tokens << [match, kind]\n              next\n\n          elsif state == :initial\n\n            # IDENTS #\n            if match = scan(/#{patterns::METHOD_NAME}/o)\n              if last_token_dot\n                kind = if match[/^[A-Z]/] and not match?(/\\(/) then :constant else :ident end\n              else\n                kind = patterns::IDENT_KIND[match]\n                if kind == :ident and match[/^[A-Z]/] and not match[/[!?]$/] and not match?(/\\(/)\n                  kind = :constant\n                elsif kind == :reserved\n                  state = patterns::DEF_NEW_STATE[match]\n                end\n              end\n              ## experimental!\n              value_expected = :set if\n                patterns::REGEXP_ALLOWED[match] or check(/#{patterns::VALUE_FOLLOWS}/o)\n            \n            elsif last_token_dot and match = scan(/#{patterns::METHOD_NAME_OPERATOR}/o)\n              kind = :ident\n              value_expected = :set if check(/#{patterns::VALUE_FOLLOWS}/o)\n\n            # OPERATORS #\n            elsif not last_token_dot and match = scan(/ \\.\\.\\.? | (?:\\.|::)() | [,\\(\\)\\[\\]\\{\\}] | ==?=? /x)\n              if match !~ / [.\\)\\]\\}] /x or match =~ /\\.\\.\\.?/\n                value_expected = :set\n              end\n              last_token_dot = :set if self[1]\n              kind = :operator\n              unless inline_block_stack.empty?\n                case match\n                when '{'\n                  depth += 1\n                when '}'\n                  depth -= 1\n                  if depth == 0  # closing brace of inline block reached\n                    state, depth, heredocs = inline_block_stack.pop\n                    tokens << [match, :inline_delimiter]\n                    kind = :inline\n                    match = :close\n                  end\n                end\n              end\n\n            elsif match = scan(/ ['\"] /mx)\n              tokens << [:open, :string]\n              kind = :delimiter\n              state = patterns::StringState.new :string, match == '\"', match  # important for streaming\n\n            elsif match = scan(/#{patterns::INSTANCE_VARIABLE}/o)\n              kind = :instance_variable\n\n            elsif value_expected and match = scan(/\\//)\n              tokens << [:open, :regexp]\n              kind = :delimiter\n              interpreted = true\n              state = patterns::StringState.new :regexp, interpreted, match\n\n            elsif match = scan(/#{patterns::NUMERIC}/o)\n              kind = if self[1] then :float else :integer end\n\n            elsif match = scan(/#{patterns::SYMBOL}/o)\n              case delim = match[1]\n              when ?', ?\"\n                tokens << [:open, :symbol]\n                tokens << [':', :symbol]\n                match = delim.chr\n                kind = :delimiter\n                state = patterns::StringState.new :symbol, delim == ?\", match\n              else\n                kind = :symbol\n              end\n\n            elsif match = scan(/ [-+!~^]=? | [*|&]{1,2}=? | >>? /x)\n              value_expected = :set\n              kind = :operator\n\n            elsif value_expected and match = scan(/#{patterns::HEREDOC_OPEN}/o)\n              indented = self[1] == '-'\n              quote = self[3]\n              delim = self[quote ? 4 : 2]\n              kind = patterns::QUOTE_TO_TYPE[quote]\n              tokens << [:open, kind]\n              tokens << [match, :delimiter]\n              match = :close\n              heredoc = patterns::StringState.new kind, quote != '\\'', delim, (indented ? :indented : :linestart )\n              heredocs ||= []  # create heredocs if empty\n              heredocs << heredoc\n\n            elsif value_expected and match = scan(/#{patterns::FANCY_START_CORRECT}/o)\n              kind, interpreted = *patterns::FancyStringType.fetch(self[1]) do\n                raise_inspect 'Unknown fancy string: %%%p' % k, tokens\n              end\n              tokens << [:open, kind]\n              state = patterns::StringState.new kind, interpreted, self[2]\n              kind = :delimiter\n\n            elsif value_expected and match = scan(/#{patterns::CHARACTER}/o)\n              kind = :integer\n\n            elsif match = scan(/ [\\/%]=? | <(?:<|=>?)? | [?:;] /x)\n              value_expected = :set\n              kind = :operator\n\n            elsif match = scan(/`/)\n              if last_token_dot\n                kind = :operator\n              else\n                tokens << [:open, :shell]\n                kind = :delimiter\n                state = patterns::StringState.new :shell, true, match\n              end\n\n            elsif match = scan(/#{patterns::GLOBAL_VARIABLE}/o)\n              kind = :global_variable\n\n            elsif match = scan(/#{patterns::CLASS_VARIABLE}/o)\n              kind = :class_variable\n\n            else\n              kind = :error\n              match = getch\n\n            end\n\n          elsif state == :def_expected\n            state = :initial\n            if match = scan(/(?>#{patterns::METHOD_NAME_EX})(?!\\.|::)/o)\n              kind = :method\n            else\n              next\n            end\n\n          elsif state == :undef_expected\n            state = :undef_comma_expected\n            if match = scan(/#{patterns::METHOD_NAME_EX}/o)\n              kind = :method\n            elsif match = scan(/#{patterns::SYMBOL}/o)\n              case delim = match[1]\n              when ?', ?\"\n                tokens << [:open, :symbol]\n                tokens << [':', :symbol]\n                match = delim.chr\n                kind = :delimiter\n                state = patterns::StringState.new :symbol, delim == ?\", match\n                state.next_state = :undef_comma_expected\n              else\n                kind = :symbol\n              end\n            else\n              state = :initial\n              next\n            end\n\n          elsif state == :undef_comma_expected\n            if match = scan(/,/)\n              kind = :operator\n              state = :undef_expected\n            else\n              state = :initial\n              next\n            end\n\n          elsif state == :module_expected\n            if match = scan(/<</)\n              kind = :operator\n            else\n              state = :initial\n              if match = scan(/ (?:#{patterns::IDENT}::)* #{patterns::IDENT} /ox)\n                kind = :class\n              else\n                next\n              end\n            end\n\n          end\n# }}}\n\n          value_expected = value_expected == :set\n          last_token_dot = last_token_dot == :set\n\n          if $DEBUG and not kind\n            raise_inspect 'Error token %p in line %d' %\n              [[match, kind], line], tokens, state\n          end\n          raise_inspect 'Empty token', tokens unless match\n\n          tokens << [match, kind]\n\n          if last_state\n            state = last_state\n            last_state = nil\n          end\n        end\n      end\n\n      inline_block_stack << [state] if state.is_a? patterns::StringState\n      until inline_block_stack.empty?\n        this_block = inline_block_stack.pop\n        tokens << [:close, :inline] if this_block.size > 1\n        state = this_block.first\n        tokens << [:close, state.type]\n      end\n\n      tokens\n    end\n\n  end\n\nend\nend\n\n# vim:fdm=marker\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/scheme.rb",
    "content": "module CodeRay\n  module Scanners\n\n    # Scheme scanner for CodeRay (by closure).\n    # Thanks to murphy for putting CodeRay into public.\n    class Scheme < Scanner\n      \n      register_for :scheme\n      file_extension :scm\n\n      CORE_FORMS = %w[\n        lambda let let* letrec syntax-case define-syntax let-syntax\n        letrec-syntax begin define quote if or and cond case do delay\n        quasiquote set! cons force call-with-current-continuation call/cc\n      ]\n\n      IDENT_KIND = CaseIgnoringWordList.new(:ident).\n        add(CORE_FORMS, :reserved)\n      \n      #IDENTIFIER_INITIAL = /[a-z!@\\$%&\\*\\/\\:<=>\\?~_\\^]/i\n      #IDENTIFIER_SUBSEQUENT = /#{IDENTIFIER_INITIAL}|\\d|\\.|\\+|-/\n      #IDENTIFIER = /#{IDENTIFIER_INITIAL}#{IDENTIFIER_SUBSEQUENT}*|\\+|-|\\.{3}/\n      IDENTIFIER = /[a-zA-Z!@$%&*\\/:<=>?~_^][\\w!@$%&*\\/:<=>?~^.+\\-]*|[+-]|\\.\\.\\./\n      DIGIT = /\\d/\n      DIGIT10 = DIGIT\n      DIGIT16 = /[0-9a-f]/i\n      DIGIT8 = /[0-7]/\n      DIGIT2 = /[01]/\n      RADIX16 = /\\#x/i\n      RADIX8 = /\\#o/i\n      RADIX2 = /\\#b/i\n      RADIX10 = /\\#d/i\n      EXACTNESS = /#i|#e/i\n      SIGN = /[\\+-]?/\n      EXP_MARK = /[esfdl]/i\n      EXP = /#{EXP_MARK}#{SIGN}#{DIGIT}+/\n      SUFFIX = /#{EXP}?/\n      PREFIX10 = /#{RADIX10}?#{EXACTNESS}?|#{EXACTNESS}?#{RADIX10}?/\n      PREFIX16 = /#{RADIX16}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX16}/\n      PREFIX8 = /#{RADIX8}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX8}/\n      PREFIX2 = /#{RADIX2}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX2}/\n      UINT10 = /#{DIGIT10}+#*/\n      UINT16 = /#{DIGIT16}+#*/\n      UINT8 = /#{DIGIT8}+#*/\n      UINT2 = /#{DIGIT2}+#*/\n      DECIMAL = /#{DIGIT10}+#+\\.#*#{SUFFIX}|#{DIGIT10}+\\.#{DIGIT10}*#*#{SUFFIX}|\\.#{DIGIT10}+#*#{SUFFIX}|#{UINT10}#{EXP}/\n      UREAL10 = /#{UINT10}\\/#{UINT10}|#{DECIMAL}|#{UINT10}/\n      UREAL16 = /#{UINT16}\\/#{UINT16}|#{UINT16}/\n      UREAL8 = /#{UINT8}\\/#{UINT8}|#{UINT8}/\n      UREAL2 = /#{UINT2}\\/#{UINT2}|#{UINT2}/\n      REAL10 = /#{SIGN}#{UREAL10}/\n      REAL16 = /#{SIGN}#{UREAL16}/\n      REAL8 = /#{SIGN}#{UREAL8}/\n      REAL2 = /#{SIGN}#{UREAL2}/\n      IMAG10 = /i|#{UREAL10}i/\n      IMAG16 = /i|#{UREAL16}i/\n      IMAG8 = /i|#{UREAL8}i/\n      IMAG2 = /i|#{UREAL2}i/\n      COMPLEX10 = /#{REAL10}@#{REAL10}|#{REAL10}\\+#{IMAG10}|#{REAL10}-#{IMAG10}|\\+#{IMAG10}|-#{IMAG10}|#{REAL10}/\n      COMPLEX16 = /#{REAL16}@#{REAL16}|#{REAL16}\\+#{IMAG16}|#{REAL16}-#{IMAG16}|\\+#{IMAG16}|-#{IMAG16}|#{REAL16}/\n      COMPLEX8 = /#{REAL8}@#{REAL8}|#{REAL8}\\+#{IMAG8}|#{REAL8}-#{IMAG8}|\\+#{IMAG8}|-#{IMAG8}|#{REAL8}/\n      COMPLEX2 = /#{REAL2}@#{REAL2}|#{REAL2}\\+#{IMAG2}|#{REAL2}-#{IMAG2}|\\+#{IMAG2}|-#{IMAG2}|#{REAL2}/\n      NUM10 = /#{PREFIX10}?#{COMPLEX10}/\n      NUM16 = /#{PREFIX16}#{COMPLEX16}/\n      NUM8 = /#{PREFIX8}#{COMPLEX8}/\n      NUM2 = /#{PREFIX2}#{COMPLEX2}/\n      NUM = /#{NUM10}|#{NUM16}|#{NUM8}|#{NUM2}/\n    \n    private\n      def scan_tokens tokens,options\n        \n        state = :initial\n        ident_kind = IDENT_KIND\n        \n        until eos?\n          kind = match = nil\n          \n          case state\n          when :initial\n            if scan(/ \\s+ | \\\\\\n /x)\n              kind = :space\n            elsif scan(/['\\(\\[\\)\\]]|#\\(/)\n              kind = :operator_fat\n            elsif scan(/;.*/)\n              kind = :comment\n            elsif scan(/#\\\\(?:newline|space|.?)/)\n              kind = :char\n            elsif scan(/#[ft]/)\n              kind = :pre_constant\n            elsif scan(/#{IDENTIFIER}/o)\n              kind = ident_kind[matched]\n            elsif scan(/\\./)\n              kind = :operator\n            elsif scan(/\"/)\n              tokens << [:open, :string]\n              state = :string\n              tokens << ['\"', :delimiter]\n              next\n            elsif scan(/#{NUM}/o) and not matched.empty?\n              kind = :integer\n            elsif getch\n              kind = :error\n            end\n            \n          when :string\n            if scan(/[^\"\\\\]+/) or scan(/\\\\.?/)\n              kind = :content\n            elsif scan(/\"/)\n              tokens << ['\"', :delimiter]\n              tokens << [:close, :string]\n              state = :initial\n              next\n            else\n              raise_inspect \"else case \\\" reached; %p not handled.\" % peek(1),\n                tokens, state\n            end\n            \n          else\n            raise \"else case reached\"\n          end\n          \n          match ||= matched\n          if $DEBUG and not kind\n            raise_inspect 'Error token %p in line %d' %\n            [[match, kind], line], tokens\n          end\n          raise_inspect 'Empty token', tokens, state unless match\n          \n          tokens << [match, kind]\n          \n        end  # until eos\n        \n        if state == :string\n          tokens << [:close, :string]\n        end\n        \n        tokens\n        \n      end #scan_tokens\n    end #class\n  end #module scanners\nend #module coderay"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/scanners/xml.rb",
    "content": "module CodeRay\nmodule Scanners\n\n  load :html\n\n  # XML Scanner\n  #\n  # $Id$\n  #\n  # Currently this is the same scanner as Scanners::HTML.\n  class XML < HTML\n\n    register_for :xml\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/style.rb",
    "content": "module CodeRay\n\n  # This module holds the Style class and its subclasses.\n  #\n  # See Plugin.\n  module Styles\n    extend PluginHost\n    plugin_path File.dirname(__FILE__), 'styles'\n\n    class Style\n      extend Plugin\n      plugin_host Styles\n\n      DEFAULT_OPTIONS = { }\n\n    end\n\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/styles/_map.rb",
    "content": "module CodeRay\nmodule Styles\n\n  default :cycnus\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/styles/cycnus.rb",
    "content": "module CodeRay\nmodule Styles\n\n  class Cycnus < Style\n\n    register_for :cycnus\n\n    code_background = '#f8f8f8'\n    numbers_background = '#def'\n    border_color = 'silver'\n    normal_color = '#100'\n\n    CSS_MAIN_STYLES = <<-MAIN\n.CodeRay {\n  background-color: #{code_background};\n  border: 1px solid #{border_color};\n  font-family: 'Courier New', 'Terminal', monospace;\n  color: #{normal_color};\n}\n.CodeRay pre { margin: 0px }\n\ndiv.CodeRay { }\n\nspan.CodeRay { white-space: pre; border: 0px; padding: 2px }\n\ntable.CodeRay { border-collapse: collapse; width: 100%; padding: 2px }\ntable.CodeRay td { padding: 2px 4px; vertical-align: top }\n\n.CodeRay .line_numbers, .CodeRay .no {\n  background-color: #{numbers_background};\n  color: gray;\n  text-align: right;\n}\n.CodeRay .line_numbers tt { font-weight: bold }\n.CodeRay .no { padding: 0px 4px }\n.CodeRay .code { width: 100% }\n\nol.CodeRay { font-size: 10pt }\nol.CodeRay li { white-space: pre }\n\n.CodeRay .code pre { overflow: auto }\n    MAIN\n\n    TOKEN_COLORS = <<-'TOKENS'\n.debug { color:white ! important; background:blue ! important; }\n\n.af { color:#00C }\n.an { color:#007 }\n.av { color:#700 }\n.aw { color:#C00 }\n.bi { color:#509; font-weight:bold }\n.c  { color:#666; }\n\n.ch { color:#04D }\n.ch .k { color:#04D }\n.ch .dl { color:#039 }\n\n.cl { color:#B06; font-weight:bold }\n.co { color:#036; font-weight:bold }\n.cr { color:#0A0 }\n.cv { color:#369 }\n.df { color:#099; font-weight:bold }\n.di { color:#088; font-weight:bold }\n.dl { color:black }\n.do { color:#970 }\n.ds { color:#D42; font-weight:bold }\n.e  { color:#666; font-weight:bold }\n.en { color:#800; font-weight:bold }\n.er { color:#F00; background-color:#FAA }\n.ex { color:#F00; font-weight:bold }\n.fl { color:#60E; font-weight:bold }\n.fu { color:#06B; font-weight:bold }\n.gv { color:#d70; font-weight:bold }\n.hx { color:#058; font-weight:bold }\n.i  { color:#00D; font-weight:bold }\n.ic { color:#B44; font-weight:bold }\n\n.il { background: #eee }\n.il .il { background: #ddd }\n.il .il .il { background: #ccc }\n.il .idl { font-weight: bold; color: #888 }\n\n.in { color:#B2B; font-weight:bold }\n.iv { color:#33B }\n.la { color:#970; font-weight:bold }\n.lv { color:#963 }\n.oc { color:#40E; font-weight:bold }\n.of { color:#000; font-weight:bold }\n.op { }\n.pc { color:#038; font-weight:bold }\n.pd { color:#369; font-weight:bold }\n.pp { color:#579 }\n.pt { color:#339; font-weight:bold }\n.r  { color:#080; font-weight:bold }\n\n.rx { background-color:#fff0ff }\n.rx .k { color:#808 }\n.rx .dl { color:#404 }\n.rx .mod { color:#C2C }\n.rx .fu  { color:#404; font-weight: bold }\n\n.s  { background-color:#fff0f0 }\n.s  .s { background-color:#ffe0e0 }\n.s  .s  .s { background-color:#ffd0d0 }\n.s  .k { color:#D20 }\n.s  .dl { color:#710 }\n\n.sh { background-color:#f0fff0 }\n.sh .k { color:#2B2 }\n.sh .dl { color:#161 }\n\n.sy { color:#A60 }\n.sy .k { color:#A60 }\n.sy .dl { color:#630 }\n\n.ta { color:#070 }\n.tf { color:#070; font-weight:bold }\n.ts { color:#D70; font-weight:bold }\n.ty { color:#339; font-weight:bold }\n.v  { color:#036 }\n.xt { color:#444 }\n    TOKENS\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/styles/murphy.rb",
    "content": "module CodeRay\nmodule Styles\n\n  class Murphy < Style\n\n    register_for :murphy\n\n    code_background = '#001129'\n    numbers_background = code_background\n    border_color = 'silver'\n    normal_color = '#C0C0C0'\n\n    CSS_MAIN_STYLES = <<-MAIN\n.CodeRay {\n  background-color: #{code_background};\n  border: 1px solid #{border_color};\n  font-family: 'Courier New', 'Terminal', monospace;\n  color: #{normal_color};\n}\n.CodeRay pre { margin: 0px; }\n\ndiv.CodeRay { }\n\nspan.CodeRay { white-space: pre; border: 0px; padding: 2px; }\n\ntable.CodeRay { border-collapse: collapse; width: 100%; padding: 2px; }\ntable.CodeRay td { padding: 2px 4px; vertical-align: top; }\n\n.CodeRay .line_numbers, .CodeRay .no {\n  background-color: #{numbers_background};\n  color: gray;\n  text-align: right;\n}\n.CodeRay .line_numbers tt { font-weight: bold; }\n.CodeRay .no { padding: 0px 4px; }\n.CodeRay .code { width: 100%; }\n\nol.CodeRay { font-size: 10pt; }\nol.CodeRay li { white-space: pre; }\n\n.CodeRay .code pre { overflow: auto; }\n    MAIN\n\n    TOKEN_COLORS = <<-'TOKENS'\n.af { color:#00C; }\n.an { color:#007; }\n.av { color:#700; }\n.aw { color:#C00; }\n.bi { color:#509; font-weight:bold; }\n.c  { color:#555; background-color: black; }\n\n.ch { color:#88F; }\n.ch .k { color:#04D; }\n.ch .dl { color:#039; }\n\n.cl { color:#e9e; font-weight:bold; }\n.co { color:#5ED; font-weight:bold; }\n.cr { color:#0A0; }\n.cv { color:#ccf; }\n.df { color:#099; font-weight:bold; }\n.di { color:#088; font-weight:bold; }\n.dl { color:black; }\n.do { color:#970; }\n.ds { color:#D42; font-weight:bold; }\n.e  { color:#666; font-weight:bold; }\n.er { color:#F00; background-color:#FAA; }\n.ex { color:#F00; font-weight:bold; }\n.fl { color:#60E; font-weight:bold; }\n.fu { color:#5ed; font-weight:bold; }\n.gv { color:#f84; }\n.hx { color:#058; font-weight:bold; }\n.i  { color:#66f; font-weight:bold; }\n.ic { color:#B44; font-weight:bold; }\n.il { }\n.in { color:#B2B; font-weight:bold; }\n.iv { color:#aaf; }\n.la { color:#970; font-weight:bold; }\n.lv { color:#963; }\n.oc { color:#40E; font-weight:bold; }\n.of { color:#000; font-weight:bold; }\n.op { }\n.pc { color:#08f; font-weight:bold; }\n.pd { color:#369; font-weight:bold; }\n.pp { color:#579; }\n.pt { color:#66f; font-weight:bold; }\n.r  { color:#5de; font-weight:bold; }\n\n.rx { background-color:#221133; }\n.rx .k { color:#f8f; }\n.rx .dl { color:#f0f; }\n.rx .mod { color:#f0b; }\n.rx .fu  { color:#404; font-weight: bold; }\n\n.s  { background-color:#331122; }\n.s  .s { background-color:#ffe0e0; }\n.s  .s  .s { background-color:#ffd0d0; }\n.s  .k { color:#F88; }\n.s  .dl { color:#f55; }\n\n.sh { background-color:#f0fff0; }\n.sh .k { color:#2B2; }\n.sh .dl { color:#161; }\n\n.sy { color:#Fc8; }\n.sy .k { color:#Fc8; }\n.sy .dl { color:#F84; }\n\n.ta { color:#070; }\n.tf { color:#070; font-weight:bold; }\n.ts { color:#D70; font-weight:bold; }\n.ty { color:#339; font-weight:bold; }\n.v  { color:#036; }\n.xt { color:#444; }\n    TOKENS\n\n  end\n\nend\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/token_classes.rb",
    "content": "module CodeRay\n  class Tokens\n    ClassOfKind = Hash.new do |h, k|\n      h[k] = k.to_s\n    end\n    ClassOfKind.update with = {\n      :attribute_name => 'an',\n      :attribute_name_fat => 'af',\n      :attribute_value => 'av',\n      :attribute_value_fat => 'aw',\n      :bin => 'bi',\n      :char => 'ch',\n      :class => 'cl',\n      :class_variable => 'cv',\n      :color => 'cr',\n      :comment => 'c',\n      :constant => 'co',\n      :content => 'k',\n      :definition => 'df',\n      :delimiter => 'dl',\n      :directive => 'di',\n      :doc => 'do',\n      :doc_string => 'ds',\n      :entity => 'en',\n      :error => 'er',\n      :escape => 'e',\n      :exception => 'ex',\n      :float => 'fl',\n      :function => 'fu',\n      :global_variable => 'gv',\n      :hex => 'hx',\n      :include => 'ic',\n      :inline => 'il',\n      :inline_delimiter => 'idl',\n      :instance_variable => 'iv',\n      :integer => 'i',\n      :interpreted => 'in',\n      :label => 'la',\n      :local_variable => 'lv',\n      :modifier => 'mod',\n      :oct => 'oc',\n      :operator_fat => 'of',\n      :pre_constant => 'pc',\n      :pre_type => 'pt',\n      :predefined => 'pd',\n      :preprocessor => 'pp',\n      :regexp => 'rx',\n      :reserved => 'r',\n      :shell => 'sh',\n      :string => 's',\n      :symbol => 'sy',\n      :tag => 'ta',\n      :tag_fat => 'tf',\n      :tag_special => 'ts',\n      :type => 'ty',\n      :variable => 'v',\n      :xml_text => 'xt',\n\n      :ident => :NO_HIGHLIGHT, # 'id'\n      #:operator => 'op',\n      :operator => :NO_HIGHLIGHT,  # 'op'\n      :space => :NO_HIGHLIGHT,  # 'sp'\n      :plain => :NO_HIGHLIGHT,\n    }\n    ClassOfKind[:procedure] = ClassOfKind[:method] = ClassOfKind[:function]\n    ClassOfKind[:open] = ClassOfKind[:close] = ClassOfKind[:delimiter]\n    ClassOfKind[:nesting_delimiter] = ClassOfKind[:delimiter]\n    ClassOfKind[:escape] = ClassOfKind[:delimiter]\n    #ClassOfKind.default = ClassOfKind[:error] or raise 'no class found for :error!'\n  end\nend"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay/tokens.rb",
    "content": "module CodeRay\n\n  # = Tokens\n  #\n  # The Tokens class represents a list of tokens returnd from\n  # a Scanner.\n  #\n  # A token is not a special object, just a two-element Array\n  # consisting of\n  # * the _token_ _kind_ (a Symbol representing the type of the token)\n  # * the _token_ _text_ (the original source of the token in a String)\n  #\n  # A token looks like this:\n  #\n  #   [:comment, '# It looks like this']\n  #   [:float, '3.1415926']\n  #   [:error, '']\n  #\n  # Some scanners also yield some kind of sub-tokens, represented by special\n  # token texts, namely :open and :close .\n  #\n  # The Ruby scanner, for example, splits \"a string\" into:\n  #\n  #  [\n  #   [:open, :string],\n  #   [:delimiter, '\"'],\n  #   [:content, 'a string'],\n  #   [:delimiter, '\"'],\n  #   [:close, :string]\n  #  ]\n  #\n  # Tokens is also the interface between Scanners and Encoders:\n  # The input is split and saved into a Tokens object. The Encoder\n  # then builds the output from this object.\n  #\n  # Thus, the syntax below becomes clear:\n  #\n  #   CodeRay.scan('price = 2.59', :ruby).html\n  #   # the Tokens object is here -------^\n  #\n  # See how small it is? ;)\n  #\n  # Tokens gives you the power to handle pre-scanned code very easily:\n  # You can convert it to a webpage, a YAML file, or dump it into a gzip'ed string\n  # that you put in your DB.\n  #\n  # Tokens' subclass TokenStream allows streaming to save memory.\n  class Tokens < Array\n\n    class << self\n\n      # Convert the token to a string.\n      #\n      # This format is used by Encoders.Tokens.\n      # It can be reverted using read_token.\n      def write_token text, type\n        if text.is_a? String\n          \"#{type}\\t#{escape(text)}\\n\"\n        else\n          \":#{text}\\t#{type}\\t\\n\"\n        end\n      end\n\n      # Read a token from the string.\n      #\n      # Inversion of write_token.\n      #\n      # TODO Test this!\n      def read_token token\n        type, text = token.split(\"\\t\", 2)\n        if type[0] == ?:\n          [text.to_sym, type[1..-1].to_sym]\n        else\n          [type.to_sym, unescape(text)]\n        end\n      end\n\n      # Escapes a string for use in write_token.\n      def escape text\n        text.gsub(/[\\n\\\\]/, '\\\\\\\\\\&')\n      end\n\n      # Unescapes a string created by escape.\n      def unescape text\n        text.gsub(/\\\\[\\n\\\\]/) { |m| m[1,1] }\n      end\n\n    end\n\n    # Whether the object is a TokenStream.\n    #\n    # Returns false.\n    def stream?\n      false\n    end\n\n    # Iterates over all tokens.\n    #\n    # If a filter is given, only tokens of that kind are yielded.\n    def each kind_filter = nil, &block\n      unless kind_filter\n        super(&block)\n      else\n        super() do |text, kind|\n          next unless kind == kind_filter\n          yield text, kind\n        end\n      end\n    end\n\n    # Iterates over all text tokens.\n    # Range tokens like [:open, :string] are left out.\n    #\n    # Example:\n    #   tokens.each_text_token { |text, kind| text.replace html_escape(text) }\n    def each_text_token\n      each do |text, kind|\n        next unless text.is_a? ::String\n        yield text, kind\n      end\n    end\n\n    # Encode the tokens using encoder.\n    #\n    # encoder can be\n    # * a symbol like :html oder :statistic\n    # * an Encoder class\n    # * an Encoder object\n    #\n    # options are passed to the encoder.\n    def encode encoder, options = {}\n      unless encoder.is_a? Encoders::Encoder\n        unless encoder.is_a? Class\n          encoder_class = Encoders[encoder]\n        end\n        encoder = encoder_class.new options\n      end\n      encoder.encode_tokens self, options\n    end\n\n\n    # Turn into a string using Encoders::Text.\n    #\n    # +options+ are passed to the encoder if given.\n    def to_s options = {}\n      encode :text, options\n    end\n\n\n    # Redirects unknown methods to encoder calls.\n    #\n    # For example, if you call +tokens.html+, the HTML encoder\n    # is used to highlight the tokens.\n    def method_missing meth, options = {}\n      Encoders[meth].new(options).encode_tokens self\n    end\n\n    # Returns the tokens compressed by joining consecutive\n    # tokens of the same kind.\n    #\n    # This can not be undone, but should yield the same output\n    # in most Encoders.  It basically makes the output smaller.\n    #\n    # Combined with dump, it saves space for the cost of time.\n    #\n    # If the scanner is written carefully, this is not required -\n    # for example, consecutive //-comment lines could already be\n    # joined in one comment token by the Scanner.\n    def optimize\n      print ' Tokens#optimize: before: %d - ' % size if $DEBUG\n      last_kind = last_text = nil\n      new = self.class.new\n      for text, kind in self\n        if text.is_a? String\n          if kind == last_kind\n            last_text << text\n          else\n            new << [last_text, last_kind] if last_kind\n            last_text = text\n            last_kind = kind\n          end\n        else\n          new << [last_text, last_kind] if last_kind\n          last_kind = last_text = nil\n          new << [text, kind]\n        end\n      end\n      new << [last_text, last_kind] if last_kind\n      print 'after: %d (%d saved = %2.0f%%)' %\n        [new.size, size - new.size, 1.0 - (new.size.to_f / size)] if $DEBUG\n      new\n    end\n\n    # Compact the object itself; see optimize.\n    def optimize!\n      replace optimize\n    end\n    \n    # Ensure that all :open tokens have a correspondent :close one.\n    #\n    # TODO: Test this!\n    def fix\n      # Check token nesting using a stack of kinds.\n      opened = []\n      for token, kind in self\n        if token == :open\n          opened.push kind\n        elsif token == :close\n          expected = opened.pop\n          if kind != expected\n            # Unexpected :close; decide what to do based on the kind:\n            # - token was opened earlier: also close tokens in between\n            # - token was never opened: delete the :close (skip with next)\n            next unless opened.rindex expected\n            tokens << [:close, kind] until (kind = opened.pop) == expected\n          end\n        end\n        tokens << [token, kind]\n      end\n      # Close remaining opened tokens\n      tokens << [:close, kind] while kind = opened.pop\n      tokens\n    end\n    \n    def fix!\n      replace fix\n    end\n    \n    # Makes sure that:\n    # - newlines are single tokens\n    #   (which means all other token are single-line)\n    # - there are no open tokens at the end the line\n    #\n    # This makes it simple for encoders that work line-oriented,\n    # like HTML with list-style numeration.\n    def split_into_lines\n      raise NotImplementedError\n    end\n\n    def split_into_lines!\n      replace split_into_lines\n    end\n\n    # Dumps the object into a String that can be saved\n    # in files or databases.\n    #\n    # The dump is created with Marshal.dump;\n    # In addition, it is gzipped using GZip.gzip.\n    #\n    # The returned String object includes Undumping\n    # so it has an #undump method. See Tokens.load.\n    #\n    # You can configure the level of compression,\n    # but the default value 7 should be what you want\n    # in most cases as it is a good compromise between\n    # speed and compression rate.\n    #\n    # See GZip module.\n    def dump gzip_level = 7\n      require 'coderay/helpers/gzip_simple'\n      dump = Marshal.dump self\n      dump = dump.gzip gzip_level\n      dump.extend Undumping\n    end\n\n    # The total size of the tokens.\n    # Should be equal to the input size before\n    # scanning.\n    def text_size\n      size = 0\n      each_text_token do |t, k|\n        size + t.size\n      end\n      size\n    end\n\n    # The total size of the tokens.\n    # Should be equal to the input size before\n    # scanning.\n    def text\n      map { |t, k| t if t.is_a? ::String }.join\n    end\n\n    # Include this module to give an object an #undump\n    # method.\n    #\n    # The string returned by Tokens.dump includes Undumping.\n    module Undumping\n      # Calls Tokens.load with itself.\n      def undump\n        Tokens.load self\n      end\n    end\n\n    # Undump the object using Marshal.load, then\n    # unzip it using GZip.gunzip.\n    #\n    # The result is commonly a Tokens object, but\n    # this is not guaranteed.\n    def Tokens.load dump\n      require 'coderay/helpers/gzip_simple'\n      dump = dump.gunzip\n      @dump = Marshal.load dump\n    end\n\n  end\n\n\n  # = TokenStream\n  #\n  # The TokenStream class is a fake Array without elements.\n  #\n  # It redirects the method << to a block given at creation.\n  #\n  # This allows scanners and Encoders to use streaming (no\n  # tokens are saved, the input is highlighted the same time it\n  # is scanned) with the same code.\n  #\n  # See CodeRay.encode_stream and CodeRay.scan_stream\n  class TokenStream < Tokens\n\n    # Whether the object is a TokenStream.\n    #\n    # Returns true.\n    def stream?\n      true\n    end\n\n    # The Array is empty, but size counts the tokens given by <<.\n    attr_reader :size\n\n    # Creates a new TokenStream that calls +block+ whenever\n    # its << method is called.\n    #\n    # Example:\n    #\n    #   require 'coderay'\n    #   \n    #   token_stream = CodeRay::TokenStream.new do |kind, text|\n    #     puts 'kind: %s, text size: %d.' % [kind, text.size]\n    #   end\n    #   \n    #   token_stream << [:regexp, '/\\d+/']\n    #   #-> kind: rexpexp, text size: 5.\n    #\n    def initialize &block\n      raise ArgumentError, 'Block expected for streaming.' unless block\n      @callback = block\n      @size = 0\n    end\n\n    # Calls +block+ with +token+ and increments size.\n    #\n    # Returns self.\n    def << token\n      @callback.call token\n      @size += 1\n      self\n    end\n\n    # This method is not implemented due to speed reasons. Use Tokens.\n    def text_size\n      raise NotImplementedError,\n        'This method is not implemented due to speed reasons.'\n    end\n\n    # A TokenStream cannot be dumped. Use Tokens.\n    def dump\n      raise NotImplementedError, 'A TokenStream cannot be dumped.'\n    end\n\n    # A TokenStream cannot be optimized. Use Tokens.\n    def optimize\n      raise NotImplementedError, 'A TokenStream cannot be optimized.'\n    end\n\n  end\n\n  \n  # Token name abbreviations\n  require 'coderay/token_classes'\n\nend\n"
  },
  {
    "path": "vendor/plugins/coderay-0.7.6.227/lib/coderay.rb",
    "content": "# = CodeRay Library\n#\n# $Id: coderay.rb 227 2007-04-24 12:26:18Z murphy $\n#\n# CodeRay is a Ruby library for syntax highlighting.\n#\n# I try to make CodeRay easy to use and intuitive, but at the same time fully featured, complete,\n# fast and efficient.\n# \n# See README.\n# \n# It consists mainly of\n# * the main engine: CodeRay (Scanners::Scanner, Tokens/TokenStream, Encoders::Encoder), PluginHost\n# * the scanners in CodeRay::Scanners\n# * the encoders in CodeRay::Encoders\n# \n# Here's a fancy graphic to light up this gray docu:\n# \n# http://rd.cYcnus.de/coderay/scheme.png\n# \n# == Documentation\n#\n# See CodeRay, Encoders, Scanners, Tokens.\n#\n# == Usage\n#\n# Remember you need RubyGems to use CodeRay, unless you have it in your load path. Run Ruby with\n# -rubygems option if required.\n#\n# === Highlight Ruby code in a string as html\n# \n#   require 'coderay'\n#   print CodeRay.scan('puts \"Hello, world!\"', :ruby).html\n#\n#   # prints something like this:\n#   puts <span class=\"s\">&quot;Hello, world!&quot;</span>\n# \n# \n# === Highlight C code from a file in a html div\n# \n#   require 'coderay'\n#   print CodeRay.scan(File.read('ruby.h'), :c).div\n#   print CodeRay.scan_file('ruby.h').html.div\n# \n# You can include this div in your page. The used CSS styles can be printed with\n# \n#   % coderay_stylesheet\n# \n# === Highlight without typing too much\n# \n# If you are one of the hasty (or lazy, or extremely curious) people, just run this file:\n# \n#   % ruby -rubygems /path/to/coderay/coderay.rb > example.html\n# \n# and look at the file it created in your browser.\n# \n# = CodeRay Module\n#\n# The CodeRay module provides convenience methods for the engine.\n#\n# * The +lang+ and +format+ arguments select Scanner and Encoder to use. These are\n#   simply lower-case symbols, like <tt>:python</tt> or <tt>:html</tt>.\n# * All methods take an optional hash as last parameter, +options+, that is send to\n#   the Encoder / Scanner.\n# * Input and language are always sorted in this order: +code+, +lang+.\n#   (This is in alphabetical order, if you need a mnemonic ;)\n# \n# You should be able to highlight everything you want just using these methods;\n# so there is no need to dive into CodeRay's deep class hierarchy.\n#\n# The examples in the demo directory demonstrate common cases using this interface.\n#  \n# = Basic Access Ways\n#\n# Read this to get a general view what CodeRay provides.\n# \n# == Scanning\n#  \n#  Scanning means analysing an input string, splitting it up into Tokens.\n#  Each Token knows about what type it is: string, comment, class name, etc.\n#\n#  Each +lang+ (language) has its own Scanner; for example, <tt>:ruby</tt> code is\n#  handled by CodeRay::Scanners::Ruby.\n# \n# CodeRay.scan:: Scan a string in a given language into Tokens.\n#                This is the most common method to use.\n# CodeRay.scan_file:: Scan a file and guess the language using FileType.\n# \n# The Tokens object you get from these methods can encode itself; see Tokens.\n# \n# == Encoding\n#\n# Encoding means compiling Tokens into an output. This can be colored HTML or\n# LaTeX, a textual statistic or just the number of non-whitespace tokens.\n# \n# Each Encoder provides output in a specific +format+, so you select Encoders via\n# formats like <tt>:html</tt> or <tt>:statistic</tt>.\n# \n# CodeRay.encode:: Scan and encode a string in a given language.\n# CodeRay.encode_tokens:: Encode the given tokens.\n# CodeRay.encode_file:: Scan a file, guess the language using FileType and encode it.\n#\n# == Streaming\n#\n# Streaming saves RAM by running Scanner and Encoder in some sort of\n# pipe mode; see TokenStream.\n#\n# CodeRay.scan_stream:: Scan in stream mode.\n#\n#  == All-in-One Encoding\n#\n# CodeRay.encode:: Highlight a string with a given input and output format.\n#\n# == Instanciating\n#\n# You can use an Encoder instance to highlight multiple inputs. This way, the setup\n# for this Encoder must only be done once.\n#\n# CodeRay.encoder:: Create an Encoder instance with format and options.\n# CodeRay.scanner:: Create an Scanner instance for lang, with '' as default code.\n#\n# To make use of CodeRay.scanner, use CodeRay::Scanner::code=.\n#\n# The scanning methods provide more flexibility; we recommend to use these.\n# \n# == Reusing Scanners and Encoders\n# \n# If you want to re-use scanners and encoders (because that is faster), see\n# CodeRay::Duo for the most convenient (and recommended) interface.\nmodule CodeRay\n\n  # Version: Major.Minor.Teeny[.Revision]\n  # Major: 0 for pre-release\n  # Minor: odd for beta, even for stable\n  # Teeny: development state\n  # Revision: Subversion Revision number (generated on rake)\n  VERSION = '0.7.6'\n\n  require 'coderay/tokens'\n  require 'coderay/scanner'\n  require 'coderay/encoder'\n  require 'coderay/duo'\n  require 'coderay/style'\n\n\n  class << self\n\n    # Scans the given +code+ (a String) with the Scanner for +lang+.\n    #\n    # This is a simple way to use CodeRay. Example:\n    #  require 'coderay'\n    #  page = CodeRay.scan(\"puts 'Hello, world!'\", :ruby).html\n    #\n    # See also demo/demo_simple.\n    def scan code, lang, options = {}, &block\n      scanner = Scanners[lang].new code, options, &block\n      scanner.tokenize\n    end\n\n    # Scans +filename+ (a path to a code file) with the Scanner for +lang+.\n    #\n    # If +lang+ is :auto or omitted, the CodeRay::FileType module is used to\n    # determine it. If it cannot find out what type it is, it uses\n    # CodeRay::Scanners::Plaintext.\n    #\n    # Calls CodeRay.scan.\n    #\n    # Example:\n    #  require 'coderay'\n    #  page = CodeRay.scan_file('some_c_code.c').html\n    def scan_file filename, lang = :auto, options = {}, &block\n      file = IO.read filename\n      if lang == :auto\n        require 'coderay/helpers/file_type'\n        lang = FileType.fetch filename, :plaintext, true\n      end\n      scan file, lang, options = {}, &block\n    end\n\n    # Scan the +code+ (a string) with the scanner for +lang+.\n    #\n    # Calls scan.\n    #\n    # See CodeRay.scan.\n    def scan_stream code, lang, options = {}, &block\n      options[:stream] = true\n      scan code, lang, options, &block\n    end\n\n    # Encode a string in Streaming mode.\n    #\n    # This starts scanning +code+ with the the Scanner for +lang+\n    # while encodes the output with the Encoder for +format+.\n    # +options+ will be passed to the Encoder.\n    #\n    # See CodeRay::Encoder.encode_stream\n    def encode_stream code, lang, format, options = {}\n      encoder(format, options).encode_stream code, lang, options\n    end\n\n    # Encode a string.\n    #\n    # This scans +code+ with the the Scanner for +lang+ and then\n    # encodes it with the Encoder for +format+.\n    # +options+ will be passed to the Encoder.\n    #\n    # See CodeRay::Encoder.encode\n    def encode code, lang, format, options = {}\n      encoder(format, options).encode code, lang, options\n    end\n\n    # Highlight a string into a HTML <div>.\n    #\n    # CSS styles use classes, so you have to include a stylesheet\n    # in your output.\n    #\n    # See encode.\n    def highlight code, lang, options = { :css => :class }, format = :div\n      encode code, lang, format, options\n    end\n\n    # Encode pre-scanned Tokens.\n    # Use this together with CodeRay.scan:\n    #\n    #  require 'coderay'\n    #  \n    #  # Highlight a short Ruby code example in a HTML span\n    #  tokens = CodeRay.scan '1 + 2', :ruby\n    #  puts CodeRay.encode_tokens(tokens, :span)\n    #\n    def encode_tokens tokens, format, options = {}\n      encoder(format, options).encode_tokens tokens, options\n    end\n\n    # Encodes +filename+ (a path to a code file) with the Scanner for +lang+.\n    #\n    # See CodeRay.scan_file.\n    # Notice that the second argument is the output +format+, not the input language.\n    #\n    # Example:\n    #  require 'coderay'\n    #  page = CodeRay.encode_file 'some_c_code.c', :html\n    def encode_file filename, format, options = {}\n      tokens = scan_file filename, :auto, get_scanner_options(options)\n      encode_tokens tokens, format, options\n    end\n\n    # Highlight a file into a HTML <div>.\n    #\n    # CSS styles use classes, so you have to include a stylesheet\n    # in your output.\n    #\n    # See encode.\n    def highlight_file filename, options = { :css => :class }, format = :div\n      encode_file filename, format, options\n    end\n\n    # Finds the Encoder class for +format+ and creates an instance, passing\n    # +options+ to it.\n    #\n    # Example:\n    #  require 'coderay'\n    #  \n    #  stats = CodeRay.encoder(:statistic)\n    #  stats.encode(\"puts 17 + 4\\n\", :ruby)\n    #  \n    #  puts '%d out of %d tokens have the kind :integer.' % [\n    #    stats.type_stats[:integer].count,\n    #    stats.real_token_count\n    #  ]\n    #  #-> 2 out of 4 tokens have the kind :integer.\n    def encoder format, options = {}\n      Encoders[format].new options\n    end\n\n    # Finds the Scanner class for +lang+ and creates an instance, passing\n    # +options+ to it.\n    #\n    # See Scanner.new.\n    def scanner lang, options = {}\n      Scanners[lang].new '', options\n    end\n\n    # Extract the options for the scanner from the +options+ hash.\n    #\n    # Returns an empty Hash if <tt>:scanner_options</tt> is not set.\n    #\n    # This is used if a method like CodeRay.encode has to provide options\n    # for Encoder _and_ scanner.\n    def get_scanner_options options\n      options.fetch :scanner_options, {}\n    end\n\n  end\n\n  # This Exception is raised when you try to stream with something that is not\n  # capable of streaming.\n  class NotStreamableError < Exception\n    def initialize obj\n      @obj = obj\n    end\n\n    def to_s\n      '%s is not Streamable!' % @obj.class\n    end\n  end\n\n  # A dummy module that is included by subclasses of CodeRay::Scanner an CodeRay::Encoder\n  # to show that they are able to handle streams.\n  module Streamable\n  end\n\nend\n\n# Run a test script.\nif $0 == __FILE__\n  $stderr.print 'Press key to print demo.'; gets\n  code = File.read(__FILE__)[/module CodeRay.*/m]\n  print CodeRay.scan(code, :ruby).html\nend\n"
  },
  {
    "path": "vendor/plugins/default_value_for/LICENSE.TXT",
    "content": "Copyright (c) 2008 Phusion\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "vendor/plugins/default_value_for/README.rdoc",
    "content": "= Introduction\n\nThe default_value_for plugin allows one to define default values for ActiveRecord\nmodels in a declarative manner. For example:\n\n  class User < ActiveRecord::Base\n    default_value_for :name, \"(no name)\"\n    default_value_for :last_seen do\n      Time.now\n    end\n  end\n  \n  u = User.new\n  u.name       # => \"(no name)\"\n  u.last_seen  # => Mon Sep 22 17:28:38 +0200 2008\n\n*Note*: critics might be interested in the \"When (not) to use default_value_for?\"\nsection. Please read on.\n\n\n== Installation\n\nInstall with:\n\n  ./script/plugin install git://github.com/FooBarWidget/default_value_for.git\n\n\n== The default_value_for method\n\nThe +default_value_for+ method is available in all ActiveRecord model classes.\n\nThe first argument is the name of the attribute for which a default value should\nbe set. This may either be a Symbol or a String.\n\nThe default value itself may either be passed as the second argument:\n\n  default_value_for :age, 20\n\n...or it may be passed as the return value of a block:\n\n  default_value_for :age do\n    if today_is_sunday?\n      20\n    else\n      30\n    end\n  end\n\nIf you pass a value argument, then the default value is static and never\nchanges. However, if you pass a block, then the default value is retrieved by\ncalling the block. This block is called not once, but every time a new record is\ninstantiated and default values need to be filled in.\n\nThe latter form is especially useful if your model has a UUID column. One can\ngenerate a new, random UUID for every newly instantiated record:\n\n  class User < ActiveRecord::Base\n    default_value_for :uuid do\n      UuidGenerator.new.generate_uuid\n    end\n  end\n  \n  User.new.uuid  # => \"51d6d6846f1d1b5c9a....\"\n  User.new.uuid  # => \"ede292289e3484cb88....\"\n\nNote that record is passed to the block as an argument, in case you need it for\nwhatever reason:\n\n  class User < ActiveRecord::Base\n    default_value_for :uuid do |x|\n      x   # <--- a User object\n      UuidGenerator.new.generate_uuid\n    end\n  end\n\n== The default_values method\n\nAs a shortcut, you can use +default_values+ to set multiple default values at once.\n\n  default_values :age  => 20\n                 :uuid => lambda { UuidGenerator.new.generate_uuid }\n\nThe difference is purely aesthetic.  If you have lots of default values which are constants or constructed with one-line blocks, +default_values+ may look nicer.  If you have default values constructed by longer blocks, +default_value_for+ suit you better.  Feel free to mix and match.\n\nAs a side note, due to specifics of Ruby's parser, you cannot say,\n\n  default_value :uuid { UuidGenerator.new.generate_uuid }\n\nbecause it will not parse.  This is in part the inspiration for the +default_values+ syntax.\n\n== Rules\n\n=== Instantiation of new record\n\nUpon instantiating a new record, the declared default values are filled into\nthe record. You've already seen this in the above examples.\n\n=== Retrieval of existing record\n\nUpon retrieving an existing record, the declared default values are _not_\nfilled into the record. Consider the example with the UUID:\n\n  user = User.create\n  user.uuid   # => \"529c91b8bbd3e...\"\n  \n  user = User.find(user.id)\n  # UUID remains unchanged because it's retrieved from the database!\n  user.uuid   # => \"529c91b8bbd3e...\"\n\n=== Mass-assignment\n\nIf a certain attribute is being assigned via the model constructor's\nmass-assignment argument, that the default value for that attribute will _not_\nbe filled in:\n\n  user = User.new(:uuid => \"hello\")\n  user.uuid   # => \"hello\"\n\nHowever, if that attribute is protected by +attr_protected+ or +attr_accessible+,\nthen it will be filled in:\n\n  class User < ActiveRecord::Base\n    default_value_for :name, 'Joe'\n    attr_protected :name\n  end\n  \n  user = User.new(:name => \"Jane\")\n  user.name   # => \"Joe\"\n\n=== Inheritance\n\nInheritance works as expected. All default values are inherited by the child\nclass:\n\n  class User < ActiveRecord::Base\n    default_value_for :name, 'Joe'\n  end\n  \n  class SuperUser < User\n  end\n  \n  SuperUser.new.name   # => \"Joe\"\n\n=== Attributes that aren't database columns\n\n+default_value_for+ also works with attributes that aren't database columns.\nIt works with anything for which there's an assignment method:\n\n  # Suppose that your 'users' table only has a 'name' column.\n  class User < ActiveRecord::Base\n    default_value_for :name, 'Joe'\n    default_value_for :age, 20\n    default_value_for :registering, true\n    \n    attr_accessor :age\n    \n    def registering=(value)\n      @registering = true\n    end\n  end\n  \n  user = User.new\n  user.age    # => 20\n  user.instance_variable_get('@registering')    # => true\n\n=== Default values are *not* duplicated\n\nThe given default values are *not* duplicated when they are filled in, so if\nyou mutate a value that was filled in with a default value, then it will affect\nall subsequent default values:\n\n  class Author < ActiveRecord::Base\n    # This model only has a 'name' attribute.\n  end\n  \n  class Book < ActiveRecord::Base\n    belongs_to :author\n    \n    # By default, a Book belongs to a new, unsaved author.\n    default_value_for :author, Author.new\n  end\n  \n  book1 = Book.new\n  book1.author.name  # => nil\n  # This mutates the default value:\n  book1.author.name = \"John\"\n  \n  book2 = Book.new\n  book2.author.name  # => \"John\"\n\nYou can prevent this from happening by passing a block to +default_value_for+,\nwhich returns a new object instance every time:\n\n  class Book < ActiveRecord::Base\n    belongs_to :author\n    \n    default_value_for :author do\n      Author.new\n    end\n  end\n  \n  book1 = Book.new\n  book1.author.name  # => nil\n  book1.author.name = \"John\"\n  \n  book2 = Book.new\n  book2.author.name  # => nil\n\nThe main reason why default values are not duplicated is because not all\nobjects can be duplicated. For example, +Fixnum+ responds to +dup+, but calling\n+dup+ on a Fixnum will raise an exception.\n\n=== Caveats\n\nA conflict can occur if your model class overrides the 'initialize' method,\nbecause this plugin overrides 'initialize' as well to do its job.\n\n  class User < ActiveRecord::Base\n    def initialize  # <-- this constructor causes problems\n      super(:name => 'Name cannot be changed in constructor')\n    end\n  end\n\nWe recommend you to alias chain your initialize method in models where you use\n+default_value_for+:\n\n  class User < ActiveRecord::Base\n    default_value_for :age, 20\n    \n    def initialize_with_my_app\n      initialize_without_my_app(:name => 'Name cannot be changed in constructor')\n    end\n    \n    alias_method_chain :initialize, :my_app\n  end\n\nAlso, stick with the following rules:\n- There is no need to +alias_method_chain+ your initialize method in models that\n  don't use +default_value_for+.\n- Make sure that +alias_method_chain+ is called *after* the last\n  +default_value_for+ occurance.\n\n\n== When (not) to use default_value_for?\n\nYou can also specify default values in the database schema. For example, you\ncan specify a default value in a migration as follows:\n\n  create_table :users do |t|\n    t.string    :username,  :null => false, :default => 'default username'\n    t.integer   :age,       :null => false, :default => 20\n    t.timestamp :last_seen, :null => false, :default => Time.now\n  end\n\nThis has the same effect as passing the default value as the second argument to\n+default_value_for+:\n\n  user = User.new\n  user.username   # => 'default username'\n  user.age        # => 20\n  user.timestamp  # => Mon Sep 22 18:31:47 +0200 2008\n\nIt's recommended that you use this over +default_value_for+ whenever possible.\n\nHowever, it's not possible to specify a schema default for serialized columns.\nWith +default_value_for+, you can:\n\n  class User < ActiveRecord::Base\n    serialize :color\n    default_value_for :color, [255, 0, 0]\n  end\n\nAnd if schema defaults don't provide the flexibility that you need, then\n+default_value_for+ is the perfect choice. For example, with +default_value_for+\nyou could specify a per-environment default:\n\n  class User < ActiveRecord::Base\n    if RAILS_ENV == \"development\"\n      default_value_for :is_admin, true\n    end\n  end\n\nOr, as you've seen in an earlier example, you can use +default_value_for+ to\ngenerate a default random UUID:\n\n  class User < ActiveRecord::Base\n    default_value_for :uuid do\n      UuidGenerator.new.generate_uuid\n    end\n  end\n\nOr you could use it to generate a timestamp that's relative to the time at which\nthe record is instantiated:\n\n  class User < ActiveRecord::Base\n    default_value_for :account_expires_at do\n      3.years.from_now\n    end\n  end\n  \n  User.new.account_expires_at   # => Mon Sep 22 18:43:42 +0200 2008\n  sleep(2)\n  User.new.account_expires_at   # => Mon Sep 22 18:43:44 +0200 2008\n\nFinally, it's also possible to specify a default via an association:\n\n  # Has columns: 'name' and 'default_price'\n  class SuperMarket < ActiveRecord::Base\n    has_many :products\n  end\n  \n  # Has columns: 'name' and 'price'\n  class Product < ActiveRecord::Base\n    belongs_to :super_market\n    \n    default_value_for :price do |product|\n      product.super_market.default_price\n    end\n  end\n  \n  super_market = SuperMarket.create(:name => 'Albert Zwijn', :default_price => 100)\n  soap = super_market.products.create(:name => 'Soap')\n  soap.price   # => 100\n\n=== What about before_validate/before_save?\n\nTrue, +before_validate+ and +before_save+ does what we want if we're only\ninterested in filling in a default before saving. However, if one wants to be\nable to access the default value even before saving, then be prepared to write\na lot of code. Suppose that we want to be able to access a new record's UUID,\neven before it's saved. We could end up with the following code:\n\n  # In the controller\n  def create\n    @user = User.new(params[:user])\n    @user.generate_uuid\n    email_report_to_admin(\"#{@user.username} with UUID #{@user.uuid} created.\")\n    @user.save!\n  end\n  \n  # Model\n  class User < ActiveRecord::Base\n    before_save :generate_uuid_if_necessary\n    \n    def generate_uuid\n      self.uuid = ...\n    end\n    \n    private\n      def generate_uuid_if_necessary\n        if uuid.blank?\n          generate_uuid\n        end\n      end\n  end\n\nThe need to manually call +generate_uuid+ here is ugly, and one can easily forget\nto do that. Can we do better? Let's see:\n\n  # Controller\n  def create\n    @user = User.new(params[:user])\n    email_report_to_admin(\"#{@user.username} with UUID #{@user.uuid} created.\")\n    @user.save!\n  end\n  \n  # Model\n  class User < ActiveRecord::Base\n    before_save :generate_uuid_if_necessary\n    \n    def uuid\n      value = read_attribute('uuid')\n      if !value\n        value = generate_uuid\n        write_attribute('uuid', value)\n      end\n      value\n    end\n    \n    # We need to override this too, otherwise User.new.attributes won't return\n    # a default UUID value. I've never tested with User.create() so maybe we\n    # need to override even more things.\n    def attributes\n      uuid\n      super\n    end\n    \n    private\n      def generate_uuid_if_necessary\n        uuid  # Reader method automatically generates UUID if it doesn't exist\n      end\n  end\n\nThat's an awful lot of code. Using +default_value_for+ is easier, don't you think?\n\n=== What about other plugins?\n\nI've only been able to find 2 similar plugins:\n\n- Default Value: http://agilewebdevelopment.com/plugins/default_value\n- ActiveRecord Defaults: http://agilewebdevelopment.com/plugins/activerecord_defaults\n\n'Default Value' appears to be unmaintained; its SVN link is broken. This leaves\nonly 'ActiveRecord Defaults'. However, it is semantically dubious, which leaves\nit wide open for corner cases. For example, it is not clearly specified what\nActiveRecord Defaults will do when attributes are protected by +attr_protected+\nor +attr_accessible+. It is also not clearly specified what one is supposed to\ndo if one needs a custom +initialize+ method in the model.\n\nI've taken my time to thoroughly document default_value_for's behavior.\n\n\n== Credits\n\nI've wanted such functionality for a while now and it baffled me that ActiveRecord\ndoesn't provide a clean way for me to specify default values. After reading\nhttp://groups.google.com/group/rubyonrails-core/browse_thread/thread/b509a2fe2b62ac5/3e8243fa1954a935,\nit became clear that someone needs to write a plugin. This is the result.\n\nThanks to Pratik Naik for providing the initial code snippet on which this plugin\nis based on: http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model\n"
  },
  {
    "path": "vendor/plugins/default_value_for/Rakefile",
    "content": "task :default => :test\n\ndesc \"Run unit tests.\"\ntask :test do\n\truby \"test.rb\"\nend\n"
  },
  {
    "path": "vendor/plugins/default_value_for/init.rb",
    "content": "# Copyright (c) 2008 Phusion\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\nmodule DefaultValueForPlugin\n\tclass NormalValueContainer\n\t\tdef initialize(value)\n\t\t\t@value = value\n\t\tend\n\t\n\t\tdef evaluate(instance)\n\t\t\treturn @value\n\t\tend\n\tend\n\t\n\tclass BlockValueContainer\n\t\tdef initialize(block)\n\t\t\t@block = block\n\t\tend\n\t\n\t\tdef evaluate(instance)\n\t\t\treturn @block.call(instance)\n\t\tend\n\tend\n\t\n\tmodule ClassMethods\n\t\tdef default_value_for(attribute, value = nil, &block)\n\t\t\tif !method_defined?(:initialize_with_defaults)\n\t\t\t\tinclude(InstanceMethods)\n\t\t\t\talias_method_chain :initialize, :defaults\n\t\t\t\tclass_inheritable_accessor :_default_attribute_values\n\t\t\t\tself._default_attribute_values = ActiveSupport::OrderedHash.new\n\t\t\tend\n\t\t\tif block_given?\n\t\t\t\tcontainer = BlockValueContainer.new(block)\n\t\t\telse\n\t\t\t\tcontainer = NormalValueContainer.new(value)\n\t\t\tend\n\t\t\t_default_attribute_values[attribute.to_s] = container\n\t\tend\n\t\t\n\t\tdef default_values(values)\n\t\t\tvalues.each_pair do |key, value|\n\t\t\t\tif value.kind_of? Proc\n\t\t\t\t\tdefault_value_for(key, &value)\n\t\t\t\telse\n\t\t\t\t\tdefault_value_for(key, value)\n\t\t\t\tend\n\t\t\tend\n\t\tend\n\tend\n\t\n\tmodule InstanceMethods\n\t\tdef initialize_with_defaults(attrs = nil)\n\t\t\tinitialize_without_defaults(attrs) do\n\t\t\t\tif attrs\n\t\t\t\t\tstringified_attrs = attrs.stringify_keys\n\t\t\t\t\tsafe_attrs = remove_attributes_protected_from_mass_assignment(stringified_attrs)\n\t\t\t\t\tsafe_attribute_names = safe_attrs.keys.map do |x|\n\t\t\t\t\t\tx.to_s\n\t\t\t\t\tend\n\t\t\t\tend\n\t\t\t\tself.class._default_attribute_values.each do |attribute, container|\n\t\t\t\t\tif safe_attribute_names.nil? || safe_attribute_names.none? { |attr_name| attr_name =~ /^#{attribute}($|\\()/ }\n\t\t\t\t\t\t__send__(\"#{attribute}=\", container.evaluate(self))\n\t\t\t\t\t\tchanged_attributes.delete(attribute)\n\t\t\t\t\tend\n\t\t\t\tend\n\t\t\t\tyield(self) if block_given?\n\t\t\tend\n\t\tend\n\tend\nend\n\nActiveRecord::Base.extend(DefaultValueForPlugin::ClassMethods)\n"
  },
  {
    "path": "vendor/plugins/default_value_for/test.rb",
    "content": "# Copyright (c) 2008, 2009 Phusion\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\nrequire 'rubygems'\nrequire 'active_record'\nrequire 'test/unit'\nrequire File.dirname(__FILE__) + '/init'\nDir.chdir(File.dirname(__FILE__))\n\nif RUBY_PLATFORM == \"java\"\n\tdatabase_adapter = \"jdbcsqlite3\"\nelse\n\tdatabase_adapter = \"sqlite3\"\nend\n\nFile.unlink('test.sqlite3') rescue nil\nActiveRecord::Base.logger = Logger.new(STDERR)\nActiveRecord::Base.logger.level = Logger::WARN\nActiveRecord::Base.establish_connection(\n\t:adapter => database_adapter,\n\t:database => 'test.sqlite3'\n)\nActiveRecord::Base.connection.create_table(:users, :force => true) do |t|\n\tt.string :username\n\tt.integer :default_number\nend\nActiveRecord::Base.connection.create_table(:numbers, :force => true) do |t|\n\tt.string :type\n\tt.integer :number\n\tt.integer :count, :null => false, :default => 1\n\tt.integer :user_id\n\tt.timestamp :timestamp\nend\n\nclass User < ActiveRecord::Base\n\thas_many :numbers, :class_name => 'TestClass'\nend\n\nclass Number < ActiveRecord::Base\nend\n\nclass DefaultValuePluginTest < Test::Unit::TestCase\n\tdef setup\n\t\tNumber.create(:number => 9876)\n\tend\n\t\n\tdef teardown\n\t\tNumber.delete_all\n\tend\n\t\n\tdef define_model_class(name = \"TestClass\", parent_class_name = \"ActiveRecord::Base\", &block)\n\t\tObject.send(:remove_const, name) rescue nil\n\t\teval(\"class #{name} < #{parent_class_name}; end\", TOPLEVEL_BINDING)\n\t\tklass = eval(name, TOPLEVEL_BINDING)\n\t\tklass.class_eval do\n\t\t\tset_table_name 'numbers'\n\t\tend\n\t\tklass.class_eval(&block) if block_given?\n\tend\n\t\n\tdef test_default_value_can_be_passed_as_argument\n\t\tdefine_model_class do\n\t\t\tdefault_value_for(:number, 1234)\n\t\tend\n\t\tobject = TestClass.new\n\t\tassert_equal 1234, object.number\n\tend\n\t\n\tdef test_default_value_can_be_passed_as_block\n\t\tdefine_model_class do\n\t\t\tdefault_value_for(:number) { 1234 }\n\t\tend\n\t\tobject = TestClass.new\n\t\tassert_equal 1234, object.number\n\tend\n\t\n\tdef test_works_with_create\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :number, 1234\n\t\tend\n\t\tTestClass.create\n\t\tassert_not_nil TestClass.find_by_number(1234)\n\tend\n\t\n\tdef test_overwrites_db_default\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :count, 1234\n\t\tend\n\t\tobject = TestClass.new\n\t\tassert_equal 1234, object.count\n\tend\n\t\n\tdef test_doesnt_overwrite_values_provided_by_mass_assignment\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :number, 1234\n\t\tend\n\t\tobject = TestClass.new(:number => 1, :count => 2)\n\t\tassert_equal 1, object.number\n\tend\n  \n\tdef test_doesnt_overwrite_values_provided_by_multiparameter_assignment\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :timestamp, Time.mktime(2000, 1, 1)\n\t\tend\n\t\ttimestamp = Time.mktime(2009, 1, 1)\n\t\tobject = TestClass.new('timestamp(1i)' => '2009', 'timestamp(2i)' => '1', 'timestamp(3i)' => '1')\n\t\tassert_equal timestamp, object.timestamp\n\tend\n\t\n\tdef test_doesnt_overwrite_values_provided_by_constructor_block\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :number, 1234\n\t\tend\n\t\tobject = TestClass.new do |x|\n\t\t\tx.number = 1\n\t\t\tx.count = 2\n\t\tend\n\t\tassert_equal 1, object.number\n\tend\n\t\n\tdef test_doesnt_overwrite_explicitly_provided_nil_values_in_mass_assignment\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :number, 1234\n\t\tend\n\t\tobject = TestClass.new(:number => nil)\n\t\tassert_nil object.number\n\tend\n\t\n\tdef test_default_values_are_inherited\n\t\tdefine_model_class(\"TestSuperClass\") do\n\t\t\tdefault_value_for :number, 1234\n\t\tend\n\t\tdefine_model_class(\"TestClass\", \"TestSuperClass\")\n\t\tobject = TestClass.new\n\t\tassert_equal 1234, object.number\n\tend\n\t\n\tdef test_doesnt_set_default_on_saved_records\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :number, 1234\n\t\tend\n\t\tassert_equal 9876, TestClass.find(:first).number\n\tend\n\t\n\tdef test_also_works_on_attributes_that_arent_database_columns\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :hello, \"hi\"\n\t\t\tattr_accessor :hello\n\t\tend\n\t\tobject = TestClass.new\n\t\tassert_equal 'hi', object.hello\n\tend\n\t\n\tdef test_constructor_ignores_forbidden_mass_assignment_attributes\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :number, 1234\n\t\t\tattr_protected :number\n\t\tend\n\t\tobject = TestClass.new(:number => 5678, :count => 987)\n\t\tassert_equal 1234, object.number\n\t\tassert_equal 987, object.count\n\tend\n\t\n\tdef test_doesnt_conflict_with_overrided_initialize_method_in_model_class\n\t\tdefine_model_class do\n\t\t\tdef initialize(attrs = {})\n\t\t\t\t@initialized = true\n\t\t\t\tsuper(:count => 5678)\n\t\t\tend\n\t\t\t\n\t\t\tdefault_value_for :number, 1234\n\t\tend\n\t\tobject = TestClass.new\n\t\tassert_equal 1234, object.number\n\t\tassert_equal 5678, object.count\n\t\tassert object.instance_variable_get('@initialized')\n\tend\n\t\n\tdef test_model_instance_is_passed_to_the_given_block\n\t\t$instance = nil\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :number do |n|\n\t\t\t\t$instance = n\n\t\t\tend\n\t\tend\n\t\tobject = TestClass.new\n\t\tassert_same object, $instance\n\tend\n\t\n\tdef test_can_specify_default_value_via_association\n\t\tuser = User.create(:username => 'Kanako', :default_number => 123)\n\t\tdefine_model_class do\n\t\t\tbelongs_to :user\n\t\t\t\n\t\t\tdefault_value_for :number do |n|\n\t\t\t\tn.user.default_number\n\t\t\tend\n\t\tend\n\t\tobject = user.numbers.create\n\t\tassert_equal 123, object.number\n\tend\n\t\n\tdef test_default_values\n\t\tdefine_model_class do\n\t\t\tdefault_values :type => \"normal\",\n\t\t\t               :number => lambda { 10 + 5 }\n\t\tend\n\t\t\n\t\tobject = TestClass.new\n\t\tassert_equal(\"normal\", object.type)\n\t\tassert_equal(15, object.number)\n\tend\n\t\n\tdef test_default_value_order\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :count, 5\n\t\t\tdefault_value_for :number do |this|\n\t\t\t\tthis.count * 2\n\t\t\tend\n\t\tend\n\t\tobject = TestClass.new\n\t\tassert_equal(5, object.count)\n\t\tassert_equal(10, object.number)\n\tend\n\t\n\tdef test_attributes_with_default_values_are_not_marked_as_changed\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :count, 5\n\t\t\tdefault_value_for :number, 2\n\t\tend\n\t\t\n\t\tobject = TestClass.new\n\t\tassert(!object.changed?)\n\t\tassert_equal([], object.changed)\n\t\t\n\t\tobject.type = \"foo\"\n\t\tassert(object.changed?)\n\t\tassert_equal([\"type\"], object.changed)\n\tend\n\t\n\tdef test_default_values_are_not_duplicated\n\t\tdefine_model_class do\n\t\t\tset_table_name \"users\"\n\t\t\tdefault_value_for :username, \"hello\"\n\t\tend\n\t\tuser1 = TestClass.new\n\t\tuser1.username << \" world\"\n\t\tuser2 = TestClass.new\n\t\tassert_equal(\"hello world\", user2.username)\n\tend\n\t\n\tdef test_constructor_does_not_affect_the_hash_passed_to_it\n\t\tdefine_model_class do\n\t\t\tdefault_value_for :count, 5\n\t\tend\n\t\t\n\t\toptions = { :count => 5, :user_id => 1 }\n\t\toptions_dup = options.dup\n\t\tobject = TestClass.new(options)\n\t\tassert_equal(options_dup, options)\n\tend\nend\n"
  },
  {
    "path": "vendor/plugins/delayed_job/MIT-LICENSE",
    "content": "Copyright (c) 2005 Tobias Luetke\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND\nNONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "vendor/plugins/delayed_job/README.textile",
    "content": "h1. Delayed::Job\n\nDelated_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background. \n\nIt is a direct extraction from Shopify where the job table is responsible for a multitude of core tasks. Amongst those tasks are:\n\n* sending massive newsletters\n* image resizing\n* http downloads\n* updating smart collections\n* updating solr, our search server, after product changes\n* batch imports \n* spam checks \n\nh2. Installation\n\nTo install as a gem, add the following to @config/environment.rb@:\n\n<pre>\nconfig.gem 'collectiveidea-delayed_job', :lib => 'delayed_job',\n  :source => 'http://gems.github.com'\n</pre>\n\nRake tasks are not automatically loaded from gems, so you'll need to add the following to your Rakefile:\n\n<pre>\nbegin\n  require 'delayed/tasks'\nrescue LoadError\n  STDERR.puts \"Run `rake gems:install` to install delayed_job\"\nend\n</pre>\n\nTo install as a plugin:\n\n<pre>\nscript/plugin install git://github.com/collectiveidea/delayed_job.git\n</pre>\n\nAfter delayed_job is installed, run:\n\n<pre>\nscript/generate delayed_job\nrake db:migrate\n</pre>\n\nh2. Upgrading to 1.8\n\nIf you are upgrading from a previous release, you will need to generate the new @script/delayed_job@:\n\n<pre>\nscript/generate delayed_job --skip-migration\n</pre>\n\nh2. Queuing Jobs\n\nCall @#send_later(method, params)@ on any object and it will be processed in the background.\n\n<pre>\n# without delayed_job\nNotifier.deliver_signup(@user)\n\n# with delayed_job\nNotifier.send_later :deliver_signup, @user\n</pre>\n\nIf a method should always be run in the background, you can call @#handle_asynchronously@ after the method declaration:\n\n<pre>\nclass Device\n  def deliver\n    # long running method\n  end\n  handle_asynchronously :deliver\nend\n\ndevice = Device.new\ndevice.deliver\n</pre>\n\nh2. Running Jobs\n\n@script/delayed_job@ can be used to manage a background process which will start working off jobs.\n\n<pre>\n$ RAILS_ENV=production script/delayed_job start\n$ RAILS_ENV=production script/delayed_job stop\n\n# Runs two workers in separate processes.\n$ RAILS_ENV=production script/delayed_job -n 2 start\n$ RAILS_ENV=production script/delayed_job stop\n</pre>\n\nWorkers can be running on any computer, as long as they have access to the database and their clock is in sync. Keep in mind that each worker will check the database at least every 5 seconds.\n\nYou can also invoke @rake jobs:work@ which will start working off jobs. You can cancel the rake task with @CTRL-C@. \n\nh2. Custom Jobs\n\nJobs are simple ruby objects with a method called perform. Any object which responds to perform can be stuffed into the jobs table. Job objects are serialized to yaml so that they can later be resurrected by the job runner. \n\n<pre>\nclass NewsletterJob < Struct.new(:text, :emails)\n  def perform\n    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }\n  end    \nend  \n  \nDelayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))\n</pre>\n\nh2. Gory Details\n\nThe library evolves around a delayed_jobs table which looks as follows: \n\n  create_table :delayed_jobs, :force => true do |table|\n    table.integer  :priority, :default => 0      # Allows some jobs to jump to the front of the queue\n    table.integer  :attempts, :default => 0      # Provides for retries, but still fail eventually.\n    table.text     :handler                      # YAML-encoded string of the object that will do work\n    table.text   :last_error                   # reason for last failure (See Note below)\n    table.datetime :run_at                       # When to run. Could be Time.zone.now for immediately, or sometime in the future.\n    table.datetime :locked_at                    # Set when a client is working on this object\n    table.datetime :failed_at                    # Set when all retries have failed (actually, by default, the record is deleted instead)\n    table.string   :locked_by                    # Who is working on this object (if locked)\n    table.timestamps\n  end\n\nOn failure, the job is scheduled again in 5 seconds + N ** 4, where N is the number of retries.\n\nThe default Worker.max_attempts is 25. After this, the job either deleted (default), or left in the database with \"failed_at\" set.\nWith the default of 25 attempts, the last retry will be 20 days later, with the last interval being almost 100 hours.\n\nThe default Worker.max_run_time is 4.hours. If your job takes longer than that, another computer could pick it up. It's up to you to\nmake sure your job doesn't exceed this time. You should set this to the longest time you think the job could take.\n\nBy default, it will delete failed jobs (and it always deletes successful jobs). If you want to keep failed jobs, set\nDelayed::Worker.destroy_failed_jobs = false. The failed jobs will be marked with non-null failed_at.\n\nHere is an example of changing job parameters in Rails:\n\n<pre>\n# config/initializers/delayed_job_config.rb\nDelayed::Worker.destroy_failed_jobs = false\nDelayed::Worker.sleep_delay = 60\nDelayed::Worker.max_attempts = 3\nDelayed::Worker.max_run_time = 5.minutes\n</pre>\n\nh3. Cleaning up\n\nYou can invoke @rake jobs:clear@ to delete all jobs in the queue.\n\nh2. Mailing List\n\nJoin us on the mailing list at http://groups.google.com/group/delayed_job\n\nh2. How to contribute\n\nIf you find what looks like a bug:\n\n# Check the GitHub issue tracker to see if anyone else has had the same issue.\n   http://github.com/collectiveidea/delayed_job/issues/\n# If you don't see anything, create an issue with information on how to reproduce it.\n\nIf you want to contribute an enhancement or a fix:\n\n# Fork the project on github.\n   http://github.com/collectiveidea/delayed_job/\n# Make your changes with tests.\n# Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix\n# Send a pull request.\n\nh3. Changes\n\n* 1.7.0: Added failed_at column which can optionally be set after a certain amount of failed job attempts. By default failed job attempts are destroyed after about a month. \n\n* 1.6.0: Renamed locked_until to locked_at. We now store when we start a given job instead of how long it will be locked by the worker. This allows us to get a reading on how long a job took to execute.                    \n\n* 1.5.0: Job runners can now be run in parallel. Two new database columns are needed: locked_until and locked_by. This allows us to use   pessimistic locking instead of relying on row level locks. This enables us to run as many worker processes as we need to speed up queue processing.\n\n* 1.2.0: Added #send_later to Object for simpler job creation\n\n* 1.0.0: Initial release\n"
  },
  {
    "path": "vendor/plugins/delayed_job/Rakefile",
    "content": "# -*- encoding: utf-8 -*-\nbegin\n  require 'jeweler'\nrescue LoadError\n  puts \"Jeweler not available. Install it with: sudo gem install jeweler\"\n  exit 1\nend\n\nJeweler::Tasks.new do |s|\n  s.name     = \"delayed_job\"\n  s.summary  = \"Database-backed asynchronous priority queue system -- Extracted from Shopify\"\n  s.email    = \"tobi@leetsoft.com\"\n  s.homepage = \"http://github.com/collectiveidea/delayed_job\"\n  s.description = \"Delayed_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background. It is a direct extraction from Shopify where the job table is responsible for a multitude of core tasks.\"\n  s.authors  = [\"Brandon Keepers\", \"Tobias Lütke\"]\n  \n  s.has_rdoc = true\n  s.rdoc_options = [\"--main\", \"README.textile\", \"--inline-source\", \"--line-numbers\"]\n  s.extra_rdoc_files = [\"README.textile\"]\n  \n  s.test_files = Dir['spec/**/*']\n  \n  s.add_development_dependency \"rspec\"\n  s.add_development_dependency \"sqlite3-ruby\"\nend\n\nrequire 'spec/rake/spectask'\n\ntask :default => :spec\n\ndesc 'Run the specs'\nSpec::Rake::SpecTask.new(:spec) do |t|\n  t.libs << 'lib'\n  t.pattern = 'spec/**/*_spec.rb'\n  t.verbose = true\nend\ntask :spec => :check_dependencies\n\n"
  },
  {
    "path": "vendor/plugins/delayed_job/VERSION",
    "content": "1.8.4\n"
  },
  {
    "path": "vendor/plugins/delayed_job/contrib/delayed_job.monitrc",
    "content": "# an example Monit configuration file for delayed_job\n# See: http://stackoverflow.com/questions/1226302/how-to-monitor-delayedjob-with-monit/1285611\n#\n# To use:\n# 1. copy to /var/www/apps/{app_name}/shared/delayed_job.monitrc\n# 2. replace {app_name} as appropriate\n# 3. add this to your /etc/monit/monitrc\n#\n#   include /var/www/apps/{app_name}/shared/delayed_job.monitrc\n\ncheck process delayed_job\n  with pidfile /var/www/apps/{app_name}/shared/pids/delayed_job.pid\n  start program = \"/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job start\"\n  stop program = \"/usr/bin/env RAILS_ENV=production /var/www/apps/{app_name}/current/script/delayed_job stop\""
  },
  {
    "path": "vendor/plugins/delayed_job/delayed_job.gemspec",
    "content": "# Generated by jeweler\n# DO NOT EDIT THIS FILE\n# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`\n# -*- encoding: utf-8 -*-\n\nGem::Specification.new do |s|\n  s.name = %q{delayed_job}\n  s.version = \"1.8.4\"\n\n  s.required_rubygems_version = Gem::Requirement.new(\">= 0\") if s.respond_to? :required_rubygems_version=\n  s.authors = [\"Brandon Keepers\", \"Tobias L\\303\\274tke\"]\n  s.date = %q{2009-10-06}\n  s.description = %q{Delayed_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background. It is a direct extraction from Shopify where the job table is responsible for a multitude of core tasks.}\n  s.email = %q{tobi@leetsoft.com}\n  s.extra_rdoc_files = [\n    \"README.textile\"\n  ]\n  s.files = [\n    \".gitignore\",\n     \"MIT-LICENSE\",\n     \"README.textile\",\n     \"Rakefile\",\n     \"VERSION\",\n     \"contrib/delayed_job.monitrc\",\n     \"delayed_job.gemspec\",\n     \"generators/delayed_job/delayed_job_generator.rb\",\n     \"generators/delayed_job/templates/migration.rb\",\n     \"generators/delayed_job/templates/script\",\n     \"init.rb\",\n     \"lib/delayed/command.rb\",\n     \"lib/delayed/job.rb\",\n     \"lib/delayed/message_sending.rb\",\n     \"lib/delayed/performable_method.rb\",\n     \"lib/delayed/recipes.rb\",\n     \"lib/delayed/tasks.rb\",\n     \"lib/delayed/worker.rb\",\n     \"lib/delayed_job.rb\",\n     \"recipes/delayed_job.rb\",\n     \"spec/database.rb\",\n     \"spec/delayed_method_spec.rb\",\n     \"spec/job_spec.rb\",\n     \"spec/story_spec.rb\",\n     \"tasks/jobs.rake\"\n  ]\n  s.homepage = %q{http://github.com/collectiveidea/delayed_job}\n  s.rdoc_options = [\"--main\", \"README.textile\", \"--inline-source\", \"--line-numbers\"]\n  s.require_paths = [\"lib\"]\n  s.rubygems_version = %q{1.3.5}\n  s.summary = %q{Database-backed asynchronous priority queue system -- Extracted from Shopify}\n  s.test_files = [\n    \"spec/database.rb\",\n     \"spec/delayed_method_spec.rb\",\n     \"spec/job_spec.rb\",\n     \"spec/story_spec.rb\"\n  ]\n\n  if s.respond_to? :specification_version then\n    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION\n    s.specification_version = 3\n\n    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then\n    else\n    end\n  else\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/delayed_job/generators/delayed_job/delayed_job_generator.rb",
    "content": "class DelayedJobGenerator < Rails::Generator::Base\n  default_options :skip_migration => false\n  \n  def manifest\n    record do |m|\n      m.template 'script', 'script/delayed_job', :chmod => 0755\n      unless options[:skip_migration]\n        m.migration_template \"migration.rb\", 'db/migrate',\n                             :migration_file_name => \"create_delayed_jobs\"\n      end\n    end\n  end\n  \nprotected\n\n  def add_options!(opt)\n    opt.separator ''\n    opt.separator 'Options:'\n    opt.on(\"--skip-migration\", \"Don't generate a migration\") { |v| options[:skip_migration] = v }\n  end\n  \nend\n"
  },
  {
    "path": "vendor/plugins/delayed_job/generators/delayed_job/templates/migration.rb",
    "content": "class CreateDelayedJobs < ActiveRecord::Migration\n  def self.up\n    create_table :delayed_jobs, :force => true do |table|\n      table.integer  :priority, :default => 0      # Allows some jobs to jump to the front of the queue\n      table.integer  :attempts, :default => 0      # Provides for retries, but still fail eventually.\n      table.text     :handler                      # YAML-encoded string of the object that will do work\n      table.text     :last_error                   # reason for last failure (See Note below)\n      table.datetime :run_at                       # When to run. Could be Time.zone.now for immediately, or sometime in the future.\n      table.datetime :locked_at                    # Set when a client is working on this object\n      table.datetime :failed_at                    # Set when all retries have failed (actually, by default, the record is deleted instead)\n      table.string   :locked_by                    # Who is working on this object (if locked)\n      table.timestamps\n    end\n\n  end\n  \n  def self.down\n    drop_table :delayed_jobs  \n  end\nend"
  },
  {
    "path": "vendor/plugins/delayed_job/generators/delayed_job/templates/script",
    "content": "#!/usr/bin/env ruby\n\nrequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))\nrequire 'delayed/command'\nDelayed::Command.new(ARGV).daemonize\n"
  },
  {
    "path": "vendor/plugins/delayed_job/init.rb",
    "content": "require File.dirname(__FILE__) + '/lib/delayed_job'\n"
  },
  {
    "path": "vendor/plugins/delayed_job/lib/delayed/command.rb",
    "content": "require 'rubygems'\nrequire 'daemons'\nrequire 'optparse'\n\nmodule Delayed\n  class Command\n    attr_accessor :worker_count\n    \n    def initialize(args)\n      @files_to_reopen = []\n      @options = {:quiet => true}\n      \n      @worker_count = 1\n      \n      opts = OptionParser.new do |opts|\n        opts.banner = \"Usage: #{File.basename($0)} [options] start|stop|restart|run\"\n\n        opts.on('-h', '--help', 'Show this message') do\n          puts opts\n          exit 1\n        end\n        opts.on('-e', '--environment=NAME', 'Specifies the environment to run this delayed jobs under (test/development/production).') do |e|\n          STDERR.puts \"The -e/--environment option has been deprecated and has no effect. Use RAILS_ENV and see http://github.com/collectiveidea/delayed_job/issues/#issue/7\"\n        end\n        opts.on('--min-priority N', 'Minimum priority of jobs to run.') do |n|\n          @options[:min_priority] = n\n        end\n        opts.on('--max-priority N', 'Maximum priority of jobs to run.') do |n|\n          @options[:max_priority] = n\n        end\n        opts.on('-n', '--number_of_workers=workers', \"Number of unique workers to spawn\") do |worker_count|\n          @worker_count = worker_count.to_i rescue 1\n        end\n      end\n      @args = opts.parse!(args)\n    end\n  \n    def daemonize\n      ObjectSpace.each_object(File) do |file|\n        @files_to_reopen << file unless file.closed?\n      end\n      \n      worker_count.times do |worker_index|\n        process_name = worker_count == 1 ? \"delayed_job\" : \"delayed_job.#{worker_index}\"\n        Daemons.run_proc(process_name, :dir => \"#{RAILS_ROOT}/tmp/pids\", :dir_mode => :normal, :ARGV => @args) do |*args|\n          run process_name\n        end\n      end\n    end\n    \n    def run(worker_name = nil)\n      Dir.chdir(RAILS_ROOT)\n      \n      # Re-open file handles\n      @files_to_reopen.each do |file|\n        begin\n          file.reopen File.join(RAILS_ROOT, 'log', 'delayed_job.log'), 'a+'\n          file.sync = true\n        rescue ::Exception\n        end\n      end\n      \n      Delayed::Worker.logger = Rails.logger\n      ActiveRecord::Base.connection.reconnect!\n      \n      worker = Delayed::Worker.new(@options)\n      worker.name_prefix = \"#{worker_name} \"\n      worker.start\n    rescue => e\n      Rails.logger.fatal e\n      STDERR.puts e.message\n      exit 1\n    end\n    \n  end\nend\n"
  },
  {
    "path": "vendor/plugins/delayed_job/lib/delayed/job.rb",
    "content": "require 'timeout'\n\nmodule Delayed\n\n  class DeserializationError < StandardError\n  end\n\n  # A job object that is persisted to the database.\n  # Contains the work object as a YAML field.\n  class Job < ActiveRecord::Base\n    set_table_name :delayed_jobs\n\n    named_scope :ready_to_run, lambda {|worker_name, max_run_time|\n      {:conditions => ['(run_at <= ? AND (locked_at IS NULL OR locked_at < ?) OR locked_by = ?) AND failed_at IS NULL', db_time_now, db_time_now - max_run_time, worker_name]}\n    }\n    named_scope :by_priority, :order => 'priority DESC, run_at ASC'\n\n    ParseObjectFromYaml = /\\!ruby\\/\\w+\\:([^\\s]+)/\n\n    # When a worker is exiting, make sure we don't have any locked jobs.\n    def self.clear_locks!(worker_name)\n      update_all(\"locked_by = null, locked_at = null\", [\"locked_by = ?\", worker_name])\n    end\n\n    def failed?\n      failed_at\n    end\n    alias_method :failed, :failed?\n\n    def payload_object\n      @payload_object ||= deserialize(self['handler'])\n    end\n\n    def name\n      @name ||= begin\n        payload = payload_object\n        if payload.respond_to?(:display_name)\n          payload.display_name\n        else\n          payload.class.name\n        end\n      end\n    end\n\n    def payload_object=(object)\n      self['handler'] = object.to_yaml\n    end\n\n    # Add a job to the queue\n    def self.enqueue(*args)\n      object = args.shift\n      unless object.respond_to?(:perform)\n        raise ArgumentError, 'Cannot enqueue items which do not respond to perform'\n      end\n    \n      priority = args.first || 0\n      run_at   = args[1]\n\n      Job.create(:payload_object => object, :priority => priority.to_i, :run_at => run_at)\n    end\n\n    # Find a few candidate jobs to run (in case some immediately get locked by others).\n    def self.find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time)\n      scope = self.ready_to_run(worker_name, max_run_time)\n      scope = scope.scoped(:conditions => ['priority >= ?', Worker.min_priority]) if Worker.min_priority\n      scope = scope.scoped(:conditions => ['priority <= ?', Worker.max_priority]) if Worker.max_priority\n      \n      ActiveRecord::Base.silence do\n        scope.by_priority.all(:limit => limit)\n      end\n    end\n\n    # Lock this job for this worker.\n    # Returns true if we have the lock, false otherwise.\n    def lock_exclusively!(max_run_time, worker)\n      now = self.class.db_time_now\n      affected_rows = if locked_by != worker\n        # We don't own this job so we will update the locked_by name and the locked_at\n        self.class.update_all([\"locked_at = ?, locked_by = ?\", now, worker], [\"id = ? and (locked_at is null or locked_at < ?) and (run_at <= ?)\", id, (now - max_run_time.to_i), now])\n      else\n        # We already own this job, this may happen if the job queue crashes.\n        # Simply resume and update the locked_at\n        self.class.update_all([\"locked_at = ?\", now], [\"id = ? and locked_by = ?\", id, worker])\n      end\n      if affected_rows == 1\n        self.locked_at    = now\n        self.locked_by    = worker\n        return true\n      else\n        return false\n      end\n    end\n\n    # Unlock this job (note: not saved to DB)\n    def unlock\n      self.locked_at    = nil\n      self.locked_by    = nil\n    end\n\n    # Moved into its own method so that new_relic can trace it.\n    def invoke_job\n      payload_object.perform\n    end\n\n  private\n\n    def deserialize(source)\n      handler = YAML.load(source) rescue nil\n\n      unless handler.respond_to?(:perform)\n        if handler.nil? && source =~ ParseObjectFromYaml\n          handler_class = $1\n        end\n        attempt_to_load(handler_class || handler.class)\n        handler = YAML.load(source)\n      end\n\n      return handler if handler.respond_to?(:perform)\n\n      raise DeserializationError,\n        'Job failed to load: Unknown handler. Try to manually require the appropriate file.'\n    rescue TypeError, LoadError, NameError => e\n      raise DeserializationError,\n        \"Job failed to load: #{e.message}. Try to manually require the required file.\"\n    end\n\n    # Constantize the object so that ActiveSupport can attempt\n    # its auto loading magic. Will raise LoadError if not successful.\n    def attempt_to_load(klass)\n       klass.constantize\n    end\n\n    # Get the current time (GMT or local depending on DB)\n    # Note: This does not ping the DB to get the time, so all your clients\n    # must have syncronized clocks.\n    def self.db_time_now\n      if Time.zone\n        Time.zone.now\n      elsif ActiveRecord::Base.default_timezone == :utc\n        Time.now.utc\n      else\n        Time.now\n      end\n    end\n\n  protected\n\n    def before_save\n      self.run_at ||= self.class.db_time_now\n    end\n\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/delayed_job/lib/delayed/message_sending.rb",
    "content": "module Delayed\n  module MessageSending\n    def send_later(method, *args)\n      Delayed::Job.enqueue Delayed::PerformableMethod.new(self, method.to_sym, args)\n    end\n\n    def send_at(time, method, *args)\n      Delayed::Job.enqueue(Delayed::PerformableMethod.new(self, method.to_sym, args), 0, time)\n    end\n    \n    module ClassMethods\n      def handle_asynchronously(method)\n        aliased_method, punctuation = method.to_s.sub(/([?!=])$/, ''), $1\n        with_method, without_method = \"#{aliased_method}_with_send_later#{punctuation}\", \"#{aliased_method}_without_send_later#{punctuation}\"\n        define_method(with_method) do |*args|\n          send_later(without_method, *args)\n        end\n        alias_method_chain method, :send_later\n      end\n    end\n  end                               \nend"
  },
  {
    "path": "vendor/plugins/delayed_job/lib/delayed/performable_method.rb",
    "content": "module Delayed\n  class PerformableMethod < Struct.new(:object, :method, :args)\n    CLASS_STRING_FORMAT = /^CLASS\\:([A-Z][\\w\\:]+)$/\n    AR_STRING_FORMAT    = /^AR\\:([A-Z][\\w\\:]+)\\:(\\d+)$/\n\n    def initialize(object, method, args)\n      raise NoMethodError, \"undefined method `#{method}' for #{self.inspect}\" unless object.respond_to?(method)\n\n      self.object = dump(object)\n      self.args   = args.map { |a| dump(a) }\n      self.method = method.to_sym\n    end\n    \n    def display_name  \n      case self.object\n      when CLASS_STRING_FORMAT then \"#{$1}.#{method}\"\n      when AR_STRING_FORMAT    then \"#{$1}##{method}\"\n      else \"Unknown##{method}\"\n      end      \n    end    \n\n    def perform\n      load(object).send(method, *args.map{|a| load(a)})\n    rescue ActiveRecord::RecordNotFound\n      # We cannot do anything about objects which were deleted in the meantime\n      true\n    end\n\n    private\n\n    def load(arg)\n      case arg\n      when CLASS_STRING_FORMAT then $1.constantize\n      when AR_STRING_FORMAT    then $1.constantize.find($2)\n      else arg\n      end\n    end\n\n    def dump(arg)\n      case arg\n      when Class              then class_to_string(arg)\n      when ActiveRecord::Base then ar_to_string(arg)\n      else arg\n      end\n    end\n\n    def ar_to_string(obj)\n      \"AR:#{obj.class}:#{obj.id}\"\n    end\n\n    def class_to_string(obj)\n      \"CLASS:#{obj.name}\"\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/delayed_job/lib/delayed/recipes.rb",
    "content": "# Capistrano Recipes for managing delayed_job\n#\n# Add these callbacks to have the delayed_job process restart when the server\n# is restarted:\n#\n#   after \"deploy:stop\",    \"delayed_job:stop\"\n#   after \"deploy:start\",   \"delayed_job:start\"\n#   after \"deploy:restart\", \"delayed_job:restart\"\n\nCapistrano::Configuration.instance.load do\n  namespace :delayed_job do\n    def rails_env\n      fetch(:rails_env, false) ? \"RAILS_ENV=#{fetch(:rails_env)}\" : ''\n    end\n    \n    desc \"Stop the delayed_job process\"\n    task :stop, :roles => :app do\n      run \"cd #{current_path};#{rails_env} script/delayed_job stop\"\n    end\n\n    desc \"Start the delayed_job process\"\n    task :start, :roles => :app do\n      run \"cd #{current_path};#{rails_env} script/delayed_job start\"\n    end\n\n    desc \"Restart the delayed_job process\"\n    task :restart, :roles => :app do\n      run \"cd #{current_path};#{rails_env} script/delayed_job restart\"\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/delayed_job/lib/delayed/tasks.rb",
    "content": "# Re-definitions are appended to existing tasks\ntask :environment\ntask :merb_env\n\nnamespace :jobs do\n  desc \"Clear the delayed_job queue.\"\n  task :clear => [:merb_env, :environment] do\n    Delayed::Job.delete_all\n  end\n\n  desc \"Start a delayed_job worker.\"\n  task :work => [:merb_env, :environment] do\n    Delayed::Worker.new(:min_priority => ENV['MIN_PRIORITY'], :max_priority => ENV['MAX_PRIORITY']).start\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/delayed_job/lib/delayed/worker.rb",
    "content": "module Delayed\n  class Worker\n    cattr_accessor :min_priority, :max_priority, :max_attempts, :max_run_time, :sleep_delay, :logger\n    self.sleep_delay = 5\n    self.max_attempts = 25\n    self.max_run_time = 4.hours\n    \n    # By default failed jobs are destroyed after too many attempts. If you want to keep them around\n    # (perhaps to inspect the reason for the failure), set this to false.\n    cattr_accessor :destroy_failed_jobs\n    self.destroy_failed_jobs = true\n    \n    self.logger = if defined?(Merb::Logger)\n      Merb.logger\n    elsif defined?(RAILS_DEFAULT_LOGGER)\n      RAILS_DEFAULT_LOGGER\n    end\n\n    # name_prefix is ignored if name is set directly\n    attr_accessor :name_prefix\n\n    def initialize(options={})\n      @quiet = options[:quiet]\n      self.class.min_priority = options[:min_priority] if options.has_key?(:min_priority)\n      self.class.max_priority = options[:max_priority] if options.has_key?(:max_priority)\n    end\n\n    # Every worker has a unique name which by default is the pid of the process. There are some\n    # advantages to overriding this with something which survives worker retarts:  Workers can#\n    # safely resume working on tasks which are locked by themselves. The worker will assume that\n    # it crashed before.\n    def name\n      return @name unless @name.nil?\n      \"#{@name_prefix}host:#{Socket.gethostname} pid:#{Process.pid}\" rescue \"#{@name_prefix}pid:#{Process.pid}\"\n    end\n\n    # Sets the name of the worker.\n    # Setting the name to nil will reset the default worker name\n    def name=(val)\n      @name = val\n    end\n\n    def start\n      say \"*** Starting job worker #{name}\"\n\n      trap('TERM') { say 'Exiting...'; $exit = true }\n      trap('INT')  { say 'Exiting...'; $exit = true }\n\n      loop do\n        result = nil\n\n        realtime = Benchmark.realtime do\n          result = work_off\n        end\n\n        count = result.sum\n\n        break if $exit\n\n        if count.zero?\n          sleep(@@sleep_delay)\n        else\n          say \"#{count} jobs processed at %.4f j/s, %d failed ...\" % [count / realtime, result.last]\n        end\n\n        break if $exit\n      end\n\n    ensure\n      Delayed::Job.clear_locks!(name)\n    end\n    \n    def run(job)\n      runtime =  Benchmark.realtime do\n        Timeout.timeout(self.class.max_run_time.to_i) { job.invoke_job }\n        job.destroy\n      end\n      # TODO: warn if runtime > max_run_time ?\n      say \"* [JOB] #{name} completed after %.4f\" % runtime\n      return true  # did work\n    rescue Exception => e\n      handle_failed_job(job, e)\n      return false  # work failed\n    end\n    \n    # Reschedule the job in the future (when a job fails).\n    # Uses an exponential scale depending on the number of failed attempts.\n    def reschedule(job, time = nil)\n      if (job.attempts += 1) < self.class.max_attempts\n        time ||= Job.db_time_now + (job.attempts ** 4) + 5\n        job.run_at = time\n        job.unlock\n        job.save!\n      else\n        say \"* [JOB] PERMANENTLY removing #{job.name} because of #{job.attempts} consecutive failures.\", Logger::INFO\n        self.class.destroy_failed_jobs ? job.destroy : job.update_attribute(:failed_at, Delayed::Job.db_time_now)\n      end\n    end\n\n    def say(text, level = Logger::INFO)\n      puts text unless @quiet\n      logger.add level, text if logger\n    end\n\n  protected\n    \n    def handle_failed_job(job, error)\n      job.last_error = error.message + \"\\n\" + error.backtrace.join(\"\\n\")\n      say \"* [JOB] #{name} failed with #{error.class.name}: #{error.message} - #{job.attempts} failed attempts\", Logger::ERROR\n      reschedule(job)\n    end\n    \n    # Run the next job we can get an exclusive lock on.\n    # If no jobs are left we return nil\n    def reserve_and_run_one_job\n\n      # We get up to 5 jobs from the db. In case we cannot get exclusive access to a job we try the next.\n      # this leads to a more even distribution of jobs across the worker processes\n      job = Delayed::Job.find_available(name, 5, self.class.max_run_time).detect do |job|\n        if job.lock_exclusively!(self.class.max_run_time, name)\n          say \"* [Worker(#{name})] acquired lock on #{job.name}\"\n          true\n        else\n          say \"* [Worker(#{name})] failed to acquire exclusive lock for #{job.name}\", Logger::WARN\n          false\n        end\n      end\n\n      run(job) if job\n    end\n\n    # Do num jobs and return stats on success/failure.\n    # Exit early if interrupted.\n    def work_off(num = 100)\n      success, failure = 0, 0\n\n      num.times do\n        case reserve_and_run_one_job\n        when true\n            success += 1\n        when false\n            failure += 1\n        else\n          break  # leave if no work could be done\n        end\n        break if $exit # leave if we're exiting\n      end\n\n      return [success, failure]\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/delayed_job/lib/delayed_job.rb",
    "content": "autoload :ActiveRecord, 'activerecord'\n\nrequire File.dirname(__FILE__) + '/delayed/message_sending'\nrequire File.dirname(__FILE__) + '/delayed/performable_method'\nrequire File.dirname(__FILE__) + '/delayed/job'\nrequire File.dirname(__FILE__) + '/delayed/worker'\n\nObject.send(:include, Delayed::MessageSending)   \nModule.send(:include, Delayed::MessageSending::ClassMethods)\n\nif defined?(Merb::Plugins)\n  Merb::Plugins.add_rakefiles File.dirname(__FILE__) / 'delayed' / 'tasks'\nend\n"
  },
  {
    "path": "vendor/plugins/delayed_job/recipes/delayed_job.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'delayed', 'recipes'))\n"
  },
  {
    "path": "vendor/plugins/delayed_job/spec/delayed_method_spec.rb",
    "content": "require 'spec_helper'\n\nclass SimpleJob\n  cattr_accessor :runs; self.runs = 0\n  def perform; @@runs += 1; end\nend\n\nclass RandomRubyObject  \n  def say_hello\n    'hello'\n  end\nend\n\nclass ErrorObject\n\n  def throw\n    raise ActiveRecord::RecordNotFound, '...'\n    false\n  end\n\nend\n\nclass StoryReader\n\n  def read(story)\n    \"Epilog: #{story.tell}\"\n  end\n\nend\n\nclass StoryReader\n\n  def read(story)\n    \"Epilog: #{story.tell}\"\n  end\n\nend\n\ndescribe 'random ruby objects' do\n  before       { Delayed::Job.delete_all }\n\n  it \"should respond_to :send_later method\" do\n\n    RandomRubyObject.new.respond_to?(:send_later)\n\n  end\n\n  it \"should raise a ArgumentError if send_later is called but the target method doesn't exist\" do\n    lambda { RandomRubyObject.new.send_later(:method_that_deos_not_exist) }.should raise_error(NoMethodError)\n  end\n\n  it \"should add a new entry to the job table when send_later is called on it\" do\n    Delayed::Job.count.should == 0\n\n    RandomRubyObject.new.send_later(:to_s)\n\n    Delayed::Job.count.should == 1\n  end\n\n  it \"should add a new entry to the job table when send_later is called on the class\" do\n    Delayed::Job.count.should == 0\n\n    RandomRubyObject.send_later(:to_s)\n\n    Delayed::Job.count.should == 1\n  end\n\n  it \"should run get the original method executed when the job is performed\" do\n\n    RandomRubyObject.new.send_later(:say_hello)\n\n    Delayed::Job.count.should == 1\n  end\n\n  it \"should ignore ActiveRecord::RecordNotFound errors because they are permanent\" do\n    job = ErrorObject.new.send_later(:throw)\n    lambda { job.invoke_job }.should_not raise_error\n  end\n\n  it \"should store the object as string if its an active record\" do\n    story = Story.create :text => 'Once upon...'\n    story.send_later(:tell)\n\n    job =  Delayed::Job.find(:first)\n    job.payload_object.class.should   == Delayed::PerformableMethod\n    job.payload_object.object.should  == \"AR:Story:#{story.id}\"\n    job.payload_object.method.should  == :tell\n    job.payload_object.args.should    == []\n    job.payload_object.perform.should == 'Once upon...'\n  end\n\n  it \"should store arguments as string if they an active record\" do\n\n    story = Story.create :text => 'Once upon...'\n\n    reader = StoryReader.new\n    reader.send_later(:read, story)\n\n    job =  Delayed::Job.find(:first)\n    job.payload_object.class.should   == Delayed::PerformableMethod\n    job.payload_object.method.should  == :read\n    job.payload_object.args.should    == [\"AR:Story:#{story.id}\"]\n    job.payload_object.perform.should == 'Epilog: Once upon...'\n  end                 \n  \n  it \"should call send later on methods which are wrapped with handle_asynchronously\" do\n    story = Story.create :text => 'Once upon...'\n  \n    Delayed::Job.count.should == 0\n  \n    story.whatever(1, 5)\n  \n    Delayed::Job.count.should == 1\n    job =  Delayed::Job.find(:first)\n    job.payload_object.class.should   == Delayed::PerformableMethod\n    job.payload_object.method.should  == :whatever_without_send_later\n    job.payload_object.args.should    == [1, 5]\n    job.payload_object.perform.should == 'Once upon...'\n  end\n\n  context \"send_at\" do\n    it \"should queue a new job\" do\n      lambda do\n        \"string\".send_at(1.hour.from_now, :length)\n      end.should change { Delayed::Job.count }.by(1)\n    end\n    \n    it \"should schedule the job in the future\" do\n      time = 1.hour.from_now\n      job = \"string\".send_at(time, :length)\n      job.run_at.should == time\n    end\n    \n    it \"should store payload as PerformableMethod\" do\n      job = \"string\".send_at(1.hour.from_now, :count, 'r')\n      job.payload_object.class.should   == Delayed::PerformableMethod\n      job.payload_object.method.should  == :count\n      job.payload_object.args.should    == ['r']\n      job.payload_object.perform.should == 1\n    end\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/delayed_job/spec/job_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe Delayed::Job do\n  before  do               \n    Delayed::Worker.max_priority = nil\n    Delayed::Worker.min_priority = nil\n    \n    Delayed::Job.delete_all\n  end\n  \n  before(:each) do\n    SimpleJob.runs = 0\n  end\n\n  it \"should set run_at automatically if not set\" do\n    Delayed::Job.create(:payload_object => ErrorJob.new ).run_at.should_not == nil\n  end\n\n  it \"should not set run_at automatically if already set\" do\n    later = 5.minutes.from_now\n    Delayed::Job.create(:payload_object => ErrorJob.new, :run_at => later).run_at.should == later\n  end\n\n  it \"should raise ArgumentError when handler doesn't respond_to :perform\" do\n    lambda { Delayed::Job.enqueue(Object.new) }.should raise_error(ArgumentError)\n  end\n\n  it \"should increase count after enqueuing items\" do\n    Delayed::Job.enqueue SimpleJob.new\n    Delayed::Job.count.should == 1\n  end\n\n  it \"should be able to set priority when enqueuing items\" do\n    Delayed::Job.enqueue SimpleJob.new, 5\n    Delayed::Job.first.priority.should == 5\n  end\n\n  it \"should be able to set run_at when enqueuing items\" do\n    later = (Delayed::Job.db_time_now+5.minutes)\n    Delayed::Job.enqueue SimpleJob.new, 5, later\n\n    # use be close rather than equal to because millisecond values cn be lost in DB round trip\n    Delayed::Job.first.run_at.should be_close(later, 1)\n  end\n\n  it \"should work with jobs in modules\" do\n    job = Delayed::Job.enqueue M::ModuleJob.new\n    lambda { job.invoke_job }.should change { M::ModuleJob.runs }.from(0).to(1)\n  end\n                   \n  it \"should raise an DeserializationError when the job class is totally unknown\" do\n\n    job = Delayed::Job.new\n    job['handler'] = \"--- !ruby/object:JobThatDoesNotExist {}\"\n\n    lambda { job.payload_object.perform }.should raise_error(Delayed::DeserializationError)\n  end\n\n  it \"should try to load the class when it is unknown at the time of the deserialization\" do\n    job = Delayed::Job.new\n    job['handler'] = \"--- !ruby/object:JobThatDoesNotExist {}\"\n\n    job.should_receive(:attempt_to_load).with('JobThatDoesNotExist').and_return(true)\n\n    lambda { job.payload_object.perform }.should raise_error(Delayed::DeserializationError)\n  end\n\n  it \"should try include the namespace when loading unknown objects\" do\n    job = Delayed::Job.new\n    job['handler'] = \"--- !ruby/object:Delayed::JobThatDoesNotExist {}\"\n    job.should_receive(:attempt_to_load).with('Delayed::JobThatDoesNotExist').and_return(true)\n    lambda { job.payload_object.perform }.should raise_error(Delayed::DeserializationError)\n  end\n\n  it \"should also try to load structs when they are unknown (raises TypeError)\" do\n    job = Delayed::Job.new\n    job['handler'] = \"--- !ruby/struct:JobThatDoesNotExist {}\"\n\n    job.should_receive(:attempt_to_load).with('JobThatDoesNotExist').and_return(true)\n\n    lambda { job.payload_object.perform }.should raise_error(Delayed::DeserializationError)\n  end\n\n  it \"should try include the namespace when loading unknown structs\" do\n    job = Delayed::Job.new\n    job['handler'] = \"--- !ruby/struct:Delayed::JobThatDoesNotExist {}\"\n\n    job.should_receive(:attempt_to_load).with('Delayed::JobThatDoesNotExist').and_return(true)\n    lambda { job.payload_object.perform }.should raise_error(Delayed::DeserializationError)\n  end\n  \n  it \"should never find failed jobs\" do\n    @job = Delayed::Job.create :payload_object => SimpleJob.new, :attempts => 50, :failed_at => Delayed::Job.db_time_now\n    Delayed::Job.find_available('worker', 1).length.should == 0\n  end\n\n  context \"when another worker is already performing an task, it\" do\n\n    before :each do\n      @job = Delayed::Job.create :payload_object => SimpleJob.new, :locked_by => 'worker1', :locked_at => Delayed::Job.db_time_now - 5.minutes\n    end\n\n    it \"should not allow a second worker to get exclusive access\" do\n      @job.lock_exclusively!(4.hours, 'worker2').should == false\n    end\n\n    it \"should allow a second worker to get exclusive access if the timeout has passed\" do\n      @job.lock_exclusively!(1.minute, 'worker2').should == true\n    end      \n    \n    it \"should be able to get access to the task if it was started more then max_age ago\" do\n      @job.locked_at = 5.hours.ago\n      @job.save\n\n      @job.lock_exclusively! 4.hours, 'worker2'\n      @job.reload\n      @job.locked_by.should == 'worker2'\n      @job.locked_at.should > 1.minute.ago\n    end\n\n    it \"should not be found by another worker\" do\n      Delayed::Job.find_available('worker2', 1, 6.minutes).length.should == 0\n    end\n\n    it \"should be found by another worker if the time has expired\" do\n      Delayed::Job.find_available('worker2', 1, 4.minutes).length.should == 1\n    end\n\n    it \"should be able to get exclusive access again when the worker name is the same\" do\n      @job.lock_exclusively!(5.minutes, 'worker1').should be_true\n      @job.lock_exclusively!(5.minutes, 'worker1').should be_true\n      @job.lock_exclusively!(5.minutes, 'worker1').should be_true\n    end                                        \n  end\n  \n  context \"when another worker has worked on a task since the job was found to be available, it\" do\n\n    before :each do\n      @job = Delayed::Job.create :payload_object => SimpleJob.new\n      @job_copy_for_worker_2 = Delayed::Job.find(@job.id)\n    end\n\n    it \"should not allow a second worker to get exclusive access if already successfully processed by worker1\" do\n      @job.delete\n      @job_copy_for_worker_2.lock_exclusively!(4.hours, 'worker2').should == false\n    end\n\n    it \"should not allow a second worker to get exclusive access if failed to be processed by worker1 and run_at time is now in future (due to backing off behaviour)\" do\n      @job.update_attributes(:attempts => 1, :run_at => 1.day.from_now)\n      @job_copy_for_worker_2.lock_exclusively!(4.hours, 'worker2').should == false\n    end\n  end\n\n  context \"#name\" do\n    it \"should be the class name of the job that was enqueued\" do\n      Delayed::Job.create(:payload_object => ErrorJob.new ).name.should == 'ErrorJob'\n    end\n\n    it \"should be the method that will be called if its a performable method object\" do\n      Delayed::Job.send_later(:clear_locks!)\n      Delayed::Job.last.name.should == 'Delayed::Job.clear_locks!'\n\n    end\n    it \"should be the instance method that will be called if its a performable method object\" do\n      story = Story.create :text => \"...\"                 \n      \n      story.send_later(:save)\n      \n      Delayed::Job.last.name.should == 'Story#save'\n    end\n  end\n  \n  context \"worker prioritization\" do\n    \n    before(:each) do\n      Delayed::Worker.max_priority = nil\n      Delayed::Worker.min_priority = nil\n    end\n\n    it \"should fetch jobs ordered by priority\" do\n      number_of_jobs = 10\n      number_of_jobs.times { Delayed::Job.enqueue SimpleJob.new, rand(10) }\n      jobs = Delayed::Job.find_available('worker', 10)\n      ordered = true\n      jobs[1..-1].each_index{ |i| \n        if (jobs[i].priority < jobs[i+1].priority)\n          ordered = false\n          break\n        end\n      }\n      ordered.should == true\n    end\n   \n  end\n  \n  context \"db_time_now\" do\n    it \"should return time in current time zone if set\" do\n      Time.zone = 'Eastern Time (US & Canada)'\n      Delayed::Job.db_time_now.zone.should == 'EST'\n    end\n    \n    it \"should return UTC time if that is the AR default\" do\n      Time.zone = nil\n      ActiveRecord::Base.default_timezone = :utc\n      Delayed::Job.db_time_now.zone.should == 'UTC'\n    end\n\n    it \"should return local time if that is the AR default\" do\n      Time.zone = nil\n      ActiveRecord::Base.default_timezone = :local\n      Delayed::Job.db_time_now.zone.should_not == 'UTC'\n    end\n  end\n  \nend\n"
  },
  {
    "path": "vendor/plugins/delayed_job/spec/sample_jobs.rb",
    "content": "class SimpleJob\n  cattr_accessor :runs; self.runs = 0\n  def perform; @@runs += 1; end\nend\n\nclass ErrorJob\n  cattr_accessor :runs; self.runs = 0\n  def perform; raise 'did not work'; end\nend             \n\nclass LongRunningJob\n  def perform; sleep 250; end\nend\n\nmodule M\n  class ModuleJob\n    cattr_accessor :runs; self.runs = 0\n    def perform; @@runs += 1; end    \n  end\n  \nend"
  },
  {
    "path": "vendor/plugins/delayed_job/spec/spec_helper.rb",
    "content": "$:.unshift(File.dirname(__FILE__) + '/../lib')\n\nrequire 'rubygems'\nrequire 'spec'\nrequire 'active_record'\nrequire 'delayed_job'\n  \nActiveRecord::Base.logger = Logger.new('/tmp/dj.log')\nActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')\nActiveRecord::Migration.verbose = false\n\nActiveRecord::Schema.define do\n\n  create_table :delayed_jobs, :force => true do |table|\n    table.integer  :priority, :default => 0\n    table.integer  :attempts, :default => 0\n    table.text     :handler\n    table.string   :last_error\n    table.datetime :run_at\n    table.datetime :locked_at\n    table.string   :locked_by\n    table.datetime :failed_at\n    table.timestamps\n  end\n\n  create_table :stories, :force => true do |table|\n    table.string :text\n  end\n\nend\n\n# Purely useful for test cases...\nclass Story < ActiveRecord::Base\n  def tell; text; end       \n  def whatever(n, _); tell*n; end\n  \n  handle_asynchronously :whatever\nend\n\nrequire 'sample_jobs'\n"
  },
  {
    "path": "vendor/plugins/delayed_job/spec/story_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe \"A story\" do\n\n  before(:all) do\n    @story = Story.create :text => \"Once upon a time...\"\n  end\n\n  it \"should be shared\" do\n    @story.tell.should == 'Once upon a time...'\n  end\n\n  it \"should not return its result if it storytelling is delayed\" do\n    @story.send_later(:tell).should_not == 'Once upon a time...'\n  end\n\nend"
  },
  {
    "path": "vendor/plugins/delayed_job/spec/worker_spec.rb",
    "content": "require 'spec_helper'\n\ndescribe Delayed::Worker do\n  def job_create(opts = {})\n    Delayed::Job.create(opts.merge(:payload_object => SimpleJob.new))\n  end\n\n  before(:all) do\n    Delayed::Worker.send :public, :work_off\n  end\n\n  before(:each) do\n    @worker = Delayed::Worker.new(:max_priority => nil, :min_priority => nil, :quiet => true)\n\n    Delayed::Job.delete_all\n    \n    SimpleJob.runs = 0\n  end\n  \n  describe \"running a job\" do\n    it \"should fail after Worker.max_run_time\" do\n      begin\n        old_max_run_time = Delayed::Worker.max_run_time\n        Delayed::Worker.max_run_time = 1.second\n        @job = Delayed::Job.create :payload_object => LongRunningJob.new\n        @worker.run(@job)\n        @job.reload.last_error.should =~ /expired/\n        @job.attempts.should == 1\n      ensure\n        Delayed::Worker.max_run_time = old_max_run_time\n      end\n    end\n  end\n  \n  context \"worker prioritization\" do\n    before(:each) do\n      @worker = Delayed::Worker.new(:max_priority => 5, :min_priority => -5, :quiet => true)\n    end\n\n    it \"should only work_off jobs that are >= min_priority\" do\n      SimpleJob.runs.should == 0\n\n      job_create(:priority => -10)\n      job_create(:priority => 0)\n      @worker.work_off\n\n      SimpleJob.runs.should == 1\n    end\n\n    it \"should only work_off jobs that are <= max_priority\" do\n      SimpleJob.runs.should == 0\n\n      job_create(:priority => 10)\n      job_create(:priority => 0)\n\n      @worker.work_off\n\n      SimpleJob.runs.should == 1\n    end\n  end\n\n  context \"while running with locked and expired jobs\" do\n    before(:each) do\n      @worker.name = 'worker1'\n    end\n    \n    it \"should not run jobs locked by another worker\" do\n      job_create(:locked_by => 'other_worker', :locked_at => (Delayed::Job.db_time_now - 1.minutes))\n      lambda { @worker.work_off }.should_not change { SimpleJob.runs }\n    end\n    \n    it \"should run open jobs\" do\n      job_create\n      lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)\n    end\n    \n    it \"should run expired jobs\" do\n      expired_time = Delayed::Job.db_time_now - (1.minutes + Delayed::Worker.max_run_time)\n      job_create(:locked_by => 'other_worker', :locked_at => expired_time)\n      lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)\n    end\n    \n    it \"should run own jobs\" do\n      job_create(:locked_by => @worker.name, :locked_at => (Delayed::Job.db_time_now - 1.minutes))\n      lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)\n    end\n  end\n  \n  describe \"failed jobs\" do\n    before do\n      # reset defaults\n      Delayed::Worker.destroy_failed_jobs = true\n      Delayed::Worker.max_attempts = 25\n\n      @job = Delayed::Job.enqueue ErrorJob.new\n    end\n\n    it \"should record last_error when destroy_failed_jobs = false, max_attempts = 1\" do\n      Delayed::Worker.destroy_failed_jobs = false\n      Delayed::Worker.max_attempts = 1\n      @worker.run(@job)\n      @job.reload\n      @job.last_error.should =~ /did not work/\n      @job.last_error.should =~ /worker_spec.rb/\n      @job.attempts.should == 1\n      @job.failed_at.should_not be_nil\n    end\n    \n    it \"should re-schedule jobs after failing\" do\n      @worker.run(@job)\n      @job.reload\n      @job.last_error.should =~ /did not work/\n      @job.last_error.should =~ /sample_jobs.rb:8:in `perform'/\n      @job.attempts.should == 1\n      @job.run_at.should > Delayed::Job.db_time_now - 10.minutes\n      @job.run_at.should < Delayed::Job.db_time_now + 10.minutes\n    end\n  end\n  \n  context \"reschedule\" do\n    before do\n      @job = Delayed::Job.create :payload_object => SimpleJob.new\n    end\n    \n    context \"and we want to destroy jobs\" do\n      before do\n        Delayed::Worker.destroy_failed_jobs = true\n      end\n      \n      it \"should be destroyed if it failed more than Worker.max_attempts times\" do\n        @job.should_receive(:destroy)\n        Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }\n      end\n      \n      it \"should not be destroyed if failed fewer than Worker.max_attempts times\" do\n        @job.should_not_receive(:destroy)\n        (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }\n      end\n    end\n    \n    context \"and we don't want to destroy jobs\" do\n      before do\n        Delayed::Worker.destroy_failed_jobs = false\n      end\n      \n      it \"should be failed if it failed more than Worker.max_attempts times\" do\n        @job.reload.failed_at.should == nil\n        Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }\n        @job.reload.failed_at.should_not == nil\n      end\n\n      it \"should not be failed if it failed fewer than Worker.max_attempts times\" do\n        (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }\n        @job.reload.failed_at.should == nil\n      end\n      \n    end\n  end\n  \n  \nend\n"
  },
  {
    "path": "vendor/plugins/delayed_job/tasks/jobs.rake",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'delayed', 'tasks'))\n"
  },
  {
    "path": "vendor/plugins/engines/.gitignore",
    "content": ".DS_Store\ntest_app\ndoc"
  },
  {
    "path": "vendor/plugins/engines/CHANGELOG",
    "content": "= EDGE\n\n* Samuel Williams (http://www.oriontransfer.co.nz/):\n\tThanks to Tekin for his patches.\n\tUpdated migrations system to tie in more closely with the current rails mechanism.\n\tRake task for updating database schema info\n\t\trake db:migrate:upgrade_plugin_migrations\n\tPlease see http://engines.lighthouseapp.com/projects/10178-engines-plugin/tickets/17 for more information.\n\n* Refactored the view loading to work with changes in Edge Rails\n\n* Fixed integration of plugin migrations with the new, default timestamped migrations in Edge Rails\n\n* Refactored tests into the plugin itself - the plugin can now generate its own test_app harness and run tests within it.\n\n\n= 2.0.0 - (ANOTHER) MASSIVE INTERNAL REFACTORING\n\n* Engines now conforms to the new plugin loading mechanism, delegating plugin load order and lots of other things to Rails itself.\n\n\n\n= 1.2.2\n\n* Added the ability to code mix different types of files, cleaning up the existing code-mixing implementation slightly (Ticket #271)\n\n\n= 1.2.1\n\n* Added documentation to clarify some of the issues with Rails unloading classes that aren't required using \"require_dependency\" (Ticket #266)\n\n* Fixed a bug where test_help was being loaded when it wasn't needed, and was actually causing problems (Ticket #265)\n\n\n= 1.2.0 - MASSIVE INTERNAL REFACTORING\n\n* !!!Support for Rails < 1.2 has been dropped!!!; if you are using Rails =< 1.1.6, please use Engines 1.1.6, available from http://svn.rails-engines.org/engines/tags/rel_1.1.6\n\n* Engines are dead! Long live plugins! There is now no meaningful notion of an engine - all plugins can take advantage of the more powerful features that the engines plugin provides by including app directories, etc.\n\n* Init_engine.rb is no longer used; please use the plugin-standard init.rb instead.\n\n* Engines.start is no longer required; please use the config.plugins array provided by Rails instead\n\n* To get the most benefit from Engines, set config.plugins to [\"engines\", \"*\"] to load the engines plugin first, and then all other plugins in their normal order after.\n\n* Access all loaded plugins via the new Rails.plugins array, and by name using Rails.plugins[:plugin_name].\n\n* Access plugin metadata loaded automatically from about.yml: Rails.plugins[:name].about. Plugin#version is provided directly, for easy access.\n\n* Module.config is has been removed - use mattr_accessor instead, and initialize your default values via the init.rb mechanism.\n\n* Public asset helpers have been rewritten; instead of engine_stylesheet, now use stylesheet_link_tag :name, :plugin => \"plugin_name\"\n\n* Plugin migrations have been reworked to integrate into the main migration stream. Please run script/generate plugin_migration to create plugin migrations in your main application.\n\n* The fixture method for loading fixtures against any class has been removed; instead, engines will now provide a mechanism for loading fixtures from all plugins, by mirroring fixtures into a common location.\n\n* All references to engines have been removed; For example, any rake tasks which applied to engines now apply to all plugins. The default Rails rake tasks for plugins are overridden where necessary.\n\n* Layouts can now be shared via plugins - inspiration gratefully taken from PluginAWeek's plugin_routing :)\n\n* Actual routing from plugins is now possible, by including routes.rb in your plugin directory and using the from_plugin method in config/routes.rb (Ticket #182)\n\n* Controllers are no longer loaded twice if they're not present in the normal app/ directory (Ticket #177)\n\n* The preferred location for javascripts/stylesheets/etc is now 'assets' rather than 'public'\n\n* Ensure that plugins started before routing have their controllers appropriately added to config.controller_paths (Ticket #258)\n\n* Removed Engines.version - it's not longer relevant, now we're loading version information from about.yml files.\n\n* Added a huge amount of documentation to all new modules.\n\n* Added new warning message if installation of engines 1.2.x is attempted in a Rails 1.1.x application\n\n* Added details of the removal of the config method to UPGRADING\n\n* Removed the plugins:info rake task in favour of adding information to script/about via the Rails::Info module (Ticket #261)\n\n* Improved handling of testing and documentation tasks for plugins\n\n\n\n= 1.1.4\n\n* Fixed creation of multipart emails (Ticket #190)\n\n* Added a temporary fix to the code-mixing issue. In your engine's test/test_helper.rb, please add the following lines:\n\n   # Ensure that the code mixing and view loading from the application is disabled\n   Engines.disable_app_views_loading = true\n   Engines.disable_app_code_mixing = true\n\n  which will prevent code mixing for controllers and helpers, and loading views from the application. One thing to remember is to load any controllers/helpers using 'require_or_load' in your tests, to ensure that the engine behaviour is respected (Ticket #135)\n\n* Added tasks to easily test engines individually (Ticket #120)\n\n* Fixture extensions will now fail with an exception if the corresponding class cannot be loaded (Ticket #138)\n\n* Patch for new routing/controller loading in Rails 1.1.6. The routing code is now replaced with the contents of config.controller_paths, along with controller paths from any started engines (Ticket #196)\n\n* Rails' Configuration instance is now stored, and available from all engines and plugins.\n\n\n\n= 1.1.3\n\n* Fixed README to show 'models' rather than 'model' class (Ticket #167)\n* Fixed dependency loading to work with Rails 1.1.4 (Ticket #180)\n\n\n\n= 1.1.2\n\n* Added better fix to version checking (Ticket #130, jdell@gbdev.com).\n\n* Fixed generated init_engine.rb so that VERSION module doesn't cause probems (Ticket #131, japgolly@gmail.com)\n\n* Fixed error with Rails 1.0 when trying to ignore the engine_schema_info table (Ticket #132, snowblink@gmail.com)\n\n* Re-added old style rake tasks (Ticket #133)\n\n* No longer adding all subdirectories of <engine>/app or <engine>/lib, as this can cause issues when files are grouped in modules (Ticket #149, kasatani@gmail.com)\n\n* Fixed engine precidence ordering for Rails 1.1 (Ticket #146)\n\n* Added new Engines.each method to assist in processing the engines in the desired order (Ticket #146)\n\n* Fixed annoying error message at appears when starting the console in development mode (Ticket #134)\n\n* Engines is now super-careful about loading the correct version of Rails from vendor (Ticket #154)\n\n\n\n= 1.1.1\n\n* Fixed migration rake task failing when given a specific version (Ticket #115)\n\n* Added new rake task \"test:engines\" which will test engines (and other plugins) but ensure that the test database is cloned from development beforehand (Ticket #125)\n\n* Fixed issue where 'engine_schema_info' table was included in schema dumps (Ticket #87)\n\n* Fixed multi-part emails (Ticket #121)\n\n* Added an 'install.rb' file to new engines created by the bundled generator, which installs the engines plugin automatically if it doesn't already exist (Ticket #122)\n\n* Added a default VERSION module to generated engines (Ticket #123)\n\n* Refactored copying of engine's public files to a method of an Engine instance. You can now call Engines.get(:engine_name).copy_public_files (Ticket #108)\n\n* Changed engine generator templates from .rb files to .erb files (Ticket #106)\n\n* Fixed the test_helper.erb file to use the correct testing extensions and not load any schema - the schema will be cloned automatically via rake test:engines\n\n* Fixed problem when running with Rails 1.1.1 where version wasn't determined correctly (Ticket #129)\n\n* Fixed bug preventing engines from loading when both Rails 1.1.0 and 1.1.1 gems are installed and in use.\n\n* Updated version (d'oh!)\n\n\n\n= 1.1.0\n\n* Improved regexp matching for Rails 1.0 engines with peculiar paths\n\n* Engine instance objects can be accessed via Engines[:name], an alias for Engines.get(:name) (Ticket #99)\n\n* init_engine.rb is now processed as the final step in the Engine.start process, so it can access files within the lib directory, which is now in the $LOAD_PATH at that point. (Ticket #99)\n\n* Clarified MIT license (Ticket #98)\n\n* Updated Rake tasks to integrate smoothly with Rails 1.1 namespaces\n\n* Changed the version to \"1.1.0 (svn)\"\n\n* Added more information about using the plugin with Edge Rails to the README\n\n* moved extensions into lib/engines/ directory to enable use of Engines module in extension code.\n\n* Added conditional require_or_load method which attempts to detect the current Rails version. To use the Edge Rails version of the loading mechanism, add the line:\n\n*   Engines.config :edge, true\n\n* to your environment.rb file.\n\n* Merged changes from /branches/edge and /branches/rb_1.0 into /trunk\n\n* engine_schema_info now respects the prefix/suffixes set for ActiveRecord::Base (Ticket #67)\n\n* added ActiveRecord::Base.wrapped_table_name(name) method to assist in determining the correct table name\n\n\n\n= 1.0.6\n\n* Added ability to determine version information for engines: rake engine_info\n\n* Added a custom logger for the Engines module, to stop pollution of the Rails logs.\n\n* Added some more tests (in particular, see rails_engines/applications/engines_test).\n\n* Another attempt at solving Ticket #53 - controllers and helpers should now be loadable from modules, and if a full path (including RAILS_ROOT/ENGINES_ROOT) is given, it should be safely stripped from the require filename such that corresponding files can be located in any active engines. In other words, controller/helper overloading should now completely work, even if the controllers/helpers are in modules.\n\n* Added (finally) patch from Ticket #22 - ActionMailer helpers should now load\n\n* Removed support for Engines.start :engine, :engine_name => 'whatever'. It was pointless.\n\n* Fixed engine name referencing; engine_stylesheet/engine_javascript can now happily use shorthand engine names (i.e. :test == :test_engine) (Ticket #45)\n\n* Fixed minor documentation error ('Engine.start' ==> 'Engines.start') (Ticket #57)\n\n* Fixed double inclusion of RAILS_ROOT in engine_migrate rake task (Ticket #61)\n\n* Added ability to force config values even if given as a hash (Ticket #62)\n\n\n\n= 1.0.5\n\n* Fixed bug stopping fixtures from loading with PostgreSQL\n\n\n\n= 1.0.4\n\n* Another attempt at loading controllers within modules (Ticket #56)\n\n\n\n= 1.0.3\n\n* Fixed serious dependency bug stopping controllers being loaded (Ticket #56)\n\n\n\n= 1.0.2\n\n* Fixed bug with overloading controllers in modules from /app directory\n\n* Fixed exception thrown when public files couldn't be created; exception is now logged (Ticket #52)\n\n* Fixed problem with generated test_helper.rb file via File.expand_path (Ticket #50)\n\n\n\n= 1.0.1\n\n* Added engine generator for creation of new engines\n\n* Fixed 'Engine' typo in README\n\n* Fixed bug in fixtures extensions\n\n* Fixed /lib path management bug\n\n* Added method to determine public directory location from Engine object\n\n* Fixed bug in the error message in get_engine_dir()\n\n* Added proper component loading\n\n* Added preliminary tests for the config() methods module\n\n\n\n= pre-v170\n\n* Fixed copyright notices to point to DHH, rather than me.\n\n* Moved extension require statements into lib/engines.rb, so the will be loaded if another module/file calls require 'engines\n\n* Added a CHANGELOG file (this file)\n"
  },
  {
    "path": "vendor/plugins/engines/MIT-LICENSE",
    "content": "Copyright (c) 2008 James Adam\n\nThe MIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE."
  },
  {
    "path": "vendor/plugins/engines/README",
    "content": "The engines plugin enhances Rails' own plugin framework, making it simple to share controllers, helpers, models, public assets, routes and migrations in plugins.\n\nFor more information, see http://rails-engines.org\n\n= Using the plugin\n\nOnce you've installed the engines plugin, you'll need to add a single line to the top of config/environment.rb:\n\n  require File.join(File.dirname(__FILE__), '../vendor/plugins/engines/boot')\n  \nYou should add this line just below the require for Rails' own boot.rb file. This will enabled the enhanced plugin loading mechanism automatically for you (i.e. you don't need to set config.plugin_loader manually).\n\nWith that aside, you're now ready to start using more powerful plugins in your application. Read on to find out more about what the engines plugin enables.\n\n\n== Better plugins\n\nIn addition to the regular set of plugin-supported files (lib, init.rb, tasks, generators, tests), plugins can carry the following when the engines plugin is also installed.\n\n\n=== Controllers, Helpers, and Views\n\nInclude these files in an <tt>app</tt> directory just like you would in a normal Rails application. If you need to override a method, view or partial, create the corresponding file in your main <tt>app</tt> directory and it will be used instead.\n\n* Controllers & Helpers: See Engines::RailsExtensions::Dependencies for more information.\n* Views: now handled almost entirely by ActionView itself (see Engines::Plugin#add_plugin_view_paths for more information)\n\n=== Models\n\nModel code can similarly be placed in an <tt>app/models/</tt> directory. Unfortunately, it's not possible to automatically override methods within a model; if your application needs to change the way a model behaves, consider creating a subclass, or replacing the model entirely within your application's <tt>app/models/</tt> directory. See Engines::RailsExtensions::Dependencies for more information.\n\nIMPORTANT NOTE: when you load code from within plugins, it is typically not handled well by Rails in terms of unloading and reloading changes. Look here for more information - http://rails-engines.org/development/common-issues-when-overloading-code-from-plugins/\n\n=== Routes\n\nInclude your route declarations in a <tt>routes.rb</tt> file at the root of your plugins, e.g.:\n\n  connect \"/my/url\", :controller => \"some_controller\"\n  my_named_route \"do_stuff\", :controller => \"blah\", :action => \"stuff\"\n  # etc.\n  \nYou can then load these files into your application by declaring their inclusion in the application's <tt>config/routes.rb</tt>:\n\n  map.from_plugin :plugin_name\n\nSee Engines::RailsExtensions::Routing for more information.\n  \n=== Migrations\n\nMigrations record the changes in your database as your application evolves. With engines 1.2, migrations from plugins can also join in this evolution as first-class entities. To add migrations to a plugin, include a <tt>db/migrate/</tt> folder and add migrations there as normal. These migrations can then be integrated into the main flow of database evolution by running the plugin_migration generator:\n\n  script/generate plugin_migration\n  \nThis will produce a migration in your application. Running this migration (via <tt>rake db:migrate</tt>, as normal) will migrate the database according to the latest migrations in each plugin. See Engines::RailsExtensions::Migrations for more information.\n\n\n=== More powerful Rake tasks\n\nThe engines plugin enhances and adds to the suite of default rake tasks for working with plugins. The <tt>doc:plugins</tt> task now includes controllers, helpers and models under <tt>app</tt>, and anything other code found under the plugin's <tt>code_paths</tt> attribute. New testing tasks have been added to run unit, functional and integration tests from plugins, whilst making it easier to load fixtures from plugins. See Engines::Testing for more details about testing, and run\n\n  rake -T\n  \nto see the set of rake tasks available.\n\n= Testing the engines plugin itself\n\nBecause of the way the engines plugin modifies Rails, the simplest way to consistently test it against multiple versions is by generating a test harness application - a full Rails application that includes tests to verify the engines plugin behaviour in a real, running environment.\n\nRun the tests like this:\n\n  $ cd engines\n  $ rake test\n  \nThis will generate a test_app directory within the engines plugin (using the default 'rails' command), import tests and code into that application and then run the test suite.\n\nIf you wish to test against a specific version of Rails, run the tests with the RAILS environment variable set to the local directory containing your Rails checkout\n\n  $ rake test RAILS=/Users/james/Code/rails_edge_checkout\n  \nAlternatively, you can clone the latest version of Rails ('edge rails') from github like so:\n\n  $ rake test RAILS=edge\n  \n"
  },
  {
    "path": "vendor/plugins/engines/Rakefile",
    "content": "require 'rake'\nrequire 'rake/rdoctask'\nrequire 'tmpdir'\n\ntask :default => :doc\n\ndesc 'Generate documentation for the engines plugin.'\nRake::RDocTask.new(:doc) do |doc|\n  doc.rdoc_dir = 'doc'\n  doc.title    = 'Engines'\n  doc.main     = \"README\"\n  doc.rdoc_files.include(\"README\", \"CHANGELOG\", \"MIT-LICENSE\")\n  doc.rdoc_files.include('lib/**/*.rb')\n  doc.options << '--line-numbers' << '--inline-source'\nend\n\ndesc 'Run the engine plugin tests within their test harness'\ntask :cruise do\n  # checkout the project into a temporary directory\n  version = \"rails_2.0\"\n  test_dir = \"#{Dir.tmpdir}/engines_plugin_#{version}_test\"\n  puts \"Checking out test harness for #{version} into #{test_dir}\"\n  `svn co http://svn.rails-engines.org/test/engines/#{version} #{test_dir}`\n\n  # run all the tests in this project\n  Dir.chdir(test_dir)\n  load 'Rakefile'\n  puts \"Running all tests in test harness\"\n  ['db:migrate', 'test', 'test:plugins'].each do |t|\n    Rake::Task[t].invoke\n  end  \nend\n\ntask :clean => [:clobber_doc, \"test:clean\"]\n\nnamespace :test do\n  \n  # Yields a block with STDOUT and STDERR silenced. If you *really* want\n  # to output something, the block is yielded with the original output\n  # streams, i.e.\n  #\n  #   silence do |o, e|\n  #     puts 'hello!' # no output produced\n  #     o.puts 'hello!' # output on STDOUT\n  #   end\n  #\n  # (based on silence_stream in ActiveSupport.)\n  def silence\n    yield(STDOUT, STDERR) if ENV['VERBOSE']\n    streams = [STDOUT, STDERR]\n    actual_stdout = STDOUT.dup\n    actual_stderr = STDERR.dup\n    streams.each do |s| \n      s.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null') \n      s.sync = true\n    end\n    yield actual_stdout, actual_stderr\n  ensure\n    STDOUT.reopen(actual_stdout)\n    STDERR.reopen(actual_stderr)\n  end\n  \n  def test_app_dir\n    File.join(File.dirname(__FILE__), 'test_app')\n  end\n  \n  def run(cmd)\n    cmd = cmd.join(\" && \") if cmd.is_a?(Array)\n    system(cmd) || raise(\"failed running '#{cmd}'\")\n  end\n  \n  desc 'Remove the test application'\n  task :clean do\n    FileUtils.rm_r(test_app_dir) if File.exist?(test_app_dir)\n  end\n  \n  desc 'Build the test rails application (use RAILS=[edge,<directory>] to test against specific version)'\n  task :generate_app do\n    silence do |out, err|\n      out.puts \"> Creating test application at #{test_app_dir}\"\n        \n      if ENV['RAILS']\n        vendor_dir = File.join(test_app_dir, 'vendor')\n        FileUtils.mkdir_p vendor_dir\n        \n        if ENV['RAILS'] == 'edge'\n          out.puts \"    Cloning Edge Rails from GitHub\"\n          run \"cd #{vendor_dir} && git clone --depth 1 git://github.com/rails/rails.git\"\n        elsif ENV['RAILS'] =~ /\\d\\.\\d\\.\\d/\n          if ENV['CURL']\n            out.puts \"    Cloning Rails Tag #{ENV['RAILS']} from GitHub using curl and tar\"\n            run [\"cd #{vendor_dir}\",\n                 \"mkdir rails\",\n                 \"cd rails\",\n                 \"curl -s -L http://github.com/rails/rails/tarball/#{ENV['RAILS']} | tar xzv --strip-components 1\"]\n          else\n            out.puts \"    Cloning Rails Tag #{ENV['RAILS']} from GitHub (can be slow - set CURL=true to use curl)\"\n            run [\"cd #{vendor_dir}\",\n                 \"git clone git://github.com/rails/rails.git\",\n                 \"cd rails\",\n                 \"git pull\",\n                 \"git checkout v#{ENV['RAILS']}\"]\n          end\n        elsif File.exist?(ENV['RAILS'])\n          out.puts \"    Linking rails from #{ENV['RAILS']}\"\n          run \"cd #{vendor_dir} && ln -s #{ENV['RAILS']} rails\"\n        else\n          raise \"Couldn't build test application from '#{ENV['RAILS']}'\"\n        end\n      \n        out.puts \"    generating rails default directory structure\"\n        run \"ruby #{File.join(vendor_dir, 'rails', 'railties', 'bin', 'rails')} #{test_app_dir}\"\n      else\n        version = `rails --version`.chomp.split.last\n        out.puts \"    building rails using the 'rails' command (rails version: #{version})\"\n        run \"rails #{test_app_dir}\"\n      end\n    \n      # get the database config and schema in place\n      out.puts \"    writing database.yml\"\n      require 'yaml'\n      File.open(File.join(test_app_dir, 'config', 'database.yml'), 'w') do |f|\n        f.write(%w(development test).inject({}) do |h, env| \n          h[env] = {\"adapter\" => \"sqlite3\", \"database\" => \"engines_#{env}.sqlite3\"} ; h\n        end.to_yaml)\n      end\n      out.puts \"    installing exception_notification plugin\"\n      run \"cd #{test_app_dir} && ./script/plugin install git://github.com/rails/exception_notification.git\"\n    end\n  end\n  \n  # We can't link the plugin, as it needs to be present for script/generate to find\n  # the plugin generator.\n  # TODO: find and +1/create issue for loading generators from symlinked plugins\n  desc 'Mirror the engines plugin into the test application'\n  task :copy_engines_plugin do\n    puts \"> Copying engines plugin into test application\"\n    engines_plugin = File.join(test_app_dir, \"vendor\", \"plugins\", \"engines\")\n    FileUtils.rm_r(engines_plugin) if File.exist?(engines_plugin)\n    FileUtils.mkdir_p(engines_plugin)\n    FileList[\"*\"].exclude(\"test_app\").each do |file|\n      FileUtils.cp_r(file, engines_plugin)\n    end\n  end\n  \n  def insert_line(line, options)\n    line = line + \"\\n\"\n    target_file = File.join(test_app_dir, options[:into])\n    lines = File.readlines(target_file)\n    return if lines.include?(line)\n    \n    if options[:after]\n      if options[:after].is_a?(String)\n        after_line = options[:after] + \"\\n\"\n      else\n        after_line = lines.find { |l| l =~ options[:after] }\n        raise \"couldn't find a line matching #{options[:after].inspect} in #{target_file}\" unless after_line\n      end\n      index = lines.index(after_line)\n      raise \"couldn't find line '#{after_line}' in #{target_file}\" unless index\n      lines.insert(index + 1, line)\n    else\n      lines << line\n    end\n    File.open(target_file, 'w') { |f| f.write lines.join }\n  end\n  \n  def mirror_test_files(src, dest=nil)\n    destination_dir = File.join(*([test_app_dir, dest].compact))\n    FileUtils.cp_r(File.join(File.dirname(__FILE__), 'test', src), destination_dir)\n  end\n  \n  desc 'Update the plugin and tests files in the test application from the plugin'\n  task :mirror_engine_files => [:test_app, :copy_engines_plugin] do\n    puts \"> Tweaking generated application to be suitable for testing\"\n    \n    # Replace the Rails plugin loader with the engines one.\n    insert_line(\"require File.join(File.dirname(__FILE__), '../vendor/plugins/engines/boot')\",\n                :into => 'config/environment.rb',\n                :after => \"require File.join(File.dirname(__FILE__), 'boot')\")\n    \n    # Add the engines test helper to handle fixtures & stuff.\n    insert_line(\"require 'engines_test_helper'\", :into => 'test/test_helper.rb')\n    \n    # Run engine plugin tests when running the application \n    insert_line(\"task :test => ['test:engines:all']\", :into => 'Rakefile')\n    \n    # We want exceptions to be raised\n    insert_line(\"def rescue_action(e) raise e end;\", \n                :into => \"app/controllers/application_controller.rb\",\n                :after => \"class ApplicationController < ActionController::Base\")\n    \n    # We need this method to test where actions are being rendered from.\n    insert_line(\"include RenderInformation\", \n                :into => \"app/controllers/application_controller.rb\",\n                :after => \"class ApplicationController < ActionController::Base\")\n    \n    puts \"> Mirroring test application files into #{test_app_dir}\"\n    mirror_test_files('app')\n    mirror_test_files('lib')\n    mirror_test_files('plugins', 'vendor')\n    mirror_test_files('unit', 'test')\n    mirror_test_files('functional', 'test')\n  end\n  \n  desc 'Prepare the engines test environment'\n  task :test_app do\n    version_tag = File.join(test_app_dir, 'RAILS_VERSION')\n    existing_version = File.read(version_tag).chomp rescue 'unknown'\n    if existing_version == ENV['RAILS']\n      puts \"> Reusing existing test application (#{ENV['RAILS']})\"\n    else\n      puts \"> Recreating test application\"\n      Rake::Task[\"test:clean\"].invoke\n      Rake::Task[\"test:generate_app\"].invoke\n      \n      File.open(version_tag, \"w\") { |f| f.write ENV['RAILS'] }\n    end\n  end\nend\n\ntask :test => \"test:mirror_engine_files\" do\n  puts \"> Loading the test application environment and running tests\"\n  # We use exec here to replace the current running rake process\n  exec(\"cd #{test_app_dir} && rake db:migrate && rake\")\nend\n"
  },
  {
    "path": "vendor/plugins/engines/about.yml",
    "content": "author: James Adam\nemail: james.adam@gmail.com\nhomepage: http://www.rails-engines.org\nsummary: Enhances the plugin mechanism to perform more flexible sharing\ndescription: The Rails Engines plugin allows the sharing of almost any type of code or asset that you could use in a Rails application, including controllers, models, stylesheets, and views.\nlicense: MIT\nversion: 2.3.2"
  },
  {
    "path": "vendor/plugins/engines/boot.rb",
    "content": "begin\n  require 'rails/version'\n  unless Rails::VERSION::MAJOR >= 2 && Rails::VERSION::MINOR >= 3 && Rails::VERSION::TINY >= 2\n    raise \"This version of the engines plugin requires Rails 2.3.2 or later!\"\n  end\nend\n\nrequire File.join(File.dirname(__FILE__), 'lib/engines')\n\n# initialize Rails::Configuration with our own default values to spare users \n# some hassle with the installation and keep the environment cleaner\n\n{ :default_plugin_locators => (defined?(Gem) ? [Rails::Plugin::GemLocator] : []).push(Engines::Plugin::FileSystemLocator),\n  :default_plugin_loader => Engines::Plugin::Loader,\n  :default_plugins => [:engines, :all] }.each do |name, default|    \n  Rails::Configuration.send(:define_method, name) { default }\nend"
  },
  {
    "path": "vendor/plugins/engines/generators/plugin_migration/USAGE",
    "content": "Description:\n  The plugin migration generator assists in working with schema additions \n  required by plugins. Instead of running migrations from plugins directly,\n  the generator creates a regular Rails migration which will be responsible\n  for migrating the plugins from their current version to the latest version\n  installed.\n  \n  This is important because the set of application migrations remains an\n  accurate record of the state of the database, even as plugins are installed\n  and removed during the development process.\n\nExample:\n  ./script/generate plugin_migration [<plugin_name> <another_plugin_name> ...]\n\n  This will generate:\n\n    RAILS_ROOT\n      |- db\n          |-migrate\n              |- xxx_plugin_migrations.rb\n\n  which contains the migrations for the given plugin(s).\n  \n  \nAdvanced Usage:\n\nThere may be situations where you need *complete* control over the migrations\nof plugins in your application, migrating a certainly plugin down to X, and\nanother plugin up to Y, where neither X or Y are the latest migrations for those\nplugins.\n\nFor those unfortunate few, I have two pieces of advice:\n\n 1. Why? This is a code smell [http://c2.com/xp/CodeSmell.html].\n \n 2. Well, OK. Don't panic. You can completely control plugin migrations by\n    creating your own migrations. To manually migrate a plugin to a specific\n    version, simply use\n    \n      Engines.plugins[:your_plugin_name].migrate(version)\n      \n    where version is the integer of the migration this plugin should end\n    up at.\n    \nWith great power comes great responsibility. Use this wisely."
  },
  {
    "path": "vendor/plugins/engines/generators/plugin_migration/plugin_migration_generator.rb",
    "content": "# Generates a migration which migrates all plugins to their latest versions\n# within the database.\nclass PluginMigrationGenerator < Rails::Generator::Base\n  \n  # 255 characters max for Windows NTFS (http://en.wikipedia.org/wiki/Filename)\n  # minus 14 for timestamp, minus some extra chars for dot, underscore, file \n  # extension. So let's have 230.\n  MAX_FILENAME_LENGTH = 230\n    \n  def initialize(runtime_args, runtime_options={})\n    super\n    @options = {:assigns => {}}\n    ensure_schema_table_exists    \n    get_plugins_to_migrate(runtime_args)\n    \n    if @plugins_to_migrate.empty?\n      puts \"All plugins are migrated to their latest versions\"\n      exit(0)\n    end\n\n    @options[:migration_file_name] = build_migration_name\n    @options[:assigns][:class_name] = build_migration_name.classify\n  end\n  \n  def manifest\n    record do |m|\n      m.migration_template 'plugin_migration.erb', 'db/migrate', @options\n    end\n  end\n  \n  protected\n\n    # Create the schema table if it doesn't already exist.\n    def ensure_schema_table_exists\n      ActiveRecord::Base.connection.initialize_schema_migrations_table\n    end\n\n    # Determine all the plugins which have migrations that aren't present\n    # according to the plugin schema information from the database.\n    def get_plugins_to_migrate(plugin_names)\n\n      # First, grab all the plugins which exist and have migrations\n      @plugins_to_migrate = if plugin_names.empty?\n        Engines.plugins\n      else\n        plugin_names.map do |name| \n          Engines.plugins[name] ? Engines.plugins[name] : raise(\"Cannot find the plugin '#{name}'\")\n        end\n      end\n      \n      @plugins_to_migrate.reject! { |p| !p.respond_to?(:latest_migration) || p.latest_migration.nil? }\n      \n      # Then find the current versions from the database    \n      @current_versions = {}\n      @plugins_to_migrate.each do |plugin|\n        @current_versions[plugin.name] = Engines::Plugin::Migrator.current_version(plugin)\n      end\n\n      # Then find the latest versions from their migration directories\n      @new_versions = {}      \n      @plugins_to_migrate.each do |plugin|\n        @new_versions[plugin.name] = plugin.latest_migration\n      end\n      \n      # Remove any plugins that don't need migration\n      @plugins_to_migrate.map { |p| p.name }.each do |name|\n        @plugins_to_migrate.delete(Engines.plugins[name]) if @current_versions[name] == @new_versions[name]\n      end\n      \n      @options[:assigns][:plugins] = @plugins_to_migrate\n      @options[:assigns][:new_versions] = @new_versions\n      @options[:assigns][:current_versions] = @current_versions\n    end\n\n    # Returns a migration name. If the descriptive migration name based on the \n    # plugin names involved is shorter than 230 characters that one will be\n    # used. Otherwise a shorter name will be returned.\n    def build_migration_name\n      returning descriptive_migration_name do |name|        \n        name.replace short_migration_name if name.length > MAX_FILENAME_LENGTH\n      end\n    end\n\n    # Construct a unique migration name based on the plugins involved and the\n    # versions they should reach after this migration is run. The name constructed\n    # needs to be lowercase\n    def descriptive_migration_name\n      @plugins_to_migrate.map do |plugin| \n        \"#{plugin.name}_to_version_#{@new_versions[plugin.name]}\" \n      end.join(\"_and_\").downcase\n    end\n\n    # Short migration name that will be used if the descriptive_migration_name\n    # exceeds 230 characters\n    def short_migration_name\n      'plugin_migrations'\n    end\nend"
  },
  {
    "path": "vendor/plugins/engines/generators/plugin_migration/templates/plugin_migration.erb",
    "content": "class <%= class_name %> < ActiveRecord::Migration\n  def self.up\n  <%- plugins.each do |plugin| -%>\n    Engines.plugins[\"<%= plugin.name %>\"].migrate(<%= new_versions[plugin.name] %>)\n  <%- end -%>\n  end\n\n  def self.down\n  <%- plugins.each do |plugin| -%>\n    Engines.plugins[\"<%= plugin.name %>\"].migrate(<%= current_versions[plugin.name] %>)\n  <%- end -%>\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/init.rb",
    "content": "# Only call Engines.init once, in the after_initialize block so that Rails\n# plugin reloading works when turned on\nconfig.after_initialize do\n  Engines.init(initializer) if defined? :Engines\nend"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/assets.rb",
    "content": "module Engines\n  module Assets    \n    class << self      \n      @@readme = %{Files in this directory are automatically generated from your plugins.\nThey are copied from the 'assets' directories of each plugin into this directory\neach time Rails starts (script/server, script/console... and so on).\nAny edits you make will NOT persist across the next server restart; instead you\nshould edit the files within the <plugin_name>/assets/ directory itself.}     \n       \n      # Ensure that the plugin asset subdirectory of RAILS_ROOT/public exists, and\n      # that we've added a little warning message to instruct developers not to mess with\n      # the files inside, since they're automatically generated.\n      def initialize_base_public_directory\n        dir = Engines.public_directory\n        unless File.exist?(dir)\n          FileUtils.mkdir_p(dir)\n        end\n        readme = File.join(dir, \"README\")        \n        File.open(readme, 'w') { |f| f.puts @@readme } unless File.exist?(readme)\n      end\n    \n      # Replicates the subdirectories under the plugins's +assets+ (or +public+) \n      # directory into the corresponding public directory. See also \n      # Plugin#public_directory for more.\n      def mirror_files_for(plugin)\n        return if plugin.public_directory.nil?\n        begin \n          Engines.mirror_files_from(plugin.public_directory, File.join(Engines.public_directory, plugin.name))      \n        rescue Exception => e\n          Engines.logger.warn \"WARNING: Couldn't create the public file structure for plugin '#{plugin.name}'; Error follows:\"\n          Engines.logger.warn e\n        end\n      end\n    end \n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/plugin/list.rb",
    "content": "# The PluginList class is an array, enhanced to allow access to loaded plugins\n# by name, and iteration over loaded plugins in order of priority. This array is used\n# by Engines::RailsExtensions::RailsInitializer to create the Engines.plugins array.\n#\n# Each loaded plugin has a corresponding Plugin instance within this array, and \n# the order the plugins were loaded is reflected in the entries in this array.\n#\n# For more information, see the Rails module.\nmodule Engines\n  class Plugin\n    class List < Array\n      # Finds plugins with the set with the given name (accepts Strings or Symbols), or\n      # index. So, Engines.plugins[0] returns the first-loaded Plugin, and Engines.plugins[:engines]\n      # returns the Plugin instance for the engines plugin itself.\n      def [](name_or_index)\n        if name_or_index.is_a?(Fixnum)\n          super\n        else\n          self.find { |plugin| plugin.name.to_s == name_or_index.to_s }\n        end\n      end\n  \n      # Go through each plugin, highest priority first (last loaded first). Effectively,\n      # this is like <tt>Engines.plugins.reverse</tt>\n      def by_precedence\n        reverse\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/plugin/loader.rb",
    "content": "module Engines\n  class Plugin\n    class Loader < Rails::Plugin::Loader    \n      protected    \n        def register_plugin_as_loaded(plugin)\n          super plugin\n          Engines.plugins << plugin\n        end    \n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/plugin/locator.rb",
    "content": "module Engines\n  class Plugin\n    class FileSystemLocator < Rails::Plugin::FileSystemLocator\n      def create_plugin(path)\n        plugin = Engines::Plugin.new(path)\n        plugin.valid? ? plugin : nil\n      end        \n    end\n  end\nend\n\n"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/plugin/migrator.rb",
    "content": "# The Plugin::Migrator class contains the logic to run migrations from\n# within plugin directories. The directory in which a plugin's migrations\n# should be is determined by the Plugin#migration_directory method.\n#\n# To migrate a plugin, you can simple call the migrate method (Plugin#migrate)\n# with the version number that plugin should be at. The plugin's migrations\n# will then be used to migrate up (or down) to the given version.\n#\n# For more information, see Engines::RailsExtensions::Migrations\nclass Engines::Plugin::Migrator < ActiveRecord::Migrator\n\n  # We need to be able to set the 'current' engine being migrated.\n  cattr_accessor :current_plugin\n\n  class << self\n    # Runs the migrations from a plugin, up (or down) to the version given\n    def migrate_plugin(plugin, version)\n      self.current_plugin = plugin\n      return if current_version(plugin) == version\n      migrate(plugin.migration_directory, version)\n    end\n    \n    def current_version(plugin=current_plugin)\n      # Delete migrations that don't match .. to_i will work because the number comes first\n      ::ActiveRecord::Base.connection.select_values(\n        \"SELECT version FROM #{schema_migrations_table_name}\"\n      ).delete_if{ |v| v.match(/-#{plugin.name}/) == nil }.map(&:to_i).max || 0\n    end\n  end\n       \n  def migrated\n    sm_table = self.class.schema_migrations_table_name\n    ::ActiveRecord::Base.connection.select_values(\n      \"SELECT version FROM #{sm_table}\"\n    ).delete_if{ |v| v.match(/-#{current_plugin.name}/) == nil }.map(&:to_i).sort\n  end\n  \n  def record_version_state_after_migrating(version)\n    super(version.to_s + \"-\" + current_plugin.name)\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/plugin.rb",
    "content": "# An instance of Plugin is created for each plugin loaded by Rails, and\n# stored in the <tt>Engines.plugins</tt> PluginList \n# (see Engines::RailsExtensions::RailsInitializer for more details).\n#\n#   Engines.plugins[:plugin_name]\n#\n# Other properties of the Plugin instance can also be set.\nmodule Engines\n  class Plugin < Rails::Plugin    \n    # Plugins can add paths to this attribute in init.rb if they need\n    # controllers loaded from additional locations. \n    attr_accessor :controller_paths\n  \n    # The directory in this plugin to mirror into the shared directory\n    # under +public+.\n    #\n    # Defaults to \"assets\" (see default_public_directory).\n    attr_accessor :public_directory   \n    \n    protected\n      # The default set of code paths which will be added to the routing system\n      def default_controller_paths\n        %w(app/controllers components)\n      end\n\n      # Attempts to detect the directory to use for public files.\n      # If +assets+ exists in the plugin, this will be used. If +assets+ is missing\n      # but +public+ is found, +public+ will be used.\n      def default_public_directory\n        Engines.select_existing_paths(%w(assets public).map { |p| File.join(directory, p) }).first\n      end\n    \n    public\n  \n    def initialize(directory)\n      super directory\n      @controller_paths = default_controller_paths\n      @public_directory = default_public_directory\n    end\n  \n    # Extends the superclass' load method to additionally mirror public assets\n    def load(initializer)\n      return if loaded?\n      super initializer\n      add_plugin_locale_paths\n      Assets.mirror_files_for(self)\n    end    \n  \n    # select those paths that actually exist in the plugin's directory\n    def select_existing_paths(name)\n      Engines.select_existing_paths(self.send(name).map { |p| File.join(directory, p) })\n    end    \n\n    def add_plugin_locale_paths\n      locale_path = File.join(directory, 'locales')\n      return unless File.exists?(locale_path)\n\n      locale_files = Dir[File.join(locale_path, '*.{rb,yml}')]\n      return if locale_files.blank?\n\n      first_app_element = \n        I18n.load_path.select{ |e| e =~ /^#{ RAILS_ROOT }/ }.reject{ |e| e =~ /^#{ RAILS_ROOT }\\/vendor\\/plugins/ }.first\n      app_index = I18n.load_path.index(first_app_element) || - 1\n\n      I18n.load_path.insert(app_index, *locale_files)\n    end\n\n    # The path to this plugin's public files\n    def public_asset_directory\n      \"#{File.basename(Engines.public_directory)}/#{name}\"\n    end\n    \n    # The directory containing this plugin's migrations (<tt>plugin/db/migrate</tt>)\n    def migration_directory\n      File.join(self.directory, 'db', 'migrate')\n    end\n  \n    # Returns the version number of the latest migration for this plugin. Returns\n    # nil if this plugin has no migrations.\n    def latest_migration\n      migrations.last\n    end\n    \n    # Returns the version numbers of all migrations for this plugin.\n    def migrations\n      migrations = Dir[migration_directory+\"/*.rb\"]\n      migrations.map { |p| File.basename(p).match(/0*(\\d+)\\_/)[1].to_i }.sort\n    end\n    \n    # Migrate this plugin to the given version. See Engines::Plugin::Migrator for more\n    # information.   \n    def migrate(version = nil)\n      Engines::Plugin::Migrator.migrate_plugin(self, version)\n    end\n  end\nend\n\n"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/rails_extensions/asset_helpers.rb",
    "content": "# The engines plugin makes it trivial to share public assets using plugins. \n# To do this, include an <tt>assets</tt> directory within your plugin, and put\n# your javascripts, stylesheets and images in subdirectories of that folder:\n#\n#   my_plugin\n#     |- init.rb\n#     |- lib/\n#     |- assets/\n#          |- javascripts/\n#          |    |- my_functions.js\n#          |\n#          |- stylesheets/\n#          |    |- my_styles.css\n#          |\n#          |- images/\n#               |- my_face.jpg\n#\n# Files within the <tt>asset</tt> structure are automatically mirrored into\n# a publicly-accessible folder each time your application starts (see\n# Engines::Assets#mirror_assets).\n#\n#\n# == Using plugin assets in views\n#\n# It's also simple to use Rails' helpers in your views to use plugin assets.\n# The default helper methods have been enhanced by the engines plugin to accept\n# a <tt>:plugin</tt> option, indicating the plugin containing the desired asset.\n#\n# For example, it's easy to use plugin assets in your layouts:\n#\n#   <%= stylesheet_link_tag \"my_styles\", :plugin => \"my_plugin\", :media => \"screen\" %>\n#   <%= javascript_include_tag \"my_functions\", :plugin => \"my_plugin\" %>\n# \n# ... and similarly in views and partials, it's easy to use plugin images:\n#\n#   <%= image_tag \"my_face\", :plugin => \"my_plugin\" %>\n#   <!-- or -->\n#   <%= image_path \"my_face\", :plugin => \"my_plugin\" %>\n#\n# Where the default helpers allow the specification of more than one file (i.e. the\n# javascript and stylesheet helpers), you can do similarly for multiple assets from \n# within a single plugin.\n#\n# ---\n#\n# This module enhances four of the methods from ActionView::Helpers::AssetTagHelper:\n#\n#  * stylesheet_link_tag\n#  * javascript_include_tag\n#  * image_path\n#  * image_tag\n#\n# Each one of these methods now accepts the key/value pair <tt>:plugin => \"plugin_name\"</tt>,\n# which can be used to specify the originating plugin for any assets.\n#\nmodule Engines::RailsExtensions::AssetHelpers\n  def self.included(base) #:nodoc:\n    base.class_eval do\n      [:stylesheet_link_tag, :javascript_include_tag, :image_path, :image_tag].each do |m|\n        alias_method_chain m, :engine_additions\n      end\n    end\n  end\n\n  # Adds plugin functionality to Rails' default stylesheet_link_tag method.\n  def stylesheet_link_tag_with_engine_additions(*sources)\n    stylesheet_link_tag_without_engine_additions(*Engines::RailsExtensions::AssetHelpers.pluginify_sources(\"stylesheets\", *sources))\n  end\n\n  # Adds plugin functionality to Rails' default javascript_include_tag method.  \n  def javascript_include_tag_with_engine_additions(*sources)\n    javascript_include_tag_without_engine_additions(*Engines::RailsExtensions::AssetHelpers.pluginify_sources(\"javascripts\", *sources))\n  end\n\n  #--\n  # Our modified image_path now takes a 'plugin' option, though it doesn't require it\n  #++\n\n  # Adds plugin functionality to Rails' default image_path method.\n  def image_path_with_engine_additions(source, options={})\n    options.stringify_keys!\n    source = Engines::RailsExtensions::AssetHelpers.plugin_asset_path(options[\"plugin\"], \"images\", source) if options[\"plugin\"]\n    image_path_without_engine_additions(source)\n  end\n\n  # Adds plugin functionality to Rails' default image_tag method.\n  def image_tag_with_engine_additions(source, options={})\n    options.stringify_keys!\n    if options[\"plugin\"]\n      source = Engines::RailsExtensions::AssetHelpers.plugin_asset_path(options[\"plugin\"], \"images\", source)\n      options.delete(\"plugin\")\n    end\n    image_tag_without_engine_additions(source, options)\n  end\n\n  #--\n  # The following are methods on this module directly because of the weird-freaky way\n  # Rails creates the helper instance that views actually get\n  #++\n\n  # Convert sources to the paths for the given plugin, if any plugin option is given\n  def self.pluginify_sources(type, *sources)\n    options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }\n    sources.map! { |s| plugin_asset_path(options[\"plugin\"], type, s) } if options[\"plugin\"]\n    options.delete(\"plugin\") # we don't want it appearing in the HTML\n    sources << options # re-add options      \n  end  \n\n  # Returns the publicly-addressable relative URI for the given asset, type and plugin\n  def self.plugin_asset_path(plugin_name, type, asset)\n    raise \"No plugin called '#{plugin_name}' - please use the full name of a loaded plugin.\" if Engines.plugins[plugin_name].nil?\n    \"/#{Engines.plugins[plugin_name].public_asset_directory}/#{type}/#{asset}\"\n  end\n  \nend\n\nmodule ::ActionView::Helpers::AssetTagHelper #:nodoc:\n  include Engines::RailsExtensions::AssetHelpers\nend"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/rails_extensions/dependencies.rb",
    "content": "# One of the magic features that that engines plugin provides is the ability to\n# override selected methods in controllers and helpers from your application.\n# This is achieved by trapping requests to load those files, and then mixing in\n# code from plugins (in the order the plugins were loaded) before finally loading\n# any versions from the main +app+ directory.\n#\n# The behaviour of this extension is output to the log file for help when\n# debugging.\n#\n# == Example\n#\n# A plugin contains the following controller in <tt>plugin/app/controllers/my_controller.rb</tt>:\n#\n#   class MyController < ApplicationController\n#     def index\n#       @name = \"HAL 9000\"\n#     end\n#     def list\n#       @robots = Robot.find(:all)\n#     end\n#   end\n#\n# In one application that uses this plugin, we decide that the name used in the\n# index action should be \"Robbie\", not \"HAL 9000\". To override this single method,\n# we create the corresponding controller in our application \n# (<tt>RAILS_ROOT/app/controllers/my_controller.rb</tt>), and redefine the method:\n#\n#   class MyController < ApplicationController\n#     def index\n#       @name = \"Robbie\"\n#     end\n#   end\n#\n# The list method remains as it was defined in the plugin controller.\n#\n# The same basic principle applies to helpers, and also views and partials (although\n# view overriding is performed in Engines::RailsExtensions::Templates; see that\n# module for more information).\n#\n# === What about models?\n#\n# Unfortunately, it's not possible to provide this kind of magic for models.\n# The only reason why it's possible for controllers and helpers is because\n# they can be recognised by their filenames (\"whatever_controller\", \"jazz_helper\"),\n# whereas models appear the same as any other typical Ruby library (\"node\",\n# \"user\", \"image\", etc.). \n#\n# If mixing were allowed in models, it would mean code mixing for *every* \n# file that was loaded via +require_or_load+, and this could result in\n# problems where, for example, a Node model might start to include \n# functionality from another file called \"node\" somewhere else in the\n# <tt>$LOAD_PATH</tt>.\n#\n# One way to overcome this is to provide model functionality as a module in\n# a plugin, which developers can then include into their own model\n# implementations.\n#\n# Another option is to provide an abstract model (see the ActiveRecord::Base\n# documentation) and have developers subclass this model in their own\n# application if they must.\n#\n# ---\n#\n# The Engines::RailsExtensions::Dependencies module includes a method to\n# override Dependencies.require_or_load, which is called to load code needed\n# by Rails as it encounters constants that aren't defined.\n#\n# This method is enhanced with the code-mixing features described above.\n#\nmodule Engines::RailsExtensions::Dependencies\n  def self.included(base) #:nodoc:\n    base.class_eval { alias_method_chain :require_or_load, :engine_additions }\n  end\n\n  # Attempt to load the given file from any plugins, as well as the application.\n  # This performs the 'code mixing' magic, allowing application controllers and\n  # helpers to override single methods from those in plugins.\n  # If the file can be found in any plugins, it will be loaded first from those\n  # locations. Finally, the application version is loaded, using Ruby's behaviour\n  # to replace existing methods with their new definitions.\n  #\n  # If <tt>Engines.disable_code_mixing == true</tt>, the first controller/helper on the\n  # <tt>$LOAD_PATH</tt> will be used (plugins' +app+ directories are always lower on the\n  # <tt>$LOAD_PATH</tt> than the main +app+ directory).\n  #\n  # If <tt>Engines.disable_application_code_loading == true</tt>, controllers will\n  # not be loaded from the main +app+ directory *if* they are present in any\n  # plugins.\n  #\n  # Returns true if the file could be loaded (from anywhere); false otherwise -\n  # mirroring the behaviour of +require_or_load+ from Rails (which mirrors\n  # that of Ruby's own +require+, I believe).\n  def require_or_load_with_engine_additions(file_name, const_path=nil)\n    return require_or_load_without_engine_additions(file_name, const_path) if Engines.disable_code_mixing\n\n    file_loaded = false\n\n    # try and load the plugin code first\n    # can't use model, as there's nothing in the name to indicate that the file is a 'model' file\n    # rather than a library or anything else.\n    Engines.code_mixing_file_types.each do |file_type| \n      # if we recognise this type\n      # (this regexp splits out the module/filename from any instances of app/#{type}, so that\n      #  modules are still respected.)\n      if file_name =~ /^(.*app\\/#{file_type}s\\/)+(.*_#{file_type})(\\.rb)?$/\n        base_name = $2\n        # ... go through the plugins from first started to last, so that\n        # code with a high precedence (started later) will override lower precedence\n        # implementations\n        Engines.plugins.each do |plugin|\n          plugin_file_name = File.expand_path(File.join(plugin.directory, 'app', \"#{file_type}s\", base_name))\n          if File.file?(\"#{plugin_file_name}.rb\")\n            file_loaded = true if require_or_load_without_engine_additions(plugin_file_name, const_path)\n          end\n        end\n    \n        # finally, load any application-specific controller classes using the 'proper'\n        # rails load mechanism, EXCEPT when we're testing engines and could load this file\n        # from an engine\n        unless Engines.disable_application_code_loading\n          # Ensure we are only loading from the /app directory at this point\n          app_file_name = File.join(RAILS_ROOT, 'app', \"#{file_type}s\", \"#{base_name}\")\n          if File.file?(\"#{app_file_name}.rb\")\n            file_loaded = true if require_or_load_without_engine_additions(app_file_name, const_path)\n          end\n        end        \n      end \n    end\n\n    # if we managed to load a file, return true. If not, default to the original method.\n    # Note that this relies on the RHS of a boolean || not to be evaluated if the LHS is true.\n    file_loaded || require_or_load_without_engine_additions(file_name, const_path)\n  end  \nend\n\nmodule ActiveSupport::Dependencies #:nodoc:\n  include Engines::RailsExtensions::Dependencies\nend\n"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/rails_extensions/form_tag_helpers.rb",
    "content": "# == Using plugin assets for form tag helpers\n#\n# It's as easy to use plugin images for image_submit_tag using Engines as it is for image_tag:\n#\n#   <%= image_submit_tag \"my_face\", :plugin => \"my_plugin\" %>\n#\n# ---\n#\n# This module enhances one of the methods from ActionView::Helpers::FormTagHelper:\n#\n#  * image_submit_tag\n#\n# This method now accepts the key/value pair <tt>:plugin => \"plugin_name\"</tt>,\n# which can be used to specify the originating plugin for any assets.\n#\nmodule Engines::RailsExtensions::FormTagHelpers\n\tdef self.included(base)\n\t\tbase.class_eval do\n\t\t\talias_method_chain :image_submit_tag, :engine_additions\n\t\tend\n\tend\n\t\n\t# Adds plugin functionality to Rails' default image_submit_tag method.\n\tdef image_submit_tag_with_engine_additions(source, options={})\n\t\toptions.stringify_keys!\n\t\tif options[\"plugin\"]\n\t\t\tsource = Engines::RailsExtensions::AssetHelpers.plugin_asset_path(options[\"plugin\"], \"images\", source)\n\t\t\toptions.delete(\"plugin\")\n\t\tend\n\t\timage_submit_tag_without_engine_additions(source, options)\n\tend\nend\n\nmodule ::ActionView::Helpers::FormTagHelper #:nodoc:\n  include Engines::RailsExtensions::FormTagHelpers\nend\n\n"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/rails_extensions/migrations.rb",
    "content": "# Contains the enhancements to Rails' migrations system to support the \n# Engines::Plugin::Migrator. See Engines::RailsExtensions::Migrations for more\n# information.\n\nrequire \"engines/plugin/migrator\"\n\n# = Plugins and Migrations: Background\n#\n# Rails uses migrations to describe changes to the databases as your application\n# evolves. Each change to your application - adding and removing models, most\n# commonly - might require tweaks to your schema in the form of new tables, or new\n# columns on existing tables, or possibly the removal of tables or columns. Migrations\n# can even include arbitrary code to *transform* data as the underlying schema\n# changes.\n# \n# The point is that at any particular stage in your application's development, \n# migrations serve to transform the database into a state where it is compatible\n# and appropriate at that time.\n# \n# == What about plugins?\n# \n# If you want to share models using plugins, chances are that you might also\n# want to include the corresponding migrations to create tables for those models.\n# With the engines plugin installed, plugins can carry migration data easily:\n# \n#   vendor/\n#     |\n#     plugins/\n#       |\n#       my_plugin/\n#         |- init.rb\n#         |- lib/\n#         |- db/\n#             |-migrate/\n#                 |- 20081105123419_add_some_new_feature.rb\n#                 |- 20081107144959_and_something_else.rb\n#                 |- ...\n# \n# When you install a plugin which contains migrations, you are undertaking a\n# further step in the development of your application, the same as the addition\n# of any other code. With this in mind, you may want to 'roll back' the\n# installation of this plugin at some point, and the database should be able\n# to migrate back to the point without this plugin in it too.\n#\n# == An example\n#\n# For example, our current application is at version 20081106164503 (according to the\n# +schema_migrations+ table), when we decide that we want to add a tagging plugin. The\n# tagging plugin chosen includes migrations to create the tables it requires\n# (say, _tags_ and _taggings_, for instance), along with the models and helpers\n# one might expect.\n#\n# After installing this plugin, these tables should be created in our database.\n# Rather than running the migrations directly from the plugin, they should be\n# integrated into our main migration stream in order to accurately reflect the\n# state of our application's database *at this moment in time*.\n#\n#   $ script/generate plugin_migration\n#         exists  db/migrate\n#         create  db/migrate/20081108120415_my_plugin_to_version_20081107144959.rb\n#\n# This migration will take our application to version 20081108120415, and contains the \n# following, typical migration code:\n# \n#   class TaggingToVersion20081107144959 < ActiveRecord::Migration\n#     def self.up\n#       Engines.plugins[:tagging].migrate(20081107144959)\n#     end\n#     def self.down\n#       Engines.plugins[:tagging].migrate(0)\n#     end\n#   end\n#\n# When we migrate our application up, using <tt>rake db:migrate</tt> as normal,\n# the plugin will be migrated up to its latest version (20081108120415 in this example). If we\n# ever decide to migrate the application back to the state it was in at version 20081106164503,\n# the plugin migrations will be taken back down to version 0 (which, typically,\n# would remove all tables the plugin migrations define).\n#\n# == Upgrading plugins\n#\n# It might happen that later in an application's life, we update to a new version of\n# the tagging plugin which requires some changes to our database. The tagging plugin\n# provides these changes in the form of its own migrations. \n#\n# In this case, we just need to re-run the plugin_migration generator to create a \n# new migration from the current revision to the newest one:\n#\n#   $ script/generate plugin_migration\n#        exists db/migrate\n#        create db/migrate/20081210131437_tagging_to_version_20081201172034.rb\n#\n# The contents of this migration are:\n#\n#   class TaggingToVersion20081108120415 < ActiveRecord::Migration\n#     def self.up\n#       Engines.plugins[:tagging].migrate(20081201172034)\n#     end\n#     def self.down\n#       Engines.plugins[:tagging].migrate(20081107144959)\n#     end\n#   end\n#\n# Notice that if we were to migrate down to revision 20081108120415 or lower, the tagging plugin\n# will be migrated back down to version 20081107144959 - the version we were previously at.\n#\n#\n# = Creating migrations in plugins\n#\n# In order to use the plugin migration functionality that engines provides, a plugin \n# only needs to provide regular migrations in a <tt>db/migrate</tt> folder within it.\n#\n# = Explicitly migrating plugins\n#\n# It's possible to migrate plugins within your own migrations, or any other code.\n# Simply get the Plugin instance, and its Plugin#migrate method with the version\n# you wish to end up at:\n#\n#   Engines.plugins[:whatever].migrate(version)\n#\n#\n# = Upgrading from previous versions of the engines plugin\n#\n# Thanks to the tireless work of the plugin developer community, we can now relying on the migration \n# mechanism in Rails 2.1+ to do much of the plugin migration work for us. This also means that we\n# don't need a seperate schema_info table for plugins.\n#\n# To update your application, run\n#\n#   rake db:migrate:upgrade_plugin_migrations\n#\n# This will ensure that migration information is carried over into the main schema_migrations table.\n# "
  },
  {
    "path": "vendor/plugins/engines/lib/engines/rails_extensions/rails.rb",
    "content": "# This is only here to allow for backwards compability with Engines that\n# have been implemented based on Engines for Rails 1.2. It is preferred that\n# the plugin list be accessed via Engines.plugins.\n\nmodule Rails\n  # Returns the Engines::Plugin::List from Engines.plugins. It is preferable to\n  # access Engines.plugins directly.\n  def self.plugins\n    Engines.plugins\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/tasks/engines.rake",
    "content": "# This code lets us redefine existing Rake tasks, which is extremely\n# handy for modifying existing Rails rake tasks.\n# Credit for the original snippet of code goes to Jeremy Kemper\n# http://pastie.caboo.se/9620\nunless Rake::TaskManager.methods.include?('redefine_task')\n  module Rake\n    module TaskManager\n      def redefine_task(task_class, args, &block)\n        task_name, arg_names, deps = resolve_args([args])\n        task_name = task_class.scope_name(@scope, task_name)\n        deps = [deps] unless deps.respond_to?(:to_ary)\n        deps = deps.collect {|d| d.to_s }\n        task = @tasks[task_name.to_s] = task_class.new(task_name, self)\n        task.application = self\n        task.add_description(@last_description)\n        @last_description = nil\n        task.enhance(deps, &block)\n        task\n      end\n      \n    end\n    class Task\n      class << self\n        def redefine_task(args, &block)\n          Rake.application.redefine_task(self, [args], &block)\n        end\n      end\n    end\n  end\nend\n\nnamespace :db do\n  namespace :migrate do\n    desc 'Migrate database and plugins to current status.'\n    task :all => [ 'db:migrate', 'db:migrate:plugins' ]\n    \n    desc 'Migrate plugins to current status.'\n    task :plugins => :environment do\n      Engines.plugins.each do |plugin|\n        next unless plugin.respond_to?(:migration_directory)\n        next unless File.exists? plugin.migration_directory\n        puts \"Migrating plugin #{plugin.name} ...\"\n        plugin.migrate\n      end\n    end\n\n    desc 'For engines coming from Rails version < 2.0 or for those previously updated to work with Sven Fuch\\'s fork of engines, you need to upgrade the schema info table'\n    task :upgrade_plugin_migrations => :environment do\n      svens_fork_table_name = 'plugin_schema_migrations'\n      \n      # Check if app was previously using Sven's fork\n      if ActiveRecord::Base.connection.table_exists?(svens_fork_table_name)\n        old_sm_table = svens_fork_table_name\n      else\n        old_sm_table = ActiveRecord::Migrator.proper_table_name(Engines.schema_info_table)\n      end\n      \n      unless ActiveRecord::Base.connection.table_exists?(old_sm_table)\n        abort \"Cannot find old migration table - assuming nothing needs to be done\"\n      end\n      \n      # There are two forms of the engines schema info - pre-fix_plugin_migrations and post\n      # We need to figure this out before we continue.\n      \n      results = ActiveRecord::Base.connection.select_rows(\n        \"SELECT version, plugin_name FROM #{old_sm_table}\"\n      ).uniq\n      \n      def insert_new_version(plugin_name, version)\n        version_string = \"#{version}-#{plugin_name}\"\n        new_sm_table = ActiveRecord::Migrator.schema_migrations_table_name\n        \n        # Check if the row already exists for some reason - maybe run this task more than once.\n        return if ActiveRecord::Base.connection.select_rows(\"SELECT * FROM #{new_sm_table} WHERE version = #{version_string.dump.gsub(\"\\\"\", \"'\")}\").size > 0\n        \n        puts \"Inserting new version #{version} for plugin #{plugin_name}..\"\n        ActiveRecord::Base.connection.insert(\"INSERT INTO #{new_sm_table} (version) VALUES (#{version_string.dump.gsub(\"\\\"\", \"'\")})\")\n      end\n      \n      # We need to figure out if they already used \"fix_plugin_migrations\"\n      versions = {}\n      results.each do |r|\n        versions[r[1]] ||= []\n        versions[r[1]] << r[0].to_i\n      end\n      \n      if versions.values.find{ |v| v.size > 1 } == nil\n        puts \"Fixing migration info\"\n        # We only have one listed migration per plugin - this is pre-fix_plugin_migrations,\n        # so we build all versions required. In this case, all migrations should \n        versions.each do |plugin_name, version|\n          version = version[0] # There is only one version\n          \n          # We have to make an assumption that numeric migrations won't get this long..\n          # I'm not sure if there is a better assumption, it should work in all\n          # current cases.. (touch wood..)\n          if version.to_s.size < \"YYYYMMDDHHMMSS\".size\n            # Insert version records for each migration\n            (1..version).each do |v|\n             insert_new_version(plugin_name, v)\n            end\n          else\n            # If the plugin is new-format \"YYYYMMDDHHMMSS\", we just copy it across... \n            # The case in which this occurs is very rare..\n            insert_new_version(plugin_name, version)\n          end\n        end\n      else\n        puts \"Moving migration info\"\n        # We have multiple migrations listed per plugin - thus we can assume they have\n        # already applied fix_plugin_migrations - we just copy it across verbatim\n        versions.each do |plugin_name, version|\n          version.each { |v| insert_new_version(plugin_name, v) }\n        end\n      end\n      \n      puts \"Migration info successfully migrated - removing old schema info table\"\n      ActiveRecord::Base.connection.drop_table(old_sm_table)\n    end\n    \n    desc 'Migrate a specified plugin.'\n    task(:plugin => :environment) do\n      name = ENV['NAME']\n      if plugin = Engines.plugins[name]\n        version = ENV['VERSION']\n        puts \"Migrating #{plugin.name} to \" + (version ? \"version #{version}\" : 'latest version') + \" ...\"\n        plugin.migrate(version ? version.to_i : nil)\n      else\n        puts \"Plugin #{name} does not exist.\"\n      end\n    end\n  end\nend\n\n\nnamespace :db do  \n  namespace :fixtures do\n    namespace :plugins do\n      \n      desc \"Load plugin fixtures into the current environment's database.\"\n      task :load => :environment do\n        require 'active_record/fixtures'\n        ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)\n        Dir.glob(File.join(RAILS_ROOT, 'vendor', 'plugins', ENV['PLUGIN'] || '**', \n                 'test', 'fixtures', '*.yml')).each do |fixture_file|\n          Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*'))\n        end\n      end\n      \n    end\n  end\nend\n\n# this is just a modification of the original task in railties/lib/tasks/documentation.rake, \n# because the default task doesn't support subdirectories like <plugin>/app or\n# <plugin>/component. These tasks now include every file under a plugin's load paths (see\n# Plugin#load_paths).\nnamespace :doc do\n\n  plugins = FileList['vendor/plugins/**'].collect { |plugin| File.basename(plugin) }\n\n  namespace :plugins do\n\n    # Define doc tasks for each plugin\n    plugins.each do |plugin|\n      desc \"Create plugin documentation for '#{plugin}'\"\n      Rake::Task.redefine_task(plugin => :environment) do\n        plugin_base   = RAILS_ROOT + \"/vendor/plugins/#{plugin}\"\n        options       = []\n        files         = Rake::FileList.new\n        options << \"-o doc/plugins/#{plugin}\"\n        options << \"--title '#{plugin.titlecase} Plugin Documentation'\"\n        options << '--line-numbers' << '--inline-source'\n        options << '-T html'\n\n        # Include every file in the plugin's load_paths (see Plugin#load_paths)\n        if Engines.plugins[plugin]\n          files.include(\"#{plugin_base}/{#{Engines.plugins[plugin].load_paths.join(\",\")}}/**/*.rb\")\n        end\n        if File.exists?(\"#{plugin_base}/README\")\n          files.include(\"#{plugin_base}/README\")    \n          options << \"--main '#{plugin_base}/README'\"\n        end\n        files.include(\"#{plugin_base}/CHANGELOG\") if File.exists?(\"#{plugin_base}/CHANGELOG\")\n\n        if files.empty?\n          puts \"No source files found in #{plugin_base}. No documentation will be generated.\"\n        else\n          options << files.to_s\n          sh %(rdoc #{options * ' '})\n        end\n      end\n    end\n  end\nend\n\n\n\nnamespace :test do\n  task :warn_about_multiple_plugin_testing_with_engines do\n    puts %{-~============== A Moste Polite Warninge ===========================~-\n\nYou may experience issues testing multiple plugins at once when using\nthe code-mixing features that the engines plugin provides. If you do\nexperience any problems, please test plugins individually, i.e.\n\n  $ rake test:plugins PLUGIN=my_plugin\n\nor use the per-type plugin test tasks:\n\n  $ rake test:plugins:units\n  $ rake test:plugins:functionals\n  $ rake test:plugins:integration\n  $ rake test:plugins:all\n\nReport any issues on http://dev.rails-engines.org. Thanks!\n\n-~===============( ... as you were ... )============================~-}\n  end\n  \n  namespace :engines do\n    \n    def engine_plugins\n      Dir[\"vendor/plugins/*\"].select { |f| File.directory?(File.join(f, \"app\")) }.map { |f| File.basename(f) }.join(\",\")\n    end\n    \n    desc \"Run tests from within engines plugins (plugins with an 'app' directory)\"\n    task :all => [:units, :functionals, :integration]\n    \n    desc \"Run unit tests from within engines plugins (plugins with an 'app' directory)\"\n    Rake::TestTask.new(:units => \"test:plugins:setup_plugin_fixtures\") do |t|\n      t.pattern = \"vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/unit/**/*_test.rb\"\n      t.verbose = true\n    end\n\n    desc \"Run functional tests from within engines plugins (plugins with an 'app' directory)\"\n    Rake::TestTask.new(:functionals => \"test:plugins:setup_plugin_fixtures\") do |t|\n      t.pattern = \"vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/functional/**/*_test.rb\"\n      t.verbose = true\n    end\n\n    desc \"Run integration tests from within engines plugins (plugins with an 'app' directory)\"\n    Rake::TestTask.new(:integration => \"test:plugins:setup_plugin_fixtures\") do |t|\n      t.pattern = \"vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/integration/**/*_test.rb\"\n      t.verbose = true\n    end\n  end\n  \n  namespace :plugins do\n\n    desc \"Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name)\"\n    task :all => [:warn_about_multiple_plugin_testing_with_engines, \n                  :units, :functionals, :integration]\n    \n    desc \"Run all plugin unit tests\"\n    Rake::TestTask.new(:units => :setup_plugin_fixtures) do |t|\n      t.pattern = \"vendor/plugins/#{ENV['PLUGIN'] || \"**\"}/test/unit/**/*_test.rb\"\n      t.verbose = true\n    end\n    \n    desc \"Run all plugin functional tests\"\n    Rake::TestTask.new(:functionals => :setup_plugin_fixtures) do |t|\n      t.pattern = \"vendor/plugins/#{ENV['PLUGIN'] || \"**\"}/test/functional/**/*_test.rb\"\n      t.verbose = true\n    end\n    \n    desc \"Integration test engines\"\n    Rake::TestTask.new(:integration => :setup_plugin_fixtures) do |t|\n      t.pattern = \"vendor/plugins/#{ENV['PLUGIN'] || \"**\"}/test/integration/**/*_test.rb\"\n      t.verbose = true\n    end\n\n    desc \"Mirrors plugin fixtures into a single location to help plugin tests\"\n    task :setup_plugin_fixtures => :environment do\n      Engines::Testing.setup_plugin_fixtures\n    end\n    \n    # Patch the default plugin testing task to have setup_plugin_fixtures as a prerequisite\n    Rake::Task[\"test:plugins\"].prerequisites << \"test:plugins:setup_plugin_fixtures\"\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/tasks/engines.rake~HEAD",
    "content": "# This code lets us redefine existing Rake tasks, which is extremely\n# handy for modifying existing Rails rake tasks.\n# Credit for the original snippet of code goes to Jeremy Kemper\n# http://pastie.caboo.se/9620\nunless Rake::TaskManager.methods.include?('redefine_task')\n  module Rake\n    module TaskManager\n      def redefine_task(task_class, args, &block)\n        task_name, arg_names, deps = resolve_args([args])\n        task_name = task_class.scope_name(@scope, task_name)\n        deps = [deps] unless deps.respond_to?(:to_ary)\n        deps = deps.collect {|d| d.to_s }\n        task = @tasks[task_name.to_s] = task_class.new(task_name, self)\n        task.application = self\n        task.add_description(@last_description)\n        @last_description = nil\n        task.enhance(deps, &block)\n        task\n      end\n      \n    end\n    class Task\n      class << self\n        def redefine_task(args, &block)\n          Rake.application.redefine_task(self, [args], &block)\n        end\n      end\n    end\n  end\nend\n\nnamespace :db do\n  namespace :migrate do\n    desc 'Migrate database and plugins to current status.'\n    task :all => [ 'db:migrate', 'db:migrate:plugins' ]\n    \n    desc 'Migrate plugins to current status.'\n    task :plugins => :environment do\n      Engines.plugins.each do |plugin|\n        next unless plugin.respond_to?(:migration_directory)\n        next unless File.exists? plugin.migration_directory\n        puts \"Migrating plugin #{plugin.name} ...\"\n        plugin.migrate\n      end\n    end\n\n    desc 'For engines coming from Rails version < 2.0 or for those previously updated to work with Sven Fuch\\'s fork of engines, you need to upgrade the schema info table'\n    task :upgrade_plugin_migrations => :environment do\n      svens_fork_table_name = 'plugin_schema_migrations'\n      \n      # Check if app was previously using Sven's fork\n      if ActiveRecord::Base.connection.table_exists?(svens_fork_table_name)\n        old_sm_table = svens_fork_table_name\n      else\n        old_sm_table = ActiveRecord::Migrator.proper_table_name(Engines.schema_info_table)\n      end\n      \n      unless ActiveRecord::Base.connection.table_exists?(old_sm_table)\n        abort \"Cannot find old migration table - assuming nothing needs to be done\"\n      end\n      \n      # There are two forms of the engines schema info - pre-fix_plugin_migrations and post\n      # We need to figure this out before we continue.\n      \n      results = ActiveRecord::Base.connection.select_rows(\n        \"SELECT version, plugin_name FROM #{old_sm_table}\"\n      ).uniq\n      \n      def insert_new_version(plugin_name, version)\n        version_string = \"#{version}-#{plugin_name}\"\n        new_sm_table = ActiveRecord::Migrator.schema_migrations_table_name\n        \n        # Check if the row already exists for some reason - maybe run this task more than once.\n        return if ActiveRecord::Base.connection.select_rows(\"SELECT * FROM #{new_sm_table} WHERE version = #{version_string.dump.gsub(\"\\\"\", \"'\")}\").size > 0\n        \n        puts \"Inserting new version #{version} for plugin #{plugin_name}..\"\n        ActiveRecord::Base.connection.insert(\"INSERT INTO #{new_sm_table} (version) VALUES (#{version_string.dump.gsub(\"\\\"\", \"'\")})\")\n      end\n      \n      # We need to figure out if they already used \"fix_plugin_migrations\"\n      versions = {}\n      results.each do |r|\n        versions[r[1]] ||= []\n        versions[r[1]] << r[0].to_i\n      end\n      \n      if versions.values.find{ |v| v.size > 1 } == nil\n        puts \"Fixing migration info\"\n        # We only have one listed migration per plugin - this is pre-fix_plugin_migrations,\n        # so we build all versions required. In this case, all migrations should \n        versions.each do |plugin_name, version|\n          version = version[0] # There is only one version\n          \n          # We have to make an assumption that numeric migrations won't get this long..\n          # I'm not sure if there is a better assumption, it should work in all\n          # current cases.. (touch wood..)\n          if version.to_s.size < \"YYYYMMDDHHMMSS\".size\n            # Insert version records for each migration\n            (1..version).each do |v|\n             insert_new_version(plugin_name, v)\n            end\n          else\n            # If the plugin is new-format \"YYYYMMDDHHMMSS\", we just copy it across... \n            # The case in which this occurs is very rare..\n            insert_new_version(plugin_name, version)\n          end\n        end\n      else\n        puts \"Moving migration info\"\n        # We have multiple migrations listed per plugin - thus we can assume they have\n        # already applied fix_plugin_migrations - we just copy it across verbatim\n        versions.each do |plugin_name, version|\n          version.each { |v| insert_new_version(plugin_name, v) }\n        end\n      end\n      \n      puts \"Migration info successfully migrated - removing old schema info table\"\n      ActiveRecord::Base.connection.drop_table(old_sm_table)\n    end\n    \n    desc 'Migrate a specified plugin.'\n    task(:plugin => :environment) do\n      name = ENV['NAME']\n      if plugin = Engines.plugins[name]\n        version = ENV['VERSION']\n        puts \"Migrating #{plugin.name} to \" + (version ? \"version #{version}\" : 'latest version') + \" ...\"\n        plugin.migrate(version ? version.to_i : nil)\n      else\n        puts \"Plugin #{name} does not exist.\"\n      end\n    end\n  end\nend\n\n\nnamespace :db do  \n  namespace :fixtures do\n    namespace :plugins do\n      \n      desc \"Load plugin fixtures into the current environment's database.\"\n      task :load => :environment do\n        require 'active_record/fixtures'\n        ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)\n        Dir.glob(File.join(RAILS_ROOT, 'vendor', 'plugins', ENV['PLUGIN'] || '**', \n                 'test', 'fixtures', '*.yml')).each do |fixture_file|\n          Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*'))\n        end\n      end\n      \n    end\n  end\nend\n\n# this is just a modification of the original task in railties/lib/tasks/documentation.rake, \n# because the default task doesn't support subdirectories like <plugin>/app or\n# <plugin>/component. These tasks now include every file under a plugin's load paths (see\n# Plugin#load_paths).\nnamespace :doc do\n\n  plugins = FileList['vendor/plugins/**'].collect { |plugin| File.basename(plugin) }\n\n  namespace :plugins do\n\n    # Define doc tasks for each plugin\n    plugins.each do |plugin|\n      desc \"Create plugin documentation for '#{plugin}'\"\n      Rake::Task.redefine_task(plugin => :environment) do\n        plugin_base   = RAILS_ROOT + \"/vendor/plugins/#{plugin}\"\n        options       = []\n        files         = Rake::FileList.new\n        options << \"-o doc/plugins/#{plugin}\"\n        options << \"--title '#{plugin.titlecase} Plugin Documentation'\"\n        options << '--line-numbers' << '--inline-source'\n        options << '-T html'\n\n        # Include every file in the plugin's load_paths (see Plugin#load_paths)\n        if Engines.plugins[plugin]\n          files.include(\"#{plugin_base}/{#{Engines.plugins[plugin].load_paths.join(\",\")}}/**/*.rb\")\n        end\n        if File.exists?(\"#{plugin_base}/README\")\n          files.include(\"#{plugin_base}/README\")    \n          options << \"--main '#{plugin_base}/README'\"\n        end\n        files.include(\"#{plugin_base}/CHANGELOG\") if File.exists?(\"#{plugin_base}/CHANGELOG\")\n\n        if files.empty?\n          puts \"No source files found in #{plugin_base}. No documentation will be generated.\"\n        else\n          options << files.to_s\n          sh %(rdoc #{options * ' '})\n        end\n      end\n    end\n  end\nend\n\n\n\nnamespace :test do\n  task :warn_about_multiple_plugin_testing_with_engines do\n    puts %{-~============== A Moste Polite Warninge ===========================~-\n\nYou may experience issues testing multiple plugins at once when using\nthe code-mixing features that the engines plugin provides. If you do\nexperience any problems, please test plugins individually, i.e.\n\n  $ rake test:plugins PLUGIN=my_plugin\n\nor use the per-type plugin test tasks:\n\n  $ rake test:plugins:units\n  $ rake test:plugins:functionals\n  $ rake test:plugins:integration\n  $ rake test:plugins:all\n\nReport any issues on http://dev.rails-engines.org. Thanks!\n\n-~===============( ... as you were ... )============================~-}\n  end\n  \n  namespace :engines do\n    \n    def engine_plugins\n      Dir[\"vendor/plugins/*\"].select { |f| File.directory?(File.join(f, \"app\")) }.map { |f| File.basename(f) }.join(\",\")\n    end\n    \n    desc \"Run tests from within engines plugins (plugins with an 'app' directory)\"\n    task :all => [:units, :functionals, :integration]\n    \n    desc \"Run unit tests from within engines plugins (plugins with an 'app' directory)\"\n    Rake::TestTask.new(:units => \"test:plugins:setup_plugin_fixtures\") do |t|\n      t.pattern = \"vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/unit/**/*_test.rb\"\n      t.verbose = true\n    end\n\n    desc \"Run functional tests from within engines plugins (plugins with an 'app' directory)\"\n    Rake::TestTask.new(:functionals => \"test:plugins:setup_plugin_fixtures\") do |t|\n      t.pattern = \"vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/functional/**/*_test.rb\"\n      t.verbose = true\n    end\n\n    desc \"Run integration tests from within engines plugins (plugins with an 'app' directory)\"\n    Rake::TestTask.new(:integration => \"test:plugins:setup_plugin_fixtures\") do |t|\n      t.pattern = \"vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/integration/**/*_test.rb\"\n      t.verbose = true\n    end\n  end\n  \n  namespace :plugins do\n\n    desc \"Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name)\"\n    task :all => [:warn_about_multiple_plugin_testing_with_engines, \n                  :units, :functionals, :integration]\n    \n    desc \"Run all plugin unit tests\"\n    Rake::TestTask.new(:units => :setup_plugin_fixtures) do |t|\n      t.pattern = \"vendor/plugins/#{ENV['PLUGIN'] || \"**\"}/test/unit/**/*_test.rb\"\n      t.verbose = true\n    end\n    \n    desc \"Run all plugin functional tests\"\n    Rake::TestTask.new(:functionals => :setup_plugin_fixtures) do |t|\n      t.pattern = \"vendor/plugins/#{ENV['PLUGIN'] || \"**\"}/test/functional/**/*_test.rb\"\n      t.verbose = true\n    end\n    \n    desc \"Integration test engines\"\n    Rake::TestTask.new(:integration => :setup_plugin_fixtures) do |t|\n      t.pattern = \"vendor/plugins/#{ENV['PLUGIN'] || \"**\"}/test/integration/**/*_test.rb\"\n      t.verbose = true\n    end\n\n    desc \"Mirrors plugin fixtures into a single location to help plugin tests\"\n    task :setup_plugin_fixtures => :environment do\n      Engines::Testing.setup_plugin_fixtures\n    end\n    \n    # Patch the default plugin testing task to have setup_plugin_fixtures as a prerequisite\n    Rake::Task[\"test:plugins\"].prerequisites << \"test:plugins:setup_plugin_fixtures\"\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/lib/engines/testing.rb",
    "content": "# Contains the enhancements to assist in testing plugins. See Engines::Testing\n# for more details.\n\nrequire 'test/unit'\n\nrequire 'tmpdir'\nrequire 'fileutils'\n\n# In most cases, Rails' own plugin testing mechanisms are sufficient. However, there\n# are cases where plugins can be given a helping hand in the testing arena. This module \n# contains some methods to assist when testing plugins that contain fixtures.\n# \n# == Fixtures and plugins\n#\n# Since Rails' own fixtures method is fairly strict about where files can be loaded from,\n# the simplest approach when running plugin tests with fixtures is to simply copy all\n# fixtures into a single temporary location and inform the standard Rails mechanism to\n# use this directory, rather than RAILS_ROOT/test/fixtures.\n#\n# The Engines::Testing#setup_plugin_fixtures method does this, copying all plugin fixtures\n# into the temporary location before and tests are performed. This behaviour is invoked\n# the the rake tasks provided by the Engines plugin, in the \"test:plugins\" namespace. If\n# necessary, you can invoke the task manually.\n#\n# If you wish to take advantage of this, add a call to the Engines::Testing.set_fixture_path\n# method somewhere before your tests (in a test_helper file, or above the TestCase itself).\n#\n# = Testing plugins\n#\n# Normally testing a plugin will require that Rails is loaded, unless you are including\n# a skeleton Rails environment or set of mocks within your plugin tests. If you require\n# the Rails environment to be started, you must ensure that this actually happens; while\n# it's not obvious, your tests do not automatically run with Rails loaded.\n#\n# The simplest way to setup plugin tests is to include a test helper with the following\n# contents:\n#\n#   # Load the normal Rails helper. This ensures the environment is loaded\n#   require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')\n#   # Ensure that we are using the temporary fixture path\n#   Engines::Testing.set_fixture_path\n#\n# Then run tests using the provided tasks (<tt>test:plugins</tt>, or the tasks that the engines\n# plugin provides - <tt>test:plugins:units</tt>, etc.).\n#\n# Alternatively, you can explicitly load the environment by adpating the contents of the\n# default <tt>test_helper</tt>:\n#\n#   ENV[\"RAILS_ENV\"] = \"test\"\n#   # Note that we are requiring config/environment from the root of the enclosing application.\n#   require File.expand_path(File.dirname(__FILE__) + \"/../../../../config/environment\")\n#   require 'test_help'\n#\nmodule Engines::Testing\n  mattr_accessor :temporary_fixtures_directory\n  self.temporary_fixtures_directory = FileUtils.mkdir_p(File.join(Dir.tmpdir, \"rails_fixtures\"))\n  \n  # Copies fixtures from plugins and the application into a temporary directory \n  # (Engines::Testing.temporary_fixtures_directory). \n  # \n  # If a set of plugins is not given, fixtures are copied from all plugins in order \n  # of precedence, meaning that plugins can 'overwrite' the fixtures of others if they are \n  # loaded later; the application's fixtures are copied last, allowing any custom fixtures\n  # to override those in the plugins. If no argument is given, plugins are loaded via\n  # PluginList#by_precedence.\n  #\n  # This method is called by the engines-supplied plugin testing rake tasks\n  def self.setup_plugin_fixtures(plugins = Engines.plugins.by_precedence)\n    \n    # First, clear the directory\n    Dir.glob(\"#{self.temporary_fixtures_directory}/*.yml\").each{|fixture| File.delete(fixture)}\n    \n    # Copy all plugin fixtures, and then the application fixtures, into this directory\n    plugins.each do |plugin| \n      plugin_fixtures_directory =  File.join(plugin.directory, \"test\", \"fixtures\")\n      plugin_app_directory =  File.join(plugin.directory, \"app\")\n      if File.directory?(plugin_app_directory) && File.directory?(plugin_fixtures_directory)\n        Engines.mirror_files_from(plugin_fixtures_directory, self.temporary_fixtures_directory)\n      end\n    end\n    Engines.mirror_files_from(File.join(RAILS_ROOT, \"test\", \"fixtures\"),\n                              self.temporary_fixtures_directory)\n  end\n  \n  # Sets the fixture path used by Test::Unit::TestCase to the temporary\n  # directory which contains all plugin fixtures.\n  def self.set_fixture_path\n    ActiveSupport::TestCase.fixture_path = self.temporary_fixtures_directory\n    $LOAD_PATH.unshift self.temporary_fixtures_directory\n  end\n  \n  # overridden test should be in test/{unit,functional,integration}/{plugin_name}/{test_name}\n  def self.override_tests_from_app\n    filename = caller.first.split(\":\").first\n    plugin_name = filename.split(\"/\")[-4]\n    test_kind = filename.split(\"/\")[-2]\n    override_file = File.expand_path(File.join(File.dirname(filename), \"..\", \"..\", \"..\", \"..\", \"..\", \"test\", \n                                               test_kind, plugin_name, File.basename(filename)))\n    load(override_file) if File.exist?(override_file)\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/lib/engines.rb",
    "content": "require 'active_support'\nrequire File.join(File.dirname(__FILE__), 'engines/plugin')\nrequire File.join(File.dirname(__FILE__), 'engines/plugin/list')\nrequire File.join(File.dirname(__FILE__), 'engines/plugin/loader')\nrequire File.join(File.dirname(__FILE__), 'engines/plugin/locator')\nrequire File.join(File.dirname(__FILE__), 'engines/assets')\nrequire File.join(File.dirname(__FILE__), 'engines/rails_extensions/rails')\n\n# == Parameters\n#\n# The Engines module has a number of public configuration parameters:\n#\n# [+public_directory+]  The directory into which plugin assets should be\n#                       mirrored. Defaults to <tt>RAILS_ROOT/public/plugin_assets</tt>.\n# [+schema_info_table+] The table to use when storing plugin migration \n#                       version information. Defaults to +plugin_schema_info+.\n#\n# Additionally, there are a few flags which control the behaviour of\n# some of the features the engines plugin adds to Rails:\n#\n# [+disable_application_view_loading+] A boolean flag determining whether\n#                                      or not views should be loaded from \n#                                      the main <tt>app/views</tt> directory.\n#                                      Defaults to false; probably only \n#                                      useful when testing your plugin.\n# [+disable_application_code_loading+] A boolean flag determining whether\n#                                      or not to load controllers/helpers \n#                                      from the main +app+ directory,\n#                                      if corresponding code exists within \n#                                      a plugin. Defaults to false; again, \n#                                      probably only useful when testing \n#                                      your plugin.\n# [+disable_code_mixing+] A boolean flag indicating whether all plugin\n#                         copies of a particular controller/helper should \n#                         be loaded and allowed to override each other, \n#                         or if the first matching file should be loaded \n#                         instead. Defaults to false.\n#\nmodule Engines\n  # The set of all loaded plugins\n  mattr_accessor :plugins\n  self.plugins = Engines::Plugin::List.new  \n  \n  # List of extensions to load, can be changed in init.rb before calling Engines.init\n  mattr_accessor :rails_extensions\n  self.rails_extensions = %w(asset_helpers form_tag_helpers migrations dependencies)\n  \n  # The name of the public directory to mirror public engine assets into.\n  # Defaults to <tt>RAILS_ROOT/public/plugin_assets</tt>.\n  mattr_accessor :public_directory\n  #self.public_directory = File.join(RAILS_ROOT, 'public', 'plugin_assets')\n  self.public_directory = File.join(RAILS_ROOT, 'tmp')\n\n  # The table in which to store plugin schema information. Defaults to\n  # \"plugin_schema_info\".\n  mattr_accessor :schema_info_table\n  self.schema_info_table = \"plugin_schema_info\"\n\n  #--\n  # These attributes control the behaviour of the engines extensions\n  #++\n  \n  # Set this to true if views should *only* be loaded from plugins\n  mattr_accessor :disable_application_view_loading\n  self.disable_application_view_loading = false\n  \n  # Set this to true if controller/helper code shouldn't be loaded \n  # from the application\n  mattr_accessor :disable_application_code_loading\n  self.disable_application_code_loading = false\n  \n  # Set this to true if code should not be mixed (i.e. it will be loaded\n  # from the first valid path on $LOAD_PATH)\n  mattr_accessor :disable_code_mixing\n  self.disable_code_mixing = false\n  \n  # This is used to determine which files are candidates for the \"code\n  # mixing\" feature that the engines plugin provides, where classes from\n  # plugins can be loaded, and then code from the application loaded\n  # on top of that code to override certain methods.\n  mattr_accessor :code_mixing_file_types\n  self.code_mixing_file_types = %w(controller helper)\n  \n  class << self\n    def init(initializer)\n      load_extensions\n      Engines::Assets.initialize_base_public_directory\n    end\n    \n    def logger\n      RAILS_DEFAULT_LOGGER\n    end\n    \n    def load_extensions\n      rails_extensions.each { |name| require \"engines/rails_extensions/#{name}\" }\n      # load the testing extensions, if we are in the test environment.\n      require \"engines/testing\" if RAILS_ENV == \"test\"\n    end\n    \n    def select_existing_paths(paths)\n      paths.select { |path| File.directory?(path) }\n    end  \n  \n    # The engines plugin will, by default, mix code from controllers and helpers,\n    # allowing application code to override specific methods in the corresponding\n    # controller or helper classes and modules. However, if other file types should\n    # also be mixed like this, they can be added by calling this method. For example,\n    # if you want to include \"things\" within your plugin and override them from\n    # your applications, you should use the following layout:\n    #\n    #   app/\n    #    +-- things/\n    #    |       +-- one_thing.rb\n    #    |       +-- another_thing.rb\n    #   ...\n    #   vendor/\n    #       +-- plugins/\n    #                +-- my_plugin/\n    #                           +-- app/\n    #                                +-- things/\n    #                                        +-- one_thing.rb\n    #                                        +-- another_thing.rb\n    #\n    # The important point here is that your \"things\" are named <whatever>_thing.rb,\n    # and that they are placed within plugin/app/things (the pluralized form of 'thing').\n    # \n    # It's important to note that you'll also want to ensure that the \"things\" are\n    # on your load path by including them in Rails load path mechanism, e.g. in init.rb:\n    #\n    #  ActiveSupport::Dependencies.load_paths << File.join(File.dirname(__FILE__), 'app', 'things'))\n    #\n    def mix_code_from(*types)\n      self.code_mixing_file_types += types.map { |x| x.to_s.singularize }\n    end\n    \n    # A general purpose method to mirror a directory (+source+) into a destination\n    # directory, including all files and subdirectories. Files will not be mirrored\n    # if they are identical already (checked via FileUtils#identical?).\n    def mirror_files_from(source, destination)\n      return unless File.directory?(source)\n      \n      # TODO: use Rake::FileList#pathmap?    \n      source_files = Dir[source + \"/**/*\"]\n      source_dirs = source_files.select { |d| File.directory?(d) }\n      source_files -= source_dirs\n      \n      unless source_files.empty?\n        base_target_dir = File.join(destination, File.dirname(source_files.first).gsub(source, ''))\n        FileUtils.mkdir_p(base_target_dir)\n      end\n      \n      source_dirs.each do |dir|\n        # strip down these paths so we have simple, relative paths we can\n        # add to the destination\n        target_dir = File.join(destination, dir.gsub(source, ''))\n        begin        \n          FileUtils.mkdir_p(target_dir)\n        rescue Exception => e\n          raise \"Could not create directory #{target_dir}: \\n\" + e\n        end\n      end\n      \n      source_files.each do |file|\n        begin\n          target = File.join(destination, file.gsub(source, ''))\n          unless File.exist?(target) && FileUtils.identical?(file, target)\n            FileUtils.cp(file, target)\n          end \n        rescue Exception => e\n          raise \"Could not copy #{file} to #{target}: \\n\" + e \n        end\n      end  \n    end   \n  end  \nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/app/controllers/app_and_plugin_controller.rb",
    "content": "class AppAndPluginController < ApplicationController\n  def an_action\n    render_class_and_action 'from app'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/app/controllers/namespace/app_and_plugin_controller.rb",
    "content": "class Namespace::AppAndPluginController < ApplicationController\n  def an_action\n    render_class_and_action 'from app'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/app/helpers/mail_helper.rb",
    "content": "module MailHelper\n  def do_something_helpful(var)\n    var.to_s.reverse\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/app/models/app_and_plugin_model.rb",
    "content": "class AppAndPluginModel < ActiveRecord::Base\n  def self.report_location; TestHelper::report_location(__FILE__); end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/app/models/notify_mail.rb",
    "content": "class NotifyMail < ActionMailer::Base\n\n  helper :mail\n  \n  def signup(txt)\n    body(:name => txt)\n  end\n  \n  def multipart\n    recipients 'some_address@email.com'\n    subject    'multi part email'\n    from       \"another_user@email.com\"\n    content_type 'multipart/alternative'\n    \n    part :content_type => \"text/html\", :body => render_message(\"multipart_html\", {})\n    part \"text/plain\" do |p|\n      p.body = render_message(\"multipart_plain\", {})\n    end\n  end\n  \n  def implicit_multipart\n    recipients 'some_address@email.com'\n    subject    'multi part email'\n    from       \"another_user@email.com\"\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/app/things/thing.rb",
    "content": "class Thing\n  def self.from_app; TestHelper::report_location(__FILE__); end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/app/views/app_and_plugin/a_view.html.erb",
    "content": "<%= TestHelper.view_path_for __FILE__ %> (from app)"
  },
  {
    "path": "vendor/plugins/engines/test/app/views/namespace/app_and_plugin/a_view.html.erb",
    "content": "<%= TestHelper.view_path_for __FILE__ %> (from app)"
  },
  {
    "path": "vendor/plugins/engines/test/app/views/notify_mail/implicit_multipart.text.html.erb",
    "content": "the implicit html part of the email <%= do_something_helpful(\"semaj\") %>"
  },
  {
    "path": "vendor/plugins/engines/test/app/views/notify_mail/implicit_multipart.text.plain.erb",
    "content": "the implicit plaintext part of the email"
  },
  {
    "path": "vendor/plugins/engines/test/app/views/notify_mail/multipart_html.html.erb",
    "content": "the html part of the email <%= do_something_helpful(\"semaj\") %>"
  },
  {
    "path": "vendor/plugins/engines/test/app/views/notify_mail/multipart_plain.html.erb",
    "content": "the plaintext part of the email"
  },
  {
    "path": "vendor/plugins/engines/test/app/views/notify_mail/signup.text.plain.erb",
    "content": "Signup template from application\n\nHere's a local variable set in the Mail object: <%= @name %>.\n\nAnd here's a method called in a mail helper: <%= do_something_helpful(@name) %>\n"
  },
  {
    "path": "vendor/plugins/engines/test/app/views/plugin_mail/mail_from_plugin_with_application_template.text.plain.erb",
    "content": "<%= @note %> (from application)"
  },
  {
    "path": "vendor/plugins/engines/test/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb",
    "content": "plugin mail template loaded from application"
  },
  {
    "path": "vendor/plugins/engines/test/functional/controller_loading_test.rb",
    "content": "# Tests in this file ensure that:\n#\n# * plugin controller actions are found\n# * actions defined in application controllers take precedence over those in plugins\n# * actions in controllers in subsequently loaded plugins take precendence over those in previously loaded plugins\n# * this works for actions in namespaced controllers accordingly\n\nrequire File.dirname(__FILE__) + '/../test_helper'\n\nclass ControllerLoadingTest < ActionController::TestCase\n  def setup\n    @request    = ActionController::TestRequest.new\n    @response   = ActionController::TestResponse.new\n  end\n\n  # plugin controller actions should be found\n\n\tdef test_WITH_an_action_defined_only_in_a_plugin_IT_should_use_this_action\n\t  get_action_on_controller :an_action, :alpha_plugin\n    assert_response_body 'rendered in AlphaPluginController#an_action'\n  end\n  \n\tdef test_WITH_an_action_defined_only_in_a_namespaced_plugin_controller_IT_should_use_this_action\n\t  get_action_on_controller :an_action, :alpha_plugin, :namespace\n    assert_response_body 'rendered in Namespace::AlphaPluginController#an_action'\n  end\n\n  # app takes precedence over plugins\n\n  def test_WITH_an_action_defined_in_both_app_and_plugin_IT_should_use_the_one_in_app\n\t  get_action_on_controller :an_action, :app_and_plugin\n    assert_response_body 'rendered in AppAndPluginController#an_action (from app)'\n  end\n  \n  def test_WITH_an_action_defined_in_namespaced_controllers_in_both_app_and_plugin_IT_should_use_the_one_in_app\n\t  get_action_on_controller :an_action, :app_and_plugin, :namespace\n    assert_response_body 'rendered in Namespace::AppAndPluginController#an_action (from app)'\n  end\n\n  # subsequently loaded plugins take precendence over previously loaded plugins\n\n  def test_WITH_an_action_defined_in_two_plugin_controllers_IT_should_use_the_latter_of_both\n\t  get_action_on_controller :an_action, :shared_plugin\n    assert_response_body 'rendered in SharedPluginController#an_action (from beta_plugin)'\n  end\n  \n  def test_WITH_an_action_defined_in_two_namespaced_plugin_controllers_IT_should_use_the_latter_of_both\n\t  get_action_on_controller :an_action, :shared_plugin, :namespace\n    assert_response_body 'rendered in Namespace::SharedPluginController#an_action (from beta_plugin)'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/functional/exception_notification_compatibility_test.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass ExceptionNotificationCompatibilityTest < ActionController::TestCase\n  ExceptionNotifier.exception_recipients = %w(joe@schmoe.com bill@schmoe.com)\n  class SimpleController < ApplicationController\n    include ExceptionNotifiable\n    local_addresses.clear\n    consider_all_requests_local = false\n    def index\n      begin\n        raise \"Fail!\"\n      rescue Exception => e\n        rescue_action_in_public(e)\n      end\n    end\n  end\n  \n  def setup\n    @controller = SimpleController.new\n    @request    = ActionController::TestRequest.new\n    @response   = ActionController::TestResponse.new\n  end\n  \n  def test_should_work\n    assert_nothing_raised do\n      get :index\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/functional/locale_loading_test.rb",
    "content": "# Tests in this file ensure that:\n#\n# * translations in the application take precedence over those in plugins\n# * translations in subsequently loaded plugins take precendence over those in previously loaded plugins\n\nrequire File.dirname(__FILE__) + '/../test_helper'\n\nclass LocaleLoadingTest < ActionController::TestCase\n  def setup\n    @request    = ActionController::TestRequest.new\n    @response   = ActionController::TestResponse.new\n  end\n\n  # app takes precedence over plugins\n\t\n  def test_WITH_a_translation_defined_in_both_app_and_plugin_IT_should_find_the_one_in_app\n    assert_equal I18n.t('hello'), 'Hello world'\n  end\n\t\n  # subsequently loaded plugins take precendence over previously loaded plugins\n\t\n  def test_WITH_a_translation_defined_in_two_plugins_IT_should_find_the_latter_of_both\n    assert_equal I18n.t('plugin'), 'beta'\n  end\nend\n\t\n"
  },
  {
    "path": "vendor/plugins/engines/test/functional/routes_test.rb",
    "content": "# Tests in this file ensure that:\n#\n# * Routes from plugins can be routed to\n# * Named routes can be defined within a plugin\n\nrequire File.dirname(__FILE__) + '/../test_helper'\n\nclass RoutesTest < ActionController::TestCase\n  tests TestRoutingController\n  \n\tdef test_WITH_a_route_defined_in_a_plugin_IT_should_route_it\n\t  path = '/routes/an_action'\n    opts = {:controller => 'test_routing', :action => 'an_action'}\n    assert_routing path, opts\n    assert_recognizes opts, path # not sure what exactly the difference is, but it won't hurt either\n  end\n\n\tdef test_WITH_a_route_for_a_namespaced_controller_defined_in_a_plugin_IT_should_route_it\n\t  path = 'somespace/routes/an_action'\n    opts = {:controller => 'namespace/test_routing', :action => 'an_action'}\n    assert_routing path, opts\n    assert_recognizes opts, path\n  end\n  \n  def test_should_properly_generate_named_routes\n    get :test_named_routes_from_plugin\n    assert_response_body '/somespace/routes'\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/functional/view_helpers_test.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass ViewHelpersTest < ActionController::TestCase\n  tests AssetsController\n  \n  def setup\n    get :index\n  end\n  \n  def test_plugin_javascript_helpers\n    base_selector = \"script[type='text/javascript']\"\n    js_dir = \"/plugin_assets/test_assets/javascripts\"\n    assert_select \"#{base_selector}[src='#{js_dir}/file.1.js']\"\n    assert_select \"#{base_selector}[src='#{js_dir}/file2.js']\"\n  end\n\n  def test_plugin_stylesheet_helpers\n    base_selector = \"link[media='screen'][rel='stylesheet'][type='text/css']\"\n    css_dir = \"/plugin_assets/test_assets/stylesheets\"\n    assert_select \"#{base_selector}[href='#{css_dir}/file.1.css']\"\n    assert_select \"#{base_selector}[href='#{css_dir}/file2.css']\"\n  end\n\n  def test_plugin_image_helpers\n    assert_select \"img[src='/plugin_assets/test_assets/images/image.png'][alt='Image']\"\n  end\n\n  def test_plugin_layouts\n    get :index\n    assert_select \"div[id='assets_layout']\"\n  end  \n\n  def test_plugin_image_submit_helpers\n    assert_select \"input[src='/plugin_assets/test_assets/images/image.png'][type='image']\"\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/functional/view_loading_test.rb",
    "content": "# Tests in this file ensure that:\n#\n# * plugin views are found\n# * views in the application take precedence over those in plugins\n# * views in subsequently loaded plugins take precendence over those in previously loaded plugins\n# * this works for namespaced views accordingly\n\nrequire File.dirname(__FILE__) + '/../test_helper'\n\nclass ViewLoadingTest < ActionController::TestCase\n  def setup\n    @request    = ActionController::TestRequest.new\n    @response   = ActionController::TestResponse.new\n  end\n\n  # plugin views should be found\n\n \tdef test_WITH_a_view_defined_only_in_a_plugin_IT_should_find_the_view\n\t  get_action_on_controller :a_view, :alpha_plugin\n    assert_response_body 'alpha_plugin/a_view'\n  end\n\t\n\tdef test_WITH_a_namespaced_view_defined_only_in_a_plugin_IT_should_find_the_view\n\t  get_action_on_controller :a_view, :alpha_plugin, :namespace\n    assert_response_body 'namespace/alpha_plugin/a_view'\n  end\n\n  # app takes precedence over plugins\n\t\n\tdef test_WITH_a_view_defined_in_both_app_and_plugin_IT_should_find_the_one_in_app\n\t  get_action_on_controller :a_view, :app_and_plugin\n    assert_response_body 'app_and_plugin/a_view (from app)'\n  end\n\t\n\tdef test_WITH_a_namespaced_view_defined_in_both_app_and_plugin_IT_should_find_the_one_in_app\n\t  get_action_on_controller :a_view, :app_and_plugin, :namespace\n    assert_response_body 'namespace/app_and_plugin/a_view (from app)'\n  end\n\n  # subsequently loaded plugins take precendence over previously loaded plugins\n\t\n\tdef test_WITH_a_view_defined_in_two_plugins_IT_should_find_the_latter_of_both\n\t  get_action_on_controller :a_view, :shared_plugin\n    assert_response_body 'shared_plugin/a_view (from beta_plugin)'\n  end\n\t\n\tdef test_WITH_a_namespaced_view_defined_in_two_plugins_IT_should_find_the_latter_of_both\n\t  get_action_on_controller :a_view, :shared_plugin, :namespace\n    assert_response_body 'namespace/shared_plugin/a_view (from beta_plugin)'\n  end\n  \n  # layouts loaded from plugins\n\n  def test_should_be_able_to_load_a_layout_from_a_plugin\n    get_action_on_controller :action_with_layout, :alpha_plugin\n    assert_response_body 'rendered in AlphaPluginController#action_with_layout (with plugin layout)'\n  end\n\t\nend\n\t"
  },
  {
    "path": "vendor/plugins/engines/test/lib/app_and_plugin_lib_model.rb",
    "content": "class AppAndPluginLibModel < ActiveRecord::Base\n  def self.report_location; TestHelper::report_location(__FILE__); end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/lib/engines_test_helper.rb",
    "content": "module TestHelper\n  def self.report_location(path)\n    [RAILS_ROOT + '/', 'vendor/plugins/'].each { |part| path.sub! part, ''}\n    path = path.split('/')\n    location, subject = path.first, path.last\n    if subject.sub! '.rb', ''\n      subject = subject.classify\n    else \n      subject.sub! '.html.erb', ''\n    end\n    \"#{subject} (from #{location})\"\n  end\n  \n  def self.view_path_for path\n    [RAILS_ROOT + '/', 'vendor/plugins/', '.html.erb'].each { |part| path.sub! part, ''}\n    parts = path.split('/')\n    parts[(parts.index('views')+1)..-1].join('/')\n  end\nend\n\nclass Test::Unit::TestCase\n  # Add more helper methods to be used by all tests here...  \n  def get_action_on_controller(*args)\n    action = args.shift\n    with_controller *args\n    get action\n  end\n  \n  def with_controller(controller, namespace = nil)\n    classname = controller.to_s.classify + 'Controller'\n    classname = namespace.to_s.classify + '::' + classname unless namespace.nil?\n    @controller = classname.constantize.new\n  end\n  \n  def assert_response_body(expected)\n    assert_equal expected, @response.body\n  end\nend\n\n# Because we're testing this behaviour, we actually want these features on!\nEngines.disable_application_view_loading = false\nEngines.disable_application_code_loading = false\n"
  },
  {
    "path": "vendor/plugins/engines/test/lib/render_information.rb",
    "content": "module RenderInformation\n  def render_class_and_action(note = nil, options={})\n    text = \"rendered in #{self.class.name}##{params[:action]}\"\n    text += \" (#{note})\" unless note.nil?\n    render options.update(:text => text)\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/alpha_plugin_controller.rb",
    "content": "class AlphaPluginController < ApplicationController\n  def an_action\n    render_class_and_action\n  end\n  def action_with_layout\n    render_class_and_action(nil, :layout => \"plugin_layout\")\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/app_and_plugin_controller.rb",
    "content": "class AppAndPluginController < ApplicationController\n  def an_action\n    render_class_and_action 'from alpha_plugin'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/alpha_plugin_controller.rb",
    "content": "class Namespace::AlphaPluginController < ApplicationController\n  def an_action\n    render_class_and_action\n  end  \nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/app_and_plugin_controller.rb",
    "content": "class Namespace::AppAndPluginController < ApplicationController\n  def an_action\n    render_class_and_action 'from alpha_plugin'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/shared_plugin_controller.rb",
    "content": "class Namespace::SharedPluginController < ApplicationController\n  def an_action\n    render_class_and_action 'from alpha_plugin'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/shared_plugin_controller.rb",
    "content": "class SharedEngineController < ApplicationController\n  def an_action\n    render_class_and_action 'from alpha_engine'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/models/alpha_plugin_model.rb",
    "content": "class AlphaPluginModel < ActiveRecord::Base\n  def self.report_location; TestHelper::report_location(__FILE__); end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/models/app_and_plugin_model.rb",
    "content": "class AppAndPluginModel < ActiveRecord::Base\n  def self.report_location; TestHelper::report_location(__FILE__); end\n\n  def defined_only_in_alpha_plugin_version\n    # should not be defined as the model in app/models takes precedence\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/models/shared_plugin_model.rb",
    "content": "class SharedPluginModel < ActiveRecord::Base  \n  def self.report_location; TestHelper::report_location(__FILE__); end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/views/alpha_plugin/a_view.html.erb",
    "content": "<%= TestHelper.view_path_for __FILE__ %>"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/views/app_and_plugin/a_view.html.erb",
    "content": "<%= TestHelper.view_path_for __FILE__ %> (from a_view)"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/views/layouts/plugin_layout.erb",
    "content": "<%= yield %> (with plugin layout)"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/alpha_plugin/a_view.html.erb",
    "content": "<%= TestHelper.view_path_for __FILE__ %>"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/app_and_plugin/a_view.html.erb",
    "content": "<%= TestHelper.view_path_for __FILE__ %>"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/shared_plugin/a_view.html.erb",
    "content": "<%= TestHelper.view_path_for __FILE__ %> (from alpha_plugin)"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/app/views/shared_plugin/a_view.html.erb",
    "content": "<%= TestHelper.view_path_for __FILE__ %> (from alpha_plugin)"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/lib/alpha_plugin_lib_model.rb",
    "content": "class AlphaPluginLibModel < ActiveRecord::Base\n  def self.report_location; TestHelper::report_location(__FILE__); end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/lib/app_and_plugin_lib_model.rb",
    "content": "class AppAndPluginLibModel < ActiveRecord::Base\n  def self.report_location; TestHelper::report_location(__FILE__); end\n\n  def defined_only_in_alpha_plugin_version\n    # should not be defined\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/alpha_plugin/locales/en.yml",
    "content": "en:\n  hello: \"Hello from alfa\"\n  plugin: \"alfa\"\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/app_and_plugin_controller.rb",
    "content": "class AppAndPluginController < ApplicationController\n  def an_action\n    render_class_and_action 'from beta_plugin'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/namespace/shared_plugin_controller.rb",
    "content": "class Namespace::SharedPluginController < ApplicationController\n  def an_action\n    render_class_and_action 'from beta_plugin'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/shared_plugin_controller.rb",
    "content": "class SharedPluginController < ApplicationController\n  def an_action\n    render_class_and_action 'from beta_plugin'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/beta_plugin/app/models/shared_plugin_model.rb",
    "content": "class SharedPluginModel < ActiveRecord::Base\n  def self.report_location; TestHelper::report_location(__FILE__); end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/beta_plugin/app/views/namespace/shared_plugin/a_view.html.erb",
    "content": "<%= TestHelper.view_path_for __FILE__ %> (from beta_plugin)"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/beta_plugin/app/views/shared_plugin/a_view.html.erb",
    "content": "<%= TestHelper.view_path_for __FILE__ %> (from beta_plugin)"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/beta_plugin/init.rb",
    "content": "# just here so that Rails recognizes this as a plugin"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/beta_plugin/locales/en.yml",
    "content": "en:\n  hello: \"Hello from beta\"\n  plugin: \"beta\"\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/not_a_plugin/public/should_not_be_copied.txt",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_assets/app/controllers/assets_controller.rb",
    "content": "class AssetsController < ApplicationController\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_assets/app/views/assets/index.html.erb",
    "content": "<%= image_tag 'image.png', :plugin => 'test_assets' %>\n<%= javascript_include_tag 'file.1.js', 'file2', :plugin => \"test_assets\" %>\n<%= stylesheet_link_tag 'file.1.css', 'file2', :plugin => \"test_assets\" %>\n<%= image_submit_tag 'image.png', :plugin => \"test_assets\" %>\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_assets/app/views/layouts/assets.html.erb",
    "content": "<div id=\"assets_layout\">\n\t<%= yield %>\n</div>"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_assets/init.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_assets/public/file.txt",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_assets/public/subfolder/file_in_subfolder.txt",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/assets/file.txt",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/assets/subfolder/file_in_subfolder.txt",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/init.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_assets_with_no_subdirectory/assets/file.txt",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_assets_with_no_subdirectory/init.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_code_mixing/app/things/thing.rb",
    "content": "class Thing\n  def self.from_plugin; TestHelper::report_location(__FILE__); end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_code_mixing/init.rb",
    "content": "# just here so that Rails recognizes this as a plugin"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_load_path/init.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_migration/db/migrate/001_create_tests.rb",
    "content": "class CreateTests < ActiveRecord::Migration\n  def self.up\n    create_table 'tests' do |t|\n      t.column 'name', :string\n    end\n  end\n\n  def self.down\n    drop_table 'tests'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_migration/db/migrate/002_create_others.rb",
    "content": "class CreateOthers < ActiveRecord::Migration\n  def self.up\n    create_table 'others' do |t|\n      t.column 'name', :string\n    end\n  end\n\n  def self.down\n    drop_table 'others'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_migration/db/migrate/003_create_extras.rb",
    "content": "class CreateExtras < ActiveRecord::Migration\n  def self.up\n    create_table 'extras' do |t|\n      t.column 'name', :string\n    end\n  end\n\n  def self.down\n    drop_table 'extras'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_migration/init.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_plugin_mailing/app/models/plugin_mail.rb",
    "content": "class PluginMail < ActionMailer::Base\n  def mail_from_plugin(note=nil)\n    body(:note => note)\n  end\n  \n  def mail_from_plugin_with_application_template(note=nil)\n    body(:note => note)\n  end\n  \n  def multipart_from_plugin\n    content_type 'multipart/alternative'\n    part :content_type => \"text/html\", :body => render_message(\"multipart_from_plugin_html\", {})\n    part \"text/plain\" do |p|\n      p.body = render_message(\"multipart_from_plugin_plain\", {})\n    end\n  end\n  \n  def multipart_from_plugin_with_application_template\n    content_type 'multipart/alternative'\n    part :content_type => \"text/html\", :body => render_message(\"multipart_from_plugin_with_application_template_html\", {})\n    part \"text/plain\" do |p|\n      p.body = render_message(\"multipart_from_plugin_with_application_template_plain\", {})\n    end\n  end  \n  \nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/mail_from_plugin.erb",
    "content": "<%= @note %>"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_html.html.erb",
    "content": "html template"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_plain.html.erb",
    "content": "plain template"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_html.html.erb",
    "content": "template from plugin"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb",
    "content": "template from plugin"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_plugin_mailing/init.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_routing/app/controllers/namespace/test_routing_controller.rb",
    "content": "class Namespace::TestRoutingController < ApplicationController\n  def routed_action\n    render_class_and_action\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_routing/app/controllers/test_routing_controller.rb",
    "content": "class TestRoutingController < ApplicationController\n  def routed_action\n    render_class_and_action\n  end\n  \n  def test_named_routes_from_plugin\n    render :text => plugin_route_path(:action => \"index\")\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_routing/config/routes.rb",
    "content": "ActionController::Routing::Routes.draw do |map|\n  map.connect 'routes/:action', :controller => \"test_routing\"\n  map.plugin_route 'somespace/routes/:action', :controller => \"namespace/test_routing\"\nend"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_routing/init.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_testing/app/README.txt",
    "content": "Fixtures are only copied from plugins with an +app+ directory, but git needs this directory to be non-empty"
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_testing/init.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_testing/test/fixtures/testing_fixtures.yml",
    "content": ""
  },
  {
    "path": "vendor/plugins/engines/test/plugins/test_testing/test/unit/override_test.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), *%w[.. .. .. .. .. test test_helper]))\n\nclass OverrideTest < ActiveSupport::TestCase\n  def test_overrides_from_the_application_should_work\n    flunk \"this test should be overridden by the app\"\n  end\n  \n  def test_tests_within_the_plugin_should_still_run\n    assert true, \"non-overridden plugin tests should still run\"\n  end\nend\n\nEngines::Testing.override_tests_from_app"
  },
  {
    "path": "vendor/plugins/engines/test/unit/action_mailer_test.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass ActionMailerWithinApplicationTest < Test::Unit::TestCase\n  \n  def test_normal_implicit_template\n    m = NotifyMail.create_signup(\"hello\")\n    assert m.body =~ /^Signup template from application/\n  end\n  \n  def test_action_mailer_can_get_helper\n    m = NotifyMail.create_signup('James')\n    assert m.body =~ /James/\n    assert m.body =~ /semaJ/ # from the helper\n  end\n  \n  def test_multipart_mails_with_explicit_templates\n    m = NotifyMail.create_multipart\n    assert_equal 2, m.parts.length\n    assert_equal 'the html part of the email james', m.parts[0].body\n    assert_equal 'the plaintext part of the email', m.parts[1].body\n  end\n  \n  def test_multipart_mails_with_implicit_templates\n    m = NotifyMail.create_implicit_multipart\n    assert_equal 2, m.parts.length\n    assert_equal 'the implicit plaintext part of the email', m.parts[0].body    \n    assert_equal 'the implicit html part of the email james', m.parts[1].body\n  end\nend\n\n\nclass ActionMailerWithinPluginsTest < Test::Unit::TestCase  \n  def test_should_be_able_to_create_mails_from_plugin\n    m = PluginMail.create_mail_from_plugin(\"from_plugin\")\n    assert_equal \"from_plugin\", m.body\n  end\n  \n  def test_should_be_able_to_overload_views_within_the_application\n    m = PluginMail.create_mail_from_plugin_with_application_template(\"from_plugin\")\n    assert_equal \"from_plugin (from application)\", m.body    \n  end\n  \n  def test_should_be_able_to_create_a_multipart_mail_from_within_plugin\n    m = PluginMail.create_multipart_from_plugin\n    assert_equal 2, m.parts.length\n    assert_equal 'html template', m.parts[0].body\n    assert_equal 'plain template', m.parts[1].body\n  end\n  \n  def test_plugin_mailer_template_overriding\n    m = PluginMail.create_multipart_from_plugin_with_application_template\n    assert_equal 'plugin mail template loaded from application', m.parts[1].body\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/unit/arbitrary_code_mixing_test.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass ArbitraryCodeMixingTest < Test::Unit::TestCase  \n  def setup\n    Engines.code_mixing_file_types = %w(controller helper)\n  end\n  \n  def test_should_allow_setting_of_different_code_mixing_file_types\n    assert_nothing_raised {\n      Engines.mix_code_from :things\n    }\n  end\n\n  def test_should_add_new_types_to_existing_code_mixing_file_types\n    Engines.mix_code_from :things\n    assert_equal [\"controller\", \"helper\", \"thing\"], Engines.code_mixing_file_types\n    Engines.mix_code_from :other\n    assert_equal [\"controller\", \"helper\", \"thing\", \"other\"], Engines.code_mixing_file_types\n  end\n  \n  def test_should_allow_setting_of_multiple_types_at_once\n    Engines.mix_code_from :things, :other\n    assert_equal [\"controller\", \"helper\", \"thing\", \"other\"], Engines.code_mixing_file_types\n  end\n   \n  def test_should_singularize_elements_to_be_mixed\n    # this is the only test using mocha, so let's try to work around it\n    # also, this seems to be already tested with the :things in the tests above\n    # arg = stub(:to_s => stub(:singularize => \"element\")) \n    Engines.mix_code_from :elements\n    assert Engines.code_mixing_file_types.include?(\"element\")\n  end\n  \n  # TODO doesn't seem to work as expected?\n  \n  # def test_should_successfully_mix_custom_types\n  #   Engines.mix_code_from :things    \n  #   assert_equal 'Thing (from app)', Thing.from_app\n  #   assert_equal 'Thing (from test_code_mixing)', Thing.from_plugin\n  # end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/unit/assets_test.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass AssetsTest < Test::Unit::TestCase  \n  def setup\n    Engines::Assets.mirror_files_for Engines.plugins[:test_assets]\n  end\n  \n  def teardown\n    FileUtils.rm_r(Engines.public_directory) if File.exist?(Engines.public_directory)\n  end\n  \n  def test_engines_has_created_base_public_file\n    assert File.exist?(Engines.public_directory)\n  end\n  \n  def test_engines_has_created_README_in_public_directory\n    assert File.exist?(File.join(Engines.public_directory, 'README'))\n  end\n  \n  def test_public_files_have_been_copied_from_test_assets_plugin\n    assert File.exist?(File.join(Engines.public_directory, 'test_assets'))\n    assert File.exist?(File.join(Engines.public_directory, 'test_assets', 'file.txt'))\n    assert File.exist?(File.join(Engines.public_directory, 'test_assets', 'subfolder'))\n    assert File.exist?(File.join(Engines.public_directory, 'test_assets', 'subfolder', 'file_in_subfolder.txt'))\n  end\n  \n  def test_engines_has_not_created_duplicated_file_structure\n    assert !File.exists?(File.join(Engines.public_directory, \"test_assets\", RAILS_ROOT))\n  end\n  \n  def test_public_files_have_been_copied_from_test_assets_with_assets_dir_plugin\n    Engines::Assets.mirror_files_for Engines.plugins[:test_assets_with_assets_directory]\n\n    assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_assets_directory'))\n    assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_assets_directory', 'file.txt'))\n    assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_assets_directory', 'subfolder'))\n    assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_assets_directory', 'subfolder', 'file_in_subfolder.txt'))\n  end\n  \n  def test_public_files_have_been_copied_from_test_assets_with_no_subdirectory_plugin\n    Engines::Assets.mirror_files_for Engines.plugins[:test_assets_with_no_subdirectory]\n\n    assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_no_subdirectory'))\n    assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_no_subdirectory', 'file.txt'))    \n  end\n  \n  def test_public_files_have_NOT_been_copied_from_plugins_without_public_or_asset_directories\n    Engines::Assets.mirror_files_for Engines.plugins[:alpha_plugin]\n    \n    assert !File.exist?(File.join(Engines.public_directory, 'alpha_plugin'))\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/unit/backwards_compat_test.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass BackwardsCompatibilityTest < Test::Unit::TestCase\n  def test_rails_module_plugin_method_should_delegate_to_engines_plugins\n    assert_nothing_raised { Rails.plugins }\n    assert_equal Engines.plugins, Rails.plugins \n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/unit/load_path_test.rb",
    "content": "# Tests in this file ensure that:\n#\n# * the application /app/[controllers|helpers|models] and /lib \n#   paths preceed the corresponding plugin paths\n# * the plugin paths are added to $LOAD_PATH in the order in which plugins are \n#   loaded\n\nrequire File.dirname(__FILE__) + '/../test_helper'\n\nclass LoadPathTest < Test::Unit::TestCase\n  def setup\n    @load_path = expand_paths($LOAD_PATH)\n  end\n  \n  # Not sure if these test actually make sense as this now essentially tests\n  # Rails core functionality. On the other hand Engines relies on this to some\n  # extend so this will choke if something important changes in Rails.\n  \n  # the application app/... and lib/ directories should appear\n  # before any plugin directories\n  \n  def test_application_app_libs_should_precede_all_plugin_app_libs\n    types = %w(app/controllers app/helpers app/models lib)\n    types.each do |t|\n      app_index = load_path_index(File.join(RAILS_ROOT, t))\n      assert_not_nil app_index, \"#{t} is missing in $LOAD_PATH\"\n      Engines.plugins.each do |plugin|\n        first_plugin_index = load_path_index(File.join(plugin.directory, t))\n        assert(app_index < first_plugin_index) unless first_plugin_index.nil?\n      end\n    end\n  end\n  \n  # the engine directories should appear in the proper order based on\n  # the order they were started  \n  \n  def test_plugin_dirs_should_appear_in_reverse_plugin_loading_order\n    app_paths = %w(app/controllers/ app app/models app/helpers lib)\n    app_paths.map { |p| File.join(RAILS_ROOT, p)}\n    plugin_paths = Engines.plugins.reverse.collect { |plugin| plugin.load_paths.reverse }.flatten    \n    \n    expected_paths = expand_paths(app_paths + plugin_paths)    \n    # only look at those paths that are also present in expected_paths so\n    # the only difference would be in the order of the paths\n    actual_paths = @load_path & expected_paths \n    \n    assert_equal expected_paths, actual_paths\n  end\n  \n  protected    \n    def expand_paths(paths)\n      paths.collect { |p| File.expand_path(p) }\n    end\n    \n    def load_path_index(dir)\n      @load_path.index(File.expand_path(dir))\n    end  \nend"
  },
  {
    "path": "vendor/plugins/engines/test/unit/migration_test.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\nrequire 'rails_generator'\nrequire 'rails_generator/scripts/generate'\n\nclass MigrationsTest < Test::Unit::TestCase\n  \n  @@migration_dir = \"#{RAILS_ROOT}/db/migrate\"\n\n  def setup\n    ActiveRecord::Migration.verbose = false\n    Engines.plugins[:test_migration].migrate(0)\n  end\n  \n  def teardown\n    FileUtils.rm_r(@@migration_dir) if File.exist?(@@migration_dir)\n  end\n  \n  def test_engine_migrations_can_run_down\n    assert !table_exists?('tests'), ActiveRecord::Base.connection.tables.inspect\n    assert !table_exists?('others'), ActiveRecord::Base.connection.tables.inspect\n    assert !table_exists?('extras'), ActiveRecord::Base.connection.tables.inspect\n  end\n    \n  def test_engine_migrations_can_run_up\n    Engines.plugins[:test_migration].migrate(3)\n    assert table_exists?('tests')\n    assert table_exists?('others')\n    assert table_exists?('extras')\n  end\n  \n  def test_engine_migrations_can_upgrade_incrementally\n    Engines.plugins[:test_migration].migrate(1)\n    assert table_exists?('tests')\n    assert !table_exists?('others')\n    assert !table_exists?('extras')\n    assert_equal 1, Engines::Plugin::Migrator.current_version(Engines.plugins[:test_migration])\n    \n    \n    Engines.plugins[:test_migration].migrate(2)\n    assert table_exists?('others')\n    assert_equal 2, Engines::Plugin::Migrator.current_version(Engines.plugins[:test_migration])\n    \n    \n    Engines.plugins[:test_migration].migrate(3)\n    assert table_exists?('extras')\n    assert_equal 3, Engines::Plugin::Migrator.current_version(Engines.plugins[:test_migration])\n  end\n    \n  def test_generator_creates_plugin_migration_file\n    Rails::Generator::Scripts::Generate.new.run(['plugin_migration', 'test_migration'], :quiet => true)\n    assert migration_file, \"migration file is missing\"\n  end\n  \n  private\n  \n  def table_exists?(table)\n    ActiveRecord::Base.connection.tables.include?(table)\n  end\n  \n  def migration_file\n    Dir[\"#{@@migration_dir}/*test_migration_to_version_3.rb\"][0]\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/unit/model_and_lib_test.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass ModelAndLibTest < Test::Unit::TestCase\n\n \tdef test_WITH_a_model_defined_only_in_a_plugin_IT_should_load_the_model\n \t  assert_equal 'AlphaPluginModel (from alpha_plugin)', AlphaPluginModel.report_location\n  end\n  \n  def test_WITH_a_model_defined_only_in_a_plugin_lib_dir_IT_should_load_the_model\n \t  assert_equal 'AlphaPluginLibModel (from alpha_plugin)', AlphaPluginLibModel.report_location\n  end\n\n  # app takes precedence over plugins\n\t\n\tdef test_WITH_a_model_defined_in_both_app_and_plugin_IT_should_load_the_one_in_app\n \t  assert_equal 'AppAndPluginModel (from app)',\tAppAndPluginModel.report_location  \n \t  assert_raises(NoMethodError) { AppAndPluginLibModel.defined_only_in_alpha_engine_version }\n  end\n\t\n\tdef test_WITH_a_model_defined_in_both_app_and_plugin_lib_dirs_IT_should_load_the_one_in_app\n \t  assert_equal 'AppAndPluginLibModel (from lib)', AppAndPluginLibModel.report_location\n \t  assert_raises(NoMethodError) { AppAndPluginLibModel.defined_only_in_alpha_engine_version }\n  end\n\n  # subsequently loaded plugins take precendence over previously loaded plugins\n\t\n  # TODO\n  #\n  # this does work when we rely on $LOAD_PATH while it won't work when we use\n  # Dependency constant autoloading. This somewhat confusing difference has\n  # been there since at least Rails 1.2.x. See http://www.ruby-forum.com/topic/134529\n  \n  def test_WITH_a_model_defined_in_two_plugins_IT_should_load_the_latter_of_both\n    require 'shared_plugin_model'\n    assert_equal SharedPluginModel.report_location, 'SharedPluginModel (from beta_plugin)'\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/unit/plugins_test.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass PluginsTest < Test::Unit::TestCase\n  \n  def test_should_allow_access_to_plugins_by_strings_or_symbols\n    p = Engines.plugins[\"alpha_plugin\"]\n    q = Engines.plugins[:alpha_plugin]\n    assert_kind_of Engines::Plugin, p\n    assert_equal p, q\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/unit/test_testing/override_test.rb",
    "content": "require File.join(File.dirname(__FILE__), *%w[.. .. test_helper])\n\nclass OverrideTest < ActiveSupport::TestCase\n  def test_overrides_from_the_application_should_work\n    assert true, \"overriding plugin tests from the application should work\"\n  end\nend"
  },
  {
    "path": "vendor/plugins/engines/test/unit/testing_test.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass TestingTest < Test::Unit::TestCase\n  def setup\n    Engines::Testing.set_fixture_path\n    @filename = File.join(Engines::Testing.temporary_fixtures_directory, 'testing_fixtures.yml')\n    File.delete(@filename) if File.exists?(@filename)\n  end\n  \n  def teardown\n    File.delete(@filename) if File.exists?(@filename)\n  end\n\n  def test_should_copy_fixtures_files_to_tmp_directory\n    assert !File.exists?(@filename)\n    Engines::Testing.setup_plugin_fixtures\n    assert File.exists?(@filename)\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/History.txt",
    "content": "0.0.6 - Added a better 'safe' to_json method which works more effectively for rails integration avoiding cyclic reference and un-jsonable data\n0.0.5 - Fixed a bug in the plugin where request.env was being modified directly. dup to solve issues.\n0.0.4 - Restructured the plugin to extract all different concerns into self contained modules, will give a better base to extend. Also plays nicer with Rdoc + singleton classes\n0.0.3 - Dropped background queing of exceptions, send them all directly. Fixed issues with session/environment data. Working with rails 2.3 (some hacks needed to get there, need to refactor.)\n0.0.2 - Fix a bug introduced with nil sessions\n0.0.1 - First Version"
  },
  {
    "path": "vendor/plugins/exceptional/Manifest",
    "content": "exceptional.gemspec\nexceptional.yml\nHistory.txt\ninit.rb\ninstall.rb\nlib/exceptional/api.rb\nlib/exceptional/bootstrap.rb\nlib/exceptional/config.rb\nlib/exceptional/exception_data.rb\nlib/exceptional/integration/rails.rb\nlib/exceptional/log.rb\nlib/exceptional/remote.rb\nlib/exceptional/version.rb\nlib/exceptional.rb\nManifest\nRakefile\nREADME\nspec/api_spec.rb\nspec/bootstrap_spec.rb\nspec/config_spec.rb\nspec/exception_data_spec.rb\nspec/exceptional_rescue_from_spec.rb\nspec/exceptional_spec.rb\nspec/log_spec.rb\nspec/remote_spec.rb\nspec/spec_helper.rb\n"
  },
  {
    "path": "vendor/plugins/exceptional/README",
    "content": "= Exceptional plugin for Ruby on Rails\n\nThis plugin posts exception data to Exceptional (http://getexceptional.com). Data about the request, session, environment and a backtrace of the exception is transmitted.\n\n= Exceptional\n\nExceptional (http://getexceptional.com) is a web-based exception tracking and managing system for Ruby on Rails folks and their apps.\n\n= Installation\n\nFor installation instructions, follow the steps displayed after adding a new app to your account. Please send any questions or comments to feedback@getexceptional.com.\n\nCopyright © 2008, 2009 Contrast.\n"
  },
  {
    "path": "vendor/plugins/exceptional/Rakefile",
    "content": "begin\n  require 'echoe'\n\n  Echoe.new('exceptional', '0.0.6') do |p|\n    p.rubyforge_name = 'exceptional'\n    p.summary = \"Exceptional is the core Ruby library for communicating with http://getexceptional.com (hosted error tracking service)\"\n    p.description = \"Exceptional is the core Ruby library for communicating with http://getexceptional.com (hosted error tracking service)\"\n    p.url = \"http://getexceptional.com/\"\n    p.author = [\"Contrast\"]\n    p.email = \"hello@contrast.ie\"\n    p.dependencies = [\"json\"]\n  end\nrescue LoadError => e\n  puts \"You are missing a dependency required for meta-operations on this gem.\"\n  puts \"#{e.to_s.capitalize}.\"\nend\n# add spec tasks, if you have rspec installed\nbegin\n  require 'spec/rake/spectask'\n  Spec::Rake::SpecTask.new(\"spec\") do |t|\n    t.spec_files = FileList['spec/**/*_spec.rb']\n    t.spec_opts = ['--color']\n  end\n\n  task :test do\n    Rake::Task['spec'].invoke\n  end\n\n  Spec::Rake::SpecTask.new(\"coverage\") do |t|\n    t.spec_files = FileList['spec/**/*_spec.rb']\n    t.spec_opts = ['--color']\n    t.rcov = true\n    t.rcov_opts = ['--exclude', '^spec,/gems/']\n  end\nend\n\ndesc 'Run specs using ginger'\ntask :ginger do\n  ARGV.clear\n  ARGV << 'spec'\n  load File.join(*%w[bin ginger])\nend"
  },
  {
    "path": "vendor/plugins/exceptional/bin/ginger",
    "content": "#!/usr/bin/env ruby\n\nrequire 'rubygems'\nbegin\n  require 'ginger'\nrescue LoadError\n  puts <<-INSTALL_GINGER\nInstall ginger to test plugin against multiple environments:\n\nsudo gem install freelancing-god-ginger --source=http://gems.github.com\n\nMore details: http://github.com/freelancing-god/ginger\n  INSTALL_GINGER\n  exit 0\nend\n\nrequire 'rake'\n\nif ARGV.length == 0\n  puts <<-USAGE\nginger #{Ginger::Version::String}\nUse ginger to run specs for each scenario defined. Scenarios must be set out in\na file called ginger_scenarios.rb wherever this tool is run. Once they're\ndefined, then you can run this tool and provide the rake task that would\nnormally be called.\n\nExamples:\n  ginger spec\n  ginger test\n  ginger spec:models\n  USAGE\n  exit 0\nend\n\nfile_path = File.join Dir.pwd, \".ginger\"\n\nFile.delete(file_path) if File.exists?(file_path)\n\nscenarios = Ginger::Configuration.instance.scenarios\nputs \"No Ginger Scenarios defined\" if scenarios.empty?\n\nscenarios.each_with_index do |scenario, index|\n  puts <<-SCENARIO\n\n-------------------\nGinger Scenario: #{scenario.name || index+1}\n-------------------\n  SCENARIO\n\n  File.open('.ginger', 'w') { |f| f.write index.to_s }\n  system(\"rake #{ARGV.join(\" \")}\") || system(\"rake.bat #{ARGV.join(\" \")}\")\nend\n\nFile.delete(file_path) if File.exists?(file_path)"
  },
  {
    "path": "vendor/plugins/exceptional/exceptional.gemspec",
    "content": "# -*- encoding: utf-8 -*-\n\nGem::Specification.new do |s|\n  s.name = %q{exceptional}\n  s.version = \"0.0.6\"\n\n  s.required_rubygems_version = Gem::Requirement.new(\">= 1.2\") if s.respond_to? :required_rubygems_version=\n  s.authors = [\"Contrast\"]\n  s.date = %q{2009-07-09}\n  s.description = %q{Exceptional is the core Ruby library for communicating with http://getexceptional.com (hosted error tracking service)}\n  s.email = %q{hello@contrast.ie}\n  s.extra_rdoc_files = [\"lib/exceptional/api.rb\", \"lib/exceptional/bootstrap.rb\", \"lib/exceptional/config.rb\", \"lib/exceptional/exception_data.rb\", \"lib/exceptional/integration/rails.rb\", \"lib/exceptional/log.rb\", \"lib/exceptional/remote.rb\", \"lib/exceptional/version.rb\", \"lib/exceptional.rb\", \"README\"]\n  s.files = [\"exceptional.gemspec\", \"exceptional.yml\", \"History.txt\", \"init.rb\", \"install.rb\", \"lib/exceptional/api.rb\", \"lib/exceptional/bootstrap.rb\", \"lib/exceptional/config.rb\", \"lib/exceptional/exception_data.rb\", \"lib/exceptional/integration/rails.rb\", \"lib/exceptional/log.rb\", \"lib/exceptional/remote.rb\", \"lib/exceptional/version.rb\", \"lib/exceptional.rb\", \"Manifest\", \"Rakefile\", \"README\", \"spec/api_spec.rb\", \"spec/bootstrap_spec.rb\", \"spec/config_spec.rb\", \"spec/exception_data_spec.rb\", \"spec/exceptional_rescue_from_spec.rb\", \"spec/exceptional_spec.rb\", \"spec/log_spec.rb\", \"spec/remote_spec.rb\", \"spec/spec_helper.rb\"]\n  s.has_rdoc = true\n  s.homepage = %q{http://getexceptional.com/}\n  s.rdoc_options = [\"--line-numbers\", \"--inline-source\", \"--title\", \"Exceptional\", \"--main\", \"README\"]\n  s.require_paths = [\"lib\"]\n  s.rubyforge_project = %q{exceptional}\n  s.rubygems_version = %q{1.3.1}\n  s.summary = %q{Exceptional is the core Ruby library for communicating with http://getexceptional.com (hosted error tracking service)}\n\n  if s.respond_to? :specification_version then\n    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION\n    s.specification_version = 2\n\n    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then\n      s.add_runtime_dependency(%q<json>, [\">= 0\"])\n    else\n      s.add_dependency(%q<json>, [\">= 0\"])\n    end\n  else\n    s.add_dependency(%q<json>, [\">= 0\"])\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/exceptional.yml",
    "content": "# here are the settings that are common to all environments\ncommon: &default_settings\n  # You must specify your Exceptional API key here.\n  api-key: 6e2a223d45e17bdeac6914c20665b26524ad6344\n  # Exceptional creates a separate log file from your application's logs\n  # available levels are debug, info, warn, error, fatal\n  log-level: info\n  # The exceptional agent sends data via regular http by default\n  # Setting this value to true will send data over SSL, increasing security\n  # There will be an additional CPU overhead in encrypting the data, however\n  # as long as your deployment environment is not Passenger (mod_rails), this\n  # happens in the background so as not to incur a page wait for your users.\n  ssl: false\n  \ndevelopment:\n  <<: *default_settings\n  # Normally no reason to collect exceptions in development\n  # NOTE: for trial purposes you may want to enable exceptional in development\n  enabled: true\n  \ntest:\n  <<: *default_settings\n  # No reason to collect exceptions when running tests by default\n  enabled: false\n\nproduction:\n  <<: *default_settings\n  enabled: true\n\nstaging:\n  # It's common development practice to have a staging environment that closely\n  # mirrors production, by default catch errors in this environment too.\n  <<: *default_settings\n  enabled: true\n"
  },
  {
    "path": "vendor/plugins/exceptional/ginger_scenarios.rb",
    "content": "require 'ginger'\n\nclass ScenarioWithName < Ginger::Scenario\n  attr_accessor :name\n  def initialize(name)\n    @name = name\n  end\nend\n\ndef create_scenario(version)\n  scenario = ScenarioWithName.new(\"Rails #{version}\")\n  scenario[/^active_?support$/]    = version\n  scenario[/^active_?record$/]     = version\n  scenario[/^action_?pack$/]       = version\n  scenario[/^action_?controller$/] = version\n  scenario[/^rails$/] = version\n  scenario\nend\n\nGinger.configure do |config|\n  config.aliases[\"active_record\"] = \"activerecord\"\n  config.aliases[\"active_support\"] = \"activesupport\"\n  config.aliases[\"action_controller\"] = \"actionpack\"\n\n  rails_1_2_6 = ScenarioWithName.new(\"Rails 1.2.6\")\n  rails_1_2_6[/^active_?support$/] = \"1.4.4\"\n  rails_1_2_6[/^active_?record$/] = \"1.15.6\"\n  rails_1_2_6[/^action_?pack$/] = \"1.13.6\"\n  rails_1_2_6[/^action_?controller$/] = \"1.13.6\"\n  rails_1_2_6[/^rails$/] = \"1.2.6\"\n\n  config.scenarios << rails_1_2_6\n  config.scenarios << create_scenario(\"2.0.2\")\n  config.scenarios << create_scenario(\"2.1.2\")\n  config.scenarios << create_scenario(\"2.2.2\")\n  config.scenarios << create_scenario(\"2.3.2\")\n  config.scenarios << create_scenario(\"2.3.3\")\n  config.scenarios << create_scenario(\"2.3.4\")\nend"
  },
  {
    "path": "vendor/plugins/exceptional/init.rb",
    "content": "require 'exceptional'\nExceptional.bootstrap(RAILS_ENV, RAILS_ROOT)"
  },
  {
    "path": "vendor/plugins/exceptional/install.rb",
    "content": "# This is the post install hook for when Exceptional is installed as a plugin.\nrequire 'ftools'\n\n# puts IO.read(File.join(File.dirname(__FILE__), 'README'))\n\nconfig_file = File.expand_path(\"#{File.dirname(__FILE__)}/../../../config/exceptional.yml\")\nexample_config_file = \"#{File.dirname(__FILE__)}/exceptional.yml\"\n\nif File::exists? config_file\n  puts \"Exceptional config file already exists. Please ensure it is up-to-date with the current format.\"\n  puts \"See #{example_config_file}\"\nelse  \n  puts \"Installing default Exceptional config\"\n  puts \"  From #{example_config_file}\"\n  puts \"For exceptional to work you need to configure your API Key\"\n  puts \"  See #{example_config_file}\"\n  puts \"If you don't have an API Key, get one at http://getexceptional.com/\"\n  File.copy example_config_file, config_file\nend\n"
  },
  {
    "path": "vendor/plugins/exceptional/lib/exceptional/api.rb",
    "content": "require 'json' unless defined? Rails\n\nmodule Exceptional\n  module Api\n    # post the given exception data to getexceptional.com\n    def post(exception_data)\n      hash = exception_data.to_hash\n      if hash[:session]\n        hash[:session].delete(\"initialization_options\")\n        hash[:session].delete(\"request\")\n      end\n\n      Exceptional.post_exception(hash.to_json)\n    end\n\n    # used with Rails, takes an exception, controller, request and parameters\n    # creates an ExceptionData object\n    def handle(exception, controller, request, params)\n      Exceptional.log! \"Handling #{exception.message}\", 'info'\n      begin\n        exception_data = ExceptionData.new(exception)\n        # Additional data for Rails Exceptions\n        exception_data.framework = \"rails\"\n        exception_data.controller_name = controller.controller_name\n        exception_data.action_name = controller.action_name\n        exception_data.application_root = Exceptional.application_root\n        exception_data.occurred_at = Time.now.strftime(\"%Y%m%d %H:%M:%S %Z\")\n        exception_data.environment = request.env.to_hash\n        exception_data.url = \"#{request.protocol}#{request.host}#{request.request_uri}\"\n        exception_data.environment = safe_environment(request)\n        exception_data.session = safe_session(request.session)\n        exception_data.parameters = sanitize_hash(params.to_hash)\n\n        post(exception_data)\n      rescue Exception => exception\n        Exceptional.log! \"Error preparing exception data.\"\n        Exceptional.log! exception.message\n        Exceptional.log! exception.backtrace.join(\"\\n\"), 'debug'\n      end\n    end\n\n    # rescue any exceptions within the given block,\n    # send it to exceptional,\n    # then raise\n    def rescue(&block)\n      begin\n        block.call\n      rescue Exception => e\n        self.catch(e)\n        raise(e)\n      end\n    end\n\n    def catch(exception)\n      exception_data = ExceptionData.new(exception)\n      exception_data.controller_name = File.basename($0)\n      post(exception_data)\n    end\n\n    protected\n\n    def safe_environment(request)\n      safe_environment = request.env.dup.to_hash\n      # From Rails 2.3 these objects that cause a circular reference error on .to_json need removed\n      # TODO potentially remove this case, should be covered by sanitize_hash\n      safe_environment.delete_if { |k,v| k =~ /rack/ || k =~ /action_controller/ || k == \"_\"}\n      # needed to add a filter for the hash for \"_\", causing invalid xml.\n      sanitize_hash(safe_environment)\n    end\n\n    def safe_session(session)\n      result = {}\n      session.instance_variables.each do |v|\n        next if v =~ /cgi/ || v =~ /db/ || v =~ /env/\n        var = v.sub(\"@\",\"\") # remove prepended @'s\n        result[var] = session.instance_variable_get(v)\n      end\n      sanitize_hash(result)\n    end\n\n    private\n\n    def sanitize_hash(hash)\n      return {} if hash.nil?\n      hash.reject { |key, val| !ensure_json_able(val) }\n    end\n\n    def ensure_json_able(value)\n      begin\n        value.to_json\n        true && value.instance_values.all? { |e| ensure_json_able(e)}        \n      rescue Exception => e\n        false\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/lib/exceptional/bootstrap.rb",
    "content": "module Exceptional\n  module Bootstrap\n    \n    # called from init.rb\n    def bootstrap(environment, application_root)\n      begin\n        setup_config(environment, File.join(application_root,\"config\", \"exceptional.yml\"))\n        setup_log(File.join(application_root, \"log\"), log_level)\n\n        if enabled?\n          if authenticate\n            require File.join('exceptional', 'integration', 'rails')\n          else\n            STDERR.puts \"Exceptional plugin not authenticated, check your API Key\"\n          end\n        end\n      rescue Exception => e\n        STDERR.puts e\n        STDERR.puts \"Exceptional Plugin disabled.\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/exceptional/lib/exceptional/config.rb",
    "content": "require 'yaml'\n\nmodule Exceptional\n  module Config\n\n    # Defaults for configuration variables\n    REMOTE_HOST = \"exceptional.io\"\n    REMOTE_PORT = 80\n    REMOTE_SSL_PORT = 443\n    SSL = false\n    LOG_LEVEL = 'info'\n    LOG_PATH = nil\n\n    class ConfigurationException < StandardError; end\n\n    attr_reader :api_key\n    attr_writer :ssl_enabled, :remote_host, :remote_port, :api_key\n\n    def setup_config(environment, config_file)\n      begin\n        config = YAML::load(File.open(config_file))[environment]\n        @api_key = config['api-key'] unless config['api-key'].nil?\n        @ssl_enabled = config['ssl'] unless config['ssl'].nil?\n        @log_level = config['log-level'] unless config['log-level'].nil?\n        @enabled = config['enabled'] unless config['enabled'].nil?\n        @remote_port = config['remote-port'].to_i unless config['remote-port'].nil?\n        @remote_host = config['remote-host'] unless config['remote-host'].nil?\n        @applicaton_root = application_root\n\n        log_config_info\n      rescue Exception => e\n        raise ConfigurationException.new(\"Unable to load configuration #{config_file} for environment #{environment} : #{e.message}\")\n      end\n    end\n\n    def application_root\n      @applicaton_root || (File.dirname(__FILE__) + '/../..')\n    end\n\n    def remote_host\n      @remote_host || REMOTE_HOST\n    end\n\n    def remote_port\n      @remote_port || default_port\n    end\n\n    def log_level\n      @log_level || LOG_LEVEL\n    end\n\n    def default_port\n      ssl_enabled? ? REMOTE_SSL_PORT : REMOTE_PORT\n    end\n\n    def ssl_enabled?\n      @ssl_enabled || SSL\n    end\n\n    def enabled?\n      @enabled || false\n    end\n\n    def valid_api_key?\n      @api_key && @api_key.length == 40 ? true : false\n    end\n\n    def log_config_info\n      Exceptional.to_log('debug', \"API Key: #{api_key}\")\n      Exceptional.to_log('debug', \"Remote Host: #{remote_host}:#{remote_port}\")\n      Exceptional.to_log('debug', \"Log level: #{log_level}\")\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/lib/exceptional/exception_data.rb",
    "content": "# This class encapsulates data about an exception.\nmodule Exceptional\n  class DataError < StandardError; end\n  \n  class ExceptionData\n    ::LANGUAGE = \"ruby\"\n    ::BASE_ATTRS = [:exception_class, :exception_message, :exception_backtrace]\n    ::OPTIONAL_ATTRS = [:framework, :controller_name, :action_name, :application_root, \n                        :url, :occurred_at, :environment, :session, :parameters]\n    ::ACCESSIBLE_ATTRS = ::BASE_ATTRS + ::OPTIONAL_ATTRS\n    ::ATTRS = [:language] + ::ACCESSIBLE_ATTRS\n    \n    ::ACCESSIBLE_ATTRS.each do |attribute|\n      attr_accessor attribute\n    end\n    attr_reader   :language\n\n    def initialize(exception)\n      environment = {}\n      session = {}\n      parameters = {}\n      self.exception_backtrace = exception.backtrace\n      self.exception_message = exception.message\n      self.exception_class = exception.class.to_s\n      @language = ::LANGUAGE\n    end\n    \n    def valid?\n      ::BASE_ATTRS.each do |method|\n        raise(DataError, \"base data #{method} not set\") if (self.send(method).nil? || self.send(method).empty?)\n      end\n    end\n    \n    def to_hash\n      hash = {}\n      ::ATTRS.each do |attribute|\n        value = send(attribute)\n        hash[attribute] = value unless (value.nil? || value.empty? || attribute.is_a?(TCPSocket) || attribute.is_a?(TCPServer)) \n      end\n      hash\n    end\n    \n    def to_json\n      self.to_hash.to_json\n    end    \n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/lib/exceptional/integration/rails.rb",
    "content": "if defined? ActiveSupport\n  # Hack to force Rails version prior to 2.0 to use quoted JSON as per the JSON standard...\n  if (defined?(ActiveSupport::JSON) && ActiveSupport::JSON.respond_to?(:unquote_hash_key_identifiers))\n    ActiveSupport::JSON.unquote_hash_key_identifiers = false \n  end\nend\n\nif defined? ActionController\n  module ActionController\n    class Base\n    \n      def rescue_action_with_exceptional(exception)\n        unless exception_will_be_handled_by_rescue_from?(exception)\n          params_to_send = (respond_to? :filter_parameters) ? filter_parameters(params) : params\n          Exceptional.handle(exception, self, request, params_to_send)\n        end\n        rescue_action_without_exceptional(exception)\n      end\n\n      def exception_will_be_handled_by_rescue_from?(exception)\n        # don't report to exceptional if app has custom rescue_from for particular exception\n        respond_to?(:handler_for_rescue) && handler_for_rescue(exception)\n      end\n    \n      alias_method :rescue_action_without_exceptional, :rescue_action\n      alias_method :rescue_action, :rescue_action_with_exceptional\n      protected :rescue_action\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/lib/exceptional/log.rb",
    "content": "require 'logger'\n\nmodule Exceptional\n  module Log\n\n    attr_reader :log\n    \n    def setup_log(log_dir, log_level = Logger::INFO)\n      begin\n        Dir.mkdir(log_dir) unless File.directory?(log_dir)\n\n        \n        log_path = File.join(log_dir, \"/exceptional.log\")\n        log = Logger.new log_path\n        \n        log.level = log_level\n\n        allowed_log_levels = ['debug', 'info', 'warn', 'error', 'fatal']\n        if log_level && allowed_log_levels.include?(log_level)\n          log.level = eval(\"Logger::#{log_level.upcase}\")\n        end\n\n        @log = log\n      rescue Exception => e\n        raise Exceptional::Config::ConfigurationException.new(\"Unable to create log file #{log_path} #{e.message}\")\n      end\n    end\n\n    def log!(msg, level = 'info')\n      to_log level, msg\n      to_stderr msg\n    end\n\n    def to_stderr(msg)\n      STDERR.puts format_log_message(msg)\n    end\n\n    protected\n\n    def to_log(level, msg)\n      @log.send level, msg if @log\n    end\n\n    private\n\n    def format_log_message(msg)\n      \"** [Exceptional] \" + msg\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/lib/exceptional/remote.rb",
    "content": "require 'zlib'\nrequire 'cgi'\nrequire 'net/http'\n\nmodule Exceptional\n  module Remote\n\n    class RemoteException < StandardError; end\n\n    ::PROTOCOL_VERSION = 3\n\n    # authenticate with getexceptional.com\n    # returns true if the configured api_key is registered and can send data\n    # otherwise false\n    def authenticate\n\n      return @authenticated if @authenticated\n\n      if Exceptional.api_key.nil?\n        raise Exceptional::Config::ConfigurationException.new(\"API Key must be configured\")\n      end\n\n      begin\n        # TODO No data required to authenticate, send a nil string? hacky\n        # TODO should retry if a http connection failed\n        authenticated = call_remote(:authenticate, \"\")\n        \n        @authenticated = authenticated =~ /true/ ? true : false\n      rescue\n        @authenticated = false\n      ensure\n        return @authenticated\n      end\n    end\n\n    def authenticated?\n      @authenticated || false\n    end\n\n    def post_exception(data)\n      if !authenticated?\n        authenticate\n      end\n\n      call_remote(:errors, data)\n    end\n\n    protected\n\n    def call_remote(method, data)\n      begin\n        http = Net::HTTP.new(Exceptional.remote_host, Exceptional.remote_port)\n        http.use_ssl = true if Exceptional.ssl_enabled?\n        uri = \"/#{method.to_s}?&api_key=#{Exceptional.api_key}&protocol_version=#{::PROTOCOL_VERSION}\"\n        headers = method.to_s == 'errors' ? { 'Content-Type' => 'application/x-gzip', 'Accept' => 'application/x-gzip' } : {}\n\n        compressed_data = CGI::escape(Zlib::Deflate.deflate(data, Zlib::BEST_SPEED))\n        response = http.start do |http|\n          http.post(uri, compressed_data, headers)\n        end\n\n        if response.kind_of? Net::HTTPSuccess\n          return response.body\n        else\n          raise RemoteException.new(\"#{response.code}: #{response.message}\")\n        end\n\n      rescue Exception => e\n        Exceptional.log! \"Error contacting Exceptional: #{e}\", 'info'\n        Exceptional.log! e.backtrace.join(\"\\n\"), 'debug'\n        raise e\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/lib/exceptional/version.rb",
    "content": "module Exceptional #:nodoc:\n  module VERSION #:nodoc:\n    MAJOR = 0\n    MINOR = 0\n    TINY  = 6\n \n    STRING = [MAJOR, MINOR, TINY].join('.')\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/lib/exceptional.rb",
    "content": "$:.unshift File.dirname(__FILE__)\n\nrequire 'exceptional/exception_data'\nrequire 'exceptional/version'\nrequire 'exceptional/log'\nrequire 'exceptional/config'\nrequire 'exceptional/remote'\nrequire 'exceptional/api'\nrequire 'exceptional/bootstrap'\n\nmodule Exceptional\n  class << self\n    include Exceptional::Config\n    include Exceptional::Api\n    include Exceptional::Remote\n    include Exceptional::Log\n    include Exceptional::Bootstrap\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/spec/api_spec.rb",
    "content": "require File.dirname(__FILE__) + '/spec_helper'\n\ndescribe Exceptional::Api do\n  describe \"with no configuration\" do\n    before(:each) do\n      Exceptional.stub!(:to_stderr) # Don't print error when testing\n    end\n\n    after(:each) do\n      Exceptional.api_key= nil\n    end\n\n    it \"should connect to getexceptional.com by default\" do\n      Exceptional.remote_host.should == \"getexceptional.com\"\n    end\n\n    it \"should connect to port 80 by default\" do\n      Exceptional.remote_port.should == 80\n    end\n\n    it \"should parse exception into exception data object\" do\n      exception = mock(Exception, :message => \"Something bad has happened\",\n                       :backtrace => [\"/app/controllers/buggy_controller.rb:29:in `index'\"])\n      exception_data = Exceptional::ExceptionData.new(exception)\n      exception_data.kind_of?(Exceptional::ExceptionData).should be_true\n      exception_data.exception_message.should == exception.message\n      exception_data.exception_backtrace.should == exception.backtrace\n      exception_data.exception_class.should == exception.class.to_s\n    end\n\n    it \"should post exception\" do\n      exception_data = mock(Exceptional::ExceptionData,\n                            :message => \"Something bad has happened\",\n                            :backtrace => [\"/app/controllers/buggy_controller.rb:29:in `index'\"],\n                            :class => Exception, :to_hash => { :message => \"Something bad has happened\" })\n      Exceptional.api_key = \"TEST_API_KEY\"\n      Exceptional.should_receive(:authenticate).once.and_return(true)\n      Exceptional.should_receive(:call_remote, :with => [:errors, exception_data]).once\n      Exceptional.post(exception_data)\n    end\n\n    it \"should catch exception\" do\n      exception = mock(Exception, :message => \"Something bad has happened\",\n                       :backtrace => [\"/app/controllers/buggy_controller.rb:29:in `index'\"])\n\n      exception_data = mock(Exceptional::ExceptionData,\n                            :message => \"Something bad has happened\",\n                            :backtrace => [\"/app/controllers/buggy_controller.rb:29:in `index'\"],\n                            :class => Exception, :to_hash => { :message => \"Something bad has happened\" })\n      exception_data.should_receive(:controller_name=).with(File.basename($0))\n\n      Exceptional::ExceptionData.should_receive(:new).with(exception).and_return(exception_data)\n      Exceptional.should_receive(:post, :with => [exception_data])\n\n      Exceptional.catch(exception)\n    end\n\n    it \"should raise a license exception if api key is not set\" do\n      exception_data = mock(Exceptional::ExceptionData,\n                            :message => \"Something bad has happened\",\n                            :backtrace => [\"/app/controllers/buggy_controller.rb:29:in `index'\"],\n                            :class => Exception,\n                            :to_hash => { :message => \"Something bad has happened\" })\n      Exceptional.api_key.should == nil\n      lambda { Exceptional.post(exception_data) }.should raise_error(Exceptional::Config::ConfigurationException)\n    end\n  end\n\n  describe \"rescue\" do\n    it \"should send exception data onto catch\" do\n      Exceptional.should_receive(:catch)\n      lambda{ Exceptional.rescue do\n        raise IOError\n      end}.should raise_error(IOError)\n    end\n  end\n\n  describe \"handle\" do\n    before(:each) do\n      Exceptional.stub!(:to_stderr) # Don't print error when testing\n      Exceptional.stub!(:log!) # Don't even attempt to log\n    end\n\n    it \"should send exception data onto post\" do\n      exception = mock(Exception, :message => \"Something bad has happened\",\n                       :backtrace => \"/app/controllers/buggy_controller.rb:29:in `index'\")\n\n      controller = mock(\"controller\", :controller_name => \"Test Controller Name\", :action_name => \"Test Action Name\")\n\n      class SessionHelper\n        def initialize\n          @some_var = 1\n          @cgi_var = 2\n          @x_db = 3\n        end\n      end\n\n      request = mock(\"request\", :env => {\"key1\" => \"val1\"}, :protocol => \"http\", :host => \"getexceptional.com\", :request_uri => \"/path/to/resource\", :session => SessionHelper.new)\n\n      Exceptional.should_receive(:post_exception).once\n      Exceptional.handle(exception, controller, request, {:clients => {:name => \"bar\"}})\n    end\n  end\n\n  describe \"with helper methods\" do\n\n    it \"safe_environment() should delete all rack related stuff from environment\" do\n      request = mock(request, :env => { 'rack_var' => 'value', 'non_ack' => 'value2' })\n      Exceptional.send(:safe_environment, request).should == { 'non_ack' => 'value2' }\n    end\n\n    it \"safe_environment() should handle array type parameters\" do\n\n      request = mock(request, :env => {\n              'string_array_var' => ['value', 'another value'],\n              'bool_array_var' => [false, false, true],\n              'numb_array_var' => [3, 2, 1],\n              'nil_array_var' => [nil, nil],\n              'non_ack' => 'value2' }\n      )\n      Exceptional.send(:safe_environment, request).should == {\n              'string_array_var' => ['value', 'another value'],\n              'bool_array_var' => [false, false, true],\n              'numb_array_var' => [3, 2, 1],\n              'nil_array_var' => [nil, nil],\n              'non_ack' => 'value2' }\n\n    end\n\n    it \"safe_session() should handle array type parameters\" do\n      mock_session = mock(\"session\")\n      mock_session.should_receive(:instance_variables).and_return(['var1', 'var2'])\n      mock_session.should_receive(:instance_variable_get).with('var1').and_return(['value', 'another value'])\n      mock_session.should_receive(:instance_variable_get).with('var2').and_return('value2')\n      Exceptional.send(:safe_session, mock_session).should == { 'var1' => ['value', 'another value'], 'var2' => 'value2' }\n    end\n\n    it \"safe_session() should filter all /db/, /cgi/ variables and sub @ for blank\" do\n      class SessionHelper\n        def initialize\n          @some_var = 1\n          @cgi_var = 2\n          @x_db = 3\n        end\n      end\n\n      session = SessionHelper.new\n      Exceptional.send(:safe_session, session).should == { 'some_var' => 1 }\n    end\n\n    class ClassWithCircularReferenceToHash\n      def initialize\n        @test = self\n      end\n\n      def to_hash\n        { :test => self }\n      end\n    end\n\n    it \"sanitize_hash() should sanitize cyclic problem for to_json\" do\n      circular = ClassWithCircularReferenceToHash.new\n\n      lambda { circular.to_json }.should raise_error\n      Exceptional.send(:sanitize_hash, circular.to_hash).to_json.should == \"{}\"\n    end\n\n    it \"sanitize_hash() should sanitize cyclic problem for to_json passing hash\" do\n      circular = ClassWithCircularReferenceToHash.new\n\n      lambda { circular.to_json }.should raise_error\n      Exceptional.send(:sanitize_hash, {'hkey' => circular}).to_json.should == \"{}\"\n    end\n\n    it \"sanitize_hash() should sanitize cyclic problem for to_json passing hash mult params\" do\n      circular = ClassWithCircularReferenceToHash.new\n\n      lambda { circular.to_json }.should raise_error\n      Exceptional.send(:sanitize_hash, {'hkey' => circular, 'ruby' => 'tuesday'}).should == {'ruby' => 'tuesday'}\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/exceptional/spec/bootstrap_spec.rb",
    "content": "require File.dirname(__FILE__) + '/spec_helper'\n\ndescribe Exceptional::Bootstrap do\n  describe \"setup\" do\n    TEST_ENVIRONMENT= \"development\"\n\n    it \"should initialize the config and log\" do\n      Exceptional.should_receive(:setup_config)\n      Exceptional.should_receive(:setup_log)\n\n      Exceptional.bootstrap(TEST_ENVIRONMENT, File.dirname(__FILE__))\n    end\n\n    it \"should authenticate if enabled\" do\n      Exceptional.should_receive(:setup_config)\n      Exceptional.should_receive(:setup_log)\n      Exceptional.should_receive(:enabled?).and_return(true)\n      Exceptional.should_receive(:authenticate).and_return(true)\n      STDERR.should_not_receive(:puts) #Should be no errors to report\n\n      Exceptional.bootstrap(TEST_ENVIRONMENT, File.dirname(__FILE__))\n    end\n\n    it \"should not authenticate if not enabled\" do\n      Exceptional.should_receive(:setup_config)\n      Exceptional.should_receive(:setup_log)\n      Exceptional.should_receive(:enabled?).and_return(false)\n      Exceptional.should_not_receive(:authenticate)\n      STDERR.should_not_receive(:puts) # Will silently not enable itself\n\n      Exceptional.bootstrap(TEST_ENVIRONMENT, File.dirname(__FILE__))\n    end\n\n    it \"should report to STDERR if authentication fails\" do\n      Exceptional.should_receive(:setup_config)\n      Exceptional.should_receive(:setup_log)\n      Exceptional.should_receive(:enabled?).and_return(true)\n      Exceptional.should_receive(:authenticate).and_return(false)\n      STDERR.should_receive(:puts) #Should be no errors to report\n\n      Exceptional.bootstrap(TEST_ENVIRONMENT, File.dirname(__FILE__))\n    end\n\n    it \"should report to STDERR if error during config initialization\" do\n      Exceptional.should_receive(:setup_config).and_raise(Exceptional::Config::ConfigurationException)\n      Exceptional.should_not_receive(:setup_log)\n      Exceptional.should_not_receive(:authenticate).and_return(false)\n      STDERR.should_receive(:puts).twice() #Should be no errors to report\n\n      Exceptional.bootstrap(TEST_ENVIRONMENT, File.dirname(__FILE__))\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/spec/config_spec.rb",
    "content": "require File.dirname(__FILE__) + '/spec_helper'\n\ndescribe Exceptional::Config do\n  before(:all) do\n    def Exceptional.reset_state\n      @api_key = nil\n      @ssl_enabled = nil\n      @log_level = nil\n      @enabled = nil\n      @remote_port = nil\n      @remote_host = nil\n      @applicaton_root = nil\n    end\n  end\n\n  after(:each) do\n    Exceptional.reset_state\n  end\n  \n  before(:each) do\n    Exceptional.stub!(:log!) # Don't even attempt to log\n    Exceptional.stub!(:to_log)  \n  end\n  \n  describe \"default configuration\" do\n    it \"should use port 80 by default if ssl not enabled\" do\n      Exceptional.ssl_enabled?.should be_false\n      Exceptional.remote_port.should == 80\n    end\n\n    it \"should use port 443 if ssl enabled\" do\n      Exceptional.ssl_enabled= true\n      Exceptional.remote_port.should == 443\n      Exceptional.ssl_enabled= false\n    end\n\n    it \"should use log level of info by default\" do\n      Exceptional.log_level.should == \"info\"\n    end\n\n    it \"should not be enabled by default\" do\n      Exceptional.enabled?.should be_false\n    end\n\n    it \"should overwrite default host\" do\n      Exceptional.remote_host.should == \"getexceptional.com\"\n      Exceptional.remote_host = \"localhost\"\n      Exceptional.remote_host.should == \"localhost\"\n    end\n\n    it \"should overwrite default port\" do\n      Exceptional.remote_port.should == 80\n\n      Exceptional.remote_port = 3000\n      Exceptional.remote_port.should == 3000\n      Exceptional.remote_port = nil\n    end\n    \n    it \"api_key should by default be in-valid\" do\n      Exceptional.valid_api_key?.should be_false\n    end    \n  end\n\n  describe \"load config\" do\n    it \"error during config file loading raises configuration exception\" do\n      File.should_receive(:open).once.and_raise(IOError)\n      \n      lambda{Exceptional.setup_config(\"development\", File.dirname(__FILE__))}.should raise_error(Exceptional::Config::ConfigurationException)\n    end\n\n    it \"is enabled for production environment\" do\n      Exceptional.enabled?.should be_false\n\n      Exceptional.setup_config \"production\", File.join(File.dirname(__FILE__), \"/../exceptional.yml\")\n      Exceptional.enabled?.should be_true\n    end\n\n    it \"is enabled by default for production and staging environments\" do\n      Exceptional.enabled?.should be_false\n\n      Exceptional.setup_config \"production\", File.join(File.dirname(__FILE__), \"/../exceptional.yml\")\n      Exceptional.enabled?.should be_true\n\n      Exceptional.reset_state\n      Exceptional.enabled?.should be_false\n\n      Exceptional.setup_config \"staging\", File.join(File.dirname(__FILE__), \"/../exceptional.yml\")\n      Exceptional.enabled?.should be_true\n    end\n\n    it \"is disabled by default for development & test environments\" do\n      Exceptional.enabled?.should be_false\n\n      Exceptional.setup_config \"development\", File.join(File.dirname(__FILE__), \"/../exceptional.yml\")\n      Exceptional.enabled?.should be_false\n\n      Exceptional.reset_state\n      Exceptional.enabled?.should be_false\n\n      Exceptional.setup_config \"test\", File.join(File.dirname(__FILE__), \"/../exceptional.yml\")\n      Exceptional.enabled?.should be_false\n    end            \n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/spec/exception_data_spec.rb",
    "content": "require File.dirname(__FILE__) + '/spec_helper'\n\ndescribe Exceptional::ExceptionData do\n  describe \"with valid base data\" do\n    before(:each) do\n      exception = mock('Exception', :backtrace => \"/var/www/app/fail.rb:42 Error('There was an error')\", :message => \"There was an error\", :class => 'Error')\n      @exception_data = Exceptional::ExceptionData.new(exception)\n    end\n    \n    it \"language should be ruby\" do\n      @exception_data.language.should == \"ruby\"\n    end\n    \n    it \"should be valid\" do\n      @exception_data.should be_valid\n    end\n\n    it \"should convert to hash\" do\n      @exception_data.to_hash.should == {:exception_class => \"Error\", :exception_message => \"There was an error\",\n                                         :exception_backtrace => \"/var/www/app/fail.rb:42 Error('There was an error')\",\n                                         :language => \"ruby\"}\n    end\n        \n    it \"should convert to json\" do\n      @exception_data.to_json.class.should == String\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/spec/exceptional_rescue_from_spec.rb",
    "content": "require File.dirname(__FILE__) + '/spec_helper'\nrequire 'action_controller'\nrequire File.join(File.dirname(__FILE__), '..', 'lib', 'exceptional', 'integration', 'rails')\n\nif ActionController::Base.respond_to?(:rescue_from)\n  # pre 2.0 versions of rails don't have rescue_from so there's no contention\n  class MyException < Exception;end\n  class SpecialException < Exception;end\n\n  class RescueFromController < ActionController::Base\n    rescue_from MyException, :with => :my_handler\n\n    def my_handler\n      true\n    end\n  end\n\n  describe \"Exceptional with rescue_from() support\" do\n    before(:each) do\n      @controller = RescueFromController.new\n    end\n\n    it \"should not call Exceptional\" do\n      @controller.should_receive(:rescue_action_without_exceptional).and_return(true)\n      if Gem::Requirement.create(\">=2.2.0\").satisfied_by?(Gem.loaded_specs['rails'].version)\n        Exceptional.should_not_receive(:handle)\n      else\n        Exceptional.should_receive(:handle)\n      end\n      @controller.send(:rescue_action, MyException.new(\"test\")).should == true\n    end\n\n    it \"should call Exceptional\" do\n      Exceptional.should_receive(:handle)\n      @controller.should_receive(:rescue_action_without_exceptional).and_return(true)\n      @controller.send(:rescue_action, SpecialException.new(\"test\")).should == true\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/spec/exceptional_spec.rb",
    "content": "require File.dirname(__FILE__) + '/spec_helper'\n\ndescribe Exceptional do\n  describe \"with no configuration\" do\n    before(:each) do\n      Exceptional.stub!(:to_stderr) # Don't print error when testing\n    end\n\n    it \"should raise a remoting exception if not authenticated\" do\n      exception_data = mock(Exceptional::ExceptionData,\n      :message => \"Something bad has happened\",\n      :backtrace => [\"/app/controllers/buggy_controller.rb:29:in `index'\"],\n      :class => Exception,\n      :to_hash => { :message => \"Something bad has happened\" })\n\n      Exceptional.api_key.should == nil\n      Exceptional.should_receive(:authenticated?).once.and_return(false)\n\n      lambda { Exceptional.post_exception(exception_data) }.should raise_error(Exceptional::Config::ConfigurationException)\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/exceptional/spec/log_spec.rb",
    "content": "require File.dirname(__FILE__) + '/spec_helper'\n\ndescribe Exceptional::Log do\n\n  TEST_LOG_MESSAGE = \"Test-log-message\"\n\n  it \"uninitialized should only log to STDERR\" do\n    STDERR.should_receive(:puts)\n    Logger.should_not_receive(:send)\n    Exceptional.log! TEST_LOG_MESSAGE\n  end\n\n  it \"initialized should log to both STDERR and log file\" do\n    mock_log = mock(\"log\")\n    mock_log.should_receive(:level=)\n    \n    Logger.should_receive(:new).and_return(mock_log)\n\n    Exceptional.setup_log File.dirname(File.join(File.dirname(__FILE__), \"..\"))\n    \n    Exceptional.log.should_receive(:send).with(\"info\", TEST_LOG_MESSAGE)\n    STDERR.should_receive(:puts)\n\n    Exceptional.log! TEST_LOG_MESSAGE\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/exceptional/spec/remote_spec.rb",
    "content": "require File.dirname(__FILE__) + '/spec_helper'\nrequire 'net/http'\n\ndescribe Exceptional::Remote do\n\n  TEST_API_KEY = \"TEST_API_KEY\"\n\n  before(:all) do\n    def Exceptional.reset_state\n      @api_key = nil\n      @ssl_enabled = nil\n      @log_level = nil\n      @enabled = nil\n      @remote_port = nil\n      @remote_host = nil\n      @applicaton_root = nil\n    end\n\n    def Exceptional.reset_authentication\n      @authenticated = false\n    end\n  end\n\n  after(:each) do\n    Exceptional.reset_state\n    Exceptional.reset_authentication\n  end\n\n  describe \"authentication\" do\n    it \"should not be authenticated if API authentication unsuccessful\" do\n      Exceptional.api_key = TEST_API_KEY\n\n      Exceptional.authenticated?.should be_false\n      Exceptional.should_receive(:call_remote, {:method => \"authenticate\", :data => \"\"}).once.and_return(\"false\")\n      Exceptional.authenticate.should be_false\n      Exceptional.authenticated?.should be_false\n    end\n\n    it \"should not be authenticated if error during API authenticate\" do\n      Exceptional.api_key = TEST_API_KEY\n\n      Exceptional.authenticated?.should be_false\n      Exceptional.should_receive(:call_remote, {:method => \"authenticate\", :data => \"\"}).once.and_raise(IOError)\n\n      Exceptional.authenticate.should be_false\n      Exceptional.authenticated?.should be_false\n    end\n\n    it \"should not re-authenticate subsequently if 1 successful \" do\n      Exceptional.api_key = TEST_API_KEY\n\n      Exceptional.authenticated?.should be_false\n      Exceptional.should_receive(:call_remote, {:method => \"authenticate\", :data => \"\"}).once.and_return(\"true\")\n      # If authentication is successful, authenticate called only once\n\n      Exceptional.authenticate.should be_true\n      Exceptional.authenticated?.should be_true\n\n      Exceptional.authenticate.should be_true\n      Exceptional.authenticated?.should be_true\n    end\n\n    it \"with no API Key set throws Configuration Exception\" do\n      Exceptional.authenticated?.should be_false\n\n      lambda {Exceptional.authenticate}.should raise_error(Exceptional::Config::ConfigurationException)\n    end\n  end\n\n  describe \"sending data \" do\n    it \"should return response body if successful\" do\n      OK_RESPONSE_BODY = \"OK-RESP-BODY\"\n      \n      Exceptional.api_key = TEST_API_KEY\n      Exceptional.authenticated?.should be_false\n\n      Exceptional.should_receive(:authenticated?).once.and_return(true)\n\n      mock_http = mock(Net::HTTP)\n      Net::HTTP.should_receive(:new).with(\"getexceptional.com\", 80).once.and_return(mock_http)\n\n      mock_http_response= mock(Net::HTTPSuccess)\n      mock_http_response.should_receive(:kind_of?).with(Net::HTTPSuccess).once.and_return(true)\n      mock_http_response.should_receive(:body).once.and_return(OK_RESPONSE_BODY)\n\n      mock_http.should_receive(:start).once.and_return(mock_http_response)\n\n      Exceptional.post_exception(\"data\").should == OK_RESPONSE_BODY\n    end\n    \n    it \"should raise error if network problem during sending exception\" do\n      Exceptional.api_key = TEST_API_KEY\n      Exceptional.authenticated?.should be_false\n\n      Exceptional.should_receive(:authenticated?).once.and_return(true)\n\n      mock_http = mock(Net::HTTP)\n      Net::HTTP.should_receive(:new).with(\"getexceptional.com\", 80).once.and_return(mock_http)\n\n      mock_http_response= mock(Net::HTTPSuccess)\n\n      mock_http.should_receive(:start).once.and_raise(IOError)\n\n      #surpress the logging of the exception\n      Exceptional.should_receive(:log!).twice\n\n      lambda{Exceptional.post_exception(\"data\")}.should raise_error(IOError) \n    end\n\n    it \"should raise Exception if sending exception unsuccessful\" do\n      Exceptional.api_key = TEST_API_KEY\n      Exceptional.authenticated?.should be_false\n\n      Exceptional.should_receive(:authenticated?).once.and_return(true)\n\n      mock_http = mock(Net::HTTP)\n      Net::HTTP.should_receive(:new).with(\"getexceptional.com\", 80).once.and_return(mock_http)\n\n      mock_http_response= mock(Net::HTTPInternalServerError)\n      mock_http_response.should_receive(:kind_of?).with(Net::HTTPSuccess).once.and_return(false)\n      mock_http_response.should_receive(:code).once.and_return(501)\n      mock_http_response.should_receive(:message).once.and_return(\"Internal Server Error\")\n\n      mock_http.should_receive(:start).once.and_return(mock_http_response)\n\n      #surpress the logging of the exception\n      Exceptional.should_receive(:log!).twice\n\n      lambda{Exceptional.post_exception(\"data\")}.should raise_error(Exceptional::Remote::RemoteException) \n    end    \n  end\nend\n"
  },
  {
    "path": "vendor/plugins/exceptional/spec/spec_helper.rb",
    "content": "require 'rubygems'\nbegin\n  require 'ginger'\nrescue LoadError\nend\n\ngem 'rails'\nrequire File.dirname(__FILE__) + '/../lib/exceptional'"
  },
  {
    "path": "vendor/plugins/googlecharts/History.txt",
    "content": "== 1.3.6\n* support nil values. The Google Charts API specifies that a single underscore (_) can be used to omit a value from a line chart with 'simple' data encoding, and a double underscore (__) can do the same for a chart with 'extended' data encoding. (Matt Moyer)\n* allow a label to appear on a google-o-meter via the :legend option. (hallettj)\n\n== 1.3.5\n* added code to properly escape image tag URLs (mokolabs)\n* added themes support + 4 default themes (keynote, thirty7signals, pastel, greyscale) chart.line(:theme=>:keynote) (jakehow)\n\n== 1.3.4\n* updated documentation and cleaned it up (mokolabs)\n* added support for custom class, id and alt tags when using the image_tag format (i.e Gchart.line(:data => [0, 26], :format => 'image_tag')) (mokolabs)\n\n== 1.3.2 - 1.3.3\n* changes required by github\n\n== 1.3.1\n* added width and spacing options\n\n== 1.3.0\n* added support for google-o-meter\n* fixed a bug when the max value of a data set was 0\n\n== 1.2.0\n* added support for sparklines\n\n== 1.1.0\n* fixed another bug fix related to the uri escaping required to download the file properly.\n\n== 1.0.0\n* fixed the (URI::InvalidURIError) issue\n\n== 0.2.0\n* added export options (file and image tag)\n* added support for all arguments to be passed as a string or an array\n\n== 0.1.0 2007-12-11\n* fixed the axis labels\n\n== 0.0.3 2007-12-11\n* added :chart_background alias and fixed a bug related to the background colors.\n\n== 0.0.2 2007-12-11\n* added support for more features and aliases\n\n== 0.0.1 2007-12-08\n\n* 1 major enhancement:\n  * Initial release\n"
  },
  {
    "path": "vendor/plugins/googlecharts/License.txt",
    "content": "Copyright (c) 2007 Matt Aimonetti\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "vendor/plugins/googlecharts/Manifest.txt",
    "content": "History.txt\nLicense.txt\nManifest.txt\nREADME.txt\nRakefile\nconfig/hoe.rb\nconfig/requirements.rb\nlib/gchart.rb\nlib/gchart/aliases.rb\nlib/gchart/theme.rb\nlib/gchart/version.rb\nsetup.rb\nspec/gchart_spec.rb\nspec/theme_spec.rb\nspec/spec.opts\nspec/spec_helper.rb\ntasks/environment.rake\ntasks/rspec.rake\n"
  },
  {
    "path": "vendor/plugins/googlecharts/README",
    "content": ""
  },
  {
    "path": "vendor/plugins/googlecharts/README.markdown",
    "content": "The goal of this Gem is to make the creation of Google Charts a simple and easy task.\n\n    Gchart.line(  :size => '200x300', \n                  :title => \"example title\",\n                  :bg => 'efefef',\n                  :legend => ['first data set label', 'second data set label'],\n                  :data => [10, 30, 120, 45, 72])\n              \n\nCheck out the [full documentation over there](http://googlecharts.rubyforge.org/)\n\nThis gem is fully tested using Rspec, check the rspec folder for more examples.\n\nSee at the bottom of this file who reported using this gem.\n\nChart Type\n-------------\n\nThis gem supports the following types of charts:\n  \n  * line, \n  * line_xy\n  * sparkline\n  * scatter\n  * bar\n  * venn\n  * pie\n  * pie_3d\n  * google meter\n  \nGooglecharts also supports graphical themes and you can easily load your own.\n\nTo create a chart, simply require Gchart and call any of the existing type:\n\n    require 'gchart'\n    Gchart.pie\n  \n  \nChart Title\n-------------\n\n  To add a title to a chart pass the title to your chart:\n  \n    Gchart.line(:title => 'Sexy Charts!')\n    \nYou can also specify the color and/or size\n    \n    Gchart.line(:title => 'Sexy Charts!', :title_color => 'FF0000', :title_size => '20')\n\nColors\n-------------\n\nSpecify a color with at least a 6-letter string of hexadecimal values in the format RRGGBB. For example:\n\n    * FF0000 = red\n    * 00FF00 = green\n    * 0000FF = blue\n    * 000000 = black\n    * FFFFFF = white\n\nYou can optionally specify transparency by appending a value between 00 and FF where 00 is completely transparent and FF completely opaque. For example:\n\n    * 0000FFFF = solid blue\n    * 0000FF00 = transparent blue\n\nIf you need to use multiple colors, check the doc. Usually you just need to pass :attribute => 'FF0000,00FF00'\n\nSome charts have more options than other, make sure to refer to the documentation.\n\nBackground options:\n-------------\n\nIf you don't set the background option, your graph will be transparent.\n\n* You have 3 types of background  http://code.google.com/apis/chart/#chart_or_background_fill\n\n- solid\n- gradient\n- stripes\n\nBy default, if you set a background color, the fill will be solid:\n\n    Gchart.bar(:bg => 'efefef')\n\nHowever you can specify another fill type such as:\n            \n    Gchart.line(:bg => {:color => 'efefef', :type => 'gradient'})\n  \nIn the above code, we decided to have a gradient background, however since we only passed one color, the chart will start by the specified color and transition to white. By the default, the gradient angle is 0. Change it as follows:\n\n    Gchart.line(:title =>'bg example', :bg => {:color => 'efefef', :type => 'gradient', :angle => 90})\n    \nFor a more advance use of colors, refer to http://code.google.com/apis/chart/#linear_gradient\n\n    Gchart.line(:bg => {:color => '76A4FB,1,ffffff,0', :type => 'gradient'})\n    \n    \nThe same way you set the background color, you can also set the graph background:\n\n    Gchart.line(:graph_bg => 'cccccc')\n    \nor both\n\n    Gchart.line(:bg => {:color => '76A4FB,1,ffffff,0', :type => 'gradient'}, :graph_bg => 'cccccc', :title => 'Sexy Chart')\n    \n    \nAnother type of fill is stripes http://code.google.com/apis/chart/#linear_stripes\n\n    Gchart.line(:bg => {:color => 'efefef', :type => 'stripes'})\n    \nYou can customize the amount of stripes, colors and width by changing the color value.\n\n\nThemes\n--------\n\n  Googlecharts comes with 4 themes: keynote, thirty7signals, pastel and greyscale. (ganked from [Gruff](http://github.com/topfunky/gruff/tree/master)\n\n\n    Gchart.line(\n                :theme => :keynote, \n                :data => [[0,40,10,70,20],[41,10,80,50,40],[20,60,30,60,80],[5,23,35,10,56],[80,90,5,30,60]], \n                :title => 'keynote'\n                )\n\n  * keynote\n\n    ![keynote](http://chart.apis.google.com/chart?chtt=keynote&chco=6886B4,FDD84E,72AE6E,D1695E,8A6EAF,EFAA43&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo&chf=c,s,FFFFFF|bg,s,000000)\n\n  * thirty7signals\n\n    ![37signals](http://chart.apis.google.com/chart?chtt=thirty7signals&chco=FFF804,336699,339933,ff0000,cc99cc,cf5910&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo&chf=bg,s,FFFFFF)\n\n  * pastel\n\n    ![pastel](http://chart.apis.google.com/chart?chtt=pastel&chco=a9dada,aedaa9,daaea9,dadaa9,a9a9da&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo)\n\n  * greyscale\n\n    ![greyscale](http://chart.apis.google.com/chart?chtt=greyscale&chco=282828,383838,686868,989898,c8c8c8,e8e8e8&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo)\n\n\nYou can also use your own theme. Create a yml file using the same format as the themes located in lib/themes.yml\n\nLoad your theme(s):\n\n      Chart::Theme.add_theme_file(\"#{File.dirname(__FILE__)}/fixtures/another_test_theme.yml\")\n\nAnd use the standard method signature to use your own theme:\n\n      Gchart.line(:theme => :custom_theme, :data => [[0, 40, 10, 70, 20],[41, 10, 80, 50]], :title => 'greyscale')\n\n    \n    \nLegend & Labels\n-------------\n\nYou probably will want to use a legend or labels for your graph.\n\n    Gchart.line(:legend => 'legend label')\nor\n    Gchart.line(:legend => ['legend label 1', 'legend label 2'])\n    \nWill do the trick. You can also use the labels alias (makes more sense when using the pie charts)\n\n    chart = Gchart.pie(:labels => ['label 1', 'label 2'])\n\nMultiple axis labels \n-------------\n\nMultiple axis labels are available for line charts, bar charts and scatter plots.\n\n* x = bottom x-axis\n* t = top x-axis\n* y = left y-axis\n* r = right y-axis\n\n    Gchart.line(:label_axis => 'x,y,r')\n  \nTo add labels on these axis:\n\n    Gchart.line(:axis_labels => ['Jan|July|Jan|July|Jan', '0|100', 'A|B|C', '2005|2006|2007'])\n\n    \nData options\n-------------\n\nData are passed using an array or a nested array.    \n\n    Gchart.bar(:data => [1,2,4,67,100,41,234])  \n  \n    Gchart.bar(:data => [[1,2,4,67,100,41,234],[45,23,67,12,67,300, 250]])\n  \nBy default, the graph is drawn with your max value representing 100% of the height or width of the graph. You can change that my passing the max value.\n\n    Gchart.bar(:data => [1,2,4,67,100,41,234], :max_value => 300)\n    Gchart.bar(:data => [1,2,4,67,100,41,234], :max_value => 'auto')\n  \nor if you want to use the real values from your dataset:\n\n    Gchart.bar(:data => [1,2,4,67,100,41,234], :max_value => false)\n  \n  \nYou can also define a different encoding to add more granularity:\n\n    Gchart.bar(:data => [1,2,4,67,100,41,234], :encoding => 'simple') \n    Gchart.bar(:data => [1,2,4,67,100,41,234], :encoding => 'extended') \n    Gchart.bar(:data => [1,2,4,67,100,41,234], :encoding => 'text') \n  \n\nPies:\n-------------\n  \nyou have 2 type of pies:\n  - Gchart.pie() the standard 2D pie\n  _ Gchart.pie_3d() the fancy 3D pie\n  \nTo set labels, you can use one of these two options:\n\n    @legend = ['Matt_fu', 'Rob_fu']\n    Gchart.pie_3d(:title => @title, :labels => @legend, :data => @data, :size => '400x200')\n    Gchart.pie_3d(:title => @title, :legend => @legend, :data => @data, :size => '400x200')\n  \nBars:\n-------------\n\nA bar chart can accept options to set the width of the bars, spacing between bars and spacing between bar groups. To set these, you can either provide a string, array or hash.\n\nThe Google API sets these options in the order of width, spacing, and group spacing, with both spacing values being optional. So, if you provide a string or array, provide them in that order:\n\n    Gchart.bar(:data => @data, :bar_width_and_spacing => '25,6') # width of 25, spacing of 6\n    Gchart.bar(:data => @data, :bar_width_and_spacing => '25,6,12') # width of 25, spacing of 6, group spacing of 12\n    Gchart.bar(:data => @data, :bar_width_and_spacing => [25,6]) # width of 25, spacing of 6\n    Gchart.bar(:data => @data, :bar_width_and_spacing => 25) # width of 25\n  \nThe hash lets you set these values directly, with the Google default values set for any options you don't include:\n\n    Gchart.bar(:data => @data, :bar_width_and_spacing => {:width => 19})\n    Gchart.bar(:data => @data, :bar_width_and_spacing => {:spacing => 10, :group_spacing => 12})\n\nSparklines:\n-------------\n\nA sparkline chart has exactly the same parameters as a line chart. The only difference is that the axes lines are not drawn for sparklines by default.\n  \n\nGoogle-o-meter\n-------------\n\nA Google-o-meter has a few restrictions. It may only use a solid filled background and it may only have one label.\n\ntry yourself\n-------------\n\n    Gchart.bar( :data => [[1,2,4,67,100,41,234],[45,23,67,12,67,300, 250]], \n                :title => 'SD Ruby Fu level', \n                :legend => ['matt','patrick'], \n                :bg => {:color => '76A4FB', :type => 'gradient'}, \n                :bar_colors => 'ff0000,00ff00')\n\n \"http://chart.apis.google.com/chart?chs=300x200&chdl=matt|patrick&chd=s:AAANUIv,JENCN9y&chtt=SDRuby+Fu+level&chf=bg,lg,0,76A4FB,0,ffffff,1&cht=bvs&chco=ff0000,00ff00\"  \n \n    Gchart.pie(:data => [20,10,15,5,50], :title => 'SDRuby Fu level', :size => '400x200', :labels => ['matt', 'rob', 'patrick', 'ryan', 'jordan'])\nhttp://chart.apis.google.com/chart?cht=p&chs=400x200&chd=s:YMSG9&chtt=SDRuby+Fu+level&chl=matt|rob|patrick|ryan|jordan\n\n\nPeople reported using this gem:\n---------------------\n\n![github](http://img.skitch.com/20080627-r14subqdx2ye3w13qefbx974gc.png)\n\n* [http://github.com](http://github.com) \n\n![stafftool.com](http://stafftool.com/images/masthead_screen.gif)\n\n* [http://stafftool.com/](http://stafftool.com/) Takeo (contributor)\n\n![graffletopia.com](http://img.skitch.com/20080627-g2pp89h7gdbh15m1rr8hx48jep.jpg) \n\n* [graffleropia.com](http://graffletopia.com) Mokolabs (contributor)\n\n![gumgum](http://img.skitch.com/20080627-kc1weqsbkmxeqhwiyriq3n6g8k.jpg)\n\n* [http://gumgum.com](http://gumgum.com) Mattetti (Author)\n\n![http://img.skitch.com/20080627-n48j8pb2r7irsewfeh4yp3da12.jpg]\n\n* [http://feedflix.com/](http://feedflix.com/) [lifehacker article](http://lifehacker.com/395610/feedflix-creates-detailed-charts-from-your-netflix-use)\n\n* [California State University, Chico](http://www.csuchico.edu/)"
  },
  {
    "path": "vendor/plugins/googlecharts/README.txt",
    "content": "CHECK README.markdown  (open as a text file)\n\nOr check:\n\n  http://googlecharts.rubyforge.org\n\nand/or \n\n  http://github.com/mattetti/googlecharts"
  },
  {
    "path": "vendor/plugins/googlecharts/Rakefile",
    "content": "require 'rubygems'  \nrequire 'rake'\n\nbegin  \n  require 'jeweler'  \n  Jeweler::Tasks.new do |gemspec|  \n    gemspec.name = \"googlecharts\"  \n    gemspec.summary = \"Generate charts using Google API & Ruby\"  \n    gemspec.description = \"Generate charts using Google API & Ruby\"  \n    gemspec.email = \"mattaimonetti@gmail.com\"  \n    gemspec.homepage = \"http://googlecharts.rubyforge.org/\"  \n    gemspec.authors = [\"Matt Aimonetti\"]  \n  end \n  Jeweler::GemcutterTasks.new \nrescue LoadError  \n  puts \"Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com\"  \nend  \n  \nDir[\"#{File.dirname(__FILE__)}/tasks/*.rake\"].sort.each { |ext| load ext }\n\n"
  },
  {
    "path": "vendor/plugins/googlecharts/VERSION",
    "content": "1.5.1\n"
  },
  {
    "path": "vendor/plugins/googlecharts/config/hoe.rb",
    "content": "require 'gchart/version'\n\nAUTHOR = 'Matt Aimonetti'  # can also be an array of Authors\nEMAIL = \"mattaimonetti@gmail.com\"\nDESCRIPTION = \"description of gem\"\nGEM_NAME = 'googlecharts' # what ppl will type to install your gem\nRUBYFORGE_PROJECT = 'googlecharts' # The unix name for your project\nHOMEPATH = \"http://#{RUBYFORGE_PROJECT}.rubyforge.org\"\nDOWNLOAD_PATH = \"http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}\"\n\n@config_file = \"~/.rubyforge/user-config.yml\"\n@config = nil\nRUBYFORGE_USERNAME = \"matt_a\"\ndef rubyforge_username\n  unless @config\n    begin\n      @config = YAML.load(File.read(File.expand_path(@config_file)))\n    rescue\n      puts <<-EOS\nERROR: No rubyforge config file found: #{@config_file}\nRun 'rubyforge setup' to prepare your env for access to Rubyforge\n - See http://newgem.rubyforge.org/rubyforge.html for more details\n      EOS\n      exit\n    end\n  end\n  RUBYFORGE_USERNAME.replace @config[\"username\"]\nend\n\n\nREV = nil \n# UNCOMMENT IF REQUIRED: \n# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil\nVERS = GchartInfo::VERSION::STRING + (REV ? \".#{REV}\" : \"\")\nRDOC_OPTS = ['--quiet', '--title', 'gchart documentation',\n    \"--opname\", \"index.html\",\n    \"--line-numbers\", \n    \"--main\", \"README\",\n    \"--inline-source\"]\n\nclass Hoe\n  def extra_deps \n    @extra_deps.reject! { |x| Array(x).first == 'hoe' } \n    @extra_deps\n  end \nend\n\n# Generate all the Rake tasks\n# Run 'rake -T' to see list of generated tasks (from gem root directory)\nhoe = Hoe.new(GEM_NAME, VERS) do |p|\n  p.author = AUTHOR \n  p.description = DESCRIPTION\n  p.email = EMAIL\n  p.summary = DESCRIPTION\n  p.url = HOMEPATH\n  p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT\n  p.test_globs = [\"test/**/test_*.rb\"]\n  p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']  #An array of file patterns to delete on clean.\n  \n  # == Optional\n  p.changes = p.paragraphs_of(\"History.txt\", 0..1).join(\"\\n\\n\")\n  #p.extra_deps = []     # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]\n  \n  #p.spec_extras = {}    # A hash of extra values to set in the gemspec.\n  \nend\n\nCHANGES = hoe.paragraphs_of('History.txt', 0..1).join(\"\\\\n\\\\n\")\nPATH    = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : \"#{RUBYFORGE_PROJECT}/#{GEM_NAME}\"\nhoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\\/?/,''), 'rdoc')\nhoe.rsync_args = '-av --delete --ignore-errors'"
  },
  {
    "path": "vendor/plugins/googlecharts/config/requirements.rb",
    "content": "require 'fileutils'\ninclude FileUtils\n\nrequire 'rubygems'\n%w[rake hoe newgem rubigen].each do |req_gem|\n  begin\n    require req_gem\n  rescue LoadError\n    puts \"This Rakefile could use '#{req_gem}' RubyGem.\"\n    puts \"Installation: gem install #{req_gem} -y\"\n  end\nend\n\n$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))\n\nrequire 'gchart'"
  },
  {
    "path": "vendor/plugins/googlecharts/lib/gchart/aliases.rb",
    "content": "class Gchart\n  \n  alias_method :background=, :bg=\n  alias_method :chart_bg=, :graph_bg=\n  alias_method :chart_color=, :graph_bg=\n  alias_method :chart_background=, :graph_bg=\n  alias_method :bar_color=, :bar_colors=\n  alias_method :line_colors=, :bar_colors=\n  alias_method :line_color=, :bar_colors=\n  alias_method :labels=, :legend=\n  alias_method :horizontal?, :horizontal\n  alias_method :grouped?, :grouped\n\nend"
  },
  {
    "path": "vendor/plugins/googlecharts/lib/gchart/tasks/deployment.rake",
    "content": "desc 'Release the website and new gem version'\ntask :deploy => [:check_version, :website, :release] do\n  puts \"Remember to create SVN tag:\"\n  puts \"svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk \" +\n    \"svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} \"\n  puts \"Suggested comment:\"\n  puts \"Tagging release #{CHANGES}\"\nend\n\ndesc 'Runs tasks website_generate and install_gem as a local deployment of the gem'\ntask :local_deploy => [:website_generate, :install_gem]\n\ntask :check_version do\n  unless ENV['VERSION']\n    puts 'Must pass a VERSION=x.y.z release version'\n    exit\n  end\n  unless ENV['VERSION'] == VERS\n    puts \"Please update your version.rb to match the release version, currently #{VERS}\"\n    exit\n  end\nend\n\ndesc 'Install the package as a gem, without generating documentation(ri/rdoc)'\ntask :install_gem_no_doc => [:clean, :package] do\n  sh \"#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri\"\nend\n\nnamespace :manifest do\n  desc 'Recreate Manifest.txt to include ALL files'\n  task :refresh do\n    `rake check_manifest | patch -p0 > Manifest.txt`\n  end\nend"
  },
  {
    "path": "vendor/plugins/googlecharts/lib/gchart/tasks/environment.rake",
    "content": "task :ruby_env do\n  RUBY_APP = if RUBY_PLATFORM =~ /java/\n    \"jruby\"\n  else\n    \"ruby\"\n  end unless defined? RUBY_APP\nend\n"
  },
  {
    "path": "vendor/plugins/googlecharts/lib/gchart/tasks/rspec.rake",
    "content": "begin\n  require 'spec'\nrescue LoadError\n  require 'rubygems'\n  require 'spec'\nend\nbegin\n  require 'spec/rake/spectask'\nrescue LoadError\n  puts <<-EOS\nTo use rspec for testing you must install rspec gem:\n    gem install rspec\nEOS\n  exit(0)\nend\n\ndesc \"Run the specs under spec/models\"\nSpec::Rake::SpecTask.new do |t|\n  t.spec_opts = ['--options', \"spec/spec.opts\"]\n  t.spec_files = FileList['spec/*_spec.rb']\nend\n"
  },
  {
    "path": "vendor/plugins/googlecharts/lib/gchart/tasks/website.rake",
    "content": "desc 'Generate website files'\ntask :website_generate => :ruby_env do\n  (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|\n    sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }\n  end\nend\n\ndesc 'Upload website files to rubyforge'\ntask :website_upload do\n  host = \"#{rubyforge_username}@rubyforge.org\"\n  remote_dir = \"/var/www/gforge-projects/#{PATH}/\"\n  local_dir = 'website'\n  sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}\nend\n\ndesc 'Generate and upload website files'\ntask :website => [:website_generate, :website_upload, :publish_docs]\n"
  },
  {
    "path": "vendor/plugins/googlecharts/lib/gchart/theme.rb",
    "content": "require 'yaml'\n\nmodule Chart\n  class Theme\n    class ThemeNotFound < RuntimeError; end\n    \n    @@theme_files = [\"#{File.dirname(__FILE__)}/../themes.yml\"]\n\n    attr_accessor :colors\n    attr_accessor :bar_colors\n    attr_accessor :background\n    attr_accessor :chart_background\n    \n    def self.load(theme_name)\n      theme = new(theme_name)\n    end\n    \n    def self.theme_files\n      @@theme_files\n    end\n    \n    # Allows you to specify paths for custom theme files in YAML format\n    def self.add_theme_file(file)\n      @@theme_files << file\n    end\n    \n    def initialize(theme_name)\n      themes = {}\n      @@theme_files.each {|f| themes.update YAML::load(File.open(f))}\n      theme = themes[theme_name]\n      if theme\n        self.colors = theme[:colors]\n        self.bar_colors = theme[:bar_colors]\n        self.background = theme[:background]\n        self.chart_background = theme[:chart_background]\n        self\n      else\n        raise(ThemeNotFound, \"Could not locate the #{theme_name} theme ...\")\n      end\n    end\n    \n    def to_options\n      {:background => background, :chart_background => chart_background, :bar_colors => bar_colors.join(',')}\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/googlecharts/lib/gchart/version.rb",
    "content": "module GchartInfo #:nodoc:\n  module VERSION #:nodoc:\n    MAJOR = 1\n    MINOR = 5\n    TINY  = 1\n\n    STRING = [MAJOR, MINOR, TINY].join('.')\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/googlecharts/lib/gchart.rb",
    "content": "$:.unshift File.dirname(__FILE__)\nrequire 'gchart/version'\nrequire 'gchart/theme'\nrequire \"open-uri\"\nrequire \"uri\"\nrequire \"cgi\"\nrequire 'enumerator'\n\nclass Gchart\n  include GchartInfo\n\n  def self.url\n    \"http://chart.apis.google.com/chart?\" \n  end\n\n  def self.types\n    @types ||= ['line', 'line_xy', 'scatter', 'bar', 'venn', 'pie', 'pie_3d', 'jstize', 'sparkline', 'meter', 'map']\n  end\n\n  def self.simple_chars\n    @simple_chars ||= ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a\n  end \n\n  def self.chars\n    @chars ||= simple_chars + ['-', '.']\n  end\n\n  def self.ext_pairs\n    @ext_pairs ||= chars.map { |char_1| chars.map { |char_2| char_1 + char_2 } }.flatten\n  end\n\n  def self.default_filename\n    'chart.png'\n  end\n\n  attr_accessor :title, :type, :width, :height, :horizontal, :grouped, :legend, :data, :encoding, :bar_colors,\n  :title_color, :title_size, :custom, :axis_with_labels, :axis_labels, :bar_width_and_spacing, :id, :alt, :klass,\n  :range_markers, :geographical_area, :map_colors, :country_codes, :axis_range, :filename, :min, :max, :colors\n\n  attr_accessor :bg_type, :bg_color, :bg_angle, :chart_type, :chart_color, :chart_angle, :axis_range\n\n  attr_accessor :min_value, :max_value\n  \n  types.each do |type|\n    instance_eval <<-DYNCLASSMETH\n    def #{type}(options = {})\n      # Start with theme defaults if a theme is set\n      theme = options[:theme]\n      options = theme ? Chart::Theme.load(theme).to_options.merge(options) : options \n      # # Extract the format and optional filename, then clean the hash\n      format = options[:format] || 'url'\n      options[:filename] ||= Gchart.default_filename\n      options.delete(:format)\n      #update map_colors to become bar_colors\n      options.update(:bar_colors => options[:map_colors]) if options.has_key?(:map_colors)\n      chart = new(options.merge!({:type => \"#{type}\"}))\n      chart.send(format)\n    end\n    DYNCLASSMETH\n  end\n\n  def self.version\n    Gchart::VERSION::STRING\n  end\n\n  def self.method_missing(m, options={})\n    raise NoMethodError, \"#{m} is not a supported chart format, please use one of the following: #{supported_types}.\"\n  end\n\n  def initialize(options={})\n    @type = options[:type] || 'line'\n    @data = []\n    @width = 300\n    @height = 200\n    @horizontal = false\n    @grouped = false\n    @encoding = 'simple'\n    # @max_value = 'auto'\n    # @min_value defaults to nil meaning zero\n    @filename = options[:filename]\n    # Sets the alt tag when chart is exported as image tag\n    @alt = 'Google Chart'\n    # Sets the CSS id selector when chart is exported as image tag\n    @id = false\n    # Sets the CSS class selector when chart is exported as image tag\n    @klass = options[:class] || false\n    # set the options value if definable\n    options.each do |attribute, value| \n      send(\"#{attribute}=\", value) if self.respond_to?(\"#{attribute}=\")\n    end\n  end\n\n  def self.supported_types\n    Gchart.types.join(' ')\n  end\n\n  # Defines the Graph size using the following format:\n  # width X height\n  def size=(size='300x200')\n    @width, @height = size.split(\"x\").map { |dimension| dimension.to_i }\n  end\n\n  def size\n    \"#{width}x#{height}\"\n  end\n  \n  def dimensions\n    # TODO: maybe others?\n    [:line_xy, :scatter].include?(type) ? 2 : 1\n  end\n\n  # Sets the orientation of a bar graph\n  def orientation=(orientation='h')\n    if orientation == 'h' || orientation == 'horizontal'\n      self.horizontal = true\n    elsif orientation == 'v' || orientation == 'vertical'\n      self.horizontal = false\n    end\n  end\n\n  # Sets the bar graph presentation (stacked or grouped)\n  def stacked=(option=true)\n    @grouped = option ? false : true\n  end\n\n  def bg=(options)\n    if options.is_a?(String)\n      @bg_color = options\n    elsif options.is_a?(Hash)\n      @bg_color = options[:color]\n      @bg_type  = options[:type]\n      @bg_angle = options[:angle]\n    end\n  end\n\n  def graph_bg=(options)\n    if options.is_a?(String)\n      @chart_color = options\n    elsif options.is_a?(Hash)\n      @chart_color = options[:color]\n      @chart_type  =  options[:type]\n      @chart_angle = options[:angle]\n    end\n  end\n  \n  def max_value=(max_v)\n    if max_v =~ /false/\n      @max_value = false\n    else\n      @max_value = max_v\n    end\n  end\n\n  def min_value=(min_v)\n    if min_v =~ /false/\n      @min_value = false\n    else\n      @min_value = min_v\n    end\n  end\n\n  # returns the full data range as an array\n  # it also sets the data range if not defined\n  def full_data_range(ds)\n    return if max_value == false\n\n    ds.each_with_index do |mds, mds_index|\n      mds[:min_value] ||= min_value\n      mds[:max_value] ||= max_value\n      \n      if mds_index == 0 && type.to_s == 'bar'\n        # TODO: unless you specify a zero line (using chp or chds),\n        #       the min_value of a bar chart is always 0.\n        #mds[:min_value] ||= mds[:data].first.to_a.compact.min\n        mds[:min_value] ||= 0\n      end\n      if (mds_index == 0 && type.to_s == 'bar' && \n        !grouped && mds[:data].first.is_a?(Array))\n        totals = []\n        mds[:data].each do |l|\n          l.each_with_index do |v, index|\n            next if v.nil?\n            totals[index] ||= 0\n            totals[index] += v\n          end\n        end\n        mds[:max_value] ||= totals.compact.max\n      else\n        all = mds[:data].flatten.compact\n        # default min value should be 0 unless set to auto\n        if mds[:min_value] == 'auto'\n          mds[:min_value] = all.min\n        else\n          min = all.min\n          mds[:min_value] ||=  (min && min < 0 ? min : 0)\n        end\n        mds[:max_value] ||= all.max\n      end\n    end\n\n    unless axis_range\n      @axis_range = ds.map{|mds| [mds[:min_value], mds[:max_value]]}\n      if dimensions == 1 && (type.to_s != 'bar' || horizontal)\n        tmp = axis_range.fetch(0, [])\n        @axis_range[0] = axis_range.fetch(1, [])\n        @axis_range[1] = tmp\n      end\n    end\n    # return [min, max] unless (min.nil? || max.nil?)\n    # @max = (max_value.nil? || max_value == 'auto') ? ds.compact.map{|mds| mds.compact.max}.max : max_value\n    # \n    # if min_value.nil? \n    #   min_ds_value = ds.compact.map{|mds| mds.compact.min}.min || 0\n    #   @min = (min_ds_value < 0) ? min_ds_value : 0\n    # else\n    #   @min = min_value == 'auto' ? ds.compact.map{|mds| mds.compact.min}.min || 0 : min_value      \n    # end\n    # @axis_range = [[min,max]]\n  end\n\n  def dataset\n    if @dataset\n      @dataset \n    else\n      @dataset = convert_dataset(data || [])\n      full_data_range(@dataset)   # unless axis_range\n      @dataset\n    end\n  end\n  \n  # Sets of data to handle multiple sets\n  def datasets\n    datasets = []\n    dataset.each do |d|\n      if d[:data].first.is_a?(Array)\n        datasets += d[:data]\n      else\n        datasets << d[:data]\n      end\n    end\n    datasets\n  end\n  \n  def self.jstize(string)\n    string.gsub(' ', '+').gsub(/\\[|\\{|\\}|\\\\|\\^|\\[|\\]|\\`|\\]/) {|c| \"%#{c[0].to_s.upcase}\"}\n  end    \n  # load all the custom aliases\n  require 'gchart/aliases'\n\n  # Returns the chart's generated PNG as a blob. (borrowed from John's gchart.rubyforge.org)\n  def fetch\n    open(query_builder) { |io| io.read }\n  end\n\n  # Writes the chart's generated PNG to a file. (borrowed from John's gchart.rubyforge.org)\n  def write\n    io_or_file = filename || Gchart.default_filename\n    return io_or_file.write(fetch) if io_or_file.respond_to?(:write)\n    open(io_or_file, \"wb+\") { |io| io.write(fetch) }\n  end\n\n  # Format\n\n  def image_tag\n    image = \"<img\"\n    image += \" id=\\\"#{id}\\\"\" if id  \n    image += \" class=\\\"#{klass}\\\"\" if klass      \n    image += \" src=\\\"#{query_builder(:html)}\\\"\"\n    image += \" width=\\\"#{width}\\\"\"\n    image += \" height=\\\"#{height}\\\"\"\n    image += \" alt=\\\"#{alt}\\\"\"\n    image += \" title=\\\"#{title}\\\"\" if title\n    image += \" />\"\n  end\n\n  alias_method :img_tag, :image_tag\n\n  def url\n    query_builder\n  end\n\n  def file\n    write\n  end\n\n  #\n  def jstize(string)\n    Gchart.jstize(string)\n  end \n\n  private\n\n  # The title size cannot be set without specifying a color.\n  # A dark key will be used for the title color if no color is specified \n  def set_title\n    title_params = \"chtt=#{title}\"\n    unless (title_color.nil? && title_size.nil? )\n      title_params << \"&chts=\" + (color, size = (title_color || '454545'), title_size).compact.join(',')\n    end\n    title_params\n  end\n\n  def set_size\n    \"chs=#{size}\"\n  end\n\n  def set_data\n    data = send(\"#{@encoding}_encoding\")\n    \"chd=#{data}\"\n  end\n\n  def set_colors\n    @bg_type = fill_type(bg_type) || 's' if bg_color\n    @chart_type = fill_type(chart_type) || 's' if chart_color\n\n    \"chf=\" + {'bg' => fill_for(bg_type, bg_color, bg_angle), 'c' => fill_for(chart_type, chart_color, chart_angle)}.map{|k,v| \"#{k},#{v}\" unless v.nil?}.compact.join('|')      \n  end\n\n  # set bar, line colors\n  def set_bar_colors\n    @bar_colors = bar_colors.join(',') if bar_colors.is_a?(Array)\n    \"chco=#{bar_colors}\"\n  end\n\n  def set_country_codes\n    @country_codes = country_codes.join() if country_codes.is_a?(Array)\n    \"chld=#{country_codes}\"\n  end\n\n  # set bar spacing\n  # chbh=\n  # <bar width in pixels>,\n  # <optional space between bars in a group>,\n  # <optional space between groups>\n  def set_bar_width_and_spacing\n    width_and_spacing_values = case bar_width_and_spacing\n    when String\n      bar_width_and_spacing\n    when Array\n      bar_width_and_spacing.join(',')\n    when Hash\n      width         = bar_width_and_spacing[:width] || 23\n      spacing       = bar_width_and_spacing[:spacing] || 4\n      group_spacing = bar_width_and_spacing[:group_spacing] || 8\n      [width,spacing,group_spacing].join(',')\n    else\n      bar_width_and_spacing.to_s\n    end\n    \"chbh=#{width_and_spacing_values}\"\n  end\n\n  def set_range_markers\n    markers = case range_markers\n    when Hash\n      set_range_marker(range_markers)\n    when Array\n      range_markers.collect{|marker| set_range_marker(marker)}.join('|')\n    end\n    \"chm=#{markers}\"\n  end\n\n  def set_range_marker(options)\n    orientation = ['vertical', 'Vertical', 'V', 'v', 'R'].include?(options[:orientation]) ? 'R' : 'r'\n    \"#{orientation},#{options[:color]},0,#{options[:start_position]},#{options[:stop_position]}#{',1' if options[:overlaid?]}\"  \n  end\n\n  def fill_for(type=nil, color='', angle=nil)\n    unless type.nil? \n      case type\n      when 'lg'\n        angle ||= 0\n        color = \"#{color},0,ffffff,1\" if color.split(',').size == 1\n        \"#{type},#{angle},#{color}\"\n      when 'ls'\n        angle ||= 90\n        color = \"#{color},0.2,ffffff,0.2\" if color.split(',').size == 1\n        \"#{type},#{angle},#{color}\"\n      else\n        \"#{type},#{color}\"\n      end\n    end\n  end\n\n  # A chart can have one or many legends. \n  # Gchart.line(:legend => 'label')\n  # or\n  # Gchart.line(:legend => ['first label', 'last label'])\n  def set_legend\n    return set_labels if type.to_s =~ /pie|pie_3d|meter/\n\n    if legend.is_a?(Array)\n      \"chdl=#{@legend.map{|label| \"#{CGI::escape(label.to_s)}\"}.join('|')}\"\n    else\n      \"chdl=#{legend}\"\n    end\n\n  end\n\n  def set_labels\n    if legend.is_a?(Array)\n      \"chl=#{@legend.map{|label| \"#{CGI::escape(label.to_s)}\"}.join('|')}\"\n    else\n      \"chl=#{@legend}\"\n    end\n  end\n\n  def set_axis_with_labels\n    @axis_with_labels = axis_with_labels.join(',') if @axis_with_labels.is_a?(Array)\n    \"chxt=#{axis_with_labels}\"\n  end\n\n  def set_axis_labels\n    if axis_labels.is_a?(Array)\n      if RUBY_VERSION.to_f < 1.9\n        labels_arr = axis_labels.enum_with_index.map{|labels,index| [index,labels]}\n      else\n        labels_arr = axis_labels.map.with_index.map{|labels,index| [index,labels]}\n      end\n    elsif axis_labels.is_a?(Hash)\n      labels_arr = axis_labels.to_a\n    end\n    labels_arr.map! do |index,labels|\n      if labels.is_a?(Array)\n        \"#{index}:|#{labels.map{|label| \"#{CGI::escape(label.to_s)}\"}.join('|')}\"\n      else\n        \"#{index}:|#{labels}\"\n      end\n    end\n    \"chxl=#{labels_arr.join('|')}\"\n  end\n\n  # http://code.google.com/apis/chart/labels.html#axis_range\n  # Specify a range for axis labels\n  def set_axis_range\n    # a passed axis_range should look like:\n    # [[10,100]] or [[10,100,4]] or [[10,100], [20,300]]\n    # in the second example, 4 is the interval \n    set = axis_range || datasets\n    # in the case of a line graph, the first axis range should 1\n    index_increase = type.to_s == 'line' ? 1 : 0\n    if set && set.respond_to?(:each) && set.first.respond_to?(:each)\n      'chxr=' + datasets.enum_for(:each_with_index).map do |range, index|\n        [(index + index_increase), (min_value || range.first), (max_value || range.last)].compact.uniq.join(',')\n       end.join(\"|\")\n    else\n      nil\n    end\n  end\n\n  def set_geographical_area\n    \"chtm=#{geographical_area}\"\n  end\n\n  def set_type\n    case type.to_s\n    when 'line'\n      \"cht=lc\"\n    when 'line_xy'\n      \"cht=lxy\"\n    when 'bar'\n      \"cht=b\" + (horizontal? ? \"h\" : \"v\") + (grouped? ? \"g\" : \"s\")\n    when 'pie_3d'\n      \"cht=p3\"\n    when 'pie'\n      \"cht=p\"\n    when 'venn'\n      \"cht=v\"\n    when 'scatter'\n      \"cht=s\"\n    when 'sparkline'\n      \"cht=ls\"\n    when 'meter'\n      \"cht=gom\"\n    when 'map'\n      \"cht=t\"\n    end\n  end\n\n  def fill_type(type)\n    case type\n    when 'solid'\n      's'\n    when 'gradient'\n      'lg'\n    when 'stripes'\n      'ls'\n    end\n  end\n  \n  def number_visible\n    n = 0\n    dataset.each do |mds|\n      return n.to_s if mds[:invisible] == true\n      if mds[:data].first.is_a?(Array)\n        n += mds[:data].length\n      else\n        n += 1\n      end\n    end\n    \"\"\n  end\n  \n  # Turns input into an array of axis hashes, dependent on the chart type\n  def convert_dataset(ds)\n    if dimensions == 2\n      # valid inputs include:\n      # an array of >=2 arrays, or an array of >=2 hashes\n      ds = ds.map do |d|\n        d.is_a?(Hash) ? d : {:data => d}\n      end\n    elsif dimensions == 1\n      # valid inputs include:\n      # a hash, an array of data, an array of >=1 array, or an array of >=1 hash\n      if ds.is_a?(Hash)\n        ds = [ds]\n      elsif not ds.first.is_a?(Hash)\n        ds = [{:data => ds}]\n      end\n    end\n    ds\n  end\n  \n  # just an alias\n  def axis_set\n    dataset\n  end\n\n  def convert_to_simple_value(number)\n    if number.nil?\n      \"_\"\n    else\n      value = Gchart.simple_chars[number.to_i]\n      value.nil? ? \"_\" : value\n    end\n  end\n  \n  def convert_to_extended_value(number)\n    if number.nil?\n      '__'\n    else\n      value = Gchart.ext_pairs[number.to_i]\n      value.nil? ? \"__\" : value\n    end\n  end\n  \n  def encode_scaled_dataset(chars, nil_char)\n    dsets = []\n    dataset.each do |ds|\n      if max_value != false\n        range = ds[:max_value] - ds[:min_value]\n        range = 1 if range == 0\n      end\n      unless ds[:data].first.is_a?(Array)\n        ldatasets = [ds[:data]]\n      else\n        ldatasets = ds[:data]\n      end\n      ldatasets.each do |l|\n        dsets << l.map do |number|\n          if number.nil?\n            nil_char\n          else\n            unless range.nil? || range.zero?\n              number = chars.size * (number - ds[:min_value]) / range.to_f\n              number = [number, chars.size - 1].min\n            end\n            chars[number.to_i]\n          end\n        end.join\n      end\n    end\n    dsets.join(',')\n  end\n\n  # http://code.google.com/apis/chart/#simple\n  # Simple encoding has a resolution of 62 different values. \n  # Allowing five pixels per data point, this is sufficient for line and bar charts up\n  # to about 300 pixels. Simple encoding is suitable for all other types of chart regardless of size.\n  def simple_encoding\n    \"s\" + number_visible + \":\" + encode_scaled_dataset(Gchart.simple_chars, '_')\n  end\n\n  # http://code.google.com/apis/chart/#text\n  # Text encoding with data scaling lets you specify arbitrary positive or\n  # negative floating point numbers, in combination with a scaling parameter\n  # that lets you specify a custom range for your chart. This chart is useful\n  # when you don't want to worry about limiting your data to a specific range,\n  # or do the calculations to scale your data down or up to fit nicely inside\n  # a chart.\n  #\n  # Valid values range from (+/-)9.999e(+/-)100, and only four non-zero digits are supported (that is, 123400, 1234, 12.34, and 0.1234 are valid, but 12345, 123.45 and 123400.5 are not).\n  #\n  # This encoding is not available for maps.\n  #\n  def text_encoding\n    chds = dataset.map{|ds| \"#{ds[:min_value]},#{ds[:max_value]}\" }.join(\",\")\n    \"t\" + number_visible + \":\" + datasets.map{ |ds| ds.join(',') }.join('|') + \"&chds=\" + chds\n  end\n\n  # http://code.google.com/apis/chart/#extended\n  # Extended encoding has a resolution of 4,096 different values \n  # and is best used for large charts where a large data range is required.\n  def extended_encoding\n    \"e\" + number_visible + \":\" + encode_scaled_dataset(Gchart.ext_pairs, '__')\n  end\n\n  def query_builder(options=\"\")\n    query_params = instance_variables.sort.map do |var|\n      case var.to_s\n      when '@data'\n        set_data unless data == []  \n        # Set the graph size  \n      when '@width'\n        set_size unless width.nil? || height.nil?\n      when '@type'\n        set_type\n      when '@title'\n        set_title unless title.nil?\n      when '@legend'\n        set_legend unless legend.nil?\n      when '@bg_color'\n        set_colors\n      when '@chart_color'\n        set_colors if bg_color.nil?\n      when '@bar_colors'\n        set_bar_colors\n      when '@bar_width_and_spacing'\n        set_bar_width_and_spacing\n      when '@axis_with_labels'\n        set_axis_with_labels\n      when '@axis_labels'\n        set_axis_labels\n      when '@range_markers'\n        set_range_markers\n      when '@geographical_area'\n        set_geographical_area\n      when '@country_codes'\n        set_country_codes\n      when '@custom'\n        custom\n      end\n    end.compact\n\n    query_params << set_axis_range\n\n    # Use ampersand as default delimiter\n    unless options == :html\n      delimiter = '&'\n      # Escape ampersand for html image tags\n    else\n      delimiter = '&amp;'\n    end\n\n    jstize(Gchart.url + query_params.join(delimiter))\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/googlecharts/lib/googlecharts.rb",
    "content": "require 'gchart'\nGooglecharts = Gchart unless Object.const_defined? 'Googlechart'"
  },
  {
    "path": "vendor/plugins/googlecharts/lib/themes.yml",
    "content": "#Default themes ganked from Gruff: http://github.com/topfunky/gruff/tree/master\n:keynote:\n  :colors:\n    - &blue 6886B4\n    - &yellow FDD84E\n    - &green 72AE6E\n    - &red D1695E\n    - &purple 8A6EAF\n    - &orange EFAA43\n    - &white FFFFFF\n    - &black !str 000000\n  :bar_colors: [ *blue, *yellow, *green, *red, *purple, *orange ]\n  :background: *black\n  :chart_background: *white\n:thirty7signals:\n  :colors:\n    - &green 339933\n    - &purple cc99cc\n    - &blue 336699\n    - &yellow FFF804\n    - &red ff0000\n    - &orange cf5910\n  :bar_colors: [ *yellow, *blue, *green, *red, *purple, *orange ]\n  :background: *white\n:pastel:\n  :colors:\n    - &blue a9dada\n    - &green aedaa9\n    - &peach daaea9\n    - &yellow dadaa9\n    - &dk_purple a9a9da\n    - &purple daaeda\n    - &grey dadada\n  :bar_colors: [ *blue, *green, *peach, *yellow, *dk_purple ]\n  :background_color: *white\n:greyscale:\n  :bar_colors: [\n            282828,  \n            383838,  \n            686868,  \n            989898,  \n            c8c8c8,  \n            e8e8e8\n            ]\n  :background_color: *white"
  },
  {
    "path": "vendor/plugins/googlecharts/script/destroy",
    "content": "#!/usr/bin/env ruby\nAPP_ROOT = File.join(File.dirname(__FILE__), '..')\n\nbegin\n  require 'rubigen'\nrescue LoadError\n  require 'rubygems'\n  require 'rubigen'\nend\nrequire 'rubigen/scripts/destroy'\n\nARGV.shift if ['--help', '-h'].include?(ARGV[0])\nRubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]\nRubiGen::Scripts::Destroy.new.run(ARGV)\n"
  },
  {
    "path": "vendor/plugins/googlecharts/script/generate",
    "content": "#!/usr/bin/env ruby\nAPP_ROOT = File.join(File.dirname(__FILE__), '..')\n\nbegin\n  require 'rubigen'\nrescue LoadError\n  require 'rubygems'\n  require 'rubigen'\nend\nrequire 'rubigen/scripts/generate'\n\nARGV.shift if ['--help', '-h'].include?(ARGV[0])\nRubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]\nRubiGen::Scripts::Generate.new.run(ARGV)\n"
  },
  {
    "path": "vendor/plugins/googlecharts/script/txt2html",
    "content": "#!/usr/bin/env ruby\n\nrequire 'rubygems'\nbegin\n  require 'newgem'\nrescue LoadError\n  puts \"\\n\\nGenerating the website requires the newgem RubyGem\"\n  puts \"Install: gem install newgem\\n\\n\"\n  exit(1)\nend\nrequire 'redcloth'\nrequire 'syntax/convertors/html'\nrequire 'erb'\nrequire File.dirname(__FILE__) + '/../lib/gchart'\n\nversion  = Gchart.version\ndownload = 'http://rubyforge.org/projects/googlecharts'\n\nclass Fixnum\n  def ordinal\n    # teens\n    return 'th' if (10..19).include?(self % 100)\n    # others\n    case self % 10\n    when 1: return 'st'\n    when 2: return 'nd'\n    when 3: return 'rd'\n    else    return 'th'\n    end\n  end\nend\n\nclass Time\n  def pretty\n    return \"#{mday}#{mday.ordinal} #{strftime('%B')} #{year}\"\n  end\nend\n\ndef convert_syntax(syntax, source)\n  return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')\nend\n\nif ARGV.length >= 1\n  src, template = ARGV\n  template ||= File.join(File.dirname(__FILE__), '/../website/template.rhtml')\n  \nelse\n  puts(\"Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html\")\n  exit!\nend\n\ntemplate = ERB.new(File.open(template).read)\n\ntitle = nil\nbody = nil\nFile.open(src) do |fsrc|\n  title_text = fsrc.readline\n  body_text = fsrc.read\n  syntax_items = []\n  body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['\"]([^'\"]+)[^>]*>(.*?)</\\1>!m){\n    ident = syntax_items.length\n    element, syntax, source = $1, $2, $3\n    syntax_items << \"<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>\"\n    \"syntax-temp-#{ident}\"\n  }\n  title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip\n  body = RedCloth.new(body_text).to_html\n  body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }\nend\nstat = File.stat(src)\ncreated = stat.ctime\nmodified = stat.mtime\n\n$stdout << template.result(binding)\n"
  },
  {
    "path": "vendor/plugins/googlecharts/setup.rb",
    "content": "#\n# setup.rb\n#\n# Copyright (c) 2000-2005 Minero Aoki\n#\n# This program is free software.\n# You can distribute/modify this program under the terms of\n# the GNU LGPL, Lesser General Public License version 2.1.\n#\n\nunless Enumerable.method_defined?(:map)   # Ruby 1.4.6\n  module Enumerable\n    alias map collect\n  end\nend\n\nunless File.respond_to?(:read)   # Ruby 1.6\n  def File.read(fname)\n    open(fname) {|f|\n      return f.read\n    }\n  end\nend\n\nunless Errno.const_defined?(:ENOTEMPTY)   # Windows?\n  module Errno\n    class ENOTEMPTY\n      # We do not raise this exception, implementation is not needed.\n    end\n  end\nend\n\ndef File.binread(fname)\n  open(fname, 'rb') {|f|\n    return f.read\n  }\nend\n\n# for corrupted Windows' stat(2)\ndef File.dir?(path)\n  File.directory?((path[-1,1] == '/') ? path : path + '/')\nend\n\n\nclass ConfigTable\n\n  include Enumerable\n\n  def initialize(rbconfig)\n    @rbconfig = rbconfig\n    @items = []\n    @table = {}\n    # options\n    @install_prefix = nil\n    @config_opt = nil\n    @verbose = true\n    @no_harm = false\n  end\n\n  attr_accessor :install_prefix\n  attr_accessor :config_opt\n\n  attr_writer :verbose\n\n  def verbose?\n    @verbose\n  end\n\n  attr_writer :no_harm\n\n  def no_harm?\n    @no_harm\n  end\n\n  def [](key)\n    lookup(key).resolve(self)\n  end\n\n  def []=(key, val)\n    lookup(key).set val\n  end\n\n  def names\n    @items.map {|i| i.name }\n  end\n\n  def each(&block)\n    @items.each(&block)\n  end\n\n  def key?(name)\n    @table.key?(name)\n  end\n\n  def lookup(name)\n    @table[name] or setup_rb_error \"no such config item: #{name}\"\n  end\n\n  def add(item)\n    @items.push item\n    @table[item.name] = item\n  end\n\n  def remove(name)\n    item = lookup(name)\n    @items.delete_if {|i| i.name == name }\n    @table.delete_if {|name, i| i.name == name }\n    item\n  end\n\n  def load_script(path, inst = nil)\n    if File.file?(path)\n      MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path\n    end\n  end\n\n  def savefile\n    '.config'\n  end\n\n  def load_savefile\n    begin\n      File.foreach(savefile()) do |line|\n        k, v = *line.split(/=/, 2)\n        self[k] = v.strip\n      end\n    rescue Errno::ENOENT\n      setup_rb_error $!.message + \"\\n#{File.basename($0)} config first\"\n    end\n  end\n\n  def save\n    @items.each {|i| i.value }\n    File.open(savefile(), 'w') {|f|\n      @items.each do |i|\n        f.printf \"%s=%s\\n\", i.name, i.value if i.value? and i.value\n      end\n    }\n  end\n\n  def load_standard_entries\n    standard_entries(@rbconfig).each do |ent|\n      add ent\n    end\n  end\n\n  def standard_entries(rbconfig)\n    c = rbconfig\n\n    rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])\n\n    major = c['MAJOR'].to_i\n    minor = c['MINOR'].to_i\n    teeny = c['TEENY'].to_i\n    version = \"#{major}.#{minor}\"\n\n    # ruby ver. >= 1.4.4?\n    newpath_p = ((major >= 2) or\n                 ((major == 1) and\n                  ((minor >= 5) or\n                   ((minor == 4) and (teeny >= 4)))))\n\n    if c['rubylibdir']\n      # V > 1.6.3\n      libruby         = \"#{c['prefix']}/lib/ruby\"\n      librubyver      = c['rubylibdir']\n      librubyverarch  = c['archdir']\n      siteruby        = c['sitedir']\n      siterubyver     = c['sitelibdir']\n      siterubyverarch = c['sitearchdir']\n    elsif newpath_p\n      # 1.4.4 <= V <= 1.6.3\n      libruby         = \"#{c['prefix']}/lib/ruby\"\n      librubyver      = \"#{c['prefix']}/lib/ruby/#{version}\"\n      librubyverarch  = \"#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}\"\n      siteruby        = c['sitedir']\n      siterubyver     = \"$siteruby/#{version}\"\n      siterubyverarch = \"$siterubyver/#{c['arch']}\"\n    else\n      # V < 1.4.4\n      libruby         = \"#{c['prefix']}/lib/ruby\"\n      librubyver      = \"#{c['prefix']}/lib/ruby/#{version}\"\n      librubyverarch  = \"#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}\"\n      siteruby        = \"#{c['prefix']}/lib/ruby/#{version}/site_ruby\"\n      siterubyver     = siteruby\n      siterubyverarch = \"$siterubyver/#{c['arch']}\"\n    end\n    parameterize = lambda {|path|\n      path.sub(/\\A#{Regexp.quote(c['prefix'])}/, '$prefix')\n    }\n\n    if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }\n      makeprog = arg.sub(/'/, '').split(/=/, 2)[1]\n    else\n      makeprog = 'make'\n    end\n\n    [\n      ExecItem.new('installdirs', 'std/site/home',\n                   'std: install under libruby; site: install under site_ruby; home: install under $HOME')\\\n          {|val, table|\n            case val\n            when 'std'\n              table['rbdir'] = '$librubyver'\n              table['sodir'] = '$librubyverarch'\n            when 'site'\n              table['rbdir'] = '$siterubyver'\n              table['sodir'] = '$siterubyverarch'\n            when 'home'\n              setup_rb_error '$HOME was not set' unless ENV['HOME']\n              table['prefix'] = ENV['HOME']\n              table['rbdir'] = '$libdir/ruby'\n              table['sodir'] = '$libdir/ruby'\n            end\n          },\n      PathItem.new('prefix', 'path', c['prefix'],\n                   'path prefix of target environment'),\n      PathItem.new('bindir', 'path', parameterize.call(c['bindir']),\n                   'the directory for commands'),\n      PathItem.new('libdir', 'path', parameterize.call(c['libdir']),\n                   'the directory for libraries'),\n      PathItem.new('datadir', 'path', parameterize.call(c['datadir']),\n                   'the directory for shared data'),\n      PathItem.new('mandir', 'path', parameterize.call(c['mandir']),\n                   'the directory for man pages'),\n      PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),\n                   'the directory for system configuration files'),\n      PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),\n                   'the directory for local state data'),\n      PathItem.new('libruby', 'path', libruby,\n                   'the directory for ruby libraries'),\n      PathItem.new('librubyver', 'path', librubyver,\n                   'the directory for standard ruby libraries'),\n      PathItem.new('librubyverarch', 'path', librubyverarch,\n                   'the directory for standard ruby extensions'),\n      PathItem.new('siteruby', 'path', siteruby,\n          'the directory for version-independent aux ruby libraries'),\n      PathItem.new('siterubyver', 'path', siterubyver,\n                   'the directory for aux ruby libraries'),\n      PathItem.new('siterubyverarch', 'path', siterubyverarch,\n                   'the directory for aux ruby binaries'),\n      PathItem.new('rbdir', 'path', '$siterubyver',\n                   'the directory for ruby scripts'),\n      PathItem.new('sodir', 'path', '$siterubyverarch',\n                   'the directory for ruby extentions'),\n      PathItem.new('rubypath', 'path', rubypath,\n                   'the path to set to #! line'),\n      ProgramItem.new('rubyprog', 'name', rubypath,\n                      'the ruby program using for installation'),\n      ProgramItem.new('makeprog', 'name', makeprog,\n                      'the make program to compile ruby extentions'),\n      SelectItem.new('shebang', 'all/ruby/never', 'ruby',\n                     'shebang line (#!) editing mode'),\n      BoolItem.new('without-ext', 'yes/no', 'no',\n                   'does not compile/install ruby extentions')\n    ]\n  end\n  private :standard_entries\n\n  def load_multipackage_entries\n    multipackage_entries().each do |ent|\n      add ent\n    end\n  end\n\n  def multipackage_entries\n    [\n      PackageSelectionItem.new('with', 'name,name...', '', 'ALL',\n                               'package names that you want to install'),\n      PackageSelectionItem.new('without', 'name,name...', '', 'NONE',\n                               'package names that you do not want to install')\n    ]\n  end\n  private :multipackage_entries\n\n  ALIASES = {\n    'std-ruby'         => 'librubyver',\n    'stdruby'          => 'librubyver',\n    'rubylibdir'       => 'librubyver',\n    'archdir'          => 'librubyverarch',\n    'site-ruby-common' => 'siteruby',     # For backward compatibility\n    'site-ruby'        => 'siterubyver',  # For backward compatibility\n    'bin-dir'          => 'bindir',\n    'bin-dir'          => 'bindir',\n    'rb-dir'           => 'rbdir',\n    'so-dir'           => 'sodir',\n    'data-dir'         => 'datadir',\n    'ruby-path'        => 'rubypath',\n    'ruby-prog'        => 'rubyprog',\n    'ruby'             => 'rubyprog',\n    'make-prog'        => 'makeprog',\n    'make'             => 'makeprog'\n  }\n\n  def fixup\n    ALIASES.each do |ali, name|\n      @table[ali] = @table[name]\n    end\n    @items.freeze\n    @table.freeze\n    @options_re = /\\A--(#{@table.keys.join('|')})(?:=(.*))?\\z/\n  end\n\n  def parse_opt(opt)\n    m = @options_re.match(opt) or setup_rb_error \"config: unknown option #{opt}\"\n    m.to_a[1,2]\n  end\n\n  def dllext\n    @rbconfig['DLEXT']\n  end\n\n  def value_config?(name)\n    lookup(name).value?\n  end\n\n  class Item\n    def initialize(name, template, default, desc)\n      @name = name.freeze\n      @template = template\n      @value = default\n      @default = default\n      @description = desc\n    end\n\n    attr_reader :name\n    attr_reader :description\n\n    attr_accessor :default\n    alias help_default default\n\n    def help_opt\n      \"--#{@name}=#{@template}\"\n    end\n\n    def value?\n      true\n    end\n\n    def value\n      @value\n    end\n\n    def resolve(table)\n      @value.gsub(%r<\\$([^/]+)>) { table[$1] }\n    end\n\n    def set(val)\n      @value = check(val)\n    end\n\n    private\n\n    def check(val)\n      setup_rb_error \"config: --#{name} requires argument\" unless val\n      val\n    end\n  end\n\n  class BoolItem < Item\n    def config_type\n      'bool'\n    end\n\n    def help_opt\n      \"--#{@name}\"\n    end\n\n    private\n\n    def check(val)\n      return 'yes' unless val\n      case val\n      when /\\Ay(es)?\\z/i, /\\At(rue)?\\z/i then 'yes'\n      when /\\An(o)?\\z/i, /\\Af(alse)\\z/i  then 'no'\n      else\n        setup_rb_error \"config: --#{@name} accepts only yes/no for argument\"\n      end\n    end\n  end\n\n  class PathItem < Item\n    def config_type\n      'path'\n    end\n\n    private\n\n    def check(path)\n      setup_rb_error \"config: --#{@name} requires argument\"  unless path\n      path[0,1] == '$' ? path : File.expand_path(path)\n    end\n  end\n\n  class ProgramItem < Item\n    def config_type\n      'program'\n    end\n  end\n\n  class SelectItem < Item\n    def initialize(name, selection, default, desc)\n      super\n      @ok = selection.split('/')\n    end\n\n    def config_type\n      'select'\n    end\n\n    private\n\n    def check(val)\n      unless @ok.include?(val.strip)\n        setup_rb_error \"config: use --#{@name}=#{@template} (#{val})\"\n      end\n      val.strip\n    end\n  end\n\n  class ExecItem < Item\n    def initialize(name, selection, desc, &block)\n      super name, selection, nil, desc\n      @ok = selection.split('/')\n      @action = block\n    end\n\n    def config_type\n      'exec'\n    end\n\n    def value?\n      false\n    end\n\n    def resolve(table)\n      setup_rb_error \"$#{name()} wrongly used as option value\"\n    end\n\n    undef set\n\n    def evaluate(val, table)\n      v = val.strip.downcase\n      unless @ok.include?(v)\n        setup_rb_error \"invalid option --#{@name}=#{val} (use #{@template})\"\n      end\n      @action.call v, table\n    end\n  end\n\n  class PackageSelectionItem < Item\n    def initialize(name, template, default, help_default, desc)\n      super name, template, default, desc\n      @help_default = help_default\n    end\n\n    attr_reader :help_default\n\n    def config_type\n      'package'\n    end\n\n    private\n\n    def check(val)\n      unless File.dir?(\"packages/#{val}\")\n        setup_rb_error \"config: no such package: #{val}\"\n      end\n      val\n    end\n  end\n\n  class MetaConfigEnvironment\n    def initialize(config, installer)\n      @config = config\n      @installer = installer\n    end\n\n    def config_names\n      @config.names\n    end\n\n    def config?(name)\n      @config.key?(name)\n    end\n\n    def bool_config?(name)\n      @config.lookup(name).config_type == 'bool'\n    end\n\n    def path_config?(name)\n      @config.lookup(name).config_type == 'path'\n    end\n\n    def value_config?(name)\n      @config.lookup(name).config_type != 'exec'\n    end\n\n    def add_config(item)\n      @config.add item\n    end\n\n    def add_bool_config(name, default, desc)\n      @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)\n    end\n\n    def add_path_config(name, default, desc)\n      @config.add PathItem.new(name, 'path', default, desc)\n    end\n\n    def set_config_default(name, default)\n      @config.lookup(name).default = default\n    end\n\n    def remove_config(name)\n      @config.remove(name)\n    end\n\n    # For only multipackage\n    def packages\n      raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer\n      @installer.packages\n    end\n\n    # For only multipackage\n    def declare_packages(list)\n      raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer\n      @installer.packages = list\n    end\n  end\n\nend   # class ConfigTable\n\n\n# This module requires: #verbose?, #no_harm?\nmodule FileOperations\n\n  def mkdir_p(dirname, prefix = nil)\n    dirname = prefix + File.expand_path(dirname) if prefix\n    $stderr.puts \"mkdir -p #{dirname}\" if verbose?\n    return if no_harm?\n\n    # Does not check '/', it's too abnormal.\n    dirs = File.expand_path(dirname).split(%r<(?=/)>)\n    if /\\A[a-z]:\\z/i =~ dirs[0]\n      disk = dirs.shift\n      dirs[0] = disk + dirs[0]\n    end\n    dirs.each_index do |idx|\n      path = dirs[0..idx].join('')\n      Dir.mkdir path unless File.dir?(path)\n    end\n  end\n\n  def rm_f(path)\n    $stderr.puts \"rm -f #{path}\" if verbose?\n    return if no_harm?\n    force_remove_file path\n  end\n\n  def rm_rf(path)\n    $stderr.puts \"rm -rf #{path}\" if verbose?\n    return if no_harm?\n    remove_tree path\n  end\n\n  def remove_tree(path)\n    if File.symlink?(path)\n      remove_file path\n    elsif File.dir?(path)\n      remove_tree0 path\n    else\n      force_remove_file path\n    end\n  end\n\n  def remove_tree0(path)\n    Dir.foreach(path) do |ent|\n      next if ent == '.'\n      next if ent == '..'\n      entpath = \"#{path}/#{ent}\"\n      if File.symlink?(entpath)\n        remove_file entpath\n      elsif File.dir?(entpath)\n        remove_tree0 entpath\n      else\n        force_remove_file entpath\n      end\n    end\n    begin\n      Dir.rmdir path\n    rescue Errno::ENOTEMPTY\n      # directory may not be empty\n    end\n  end\n\n  def move_file(src, dest)\n    force_remove_file dest\n    begin\n      File.rename src, dest\n    rescue\n      File.open(dest, 'wb') {|f|\n        f.write File.binread(src)\n      }\n      File.chmod File.stat(src).mode, dest\n      File.unlink src\n    end\n  end\n\n  def force_remove_file(path)\n    begin\n      remove_file path\n    rescue\n    end\n  end\n\n  def remove_file(path)\n    File.chmod 0777, path\n    File.unlink path\n  end\n\n  def install(from, dest, mode, prefix = nil)\n    $stderr.puts \"install #{from} #{dest}\" if verbose?\n    return if no_harm?\n\n    realdest = prefix ? prefix + File.expand_path(dest) : dest\n    realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)\n    str = File.binread(from)\n    if diff?(str, realdest)\n      verbose_off {\n        rm_f realdest if File.exist?(realdest)\n      }\n      File.open(realdest, 'wb') {|f|\n        f.write str\n      }\n      File.chmod mode, realdest\n\n      File.open(\"#{objdir_root()}/InstalledFiles\", 'a') {|f|\n        if prefix\n          f.puts realdest.sub(prefix, '')\n        else\n          f.puts realdest\n        end\n      }\n    end\n  end\n\n  def diff?(new_content, path)\n    return true unless File.exist?(path)\n    new_content != File.binread(path)\n  end\n\n  def command(*args)\n    $stderr.puts args.join(' ') if verbose?\n    system(*args) or raise RuntimeError,\n        \"system(#{args.map{|a| a.inspect }.join(' ')}) failed\"\n  end\n\n  def ruby(*args)\n    command config('rubyprog'), *args\n  end\n  \n  def make(task = nil)\n    command(*[config('makeprog'), task].compact)\n  end\n\n  def extdir?(dir)\n    File.exist?(\"#{dir}/MANIFEST\") or File.exist?(\"#{dir}/extconf.rb\")\n  end\n\n  def files_of(dir)\n    Dir.open(dir) {|d|\n      return d.select {|ent| File.file?(\"#{dir}/#{ent}\") }\n    }\n  end\n\n  DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )\n\n  def directories_of(dir)\n    Dir.open(dir) {|d|\n      return d.select {|ent| File.dir?(\"#{dir}/#{ent}\") } - DIR_REJECT\n    }\n  end\n\nend\n\n\n# This module requires: #srcdir_root, #objdir_root, #relpath\nmodule HookScriptAPI\n\n  def get_config(key)\n    @config[key]\n  end\n\n  alias config get_config\n\n  # obsolete: use metaconfig to change configuration\n  def set_config(key, val)\n    @config[key] = val\n  end\n\n  #\n  # srcdir/objdir (works only in the package directory)\n  #\n\n  def curr_srcdir\n    \"#{srcdir_root()}/#{relpath()}\"\n  end\n\n  def curr_objdir\n    \"#{objdir_root()}/#{relpath()}\"\n  end\n\n  def srcfile(path)\n    \"#{curr_srcdir()}/#{path}\"\n  end\n\n  def srcexist?(path)\n    File.exist?(srcfile(path))\n  end\n\n  def srcdirectory?(path)\n    File.dir?(srcfile(path))\n  end\n  \n  def srcfile?(path)\n    File.file?(srcfile(path))\n  end\n\n  def srcentries(path = '.')\n    Dir.open(\"#{curr_srcdir()}/#{path}\") {|d|\n      return d.to_a - %w(. ..)\n    }\n  end\n\n  def srcfiles(path = '.')\n    srcentries(path).select {|fname|\n      File.file?(File.join(curr_srcdir(), path, fname))\n    }\n  end\n\n  def srcdirectories(path = '.')\n    srcentries(path).select {|fname|\n      File.dir?(File.join(curr_srcdir(), path, fname))\n    }\n  end\n\nend\n\n\nclass ToplevelInstaller\n\n  Version   = '3.4.1'\n  Copyright = 'Copyright (c) 2000-2005 Minero Aoki'\n\n  TASKS = [\n    [ 'all',      'do config, setup, then install' ],\n    [ 'config',   'saves your configurations' ],\n    [ 'show',     'shows current configuration' ],\n    [ 'setup',    'compiles ruby extentions and others' ],\n    [ 'install',  'installs files' ],\n    [ 'test',     'run all tests in test/' ],\n    [ 'clean',    \"does `make clean' for each extention\" ],\n    [ 'distclean',\"does `make distclean' for each extention\" ]\n  ]\n\n  def ToplevelInstaller.invoke\n    config = ConfigTable.new(load_rbconfig())\n    config.load_standard_entries\n    config.load_multipackage_entries if multipackage?\n    config.fixup\n    klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)\n    klass.new(File.dirname($0), config).invoke\n  end\n\n  def ToplevelInstaller.multipackage?\n    File.dir?(File.dirname($0) + '/packages')\n  end\n\n  def ToplevelInstaller.load_rbconfig\n    if arg = ARGV.detect {|arg| /\\A--rbconfig=/ =~ arg }\n      ARGV.delete(arg)\n      load File.expand_path(arg.split(/=/, 2)[1])\n      $\".push 'rbconfig.rb'\n    else\n      require 'rbconfig'\n    end\n    ::Config::CONFIG\n  end\n\n  def initialize(ardir_root, config)\n    @ardir = File.expand_path(ardir_root)\n    @config = config\n    # cache\n    @valid_task_re = nil\n  end\n\n  def config(key)\n    @config[key]\n  end\n\n  def inspect\n    \"#<#{self.class} #{__id__()}>\"\n  end\n\n  def invoke\n    run_metaconfigs\n    case task = parsearg_global()\n    when nil, 'all'\n      parsearg_config\n      init_installers\n      exec_config\n      exec_setup\n      exec_install\n    else\n      case task\n      when 'config', 'test'\n        ;\n      when 'clean', 'distclean'\n        @config.load_savefile if File.exist?(@config.savefile)\n      else\n        @config.load_savefile\n      end\n      __send__ \"parsearg_#{task}\"\n      init_installers\n      __send__ \"exec_#{task}\"\n    end\n  end\n  \n  def run_metaconfigs\n    @config.load_script \"#{@ardir}/metaconfig\"\n  end\n\n  def init_installers\n    @installer = Installer.new(@config, @ardir, File.expand_path('.'))\n  end\n\n  #\n  # Hook Script API bases\n  #\n\n  def srcdir_root\n    @ardir\n  end\n\n  def objdir_root\n    '.'\n  end\n\n  def relpath\n    '.'\n  end\n\n  #\n  # Option Parsing\n  #\n\n  def parsearg_global\n    while arg = ARGV.shift\n      case arg\n      when /\\A\\w+\\z/\n        setup_rb_error \"invalid task: #{arg}\" unless valid_task?(arg)\n        return arg\n      when '-q', '--quiet'\n        @config.verbose = false\n      when '--verbose'\n        @config.verbose = true\n      when '--help'\n        print_usage $stdout\n        exit 0\n      when '--version'\n        puts \"#{File.basename($0)} version #{Version}\"\n        exit 0\n      when '--copyright'\n        puts Copyright\n        exit 0\n      else\n        setup_rb_error \"unknown global option '#{arg}'\"\n      end\n    end\n    nil\n  end\n\n  def valid_task?(t)\n    valid_task_re() =~ t\n  end\n\n  def valid_task_re\n    @valid_task_re ||= /\\A(?:#{TASKS.map {|task,desc| task }.join('|')})\\z/\n  end\n\n  def parsearg_no_options\n    unless ARGV.empty?\n      task = caller(0).first.slice(%r<`parsearg_(\\w+)'>, 1)\n      setup_rb_error \"#{task}: unknown options: #{ARGV.join(' ')}\"\n    end\n  end\n\n  alias parsearg_show       parsearg_no_options\n  alias parsearg_setup      parsearg_no_options\n  alias parsearg_test       parsearg_no_options\n  alias parsearg_clean      parsearg_no_options\n  alias parsearg_distclean  parsearg_no_options\n\n  def parsearg_config\n    evalopt = []\n    set = []\n    @config.config_opt = []\n    while i = ARGV.shift\n      if /\\A--?\\z/ =~ i\n        @config.config_opt = ARGV.dup\n        break\n      end\n      name, value = *@config.parse_opt(i)\n      if @config.value_config?(name)\n        @config[name] = value\n      else\n        evalopt.push [name, value]\n      end\n      set.push name\n    end\n    evalopt.each do |name, value|\n      @config.lookup(name).evaluate value, @config\n    end\n    # Check if configuration is valid\n    set.each do |n|\n      @config[n] if @config.value_config?(n)\n    end\n  end\n\n  def parsearg_install\n    @config.no_harm = false\n    @config.install_prefix = ''\n    while a = ARGV.shift\n      case a\n      when '--no-harm'\n        @config.no_harm = true\n      when /\\A--prefix=/\n        path = a.split(/=/, 2)[1]\n        path = File.expand_path(path) unless path[0,1] == '/'\n        @config.install_prefix = path\n      else\n        setup_rb_error \"install: unknown option #{a}\"\n      end\n    end\n  end\n\n  def print_usage(out)\n    out.puts 'Typical Installation Procedure:'\n    out.puts \"  $ ruby #{File.basename $0} config\"\n    out.puts \"  $ ruby #{File.basename $0} setup\"\n    out.puts \"  # ruby #{File.basename $0} install (may require root privilege)\"\n    out.puts\n    out.puts 'Detailed Usage:'\n    out.puts \"  ruby #{File.basename $0} <global option>\"\n    out.puts \"  ruby #{File.basename $0} [<global options>] <task> [<task options>]\"\n\n    fmt = \"  %-24s %s\\n\"\n    out.puts\n    out.puts 'Global options:'\n    out.printf fmt, '-q,--quiet',   'suppress message outputs'\n    out.printf fmt, '   --verbose', 'output messages verbosely'\n    out.printf fmt, '   --help',    'print this message'\n    out.printf fmt, '   --version', 'print version and quit'\n    out.printf fmt, '   --copyright',  'print copyright and quit'\n    out.puts\n    out.puts 'Tasks:'\n    TASKS.each do |name, desc|\n      out.printf fmt, name, desc\n    end\n\n    fmt = \"  %-24s %s [%s]\\n\"\n    out.puts\n    out.puts 'Options for CONFIG or ALL:'\n    @config.each do |item|\n      out.printf fmt, item.help_opt, item.description, item.help_default\n    end\n    out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',\"running ruby's\"\n    out.puts\n    out.puts 'Options for INSTALL:'\n    out.printf fmt, '--no-harm', 'only display what to do if given', 'off'\n    out.printf fmt, '--prefix=path',  'install path prefix', ''\n    out.puts\n  end\n\n  #\n  # Task Handlers\n  #\n\n  def exec_config\n    @installer.exec_config\n    @config.save   # must be final\n  end\n\n  def exec_setup\n    @installer.exec_setup\n  end\n\n  def exec_install\n    @installer.exec_install\n  end\n\n  def exec_test\n    @installer.exec_test\n  end\n\n  def exec_show\n    @config.each do |i|\n      printf \"%-20s %s\\n\", i.name, i.value if i.value?\n    end\n  end\n\n  def exec_clean\n    @installer.exec_clean\n  end\n\n  def exec_distclean\n    @installer.exec_distclean\n  end\n\nend   # class ToplevelInstaller\n\n\nclass ToplevelInstallerMulti < ToplevelInstaller\n\n  include FileOperations\n\n  def initialize(ardir_root, config)\n    super\n    @packages = directories_of(\"#{@ardir}/packages\")\n    raise 'no package exists' if @packages.empty?\n    @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))\n  end\n\n  def run_metaconfigs\n    @config.load_script \"#{@ardir}/metaconfig\", self\n    @packages.each do |name|\n      @config.load_script \"#{@ardir}/packages/#{name}/metaconfig\"\n    end\n  end\n\n  attr_reader :packages\n\n  def packages=(list)\n    raise 'package list is empty' if list.empty?\n    list.each do |name|\n      raise \"directory packages/#{name} does not exist\"\\\n              unless File.dir?(\"#{@ardir}/packages/#{name}\")\n    end\n    @packages = list\n  end\n\n  def init_installers\n    @installers = {}\n    @packages.each do |pack|\n      @installers[pack] = Installer.new(@config,\n                                       \"#{@ardir}/packages/#{pack}\",\n                                       \"packages/#{pack}\")\n    end\n    with    = extract_selection(config('with'))\n    without = extract_selection(config('without'))\n    @selected = @installers.keys.select {|name|\n                  (with.empty? or with.include?(name)) \\\n                      and not without.include?(name)\n                }\n  end\n\n  def extract_selection(list)\n    a = list.split(/,/)\n    a.each do |name|\n      setup_rb_error \"no such package: #{name}\"  unless @installers.key?(name)\n    end\n    a\n  end\n\n  def print_usage(f)\n    super\n    f.puts 'Inluded packages:'\n    f.puts '  ' + @packages.sort.join(' ')\n    f.puts\n  end\n\n  #\n  # Task Handlers\n  #\n\n  def exec_config\n    run_hook 'pre-config'\n    each_selected_installers {|inst| inst.exec_config }\n    run_hook 'post-config'\n    @config.save   # must be final\n  end\n\n  def exec_setup\n    run_hook 'pre-setup'\n    each_selected_installers {|inst| inst.exec_setup }\n    run_hook 'post-setup'\n  end\n\n  def exec_install\n    run_hook 'pre-install'\n    each_selected_installers {|inst| inst.exec_install }\n    run_hook 'post-install'\n  end\n\n  def exec_test\n    run_hook 'pre-test'\n    each_selected_installers {|inst| inst.exec_test }\n    run_hook 'post-test'\n  end\n\n  def exec_clean\n    rm_f @config.savefile\n    run_hook 'pre-clean'\n    each_selected_installers {|inst| inst.exec_clean }\n    run_hook 'post-clean'\n  end\n\n  def exec_distclean\n    rm_f @config.savefile\n    run_hook 'pre-distclean'\n    each_selected_installers {|inst| inst.exec_distclean }\n    run_hook 'post-distclean'\n  end\n\n  #\n  # lib\n  #\n\n  def each_selected_installers\n    Dir.mkdir 'packages' unless File.dir?('packages')\n    @selected.each do |pack|\n      $stderr.puts \"Processing the package `#{pack}' ...\" if verbose?\n      Dir.mkdir \"packages/#{pack}\" unless File.dir?(\"packages/#{pack}\")\n      Dir.chdir \"packages/#{pack}\"\n      yield @installers[pack]\n      Dir.chdir '../..'\n    end\n  end\n\n  def run_hook(id)\n    @root_installer.run_hook id\n  end\n\n  # module FileOperations requires this\n  def verbose?\n    @config.verbose?\n  end\n\n  # module FileOperations requires this\n  def no_harm?\n    @config.no_harm?\n  end\n\nend   # class ToplevelInstallerMulti\n\n\nclass Installer\n\n  FILETYPES = %w( bin lib ext data conf man )\n\n  include FileOperations\n  include HookScriptAPI\n\n  def initialize(config, srcroot, objroot)\n    @config = config\n    @srcdir = File.expand_path(srcroot)\n    @objdir = File.expand_path(objroot)\n    @currdir = '.'\n  end\n\n  def inspect\n    \"#<#{self.class} #{File.basename(@srcdir)}>\"\n  end\n\n  def noop(rel)\n  end\n\n  #\n  # Hook Script API base methods\n  #\n\n  def srcdir_root\n    @srcdir\n  end\n\n  def objdir_root\n    @objdir\n  end\n\n  def relpath\n    @currdir\n  end\n\n  #\n  # Config Access\n  #\n\n  # module FileOperations requires this\n  def verbose?\n    @config.verbose?\n  end\n\n  # module FileOperations requires this\n  def no_harm?\n    @config.no_harm?\n  end\n\n  def verbose_off\n    begin\n      save, @config.verbose = @config.verbose?, false\n      yield\n    ensure\n      @config.verbose = save\n    end\n  end\n\n  #\n  # TASK config\n  #\n\n  def exec_config\n    exec_task_traverse 'config'\n  end\n\n  alias config_dir_bin noop\n  alias config_dir_lib noop\n\n  def config_dir_ext(rel)\n    extconf if extdir?(curr_srcdir())\n  end\n\n  alias config_dir_data noop\n  alias config_dir_conf noop\n  alias config_dir_man noop\n\n  def extconf\n    ruby \"#{curr_srcdir()}/extconf.rb\", *@config.config_opt\n  end\n\n  #\n  # TASK setup\n  #\n\n  def exec_setup\n    exec_task_traverse 'setup'\n  end\n\n  def setup_dir_bin(rel)\n    files_of(curr_srcdir()).each do |fname|\n      update_shebang_line \"#{curr_srcdir()}/#{fname}\"\n    end\n  end\n\n  alias setup_dir_lib noop\n\n  def setup_dir_ext(rel)\n    make if extdir?(curr_srcdir())\n  end\n\n  alias setup_dir_data noop\n  alias setup_dir_conf noop\n  alias setup_dir_man noop\n\n  def update_shebang_line(path)\n    return if no_harm?\n    return if config('shebang') == 'never'\n    old = Shebang.load(path)\n    if old\n      $stderr.puts \"warning: #{path}: Shebang line includes too many args.  It is not portable and your program may not work.\" if old.args.size > 1\n      new = new_shebang(old)\n      return if new.to_s == old.to_s\n    else\n      return unless config('shebang') == 'all'\n      new = Shebang.new(config('rubypath'))\n    end\n    $stderr.puts \"updating shebang: #{File.basename(path)}\" if verbose?\n    open_atomic_writer(path) {|output|\n      File.open(path, 'rb') {|f|\n        f.gets if old   # discard\n        output.puts new.to_s\n        output.print f.read\n      }\n    }\n  end\n\n  def new_shebang(old)\n    if /\\Aruby/ =~ File.basename(old.cmd)\n      Shebang.new(config('rubypath'), old.args)\n    elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'\n      Shebang.new(config('rubypath'), old.args[1..-1])\n    else\n      return old unless config('shebang') == 'all'\n      Shebang.new(config('rubypath'))\n    end\n  end\n\n  def open_atomic_writer(path, &block)\n    tmpfile = File.basename(path) + '.tmp'\n    begin\n      File.open(tmpfile, 'wb', &block)\n      File.rename tmpfile, File.basename(path)\n    ensure\n      File.unlink tmpfile if File.exist?(tmpfile)\n    end\n  end\n\n  class Shebang\n    def Shebang.load(path)\n      line = nil\n      File.open(path) {|f|\n        line = f.gets\n      }\n      return nil unless /\\A#!/ =~ line\n      parse(line)\n    end\n\n    def Shebang.parse(line)\n      cmd, *args = *line.strip.sub(/\\A\\#!/, '').split(' ')\n      new(cmd, args)\n    end\n\n    def initialize(cmd, args = [])\n      @cmd = cmd\n      @args = args\n    end\n\n    attr_reader :cmd\n    attr_reader :args\n\n    def to_s\n      \"#! #{@cmd}\" + (@args.empty? ? '' : \" #{@args.join(' ')}\")\n    end\n  end\n\n  #\n  # TASK install\n  #\n\n  def exec_install\n    rm_f 'InstalledFiles'\n    exec_task_traverse 'install'\n  end\n\n  def install_dir_bin(rel)\n    install_files targetfiles(), \"#{config('bindir')}/#{rel}\", 0755\n  end\n\n  def install_dir_lib(rel)\n    install_files libfiles(), \"#{config('rbdir')}/#{rel}\", 0644\n  end\n\n  def install_dir_ext(rel)\n    return unless extdir?(curr_srcdir())\n    install_files rubyextentions('.'),\n                  \"#{config('sodir')}/#{File.dirname(rel)}\",\n                  0555\n  end\n\n  def install_dir_data(rel)\n    install_files targetfiles(), \"#{config('datadir')}/#{rel}\", 0644\n  end\n\n  def install_dir_conf(rel)\n    # FIXME: should not remove current config files\n    # (rename previous file to .old/.org)\n    install_files targetfiles(), \"#{config('sysconfdir')}/#{rel}\", 0644\n  end\n\n  def install_dir_man(rel)\n    install_files targetfiles(), \"#{config('mandir')}/#{rel}\", 0644\n  end\n\n  def install_files(list, dest, mode)\n    mkdir_p dest, @config.install_prefix\n    list.each do |fname|\n      install fname, dest, mode, @config.install_prefix\n    end\n  end\n\n  def libfiles\n    glob_reject(%w(*.y *.output), targetfiles())\n  end\n\n  def rubyextentions(dir)\n    ents = glob_select(\"*.#{@config.dllext}\", targetfiles())\n    if ents.empty?\n      setup_rb_error \"no ruby extention exists: 'ruby #{$0} setup' first\"\n    end\n    ents\n  end\n\n  def targetfiles\n    mapdir(existfiles() - hookfiles())\n  end\n\n  def mapdir(ents)\n    ents.map {|ent|\n      if File.exist?(ent)\n      then ent                         # objdir\n      else \"#{curr_srcdir()}/#{ent}\"   # srcdir\n      end\n    }\n  end\n\n  # picked up many entries from cvs-1.11.1/src/ignore.c\n  JUNK_FILES = %w( \n    core RCSLOG tags TAGS .make.state\n    .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb\n    *~ *.old *.bak *.BAK *.orig *.rej _$* *$\n\n    *.org *.in .*\n  )\n\n  def existfiles\n    glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))\n  end\n\n  def hookfiles\n    %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|\n      %w( config setup install clean ).map {|t| sprintf(fmt, t) }\n    }.flatten\n  end\n\n  def glob_select(pat, ents)\n    re = globs2re([pat])\n    ents.select {|ent| re =~ ent }\n  end\n\n  def glob_reject(pats, ents)\n    re = globs2re(pats)\n    ents.reject {|ent| re =~ ent }\n  end\n\n  GLOB2REGEX = {\n    '.' => '\\.',\n    '$' => '\\$',\n    '#' => '\\#',\n    '*' => '.*'\n  }\n\n  def globs2re(pats)\n    /\\A(?:#{\n      pats.map {|pat| pat.gsub(/[\\.\\$\\#\\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')\n    })\\z/\n  end\n\n  #\n  # TASK test\n  #\n\n  TESTDIR = 'test'\n\n  def exec_test\n    unless File.directory?('test')\n      $stderr.puts 'no test in this package' if verbose?\n      return\n    end\n    $stderr.puts 'Running tests...' if verbose?\n    begin\n      require 'test/unit'\n    rescue LoadError\n      setup_rb_error 'test/unit cannot loaded.  You need Ruby 1.8 or later to invoke this task.'\n    end\n    runner = Test::Unit::AutoRunner.new(true)\n    runner.to_run << TESTDIR\n    runner.run\n  end\n\n  #\n  # TASK clean\n  #\n\n  def exec_clean\n    exec_task_traverse 'clean'\n    rm_f @config.savefile\n    rm_f 'InstalledFiles'\n  end\n\n  alias clean_dir_bin noop\n  alias clean_dir_lib noop\n  alias clean_dir_data noop\n  alias clean_dir_conf noop\n  alias clean_dir_man noop\n\n  def clean_dir_ext(rel)\n    return unless extdir?(curr_srcdir())\n    make 'clean' if File.file?('Makefile')\n  end\n\n  #\n  # TASK distclean\n  #\n\n  def exec_distclean\n    exec_task_traverse 'distclean'\n    rm_f @config.savefile\n    rm_f 'InstalledFiles'\n  end\n\n  alias distclean_dir_bin noop\n  alias distclean_dir_lib noop\n\n  def distclean_dir_ext(rel)\n    return unless extdir?(curr_srcdir())\n    make 'distclean' if File.file?('Makefile')\n  end\n\n  alias distclean_dir_data noop\n  alias distclean_dir_conf noop\n  alias distclean_dir_man noop\n\n  #\n  # Traversing\n  #\n\n  def exec_task_traverse(task)\n    run_hook \"pre-#{task}\"\n    FILETYPES.each do |type|\n      if type == 'ext' and config('without-ext') == 'yes'\n        $stderr.puts 'skipping ext/* by user option' if verbose?\n        next\n      end\n      traverse task, type, \"#{task}_dir_#{type}\"\n    end\n    run_hook \"post-#{task}\"\n  end\n\n  def traverse(task, rel, mid)\n    dive_into(rel) {\n      run_hook \"pre-#{task}\"\n      __send__ mid, rel.sub(%r[\\A.*?(?:/|\\z)], '')\n      directories_of(curr_srcdir()).each do |d|\n        traverse task, \"#{rel}/#{d}\", mid\n      end\n      run_hook \"post-#{task}\"\n    }\n  end\n\n  def dive_into(rel)\n    return unless File.dir?(\"#{@srcdir}/#{rel}\")\n\n    dir = File.basename(rel)\n    Dir.mkdir dir unless File.dir?(dir)\n    prevdir = Dir.pwd\n    Dir.chdir dir\n    $stderr.puts '---> ' + rel if verbose?\n    @currdir = rel\n    yield\n    Dir.chdir prevdir\n    $stderr.puts '<--- ' + rel if verbose?\n    @currdir = File.dirname(rel)\n  end\n\n  def run_hook(id)\n    path = [ \"#{curr_srcdir()}/#{id}\",\n             \"#{curr_srcdir()}/#{id}.rb\" ].detect {|cand| File.file?(cand) }\n    return unless path\n    begin\n      instance_eval File.read(path), path, 1\n    rescue\n      raise if $DEBUG\n      setup_rb_error \"hook #{path} failed:\\n\" + $!.message\n    end\n  end\n\nend   # class Installer\n\n\nclass SetupError < StandardError; end\n\ndef setup_rb_error(msg)\n  raise SetupError, msg\nend\n\nif $0 == __FILE__\n  begin\n    ToplevelInstaller.invoke\n  rescue SetupError\n    raise if $DEBUG\n    $stderr.puts $!.message\n    $stderr.puts \"Try 'ruby #{$0} --help' for detailed usage.\"\n    exit 1\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/googlecharts/spec/fixtures/another_test_theme.yml",
    "content": ":test_two:\n  :colors:\n    - &blue 6886B4\n    - &yellow FDD84E\n    - &grey 333333\n  :bar_colors: [ *blue, *yellow ]\n  :background: *grey\n  :chart_background: *grey\n"
  },
  {
    "path": "vendor/plugins/googlecharts/spec/fixtures/test_theme.yml",
    "content": ":test:\n  :colors:\n    - &blue 6886B4\n    - &yellow FDD84E\n    - &white FFFFFF\n  :bar_colors: [ *blue, *yellow ]\n  :background: *white\n  :chart_background: *white"
  },
  {
    "path": "vendor/plugins/googlecharts/spec/gchart_spec.rb",
    "content": "require File.dirname(__FILE__) + '/spec_helper.rb'\nrequire File.dirname(__FILE__) + '/../lib/gchart'\n\nChart::Theme.add_theme_file(\"#{File.dirname(__FILE__)}/fixtures/test_theme.yml\")\n\n# Time to add your specs!\n# http://rspec.rubyforge.org/\ndescribe \"generating a default Gchart\" do\n\n  before(:each) do\n    @chart = Gchart.line\n  end\n\n  it \"should include the Google URL\" do\n    @chart.include?(\"http://chart.apis.google.com/chart?\").should be_true\n  end\n\n  it \"should have a default size\" do\n    @chart.should include('chs=300x200')\n  end\n\n  it \"should be able to have a custom size\" do\n    Gchart.line(:size => '400x600').include?('chs=400x600').should be_true\n    Gchart.line(:width => 400, :height => 600).include?('chs=400x600').should be_true\n  end\n\n  it \"should have query parameters in predictable order\" do\n    Gchart.line(:axis_with_labels => 'x,y,r', :size => '400x600').should match(/chxt=.+cht=.+chs=/)\n  end\n\n  it \"should have a type\" do\n    @chart.include?('cht=lc').should be_true\n  end\n\n  it 'should use theme defaults if theme is set' do\n    Gchart.line(:theme=>:test).should include('chco=6886B4,FDD84E')\n    if RUBY_VERSION.to_f < 1.9\n      Gchart.line(:theme=>:test).should include(Gchart.jstize('chf=c,s,FFFFFF|bg,s,FFFFFF')) \n    else\n       Gchart.line(:theme=>:test).should include(Gchart.jstize('chf=bg,s,FFFFFF|c,s,FFFFFF'))\n    end\n  end\n\n  it \"should use the simple encoding by default with auto max value\" do\n    # 9 is the max value in simple encoding, 26 being our max value the 2nd encoded value should be 9\n    Gchart.line(:data => [0, 26]).should include('chd=s:A9')\n    Gchart.line(:data => [0, 26], :max_value => 26).should == Gchart.line(:data => [0, 26])\n  end\n\n  it \"should support simple encoding with and without max_value\" do\n    Gchart.line(:data => [0, 26], :max_value => 26).should include('chd=s:A9')\n    Gchart.line(:data => [0, 26], :max_value => false).should include('chd=s:Aa')\n  end\n\n  it \"should support the extended encoding and encode properly\" do\n    Gchart.line(:data => [0, 10], :encoding => 'extended', :max_value => false).include?('chd=e:AA').should be_true\n    Gchart.line(:encoding => 'extended',\n                :max_value => false,\n                :data => [[0,25,26,51,52,61,62,63], [64,89,90,115,4084]]\n                ).include?('chd=e:AAAZAaAzA0A9A-A.,BABZBaBz.0').should be_true\n  end\n\n  it \"should auto set the max value for extended encoding\" do\n    Gchart.line(:data => [0, 25], :encoding => 'extended', :max_value => false).should include('chd=e:AAAZ')\n    # Extended encoding max value is '..'\n    Gchart.line(:data => [0, 25], :encoding => 'extended').include?('chd=e:AA..').should be_true\n  end\n\n  it \"should be able to have data with text encoding\" do\n    Gchart.line(:data => [10, 5.2, 4, 45, 78], :encoding => 'text').should include('chd=t:10,5.2,4,45,78')\n  end\n\n  it \"should handle max and min values with text encoding\" do\n    Gchart.line(:data => [10, 5.2, 4, 45, 78], :encoding => 'text').should include('chds=0,78')\n  end\n\n  it \"should automatically handle negative values with proper max/min limits when using text encoding\" do\n    Gchart.line(:data => [-10, 5.2, 4, 45, 78], :encoding => 'text').should include('chds=-10,78')\n  end\n\n  it \"should handle negative values with manual max/min limits when using text encoding\" do\n   Gchart.line(:data => [-10, 5.2, 4, 45, 78], :encoding => 'text', :min_value => -20, :max_value => 100).include?('chds=-20,100').should be_true\n  end\n\n  it \"should set the proper axis values when using text encoding and negative values\" do\n    Gchart.bar( :data       => [[-10], [100]],\n                :encoding   => 'text',\n                :horizontal => true,\n                :min_value  => -20,\n                :max_value  => 100,\n                :axis_with_labels => 'x',\n                :bar_colors => ['FD9A3B', '4BC7DC']).should include(\"chxr=0,-20,100\")\n  end\n\n  it \"should be able to have muliple set of data with text encoding\" do\n    Gchart.line(:data => [[10, 5.2, 4, 45, 78], [20, 40, 70, 15, 99]], :encoding => 'text').include?(Gchart.jstize('chd=t:10,5.2,4,45,78|20,40,70,15,99')).should be_true\n  end\n\n  it \"should be able to receive a custom param\" do\n    Gchart.line(:custom => 'ceci_est_une_pipe').include?('ceci_est_une_pipe').should be_true\n  end\n\n  it \"should be able to set label axis\" do\n    Gchart.line(:axis_with_labels => 'x,y,r').include?('chxt=x,y,r').should be_true\n    Gchart.line(:axis_with_labels => ['x','y','r']).include?('chxt=x,y,r').should be_true\n  end\n\n  it \"should be able to have axis labels\" do\n   Gchart.line(:axis_labels => ['Jan|July|Jan|July|Jan', '0|100', 'A|B|C', '2005|2006|2007']).include?(Gchart.jstize('chxl=0:|Jan|July|Jan|July|Jan|1:|0|100|2:|A|B|C|3:|2005|2006|2007')).should be_true\n   Gchart.line(:axis_labels => ['Jan|July|Jan|July|Jan']).include?(Gchart.jstize('chxl=0:|Jan|July|Jan|July|Jan')).should be_true\n   Gchart.line(:axis_labels => [['Jan','July','Jan','July','Jan']]).include?(Gchart.jstize('chxl=0:|Jan|July|Jan|July|Jan')).should be_true\n   Gchart.line(:axis_labels => [['Jan','July','Jan','July','Jan'], ['0','100'], ['A','B','C'], ['2005','2006','2007']]).include?(Gchart.jstize('chxl=0:|Jan|July|Jan|July|Jan|1:|0|100|2:|A|B|C|3:|2005|2006|2007')).should be_true\n  end\n  \n  it \"should display ranges properly\" do\n    data = [85,107,123,131,155,172,173,189,203,222,217,233,250,239,256,267,247,261,275,295,288,305,322,307,325,347,331,346,363,382,343,359,383,352,374,393,358,379,396,416,377,398,419,380,409,426,453,432,452,465,436,460,480,440,457,474,501,457,489,507,347,373,413,402,424,448,475,488,513,475,507,530,440,476,500,518,481,512,531,367,396,423,387,415,446,478,442,469,492,463,489,508,463,491,518,549,503,526,547,493,530,549,493,520,541,564,510,535,564,492,512,537,502,530,548,491,514,538,568,524,548,568,512,533,552,577,520,545,570,516,536,555,514,536,566,521,553,579,604,541,569,595,551,581,602,549,576,606,631,589,615,650,597,624,646,672,605,626,654,584,608,631,574,597,622,559,591,614,644,580,603,629,584,615,631,558,591,618,641,314,356,395,397,429,450,421,454,477,507,458,490,560,593]\n    url = Gchart.line(:data => data, :axis_with_labels => 'x,y', :axis_labels => [(1.upto(24).to_a << 1)])\n    url.should include('chxr=1,85,593')\n  end\n  \n  it \"should take in consideration the max value when creating a range\" do\n    data = [85,107,123,131,155,172,173,189,203,222,217,233,250,239,256,267,247,261,275,295,288,305,322,307,325,347,331,346,363,382,343,359,383,352,374,393,358,379,396,416,377,398,419,380,409,426,453,432,452,465,436,460,480,440,457,474,501,457,489,507,347,373,413,402,424,448,475,488,513,475,507,530,440,476,500,518,481,512,531,367,396,423,387,415,446,478,442,469,492,463,489,508,463,491,518,549,503,526,547,493,530,549,493,520,541,564,510,535,564,492,512,537,502,530,548,491,514,538,568,524,548,568,512,533,552,577,520,545,570,516,536,555,514,536,566,521,553,579,604,541,569,595,551,581,602,549,576,606,631,589,615,650,597,624,646,672,605,626,654,584,608,631,574,597,622,559,591,614,644,580,603,629,584,615,631,558,591,618,641,314,356,395,397,429,450,421,454,477,507,458,490,560,593]\n    url = Gchart.line(:data => data, :axis_with_labels => 'x,y', :axis_labels => [(1.upto(24).to_a << 1)], :max_value => 700)\n    url.should include('chxr=1,85,700')\n  end\n\nend\n\ndescribe \"generating different type of charts\" do\n\n  it \"should be able to generate a line chart\" do\n    Gchart.line.should be_an_instance_of(String)\n    Gchart.line.include?('cht=lc').should be_true\n  end\n\n  it \"should be able to generate a sparkline chart\" do\n    Gchart.sparkline.should be_an_instance_of(String)\n    Gchart.sparkline.include?('cht=ls').should be_true\n  end\n\n  it \"should be able to generate a line xy chart\" do\n    Gchart.line_xy.should be_an_instance_of(String)\n    Gchart.line_xy.include?('cht=lxy').should be_true\n  end\n\n  it \"should be able to generate a scatter chart\" do\n    Gchart.scatter.should be_an_instance_of(String)\n    Gchart.scatter.include?('cht=s').should be_true\n  end\n\n  it \"should be able to generate a bar chart\" do\n    Gchart.bar.should be_an_instance_of(String)\n    Gchart.bar.include?('cht=bvs').should be_true\n  end\n\n  it \"should be able to generate a Venn diagram\" do\n    Gchart.venn.should be_an_instance_of(String)\n    Gchart.venn.include?('cht=v').should be_true\n  end\n\n  it \"should be able to generate a Pie Chart\" do\n    Gchart.pie.should be_an_instance_of(String)\n    Gchart.pie.include?('cht=p').should be_true\n  end\n\n  it \"should be able to generate a Google-O-Meter\" do\n    Gchart.meter.should be_an_instance_of(String)\n    Gchart.meter.include?('cht=gom').should be_true\n  end\n\n  it \"should be able to generate a map chart\" do\n    Gchart.map.should be_an_instance_of(String)\n    Gchart.map.include?('cht=t').should be_true\n  end\n\n  it \"should not support other types\" do\n    lambda{Gchart.sexy}.should raise_error\n    # msg => \"sexy is not a supported chart format, please use one of the following: #{Gchart.supported_types}.\"\n  end\n\nend\n\n\ndescribe \"range markers\" do\n\n  it \"should be able to generate given a hash of range-marker options\" do\n    Gchart.line(:range_markers => {:start_position => 0.59, :stop_position => 0.61, :color => 'ff0000'}).include?('chm=r,ff0000,0,0.59,0.61').should be_true\n  end\n\n  it \"should be able to generate given an array of range-marker hash options\" do\n    Gchart.line(:range_markers => [\n          {:start_position => 0.59, :stop_position => 0.61, :color => 'ff0000'},\n          {:start_position => 0, :stop_position => 0.6, :color => '666666'},\n          {:color => 'cccccc', :start_position => 0.6, :stop_position => 1}\n        ]).include?(Gchart.jstize('r,ff0000,0,0.59,0.61|r,666666,0,0,0.6|r,cccccc,0,0.6,1')).should be_true\n  end\n\n  it \"should allow a :overlaid? to be set\" do\n    Gchart.line(:range_markers => {:start_position => 0.59, :stop_position => 0.61, :color => 'ffffff', :overlaid? => true}).include?('chm=r,ffffff,0,0.59,0.61,1').should be_true\n    Gchart.line(:range_markers => {:start_position => 0.59, :stop_position => 0.61, :color => 'ffffff', :overlaid? => false}).include?('chm=r,ffffff,0,0.59,0.61').should be_true\n  end\n\n  describe \"when setting the orientation option\" do\n    before(:each) do\n      options = {:start_position => 0.59, :stop_position => 0.61, :color => 'ff0000'}\n    end\n\n    it \"to vertical (R) if given a valid option\" do\n      Gchart.line(:range_markers => options.merge(:orientation => 'v')).include?('chm=R').should be_true\n      Gchart.line(:range_markers => options.merge(:orientation => 'V')).include?('chm=R').should be_true\n      Gchart.line(:range_markers => options.merge(:orientation => 'R')).include?('chm=R').should be_true\n      Gchart.line(:range_markers => options.merge(:orientation => 'vertical')).include?('chm=R').should be_true\n      Gchart.line(:range_markers => options.merge(:orientation => 'Vertical')).include?('chm=R').should be_true\n    end\n\n    it \"to horizontal (r) if given a valid option (actually anything other than the vertical options)\" do\n      Gchart.line(:range_markers => options.merge(:orientation => 'horizontal')).include?('chm=r').should be_true\n      Gchart.line(:range_markers => options.merge(:orientation => 'h')).include?('chm=r').should be_true\n      Gchart.line(:range_markers => options.merge(:orientation => 'etc')).include?('chm=r').should be_true\n    end\n\n    it \"if left blank defaults to horizontal (r)\" do\n      Gchart.line(:range_markers => options).include?('chm=r').should be_true\n    end\n  end\n\nend\n\n\ndescribe \"a bar graph\" do\n\n  it \"should have a default vertical orientation\" do\n    Gchart.bar.include?('cht=bvs').should be_true\n  end\n\n  it \"should be able to have a different orientation\" do\n    Gchart.bar(:orientation => 'vertical').include?('cht=bvs').should be_true\n    Gchart.bar(:orientation => 'v').include?('cht=bvs').should be_true\n    Gchart.bar(:orientation => 'h').include?('cht=bhs').should be_true\n    Gchart.bar(:orientation => 'horizontal').include?('cht=bhs').should be_true\n    Gchart.bar(:horizontal => false).include?('cht=bvs').should be_true\n  end\n\n  it \"should be set to be stacked by default\" do\n    Gchart.bar.include?('cht=bvs').should be_true\n  end\n\n  it \"should be able to stacked or grouped\" do\n    Gchart.bar(:stacked => true).include?('cht=bvs').should be_true\n    Gchart.bar(:stacked => false).include?('cht=bvg').should be_true\n    Gchart.bar(:grouped => true).include?('cht=bvg').should be_true\n    Gchart.bar(:grouped => false).include?('cht=bvs').should be_true\n  end\n\n  it \"should be able to have different bar colors\" do\n    Gchart.bar(:bar_colors => 'efefef,00ffff').include?('chco=').should be_true\n    Gchart.bar(:bar_colors => 'efefef,00ffff').include?('chco=efefef,00ffff').should be_true\n    # alias\n    Gchart.bar(:bar_color => 'efefef').include?('chco=efefef').should be_true\n  end\n\n  it \"should be able to have different bar colors when using an array of colors\" do\n    Gchart.bar(:bar_colors => ['efefef','00ffff']).include?('chco=efefef,00ffff').should be_true\n  end\n\n  it 'should be able to accept a string of width and spacing options' do\n    Gchart.bar(:bar_width_and_spacing => '25,6').include?('chbh=25,6').should be_true\n  end\n\n  it 'should be able to accept a single fixnum width and spacing option to set the bar width' do\n    Gchart.bar(:bar_width_and_spacing => 25).include?('chbh=25').should be_true\n  end\n\n  it 'should be able to accept an array of width and spacing options' do\n    Gchart.bar(:bar_width_and_spacing => [25,6,12]).include?('chbh=25,6,12').should be_true\n    Gchart.bar(:bar_width_and_spacing => [25,6]).include?('chbh=25,6').should be_true\n    Gchart.bar(:bar_width_and_spacing => [25]).include?('chbh=25').should be_true\n  end\n\n  describe \"with a hash of width and spacing options\" do\n\n    before(:each) do\n      @default_width         = 23\n      @default_spacing       = 4\n      @default_group_spacing = 8\n    end\n\n    it 'should be able to have a custom bar width' do\n      Gchart.bar(:bar_width_and_spacing => {:width => 19}).include?(\"chbh=19,#{@default_spacing},#{@default_group_spacing}\").should be_true\n    end\n\n    it 'should be able to have custom spacing' do\n      Gchart.bar(:bar_width_and_spacing => {:spacing => 19}).include?(\"chbh=#{@default_width},19,#{@default_group_spacing}\").should be_true\n    end\n\n    it 'should be able to have custom group spacing' do\n      Gchart.bar(:bar_width_and_spacing => {:group_spacing => 19}).include?(\"chbh=#{@default_width},#{@default_spacing},19\").should be_true\n    end\n\n  end\n\nend\n\ndescribe \"a line chart\" do\n\n  before(:each) do\n    @title = 'Chart Title'\n    @legend = ['first data set label', 'n data set label']\n    @chart = Gchart.line(:title => @title, :legend => @legend)\n  end\n\n  it 'should be able have a chart title' do\n    @chart.include?(\"chtt=Chart+Title\").should be_true\n  end\n\n  it \"should be able to a custom color and size title\" do\n     Gchart.line(:title => @title, :title_color => 'FF0000').include?('chts=FF0000').should be_true\n     Gchart.line(:title => @title, :title_size => '20').include?('chts=454545,20').should be_true\n  end\n\n  it \"should be able to have multiple legends\" do\n    @chart.include?(Gchart.jstize(\"chdl=first+data+set+label|n+data+set+label\")).should be_true\n  end\n\n  it \"should escape text values in url\" do\n    title = 'Chart & Title'\n    legend = ['first data & set label', 'n data set label']\n    chart = Gchart.line(:title => title, :legend => legend)\n    chart.include?(Gchart.jstize(\"chdl=first+data+%26+set+label|n+data+set+label\")).should be_true\n  end\n\n  it \"should be able to have one legend\" do\n    chart = Gchart.line(:legend => 'legend label')\n    chart.include?(\"chdl=legend+label\").should be_true\n  end\n\n  it \"should be able to set the background fill\" do\n    Gchart.line(:bg => 'efefef').should include(\"chf=bg,s,efefef\")\n    Gchart.line(:bg => {:color => 'efefef', :type => 'solid'}).should include(\"chf=bg,s,efefef\")\n\n    Gchart.line(:bg => {:color => 'efefef', :type => 'gradient'}).should include(\"chf=bg,lg,0,efefef,0,ffffff,1\")\n    Gchart.line(:bg => {:color => 'efefef,0,ffffff,1', :type => 'gradient'}).should include(\"chf=bg,lg,0,efefef,0,ffffff,1\")\n    Gchart.line(:bg => {:color => 'efefef', :type => 'gradient', :angle => 90}).should include(\"chf=bg,lg,90,efefef,0,ffffff,1\")\n\n    Gchart.line(:bg => {:color => 'efefef', :type => 'stripes'}).should include(\"chf=bg,ls,90,efefef,0.2,ffffff,0.2\")\n  end\n\n  it \"should be able to set a graph fill\" do\n    Gchart.line(:graph_bg => 'efefef').should include(\"chf=c,s,efefef\")\n    Gchart.line(:graph_bg => {:color => 'efefef', :type => 'solid'}).include?(\"chf=c,s,efefef\").should be_true\n    Gchart.line(:graph_bg => {:color => 'efefef', :type => 'gradient'}).include?(\"chf=c,lg,0,efefef,0,ffffff,1\").should be_true\n    Gchart.line(:graph_bg => {:color => 'efefef,0,ffffff,1', :type => 'gradient'}).include?(\"chf=c,lg,0,efefef,0,ffffff,1\").should be_true\n    Gchart.line(:graph_bg => {:color => 'efefef', :type => 'gradient', :angle => 90}).include?(\"chf=c,lg,90,efefef,0,ffffff,1\").should be_true\n  end\n\n  it \"should be able to set both a graph and a background fill\" do\n    Gchart.line(:bg => 'efefef', :graph_bg => '76A4FB').include?(\"bg,s,efefef\").should be_true\n    Gchart.line(:bg => 'efefef', :graph_bg => '76A4FB').include?(\"c,s,76A4FB\").should be_true\n    if RUBY_VERSION.to_f < 1.9\n      Gchart.line(:bg => 'efefef', :graph_bg => '76A4FB').include?(Gchart.jstize(\"chf=c,s,76A4FB|bg,s,efefef\")).should be_true      \n    else\n      Gchart.line(:bg => 'efefef', :graph_bg => '76A4FB').include?(Gchart.jstize(\"chf=bg,s,efefef|c,s,76A4FB\")).should be_true\n    end\n  end\n\n  it \"should be able to have different line colors\" do\n    Gchart.line(:line_colors => 'efefef|00ffff').include?(Gchart.jstize('chco=efefef|00ffff')).should be_true\n    Gchart.line(:line_color => 'efefef|00ffff').include?(Gchart.jstize('chco=efefef|00ffff')).should be_true\n  end\n\n  it \"should be able to render a graph where all the data values are 0\" do\n    Gchart.line(:data => [0, 0, 0]).should include(\"chd=s:AAA\")\n  end\n\nend\n\ndescribe \"a sparkline chart\" do\n\n  before(:each) do\n    @title = 'Chart Title'\n    @legend = ['first data set label', 'n data set label']\n    @jstized_legend = Gchart.jstize(@legend.join('|'))\n    @data = [27,25,25,25,25,27,100,31,25,36,25,25,39,25,31,25,25,25,26,26,25,25,28,25,25,100,28,27,31,25,27,27,29,25,27,26,26,25,26,26,35,33,34,25,26,25,36,25,26,37,33,33,37,37,39,25,25,25,25]\n    @chart = Gchart.sparkline(:title => @title, :data => @data, :legend => @legend)\n  end\n\n  it \"should create a sparkline\" do\n    @chart.include?('cht=ls').should be_true\n  end\n\n  it 'should be able have a chart title' do\n    @chart.include?(\"chtt=Chart+Title\").should be_true\n  end\n\n  it \"should be able to a custom color and size title\" do\n     Gchart.sparkline(:title => @title, :title_color => 'FF0000').include?('chts=FF0000').should be_true\n     Gchart.sparkline(:title => @title, :title_size => '20').include?('chts=454545,20').should be_true\n  end\n\n  it \"should be able to have multiple legends\" do\n    @chart.include?(Gchart.jstize(\"chdl=first+data+set+label|n+data+set+label\")).should be_true\n  end\n\n  it \"should be able to have one legend\" do\n    chart = Gchart.sparkline(:legend => 'legend label')\n    chart.include?(\"chdl=legend+label\").should be_true\n  end\n\n  it \"should be able to set the background fill\" do\n    Gchart.sparkline(:bg => 'efefef').include?(\"chf=bg,s,efefef\").should be_true\n    Gchart.sparkline(:bg => {:color => 'efefef', :type => 'solid'}).include?(\"chf=bg,s,efefef\").should be_true\n\n    Gchart.sparkline(:bg => {:color => 'efefef', :type => 'gradient'}).include?(\"chf=bg,lg,0,efefef,0,ffffff,1\").should be_true\n    Gchart.sparkline(:bg => {:color => 'efefef,0,ffffff,1', :type => 'gradient'}).include?(\"chf=bg,lg,0,efefef,0,ffffff,1\").should be_true\n    Gchart.sparkline(:bg => {:color => 'efefef', :type => 'gradient', :angle => 90}).include?(\"chf=bg,lg,90,efefef,0,ffffff,1\").should be_true\n\n    Gchart.sparkline(:bg => {:color => 'efefef', :type => 'stripes'}).include?(\"chf=bg,ls,90,efefef,0.2,ffffff,0.2\").should be_true\n  end\n\n  it \"should be able to set a graph fill\" do\n    Gchart.sparkline(:graph_bg => 'efefef').include?(\"chf=c,s,efefef\").should be_true\n    Gchart.sparkline(:graph_bg => {:color => 'efefef', :type => 'solid'}).include?(\"chf=c,s,efefef\").should be_true\n    Gchart.sparkline(:graph_bg => {:color => 'efefef', :type => 'gradient'}).include?(\"chf=c,lg,0,efefef,0,ffffff,1\").should be_true\n    Gchart.sparkline(:graph_bg => {:color => 'efefef,0,ffffff,1', :type => 'gradient'}).include?(\"chf=c,lg,0,efefef,0,ffffff,1\").should be_true\n    Gchart.sparkline(:graph_bg => {:color => 'efefef', :type => 'gradient', :angle => 90}).include?(\"chf=c,lg,90,efefef,0,ffffff,1\").should be_true\n  end\n\n  it \"should be able to set both a graph and a background fill\" do\n    Gchart.sparkline(:bg => 'efefef', :graph_bg => '76A4FB').include?(\"bg,s,efefef\").should be_true\n    Gchart.sparkline(:bg => 'efefef', :graph_bg => '76A4FB').include?(\"c,s,76A4FB\").should be_true\n    if RUBY_VERSION.to_f < 1.9\n      Gchart.sparkline(:bg => 'efefef', :graph_bg => '76A4FB').include?(Gchart.jstize(\"chf=c,s,76A4FB|bg,s,efefef\")).should be_true\n    else\n      Gchart.sparkline(:bg => 'efefef', :graph_bg => '76A4FB').include?(Gchart.jstize(\"chf=bg,s,efefef|c,s,76A4FB\")).should be_true\n    end\n  end\n\n  it \"should be able to have different line colors\" do\n    Gchart.sparkline(:line_colors => 'efefef|00ffff').include?(Gchart.jstize('chco=efefef|00ffff')).should be_true\n    Gchart.sparkline(:line_color => 'efefef|00ffff').include?(Gchart.jstize('chco=efefef|00ffff')).should be_true\n  end\n\nend\n\ndescribe \"a 3d pie chart\" do\n\n  before(:each) do\n    @title = 'Chart Title'\n    @legend = ['first data set label', 'n data set label']\n    @jstized_legend = Gchart.jstize(@legend.join('|'))\n    @data = [12,8,40,15,5]\n    @chart = Gchart.pie(:title => @title, :legend => @legend, :data => @data)\n  end\n\n  it \"should create a pie\" do\n    @chart.include?('cht=p').should be_true\n  end\n\n  it \"should be able to be in 3d\" do\n    Gchart.pie_3d(:title => @title, :legend => @legend, :data => @data).include?('cht=p3').should be_true\n  end\n\n  it \"should be able to set labels by using the legend or labesl accessor\" do\n    Gchart.pie_3d(:title => @title, :legend => @legend, :data => @data).should include(\"chl=#{@jstized_legend}\")\n    Gchart.pie_3d(:title => @title, :labels => @legend, :data => @data).should include(\"chl=#{@jstized_legend}\")\n    Gchart.pie_3d(:title => @title, :labels => @legend, :data => @data).should == Gchart.pie_3d(:title => @title, :legend => @legend, :data => @data)\n  end\n\nend\n\ndescribe \"a google-o-meter\" do\n\n  before(:each) do\n    @data = [70]\n    @legend = ['arrow points here']\n    @jstized_legend = Gchart.jstize(@legend.join('|'))\n    @chart = Gchart.meter(:data => @data)\n  end\n\n  it \"should create a meter\" do\n    @chart.include?('cht=gom').should be_true\n  end\n\n  it \"should be able to set a solid background fill\" do\n    Gchart.meter(:bg => 'efefef').include?(\"chf=bg,s,efefef\").should be_true\n    Gchart.meter(:bg => {:color => 'efefef', :type => 'solid'}).include?(\"chf=bg,s,efefef\").should be_true\n  end\n\nend\n\ndescribe \"a map chart\" do\n\n  before(:each) do\n    @data = [0,100,50,32]\n    @geographical_area = 'usa'\n    @map_colors = ['FFFFFF', 'FF0000', 'FFFF00', '00FF00']\n    @country_codes = ['MT', 'WY', \"ID\", 'SD']\n    @chart = Gchart.map(:data => @data, :encoding => 'text', :size => '400x300',\n      :geographical_area => @geographical_area, :map_colors => @map_colors,\n      :country_codes => @country_codes)\n  end\n\n  it \"should create a map\" do\n    @chart.include?('cht=t').should be_true\n  end\n\n  it \"should set the geographical area\" do\n    @chart.include?('chtm=usa').should be_true\n  end\n\n  it \"should set the map colors\" do\n    @chart.include?('chco=FFFFFF,FF0000,FFFF00,00FF00').should be_true\n  end\n\n  it \"should set the country/state codes\" do\n    @chart.include?('chld=MTWYIDSD').should be_true\n  end\n\n  it \"should set the chart data\" do\n    @chart.include?('chd=t:0,100,50,32').should be_true\n  end\n\nend\n\ndescribe 'exporting a chart' do\n\n  it \"should be available in the url format by default\" do\n    Gchart.line(:data => [0, 26], :format => 'url').should == Gchart.line(:data => [0, 26])\n  end\n\n  it \"should be available as an image tag\" do\n    Gchart.line(:data => [0, 26], :format => 'image_tag').should match(/<img src=(.*) width=\"300\" height=\"200\" alt=\"Google Chart\" \\/>/)\n  end\n\n  it \"should be available as an image tag using img_tag alias\" do\n    Gchart.line(:data => [0, 26], :format => 'img_tag').should match(/<img src=(.*) width=\"300\" height=\"200\" alt=\"Google Chart\" \\/>/)\n  end\n\n  it \"should be available as an image tag using custom dimensions\" do\n    Gchart.line(:data => [0, 26], :format => 'image_tag', :size => '400x400').should match(/<img src=(.*) width=\"400\" height=\"400\" alt=\"Google Chart\" \\/>/)\n  end\n\n  it \"should be available as an image tag using custom alt text\" do\n    Gchart.line(:data => [0, 26], :format => 'image_tag', :alt => 'Sexy chart').should match(/<img src=(.*) width=\"300\" height=\"200\" alt=\"Sexy chart\" \\/>/)\n  end\n\n  it \"should be available as an image tag using custom title text\" do\n    Gchart.line(:data => [0, 26], :format => 'image_tag', :title => 'Sexy chart').should match(/<img src=(.*) width=\"300\" height=\"200\" alt=\"Google Chart\" title=\"Sexy chart\" \\/>/)\n  end\n\n  it \"should be available as an image tag using custom css id selector\" do\n    Gchart.line(:data => [0, 26], :format => 'image_tag', :id => 'chart').should match(/<img id=\"chart\" src=(.*) width=\"300\" height=\"200\" alt=\"Google Chart\" \\/>/)\n  end\n\n  it \"should be available as an image tag using custom css class selector\" do\n    Gchart.line(:data => [0, 26], :format => 'image_tag', :class => 'chart').should match(/<img class=\"chart\" src=(.*) width=\"300\" height=\"200\" alt=\"Google Chart\" \\/>/)\n  end\n\n  it \"should use ampersands to separate key/value pairs in URLs by default\" do\n    Gchart.line(:data => [0, 26]).should satisfy {|chart| chart.include? \"&\" }\n    Gchart.line(:data => [0, 26]).should_not satisfy {|chart| chart.include? \"&amp;\" }\n  end\n\n  it \"should escape ampersands in URLs when used as an image tag\" do\n    Gchart.line(:data => [0, 26], :format => 'image_tag', :class => 'chart').should satisfy {|chart| chart.include? \"&amp;\" }\n  end\n\n  it \"should be available as a file\" do\n    File.delete('chart.png') if File.exist?('chart.png')\n    Gchart.line(:data => [0, 26], :format => 'file')\n    File.exist?('chart.png').should be_true\n    File.delete('chart.png') if File.exist?('chart.png')\n  end\n\n  it \"should be available as a file using a custom file name\" do\n    File.delete('custom_file_name.png') if File.exist?('custom_file_name.png')\n    Gchart.line(:data => [0, 26], :format => 'file', :filename => 'custom_file_name.png')\n    File.exist?('custom_file_name.png').should be_true\n    File.delete('custom_file_name.png') if File.exist?('custom_file_name.png')\n  end\n\n  it \"should work even with multiple attrs\" do\n    File.delete('foo.png') if File.exist?('foo.png')\n    Gchart.line(:size => '400x200',\n                :data => [1,2,3,4,5],\n                # :axis_labels => [[1,2,3,4, 5], %w[foo bar]],\n                :axis_with_labels => 'x,r',\n                :format => \"file\",\n                :filename => \"foo.png\"\n                )\n    File.exist?('foo.png').should be_true\n    File.delete('foo.png') if File.exist?('foo.png')\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/googlecharts/spec/spec_helper.rb",
    "content": "begin\n  require 'spec'\nrescue LoadError\n  require 'rubygems'\n  gem 'rspec'\n  require 'spec'\nend"
  },
  {
    "path": "vendor/plugins/googlecharts/spec/theme_spec.rb",
    "content": "require File.dirname(__FILE__) + '/spec_helper.rb'\nrequire File.dirname(__FILE__) + '/../lib/gchart'\n\ndescribe \"generating a default Gchart\" do\n  it 'should be able to add additional theme files' do\n    Chart::Theme.theme_files.should_not include(\"#{File.dirname(__FILE__)}/fixtures/another_test_theme.yml\")\n    Chart::Theme.add_theme_file(\"#{File.dirname(__FILE__)}/fixtures/another_test_theme.yml\")\n    Chart::Theme.theme_files.should include(\"#{File.dirname(__FILE__)}/fixtures/another_test_theme.yml\")\n  end\n  \n  it 'should be able to load themes from the additional theme files' do\n    lambda { Chart::Theme.load(:test_two) }.should_not raise_error\n  end\n  \n  it 'should raise ThemeNotFound if theme does not exist' do\n    lambda { Chart::Theme.load(:nonexistent) }.should raise_error(Chart::Theme::ThemeNotFound, \"Could not locate the nonexistent theme ...\")\n  end\n  \n  it 'should set colors array' do\n    Chart::Theme.load(:keynote).colors.should eql([\"6886B4\", \"FDD84E\", \"72AE6E\", \"D1695E\", \"8A6EAF\", \"EFAA43\", \"FFFFFF\", \"000000\"])\n  end\n  \n  it 'should set bar colors array' do\n    Chart::Theme.load(:keynote).bar_colors.should eql([\"6886B4\", \"FDD84E\", \"72AE6E\", \"D1695E\", \"8A6EAF\", \"EFAA43\"])\n  end\n  \n  it 'should set background' do\n    Chart::Theme.load(:keynote).background.should eql(\"000000\")\n  end\n  \n  it 'should set chart background' do\n    Chart::Theme.load(:keynote).chart_background.should eql(\"FFFFFF\")\n  end\nend"
  },
  {
    "path": "vendor/plugins/googlecharts/website/index.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <link rel=\"stylesheet\" href=\"stylesheets/screen.css\" type=\"text/css\" media=\"screen\" />\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>\n      Googlecharts\n  </title>\n  <script src=\"javascripts/rounded_corners_lite.inc.js\" type=\"text/javascript\"></script>\n<style>\n\n</style>\n  <script type=\"text/javascript\">\n    window.onload = function() {\n      settings = {\n          tl: { radius: 10 },\n          tr: { radius: 10 },\n          bl: { radius: 10 },\n          br: { radius: 10 },\n          antiAlias: true,\n          autoPad: true,\n          validTags: [\"div\"]\n      }\n      var versionBox = new curvyCorners(settings, document.getElementById(\"version\"));\n      versionBox.applyCornersToAll();\n    }\n  </script>\n</head>\n<body>\n<div id=\"main\">\n\n    <h1>Googlecharts</h1>\n    <div id=\"version\" class=\"clickable\" onclick='document.location = \"http://rubyforge.org/projects/googlecharts\"; return false'>\n      <p>Get Version</p>\n      <a href=\"http://rubyforge.org/projects/googlecharts\" class=\"numbers\">1.3.4</a>\n    </div>\n    <h2>&#x2192; &#8216;Sexy Charts using Google <span class=\"caps\">API</span> &#38; Ruby&#8217;</h2>\n\n\n\t<h2>What</h2>\n\n\n\t<p>A nice and simple wrapper for <a href=\"http://code.google.com/apis/chart/\">Google Chart <span class=\"caps\">API</span></a>\n(Fully tested using RSpec, check the specs for more usage examples)</p>\n\n\n\t<h2>Installing</h2>\n\n\n\t<p>This project is now hosted at <a href=\"http://github.com\">GitHub</a>\nIf you never added <a href=\"http://github.com\">GitHub</a> as a gem source, you will need to do the following:\n<pre class='syntax'><span class=\"global\">$ </span><span class=\"ident\">gem</span> <span class=\"ident\">sources</span> <span class=\"punct\">-</span><span class=\"ident\">a</span> <span class=\"ident\">http</span><span class=\"punct\">:/</span><span class=\"regex\"></span><span class=\"punct\">/</span><span class=\"ident\">gems</span><span class=\"punct\">.</span><span class=\"ident\">github</span><span class=\"punct\">.</span><span class=\"ident\">com</span><span class=\"punct\">/</span></pre> (you only need to do this once)</p>\n\n\n\t<p><pre class='syntax'><span class=\"global\">$ </span><span class=\"ident\">sudo</span> <span class=\"ident\">gem</span> <span class=\"ident\">install</span> <span class=\"ident\">mattetti</span><span class=\"punct\">-</span><span class=\"ident\">googlecharts</span></pre></p>\n\n\n\t<p>or <pre class='syntax'><span class=\"global\">$ </span><span class=\"ident\">sudo</span> <span class=\"ident\">gem</span> <span class=\"ident\">install</span> <span class=\"ident\">googlecharts</span></pre></p>\n\n\n\t<h2>The basics</h2>\n\n\n\t<p>This gem supports the following types of charts:</p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chs=200x125&#38;chd=s:helloWorld&#38;chxt=x,y&#38;chxl=0:|Mar|Apr|May|June|July|1:||50+Kb\" title=\"Line\" alt=\"Line\" /> Gchart.line()</p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lxy&#38;chs=200x125&#38;chd=t:0,30,60,70,90,95,100|20,30,40,50,60,70,80|10,30,40,45,52|100,90,40,20,10|-1|5,33,50,55,7&#38;chco=3072F3,ff0000,00aaaa&#38;chls=2,4,1&#38;chm=s,FF0000,0,-1,5|s,0000ff,1,-1,5|s,00aa00,2,-1,5\" title=\"line_xy\" alt=\"line_xy\" /> Gchart.line_xy()</p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=s&#38;chd=s:984sttvuvkQIBLKNCAIi,DEJPgq0uov17zwopQODS,AFLPTXaflptx159gsDrn&#38;chxt=x,y&#38;chxl=0:|0|2|3|4|5|6|7|8|9|10|1:|0|25|50|75|100&#38;chs=200x125\" title=\"scatter\" alt=\"scatter\" /> Gchart.scatter()</p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=bvg&#38;chs=200x125&#38;chd=s:hello,world&#38;chco=cc0000,00aa00\" title=\"bar\" alt=\"bar\" /> Gchart.bar()</p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=v&#38;chs=200x100&#38;chd=t:100,80,60,30,30,30,10\" title=\"venn\" alt=\"venn\" /> Gchart.venn()</p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=p&#38;chd=s:world5&#38;chs=200x125&#38;chl=A|B|C|D|E|Fe\" title=\"pie\" alt=\"pie\" /> Gchart.pie()</p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=p3&#38;chd=s:Uf9a&#38;chs=200x100&#38;chl=A|B|C|D\" title=\"pie_3d\" alt=\"pie_3d\" /> Gchart.pie_3d()</p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?chs=100x20&#38;cht=ls&#38;chco=0077CC&#38;chm=B,E6F2FA,0,0,0&#38;chls=1,0,0&#38;chd=t:27,25,25,25,25,27,100,31,25,36,25,25,39,25,31,25,25,25,26,26,25,25,28,25,25,100,28,27,31,25,27,27,29,25,27,26,26,25,26,26,35,33,34,25,26,25,36,25,26,37,33,33,37,37,39,25,25,25,25\" title=\"sparkline\" alt=\"sparkline\" />Gchart.sparkline()</p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?chs=225x125&#38;cht=gom&#38;chd=t:70&#38;chl=Flavor\" title=\"google-o-meter\" alt=\"google-o-meter\" /> Gchart.meter()</p>\n\n\n\t<h2>Demonstration of usage</h2>\n\n\n\t<p>install:</p>\n\n\n<code>sudo gem install mattetti-googlecharts</code>\n\n\t<p>or use rubyforge:</p>\n\n\n<code>sudo gem install googlecharts</code>\n\n\t<p>require:\n<pre class='syntax'><span class=\"ident\">require</span> <span class=\"punct\">'</span><span class=\"string\">gchart</span><span class=\"punct\">'</span></pre></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:size</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">200x300</span><span class=\"punct\">',</span> \n            <span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">example title</span><span class=\"punct\">&quot;,</span>\n            <span class=\"symbol\">:bg</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">efefef</span><span class=\"punct\">',</span>\n            <span class=\"symbol\">:legend</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">['</span><span class=\"string\">first data set label</span><span class=\"punct\">',</span> <span class=\"punct\">'</span><span class=\"string\">second data set label</span><span class=\"punct\">'],</span>\n            <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">120</span><span class=\"punct\">,</span> <span class=\"number\">45</span><span class=\"punct\">,</span> <span class=\"number\">72</span><span class=\"punct\">])</span></pre></p>\n\n\n<hr />\n\n\n\t<p><strong>simple line chart</strong>\n<pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">0</span><span class=\"punct\">,</span> <span class=\"number\">40</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">70</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">])</span>\n</pre></p>\n\n\n\t<p>Generate the following url: http://chart.apis.google.com/chart?chs=300&#215;200&#38;chd=s:AiI9R&#38;cht=lc</p>\n\n\n\t<p>Inserted in an image tag, it will look like that:</p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?chs=300x200&#38;chd=s:AiI9R&#38;cht=lc\" title=\"simple line chart\" alt=\"simple line chart\" /></p>\n\n\n\t<p><strong>multiple line charts</strong>\n<pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[[</span><span class=\"number\">0</span><span class=\"punct\">,</span> <span class=\"number\">40</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">70</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">],[</span><span class=\"number\">41</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">80</span><span class=\"punct\">,</span> <span class=\"number\">50</span><span class=\"punct\">]])</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chs=300x200&#38;chd=s:AeH1P,fH9m\" title=\"multiple lines chart\" alt=\"multiple lines chart\" /></p>\n\n\n\t<p><strong>set line colors</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[[</span><span class=\"number\">0</span><span class=\"punct\">,</span> <span class=\"number\">40</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">70</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">],[</span><span class=\"number\">41</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">80</span><span class=\"punct\">,</span> <span class=\"number\">50</span><span class=\"punct\">]],</span> <span class=\"symbol\">:line_colors</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">FF0000,00FF00</span><span class=\"punct\">&quot;)</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chs=300x200&#38;chd=s:AeH1P,fH9m&#38;chco=FF0000,00FF00\" title=\"line colors\" alt=\"line colors\" /></p>\n\n\n\t<p><a href=\"http://code.google.com/apis/chart/#chart_colors\">more info about color settings</a></p>\n\n\n\t<p><strong>sparkline chart</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"ident\">data</span> <span class=\"punct\">=</span> <span class=\"punct\">[</span><span class=\"number\">27</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">27</span><span class=\"punct\">,</span><span class=\"number\">100</span><span class=\"punct\">,</span><span class=\"number\">31</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">36</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">39</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">31</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">26</span><span class=\"punct\">,</span><span class=\"number\">26</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">28</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">100</span><span class=\"punct\">,</span><span class=\"number\">28</span><span class=\"punct\">,</span><span class=\"number\">27</span><span class=\"punct\">,</span><span class=\"number\">31</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">27</span><span class=\"punct\">,</span><span class=\"number\">27</span><span class=\"punct\">,</span><span class=\"number\">29</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">27</span><span class=\"punct\">,</span><span class=\"number\">26</span><span class=\"punct\">,</span><span class=\"number\">26</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">26</span><span class=\"punct\">,</span><span class=\"number\">26</span><span class=\"punct\">,</span><span class=\"number\">35</span><span class=\"punct\">,</span><span class=\"number\">33</span><span class=\"punct\">,</span><span class=\"number\">34</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">26</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">36</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">26</span><span class=\"punct\">,</span><span class=\"number\">37</span><span class=\"punct\">,</span><span class=\"number\">33</span><span class=\"punct\">,</span><span class=\"number\">33</span><span class=\"punct\">,</span><span class=\"number\">37</span><span class=\"punct\">,</span><span class=\"number\">37</span><span class=\"punct\">,</span><span class=\"number\">39</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">25</span><span class=\"punct\">]</span>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">sparkline</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"ident\">data</span><span class=\"punct\">,</span> <span class=\"symbol\">:size</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">120x40</span><span class=\"punct\">',</span> <span class=\"symbol\">:line_colors</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">0077CC</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?chd=s:QPPPPQ9SPVPPXPSPPPPPPPRPP9RQSPQQRPQPPPPPVUUPPPVPPWUUWWXPPPP&#38;chco=0077CC&#38;chs=120x40&#38;cht=ls\" title=\"sparline\" alt=\"sparline\" /></p>\n\n\n\t<p>A sparkline chart has exactly the same parameters as a line chart. The only difference is that the axes lines are not drawn for sparklines by default.</p>\n\n\n\t<p><strong>bar chart</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">])</span>\n</pre>\n<img src=\"http://chart.apis.google.com/chart?cht=bvs&#38;chs=300x200&#38;chd=s:9UGo\" title=\"bars\" alt=\"bars\" /></p>\n\n\n\t<p><strong>set the bar chart orientation</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">],</span> <span class=\"symbol\">:orientation</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">horizontal</span><span class=\"punct\">')</span>\n</pre>\n<img src=\"http://chart.apis.google.com/chart?cht=bhs&#38;chs=300x200&#38;chd=s:9UGo\" title=\"bars\" alt=\"bars\" /></p>\n\n\n\t<p><strong>multiple bars chart</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">],</span> <span class=\"punct\">[</span><span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">]])</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=bvs&#38;chs=300x200&#38;chd=s:9UGo,Uo9C\" title=\"stacked multiple bars\" alt=\"stacked multiple bars\" /></p>\n\n\n\t<p>The problem is that by default the bars are stacked, so we need to set the colors:</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">],</span> <span class=\"punct\">[</span><span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">]],</span> <span class=\"symbol\">:bar_colors</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">FF0000,00FF00</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p>If you prefer you can use this other syntax:</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">],</span> <span class=\"punct\">[</span><span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">]],</span> <span class=\"symbol\">:bar_colors</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">['</span><span class=\"string\">FF0000</span><span class=\"punct\">',</span> <span class=\"punct\">'</span><span class=\"string\">00FF00</span><span class=\"punct\">'])</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=bvs&#38;chs=300x200&#38;chd=s:9UGo,Uo9C&#38;chco=FF0000,00FF00\" title=\"colors\" alt=\"colors\" /></p>\n\n\n\t<p>The problem now, is that we can&#8217;t see the first value of the second dataset since it&#8217;s lower than the first value of the first dataset. Let&#8217;s unstack the bars:</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">],</span> <span class=\"punct\">[</span><span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">]],</span> \n           <span class=\"symbol\">:bar_colors</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">FF0000,00FF00</span><span class=\"punct\">',</span>\n           <span class=\"symbol\">:stacked</span> <span class=\"punct\">=&gt;</span> <span class=\"constant\">false</span> <span class=\"punct\">)</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=bvg&#38;chs=300x200&#38;chd=s:9UGo,Uo9C&#38;chco=FF0000,00FF00\" title=\"grouped bars\" alt=\"grouped bars\" /></p>\n\n\n\t<p><strong>bar chart width and spacing</strong></p>\n\n\n\t<p>A bar chart can accept options to set the width of the bars, spacing between bars and spacing between bar groups. To set these, you can either provide a string, array or hash.</p>\n\n\n\t<p>The Google <span class=\"caps\">API</span> sets these options in the order of width, spacing, and group spacing, with both spacing values being optional. So, if you provide a string or array, provide them in that order:</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"attribute\">@data</span><span class=\"punct\">,</span> <span class=\"symbol\">:bar_width_and_spacing</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">25,6</span><span class=\"punct\">')</span> <span class=\"comment\"># width of 25, spacing of 6</span>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"attribute\">@data</span><span class=\"punct\">,</span> <span class=\"symbol\">:bar_width_and_spacing</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">25,6,12</span><span class=\"punct\">')</span> <span class=\"comment\"># width of 25, spacing of 6, group spacing of 12</span>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"attribute\">@data</span><span class=\"punct\">,</span> <span class=\"symbol\">:bar_width_and_spacing</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">25</span><span class=\"punct\">,</span><span class=\"number\">6</span><span class=\"punct\">])</span> <span class=\"comment\"># width of 25, spacing of 6</span>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"attribute\">@data</span><span class=\"punct\">,</span> <span class=\"symbol\">:bar_width_and_spacing</span> <span class=\"punct\">=&gt;</span> <span class=\"number\">25</span><span class=\"punct\">)</span> <span class=\"comment\"># width of 25</span>\n</pre></p>\n\n\n\t<p>The hash lets you set these values directly, with the Google default values set for any options you don&#8217;t include:</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"attribute\">@data</span><span class=\"punct\">,</span> <span class=\"symbol\">:bar_width_and_spacing</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">{</span><span class=\"symbol\">:width</span> <span class=\"punct\">=&gt;</span> <span class=\"number\">19</span><span class=\"punct\">})</span>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"attribute\">@data</span><span class=\"punct\">,</span> <span class=\"symbol\">:bar_width_and_spacing</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">{</span><span class=\"symbol\">:spacing</span> <span class=\"punct\">=&gt;</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"symbol\">:group_spacing</span> <span class=\"punct\">=&gt;</span> <span class=\"number\">12</span><span class=\"punct\">})</span>\n</pre></p>\n\n\n\t<p><strong>pie chart</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">pie</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">35</span><span class=\"punct\">,</span> <span class=\"number\">45</span><span class=\"punct\">])</span>\n</pre>\n<img src=\"http://chart.apis.google.com/chart?cht=p&#38;chs=300x200&#38;chd=s:bv9\" title=\"Pie Chart\" alt=\"Pie Chart\" /></p>\n\n\n\t<p><strong>3D pie chart</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">pie_3d</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">35</span><span class=\"punct\">,</span> <span class=\"number\">45</span><span class=\"punct\">])</span>\n</pre>\n<img src=\"http://chart.apis.google.com/chart?cht=p3&#38;chs=300x200&#38;chd=s:bv9\" title=\"Pie Chart\" alt=\"Pie Chart\" /></p>\n\n\n\t<p><strong>venn diagram</strong></p>\n\n\n\t<p><a href=\"http://code.google.com/apis/chart/#venn\">Google documentation</a></p>\n\n\nData set:\n\t<ul>\n\t<li>the first three values specify the relative sizes of three circles, A, B, and C</li>\n\t\t<li>the fourth value specifies the area of A intersecting B</li>\n\t\t<li>the fifth value specifies the area of B intersecting C</li>\n\t\t<li>the sixth value specifies the area of C intersecting A</li>\n\t\t<li>the seventh value specifies the area of A intersecting B intersecting C</li>\n\t</ul>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">venn</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">80</span><span class=\"punct\">,</span> <span class=\"number\">60</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">])</span>\n</pre>\n<img src=\"http://chart.apis.google.com/chart?cht=v&#38;chs=300x200&#38;chd=s:9wkSSSG\" title=\"Venn\" alt=\"Venn\" /></p>\n\n\n\t<p><strong>scatter plot</strong></p>\n\n\n\t<p><a href=\"http://code.google.com/apis/chart/#scatter_plot\">Google Documentation</a></p>\n\n\n\t<p>Supply two data sets, the first data set specifies x coordinates, the second set specifies y coordinates, the third set the data point size.</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">scatter</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[[</span><span class=\"number\">1</span><span class=\"punct\">,</span> <span class=\"number\">2</span><span class=\"punct\">,</span> <span class=\"number\">3</span><span class=\"punct\">,</span> <span class=\"number\">4</span><span class=\"punct\">,</span> <span class=\"number\">5</span><span class=\"punct\">],</span> <span class=\"punct\">[</span><span class=\"number\">1</span><span class=\"punct\">,</span> <span class=\"number\">2</span><span class=\"punct\">,</span> <span class=\"number\">3</span><span class=\"punct\">,</span> <span class=\"number\">4</span> <span class=\"punct\">,</span><span class=\"number\">5</span><span class=\"punct\">],</span> <span class=\"punct\">[</span><span class=\"number\">5</span><span class=\"punct\">,</span> <span class=\"number\">4</span><span class=\"punct\">,</span> <span class=\"number\">3</span><span class=\"punct\">,</span> <span class=\"number\">2</span><span class=\"punct\">,</span> <span class=\"number\">1</span><span class=\"punct\">]])</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=s&#38;chs=300x200&#38;chd=s:MYkw9,MYkw9,9wkYM\" title=\"scatter\" alt=\"scatter\" /></p>\n\n\n\t<p><strong>google-o-meter</strong></p>\n\n\n\t<p><a href=\"http://code.google.com/apis/chart/#gom\">Google Documentation</a></p>\n\n\n\t<p>Supply a single label that will be what the arrow points to. It only supports a solid fill for the background.</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">meter</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">70</span><span class=\"punct\">],</span> <span class=\"symbol\">:label</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">['</span><span class=\"string\">Flavor</span><span class=\"punct\">'])</span>\n</pre></p>\n\n\n<hr />\n\n\n\t<p><strong>set a chart title</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Recent Chart Sexyness</span><span class=\"punct\">&quot;,</span> <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">15</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">40</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">])</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=bvs&#38;chs=300x200&#38;chd=s:JSGM9MY9&#38;chtt=Recent+Chart+Sexyness\" title=\"chart title\" alt=\"chart title\" /></p>\n\n\n\t<p><strong>set the title size</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Recent Chart Sexyness</span><span class=\"punct\">&quot;,</span> <span class=\"symbol\">:title_size</span> <span class=\"punct\">=&gt;</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">15</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">40</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">])</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=bvs&#38;chs=300x200&#38;chd=s:JSGM9MY9&#38;chtt=Recent+Chart+Sexyness&#38;chts=454545,20\" title=\"title size\" alt=\"title size\" /></p>\n\n\n\t<p><strong>set the title color</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Recent Chart Sexyness</span><span class=\"punct\">&quot;,</span> <span class=\"symbol\">:title_color</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">FF0000</span><span class=\"punct\">',</span> <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">15</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">40</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">])</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=bvs&#38;chs=300x200&#38;chd=s:JSGM9MY9&#38;chtt=Recent+Chart+Sexyness&#38;chts=FF0000\" title=\"Title color\" alt=\"Title color\" /></p>\n\n\n\t<p><strong>set the chart&#8217;s size</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Recent Chart Sexyness</span><span class=\"punct\">&quot;,</span> \n           <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">15</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">40</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">],</span>\n           <span class=\"symbol\">:size</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">600x400</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=bvs&#38;chs=600x400&#38;chd=s:JSGM9MY9&#38;chtt=Recent+Chart+Sexyness\" title=\"size\" alt=\"size\" /></p>\n\n\n\t<p><strong>set the image background color</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Matt's Mojo</span><span class=\"punct\">&quot;,</span> \n           <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">15</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">40</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">90</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">80</span><span class=\"punct\">],</span>\n           <span class=\"symbol\">:background</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">FF9994</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?chf=bg,s,FF9994&#38;cht=bvs&#38;chs=300x200&#38;chd=s:JSGM9MY929w&#38;chtt=Matt's+Mojo\" title=\"Background\" alt=\"Background\" /></p>\n\n\n\t<p><strong>set the chart background color</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Matt's Mojo</span><span class=\"punct\">&quot;,</span> \n           <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">15</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">40</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">90</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">80</span><span class=\"punct\">],</span>\n           <span class=\"symbol\">:background</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">FF9994</span><span class=\"punct\">',</span> <span class=\"symbol\">:chart_background</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">000000</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?chf=c,s,000000|bg,s,FF9994&#38;cht=bvs&#38;chs=300x200&#38;chd=s:JSGM9MY929w&#38;chtt=Matt's+Mojo\" title=\"chart background\" alt=\"chart background\" /></p>\n\n\n\t<p><strong>Set bar/line colors</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Matt's Mojo</span><span class=\"punct\">&quot;,</span> \n           <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">15</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">40</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">90</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">80</span><span class=\"punct\">],</span>\n           <span class=\"symbol\">:bar_colors</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">76A4FB</span><span class=\"punct\">',</span>\n           <span class=\"symbol\">:background</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">EEEEEE</span><span class=\"punct\">',</span> <span class=\"symbol\">:chart_background</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">CCCCCC</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?chf=c,s,CCCCCC|bg,s,EEEEEE&#38;cht=bvs&#38;chs=300x200&#38;chd=s:JSGM9MY929w&#38;chco=76A4FB&#38;chtt=Matt's+Mojo\" title=\"bar colors\" alt=\"bar colors\" /></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Matt's Mojo</span><span class=\"punct\">&quot;,</span> \n            <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">15</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">40</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">90</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">80</span><span class=\"punct\">],</span>\n            <span class=\"symbol\">:line_colors</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">76A4FB</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chs=300x200&#38;chd=s:JSGM9MY929w&#38;chco=76A4FB&#38;chtt=Matt's+Mojo\" title=\"line colors\" alt=\"line colors\" /></p>\n\n\n\t<p><strong>legend / labels</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">bar</span><span class=\"punct\">(</span><span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Matt vs Rob</span><span class=\"punct\">&quot;,</span>\n           <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">],</span> <span class=\"punct\">[</span><span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">]],</span> \n           <span class=\"symbol\">:bar_colors</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">FF0000,00FF00</span><span class=\"punct\">',</span>\n           <span class=\"symbol\">:stacked</span> <span class=\"punct\">=&gt;</span> <span class=\"constant\">false</span><span class=\"punct\">,</span> <span class=\"symbol\">:size</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">400x200</span><span class=\"punct\">',</span>\n           <span class=\"symbol\">:legend</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[&quot;</span><span class=\"string\">Matt's Mojo</span><span class=\"punct\">&quot;,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Rob's Mojo</span><span class=\"punct\">&quot;]</span> <span class=\"punct\">)</span>\n</pre>\n<img src=\"http://chart.apis.google.com/chart?cht=bvg&#38;chdl=Matt's+Mojo|Rob's+Mojo&#38;chs=400x200&#38;chd=s:9UGo,Uo9C&#38;chco=FF0000,00FF00&#38;chtt=Matt+vs+Rob\" title=\"legend\" alt=\"legend\" /></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Matt vs Rob</span><span class=\"punct\">&quot;,</span>\n            <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">],</span> <span class=\"punct\">[</span><span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">]],</span> \n            <span class=\"symbol\">:bar_colors</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">['</span><span class=\"string\">FF0000</span><span class=\"punct\">','</span><span class=\"string\">00FF00</span><span class=\"punct\">'],</span>\n            <span class=\"symbol\">:stacked</span> <span class=\"punct\">=&gt;</span> <span class=\"constant\">false</span><span class=\"punct\">,</span> <span class=\"symbol\">:size</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">400x200</span><span class=\"punct\">',</span>\n            <span class=\"symbol\">:legend</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[&quot;</span><span class=\"string\">Matt's Mojo</span><span class=\"punct\">&quot;,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Rob's Mojo</span><span class=\"punct\">&quot;]</span> <span class=\"punct\">)</span>\n</pre>\n<img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chdl=Matt's+Mojo|Rob's+Mojo&#38;chs=400x200&#38;chd=s:9UGo,Uo9C&#38;chco=FF0000,00FF00&#38;chtt=Matt+vs+Rob\" title=\"line legend\" alt=\"line legend\" /></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">pie_3d</span><span class=\"punct\">(</span><span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">ruby_fu</span><span class=\"punct\">',</span> <span class=\"symbol\">:size</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">400x200</span><span class=\"punct\">',</span>\n              <span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">45</span><span class=\"punct\">,</span> <span class=\"number\">45</span><span class=\"punct\">],</span> <span class=\"symbol\">:labels</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[&quot;</span><span class=\"string\">DHH</span><span class=\"punct\">&quot;,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Rob</span><span class=\"punct\">&quot;,</span> <span class=\"punct\">&quot;</span><span class=\"string\">Matt</span><span class=\"punct\">&quot;]</span> <span class=\"punct\">)</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=p3&#38;chl=DHH|Rob|Matt&#38;chs=400x200&#38;chd=s:N99&#38;chtt=ruby_fu\" title=\"labels\" alt=\"labels\" /></p>\n\n\n\t<p><strong>Display axis labels</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">],</span> <span class=\"symbol\">:axis_with_labels</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">x,y,r</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p>or you can use the other syntax:</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">],</span> <span class=\"symbol\">:axis_with_labels</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">['</span><span class=\"string\">x</span><span class=\"punct\">','</span><span class=\"string\">y</span><span class=\"punct\">','</span><span class=\"string\">r</span><span class=\"punct\">'])</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chs=300x200&#38;chxt=x,y,r&#38;chd=s:9UGoUo9C\" title=\"axis with labels\" alt=\"axis with labels\" /></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">],</span> <span class=\"symbol\">:axis_with_labels</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">x</span><span class=\"punct\">',</span>\n            <span class=\"symbol\">:axis_labels</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">['</span><span class=\"string\">Jan|July|Jan|July|Jan</span><span class=\"punct\">'])</span>\n</pre></p>\n\n\n\t<p>or you can use the other syntax:</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">],</span> <span class=\"symbol\">:axis_with_labels</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">x</span><span class=\"punct\">',</span>\n            <span class=\"symbol\">:axis_labels</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">['</span><span class=\"string\">Jan</span><span class=\"punct\">','</span><span class=\"string\">July</span><span class=\"punct\">','</span><span class=\"string\">Jan</span><span class=\"punct\">','</span><span class=\"string\">July</span><span class=\"punct\">','</span><span class=\"string\">Jan</span><span class=\"punct\">'])</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chxl=0:|Jan|July|Jan|July|Jan&#38;chs=300x200&#38;chxt=x&#38;chd=s:9UGoUo9C\" title=\"x labels\" alt=\"x labels\" /></p>\n\n\n\t<p><strong>multiple axis labels</strong></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">],</span> <span class=\"symbol\">:axis_with_labels</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">x,r</span><span class=\"punct\">',</span>\n            <span class=\"symbol\">:axis_labels</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">['</span><span class=\"string\">Jan|July|Jan|July|Jan</span><span class=\"punct\">',</span> <span class=\"punct\">'</span><span class=\"string\">2005|2006|2007</span><span class=\"punct\">'])</span>\n</pre></p>\n\n\n\t<p>or</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">],</span> <span class=\"symbol\">:axis_with_labels</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">x,r</span><span class=\"punct\">',</span>\n            <span class=\"symbol\">:axis_labels</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[['</span><span class=\"string\">Jan</span><span class=\"punct\">','</span><span class=\"string\">July</span><span class=\"punct\">','</span><span class=\"string\">Jan</span><span class=\"punct\">','</span><span class=\"string\">July</span><span class=\"punct\">','</span><span class=\"string\">Jan</span><span class=\"punct\">'],</span> <span class=\"punct\">['</span><span class=\"string\">2005</span><span class=\"punct\">','</span><span class=\"string\">2006</span><span class=\"punct\">','</span><span class=\"string\">2007</span><span class=\"punct\">']])</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chxl=0:|Jan|July|Jan|July|Jan|1:|2005|2006|2007&#38;chs=300x200&#38;chxt=x,r&#38;chd=s:9UGoUo9C\" title=\"multiple axis labels\" alt=\"multiple axis labels\" /></p>\n\n\n\t<p>(This syntax will probably be improved in the future)</p>\n\n\n\t<p><strong>custom params</strong></p>\n\n\n\t<p>I certainly didn&#8217;t cover the entire <span class=\"caps\">API</span>, if you want to add your own params:</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:custom</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">chd=s:93zyvneTTOMJMLIJFHEAECFJGHDBFCFIERcgnpy45879,IJKNUWUWYdnswz047977315533zy1246872tnkgcaZQONHCECAAAAEII&amp;chls=3,6,3|1,1,0</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chs=300x200&#38;chd=s:93zyvneTTOMJMLIJFHEAECFJGHDBFCFIERcgnpy45879,IJKNUWUWYdnswz047977315533zy1246872tnkgcaZQONHCECAAAAEII&#38;chls=3,6,3|1,1,0\" title=\"Custom\" alt=\"Custom\" /></p>\n\n\n<hr />\n\n\n\t<p><strong>Save the chart as a file</strong></p>\n\n\n\t<p>You might prefer to save the chart instead of using the url, not a problem:</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">0</span><span class=\"punct\">,</span> <span class=\"number\">26</span><span class=\"punct\">],</span> <span class=\"symbol\">:format</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">file</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p>You might want to specify the path and/or the filename used to save your chart:</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">0</span><span class=\"punct\">,</span> <span class=\"number\">26</span><span class=\"punct\">],</span> <span class=\"symbol\">:format</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">file</span><span class=\"punct\">',</span> <span class=\"symbol\">:filename</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">custom_filename.png</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p><strong>Insert as an image tag</strong></p>\n\n\n\t<p>Because, I&#8217;m lazy, you can generate a full image tag, with support for standard html options.</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">0</span><span class=\"punct\">,</span> <span class=\"number\">26</span><span class=\"punct\">],</span> <span class=\"symbol\">:format</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">image_tag</span><span class=\"punct\">')</span>\n</pre></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"punct\">&lt;</span><span class=\"ident\">img</span> <span class=\"ident\">src</span><span class=\"punct\">=&quot;</span><span class=\"string\">http://chart.apis.google.com/chart?chs=300x200&amp;amp;chd=s:A9&amp;amp;cht=lc</span><span class=\"punct\">&quot;</span> <span class=\"ident\">width</span><span class=\"punct\">=&quot;</span><span class=\"string\">300</span><span class=\"punct\">&quot;</span> <span class=\"ident\">height</span><span class=\"punct\">=&quot;</span><span class=\"string\">200</span><span class=\"punct\">&quot;</span> <span class=\"ident\">alt</span><span class=\"punct\">=&quot;</span><span class=\"string\">Google Chart</span><span class=\"punct\">&quot;</span> <span class=\"punct\">/&gt;</span>\n</pre></p>\n\n\n\t<p>Here are a few more examples:</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">0</span><span class=\"punct\">,</span> <span class=\"number\">26</span><span class=\"punct\">],</span> <span class=\"symbol\">:format</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">image_tag</span><span class=\"punct\">')</span>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">0</span><span class=\"punct\">,</span> <span class=\"number\">26</span><span class=\"punct\">],</span> <span class=\"symbol\">:format</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">image_tag</span><span class=\"punct\">',</span> <span class=\"symbol\">:id</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">sexy</span><span class=\"punct\">&quot;)</span>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">0</span><span class=\"punct\">,</span> <span class=\"number\">26</span><span class=\"punct\">],</span> <span class=\"symbol\">:format</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">image_tag</span><span class=\"punct\">',</span> <span class=\"symbol\">:class</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">chart</span><span class=\"punct\">&quot;)</span>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">0</span><span class=\"punct\">,</span> <span class=\"number\">26</span><span class=\"punct\">],</span> <span class=\"symbol\">:format</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">image_tag</span><span class=\"punct\">',</span> <span class=\"symbol\">:alt</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Sexy Chart</span><span class=\"punct\">&quot;)</span>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">0</span><span class=\"punct\">,</span> <span class=\"number\">26</span><span class=\"punct\">],</span> <span class=\"symbol\">:format</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">image_tag</span><span class=\"punct\">',</span> <span class=\"symbol\">:title</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">&quot;</span><span class=\"string\">Sexy Chart</span><span class=\"punct\">&quot;)</span>\n</pre></p>\n\n\n\t<p>Image dimensions will be automatically set based on your chart&#8217;s size.</p>\n\n\n<hr />\n\n\n\t<p><strong>Encoding</strong></p>\n\n\n\t<p>Google Chart <span class=\"caps\">API</span> offers <a href=\"http://code.google.com/apis/chart/#chart_data\">3 types of data encoding</a></p>\n\n\n\t<ul>\n\t<li>simple</li>\n\t\t<li>text</li>\n\t\t<li>extended</li>\n\t</ul>\n\n\n\t<p>By default this library uses the simple encoding, if you need a different type of encoding, you can change it really easily:</p>\n\n\n\t<p>default / simple: chd=s:9UGoUo9C\n<pre class='syntax'>\n  <span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">]</span> <span class=\"punct\">)</span>\n</pre></p>\n\n\n\t<p>extended: chd=e:..VVGZqqVVqq..CI\n<pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">],</span> <span class=\"symbol\">:encoding</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">extended</span><span class=\"punct\">'</span> <span class=\"punct\">)</span>\n</pre></p>\n\n\n\t<p>text: chd=t:300,100,30,200,100,200,300,10\n<pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">],</span> <span class=\"symbol\">:encoding</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">'</span><span class=\"string\">text</span><span class=\"punct\">'</span> <span class=\"punct\">)</span>\n</pre></p>\n\n\n\t<p>(note that the text encoding doesn&#8217;t use a max value and therefore should be under 100)</p>\n\n\n\t<p><strong>Max value</strong></p>\n\n\n\t<p>Simple and extended encoding support the max value option.</p>\n\n\n\t<p>The max value option is a simple way of scaling your graph. The data is converted in chart value with the highest chart value being the highest point on the graph. By default, the calculation is done for you. However you can specify your own maximum or not use a maximum at all.</p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">]</span> <span class=\"punct\">)</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chs=300x200&#38;chd=s:9UGoUo9C\" title=\"Title\" alt=\"Title\" /></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">200</span><span class=\"punct\">,</span> <span class=\"number\">300</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">],</span> <span class=\"symbol\">:max_value</span> <span class=\"punct\">=&gt;</span> <span class=\"number\">500</span> <span class=\"punct\">)</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chs=300x200&#38;chd=s:kMDYMYkB\" title=\"max 500\" alt=\"max 500\" /></p>\n\n\n\t<p><pre class='syntax'>\n<span class=\"constant\">Gchart</span><span class=\"punct\">.</span><span class=\"ident\">line</span><span class=\"punct\">(</span><span class=\"symbol\">:data</span> <span class=\"punct\">=&gt;</span> <span class=\"punct\">[</span><span class=\"number\">100</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">20</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">,</span> <span class=\"number\">14</span><span class=\"punct\">,</span> <span class=\"number\">30</span><span class=\"punct\">,</span> <span class=\"number\">10</span><span class=\"punct\">],</span> <span class=\"symbol\">:max_value</span> <span class=\"punct\">=&gt;</span> <span class=\"constant\">false</span> <span class=\"punct\">)</span>\n</pre></p>\n\n\n\t<p><img src=\"http://chart.apis.google.com/chart?cht=lc&#38;chs=300x200&#38;chd=s:_UeUKOeK\" title=\"real size\" alt=\"real size\" /></p>\n\n\n\t<h2>Repository</h2>\n\n\n\t<p>The trunk repository is <code>http://github.com/mattetti/googlecharts/</code> for anonymous access.</p>\n\n\n\t<h2>People reported using this gem</h2>\n\n\n<div>\n  <img  src=\"http://img.skitch.com/20080627-r14subqdx2ye3w13qefbx974gc.png\" alt=\"github\"/><br/>\n  <li><a href=\"http://github.com\">http://github.com</a></li><br/>\n</div>\n\n<div>\n  <img  src=\"http://stafftool.com/images/masthead_screen.gif\" alt=\"stafftool\"/><br/>\n  <li><a href=\"http://stafftool.com/\">Takeo(contributor)</a></li><br/>\n</div>\n\n<div>\n  <img  src=\"http://img.skitch.com/20080627-g2pp89h7gdbh15m1rr8hx48jep.jpg\" alt=\"graffletopia\"/><br/>\n  <li><a href=\"http://graffletopia.com\"> http://graffletopia.com  Mokolabs(contributor)</a></li><br/>\n</div>\n\n<div>\n  <img  src=\"http://img.skitch.com/20080627-kc1weqsbkmxeqhwiyriq3n6g8k.jpg\" alt=\"gumgum\"/><br/>\n  <li><a href=\"http://gumgum.com\"> http://gumgum.com  Mattetti(contributor)</a></li><br/>\n</div>\n\n<div>\n  <img  src=\"http://img.skitch.com/20080627-n48j8pb2r7irsewfeh4yp3da12.jpg\" alt=\"gumgum\"/><br/>\n  <li><a href=\"http://feedflix.com/\"> http://feedflix.com/</a></li><br/>\n</div>\n\n\t<h2>License</h2>\n\n\n\t<p>This code is free to use under the terms of the <span class=\"caps\">MIT</span> license.</p>\n\n\n\t<h2>Contact</h2>\n\n\n\t<p>Comments are welcome. Send an email to <a href=\"mailto:mattaimonetti@gmail.com\">Matt Aimonetti</a></p>\n\n\n\t<h3>Contributors</h3>\n\n\n\t<p><a href=\"http://github.com/dbgrandi\">David Grandinetti</a>\n<a href=\"http://github.com/takeo\">Toby Sterrett</a>\n<a href=\"http://github.com/mokolabs\">Patrick Crowley</a></p>\n    <p class=\"coda\">\n      <a href=\"mattaimonetti@gmail.com\">Matt Aimonetti</a>, 2nd July 2008<br>\n      Theme extended from <a href=\"http://rb2js.rubyforge.org/\">Paul Battley</a>\n    </p>\n</div>\n\n<script src=\"http://www.google-analytics.com/urchin.js\" type=\"text/javascript\">\n</script>\n<script type=\"text/javascript\">\n_uacct = \"UA-179809-11\";\nurchinTracker();\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "vendor/plugins/googlecharts/website/index.txt",
    "content": "h1. Googlecharts\n\nh2. &#x2192; 'Sexy Charts using Google API & Ruby'\n\n\nh2. What\n  \nA nice and simple wrapper for \"Google Chart API\":http://code.google.com/apis/chart/\n(Fully tested using RSpec, check the specs for more usage examples)\n\nh2. Installing\n\nThis project is now hosted at \"GitHub\":http://github.com\nIf you never added \"GitHub\":http://github.com as a gem source, you will need to do the following:\n<pre syntax=\"ruby\">$ gem sources -a http://gems.github.com/</pre> (you only need to do this once)\n\n<pre syntax=\"ruby\">$ sudo gem install mattetti-googlecharts</pre>\n\nor <pre syntax=\"ruby\">$ sudo gem install googlecharts</pre>\n\nh2. The basics\n\nThis gem supports the following types of charts:\n   \n!http://chart.apis.google.com/chart?cht=lc&chs=200x125&chd=s:helloWorld&chxt=x,y&chxl=0:|Mar|Apr|May|June|July|1:||50+Kb(Line)! Gchart.line()\n\n!http://chart.apis.google.com/chart?cht=lxy&chs=200x125&chd=t:0,30,60,70,90,95,100|20,30,40,50,60,70,80|10,30,40,45,52|100,90,40,20,10|-1|5,33,50,55,7&chco=3072F3,ff0000,00aaaa&chls=2,4,1&chm=s,FF0000,0,-1,5|s,0000ff,1,-1,5|s,00aa00,2,-1,5(line_xy)! Gchart.line_xy()\n\n!http://chart.apis.google.com/chart?cht=s&chd=s:984sttvuvkQIBLKNCAIi,DEJPgq0uov17zwopQODS,AFLPTXaflptx159gsDrn&chxt=x,y&chxl=0:|0|2|3|4|5|6|7|8|9|10|1:|0|25|50|75|100&chs=200x125(scatter)! Gchart.scatter()\n\n!http://chart.apis.google.com/chart?cht=bvg&chs=200x125&chd=s:hello,world&chco=cc0000,00aa00(bar)! Gchart.bar()\n\n!http://chart.apis.google.com/chart?cht=v&chs=200x100&chd=t:100,80,60,30,30,30,10(venn)! Gchart.venn()\n\n!http://chart.apis.google.com/chart?cht=p&chd=s:world5&chs=200x125&chl=A|B|C|D|E|Fe(pie)! Gchart.pie()\n\n!http://chart.apis.google.com/chart?cht=p3&chd=s:Uf9a&chs=200x100&chl=A|B|C|D(pie_3d)! Gchart.pie_3d()\n\n!http://chart.apis.google.com/chart?chs=100x20&cht=ls&chco=0077CC&chm=B,E6F2FA,0,0,0&chls=1,0,0&chd=t:27,25,25,25,25,27,100,31,25,36,25,25,39,25,31,25,25,25,26,26,25,25,28,25,25,100,28,27,31,25,27,27,29,25,27,26,26,25,26,26,35,33,34,25,26,25,36,25,26,37,33,33,37,37,39,25,25,25,25(sparkline)!Gchart.sparkline()\n              \n!http://chart.apis.google.com/chart?chs=225x125&cht=gom&chd=t:70&chl=Flavor(google-o-meter)! Gchart.meter()\n\nh2. Demonstration of usage\n\ninstall:\n\n<code>sudo gem install mattetti-googlecharts</code>\n\nor use rubyforge:\n\n<code>sudo gem install googlecharts</code>\n\nrequire:\n<pre syntax=\"ruby\">require 'gchart'</pre>\n\n<pre syntax=\"ruby\">\nGchart.line(:size => '200x300', \n            :title => \"example title\",\n            :bg => 'efefef',\n            :legend => ['first data set label', 'second data set label'],\n            :data => [10, 30, 120, 45, 72])</pre>\n\n---\n\n*simple line chart*\n<pre syntax=\"ruby\">\nGchart.line(:data => [0, 40, 10, 70, 20])\n</pre>\n\nGenerate the following url: http://chart.apis.google.com/chart?chs=300x200&chd=s:AiI9R&cht=lc\n\nInserted in an image tag, it will look like that:\n\n!http://chart.apis.google.com/chart?chs=300x200&chd=s:AiI9R&cht=lc(simple line chart)!\n\n*multiple line charts*\n<pre syntax=\"ruby\">\nGchart.line(:data => [[0, 40, 10, 70, 20],[41, 10, 80, 50]])\n</pre>\n\n!http://chart.apis.google.com/chart?cht=lc&chs=300x200&chd=s:AeH1P,fH9m(multiple lines chart)!\n\n*set line colors*\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [[0, 40, 10, 70, 20],[41, 10, 80, 50]], :line_colors => \"FF0000,00FF00\")\n</pre>\n\n!http://chart.apis.google.com/chart?cht=lc&chs=300x200&chd=s:AeH1P,fH9m&chco=FF0000,00FF00(line colors)!\n\n\"more info about color settings\":http://code.google.com/apis/chart/#chart_colors\n\n*sparkline chart*\n\n<pre syntax=\"ruby\">\ndata = [27,25,25,25,25,27,100,31,25,36,25,25,39,25,31,25,25,25,26,26,25,25,28,25,25,100,28,27,31,25,27,27,29,25,27,26,26,25,26,26,35,33,34,25,26,25,36,25,26,37,33,33,37,37,39,25,25,25,25]\nGchart.sparkline(:data => data, :size => '120x40', :line_colors => '0077CC')\n</pre>\n\n!http://chart.apis.google.com/chart?chd=s:QPPPPQ9SPVPPXPSPPPPPPPRPP9RQSPQQRPQPPPPPVUUPPPVPPWUUWWXPPPP&chco=0077CC&chs=120x40&cht=ls(sparline)!\n\nA sparkline chart has exactly the same parameters as a line chart. The only difference is that the axes lines are not drawn for sparklines by default.\n\n*bar chart*\n\n<pre syntax=\"ruby\">\nGchart.bar(:data => [300, 100, 30, 200])\n</pre>\n!http://chart.apis.google.com/chart?cht=bvs&chs=300x200&chd=s:9UGo(bars)!\n\n*set the bar chart orientation*\n\n<pre syntax=\"ruby\">\nGchart.bar(:data => [300, 100, 30, 200], :orientation => 'horizontal')\n</pre>\n!http://chart.apis.google.com/chart?cht=bhs&chs=300x200&chd=s:9UGo(bars)!\n\n*multiple bars chart*\n\n<pre syntax=\"ruby\">\nGchart.bar(:data => [[300, 100, 30, 200], [100, 200, 300, 10]])\n</pre>\n\n!http://chart.apis.google.com/chart?cht=bvs&chs=300x200&chd=s:9UGo,Uo9C(stacked multiple bars)!\n\nThe problem is that by default the bars are stacked, so we need to set the colors:\n\n<pre syntax=\"ruby\">\nGchart.bar(:data => [[300, 100, 30, 200], [100, 200, 300, 10]], :bar_colors => 'FF0000,00FF00')\n</pre>\n\nIf you prefer you can use this other syntax:\n\n<pre syntax=\"ruby\">\nGchart.bar(:data => [[300, 100, 30, 200], [100, 200, 300, 10]], :bar_colors => ['FF0000', '00FF00'])\n</pre>\n\n!http://chart.apis.google.com/chart?cht=bvs&chs=300x200&chd=s:9UGo,Uo9C&chco=FF0000,00FF00(colors)!\n\nThe problem now, is that we can't see the first value of the second dataset since it's lower than the first value of the first dataset. Let's unstack the bars:\n\n<pre syntax=\"ruby\">\nGchart.bar(:data => [[300, 100, 30, 200], [100, 200, 300, 10]], \n           :bar_colors => 'FF0000,00FF00',\n           :stacked => false )\n</pre>\n\n!http://chart.apis.google.com/chart?cht=bvg&chs=300x200&chd=s:9UGo,Uo9C&chco=FF0000,00FF00(grouped bars)!\n\n*bar chart width and spacing*\n\nA bar chart can accept options to set the width of the bars, spacing between bars and spacing between bar groups. To set these, you can either provide a string, array or hash.\n\nThe Google API sets these options in the order of width, spacing, and group spacing, with both spacing values being optional. So, if you provide a string or array, provide them in that order:\n\n<pre syntax=\"ruby\">\nGchart.bar(:data => @data, :bar_width_and_spacing => '25,6') # width of 25, spacing of 6\nGchart.bar(:data => @data, :bar_width_and_spacing => '25,6,12') # width of 25, spacing of 6, group spacing of 12\nGchart.bar(:data => @data, :bar_width_and_spacing => [25,6]) # width of 25, spacing of 6\nGchart.bar(:data => @data, :bar_width_and_spacing => 25) # width of 25\n</pre>\n  \nThe hash lets you set these values directly, with the Google default values set for any options you don't include:\n\n<pre syntax=\"ruby\">\nGchart.bar(:data => @data, :bar_width_and_spacing => {:width => 19})\nGchart.bar(:data => @data, :bar_width_and_spacing => {:spacing => 10, :group_spacing => 12})\n</pre>\n\n\n*pie chart*\n\n<pre syntax=\"ruby\">\nGchart.pie(:data => [20, 35, 45])\n</pre>\n!http://chart.apis.google.com/chart?cht=p&chs=300x200&chd=s:bv9(Pie Chart)!\n\n*3D pie chart*\n\n<pre syntax=\"ruby\">\nGchart.pie_3d(:data => [20, 35, 45])\n</pre>\n!http://chart.apis.google.com/chart?cht=p3&chs=300x200&chd=s:bv9(Pie Chart)!\n\n*venn diagram*\n\n\"Google documentation\":http://code.google.com/apis/chart/#venn\n\nData set:\n* the first three values specify the relative sizes of three circles, A, B, and C\n* the fourth value specifies the area of A intersecting B\n* the fifth value specifies the area of B intersecting C\n* the sixth value specifies the area of C intersecting A\n* the seventh value specifies the area of A intersecting B intersecting C\n\n<pre syntax=\"ruby\">\nGchart.venn(:data => [100, 80, 60, 30, 30, 30, 10])\n</pre>\n!http://chart.apis.google.com/chart?cht=v&chs=300x200&chd=s:9wkSSSG(Venn)!\n\n*scatter plot*\n\n\"Google Documentation\":http://code.google.com/apis/chart/#scatter_plot\n\nSupply two data sets, the first data set specifies x coordinates, the second set specifies y coordinates, the third set the data point size.\n\n<pre syntax=\"ruby\">\nGchart.scatter(:data => [[1, 2, 3, 4, 5], [1, 2, 3, 4 ,5], [5, 4, 3, 2, 1]])\n</pre>\n\n!http://chart.apis.google.com/chart?cht=s&chs=300x200&chd=s:MYkw9,MYkw9,9wkYM(scatter)!\n\n*google-o-meter*\n\n\"Google Documentation\":http://code.google.com/apis/chart/#gom\n\nSupply a single label that will be what the arrow points to. It only supports a solid fill for the background.\n\n<pre syntax=\"ruby\">\n  Gchart.meter(:data => [70], :label => ['Flavor'])\n</pre>\n\n\n*Chart themes*\n\nGooglecharts comes with 4 themes: keynote, thirty7signals, pastel and greyscale. (ganked from \"Gruff\": http://github.com/topfunky/gruff/tree/master )\n\n<pre syntax=\"ruby\">\n  Gchart.line(\n              :theme => :keynote, \n              :data => [[0,40,10,70,20],[41,10,80,50,40],[20,60,30,60,80],[5,23,35,10,56],[80,90,5,30,60]], \n              :title => 'keynote'\n              )\n</pre>\n\n* keynote\n\n!http://chart.apis.google.com/chart?chtt=keynote&chco=6886B4,FDD84E,72AE6E,D1695E,8A6EAF,EFAA43&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo&chf=c,s,FFFFFF|bg,s,000000!\n\n* thirty7signals\n\n!http://chart.apis.google.com/chart?chtt=thirty7signals&chco=FFF804,336699,339933,ff0000,cc99cc,cf5910&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo&chf=bg,s,FFFFFF!\n\n* pastel\n\n!http://chart.apis.google.com/chart?chtt=pastel&chco=a9dada,aedaa9,daaea9,dadaa9,a9a9da&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo!\n\n* greyscale\n\n!http://chart.apis.google.com/chart?chtt=greyscale&chco=282828,383838,686868,989898,c8c8c8,e8e8e8&chs=300x200&cht=lc&chd=s:AbGvN,bG2hb,NoUo2,DPXGl,29DUo!\n\n\nYou can also use your own theme. Create a yml file using the same format as the themes located in lib/themes.yml\n\nLoad your theme(s):\n\n<pre syntax=\"ruby\">\n  Chart::Theme.add_theme_file(\"#{File.dirname(__FILE__)}/fixtures/another_test_theme.yml\")\n</pre>\n\nAnd use the standard method signature to use your own theme:\n\n<pre syntax=\"ruby\">\n  Gchart.line(:theme => :custom_theme, :data => [[0, 40, 10, 70, 20],[41, 10, 80, 50]], :title => 'greyscale')\n</pre>\n\n\n---\n\n*set a chart title*\n\n<pre syntax=\"ruby\">\nGchart.bar(:title => \"Recent Chart Sexyness\", :data => [15, 30, 10, 20, 100, 20, 40, 100])\n</pre>\n\n!http://chart.apis.google.com/chart?cht=bvs&chs=300x200&chd=s:JSGM9MY9&chtt=Recent+Chart+Sexyness(chart title)!\n\n*set the title size*\n\n<pre syntax=\"ruby\">\nGchart.bar(:title => \"Recent Chart Sexyness\", :title_size => 20, :data => [15, 30, 10, 20, 100, 20, 40, 100])\n</pre>\n\n!http://chart.apis.google.com/chart?cht=bvs&chs=300x200&chd=s:JSGM9MY9&chtt=Recent+Chart+Sexyness&chts=454545,20(title size)!\n\n*set the title color*\n\n<pre syntax=\"ruby\">\nGchart.bar(:title => \"Recent Chart Sexyness\", :title_color => 'FF0000', :data => [15, 30, 10, 20, 100, 20, 40, 100])\n</pre>\n\n!http://chart.apis.google.com/chart?cht=bvs&chs=300x200&chd=s:JSGM9MY9&chtt=Recent+Chart+Sexyness&chts=FF0000(Title color)!\n\n*set the chart's size*\n\n<pre syntax=\"ruby\">\nGchart.bar(:title => \"Recent Chart Sexyness\", \n           :data => [15, 30, 10, 20, 100, 20, 40, 100],\n           :size => '600x400')\n</pre>\n\n!http://chart.apis.google.com/chart?cht=bvs&chs=600x400&chd=s:JSGM9MY9&chtt=Recent+Chart+Sexyness(size)!\n\n*set the image background color*\n\n<pre syntax=\"ruby\">\nGchart.bar(:title => \"Matt's Mojo\", \n           :data => [15, 30, 10, 20, 100, 20, 40, 100, 90, 100, 80],\n           :background => 'FF9994')\n</pre>\n\n!http://chart.apis.google.com/chart?chf=bg,s,FF9994&cht=bvs&chs=300x200&chd=s:JSGM9MY929w&chtt=Matt's+Mojo(Background)!\n\n*set the chart background color*\n\n<pre syntax=\"ruby\">\nGchart.bar(:title => \"Matt's Mojo\", \n           :data => [15, 30, 10, 20, 100, 20, 40, 100, 90, 100, 80],\n           :background => 'FF9994', :chart_background => '000000')\n</pre>\n\n!http://chart.apis.google.com/chart?chf=c,s,000000|bg,s,FF9994&cht=bvs&chs=300x200&chd=s:JSGM9MY929w&chtt=Matt's+Mojo(chart background)!\n\n*Set bar/line colors*\n\n<pre syntax=\"ruby\">\nGchart.bar(:title => \"Matt's Mojo\", \n           :data => [15, 30, 10, 20, 100, 20, 40, 100, 90, 100, 80],\n           :bar_colors => '76A4FB',\n           :background => 'EEEEEE', :chart_background => 'CCCCCC')\n</pre>\n\n!http://chart.apis.google.com/chart?chf=c,s,CCCCCC|bg,s,EEEEEE&cht=bvs&chs=300x200&chd=s:JSGM9MY929w&chco=76A4FB&chtt=Matt's+Mojo(bar colors)!\n\n<pre syntax=\"ruby\">\nGchart.line(:title => \"Matt's Mojo\", \n            :data => [15, 30, 10, 20, 100, 20, 40, 100, 90, 100, 80],\n            :line_colors => '76A4FB')\n</pre>\n\n!http://chart.apis.google.com/chart?cht=lc&chs=300x200&chd=s:JSGM9MY929w&chco=76A4FB&chtt=Matt's+Mojo(line colors)!\n\n*legend / labels*\n\n<pre syntax=\"ruby\">\nGchart.bar(:title => \"Matt vs Rob\",\n           :data => [[300, 100, 30, 200], [100, 200, 300, 10]], \n           :bar_colors => 'FF0000,00FF00',\n           :stacked => false, :size => '400x200',\n           :legend => [\"Matt's Mojo\", \"Rob's Mojo\"] )\n</pre>\n!http://chart.apis.google.com/chart?cht=bvg&chdl=Matt's+Mojo|Rob's+Mojo&chs=400x200&chd=s:9UGo,Uo9C&chco=FF0000,00FF00&chtt=Matt+vs+Rob(legend)!\n\n<pre syntax=\"ruby\">\nGchart.line(:title => \"Matt vs Rob\",\n            :data => [[300, 100, 30, 200], [100, 200, 300, 10]], \n            :bar_colors => ['FF0000','00FF00'],\n            :stacked => false, :size => '400x200',\n            :legend => [\"Matt's Mojo\", \"Rob's Mojo\"] )\n</pre>\n!http://chart.apis.google.com/chart?cht=lc&chdl=Matt's+Mojo|Rob's+Mojo&chs=400x200&chd=s:9UGo,Uo9C&chco=FF0000,00FF00&chtt=Matt+vs+Rob(line legend)!\n\n\n<pre syntax=\"ruby\">\nGchart.pie_3d(:title => 'ruby_fu', :size => '400x200',\n              :data => [10, 45, 45], :labels => [\"DHH\", \"Rob\", \"Matt\"] )\n</pre>\n\n!http://chart.apis.google.com/chart?cht=p3&chl=DHH|Rob|Matt&chs=400x200&chd=s:N99&chtt=ruby_fu(labels)!\n\n*Display axis labels*\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [300, 100, 30, 200, 100, 200, 300, 10], :axis_with_labels => 'x,y,r')\n</pre>\n\nor you can use the other syntax:\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [300, 100, 30, 200, 100, 200, 300, 10], :axis_with_labels => ['x','y','r'])\n</pre>\n\n!http://chart.apis.google.com/chart?cht=lc&chs=300x200&chxt=x,y,r&chd=s:9UGoUo9C(axis with labels)!\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [300, 100, 30, 200, 100, 200, 300, 10], :axis_with_labels => 'x',\n            :axis_labels => ['Jan|July|Jan|July|Jan'])\n</pre>\n\nor you can use the other syntax:\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [300, 100, 30, 200, 100, 200, 300, 10], :axis_with_labels => 'x',\n            :axis_labels => ['Jan','July','Jan','July','Jan'])\n</pre>\n\n!http://chart.apis.google.com/chart?cht=lc&chxl=0:|Jan|July|Jan|July|Jan&chs=300x200&chxt=x&chd=s:9UGoUo9C(x labels)!\n\n*multiple axis labels*\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [300, 100, 30, 200, 100, 200, 300, 10], :axis_with_labels => 'x,r',\n            :axis_labels => ['Jan|July|Jan|July|Jan', '2005|2006|2007'])\n</pre>\n\nor \n\n<pre syntax=\"ruby\">\nGchart.line(:data => [300, 100, 30, 200, 100, 200, 300, 10], :axis_with_labels => 'x,r',\n            :axis_labels => [['Jan','July','Jan','July','Jan'], ['2005','2006','2007']])\n</pre>\n\n!http://chart.apis.google.com/chart?cht=lc&chxl=0:|Jan|July|Jan|July|Jan|1:|2005|2006|2007&chs=300x200&chxt=x,r&chd=s:9UGoUo9C(multiple axis labels)!\n\n(This syntax will probably be improved in the future)\n\n*custom params*\n\nI certainly didn't cover the entire API, if you want to add your own params:\n\n<pre syntax=\"ruby\">\nGchart.line(:custom => 'chd=s:93zyvneTTOMJMLIJFHEAECFJGHDBFCFIERcgnpy45879,IJKNUWUWYdnswz047977315533zy1246872tnkgcaZQONHCECAAAAEII&chls=3,6,3|1,1,0')\n</pre>\n\n!http://chart.apis.google.com/chart?cht=lc&chs=300x200&chd=s:93zyvneTTOMJMLIJFHEAECFJGHDBFCFIERcgnpy45879,IJKNUWUWYdnswz047977315533zy1246872tnkgcaZQONHCECAAAAEII&chls=3,6,3|1,1,0(Custom)!\n\n---\n\n*Save the chart as a file*\n\nYou might prefer to save the chart instead of using the url, not a problem:\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [0, 26], :format => 'file')\n</pre>\n\nYou might want to specify the path and/or the filename used to save your chart: \n\n<pre syntax=\"ruby\">\nGchart.line(:data => [0, 26], :format => 'file', :filename => 'custom_filename.png')\n</pre>\n\n*Insert as an image tag*\n\nBecause, I'm lazy, you can generate a full image tag, with support for standard html options.\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [0, 26], :format => 'image_tag')\n</pre>\n\n<pre syntax=\"ruby\">\n<img src=\"http://chart.apis.google.com/chart?chs=300x200&amp;chd=s:A9&amp;cht=lc\" width=\"300\" height=\"200\" alt=\"Google Chart\" />\n</pre>\n\nHere are a few more examples:\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [0, 26], :format => 'image_tag')\nGchart.line(:data => [0, 26], :format => 'image_tag', :id => \"sexy\")\nGchart.line(:data => [0, 26], :format => 'image_tag', :class => \"chart\")\nGchart.line(:data => [0, 26], :format => 'image_tag', :alt => \"Sexy Chart\")\nGchart.line(:data => [0, 26], :format => 'image_tag', :title => \"Sexy Chart\")\n</pre>\n\nImage dimensions will be automatically set based on your chart's size.\n\n---\n\n*Encoding*\n\nGoogle Chart API offers \"3 types of data encoding\":http://code.google.com/apis/chart/#chart_data\n\n  * simple\n  * text\n  * extended\n  \nBy default this library uses the simple encoding, if you need a different type of encoding, you can change it really easily:\n\ndefault / simple: chd=s:9UGoUo9C\n<pre syntax=\"ruby\">\n  Gchart.line(:data => [300, 100, 30, 200, 100, 200, 300, 10] )\n</pre>\n\nextended: chd=e:..VVGZqqVVqq..CI\n<pre syntax=\"ruby\">\nGchart.line(:data => [300, 100, 30, 200, 100, 200, 300, 10], :encoding => 'extended' )\n</pre>\n\ntext: chd=t:300,100,30,200,100,200,300,10\n<pre syntax=\"ruby\">\nGchart.line(:data => [300, 100, 30, 200, 100, 200, 300, 10], :encoding => 'text' )\n</pre> \n\n(note that the text encoding doesn't use a max value and therefore should be under 100)\n\n*Max value*\n\nSimple and extended encoding support the max value option.\n\nThe max value option is a simple way of scaling your graph. The data is converted in chart value with the highest chart value being the highest point on the graph. By default, the calculation is done for you. However you can specify your own maximum or not use a maximum at all.\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [300, 100, 30, 200, 100, 200, 300, 10] )\n</pre>\n\n!http://chart.apis.google.com/chart?cht=lc&chs=300x200&chd=s:9UGoUo9C(Title)!\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [300, 100, 30, 200, 100, 200, 300, 10], :max_value => 500 )\n</pre>\n\n!http://chart.apis.google.com/chart?cht=lc&chs=300x200&chd=s:kMDYMYkB(max 500)!\n\n<pre syntax=\"ruby\">\nGchart.line(:data => [100, 20, 30, 20, 10, 14, 30, 10], :max_value => false )\n</pre>\n\n!http://chart.apis.google.com/chart?cht=lc&chs=300x200&chd=s:_UeUKOeK(real size)!\n\n\nh2. Repository\n\nThe trunk repository is <code>http://github.com/mattetti/googlecharts/</code> for anonymous access.\n\nh2. People reported using this gem\n\n\n  <div>\n    <img  src=\"http://img.skitch.com/20080627-r14subqdx2ye3w13qefbx974gc.png\" alt=\"github\"/><br/>\n    <li><a href=\"http://github.com\">http://github.com</a></li><br/>\n  </div>\n  \n  <div>\n    <img  src=\"http://stafftool.com/images/masthead_screen.gif\" alt=\"stafftool\"/><br/>\n    <li><a href=\"http://stafftool.com/\">Takeo(contributor)</a></li><br/>\n  </div>\n  \n  <div>\n    <img  src=\"http://img.skitch.com/20080627-g2pp89h7gdbh15m1rr8hx48jep.jpg\" alt=\"graffletopia\"/><br/>\n    <li><a href=\"http://graffletopia.com\"> http://graffletopia.com  Mokolabs(contributor)</a></li><br/>\n  </div>\n  \n  <div>\n    <img  src=\"http://img.skitch.com/20080627-kc1weqsbkmxeqhwiyriq3n6g8k.jpg\" alt=\"gumgum\"/><br/>\n    <li><a href=\"http://gumgum.com\"> http://gumgum.com  Mattetti(contributor)</a></li><br/>\n  </div>\n  \n  <div>\n    <img  src=\"http://img.skitch.com/20080627-n48j8pb2r7irsewfeh4yp3da12.jpg\" alt=\"feedflix\"/><br/>\n    <li><a href=\"http://feedflix.com/\"> http://feedflix.com/</a></li><br/>\n  </div>\n  \n  <div>\n    <li><a href=\"http://www.csuchico.edu/\"> California State University, Chico</a></li><br/>\n  </div>\n\n\nh2. License\n\nThis code is free to use under the terms of the MIT license. \n\nh2. Contact\n\nComments are welcome. Send an email to \"Matt Aimonetti\":mailto:mattaimonetti@gmail.com\n\nh3. Contributors\n\n\"David Grandinetti\":http://github.com/dbgrandi\n\"Toby Sterrett\":http://github.com/takeo\n\"Patrick Crowley\":http://github.com/mokolabs"
  },
  {
    "path": "vendor/plugins/googlecharts/website/javascripts/rounded_corners_lite.inc.js",
    "content": "\n /****************************************************************\n  *                                                              *\n  *  curvyCorners                                                *\n  *  ------------                                                *\n  *                                                              *\n  *  This script generates rounded corners for your divs.        *\n  *                                                              *\n  *  Version 1.2.9                                               *\n  *  Copyright (c) 2006 Cameron Cooke                            *\n  *  By: Cameron Cooke and Tim Hutchison.                        *\n  *                                                              *\n  *                                                              *\n  *  Website: http://www.curvycorners.net                        *\n  *  Email:   info@totalinfinity.com                             *\n  *  Forum:   http://www.curvycorners.net/forum/                 *\n  *                                                              *\n  *                                                              *\n  *  This library is free software; you can redistribute         *\n  *  it and/or modify it under the terms of the GNU              *\n  *  Lesser General Public License as published by the           *\n  *  Free Software Foundation; either version 2.1 of the         *\n  *  License, or (at your option) any later version.             *\n  *                                                              *\n  *  This library is distributed in the hope that it will        *\n  *  be useful, but WITHOUT ANY WARRANTY; without even the       *\n  *  implied warranty of MERCHANTABILITY or FITNESS FOR A        *\n  *  PARTICULAR PURPOSE. See the GNU Lesser General Public       *\n  *  License for more details.                                   *\n  *                                                              *\n  *  You should have received a copy of the GNU Lesser           *\n  *  General Public License along with this library;             *\n  *  Inc., 59 Temple Place, Suite 330, Boston,                   *\n  *  MA 02111-1307 USA                                           *\n  *                                                              *\n  ****************************************************************/\n  \nvar isIE = navigator.userAgent.toLowerCase().indexOf(\"msie\") > -1; var isMoz = document.implementation && document.implementation.createDocument; var isSafari = ((navigator.userAgent.toLowerCase().indexOf('safari')!=-1)&&(navigator.userAgent.toLowerCase().indexOf('mac')!=-1))?true:false; function curvyCorners()\n{ if(typeof(arguments[0]) != \"object\") throw newCurvyError(\"First parameter of curvyCorners() must be an object.\"); if(typeof(arguments[1]) != \"object\" && typeof(arguments[1]) != \"string\") throw newCurvyError(\"Second parameter of curvyCorners() must be an object or a class name.\"); if(typeof(arguments[1]) == \"string\")\n{ var startIndex = 0; var boxCol = getElementsByClass(arguments[1]);}\nelse\n{ var startIndex = 1; var boxCol = arguments;}\nvar curvyCornersCol = new Array(); if(arguments[0].validTags)\nvar validElements = arguments[0].validTags; else\nvar validElements = [\"div\"]; for(var i = startIndex, j = boxCol.length; i < j; i++)\n{ var currentTag = boxCol[i].tagName.toLowerCase(); if(inArray(validElements, currentTag) !== false)\n{ curvyCornersCol[curvyCornersCol.length] = new curvyObject(arguments[0], boxCol[i]);}\n}\nthis.objects = curvyCornersCol; this.applyCornersToAll = function()\n{ for(var x = 0, k = this.objects.length; x < k; x++)\n{ this.objects[x].applyCorners();}\n}\n}\nfunction curvyObject()\n{ this.box = arguments[1]; this.settings = arguments[0]; this.topContainer = null; this.bottomContainer = null; this.masterCorners = new Array(); this.contentDIV = null; var boxHeight = get_style(this.box, \"height\", \"height\"); var boxWidth = get_style(this.box, \"width\", \"width\"); var borderWidth = get_style(this.box, \"borderTopWidth\", \"border-top-width\"); var borderColour = get_style(this.box, \"borderTopColor\", \"border-top-color\"); var boxColour = get_style(this.box, \"backgroundColor\", \"background-color\"); var backgroundImage = get_style(this.box, \"backgroundImage\", \"background-image\"); var boxPosition = get_style(this.box, \"position\", \"position\"); var boxPadding = get_style(this.box, \"paddingTop\", \"padding-top\"); this.boxHeight = parseInt(((boxHeight != \"\" && boxHeight != \"auto\" && boxHeight.indexOf(\"%\") == -1)? boxHeight.substring(0, boxHeight.indexOf(\"px\")) : this.box.scrollHeight)); this.boxWidth = parseInt(((boxWidth != \"\" && boxWidth != \"auto\" && boxWidth.indexOf(\"%\") == -1)? boxWidth.substring(0, boxWidth.indexOf(\"px\")) : this.box.scrollWidth)); this.borderWidth = parseInt(((borderWidth != \"\" && borderWidth.indexOf(\"px\") !== -1)? borderWidth.slice(0, borderWidth.indexOf(\"px\")) : 0)); this.boxColour = format_colour(boxColour); this.boxPadding = parseInt(((boxPadding != \"\" && boxPadding.indexOf(\"px\") !== -1)? boxPadding.slice(0, boxPadding.indexOf(\"px\")) : 0)); this.borderColour = format_colour(borderColour); this.borderString = this.borderWidth + \"px\" + \" solid \" + this.borderColour; this.backgroundImage = ((backgroundImage != \"none\")? backgroundImage : \"\"); this.boxContent = this.box.innerHTML; if(boxPosition != \"absolute\") this.box.style.position = \"relative\"; this.box.style.padding = \"0px\"; if(isIE && boxWidth == \"auto\" && boxHeight == \"auto\") this.box.style.width = \"100%\"; if(this.settings.autoPad == true && this.boxPadding > 0)\nthis.box.innerHTML = \"\"; this.applyCorners = function()\n{ for(var t = 0; t < 2; t++)\n{ switch(t)\n{ case 0:\nif(this.settings.tl || this.settings.tr)\n{ var newMainContainer = document.createElement(\"DIV\"); newMainContainer.style.width = \"100%\"; newMainContainer.style.fontSize = \"1px\"; newMainContainer.style.overflow = \"hidden\"; newMainContainer.style.position = \"absolute\"; newMainContainer.style.paddingLeft = this.borderWidth + \"px\"; newMainContainer.style.paddingRight = this.borderWidth + \"px\"; var topMaxRadius = Math.max(this.settings.tl ? this.settings.tl.radius : 0, this.settings.tr ? this.settings.tr.radius : 0); newMainContainer.style.height = topMaxRadius + \"px\"; newMainContainer.style.top = 0 - topMaxRadius + \"px\"; newMainContainer.style.left = 0 - this.borderWidth + \"px\"; this.topContainer = this.box.appendChild(newMainContainer);}\nbreak; case 1:\nif(this.settings.bl || this.settings.br)\n{ var newMainContainer = document.createElement(\"DIV\"); newMainContainer.style.width = \"100%\"; newMainContainer.style.fontSize = \"1px\"; newMainContainer.style.overflow = \"hidden\"; newMainContainer.style.position = \"absolute\"; newMainContainer.style.paddingLeft = this.borderWidth + \"px\"; newMainContainer.style.paddingRight = this.borderWidth + \"px\"; var botMaxRadius = Math.max(this.settings.bl ? this.settings.bl.radius : 0, this.settings.br ? this.settings.br.radius : 0); newMainContainer.style.height = botMaxRadius + \"px\"; newMainContainer.style.bottom = 0 - botMaxRadius + \"px\"; newMainContainer.style.left = 0 - this.borderWidth + \"px\"; this.bottomContainer = this.box.appendChild(newMainContainer);}\nbreak;}\n}\nif(this.topContainer) this.box.style.borderTopWidth = \"0px\"; if(this.bottomContainer) this.box.style.borderBottomWidth = \"0px\"; var corners = [\"tr\", \"tl\", \"br\", \"bl\"]; for(var i in corners)\n{ if(i > -1 < 4)\n{ var cc = corners[i]; if(!this.settings[cc])\n{ if(((cc == \"tr\" || cc == \"tl\") && this.topContainer != null) || ((cc == \"br\" || cc == \"bl\") && this.bottomContainer != null))\n{ var newCorner = document.createElement(\"DIV\"); newCorner.style.position = \"relative\"; newCorner.style.fontSize = \"1px\"; newCorner.style.overflow = \"hidden\"; if(this.backgroundImage == \"\")\nnewCorner.style.backgroundColor = this.boxColour; else\nnewCorner.style.backgroundImage = this.backgroundImage; switch(cc)\n{ case \"tl\":\nnewCorner.style.height = topMaxRadius - this.borderWidth + \"px\"; newCorner.style.marginRight = this.settings.tr.radius - (this.borderWidth*2) + \"px\"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.left = -this.borderWidth + \"px\"; break; case \"tr\":\nnewCorner.style.height = topMaxRadius - this.borderWidth + \"px\"; newCorner.style.marginLeft = this.settings.tl.radius - (this.borderWidth*2) + \"px\"; newCorner.style.borderRight = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.backgroundPosition = \"-\" + (topMaxRadius + this.borderWidth) + \"px 0px\"; newCorner.style.left = this.borderWidth + \"px\"; break; case \"bl\":\nnewCorner.style.height = botMaxRadius - this.borderWidth + \"px\"; newCorner.style.marginRight = this.settings.br.radius - (this.borderWidth*2) + \"px\"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = -this.borderWidth + \"px\"; newCorner.style.backgroundPosition = \"-\" + (this.borderWidth) + \"px -\" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + \"px\"; break; case \"br\":\nnewCorner.style.height = botMaxRadius - this.borderWidth + \"px\"; newCorner.style.marginLeft = this.settings.bl.radius - (this.borderWidth*2) + \"px\"; newCorner.style.borderRight = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = this.borderWidth + \"px\"\nnewCorner.style.backgroundPosition = \"-\" + (botMaxRadius + this.borderWidth) + \"px -\" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + \"px\"; break;}\n}\n}\nelse\n{ if(this.masterCorners[this.settings[cc].radius])\n{ var newCorner = this.masterCorners[this.settings[cc].radius].cloneNode(true);}\nelse\n{ var newCorner = document.createElement(\"DIV\"); newCorner.style.height = this.settings[cc].radius + \"px\"; newCorner.style.width = this.settings[cc].radius + \"px\"; newCorner.style.position = \"absolute\"; newCorner.style.fontSize = \"1px\"; newCorner.style.overflow = \"hidden\"; var borderRadius = parseInt(this.settings[cc].radius - this.borderWidth); for(var intx = 0, j = this.settings[cc].radius; intx < j; intx++)\n{ if((intx +1) >= borderRadius)\nvar y1 = -1; else\nvar y1 = (Math.floor(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow((intx+1), 2))) - 1); if(borderRadius != j)\n{ if((intx) >= borderRadius)\nvar y2 = -1; else\nvar y2 = Math.ceil(Math.sqrt(Math.pow(borderRadius,2) - Math.pow(intx, 2))); if((intx+1) >= j)\nvar y3 = -1; else\nvar y3 = (Math.floor(Math.sqrt(Math.pow(j ,2) - Math.pow((intx+1), 2))) - 1);}\nif((intx) >= j)\nvar y4 = -1; else\nvar y4 = Math.ceil(Math.sqrt(Math.pow(j ,2) - Math.pow(intx, 2))); if(y1 > -1) this.drawPixel(intx, 0, this.boxColour, 100, (y1+1), newCorner, -1, this.settings[cc].radius); if(borderRadius != j)\n{ for(var inty = (y1 + 1); inty < y2; inty++)\n{ if(this.settings.antiAlias)\n{ if(this.backgroundImage != \"\")\n{ var borderFract = (pixelFraction(intx, inty, borderRadius) * 100); if(borderFract < 30)\n{ this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, 0, this.settings[cc].radius);}\nelse\n{ this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, -1, this.settings[cc].radius);}\n}\nelse\n{ var pixelcolour = BlendColour(this.boxColour, this.borderColour, pixelFraction(intx, inty, borderRadius)); this.drawPixel(intx, inty, pixelcolour, 100, 1, newCorner, 0, this.settings[cc].radius, cc);}\n}\n}\nif(this.settings.antiAlias)\n{ if(y3 >= y2)\n{ if (y2 == -1) y2 = 0; this.drawPixel(intx, y2, this.borderColour, 100, (y3 - y2 + 1), newCorner, 0, 0);}\n}\nelse\n{ if(y3 >= y1)\n{ this.drawPixel(intx, (y1 + 1), this.borderColour, 100, (y3 - y1), newCorner, 0, 0);}\n}\nvar outsideColour = this.borderColour;}\nelse\n{ var outsideColour = this.boxColour; var y3 = y1;}\nif(this.settings.antiAlias)\n{ for(var inty = (y3 + 1); inty < y4; inty++)\n{ this.drawPixel(intx, inty, outsideColour, (pixelFraction(intx, inty , j) * 100), 1, newCorner, ((this.borderWidth > 0)? 0 : -1), this.settings[cc].radius);}\n}\n}\nthis.masterCorners[this.settings[cc].radius] = newCorner.cloneNode(true);}\nif(cc != \"br\")\n{ for(var t = 0, k = newCorner.childNodes.length; t < k; t++)\n{ var pixelBar = newCorner.childNodes[t]; var pixelBarTop = parseInt(pixelBar.style.top.substring(0, pixelBar.style.top.indexOf(\"px\"))); var pixelBarLeft = parseInt(pixelBar.style.left.substring(0, pixelBar.style.left.indexOf(\"px\"))); var pixelBarHeight = parseInt(pixelBar.style.height.substring(0, pixelBar.style.height.indexOf(\"px\"))); if(cc == \"tl\" || cc == \"bl\"){ pixelBar.style.left = this.settings[cc].radius -pixelBarLeft -1 + \"px\";}\nif(cc == \"tr\" || cc == \"tl\"){ pixelBar.style.top = this.settings[cc].radius -pixelBarHeight -pixelBarTop + \"px\";}\nswitch(cc)\n{ case \"tr\":\npixelBar.style.backgroundPosition = \"-\" + Math.abs((this.boxWidth - this.settings[cc].radius + this.borderWidth) + pixelBarLeft) + \"px -\" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + \"px\"; break; case \"tl\":\npixelBar.style.backgroundPosition = \"-\" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + \"px -\" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + \"px\"; break; case \"bl\":\npixelBar.style.backgroundPosition = \"-\" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + \"px -\" + Math.abs((this.boxHeight + this.settings[cc].radius + pixelBarTop) -this.borderWidth) + \"px\"; break;}\n}\n}\n}\nif(newCorner)\n{ switch(cc)\n{ case \"tl\":\nif(newCorner.style.position == \"absolute\") newCorner.style.top = \"0px\"; if(newCorner.style.position == \"absolute\") newCorner.style.left = \"0px\"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case \"tr\":\nif(newCorner.style.position == \"absolute\") newCorner.style.top = \"0px\"; if(newCorner.style.position == \"absolute\") newCorner.style.right = \"0px\"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case \"bl\":\nif(newCorner.style.position == \"absolute\") newCorner.style.bottom = \"0px\"; if(newCorner.style.position == \"absolute\") newCorner.style.left = \"0px\"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break; case \"br\":\nif(newCorner.style.position == \"absolute\") newCorner.style.bottom = \"0px\"; if(newCorner.style.position == \"absolute\") newCorner.style.right = \"0px\"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break;}\n}\n}\n}\nvar radiusDiff = new Array(); radiusDiff[\"t\"] = Math.abs(this.settings.tl.radius - this.settings.tr.radius)\nradiusDiff[\"b\"] = Math.abs(this.settings.bl.radius - this.settings.br.radius); for(z in radiusDiff)\n{ if(z == \"t\" || z == \"b\")\n{ if(radiusDiff[z])\n{ var smallerCornerType = ((this.settings[z + \"l\"].radius < this.settings[z + \"r\"].radius)? z +\"l\" : z +\"r\"); var newFiller = document.createElement(\"DIV\"); newFiller.style.height = radiusDiff[z] + \"px\"; newFiller.style.width = this.settings[smallerCornerType].radius+ \"px\"\nnewFiller.style.position = \"absolute\"; newFiller.style.fontSize = \"1px\"; newFiller.style.overflow = \"hidden\"; newFiller.style.backgroundColor = this.boxColour; switch(smallerCornerType)\n{ case \"tl\":\nnewFiller.style.bottom = \"0px\"; newFiller.style.left = \"0px\"; newFiller.style.borderLeft = this.borderString; this.topContainer.appendChild(newFiller); break; case \"tr\":\nnewFiller.style.bottom = \"0px\"; newFiller.style.right = \"0px\"; newFiller.style.borderRight = this.borderString; this.topContainer.appendChild(newFiller); break; case \"bl\":\nnewFiller.style.top = \"0px\"; newFiller.style.left = \"0px\"; newFiller.style.borderLeft = this.borderString; this.bottomContainer.appendChild(newFiller); break; case \"br\":\nnewFiller.style.top = \"0px\"; newFiller.style.right = \"0px\"; newFiller.style.borderRight = this.borderString; this.bottomContainer.appendChild(newFiller); break;}\n}\nvar newFillerBar = document.createElement(\"DIV\"); newFillerBar.style.position = \"relative\"; newFillerBar.style.fontSize = \"1px\"; newFillerBar.style.overflow = \"hidden\"; newFillerBar.style.backgroundColor = this.boxColour; newFillerBar.style.backgroundImage = this.backgroundImage; switch(z)\n{ case \"t\":\nif(this.topContainer)\n{ if(this.settings.tl.radius && this.settings.tr.radius)\n{ newFillerBar.style.height = topMaxRadius - this.borderWidth + \"px\"; newFillerBar.style.marginLeft = this.settings.tl.radius - this.borderWidth + \"px\"; newFillerBar.style.marginRight = this.settings.tr.radius - this.borderWidth + \"px\"; newFillerBar.style.borderTop = this.borderString; if(this.backgroundImage != \"\")\nnewFillerBar.style.backgroundPosition = \"-\" + (topMaxRadius + this.borderWidth) + \"px 0px\"; this.topContainer.appendChild(newFillerBar);}\nthis.box.style.backgroundPosition = \"0px -\" + (topMaxRadius - this.borderWidth) + \"px\";}\nbreak; case \"b\":\nif(this.bottomContainer)\n{ if(this.settings.bl.radius && this.settings.br.radius)\n{ newFillerBar.style.height = botMaxRadius - this.borderWidth + \"px\"; newFillerBar.style.marginLeft = this.settings.bl.radius - this.borderWidth + \"px\"; newFillerBar.style.marginRight = this.settings.br.radius - this.borderWidth + \"px\"; newFillerBar.style.borderBottom = this.borderString; if(this.backgroundImage != \"\")\nnewFillerBar.style.backgroundPosition = \"-\" + (botMaxRadius + this.borderWidth) + \"px -\" + (this.boxHeight + (topMaxRadius + this.borderWidth)) + \"px\"; this.bottomContainer.appendChild(newFillerBar);}\n}\nbreak;}\n}\n}\nif(this.settings.autoPad == true && this.boxPadding > 0)\n{ var contentContainer = document.createElement(\"DIV\"); contentContainer.style.position = \"relative\"; contentContainer.innerHTML = this.boxContent; contentContainer.className = \"autoPadDiv\"; var topPadding = Math.abs(topMaxRadius - this.boxPadding); var botPadding = Math.abs(botMaxRadius - this.boxPadding); if(topMaxRadius < this.boxPadding)\ncontentContainer.style.paddingTop = topPadding + \"px\"; if(botMaxRadius < this.boxPadding)\ncontentContainer.style.paddingBottom = botMaxRadius + \"px\"; contentContainer.style.paddingLeft = this.boxPadding + \"px\"; contentContainer.style.paddingRight = this.boxPadding + \"px\"; this.contentDIV = this.box.appendChild(contentContainer);}\n}\nthis.drawPixel = function(intx, inty, colour, transAmount, height, newCorner, image, cornerRadius)\n{ var pixel = document.createElement(\"DIV\"); pixel.style.height = height + \"px\"; pixel.style.width = \"1px\"; pixel.style.position = \"absolute\"; pixel.style.fontSize = \"1px\"; pixel.style.overflow = \"hidden\"; var topMaxRadius = Math.max(this.settings[\"tr\"].radius, this.settings[\"tl\"].radius); if(image == -1 && this.backgroundImage != \"\")\n{ pixel.style.backgroundImage = this.backgroundImage; pixel.style.backgroundPosition = \"-\" + (this.boxWidth - (cornerRadius - intx) + this.borderWidth) + \"px -\" + ((this.boxHeight + topMaxRadius + inty) -this.borderWidth) + \"px\";}\nelse\n{ pixel.style.backgroundColor = colour;}\nif (transAmount != 100)\nsetOpacity(pixel, transAmount); pixel.style.top = inty + \"px\"; pixel.style.left = intx + \"px\"; newCorner.appendChild(pixel);}\n}\nfunction insertAfter(parent, node, referenceNode)\n{ parent.insertBefore(node, referenceNode.nextSibling);}\nfunction BlendColour(Col1, Col2, Col1Fraction)\n{ var red1 = parseInt(Col1.substr(1,2),16); var green1 = parseInt(Col1.substr(3,2),16); var blue1 = parseInt(Col1.substr(5,2),16); var red2 = parseInt(Col2.substr(1,2),16); var green2 = parseInt(Col2.substr(3,2),16); var blue2 = parseInt(Col2.substr(5,2),16); if(Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1; var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction))); if(endRed > 255) endRed = 255; if(endRed < 0) endRed = 0; var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction))); if(endGreen > 255) endGreen = 255; if(endGreen < 0) endGreen = 0; var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction))); if(endBlue > 255) endBlue = 255; if(endBlue < 0) endBlue = 0; return \"#\" + IntToHex(endRed)+ IntToHex(endGreen)+ IntToHex(endBlue);}\nfunction IntToHex(strNum)\n{ base = strNum / 16; rem = strNum % 16; base = base - (rem / 16); baseS = MakeHex(base); remS = MakeHex(rem); return baseS + '' + remS;}\nfunction MakeHex(x)\n{ if((x >= 0) && (x <= 9))\n{ return x;}\nelse\n{ switch(x)\n{ case 10: return \"A\"; case 11: return \"B\"; case 12: return \"C\"; case 13: return \"D\"; case 14: return \"E\"; case 15: return \"F\";}\n}\n}\nfunction pixelFraction(x, y, r)\n{ var pixelfraction = 0; var xvalues = new Array(1); var yvalues = new Array(1); var point = 0; var whatsides = \"\"; var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2))); if ((intersect >= y) && (intersect < (y+1)))\n{ whatsides = \"Left\"; xvalues[point] = 0; yvalues[point] = intersect - y; point = point + 1;}\nvar intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2))); if ((intersect >= x) && (intersect < (x+1)))\n{ whatsides = whatsides + \"Top\"; xvalues[point] = intersect - x; yvalues[point] = 1; point = point + 1;}\nvar intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2))); if ((intersect >= y) && (intersect < (y+1)))\n{ whatsides = whatsides + \"Right\"; xvalues[point] = 1; yvalues[point] = intersect - y; point = point + 1;}\nvar intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2))); if ((intersect >= x) && (intersect < (x+1)))\n{ whatsides = whatsides + \"Bottom\"; xvalues[point] = intersect - x; yvalues[point] = 0;}\nswitch (whatsides)\n{ case \"LeftRight\":\npixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2); break; case \"TopRight\":\npixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2); break; case \"TopBottom\":\npixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2); break; case \"LeftBottom\":\npixelfraction = (yvalues[0]*xvalues[1])/2; break; default:\npixelfraction = 1;}\nreturn pixelfraction;}\nfunction rgb2Hex(rgbColour)\n{ try{ var rgbArray = rgb2Array(rgbColour); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); var hexColour = \"#\" + IntToHex(red) + IntToHex(green) + IntToHex(blue);}\ncatch(e){ alert(\"There was an error converting the RGB value to Hexadecimal in function rgb2Hex\");}\nreturn hexColour;}\nfunction rgb2Array(rgbColour)\n{ var rgbValues = rgbColour.substring(4, rgbColour.indexOf(\")\")); var rgbArray = rgbValues.split(\", \"); return rgbArray;}\nfunction setOpacity(obj, opacity)\n{ opacity = (opacity == 100)?99.999:opacity; if(isSafari && obj.tagName != \"IFRAME\")\n{ var rgbArray = rgb2Array(obj.style.backgroundColor); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); obj.style.backgroundColor = \"rgba(\" + red + \", \" + green + \", \" + blue + \", \" + opacity/100 + \")\";}\nelse if(typeof(obj.style.opacity) != \"undefined\")\n{ obj.style.opacity = opacity/100;}\nelse if(typeof(obj.style.MozOpacity) != \"undefined\")\n{ obj.style.MozOpacity = opacity/100;}\nelse if(typeof(obj.style.filter) != \"undefined\")\n{ obj.style.filter = \"alpha(opacity:\" + opacity + \")\";}\nelse if(typeof(obj.style.KHTMLOpacity) != \"undefined\")\n{ obj.style.KHTMLOpacity = opacity/100;}\n}\nfunction inArray(array, value)\n{ for(var i = 0; i < array.length; i++){ if (array[i] === value) return i;}\nreturn false;}\nfunction inArrayKey(array, value)\n{ for(key in array){ if(key === value) return true;}\nreturn false;}\nfunction addEvent(elm, evType, fn, useCapture) { if (elm.addEventListener) { elm.addEventListener(evType, fn, useCapture); return true;}\nelse if (elm.attachEvent) { var r = elm.attachEvent('on' + evType, fn); return r;}\nelse { elm['on' + evType] = fn;}\n}\nfunction removeEvent(obj, evType, fn, useCapture){ if (obj.removeEventListener){ obj.removeEventListener(evType, fn, useCapture); return true;} else if (obj.detachEvent){ var r = obj.detachEvent(\"on\"+evType, fn); return r;} else { alert(\"Handler could not be removed\");}\n}\nfunction format_colour(colour)\n{ var returnColour = \"#ffffff\"; if(colour != \"\" && colour != \"transparent\")\n{ if(colour.substr(0, 3) == \"rgb\")\n{ returnColour = rgb2Hex(colour);}\nelse if(colour.length == 4)\n{ returnColour = \"#\" + colour.substring(1, 2) + colour.substring(1, 2) + colour.substring(2, 3) + colour.substring(2, 3) + colour.substring(3, 4) + colour.substring(3, 4);}\nelse\n{ returnColour = colour;}\n}\nreturn returnColour;}\nfunction get_style(obj, property, propertyNS)\n{ try\n{ if(obj.currentStyle)\n{ var returnVal = eval(\"obj.currentStyle.\" + property);}\nelse\n{ if(isSafari && obj.style.display == \"none\")\n{ obj.style.display = \"\"; var wasHidden = true;}\nvar returnVal = document.defaultView.getComputedStyle(obj, '').getPropertyValue(propertyNS); if(isSafari && wasHidden)\n{ obj.style.display = \"none\";}\n}\n}\ncatch(e)\n{ }\nreturn returnVal;}\nfunction getElementsByClass(searchClass, node, tag)\n{ var classElements = new Array(); if(node == null)\nnode = document; if(tag == null)\ntag = '*'; var els = node.getElementsByTagName(tag); var elsLen = els.length; var pattern = new RegExp(\"(^|\\s)\"+searchClass+\"(\\s|$)\"); for (i = 0, j = 0; i < elsLen; i++)\n{ if(pattern.test(els[i].className))\n{ classElements[j] = els[i]; j++;}\n}\nreturn classElements;}\nfunction newCurvyError(errorMessage)\n{ return new Error(\"curvyCorners Error:\\n\" + errorMessage)\n}\n"
  },
  {
    "path": "vendor/plugins/googlecharts/website/stylesheets/screen.css",
    "content": "body {\n  background-color: #E1D1F1;\n  font-family: \"Georgia\", sans-serif;\n  font-size: 16px;\n  line-height: 1.6em;\n  padding: 1.6em 0 0 0;\n  color: #333;\n}\nh1, h2, h3, h4, h5, h6 {\n  color: #444;\n}\nh1 { \n  font-family: sans-serif;\n  font-weight: normal;\n  font-size: 4em;\n  line-height: 0.8em;\n  letter-spacing: -0.1ex;\n\tmargin: 5px;\n}\nli {\n  padding: 0;\n  margin: 0;\n  list-style-type: square;\n}\na {\n  color: #5E5AFF;\n\tbackground-color: #DAC;\n  font-weight: normal;\n  text-decoration: underline;\n}\nblockquote {\n  font-size: 90%;\n  font-style: italic;\n  border-left: 1px solid #111;\n  padding-left: 1em;\n}\n.caps {\n  font-size: 80%;\n}\n\n#main {\n  width: 45em;\n  padding: 0;\n  margin: 0 auto;\n}\n.coda {\n  text-align: right;\n  color: #77f;\n  font-size: smaller;\n}\n\ntable {\n  font-size: 90%;\n  line-height: 1.4em;\n  color: #ff8;\n  background-color: #111;\n  padding: 2px 10px 2px 10px;\n\tborder-style: dashed;\n}\n\nth {\n\tcolor: #fff;\n}\n\ntd {\n  padding: 2px 10px 2px 10px;\n}\n\n.success {\n\tcolor: #0CC52B;\n}\n\n.failed {\n\tcolor: #E90A1B;\n}\n\n.unknown {\n\tcolor: #995000;\n}\npre, code {\n  font-family: monospace;\n  font-size: 90%;\n  line-height: 1.4em;\n  color: #ff8;\n  background-color: #111;\n  padding: 2px 10px 2px 10px;\n  overflow: auto;\n}\n.comment { color: #aaa; font-style: italic; }\n.keyword { color: #eff; font-weight: bold; }\n.punct { color: #eee; font-weight: bold; }\n.symbol { color: #0bb; }\n.string { color: #6b4; }\n.ident { color: #ff8; }\n.constant { color: #66f; }\n.regex { color: #ec6; }\n.number { color: #F99; }\n.expr { color: #227; }\n\n#version {\n  float: right;\n  text-align: right;\n  font-family: sans-serif;\n  font-weight: normal;\n  background-color: #B3ABFF;\n  color: #141331;\n  padding: 15px 20px 10px 20px;\n  margin: 0 auto;\n\tmargin-top: 15px;\n  border: 3px solid #141331;\n}\n\n#version .numbers {\n  display: block;\n  font-size: 4em;\n  line-height: 0.8em;\n  letter-spacing: -0.1ex;\n\tmargin-bottom: 15px;\n}\n\n#version p {\n  text-decoration: none;\n\tcolor: #141331;\n\tbackground-color: #B3ABFF;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n#version a {\n  text-decoration: none;\n\tcolor: #141331;\n\tbackground-color: #B3ABFF;\n}\n\n.clickable {\n\tcursor:\tpointer; \n\tcursor:\thand;\n}\n\n"
  },
  {
    "path": "vendor/plugins/googlecharts/website/template.rhtml",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <link rel=\"stylesheet\" href=\"stylesheets/screen.css\" type=\"text/css\" media=\"screen\" />\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>\n      <%= title %>\n  </title>\n  <script src=\"javascripts/rounded_corners_lite.inc.js\" type=\"text/javascript\"></script>\n<style>\n\n</style>\n  <script type=\"text/javascript\">\n    window.onload = function() {\n      settings = {\n          tl: { radius: 10 },\n          tr: { radius: 10 },\n          bl: { radius: 10 },\n          br: { radius: 10 },\n          antiAlias: true,\n          autoPad: true,\n          validTags: [\"div\"]\n      }\n      var versionBox = new curvyCorners(settings, document.getElementById(\"version\"));\n      versionBox.applyCornersToAll();\n    }\n  </script>\n</head>\n<body>\n<div id=\"main\">\n\n    <h1><%= title %></h1>\n    <div id=\"version\" class=\"clickable\" onclick='document.location = \"<%= download %>\"; return false'>\n      <p>Get Version</p>\n      <a href=\"<%= download %>\" class=\"numbers\"><%= version %></a>\n    </div>\n    <%= body %>\n    <p class=\"coda\">\n      <a href=\"mattaimonetti@gmail.com\">Matt Aimonetti</a>, <%= modified.pretty %><br>\n      Theme extended from <a href=\"http://rb2js.rubyforge.org/\">Paul Battley</a>\n    </p>\n</div>\n\n<script src=\"http://www.google-analytics.com/urchin.js\" type=\"text/javascript\">\n</script>\n<script type=\"text/javascript\">\n_uacct = \"UA-179809-11\";\nurchinTracker();\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "vendor/plugins/gravatar/.gitignore",
    "content": "coverage\n"
  },
  {
    "path": "vendor/plugins/gravatar/MIT-LICENSE",
    "content": "Copyright (c) 2007 West Arete Computing, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "vendor/plugins/gravatar/README.rdoc",
    "content": "== Gravatar Plugin\n\nThis plugin provides a handful of view helpers for displaying gravatars \n(globally-recognized avatars). \n\nGravatars allow users to configure an avatar to go with their email address at\na central location: http://gravatar.com. Gravatar-aware websites (such\nas yours) can then look up and display each user's preferred avatar, without\nhaving to handle avatar management. The user gets the benefit of not having to\nset up an avatar for each site that they post on.\n\n== Installation\n\n  cd ~/myapp\n  ruby script/plugin install git://github.com/woods/gravatar-plugin.git\n\nor, if you're using piston[http://piston.rubyforge.org] (worth it!):\n\n  cd ~/myapp/vendor/plugins\n  piston import git://github.com/woods/gravatar-plugin.git\n\n== Example\n\nIf you represent your users with a model that has an +email+ method (typical\nfor most rails authentication setups), then you can simply use this method\nin your views:\n\n  <%= gravatar_for @user %>\n  \nThis will be replaced with the full HTML +img+ tag necessary for displaying \nthat user's gravatar.\n\nOther helpers are documented under GravatarHelper::PublicMethods.\n\n== Acknowledgments\n\nThanks to Magnus Bergmark (http://github.com/Mange), who contributed the SSL\nsupport in this plugin, as well as a few minor fixes.\n\nThe following people have also written gravatar-related Ruby libraries:\n* Seth Rasmussen created the gravatar gem[http://gravatar.rubyforge.org]\n* Matt McCray has also created a gravatar \n  plugin[http://mattmccray.com/svn/rails/plugins/gravatar_helper]\n\n== Author\n\n  Scott A. Woods\n  West Arete Computing, Inc.\n  http://westarete.com\n  scott at westarete dot com\n\n== TODO\n\n* Add specs for ssl support\n* Finish rdoc documentation"
  },
  {
    "path": "vendor/plugins/gravatar/Rakefile",
    "content": "require 'spec/rake/spectask'\nrequire 'rake/rdoctask'\n\ndesc 'Default: run all specs'\ntask :default => :spec\n\ndesc 'Run all application-specific specs'\nSpec::Rake::SpecTask.new(:spec) do |t|\n  t.rcov = true\nend\n\ndesc \"Report code statistics (KLOCs, etc) from the application\"\ntask :stats do\n  RAILS_ROOT = File.dirname(__FILE__)\n  STATS_DIRECTORIES = [\n    %w(Libraries  lib/),\n    %w(Specs      spec/),\n  ].collect { |name, dir| [ name, \"#{RAILS_ROOT}/#{dir}\" ] }.select { |name, dir| File.directory?(dir) }\n  require 'code_statistics'\n  CodeStatistics.new(*STATS_DIRECTORIES).to_s\nend\n\nnamespace :doc do\n  desc 'Generate documentation for the assert_request plugin.'\n  Rake::RDocTask.new(:plugin) do |rdoc|\n    rdoc.rdoc_dir = 'rdoc'\n    rdoc.title    = 'Gravatar Rails Plugin'\n    rdoc.options << '--line-numbers' << '--inline-source' << '--accessor' << 'cattr_accessor=rw'\n    rdoc.rdoc_files.include('README')\n    rdoc.rdoc_files.include('lib/**/*.rb')\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/gravatar/about.yml",
    "content": "author: Scott Woods, West Arete Computing\nsummary: View helpers for displaying gravatars.\nhomepage: http://github.com/woods/gravatar-plugin/\nplugin: git://github.com/woods/gravatar-plugin.git\nlicense: MIT\nversion: 0.1\nrails_version: 1.0+\n"
  },
  {
    "path": "vendor/plugins/gravatar/init.rb",
    "content": "require 'gravatar'\nActionView::Base.send :include, GravatarHelper::PublicMethods\n"
  },
  {
    "path": "vendor/plugins/gravatar/lib/gravatar.rb",
    "content": "require 'digest/md5'\nrequire 'cgi'\n\nmodule GravatarHelper\n\n  # These are the options that control the default behavior of the public\n  # methods. They can be overridden during the actual call to the helper,\n  # or you can set them in your environment.rb as such:\n  #\n  #   # Allow racier gravatars\n  #   GravatarHelper::DEFAULT_OPTIONS[:rating] = 'R'\n  #\n  DEFAULT_OPTIONS = {\n    # The URL of a default image to display if the given email address does\n    # not have a gravatar.\n    :default => nil,\n    \n    # The default size in pixels for the gravatar image (they're square).\n    :size => 50,\n    \n    # The maximum allowed MPAA rating for gravatars. This allows you to \n    # exclude gravatars that may be out of character for your site.\n    :rating => 'PG',\n    \n    # The alt text to use in the img tag for the gravatar.  Since it's a\n    # decorational picture, the alt text should be empty according to the\n    # XHTML specs.\n    :alt => '',\n    \n    # The class to assign to the img tag for the gravatar.\n    :class => 'gravatar',\n    \n    # Whether or not to display the gravatars using HTTPS instead of HTTP\n    :ssl => true,\n  }\n  \n  # The methods that will be made available to your views.\n  module PublicMethods\n  \n    # Return the HTML img tag for the given user's gravatar. Presumes that \n    # the given user object will respond_to \"email\", and return the user's\n    # email address.\n    def gravatar_for(user, options={})\n      gravatar(user.email, options)\n    end\n\n    # Return the HTML img tag for the given email address's gravatar.\n    def gravatar(email, options={})\n      src = h(gravatar_url(email, options))\n      options = DEFAULT_OPTIONS.merge(options)\n      [:class, :alt, :size].each { |opt| options[opt] = h(options[opt]) }\n      \"<img class=\\\"#{options[:class]}\\\" alt=\\\"#{options[:alt]}\\\" width=\\\"#{options[:size]}\\\" height=\\\"#{options[:size]}\\\" src=\\\"#{src}\\\" />\"      \n    end\n    \n    # Returns the base Gravatar URL for the given email hash. If ssl evaluates to true,\n    # a secure URL will be used instead. This is required when the gravatar is to be \n    # displayed on a HTTPS site.\n    def gravatar_api_url(hash, ssl=false)\n      if ssl\n        \"https://secure.gravatar.com/avatar/#{hash}\"\n      else\n        \"http://www.gravatar.com/avatar/#{hash}\"\n      end\n    end\n\n    # Return the gravatar URL for the given email address.\n    def gravatar_url(email, options={})\n      email_hash = Digest::MD5.hexdigest(email)\n      options = DEFAULT_OPTIONS.merge(options)\n      options[:default] = CGI::escape(options[:default]) unless options[:default].nil?\n      returning gravatar_api_url(email_hash, options) do |url|\n        opts = []\n        [:rating, :size, :default].each do |opt|\n          unless options[opt].nil?\n            value = h(options[opt])\n            opts << [opt, value].join('=')\n          end\n        end\n        url << \"?#{opts.join('&')}\" unless opts.empty?\n      end\n    end\n\n  end\n  \nend"
  },
  {
    "path": "vendor/plugins/gravatar/spec/gravatar_spec.rb",
    "content": "require 'rubygems'\nrequire 'erb'  # to get \"h\"\nrequire 'active_support'  # to get \"returning\"\nrequire File.dirname(__FILE__) + '/../lib/gravatar'\ninclude GravatarHelper, GravatarHelper::PublicMethods, ERB::Util\n\ncontext \"gravatar_url with a custom default URL\" do\n  setup do\n    @original_options = DEFAULT_OPTIONS.dup\n    DEFAULT_OPTIONS[:default] = \"no_avatar.png\"\n    @url = gravatar_url(\"somewhere\")\n  end\n  \n  specify \"should include the \\\"default\\\" argument in the result\" do\n    @url.should match(/&default=no_avatar.png/)\n  end\n  \n  teardown do\n    DEFAULT_OPTIONS.merge!(@original_options)\n  end\n  \nend\n\ncontext \"gravatar_url with default settings\" do\n  setup do\n    @url = gravatar_url(\"somewhere\")\n  end\n  \n  specify \"should have a nil default URL\" do\n    DEFAULT_OPTIONS[:default].should be_nil\n  end\n  \n  specify \"should not include the \\\"default\\\" argument in the result\" do\n    @url.should_not match(/&default=/)\n  end  \n  \nend"
  },
  {
    "path": "vendor/plugins/jrails/CHANGELOG",
    "content": "0.5.0 (31 July 2009)\n* Gemification\n* Support for Ruby 1.9.X\n* Updated to jQuery 1.3.2\n* Updated to jQuery UI 1.7.2\n* Created a jrails binary (runs rake tasks) because rails does not (yet?) pickup\ntasks from gem plugins\n* Changed default to use jQuery compatibility name (not $)\n* Created a scrub task that will remove the prototype / script.aculo.us\njavascript files\n* better approximate scriptaculous effect names\n* add support for page[:element_id].visual_effect(:effect) as well as page.visual_effect(:effect, :element_id)\n* added a reset form function to jrails.js (stolen from jquery form)\n* can now use jquery selectors in all functions\n* added javascript_function helper to render inline rjs helpers\n* better support for sortable_element\n\n0.4.0 (16 June 2008)\n* updated to jquery-ui 1.5 & merged js into single file\n* Added jQuery.noConflict support\n* support for value/val\n* additional support for update/delete methods\n* support for success/failure hash\n* setRequestHeader now gets called globally\n* Better support for droppables, sortables\n* Add support for prototype AJAX callbacks\n* better support for AJAX form calls\n\n0.3.0 (22 Feb 2008)\n* updated to jquery-fx 1.0b and jquery-ui 1.5b\n* Add text/javascript request header to fix format.js\n* Added Tasks (thanks ggarside)\n* Improve visual_effects methods\n* Fixed some RJS calls\n* Fixed observer code for ie\n\n0.2.0 (26 Nov 2007)\n* Vastly Improved FX\n* Improved Form Observers\n* Fixed Rails <= 1.2.6 Compatibility\n\n0.1.0 (15 Nov 2007)\n* Initial release\n"
  },
  {
    "path": "vendor/plugins/jrails/LICENSE",
    "content": "Copyright (c) 2008 Aaron Eisenberger\n \nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n \nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n \nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "vendor/plugins/jrails/README.rdoc",
    "content": "= jRails\n\njRails is a drop-in jQuery replacement for the Rails Prototype/script.aculo.us helpers.\n\n== Resources\n\nInstall\n\n* .script/plugin install git://github.com/aaronchi/jrails.git\n\nProject Site\n\n* http://code.google.com/p/ennerchi\n\nWeb Site\n\n* http://www.ennerchi.com/projects/jrails\n\nGroup Site\n\n* http://groups.google.com/group/jrails\n"
  },
  {
    "path": "vendor/plugins/jrails/Rakefile",
    "content": "require 'rubygems'\nrequire 'rake'\n\nbegin\n  require 'jeweler'\n  Jeweler::Tasks.new do |gem|\n    gem.name = \"jrails\"\n    gem.summary = \"jRails is a drop-in jQuery replacement for the Rails Prototype/script.aculo.us helpers.\"\n    gem.description = \"Using jRails, you can get all of the same default Rails helpers for javascript functionality using the lighter jQuery library.\"\n    gem.email = \"aaronchi@gmail.com\"\n    gem.homepage = \"http://ennerchi.com/projects/jrails\"\n    gem.authors = [\"Aaron Eisenberger\", \"Patrick Hurley\"]\n    gem.rubyforge_project = \"jrails\"\n    gem.files =  FileList[\"[A-Z]*.rb\",\"{bin,javascripts,lib,rails,tasks}/**/*\"]\n  end\n  Jeweler::GemcutterTasks.new\nrescue LoadError\n  puts \"Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler\"\nend"
  },
  {
    "path": "vendor/plugins/jrails/VERSION.yml",
    "content": "--- \n:build: \n:patch: 0\n:major: 0\n:minor: 6\n"
  },
  {
    "path": "vendor/plugins/jrails/bin/jrails",
    "content": "#!/usr/bin/env ruby\n\nrequire 'rubygems'\nrequire 'rake'\n\nRAILS_ROOT = Dir.pwd\nrakeapp = Rake.application\nfname =File.join(File.dirname(__FILE__), '..', 'tasks', 'jrails.rake')\nload fname\n\ntask :help do\n  puts \"jrails [command]\\n\\n\"\n  rakeapp.options.show_task_pattern = Regexp.new('^[hius]')\n  rakeapp.display_tasks_and_comments\nend\n\ndesc 'Installs the jQuery and jRails javascripts to public/javascripts'\ntask :install do\n  Rake::Task['jrails:js:install'].invoke\nend\n\ndesc 'Remove the prototype / script.aculo.us javascript files'\ntask :scrub do\n  Rake::Task['jrails:js:scrub'].invoke\nend\n\nrakeapp.init(\"jrails\")\ntask :default => [:help]\n\nrakeapp.top_level\n"
  },
  {
    "path": "vendor/plugins/jrails/init.rb",
    "content": "require 'rails/init.rb'\n"
  },
  {
    "path": "vendor/plugins/jrails/install.rb",
    "content": "# Install hook code here\nputs \"Copying files...\"\ndir = \"javascripts\"\n[\"jquery-ui.js\", \"jquery.js\", \"jrails.js\"].each do |js_file|\n\tdest_file = File.join(RAILS_ROOT, \"public\", dir, js_file)\n\tsrc_file = File.join(File.dirname(__FILE__) , dir, js_file)\n\tFileUtils.cp_r(src_file, dest_file)\nend\nputs \"Files copied - Installation complete!\"\n"
  },
  {
    "path": "vendor/plugins/jrails/javascripts/jquery-ui.js",
    "content": "/*\n * jQuery UI 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI\n */\njQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:\"1.7.2\",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m<n.length;m++){if(j.options[n[m][0]]){n[m][1].apply(j.element,k)}}}},contains:function(k,j){return document.compareDocumentPosition?k.compareDocumentPosition(j)&16:k!==j&&k.contains(j)},hasScroll:function(m,k){if(c(m).css(\"overflow\")==\"hidden\"){return false}var j=(k&&k==\"left\")?\"scrollLeft\":\"scrollTop\",l=false;if(m[j]>0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h=\"http://www.w3.org/2005/07/aaa\",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j==\"role\"?(m?f.call(this,k,j,\"wairole:\"+l):(f.apply(this,arguments)||\"\").replace(b,\"\")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,\"aaa:\"),l):f.call(this,k,j.replace(a,\"aaa:\"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,\"\"))}):e.call(this,j))}}c.fn.extend({remove:function(){c(\"*\",this).add(this).each(function(){c(this).triggerHandler(\"remove\")});return i.apply(this,arguments)},enableSelection:function(){return this.attr(\"unselectable\",\"off\").css(\"MozUserSelect\",\"\").unbind(\"selectstart.ui\")},disableSelection:function(){return this.attr(\"unselectable\",\"on\").css(\"MozUserSelect\",\"none\").bind(\"selectstart.ui\",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css(\"position\")))||(/absolute/).test(this.css(\"position\"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,\"position\",1))&&(/(auto|scroll)/).test(c.curCSS(this,\"overflow\",1)+c.curCSS(this,\"overflow-y\",1)+c.curCSS(this,\"overflow-x\",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,\"overflow\",1)+c.curCSS(this,\"overflow-y\",1)+c.curCSS(this,\"overflow-x\",1))}).eq(0)}return(/fixed/).test(this.css(\"position\"))||!j.length?c(document):j}});c.extend(c.expr[\":\"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,\"tabindex\");return(/input|select|textarea|button|object/.test(l)?!k.disabled:\"a\"==l||\"area\"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)[\"area\"==l?\"parents\":\"closest\"](\":hidden\").length},tabbable:function(k){var j=c.attr(k,\"tabindex\");return(isNaN(j)||j>=0)&&c(k).is(\":focusable\")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p==\"string\"?p.split(/,?\\s+/):p)}var j=k(\"getter\");if(l.length==1&&typeof l[0]==\"string\"){j=j.concat(k(\"getterSetter\"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(\".\")[0];k=k.split(\".\")[1];c.fn[k]=function(p){var n=(typeof p==\"string\"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)==\"_\"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+\"-\"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind(\"setData.\"+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind(\"getData.\"+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind(\"remove\",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter=\"option\"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+\"-disabled \"+this.namespace+\"-state-disabled\").removeAttr(\"aria-disabled\")},option:function(l,m){var k=l,j=this;if(typeof l==\"string\"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j==\"disabled\"){this.element[k?\"addClass\":\"removeClass\"](this.widgetBaseClass+\"-disabled \"+this.namespace+\"-state-disabled\").attr(\"aria-disabled\",k)}},enable:function(){this._setData(\"disabled\",false)},disable:function(){this._setData(\"disabled\",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind(\"mousedown.\"+this.widgetName,function(k){return j._mouseDown(k)}).bind(\"click.\"+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr(\"unselectable\");this.element.attr(\"unselectable\",\"on\")}this.started=false},_mouseDestroy:function(){this.element.unbind(\".\"+this.widgetName);(c.browser.msie&&this.element.attr(\"unselectable\",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel==\"string\"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind(\"mousemove.\"+this.widgetName,this._mouseMoveDelegate).bind(\"mouseup.\"+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind(\"mousemove.\"+this.widgetName,this._mouseMoveDelegate).unbind(\"mouseup.\"+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);;/*\n * jQuery UI Draggable 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Draggables\n *\n * Depends:\n *\tui.core.js\n */\n(function(a){a.widget(\"ui.draggable\",a.extend({},a.ui.mouse,{_init:function(){if(this.options.helper==\"original\"&&!(/^(?:r|a|f)/).test(this.element.css(\"position\"))){this.element[0].style.position=\"relative\"}(this.options.addClasses&&this.element.addClass(\"ui-draggable\"));(this.options.disabled&&this.element.addClass(\"ui-draggable-disabled\"));this._mouseInit()},destroy:function(){if(!this.element.data(\"draggable\")){return}this.element.removeData(\"draggable\").unbind(\".draggable\").removeClass(\"ui-draggable ui-draggable-dragging ui-draggable-disabled\");this._mouseDestroy()},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is(\".ui-resizable-handle\")){return false}this.handle=this._getHandle(b);if(!this.handle){return false}return true},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b);this._cacheHelperProportions();if(a.ui.ddmanager){a.ui.ddmanager.current=this}this._cacheMargins();this.cssPosition=this.helper.css(\"position\");this.scrollParent=this.helper.scrollParent();this.offset=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(b);this.originalPageX=b.pageX;this.originalPageY=b.pageY;if(c.cursorAt){this._adjustOffsetFromHelper(c.cursorAt)}if(c.containment){this._setContainment()}this._trigger(\"start\",b);this._cacheHelperProportions();if(a.ui.ddmanager&&!c.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,b)}this.helper.addClass(\"ui-draggable-dragging\");this._mouseDrag(b,true);return true},_mouseDrag:function(b,d){this.position=this._generatePosition(b);this.positionAbs=this._convertPositionTo(\"absolute\");if(!d){var c=this._uiHash();this._trigger(\"drag\",b,c);this.position=c.position}if(!this.options.axis||this.options.axis!=\"y\"){this.helper[0].style.left=this.position.left+\"px\"}if(!this.options.axis||this.options.axis!=\"x\"){this.helper[0].style.top=this.position.top+\"px\"}if(a.ui.ddmanager){a.ui.ddmanager.drag(this,b)}return false},_mouseStop:function(c){var d=false;if(a.ui.ddmanager&&!this.options.dropBehaviour){d=a.ui.ddmanager.drop(this,c)}if(this.dropped){d=this.dropped;this.dropped=false}if((this.options.revert==\"invalid\"&&!d)||(this.options.revert==\"valid\"&&d)||this.options.revert===true||(a.isFunction(this.options.revert)&&this.options.revert.call(this.element,d))){var b=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){b._trigger(\"stop\",c);b._clear()})}else{this._trigger(\"stop\",c);this._clear()}return false},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find(\"*\").andSelf().each(function(){if(this==b.target){c=true}});return c},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c])):(d.helper==\"clone\"?this.element.clone():this.element);if(!b.parents(\"body\").length){b.appendTo((d.appendTo==\"parent\"?this.element[0].parentNode:d.appendTo))}if(b[0]!=this.element[0]&&!(/(fixed|absolute)/).test(b.css(\"position\"))){b.css(\"position\",\"absolute\")}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition==\"absolute\"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()==\"html\"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css(\"borderTopWidth\"),10)||0),left:b.left+(parseInt(this.offsetParent.css(\"borderLeftWidth\"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition==\"relative\"){var b=this.element.position();return{top:b.top-(parseInt(this.helper.css(\"top\"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css(\"left\"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css(\"marginLeft\"),10)||0),top:(parseInt(this.element.css(\"marginTop\"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment==\"parent\"){e.containment=this.helper[0].parentNode}if(e.containment==\"document\"||e.containment==\"window\"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment==\"document\"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment==\"document\"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)&&e.containment.constructor!=Array){var c=a(e.containment)[0];if(!c){return}var d=a(e.containment).offset();var b=(a(c).css(\"overflow\")!=\"hidden\");this.containment=[d.left+(parseInt(a(c).css(\"borderLeftWidth\"),10)||0)+(parseInt(a(c).css(\"paddingLeft\"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css(\"borderTopWidth\"),10)||0)+(parseInt(a(c).css(\"paddingTop\"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css(\"borderLeftWidth\"),10)||0)-(parseInt(a(c).css(\"paddingRight\"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css(\"borderTopWidth\"),10)||0)-(parseInt(a(c).css(\"paddingBottom\"),10)||0)-this.helperProportions.height-this.margins.top]}else{if(e.containment.constructor==Array){this.containment=e.containment}}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f==\"absolute\"?1:-1;var e=this.options,b=this.cssPosition==\"absolute\"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition==\"absolute\"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition==\"relative\"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.left<this.containment[0]){d=this.containment[0]+this.offset.click.left}if(e.pageY-this.offset.click.top<this.containment[1]){c=this.containment[1]+this.offset.click.top}if(e.pageX-this.offset.click.left>this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:(!(g-this.offset.click.top<this.containment[1])?g-h.grid[1]:g+h.grid[1])):g;var f=this.originalPageX+Math.round((d-this.originalPageX)/h.grid[0])*h.grid[0];d=this.containment?(!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:(!(f-this.offset.click.left<this.containment[0])?f-h.grid[0]:f+h.grid[0])):f}}return{top:(c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollTop():(i?0:b.scrollTop())))),left:(d-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollLeft():i?0:b.scrollLeft())))}},_clear:function(){this.helper.removeClass(\"ui-draggable-dragging\");if(this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval){this.helper.remove()}this.helper=null;this.cancelHelperRemoval=false},_trigger:function(b,c,d){d=d||this._uiHash();a.ui.plugin.call(this,b,[c,d]);if(b==\"drag\"){this.positionAbs=this._convertPositionTo(\"absolute\")}return a.widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(b){return{helper:this.helper,position:this.position,absolutePosition:this.positionAbs,offset:this.positionAbs}}}));a.extend(a.ui.draggable,{version:\"1.7.2\",eventPrefix:\"drag\",defaults:{addClasses:true,appendTo:\"parent\",axis:false,cancel:\":input,option\",connectToSortable:false,containment:false,cursor:\"auto\",cursorAt:false,delay:0,distance:1,grid:false,handle:false,helper:\"original\",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:\"default\",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:\"both\",snapTolerance:20,stack:false,zIndex:false}});a.ui.plugin.add(\"draggable\",\"connectToSortable\",{start:function(c,e){var d=a(this).data(\"draggable\"),f=d.options,b=a.extend({},e,{item:d.element});d.sortables=[];a(f.connectToSortable).each(function(){var g=a.data(this,\"sortable\");if(g&&!g.options.disabled){d.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger(\"activate\",c,b)}})},stop:function(c,e){var d=a(this).data(\"draggable\"),b=a.extend({},e,{item:d.element});a.each(d.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;d.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert){this.instance.options.revert=true}this.instance._mouseStop(c);this.instance.options.helper=this.instance.options._helper;if(d.options.helper==\"original\"){this.instance.currentItem.css({top:\"auto\",left:\"auto\"})}}else{this.instance.cancelHelperRemoval=false;this.instance._trigger(\"deactivate\",c,b)}})},drag:function(c,f){var e=a(this).data(\"draggable\"),b=this;var d=function(i){var n=this.offset.click.top,m=this.offset.click.left;var g=this.positionAbs.top,k=this.positionAbs.left;var j=i.height,l=i.width;var p=i.top,h=i.left;return a.ui.isOver(g+n,k+m,p,h,j,l)};a.each(e.sortables,function(g){this.instance.positionAbs=e.positionAbs;this.instance.helperProportions=e.helperProportions;this.instance.offset.click=e.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=a(b).clone().appendTo(this.instance.element).data(\"sortable-item\",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return f.helper[0]};c.target=this.instance.currentItem[0];this.instance._mouseCapture(c,true);this.instance._mouseStart(c,true,true);this.instance.offset.click.top=e.offset.click.top;this.instance.offset.click.left=e.offset.click.left;this.instance.offset.parent.left-=e.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=e.offset.parent.top-this.instance.offset.parent.top;e._trigger(\"toSortable\",c);e.dropped=this.instance.element;e.currentItem=e.element;this.instance.fromOutside=e}if(this.instance.currentItem){this.instance._mouseDrag(c)}}else{if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger(\"out\",c,this.instance._uiHash(this.instance));this.instance._mouseStop(c,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();if(this.instance.placeholder){this.instance.placeholder.remove()}e._trigger(\"fromSortable\",c);e.dropped=false}}})}});a.ui.plugin.add(\"draggable\",\"cursor\",{start:function(c,d){var b=a(\"body\"),e=a(this).data(\"draggable\").options;if(b.css(\"cursor\")){e._cursor=b.css(\"cursor\")}b.css(\"cursor\",e.cursor)},stop:function(b,c){var d=a(this).data(\"draggable\").options;if(d._cursor){a(\"body\").css(\"cursor\",d._cursor)}}});a.ui.plugin.add(\"draggable\",\"iframeFix\",{start:function(b,c){var d=a(this).data(\"draggable\").options;a(d.iframeFix===true?\"iframe\":d.iframeFix).each(function(){a('<div class=\"ui-draggable-iframeFix\" style=\"background: #fff;\"></div>').css({width:this.offsetWidth+\"px\",height:this.offsetHeight+\"px\",position:\"absolute\",opacity:\"0.001\",zIndex:1000}).css(a(this).offset()).appendTo(\"body\")})},stop:function(b,c){a(\"div.ui-draggable-iframeFix\").each(function(){this.parentNode.removeChild(this)})}});a.ui.plugin.add(\"draggable\",\"opacity\",{start:function(c,d){var b=a(d.helper),e=a(this).data(\"draggable\").options;if(b.css(\"opacity\")){e._opacity=b.css(\"opacity\")}b.css(\"opacity\",e.opacity)},stop:function(b,c){var d=a(this).data(\"draggable\").options;if(d._opacity){a(c.helper).css(\"opacity\",d._opacity)}}});a.ui.plugin.add(\"draggable\",\"scroll\",{start:function(c,d){var b=a(this).data(\"draggable\");if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!=\"HTML\"){b.overflowOffset=b.scrollParent.offset()}},drag:function(d,e){var c=a(this).data(\"draggable\"),f=c.options,b=false;if(c.scrollParent[0]!=document&&c.scrollParent[0].tagName!=\"HTML\"){if(!f.axis||f.axis!=\"x\"){if((c.overflowOffset.top+c.scrollParent[0].offsetHeight)-d.pageY<f.scrollSensitivity){c.scrollParent[0].scrollTop=b=c.scrollParent[0].scrollTop+f.scrollSpeed}else{if(d.pageY-c.overflowOffset.top<f.scrollSensitivity){c.scrollParent[0].scrollTop=b=c.scrollParent[0].scrollTop-f.scrollSpeed}}}if(!f.axis||f.axis!=\"y\"){if((c.overflowOffset.left+c.scrollParent[0].offsetWidth)-d.pageX<f.scrollSensitivity){c.scrollParent[0].scrollLeft=b=c.scrollParent[0].scrollLeft+f.scrollSpeed}else{if(d.pageX-c.overflowOffset.left<f.scrollSensitivity){c.scrollParent[0].scrollLeft=b=c.scrollParent[0].scrollLeft-f.scrollSpeed}}}}else{if(!f.axis||f.axis!=\"x\"){if(d.pageY-a(document).scrollTop()<f.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()-f.scrollSpeed)}else{if(a(window).height()-(d.pageY-a(document).scrollTop())<f.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()+f.scrollSpeed)}}}if(!f.axis||f.axis!=\"y\"){if(d.pageX-a(document).scrollLeft()<f.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()-f.scrollSpeed)}else{if(a(window).width()-(d.pageX-a(document).scrollLeft())<f.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()+f.scrollSpeed)}}}}if(b!==false&&a.ui.ddmanager&&!f.dropBehaviour){a.ui.ddmanager.prepareOffsets(c,d)}}});a.ui.plugin.add(\"draggable\",\"snap\",{start:function(c,d){var b=a(this).data(\"draggable\"),e=b.options;b.snapElements=[];a(e.snap.constructor!=String?(e.snap.items||\":data(draggable)\"):e.snap).each(function(){var g=a(this);var f=g.offset();if(this!=b.element[0]){b.snapElements.push({item:this,width:g.outerWidth(),height:g.outerHeight(),top:f.top,left:f.left})}})},drag:function(u,p){var g=a(this).data(\"draggable\"),q=g.options;var y=q.snapTolerance;var x=p.offset.left,w=x+g.helperProportions.width,f=p.offset.top,e=f+g.helperProportions.height;for(var v=g.snapElements.length-1;v>=0;v--){var s=g.snapElements[v].left,n=s+g.snapElements[v].width,m=g.snapElements[v].top,A=m+g.snapElements[v].height;if(!((s-y<x&&x<n+y&&m-y<f&&f<A+y)||(s-y<x&&x<n+y&&m-y<e&&e<A+y)||(s-y<w&&w<n+y&&m-y<f&&f<A+y)||(s-y<w&&w<n+y&&m-y<e&&e<A+y))){if(g.snapElements[v].snapping){(g.options.snap.release&&g.options.snap.release.call(g.element,u,a.extend(g._uiHash(),{snapItem:g.snapElements[v].item})))}g.snapElements[v].snapping=false;continue}if(q.snapMode!=\"inner\"){var c=Math.abs(m-e)<=y;var z=Math.abs(A-f)<=y;var j=Math.abs(s-w)<=y;var k=Math.abs(n-x)<=y;if(c){p.position.top=g._convertPositionTo(\"relative\",{top:m-g.helperProportions.height,left:0}).top-g.margins.top}if(z){p.position.top=g._convertPositionTo(\"relative\",{top:A,left:0}).top-g.margins.top}if(j){p.position.left=g._convertPositionTo(\"relative\",{top:0,left:s-g.helperProportions.width}).left-g.margins.left}if(k){p.position.left=g._convertPositionTo(\"relative\",{top:0,left:n}).left-g.margins.left}}var h=(c||z||j||k);if(q.snapMode!=\"outer\"){var c=Math.abs(m-f)<=y;var z=Math.abs(A-e)<=y;var j=Math.abs(s-x)<=y;var k=Math.abs(n-w)<=y;if(c){p.position.top=g._convertPositionTo(\"relative\",{top:m,left:0}).top-g.margins.top}if(z){p.position.top=g._convertPositionTo(\"relative\",{top:A-g.helperProportions.height,left:0}).top-g.margins.top}if(j){p.position.left=g._convertPositionTo(\"relative\",{top:0,left:s}).left-g.margins.left}if(k){p.position.left=g._convertPositionTo(\"relative\",{top:0,left:n-g.helperProportions.width}).left-g.margins.left}}if(!g.snapElements[v].snapping&&(c||z||j||k||h)){(g.options.snap.snap&&g.options.snap.snap.call(g.element,u,a.extend(g._uiHash(),{snapItem:g.snapElements[v].item})))}g.snapElements[v].snapping=(c||z||j||k||h)}}});a.ui.plugin.add(\"draggable\",\"stack\",{start:function(b,c){var e=a(this).data(\"draggable\").options;var d=a.makeArray(a(e.stack.group)).sort(function(g,f){return(parseInt(a(g).css(\"zIndex\"),10)||e.stack.min)-(parseInt(a(f).css(\"zIndex\"),10)||e.stack.min)});a(d).each(function(f){this.style.zIndex=e.stack.min+f});this[0].style.zIndex=e.stack.min+d.length}});a.ui.plugin.add(\"draggable\",\"zIndex\",{start:function(c,d){var b=a(d.helper),e=a(this).data(\"draggable\").options;if(b.css(\"zIndex\")){e._zIndex=b.css(\"zIndex\")}b.css(\"zIndex\",e.zIndex)},stop:function(b,c){var d=a(this).data(\"draggable\").options;if(d._zIndex){a(c.helper).css(\"zIndex\",d._zIndex)}}})})(jQuery);;/*\n * jQuery UI Droppable 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Droppables\n *\n * Depends:\n *\tui.core.js\n *\tui.draggable.js\n */\n(function(a){a.widget(\"ui.droppable\",{_init:function(){var c=this.options,b=c.accept;this.isover=0;this.isout=1;this.options.accept=this.options.accept&&a.isFunction(this.options.accept)?this.options.accept:function(e){return e.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};a.ui.ddmanager.droppables[this.options.scope]=a.ui.ddmanager.droppables[this.options.scope]||[];a.ui.ddmanager.droppables[this.options.scope].push(this);(this.options.addClasses&&this.element.addClass(\"ui-droppable\"))},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++){if(b[c]==this){b.splice(c,1)}}this.element.removeClass(\"ui-droppable ui-droppable-disabled\").removeData(\"droppable\").unbind(\".droppable\")},_setData:function(b,c){if(b==\"accept\"){this.options.accept=c&&a.isFunction(c)?c:function(e){return e.is(c)}}else{a.widget.prototype._setData.apply(this,arguments)}},_activate:function(c){var b=a.ui.ddmanager.current;if(this.options.activeClass){this.element.addClass(this.options.activeClass)}(b&&this._trigger(\"activate\",c,this.ui(b)))},_deactivate:function(c){var b=a.ui.ddmanager.current;if(this.options.activeClass){this.element.removeClass(this.options.activeClass)}(b&&this._trigger(\"deactivate\",c,this.ui(b)))},_over:function(c){var b=a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.hoverClass){this.element.addClass(this.options.hoverClass)}this._trigger(\"over\",c,this.ui(b))}},_out:function(c){var b=a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass)}this._trigger(\"out\",c,this.ui(b))}},_drop:function(c,d){var b=d||a.ui.ddmanager.current;if(!b||(b.currentItem||b.element)[0]==this.element[0]){return false}var e=false;this.element.find(\":data(droppable)\").not(\".ui-draggable-dragging\").each(function(){var f=a.data(this,\"droppable\");if(f.options.greedy&&a.ui.intersect(b,a.extend(f,{offset:f.element.offset()}),f.options.tolerance)){e=true;return false}});if(e){return false}if(this.options.accept.call(this.element[0],(b.currentItem||b.element))){if(this.options.activeClass){this.element.removeClass(this.options.activeClass)}if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass)}this._trigger(\"drop\",c,this.ui(b));return this.element}return false},ui:function(b){return{draggable:(b.currentItem||b.element),helper:b.helper,position:b.position,absolutePosition:b.positionAbs,offset:b.positionAbs}}});a.extend(a.ui.droppable,{version:\"1.7.2\",eventPrefix:\"drop\",defaults:{accept:\"*\",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:\"default\",tolerance:\"intersect\"}});a.ui.intersect=function(q,j,o){if(!j.offset){return false}var e=(q.positionAbs||q.position.absolute).left,d=e+q.helperProportions.width,n=(q.positionAbs||q.position.absolute).top,m=n+q.helperProportions.height;var g=j.offset.left,c=g+j.proportions.width,p=j.offset.top,k=p+j.proportions.height;switch(o){case\"fit\":return(g<e&&d<c&&p<n&&m<k);break;case\"intersect\":return(g<e+(q.helperProportions.width/2)&&d-(q.helperProportions.width/2)<c&&p<n+(q.helperProportions.height/2)&&m-(q.helperProportions.height/2)<k);break;case\"pointer\":var h=((q.positionAbs||q.position.absolute).left+(q.clickOffset||q.offset.click).left),i=((q.positionAbs||q.position.absolute).top+(q.clickOffset||q.offset.click).top),f=a.ui.isOver(i,h,p,g,j.proportions.height,j.proportions.width);return f;break;case\"touch\":return((n>=p&&n<=k)||(m>=p&&m<=k)||(n<p&&m>k))&&((e>=g&&e<=c)||(d>=g&&d<=c)||(e<g&&d>c));break;default:return false;break}};a.ui.ddmanager={current:null,droppables:{\"default\":[]},prepareOffsets:function(e,g){var b=a.ui.ddmanager.droppables[e.options.scope];var f=g?g.type:null;var h=(e.currentItem||e.element).find(\":data(droppable)\").andSelf();droppablesLoop:for(var d=0;d<b.length;d++){if(b[d].options.disabled||(e&&!b[d].options.accept.call(b[d].element[0],(e.currentItem||e.element)))){continue}for(var c=0;c<h.length;c++){if(h[c]==b[d].element[0]){b[d].proportions.height=0;continue droppablesLoop}}b[d].visible=b[d].element.css(\"display\")!=\"none\";if(!b[d].visible){continue}b[d].offset=b[d].element.offset();b[d].proportions={width:b[d].element[0].offsetWidth,height:b[d].element[0].offsetHeight};if(f==\"mousedown\"){b[d]._activate.call(b[d],g)}}},drop:function(b,c){var d=false;a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(!this.options){return}if(!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)){d=this._drop.call(this,c)}if(!this.options.disabled&&this.visible&&this.options.accept.call(this.element[0],(b.currentItem||b.element))){this.isout=1;this.isover=0;this._deactivate.call(this,c)}});return d},drag:function(b,c){if(b.options.refreshPositions){a.ui.ddmanager.prepareOffsets(b,c)}a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(this.options.disabled||this.greedyChild||!this.visible){return}var e=a.ui.intersect(b,this,this.options.tolerance);var g=!e&&this.isover==1?\"isout\":(e&&this.isover==0?\"isover\":null);if(!g){return}var f;if(this.options.greedy){var d=this.element.parents(\":data(droppable):eq(0)\");if(d.length){f=a.data(d[0],\"droppable\");f.greedyChild=(g==\"isover\"?1:0)}}if(f&&g==\"isover\"){f.isover=0;f.isout=1;f._out.call(f,c)}this[g]=1;this[g==\"isout\"?\"isover\":\"isout\"]=0;this[g==\"isover\"?\"_over\":\"_out\"].call(this,c);if(f&&g==\"isout\"){f.isout=0;f.isover=1;f._over.call(f,c)}})}}})(jQuery);;/*\n * jQuery UI Sortable 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Sortables\n *\n * Depends:\n *\tui.core.js\n */\n(function(a){a.widget(\"ui.sortable\",a.extend({},a.ui.mouse,{_init:function(){var b=this.options;this.containerCache={};this.element.addClass(\"ui-sortable\");this.refresh();this.floating=this.items.length?(/left|right/).test(this.items[0].item.css(\"float\")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass(\"ui-sortable ui-sortable-disabled\").removeData(\"sortable\").unbind(\".sortable\");this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--){this.items[b].item.removeData(\"sortable-item\")}},_mouseCapture:function(e,f){if(this.reverting){return false}if(this.options.disabled||this.options.type==\"static\"){return false}this._refreshItems(e);var d=null,c=this,b=a(e.target).parents().each(function(){if(a.data(this,\"sortable-item\")==c){d=a(this);return false}});if(a.data(e.target,\"sortable-item\")==c){d=a(e.target)}if(!d){return false}if(this.options.handle&&!f){var g=false;a(this.options.handle,d).find(\"*\").andSelf().each(function(){if(this==e.target){g=true}});if(!g){return false}}this.currentItem=d;this._removeCurrentsFromItems();return true},_mouseStart:function(e,f,b){var g=this.options,c=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(e);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css(\"position\",\"absolute\");this.cssPosition=this.helper.css(\"position\");a.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(e);this.originalPageX=e.pageX;this.originalPageY=e.pageY;if(g.cursorAt){this._adjustOffsetFromHelper(g.cursorAt)}this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!=this.currentItem[0]){this.currentItem.hide()}this._createPlaceholder();if(g.containment){this._setContainment()}if(g.cursor){if(a(\"body\").css(\"cursor\")){this._storedCursor=a(\"body\").css(\"cursor\")}a(\"body\").css(\"cursor\",g.cursor)}if(g.opacity){if(this.helper.css(\"opacity\")){this._storedOpacity=this.helper.css(\"opacity\")}this.helper.css(\"opacity\",g.opacity)}if(g.zIndex){if(this.helper.css(\"zIndex\")){this._storedZIndex=this.helper.css(\"zIndex\")}this.helper.css(\"zIndex\",g.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!=\"HTML\"){this.overflowOffset=this.scrollParent.offset()}this._trigger(\"start\",e,this._uiHash());if(!this._preserveHelperProportions){this._cacheHelperProportions()}if(!b){for(var d=this.containers.length-1;d>=0;d--){this.containers[d]._trigger(\"activate\",e,c._uiHash(this))}}if(a.ui.ddmanager){a.ui.ddmanager.current=this}if(a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,e)}this.dragging=true;this.helper.addClass(\"ui-sortable-helper\");this._mouseDrag(e);return true},_mouseDrag:function(f){this.position=this._generatePosition(f);this.positionAbs=this._convertPositionTo(\"absolute\");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs}if(this.options.scroll){var g=this.options,b=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!=\"HTML\"){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-f.pageY<g.scrollSensitivity){this.scrollParent[0].scrollTop=b=this.scrollParent[0].scrollTop+g.scrollSpeed}else{if(f.pageY-this.overflowOffset.top<g.scrollSensitivity){this.scrollParent[0].scrollTop=b=this.scrollParent[0].scrollTop-g.scrollSpeed}}if((this.overflowOffset.left+this.scrollParent[0].offsetWidth)-f.pageX<g.scrollSensitivity){this.scrollParent[0].scrollLeft=b=this.scrollParent[0].scrollLeft+g.scrollSpeed}else{if(f.pageX-this.overflowOffset.left<g.scrollSensitivity){this.scrollParent[0].scrollLeft=b=this.scrollParent[0].scrollLeft-g.scrollSpeed}}}else{if(f.pageY-a(document).scrollTop()<g.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()-g.scrollSpeed)}else{if(a(window).height()-(f.pageY-a(document).scrollTop())<g.scrollSensitivity){b=a(document).scrollTop(a(document).scrollTop()+g.scrollSpeed)}}if(f.pageX-a(document).scrollLeft()<g.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()-g.scrollSpeed)}else{if(a(window).width()-(f.pageX-a(document).scrollLeft())<g.scrollSensitivity){b=a(document).scrollLeft(a(document).scrollLeft()+g.scrollSpeed)}}}if(b!==false&&a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,f)}}this.positionAbs=this._convertPositionTo(\"absolute\");if(!this.options.axis||this.options.axis!=\"y\"){this.helper[0].style.left=this.position.left+\"px\"}if(!this.options.axis||this.options.axis!=\"x\"){this.helper[0].style.top=this.position.top+\"px\"}for(var d=this.items.length-1;d>=0;d--){var e=this.items[d],c=e.item[0],h=this._intersectsWithPointer(e);if(!h){continue}if(c!=this.currentItem[0]&&this.placeholder[h==1?\"next\":\"prev\"]()[0]!=c&&!a.ui.contains(this.placeholder[0],c)&&(this.options.type==\"semi-dynamic\"?!a.ui.contains(this.element[0],c):true)){this.direction=h==1?\"down\":\"up\";if(this.options.tolerance==\"pointer\"||this._intersectsWithSides(e)){this._rearrange(f,e)}else{break}this._trigger(\"change\",f,this._uiHash());break}}this._contactContainers(f);if(a.ui.ddmanager){a.ui.ddmanager.drag(this,f)}this._trigger(\"sort\",f,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(c,d){if(!c){return}if(a.ui.ddmanager&&!this.options.dropBehaviour){a.ui.ddmanager.drop(this,c)}if(this.options.revert){var b=this;var e=b.placeholder.offset();b.reverting=true;a(this.helper).animate({left:e.left-this.offset.parent.left-b.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-b.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){b._clear(c)})}else{this._clear(c,d)}return false},cancel:function(){var b=this;if(this.dragging){this._mouseUp();if(this.options.helper==\"original\"){this.currentItem.css(this._storedCSS).removeClass(\"ui-sortable-helper\")}else{this.currentItem.show()}for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger(\"deactivate\",null,b._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger(\"out\",null,b._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder[0].parentNode){this.placeholder[0].parentNode.removeChild(this.placeholder[0])}if(this.options.helper!=\"original\"&&this.helper&&this.helper[0].parentNode){this.helper.remove()}a.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){a(this.domPosition.prev).after(this.currentItem)}else{a(this.domPosition.parent).prepend(this.currentItem)}return true},serialize:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};a(b).each(function(){var e=(a(d.item||this).attr(d.attribute||\"id\")||\"\").match(d.expression||(/(.+)[-=_](.+)/));if(e){c.push((d.key||e[1]+\"[]\")+\"=\"+(d.key&&d.expression?e[1]:e[2]))}});return c.join(\"&\")},toArray:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};b.each(function(){c.push(a(d.item||this).attr(d.attribute||\"id\")||\"\")});return c},_intersectsWith:function(m){var e=this.positionAbs.left,d=e+this.helperProportions.width,k=this.positionAbs.top,j=k+this.helperProportions.height;var f=m.left,c=f+m.width,n=m.top,i=n+m.height;var o=this.offset.click.top,h=this.offset.click.left;var g=(k+o)>n&&(k+o)<i&&(e+h)>f&&(e+h)<c;if(this.options.tolerance==\"pointer\"||this.options.forcePointerForContainers||(this.options.tolerance!=\"pointer\"&&this.helperProportions[this.floating?\"width\":\"height\"]>m[this.floating?\"width\":\"height\"])){return g}else{return(f<e+(this.helperProportions.width/2)&&d-(this.helperProportions.width/2)<c&&n<k+(this.helperProportions.height/2)&&j-(this.helperProportions.height/2)<i)}},_intersectsWithPointer:function(d){var e=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,d.top,d.height),c=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,d.left,d.width),g=e&&c,b=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();if(!g){return false}return this.floating?(((f&&f==\"right\")||b==\"down\")?2:1):(b&&(b==\"down\"?2:1))},_intersectsWithSides:function(e){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+(e.height/2),e.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+(e.width/2),e.width),b=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();if(this.floating&&f){return((f==\"right\"&&d)||(f==\"left\"&&!d))}else{return b&&((b==\"down\"&&c)||(b==\"up\"&&!c))}},_getDragVerticalDirection:function(){var b=this.positionAbs.top-this.lastPositionAbs.top;return b!=0&&(b>0?\"down\":\"up\")},_getDragHorizontalDirection:function(){var b=this.positionAbs.left-this.lastPositionAbs.left;return b!=0&&(b>0?\"right\":\"left\")},refresh:function(b){this._refreshItems(b);this.refreshPositions()},_connectWith:function(){var b=this.options;return b.connectWith.constructor==String?[b.connectWith]:b.connectWith},_getItemsAsjQuery:function(b){var l=this;var g=[];var e=[];var h=this._connectWith();if(h&&b){for(var d=h.length-1;d>=0;d--){var k=a(h[d]);for(var c=k.length-1;c>=0;c--){var f=a.data(k[c],\"sortable\");if(f&&f!=this&&!f.options.disabled){e.push([a.isFunction(f.options.items)?f.options.items.call(f.element):a(f.options.items,f.element).not(\".ui-sortable-helper\"),f])}}}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(\".ui-sortable-helper\"),this]);for(var d=e.length-1;d>=0;d--){e[d][0].each(function(){g.push(this)})}return a(g)},_removeCurrentsFromItems:function(){var d=this.currentItem.find(\":data(sortable-item)\");for(var c=0;c<this.items.length;c++){for(var b=0;b<d.length;b++){if(d[b]==this.items[c].item[0]){this.items.splice(c,1)}}}},_refreshItems:function(b){this.items=[];this.containers=[this];var h=this.items;var p=this;var f=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]];var l=this._connectWith();if(l){for(var e=l.length-1;e>=0;e--){var m=a(l[e]);for(var d=m.length-1;d>=0;d--){var g=a.data(m[d],\"sortable\");if(g&&g!=this&&!g.options.disabled){f.push([a.isFunction(g.options.items)?g.options.items.call(g.element[0],b,{item:this.currentItem}):a(g.options.items,g.element),g]);this.containers.push(g)}}}}for(var e=f.length-1;e>=0;e--){var k=f[e][1];var c=f[e][0];for(var d=0,n=c.length;d<n;d++){var o=a(c[d]);o.data(\"sortable-item\",k);h.push({item:o,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){if(this.offsetParent&&this.helper){this.offset.parent=this._getParentOffset()}for(var d=this.items.length-1;d>=0;d--){var e=this.items[d];if(e.instance!=this.currentContainer&&this.currentContainer&&e.item[0]!=this.currentItem[0]){continue}var c=this.options.toleranceElement?a(this.options.toleranceElement,e.item):e.item;if(!b){e.width=c.outerWidth();e.height=c.outerHeight()}var f=c.offset();e.left=f.left;e.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this)}else{for(var d=this.containers.length-1;d>=0;d--){var f=this.containers[d].element.offset();this.containers[d].containerCache.left=f.left;this.containers[d].containerCache.top=f.top;this.containers[d].containerCache.width=this.containers[d].element.outerWidth();this.containers[d].containerCache.height=this.containers[d].element.outerHeight()}}},_createPlaceholder:function(d){var b=d||this,e=b.options;if(!e.placeholder||e.placeholder.constructor==String){var c=e.placeholder;e.placeholder={element:function(){var f=a(document.createElement(b.currentItem[0].nodeName)).addClass(c||b.currentItem[0].className+\" ui-sortable-placeholder\").removeClass(\"ui-sortable-helper\")[0];if(!c){f.style.visibility=\"hidden\"}return f},update:function(f,g){if(c&&!e.forcePlaceholderSize){return}if(!g.height()){g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css(\"paddingTop\")||0,10)-parseInt(b.currentItem.css(\"paddingBottom\")||0,10))}if(!g.width()){g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css(\"paddingLeft\")||0,10)-parseInt(b.currentItem.css(\"paddingRight\")||0,10))}}}}b.placeholder=a(e.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);e.placeholder.update(b,b.placeholder)},_contactContainers:function(d){for(var c=this.containers.length-1;c>=0;c--){if(this._intersectsWith(this.containers[c].containerCache)){if(!this.containers[c].containerCache.over){if(this.currentContainer!=this.containers[c]){var h=10000;var g=null;var e=this.positionAbs[this.containers[c].floating?\"left\":\"top\"];for(var b=this.items.length-1;b>=0;b--){if(!a.ui.contains(this.containers[c].element[0],this.items[b].item[0])){continue}var f=this.items[b][this.containers[c].floating?\"left\":\"top\"];if(Math.abs(f-e)<h){h=Math.abs(f-e);g=this.items[b]}}if(!g&&!this.options.dropOnEmpty){continue}this.currentContainer=this.containers[c];g?this._rearrange(d,g,null,true):this._rearrange(d,null,this.containers[c].element,true);this._trigger(\"change\",d,this._uiHash());this.containers[c]._trigger(\"change\",d,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder)}this.containers[c]._trigger(\"over\",d,this._uiHash(this));this.containers[c].containerCache.over=1}}else{if(this.containers[c].containerCache.over){this.containers[c]._trigger(\"out\",d,this._uiHash(this));this.containers[c].containerCache.over=0}}}},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c,this.currentItem])):(d.helper==\"clone\"?this.currentItem.clone():this.currentItem);if(!b.parents(\"body\").length){a(d.appendTo!=\"parent\"?d.appendTo:this.currentItem[0].parentNode)[0].appendChild(b[0])}if(b[0]==this.currentItem[0]){this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css(\"position\"),top:this.currentItem.css(\"top\"),left:this.currentItem.css(\"left\")}}if(b[0].style.width==\"\"||d.forceHelperSize){b.width(this.currentItem.width())}if(b[0].style.height==\"\"||d.forceHelperSize){b.height(this.currentItem.height())}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition==\"absolute\"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()==\"html\"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css(\"borderTopWidth\"),10)||0),left:b.left+(parseInt(this.offsetParent.css(\"borderLeftWidth\"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition==\"relative\"){var b=this.currentItem.position();return{top:b.top-(parseInt(this.helper.css(\"top\"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css(\"left\"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.currentItem.css(\"marginLeft\"),10)||0),top:(parseInt(this.currentItem.css(\"marginTop\"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment==\"parent\"){e.containment=this.helper[0].parentNode}if(e.containment==\"document\"||e.containment==\"window\"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment==\"document\"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment==\"document\"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)){var c=a(e.containment)[0];var d=a(e.containment).offset();var b=(a(c).css(\"overflow\")!=\"hidden\");this.containment=[d.left+(parseInt(a(c).css(\"borderLeftWidth\"),10)||0)+(parseInt(a(c).css(\"paddingLeft\"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css(\"borderTopWidth\"),10)||0)+(parseInt(a(c).css(\"paddingTop\"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css(\"borderLeftWidth\"),10)||0)-(parseInt(a(c).css(\"paddingRight\"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css(\"borderTopWidth\"),10)||0)-(parseInt(a(c).css(\"paddingBottom\"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f==\"absolute\"?1:-1;var e=this.options,b=this.cssPosition==\"absolute\"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition==\"absolute\"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition==\"relative\"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.left<this.containment[0]){d=this.containment[0]+this.offset.click.left}if(e.pageY-this.offset.click.top<this.containment[1]){c=this.containment[1]+this.offset.click.top}if(e.pageX-this.offset.click.left>this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:(!(g-this.offset.click.top<this.containment[1])?g-h.grid[1]:g+h.grid[1])):g;var f=this.originalPageX+Math.round((d-this.originalPageX)/h.grid[0])*h.grid[0];d=this.containment?(!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:(!(f-this.offset.click.left<this.containment[0])?f-h.grid[0]:f+h.grid[0])):f}}return{top:(c-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollTop():(i?0:b.scrollTop())))),left:(d-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition==\"fixed\"?0:(this.cssPosition==\"fixed\"?-this.scrollParent.scrollLeft():i?0:b.scrollLeft())))}},_rearrange:function(g,f,c,e){c?c[0].appendChild(this.placeholder[0]):f.item[0].parentNode.insertBefore(this.placeholder[0],(this.direction==\"down\"?f.item[0]:f.item[0].nextSibling));this.counter=this.counter?++this.counter:1;var d=this,b=this.counter;window.setTimeout(function(){if(b==d.counter){d.refreshPositions(!e)}},0)},_clear:function(d,e){this.reverting=false;var f=[],b=this;if(!this._noFinalSort&&this.currentItem[0].parentNode){this.placeholder.before(this.currentItem)}this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var c in this._storedCSS){if(this._storedCSS[c]==\"auto\"||this._storedCSS[c]==\"static\"){this._storedCSS[c]=\"\"}}this.currentItem.css(this._storedCSS).removeClass(\"ui-sortable-helper\")}else{this.currentItem.show()}if(this.fromOutside&&!e){f.push(function(g){this._trigger(\"receive\",g,this._uiHash(this.fromOutside))})}if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(\".ui-sortable-helper\")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!e){f.push(function(g){this._trigger(\"update\",g,this._uiHash())})}if(!a.ui.contains(this.element[0],this.currentItem[0])){if(!e){f.push(function(g){this._trigger(\"remove\",g,this._uiHash())})}for(var c=this.containers.length-1;c>=0;c--){if(a.ui.contains(this.containers[c].element[0],this.currentItem[0])&&!e){f.push((function(g){return function(h){g._trigger(\"receive\",h,this._uiHash(this))}}).call(this,this.containers[c]));f.push((function(g){return function(h){g._trigger(\"update\",h,this._uiHash(this))}}).call(this,this.containers[c]))}}}for(var c=this.containers.length-1;c>=0;c--){if(!e){f.push((function(g){return function(h){g._trigger(\"deactivate\",h,this._uiHash(this))}}).call(this,this.containers[c]))}if(this.containers[c].containerCache.over){f.push((function(g){return function(h){g._trigger(\"out\",h,this._uiHash(this))}}).call(this,this.containers[c]));this.containers[c].containerCache.over=0}}if(this._storedCursor){a(\"body\").css(\"cursor\",this._storedCursor)}if(this._storedOpacity){this.helper.css(\"opacity\",this._storedOpacity)}if(this._storedZIndex){this.helper.css(\"zIndex\",this._storedZIndex==\"auto\"?\"\":this._storedZIndex)}this.dragging=false;if(this.cancelHelperRemoval){if(!e){this._trigger(\"beforeStop\",d,this._uiHash());for(var c=0;c<f.length;c++){f[c].call(this,d)}this._trigger(\"stop\",d,this._uiHash())}return false}if(!e){this._trigger(\"beforeStop\",d,this._uiHash())}this.placeholder[0].parentNode.removeChild(this.placeholder[0]);if(this.helper[0]!=this.currentItem[0]){this.helper.remove()}this.helper=null;if(!e){for(var c=0;c<f.length;c++){f[c].call(this,d)}this._trigger(\"stop\",d,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){if(a.widget.prototype._trigger.apply(this,arguments)===false){this.cancel()}},_uiHash:function(c){var b=c||this;return{helper:b.helper,placeholder:b.placeholder||a([]),position:b.position,absolutePosition:b.positionAbs,offset:b.positionAbs,item:b.currentItem,sender:c?c.element:null}}}));a.extend(a.ui.sortable,{getter:\"serialize toArray\",version:\"1.7.2\",eventPrefix:\"sort\",defaults:{appendTo:\"parent\",axis:false,cancel:\":input,option\",connectWith:false,containment:false,cursor:\"auto\",cursorAt:false,delay:0,distance:1,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:\"original\",items:\"> *\",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:\"default\",tolerance:\"intersect\",zIndex:1000}})})(jQuery);;/*\n * jQuery UI Effects 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/\n */\njQuery.effects||(function(d){d.effects={version:\"1.7.2\",save:function(g,h){for(var f=0;f<h.length;f++){if(h[f]!==null){g.data(\"ec.storage.\"+h[f],g[0].style[h[f]])}}},restore:function(g,h){for(var f=0;f<h.length;f++){if(h[f]!==null){g.css(h[f],g.data(\"ec.storage.\"+h[f]))}}},setMode:function(f,g){if(g==\"toggle\"){g=f.is(\":hidden\")?\"show\":\"hide\"}return g},getBaseline:function(g,h){var i,f;switch(g[0]){case\"top\":i=0;break;case\"middle\":i=0.5;break;case\"bottom\":i=1;break;default:i=g[0]/h.height}switch(g[1]){case\"left\":f=0;break;case\"center\":f=0.5;break;case\"right\":f=1;break;default:f=g[1]/h.width}return{x:f,y:i}},createWrapper:function(f){if(f.parent().is(\".ui-effects-wrapper\")){return f.parent()}var g={width:f.outerWidth(true),height:f.outerHeight(true),\"float\":f.css(\"float\")};f.wrap('<div class=\"ui-effects-wrapper\" style=\"font-size:100%;background:transparent;border:none;margin:0;padding:0\"></div>');var j=f.parent();if(f.css(\"position\")==\"static\"){j.css({position:\"relative\"});f.css({position:\"relative\"})}else{var i=f.css(\"top\");if(isNaN(parseInt(i,10))){i=\"auto\"}var h=f.css(\"left\");if(isNaN(parseInt(h,10))){h=\"auto\"}j.css({position:f.css(\"position\"),top:i,left:h,zIndex:f.css(\"z-index\")}).show();f.css({position:\"relative\",top:0,left:0})}j.css(g);return j},removeWrapper:function(f){if(f.parent().is(\".ui-effects-wrapper\")){return f.parent().replaceWith(f)}return f},setTransition:function(g,i,f,h){h=h||{};d.each(i,function(k,j){unit=g.cssUnit(j);if(unit[0]>0){h[j]=unit[0]*f+unit[1]}});return h},animateClass:function(h,i,k,j){var f=(typeof k==\"function\"?k:(j?j:null));var g=(typeof k==\"string\"?k:null);return this.each(function(){var q={};var o=d(this);var p=o.attr(\"style\")||\"\";if(typeof p==\"object\"){p=p.cssText}if(h.toggle){o.hasClass(h.toggle)?h.remove=h.toggle:h.add=h.toggle}var l=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.addClass(h.add)}if(h.remove){o.removeClass(h.remove)}var m=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.removeClass(h.add)}if(h.remove){o.addClass(h.remove)}for(var r in m){if(typeof m[r]!=\"function\"&&m[r]&&r.indexOf(\"Moz\")==-1&&r.indexOf(\"length\")==-1&&m[r]!=l[r]&&(r.match(/color/i)||(!r.match(/color/i)&&!isNaN(parseInt(m[r],10))))&&(l.position!=\"static\"||(l.position==\"static\"&&!r.match(/left|top|bottom|right/)))){q[r]=m[r]}}o.animate(q,i,g,function(){if(typeof d(this).attr(\"style\")==\"object\"){d(this).attr(\"style\")[\"cssText\"]=\"\";d(this).attr(\"style\")[\"cssText\"]=p}else{d(this).attr(\"style\",p)}if(h.add){d(this).addClass(h.add)}if(h.remove){d(this).removeClass(h.remove)}if(f){f.apply(this,arguments)}})})}};function c(g,f){var i=g[1]&&g[1].constructor==Object?g[1]:{};if(f){i.mode=f}var h=g[1]&&g[1].constructor!=Object?g[1]:(i.duration?i.duration:g[2]);h=d.fx.off?0:typeof h===\"number\"?h:d.fx.speeds[h]||d.fx.speeds._default;var j=i.callback||(d.isFunction(g[1])&&g[1])||(d.isFunction(g[2])&&g[2])||(d.isFunction(g[3])&&g[3]);return[g[0],i,h,j]}d.fn.extend({_show:d.fn.show,_hide:d.fn.hide,__toggle:d.fn.toggle,_addClass:d.fn.addClass,_removeClass:d.fn.removeClass,_toggleClass:d.fn.toggleClass,effect:function(g,f,h,i){return d.effects[g]?d.effects[g].call(this,{method:g,options:f||{},duration:h,callback:i}):null},show:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._show.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,\"show\"))}},hide:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._hide.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,\"hide\"))}},toggle:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))||(d.isFunction(arguments[0])||typeof arguments[0]==\"boolean\")){return this.__toggle.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,\"toggle\"))}},addClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{add:g},f,i,h]):this._addClass(g)},removeClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{remove:g},f,i,h]):this._removeClass(g)},toggleClass:function(g,f,i,h){return((typeof f!==\"boolean\")&&f)?d.effects.animateClass.apply(this,[{toggle:g},f,i,h]):this._toggleClass(g,f)},morph:function(f,h,g,j,i){return d.effects.animateClass.apply(this,[{add:h,remove:f},g,j,i])},switchClass:function(){return this.morph.apply(this,arguments)},cssUnit:function(f){var g=this.css(f),h=[];d.each([\"em\",\"px\",\"%\",\"pt\"],function(j,k){if(g.indexOf(k)>0){h=[parseFloat(g),k]}});return h}});d.each([\"backgroundColor\",\"borderBottomColor\",\"borderLeftColor\",\"borderRightColor\",\"borderTopColor\",\"color\",\"outlineColor\"],function(g,f){d.fx.step[f]=function(h){if(h.state==0){h.start=e(h.elem,f);h.end=b(h.end)}h.elem.style[f]=\"rgb(\"+[Math.max(Math.min(parseInt((h.pos*(h.end[0]-h.start[0]))+h.start[0],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[1]-h.start[1]))+h.start[1],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[2]-h.start[2]))+h.start[2],10),255),0)].join(\",\")+\")\"}});function b(g){var f;if(g&&g.constructor==Array&&g.length==3){return g}if(f=/rgb\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*\\)/.exec(g)){return[parseInt(f[1],10),parseInt(f[2],10),parseInt(f[3],10)]}if(f=/rgb\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*\\)/.exec(g)){return[parseFloat(f[1])*2.55,parseFloat(f[2])*2.55,parseFloat(f[3])*2.55]}if(f=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(g)){return[parseInt(f[1],16),parseInt(f[2],16),parseInt(f[3],16)]}if(f=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(g)){return[parseInt(f[1]+f[1],16),parseInt(f[2]+f[2],16),parseInt(f[3]+f[3],16)]}if(f=/rgba\\(0, 0, 0, 0\\)/.exec(g)){return a.transparent}return a[d.trim(g).toLowerCase()]}function e(h,f){var g;do{g=d.curCSS(h,f);if(g!=\"\"&&g!=\"transparent\"||d.nodeName(h,\"body\")){break}f=\"backgroundColor\"}while(h=h.parentNode);return b(g)}var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]};d.easing.jswing=d.easing.swing;d.extend(d.easing,{def:\"easeOutQuad\",swing:function(g,h,f,j,i){return d.easing[d.easing.def](g,h,f,j,i)},easeInQuad:function(g,h,f,j,i){return j*(h/=i)*h+f},easeOutQuad:function(g,h,f,j,i){return -j*(h/=i)*(h-2)+f},easeInOutQuad:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h+f}return -j/2*((--h)*(h-2)-1)+f},easeInCubic:function(g,h,f,j,i){return j*(h/=i)*h*h+f},easeOutCubic:function(g,h,f,j,i){return j*((h=h/i-1)*h*h+1)+f},easeInOutCubic:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h+f}return j/2*((h-=2)*h*h+2)+f},easeInQuart:function(g,h,f,j,i){return j*(h/=i)*h*h*h+f},easeOutQuart:function(g,h,f,j,i){return -j*((h=h/i-1)*h*h*h-1)+f},easeInOutQuart:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h+f}return -j/2*((h-=2)*h*h*h-2)+f},easeInQuint:function(g,h,f,j,i){return j*(h/=i)*h*h*h*h+f},easeOutQuint:function(g,h,f,j,i){return j*((h=h/i-1)*h*h*h*h+1)+f},easeInOutQuint:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h*h+f}return j/2*((h-=2)*h*h*h*h+2)+f},easeInSine:function(g,h,f,j,i){return -j*Math.cos(h/i*(Math.PI/2))+j+f},easeOutSine:function(g,h,f,j,i){return j*Math.sin(h/i*(Math.PI/2))+f},easeInOutSine:function(g,h,f,j,i){return -j/2*(Math.cos(Math.PI*h/i)-1)+f},easeInExpo:function(g,h,f,j,i){return(h==0)?f:j*Math.pow(2,10*(h/i-1))+f},easeOutExpo:function(g,h,f,j,i){return(h==i)?f+j:j*(-Math.pow(2,-10*h/i)+1)+f},easeInOutExpo:function(g,h,f,j,i){if(h==0){return f}if(h==i){return f+j}if((h/=i/2)<1){return j/2*Math.pow(2,10*(h-1))+f}return j/2*(-Math.pow(2,-10*--h)+2)+f},easeInCirc:function(g,h,f,j,i){return -j*(Math.sqrt(1-(h/=i)*h)-1)+f},easeOutCirc:function(g,h,f,j,i){return j*Math.sqrt(1-(h=h/i-1)*h)+f},easeInOutCirc:function(g,h,f,j,i){if((h/=i/2)<1){return -j/2*(Math.sqrt(1-h*h)-1)+f}return j/2*(Math.sqrt(1-(h-=2)*h)+1)+f},easeInElastic:function(g,i,f,m,l){var j=1.70158;var k=0;var h=m;if(i==0){return f}if((i/=l)==1){return f+m}if(!k){k=l*0.3}if(h<Math.abs(m)){h=m;var j=k/4}else{var j=k/(2*Math.PI)*Math.asin(m/h)}return -(h*Math.pow(2,10*(i-=1))*Math.sin((i*l-j)*(2*Math.PI)/k))+f},easeOutElastic:function(g,i,f,m,l){var j=1.70158;var k=0;var h=m;if(i==0){return f}if((i/=l)==1){return f+m}if(!k){k=l*0.3}if(h<Math.abs(m)){h=m;var j=k/4}else{var j=k/(2*Math.PI)*Math.asin(m/h)}return h*Math.pow(2,-10*i)*Math.sin((i*l-j)*(2*Math.PI)/k)+m+f},easeInOutElastic:function(g,i,f,m,l){var j=1.70158;var k=0;var h=m;if(i==0){return f}if((i/=l/2)==2){return f+m}if(!k){k=l*(0.3*1.5)}if(h<Math.abs(m)){h=m;var j=k/4}else{var j=k/(2*Math.PI)*Math.asin(m/h)}if(i<1){return -0.5*(h*Math.pow(2,10*(i-=1))*Math.sin((i*l-j)*(2*Math.PI)/k))+f}return h*Math.pow(2,-10*(i-=1))*Math.sin((i*l-j)*(2*Math.PI)/k)*0.5+m+f},easeInBack:function(g,h,f,k,j,i){if(i==undefined){i=1.70158}return k*(h/=j)*h*((i+1)*h-i)+f},easeOutBack:function(g,h,f,k,j,i){if(i==undefined){i=1.70158}return k*((h=h/j-1)*h*((i+1)*h+i)+1)+f},easeInOutBack:function(g,h,f,k,j,i){if(i==undefined){i=1.70158}if((h/=j/2)<1){return k/2*(h*h*(((i*=(1.525))+1)*h-i))+f}return k/2*((h-=2)*h*(((i*=(1.525))+1)*h+i)+2)+f},easeInBounce:function(g,h,f,j,i){return j-d.easing.easeOutBounce(g,i-h,0,j,i)+f},easeOutBounce:function(g,h,f,j,i){if((h/=i)<(1/2.75)){return j*(7.5625*h*h)+f}else{if(h<(2/2.75)){return j*(7.5625*(h-=(1.5/2.75))*h+0.75)+f}else{if(h<(2.5/2.75)){return j*(7.5625*(h-=(2.25/2.75))*h+0.9375)+f}else{return j*(7.5625*(h-=(2.625/2.75))*h+0.984375)+f}}}},easeInOutBounce:function(g,h,f,j,i){if(h<i/2){return d.easing.easeInBounce(g,h*2,0,j,i)*0.5+f}return d.easing.easeOutBounce(g,h*2-i,0,j,i)*0.5+j*0.5+f}})})(jQuery);;/*\n * jQuery UI Effects Blind 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/Blind\n *\n * Depends:\n *\teffects.core.js\n */\n(function(a){a.effects.blind=function(b){return this.queue(function(){var d=a(this),c=[\"position\",\"top\",\"left\"];var h=a.effects.setMode(d,b.options.mode||\"hide\");var g=b.options.direction||\"vertical\";a.effects.save(d,c);d.show();var j=a.effects.createWrapper(d).css({overflow:\"hidden\"});var e=(g==\"vertical\")?\"height\":\"width\";var i=(g==\"vertical\")?j.height():j.width();if(h==\"show\"){j.css(e,0)}var f={};f[e]=h==\"show\"?i:0;j.animate(f,b.duration,b.options.easing,function(){if(h==\"hide\"){d.hide()}a.effects.restore(d,c);a.effects.removeWrapper(d);if(b.callback){b.callback.apply(d[0],arguments)}d.dequeue()})})}})(jQuery);;/*\n * jQuery UI Effects Bounce 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/Bounce\n *\n * Depends:\n *\teffects.core.js\n */\n(function(a){a.effects.bounce=function(b){return this.queue(function(){var e=a(this),l=[\"position\",\"top\",\"left\"];var k=a.effects.setMode(e,b.options.mode||\"effect\");var n=b.options.direction||\"up\";var c=b.options.distance||20;var d=b.options.times||5;var g=b.duration||250;if(/show|hide/.test(k)){l.push(\"opacity\")}a.effects.save(e,l);e.show();a.effects.createWrapper(e);var f=(n==\"up\"||n==\"down\")?\"top\":\"left\";var p=(n==\"up\"||n==\"left\")?\"pos\":\"neg\";var c=b.options.distance||(f==\"top\"?e.outerHeight({margin:true})/3:e.outerWidth({margin:true})/3);if(k==\"show\"){e.css(\"opacity\",0).css(f,p==\"pos\"?-c:c)}if(k==\"hide\"){c=c/(d*2)}if(k!=\"hide\"){d--}if(k==\"show\"){var h={opacity:1};h[f]=(p==\"pos\"?\"+=\":\"-=\")+c;e.animate(h,g/2,b.options.easing);c=c/2;d--}for(var j=0;j<d;j++){var o={},m={};o[f]=(p==\"pos\"?\"-=\":\"+=\")+c;m[f]=(p==\"pos\"?\"+=\":\"-=\")+c;e.animate(o,g/2,b.options.easing).animate(m,g/2,b.options.easing);c=(k==\"hide\")?c*2:c/2}if(k==\"hide\"){var h={opacity:0};h[f]=(p==\"pos\"?\"-=\":\"+=\")+c;e.animate(h,g/2,b.options.easing,function(){e.hide();a.effects.restore(e,l);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}})}else{var o={},m={};o[f]=(p==\"pos\"?\"-=\":\"+=\")+c;m[f]=(p==\"pos\"?\"+=\":\"-=\")+c;e.animate(o,g/2,b.options.easing).animate(m,g/2,b.options.easing,function(){a.effects.restore(e,l);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}})}e.queue(\"fx\",function(){e.dequeue()});e.dequeue()})}})(jQuery);;/*\n * jQuery UI Effects Clip 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/Clip\n *\n * Depends:\n *\teffects.core.js\n */\n(function(a){a.effects.clip=function(b){return this.queue(function(){var f=a(this),j=[\"position\",\"top\",\"left\",\"height\",\"width\"];var i=a.effects.setMode(f,b.options.mode||\"hide\");var k=b.options.direction||\"vertical\";a.effects.save(f,j);f.show();var c=a.effects.createWrapper(f).css({overflow:\"hidden\"});var e=f[0].tagName==\"IMG\"?c:f;var g={size:(k==\"vertical\")?\"height\":\"width\",position:(k==\"vertical\")?\"top\":\"left\"};var d=(k==\"vertical\")?e.height():e.width();if(i==\"show\"){e.css(g.size,0);e.css(g.position,d/2)}var h={};h[g.size]=i==\"show\"?d:0;h[g.position]=i==\"show\"?0:d/2;e.animate(h,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(i==\"hide\"){f.hide()}a.effects.restore(f,j);a.effects.removeWrapper(f);if(b.callback){b.callback.apply(f[0],arguments)}f.dequeue()}})})}})(jQuery);;/*\n * jQuery UI Effects Drop 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/Drop\n *\n * Depends:\n *\teffects.core.js\n */\n(function(a){a.effects.drop=function(b){return this.queue(function(){var e=a(this),d=[\"position\",\"top\",\"left\",\"opacity\"];var i=a.effects.setMode(e,b.options.mode||\"hide\");var h=b.options.direction||\"left\";a.effects.save(e,d);e.show();a.effects.createWrapper(e);var f=(h==\"up\"||h==\"down\")?\"top\":\"left\";var c=(h==\"up\"||h==\"left\")?\"pos\":\"neg\";var j=b.options.distance||(f==\"top\"?e.outerHeight({margin:true})/2:e.outerWidth({margin:true})/2);if(i==\"show\"){e.css(\"opacity\",0).css(f,c==\"pos\"?-j:j)}var g={opacity:i==\"show\"?1:0};g[f]=(i==\"show\"?(c==\"pos\"?\"+=\":\"-=\"):(c==\"pos\"?\"-=\":\"+=\"))+j;e.animate(g,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(i==\"hide\"){e.hide()}a.effects.restore(e,d);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}e.dequeue()}})})}})(jQuery);;/*\n * jQuery UI Effects Fold 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/Fold\n *\n * Depends:\n *\teffects.core.js\n */\n(function(a){a.effects.fold=function(b){return this.queue(function(){var e=a(this),k=[\"position\",\"top\",\"left\"];var h=a.effects.setMode(e,b.options.mode||\"hide\");var o=b.options.size||15;var n=!(!b.options.horizFirst);var g=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(e,k);e.show();var d=a.effects.createWrapper(e).css({overflow:\"hidden\"});var i=((h==\"show\")!=n);var f=i?[\"width\",\"height\"]:[\"height\",\"width\"];var c=i?[d.width(),d.height()]:[d.height(),d.width()];var j=/([0-9]+)%/.exec(o);if(j){o=parseInt(j[1],10)/100*c[h==\"hide\"?0:1]}if(h==\"show\"){d.css(n?{height:0,width:o}:{height:o,width:0})}var m={},l={};m[f[0]]=h==\"show\"?c[0]:o;l[f[1]]=h==\"show\"?c[1]:0;d.animate(m,g,b.options.easing).animate(l,g,b.options.easing,function(){if(h==\"hide\"){e.hide()}a.effects.restore(e,k);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(e[0],arguments)}e.dequeue()})})}})(jQuery);;/*\n * jQuery UI Effects Highlight 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/Highlight\n *\n * Depends:\n *\teffects.core.js\n */\n(function(a){a.effects.highlight=function(b){return this.queue(function(){var e=a(this),d=[\"backgroundImage\",\"backgroundColor\",\"opacity\"];var h=a.effects.setMode(e,b.options.mode||\"show\");var c=b.options.color||\"#ffff99\";var g=e.css(\"backgroundColor\");a.effects.save(e,d);e.show();e.css({backgroundImage:\"none\",backgroundColor:c});var f={backgroundColor:g};if(h==\"hide\"){f.opacity=0}e.animate(f,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(h==\"hide\"){e.hide()}a.effects.restore(e,d);if(h==\"show\"&&a.browser.msie){this.style.removeAttribute(\"filter\")}if(b.callback){b.callback.apply(this,arguments)}e.dequeue()}})})}})(jQuery);;/*\n * jQuery UI Effects Pulsate 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/Pulsate\n *\n * Depends:\n *\teffects.core.js\n */\n(function(a){a.effects.pulsate=function(b){return this.queue(function(){var d=a(this);var g=a.effects.setMode(d,b.options.mode||\"show\");var f=b.options.times||5;var e=b.duration?b.duration/2:a.fx.speeds._default/2;if(g==\"hide\"){f--}if(d.is(\":hidden\")){d.css(\"opacity\",0);d.show();d.animate({opacity:1},e,b.options.easing);f=f-2}for(var c=0;c<f;c++){d.animate({opacity:0},e,b.options.easing).animate({opacity:1},e,b.options.easing)}if(g==\"hide\"){d.animate({opacity:0},e,b.options.easing,function(){d.hide();if(b.callback){b.callback.apply(this,arguments)}})}else{d.animate({opacity:0},e,b.options.easing).animate({opacity:1},e,b.options.easing,function(){if(b.callback){b.callback.apply(this,arguments)}})}d.queue(\"fx\",function(){d.dequeue()});d.dequeue()})}})(jQuery);;/*\n * jQuery UI Effects Scale 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/Scale\n *\n * Depends:\n *\teffects.core.js\n */\n(function(a){a.effects.puff=function(b){return this.queue(function(){var f=a(this);var c=a.extend(true,{},b.options);var h=a.effects.setMode(f,b.options.mode||\"hide\");var g=parseInt(b.options.percent,10)||150;c.fade=true;var e={height:f.height(),width:f.width()};var d=g/100;f.from=(h==\"hide\")?e:{height:e.height*d,width:e.width*d};c.from=f.from;c.percent=(h==\"hide\")?g:100;c.mode=h;f.effect(\"scale\",c,b.duration,b.callback);f.dequeue()})};a.effects.scale=function(b){return this.queue(function(){var g=a(this);var d=a.extend(true,{},b.options);var j=a.effects.setMode(g,b.options.mode||\"effect\");var h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:(j==\"hide\"?0:100));var i=b.options.direction||\"both\";var c=b.options.origin;if(j!=\"effect\"){d.origin=c||[\"middle\",\"center\"];d.restore=true}var f={height:g.height(),width:g.width()};g.from=b.options.from||(j==\"show\"?{height:0,width:0}:f);var e={y:i!=\"horizontal\"?(h/100):1,x:i!=\"vertical\"?(h/100):1};g.to={height:f.height*e.y,width:f.width*e.x};if(b.options.fade){if(j==\"show\"){g.from.opacity=0;g.to.opacity=1}if(j==\"hide\"){g.from.opacity=1;g.to.opacity=0}}d.from=g.from;d.to=g.to;d.mode=j;g.effect(\"size\",d,b.duration,b.callback);g.dequeue()})};a.effects.size=function(b){return this.queue(function(){var c=a(this),n=[\"position\",\"top\",\"left\",\"width\",\"height\",\"overflow\",\"opacity\"];var m=[\"position\",\"top\",\"left\",\"overflow\",\"opacity\"];var j=[\"width\",\"height\",\"overflow\"];var p=[\"fontSize\"];var k=[\"borderTopWidth\",\"borderBottomWidth\",\"paddingTop\",\"paddingBottom\"];var f=[\"borderLeftWidth\",\"borderRightWidth\",\"paddingLeft\",\"paddingRight\"];var g=a.effects.setMode(c,b.options.mode||\"effect\");var i=b.options.restore||false;var e=b.options.scale||\"both\";var o=b.options.origin;var d={height:c.height(),width:c.width()};c.from=b.options.from||d;c.to=b.options.to||d;if(o){var h=a.effects.getBaseline(o,d);c.from.top=(d.height-c.from.height)*h.y;c.from.left=(d.width-c.from.width)*h.x;c.to.top=(d.height-c.to.height)*h.y;c.to.left=(d.width-c.to.width)*h.x}var l={from:{y:c.from.height/d.height,x:c.from.width/d.width},to:{y:c.to.height/d.height,x:c.to.width/d.width}};if(e==\"box\"||e==\"both\"){if(l.from.y!=l.to.y){n=n.concat(k);c.from=a.effects.setTransition(c,k,l.from.y,c.from);c.to=a.effects.setTransition(c,k,l.to.y,c.to)}if(l.from.x!=l.to.x){n=n.concat(f);c.from=a.effects.setTransition(c,f,l.from.x,c.from);c.to=a.effects.setTransition(c,f,l.to.x,c.to)}}if(e==\"content\"||e==\"both\"){if(l.from.y!=l.to.y){n=n.concat(p);c.from=a.effects.setTransition(c,p,l.from.y,c.from);c.to=a.effects.setTransition(c,p,l.to.y,c.to)}}a.effects.save(c,i?n:m);c.show();a.effects.createWrapper(c);c.css(\"overflow\",\"hidden\").css(c.from);if(e==\"content\"||e==\"both\"){k=k.concat([\"marginTop\",\"marginBottom\"]).concat(p);f=f.concat([\"marginLeft\",\"marginRight\"]);j=n.concat(k).concat(f);c.find(\"*[width]\").each(function(){child=a(this);if(i){a.effects.save(child,j)}var q={height:child.height(),width:child.width()};child.from={height:q.height*l.from.y,width:q.width*l.from.x};child.to={height:q.height*l.to.y,width:q.width*l.to.x};if(l.from.y!=l.to.y){child.from=a.effects.setTransition(child,k,l.from.y,child.from);child.to=a.effects.setTransition(child,k,l.to.y,child.to)}if(l.from.x!=l.to.x){child.from=a.effects.setTransition(child,f,l.from.x,child.from);child.to=a.effects.setTransition(child,f,l.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){if(i){a.effects.restore(child,j)}})})}c.animate(c.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(g==\"hide\"){c.hide()}a.effects.restore(c,i?n:m);a.effects.removeWrapper(c);if(b.callback){b.callback.apply(this,arguments)}c.dequeue()}})})}})(jQuery);;/*\n * jQuery UI Effects Shake 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/Shake\n *\n * Depends:\n *\teffects.core.js\n */\n(function(a){a.effects.shake=function(b){return this.queue(function(){var e=a(this),l=[\"position\",\"top\",\"left\"];var k=a.effects.setMode(e,b.options.mode||\"effect\");var n=b.options.direction||\"left\";var c=b.options.distance||20;var d=b.options.times||3;var g=b.duration||b.options.duration||140;a.effects.save(e,l);e.show();a.effects.createWrapper(e);var f=(n==\"up\"||n==\"down\")?\"top\":\"left\";var p=(n==\"up\"||n==\"left\")?\"pos\":\"neg\";var h={},o={},m={};h[f]=(p==\"pos\"?\"-=\":\"+=\")+c;o[f]=(p==\"pos\"?\"+=\":\"-=\")+c*2;m[f]=(p==\"pos\"?\"-=\":\"+=\")+c*2;e.animate(h,g,b.options.easing);for(var j=1;j<d;j++){e.animate(o,g,b.options.easing).animate(m,g,b.options.easing)}e.animate(o,g,b.options.easing).animate(h,g/2,b.options.easing,function(){a.effects.restore(e,l);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}});e.queue(\"fx\",function(){e.dequeue()});e.dequeue()})}})(jQuery);;/*\n * jQuery UI Effects Slide 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/Slide\n *\n * Depends:\n *\teffects.core.js\n */\n(function(a){a.effects.slide=function(b){return this.queue(function(){var e=a(this),d=[\"position\",\"top\",\"left\"];var i=a.effects.setMode(e,b.options.mode||\"show\");var h=b.options.direction||\"left\";a.effects.save(e,d);e.show();a.effects.createWrapper(e).css({overflow:\"hidden\"});var f=(h==\"up\"||h==\"down\")?\"top\":\"left\";var c=(h==\"up\"||h==\"left\")?\"pos\":\"neg\";var j=b.options.distance||(f==\"top\"?e.outerHeight({margin:true}):e.outerWidth({margin:true}));if(i==\"show\"){e.css(f,c==\"pos\"?-j:j)}var g={};g[f]=(i==\"show\"?(c==\"pos\"?\"+=\":\"-=\"):(c==\"pos\"?\"-=\":\"+=\"))+j;e.animate(g,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(i==\"hide\"){e.hide()}a.effects.restore(e,d);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(this,arguments)}e.dequeue()}})})}})(jQuery);;/*\n * jQuery UI Effects Transfer 1.7.2\n *\n * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n *\n * http://docs.jquery.com/UI/Effects/Transfer\n *\n * Depends:\n *\teffects.core.js\n */\n(function(a){a.effects.transfer=function(b){return this.queue(function(){var f=a(this),h=a(b.options.to),e=h.offset(),g={top:e.top,left:e.left,height:h.innerHeight(),width:h.innerWidth()},d=f.offset(),c=a('<div class=\"ui-effects-transfer\"></div>').appendTo(document.body).addClass(b.options.className).css({top:d.top,left:d.left,height:f.innerHeight(),width:f.innerWidth(),position:\"absolute\"}).animate(g,b.duration,b.options.easing,function(){c.remove();(b.callback&&b.callback.apply(f[0],arguments));f.dequeue()})})}})(jQuery);;"
  },
  {
    "path": "vendor/plugins/jrails/javascripts/jquery.js",
    "content": "/*!\n * jQuery JavaScript Library v1.4.4\n * http://jquery.com/\n *\n * Copyright 2010, John Resig\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n * Copyright 2010, The Dojo Foundation\n * Released under the MIT, BSD, and GPL Licenses.\n *\n * Date: Thu Nov 11 19:04:53 2010 -0500\n */\n(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute(\"data-\"+b);if(typeof d===\"string\"){try{d=d===\"true\"?true:d===\"false\"?false:d===\"null\"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?\"events\":\"__events__\");if(typeof h===\"function\")h=\nh.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type===\"click\")){if(a.namespace)A=RegExp(\"(^|\\\\.)\"+a.namespace.split(\".\").join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,\"\")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType===\"mouseenter\"||\nh.preType===\"mouseleave\"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!==\"*\"?a+\".\":\"\")+b.replace(La,\n\"`\").replace(Ma,\"&\")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b===\"string\"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,\ne);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:\"script\"}):c.globalEval(b.text||b.textContent||b.innerHTML||\"\");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b===\"width\"?a.offsetWidth:a.offsetHeight;if(d===\"border\")return e;c.each(b===\"width\"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,\"padding\"+this))||0);if(d===\"margin\")e+=parseFloat(c.css(a,\n\"margin\"+this))||0;else e-=parseFloat(c.css(a,\"border\"+this+\"Width\"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+\"[\"+(typeof h===\"object\"||c.isArray(h)?f:\"\")+\"]\",h,d,e)});else if(!d&&b!=null&&typeof b===\"object\")c.isEmptyObject(b)?e(a,\"\"):c.each(b,function(f,h){da(a+\"[\"+f+\"]\",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c(\"<\"+\na+\">\").appendTo(\"body\"),d=b.css(\"display\");b.remove();if(d===\"none\"||d===\"\")d=\"block\";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll(\"left\")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\\w\\W]+>)[^>]*$|#([\\w\\-]+)$)/,l=/\\S/,k=/^\\s+/,o=/\\s+$/,x=/\\W/,r=/\\d/,A=/^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,\nC=/^[\\],:{}\\s]*$/,J=/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g,I=/(?:^|:|,)(?:\\s*\\[)+/g,L=/(webkit)[ \\/]([\\w.]+)/,g=/(opera)(?:.*version)?[ \\/]([\\w.]+)/,i=/(msie) ([\\w.]+)/,n=/(mozilla)(?:.*? rv:([\\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j,\ns){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j===\"body\"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector=\"body\";this.length=1;return this}if(typeof j===\"string\")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,\nj)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:\"\",jquery:\"1.4.4\",length:0,size:function(){return this.length},\ntoArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s===\"find\")z.selector=this.selector+(this.selector?\" \":\"\")+v;else if(s)z.selector=this.selector+\".\"+s+\"(\"+v+\")\";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j===\n-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),\"slice\",N.call(arguments).join(\",\"))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false;\nif(typeof G===\"boolean\"){ga=G;G=arguments[1]||{};K=2}if(typeof G!==\"object\"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--;\nif(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger(\"ready\").unbind(\"ready\")}}},bindReady:function(){if(!p){p=true;if(t.readyState===\"complete\")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener(\"DOMContentLoaded\",u,false);E.addEventListener(\"load\",b.ready,false)}else if(t.attachEvent){t.attachEvent(\"onreadystatechange\",u);E.attachEvent(\"onload\",\nb.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)===\"function\"},isArray:Array.isArray||function(j){return b.type(j)===\"array\"},isWindow:function(j){return j&&typeof j===\"object\"&&\"setInterval\"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||\"object\"},isPlainObject:function(j){if(!j||b.type(j)!==\"object\"||j.nodeType||b.isWindow(j))return false;if(j.constructor&&\n!F.call(j,\"constructor\")&&!F.call(j.constructor.prototype,\"isPrototypeOf\"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!==\"string\"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,\"@\").replace(w,\"]\").replace(I,\"\")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function(\"return \"+j))();else b.error(\"Invalid JSON: \"+j)},noop:function(){},globalEval:function(j){if(j&&\nl.test(j)){var s=t.getElementsByTagName(\"head\")[0]||t.documentElement,v=t.createElement(\"script\");v.type=\"text/javascript\";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z],\nz,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?\"\":O.call(j)}:function(j){return j==null?\"\":j.toString().replace(k,\"\").replace(o,\"\")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z===\"string\"||z===\"function\"||z===\"regexp\"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j,\ns){var v=j.length,z=0;if(typeof s.length===\"number\")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s===\"string\"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v=\ns;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s===\"object\"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf(\"compatible\")<0&&n.exec(j)||\n[];return{browser:j[1]||\"\",version:j[2]||\"0\"}},browser:{}});b.each(\"Boolean Number String Function Array Date RegExp Object\".split(\" \"),function(j,s){R[\"[object \"+s+\"]\"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\\s/.test(\"\\u00a0\")){k=/^[\\s\\xA0]+/;o=/[\\s\\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener(\"DOMContentLoaded\",u,\nfalse);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState===\"complete\"){t.detachEvent(\"onreadystatechange\",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement(\"script\"),d=t.createElement(\"div\"),e=\"script\"+c.now();d.style.display=\"none\";d.innerHTML=\"   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>\";var f=d.getElementsByTagName(\"*\"),h=d.getElementsByTagName(\"a\")[0],l=t.createElement(\"select\"),\nk=l.appendChild(t.createElement(\"option\"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName(\"tbody\").length,htmlSerialize:!!d.getElementsByTagName(\"link\").length,style:/red/.test(h.getAttribute(\"style\")),hrefNormalized:h.getAttribute(\"href\")===\"/a\",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName(\"input\")[0].value===\"on\",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false,\nscriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type=\"text/javascript\";try{b.appendChild(t.createTextNode(\"window.\"+e+\"=1;\"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent(\"onclick\",function r(){c.support.noCloneEvent=\nfalse;d.detachEvent(\"onclick\",r)});d.cloneNode(true).fireEvent(\"onclick\")}d=t.createElement(\"div\");d.innerHTML=\"<input type='radio' name='radiotest' checked='checked'/>\";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement(\"div\");r.style.width=r.style.paddingLeft=\"1px\";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if(\"zoom\"in r.style){r.style.display=\"inline\";r.style.zoom=\n1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display=\"\";r.innerHTML=\"<div style='width:4px;'></div>\";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML=\"<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>\";var A=r.getElementsByTagName(\"td\");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display=\"\";A[1].style.display=\"none\";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML=\"\";t.body.removeChild(r).style.display=\n\"none\"});a=function(r){var A=t.createElement(\"div\");r=\"on\"+r;var C=r in A;if(!C){A.setAttribute(r,\"return;\");C=typeof A[r]===\"function\"}return C};c.support.submitBubbles=a(\"submit\");c.support.changeBubbles=a(\"change\");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\\{.*\\}|\\[.*\\])$/;c.extend({cache:{},uuid:0,expando:\"jQuery\"+c.now(),noData:{embed:true,object:\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h=\nc.cache;if(!(e&&!f&&typeof b===\"string\"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b===\"object\")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b===\"string\"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);\nelse if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute(\"classid\")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a===\"undefined\"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf(\"data-\")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a===\"object\")return this.each(function(){c.data(this,\na)});var k=a.split(\".\");k[1]=k[1]?\".\"+k[1]:\"\";if(b===B){d=this.triggerHandler(\"getData\"+k[1]+\"!\",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler(\"setData\"+k[1]+\"!\",x);c.data(this,a,b);o.triggerHandler(\"changeData\"+k[1]+\"!\",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||\"fx\")+\"queue\";var e=\nc.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||\"fx\";var d=c.queue(a,b),e=d.shift();if(e===\"inprogress\")e=d.shift();if(e){b===\"fx\"&&d.unshift(\"inprogress\");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!==\"string\"){b=a;a=\"fx\"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a===\"fx\"&&d[0]!==\"inprogress\"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,\na)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||\"fx\";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||\"fx\",[])}});var sa=/[\\n\\t]/g,ha=/\\s+/,Sa=/\\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={\"for\":\"htmlFor\",\"class\":\"className\",readonly:\"readOnly\",maxlength:\"maxLength\",cellspacing:\"cellSpacing\",rowspan:\"rowSpan\",\ncolspan:\"colSpan\",tabindex:\"tabIndex\",usemap:\"useMap\",frameborder:\"frameBorder\"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,\"\");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr(\"class\")))});if(a&&typeof a===\"string\")for(var b=(a||\"\").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===\n1)if(f.className){for(var h=\" \"+f.className+\" \",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(\" \"+b[k]+\" \")<0)l+=\" \"+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr(\"class\")))});if(a&&typeof a===\"string\"||a===B)for(var b=(a||\"\").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(\" \"+f.className+\" \").replace(sa,\" \"),\nl=0,k=b.length;l<k;l++)h=h.replace(\" \"+b[l]+\" \",\" \");f.className=c.trim(h)}else f.className=\"\"}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b===\"boolean\";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr(\"class\"),b),b)});return this.each(function(){if(d===\"string\")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?\"addClass\":\"removeClass\"](f)}else if(d===\"undefined\"||d===\"boolean\"){this.className&&c.data(this,\n\"__className__\",this.className);this.className=this.className||a===false?\"\":c.data(this,\"__className__\")||\"\"}})},hasClass:function(a){a=\" \"+a+\" \";for(var b=0,d=this.length;b<d;b++)if((\" \"+this[b].className+\" \").replace(sa,\" \").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,\"option\")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,\"select\")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type===\"select-one\";\nif(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute(\"disabled\")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,\"optgroup\"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute(\"value\")===null?\"on\":b.value;return(b.value||\"\").replace(Sa,\"\")}return B}var k=c.isFunction(a);return this.each(function(o){var x=c(this),r=a;if(this.nodeType===1){if(k)r=\na.call(this,o,x.val());if(r==null)r=\"\";else if(typeof r===\"number\")r+=\"\";else if(c.isArray(r))r=c.map(r,function(C){return C==null?\"\":C+\"\"});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,\"select\")){var A=c.makeArray(r);c(\"option\",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},\nattr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b===\"type\"&&Ua.test(a.nodeName)&&a.parentNode&&c.error(\"type property can't be changed\");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,\"form\")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b===\"tabIndex\")return(b=a.getAttributeNode(\"tabIndex\"))&&\nb.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b===\"style\"){if(f)a.style.cssText=\"\"+d;return a.style.cssText}f&&a.setAttribute(b,\"\"+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\\./g,Ma=/ /g,Xa=/[^\\w\\s.|`]/g,Ya=function(a){return a.replace(Xa,\"\\\\$&\")},ua={focusin:0,focusout:0};\nc.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?\"events\":\"__events__\",k=h[l],o=h.handle;if(typeof k===\"function\"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!==\"undefined\"&&!c.event.triggered?c.event.handle.apply(o.elem,\narguments):B};o.elem=a;b=b.split(\" \");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(\".\")>-1){r=l.split(\".\");l=r.shift();h.namespace=r.slice(0).sort().join(\".\")}else{r=[];h.namespace=\"\"}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent(\"on\"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid=\nd.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?\"events\":\"__events__\",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I===\"function\"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b===\"string\"&&b.charAt(0)===\".\"){b=b||\"\";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(\" \");f=b[l++];){r=f;k=f.indexOf(\".\")<0;o=[];if(!k){o=f.split(\".\");f=o.shift();x=RegExp(\"(^|\\\\.)\"+\nc.map(o.slice(0).sort(),Ya).join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b=\nw.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w===\"function\")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a===\"object\"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf(\"!\")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===\n8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,\"handle\"):(c.data(d,\"__events__\")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d[\"on\"+f]&&d[\"on\"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,\"\"),o=c.nodeName(e,\"a\")&&k===\n\"click\",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e[\"on\"+k])e[\"on\"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e[\"on\"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(\".\")<0&&!a.exclusive;if(!b){e=a.type.split(\".\");a.type=e.shift();d=e.slice(0).sort();e=RegExp(\"(^|\\\\.)\"+\nd.join(\"\\\\.(?:.*\\\\.)?\")+\"(\\\\.|$)\")}a.namespace=a.namespace||d.join(\".\");f=c.data(this,this.nodeType?\"events\":\"__events__\");if(typeof f===\"function\")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:\"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which\".split(\" \"),\nfix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||\nd&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,\nY(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent(\"on\"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=\nc.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};\nvar va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!==\n\"form\"){c.event.add(this,\"click.specialSubmit\",function(a){var b=a.target,d=b.type;if((d===\"submit\"||d===\"image\")&&c(b).closest(\"form\").length){a.liveFired=B;return la(\"submit\",this,arguments)}});c.event.add(this,\"keypress.specialSubmit\",function(a){var b=a.target,d=b.type;if((d===\"text\"||d===\"password\")&&c(b).closest(\"form\").length&&a.keyCode===13){a.liveFired=B;return la(\"submit\",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,\".specialSubmit\")}};if(!c.support.changeBubbles){var V,\nxa=function(a){var b=a.type,d=a.value;if(b===\"radio\"||b===\"checkbox\")d=a.checked;else if(b===\"select-multiple\")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join(\"-\"):\"\";else if(a.nodeName.toLowerCase()===\"select\")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,\"_change_data\");f=xa(d);if(a.type!==\"focusout\"||d.type!==\"radio\")c.data(d,\"_change_data\",f);if(!(e===B||f===e))if(e!=null||f){a.type=\"change\";a.liveFired=\nB;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d===\"radio\"||d===\"checkbox\"||b.nodeName.toLowerCase()===\"select\")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!==\"textarea\"||a.keyCode===32&&(d===\"checkbox\"||d===\"radio\")||d===\"select-multiple\")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,\"_change_data\",xa(a))}},setup:function(){if(this.type===\n\"file\")return false;for(var a in V)c.event.add(this,a+\".specialChange\",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,\".specialChange\");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:\"focusin\",blur:\"focusout\"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]===\n0&&t.removeEventListener(a,d,true)}}});c.each([\"bind\",\"one\"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d===\"object\"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b===\"one\"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d===\"unload\"&&b!==\"one\")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a===\"object\"&&!a.preventDefault)for(var d in a)this.unbind(d,\na[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind(\"live\"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=\n1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,\"lastToggle\"+a.guid)||0)%d;c.data(this,\"lastToggle\"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:\"focusin\",blur:\"focusout\",mouseenter:\"mouseover\",mouseleave:\"mouseout\"};c.each([\"live\",\"die\"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d===\n\"object\"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=e;e=B}for(d=(d||\"\").split(\" \");(l=d[k++])!=null;){o=X.exec(l);x=\"\";if(o){x=o[0];l=l.replace(X,\"\")}if(l===\"hover\")d.push(\"mouseenter\"+x,\"mouseleave\"+x);else{o=l;if(l===\"focus\"||l===\"blur\"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b===\"live\"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],\"live.\"+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind(\"live.\"+Y(l,r),f)}}return this}});\nc.each(\"blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error\".split(\" \"),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind(\"unload\",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});\n(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!==\"string\"){if(y===i){F=true;break}}else if(k.filter(i,\n[y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^\\[\\]]*\\]|['\"][^'\"]*['\"]|[^\\[\\]'\"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!==\"string\")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec(\"\");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3];\nbreak}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]===\"~\"||D[0]===\"+\")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr,\nq.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M=\"\";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)===\"[object Array]\")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h=\nl;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!==\"\\\\\"){u[1]=(u[1]||\"\").replace(/\\\\/g,\"\");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],\"\");break}}}}m||(m=i.getElementsByTagName(\"*\"));\nreturn{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!==\"\\\\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!==\nB){n||(F=y);g=g.replace(o.match[N],\"\");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw\"Syntax error, unrecognized expression: \"+g;};var o=k.selectors={order:[\"ID\",\"NAME\",\"TAG\"],match:{ID:/#((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,CLASS:/\\.((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,NAME:/\\[name=['\"]*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)['\"]*\\]/,ATTR:/\\[\\s*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)\\s*(?:(\\S?=)\\s*(['\"]*)(.*?)\\3|)\\s*\\]/,TAG:/^((?:[\\w\\u00c0-\\uFFFF\\*\\-]|\\\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\\((even|odd|[\\dn+\\-]*)\\))?/,\nPOS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^\\-]|$)/,PSEUDO:/:((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)(?:\\((['\"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/},leftMatch:{},attrMap:{\"class\":\"className\",\"for\":\"htmlFor\"},attrHandle:{href:function(g){return g.getAttribute(\"href\")}},relative:{\"+\":function(g,i){var n=typeof i===\"string\",m=n&&!/\\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()===\ni?q||false:q===i}n&&k.filter(i,g,true)},\">\":function(g,i){var n,m=typeof i===\"string\",p=0,q=g.length;if(m&&!/\\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},\"\":function(g,i,n){var m,p=e++,q=b;if(typeof i===\"string\"&&!/\\W/.test(i)){m=i=i.toLowerCase();q=a}q(\"parentNode\",i,p,g,m,n)},\"~\":function(g,i,n){var m,p=e++,q=b;if(typeof i===\"string\"&&!/\\W/.test(i)){m=\ni=i.toLowerCase();q=a}q(\"previousSibling\",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!==\"undefined\"&&!n)return(g=i.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!==\"undefined\"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute(\"name\")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=\" \"+g[1].replace(/\\\\/g,\n\"\")+\" \";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(\" \"+u.className+\" \").replace(/[\\t\\n]/g,\" \").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\\\/g,\"\")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]===\"nth\"){var i=/(-?)(\\d*)n((?:\\+|-)?\\d*)/.exec(g[2]===\"even\"&&\"2n\"||g[2]===\"odd\"&&\"2n+1\"||!/\\D/.test(g[2])&&\"0n+\"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n,\nm,p,q){i=g[1].replace(/\\\\/g,\"\");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]===\"~=\")g[4]=\" \"+g[4]+\" \";return g},PSEUDO:function(g,i,n,m,p){if(g[1]===\"not\")if((d.exec(g[3])||\"\").length>1||/^\\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!==\"hidden\"},disabled:function(g){return g.disabled===\ntrue},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\\d/i.test(g.nodeName)},text:function(g){return\"text\"===g.type},radio:function(g){return\"radio\"===g.type},checkbox:function(g){return\"checkbox\"===g.type},file:function(g){return\"file\"===g.type},password:function(g){return\"password\"===g.type},submit:function(g){return\"submit\"===\ng.type},image:function(g){return\"image\"===g.type},reset:function(g){return\"reset\"===g.type},button:function(g){return\"button\"===g.type||g.nodeName.toLowerCase()===\"button\"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]-\n0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p===\"contains\")return(g.textContent||g.innerText||k.getText([g])||\"\").indexOf(i[3])>=0;else if(p===\"not\"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error(\"Syntax error, unrecognized expression: \"+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case \"only\":case \"first\":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n===\n\"first\")return true;m=g;case \"last\":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case \"nth\":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute(\"id\")===i},TAG:function(g,i){return i===\"*\"&&g.nodeType===1||g.nodeName.toLowerCase()===\ni},CLASS:function(g,i){return(\" \"+(g.className||g.getAttribute(\"class\"))+\" \").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+\"\",p=i[2],q=i[4];return n==null?p===\"!=\":p===\"=\"?m===q:p===\"*=\"?m.indexOf(q)>=0:p===\"~=\"?(\" \"+m+\" \").indexOf(q)>=0:!q?m&&n!==false:p===\"!=\"?m!==q:p===\"^=\"?m.indexOf(q)===0:p===\"$=\"?m.substr(m.length-q.length)===q:p===\"|=\"?m===q||m.substr(0,q.length+1)===q+\"-\":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]];\nif(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return\"\\\\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\\[]*\\])(?![^\\(]*\\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\\r|\\n)*?)/.source+o.match[A].source.replace(/\\\\(\\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)===\"[object Array]\")Array.prototype.push.apply(m,\ng);else if(typeof g.length===\"number\")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1;\nfor(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i=\"\",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement(\"div\"),\ni=\"script\"+(new Date).getTime(),n=t.documentElement;g.innerHTML=\"<a name='\"+i+\"'/>\";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!==\"undefined\"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!==\"undefined\"&&p.getAttributeNode(\"id\").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!==\"undefined\"&&m.getAttributeNode(\"id\");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g);\nn=g=null})();(function(){var g=t.createElement(\"div\");g.appendChild(t.createComment(\"\"));if(g.getElementsByTagName(\"*\").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]===\"*\"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML=\"<a href='#'></a>\";if(g.firstChild&&typeof g.firstChild.getAttribute!==\"undefined\"&&g.firstChild.getAttribute(\"href\")!==\"#\")o.attrHandle.href=function(i){return i.getAttribute(\"href\",2)};g=null})();t.querySelectorAll&&\nfunction(){var g=k,i=t.createElement(\"div\");i.innerHTML=\"<p class='TEST'></p>\";if(!(i.querySelectorAll&&i.querySelectorAll(\".TEST\").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g,\"='$1']\");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!==\"object\"){var F=p.getAttribute(\"id\"),M=F||\"__sizzle__\";F||p.setAttribute(\"id\",M);try{return C(p.querySelectorAll(\"#\"+M+\" \"+m),q)}catch(N){}finally{F||\np.removeAttribute(\"id\")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,\"[test!='']:sizzle\")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g,\"='$1']\");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g=\nt.createElement(\"div\");g.innerHTML=\"<div class='test e'></div><div class='test'></div>\";if(!(!g.getElementsByClassName||g.getElementsByClassName(\"e\").length===0)){g.lastChild.className=\"e\";if(g.getElementsByClassName(\"e\").length!==1){o.order.splice(1,0,\"CLASS\");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!==\"undefined\"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition?\nfunction(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!==\"HTML\":false};var L=function(g,i){for(var n,m=[],p=\"\",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,\"\")}g=o.relative[g]?g+\"*\":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[\":\"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML;\nc.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\\[\\.,]*$/,bb=Array.prototype.slice,cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack(\"\",\"find\",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},\nnot:function(a){return this.pushStack(ma(this,a,false),\"not\",a)},filter:function(a){return this.pushStack(ma(this,a,true),\"filter\",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h=\nh.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,\"closest\",a)},index:function(a){if(!a||typeof a===\"string\")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a===\"string\"?c(a,b||this.context):\nc.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,\"parentNode\")},parentsUntil:function(a,b,d){return c.dir(a,\"parentNode\",d)},next:function(a){return c.nth(a,2,\"nextSibling\")},prev:function(a){return c.nth(a,\n2,\"previousSibling\")},nextAll:function(a){return c.dir(a,\"nextSibling\")},prevAll:function(a){return c.dir(a,\"previousSibling\")},nextUntil:function(a,b,d){return c.dir(a,\"nextSibling\",d)},prevUntil:function(a,b,d){return c.dir(a,\"previousSibling\",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,\"iframe\")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,\nb){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e===\"string\")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(\",\"))}});c.extend({filter:function(a,b,d){if(d)a=\":not(\"+a+\")\";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&\ne.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\\d+=\"(?:\\d+|null)\"/g,$=/^\\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/ig,Ba=/<([\\w:]+)/,db=/<tbody/i,eb=/<|&#?\\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\\s*(?:[^=]|=\\s*.checked.)/i,fb=/\\=([^=\"'>\\s]+\\/)>/g,P={option:[1,\n\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],area:[1,\"<map>\",\"</map>\"],_default:[0,\"\",\"\"]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,\"div<div>\",\"</div>\"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=\nc(this);d.text(a.call(this,b,d.text()))});if(typeof a!==\"object\"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},\nwrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,\"body\")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},\nprepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,\"before\",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,\nthis.nextSibling)});else if(arguments.length){var a=this.pushStack(this,\"after\",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName(\"*\"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName(\"*\"));b.firstChild;)b.removeChild(b.firstChild);\nreturn this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement(\"div\");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,\"\").replace(fb,'=\"$1\">').replace($,\"\")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find(\"*\"),b.find(\"*\"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,\"\"):null;\nelse if(typeof a===\"string\"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||[\"\",\"\"])[1].toLowerCase()]){a=a.replace(Aa,\"<$1></$2>\");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName(\"*\"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=\nc(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!==\"string\")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),\"replaceWith\",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l===\"string\"&&Da.test(l))return this.each(function(){c(this).domManip(a,\nb,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,\"tr\");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],\"table\")?this[f].getElementsByTagName(\"tbody\")[0]||this[f].appendChild(this[f].ownerDocument.createElement(\"tbody\")):\nthis[f]:this[f],f>0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]===\"string\"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:\"append\",\nprependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement===\"undefined\")b=b.ownerDocument||\nb[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l===\"number\")l+=\"\";if(l){if(typeof l===\"string\"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l===\"string\"){l=l.replace(Aa,\"<$1></$2>\");var k=(Ba.exec(l)||[\"\",\"\"])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement(\"div\");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k===\"table\"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]===\"<table>\"&&!x?r.childNodes:[];for(o=k.length-\n1;o>=0;--o)c.nodeName(k[o],\"tbody\")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],\"script\")&&(!f[h].type||f[h].type.toLowerCase()===\"text/javascript\"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName(\"script\"))));\nd.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\\([^)]*\\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\\d+(?:px)?$/i,\njb=/^-?\\d/,kb={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Pa=[\"Left\",\"Right\"],Qa=[\"Top\",\"Bottom\"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,\"opacity\",\"opacity\");return d===\"\"?\"1\":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,\nzoom:true,lineHeight:true},cssProps:{\"float\":c.support.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d===\"number\"&&isNaN(d)||d==null)){if(typeof d===\"number\"&&!c.cssNumber[h])d+=\"px\";if(!k||!(\"set\"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&\"get\"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),\nh=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&\"get\"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each([\"height\",\"width\"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h===\"0px\"&&aa)h=aa(d,b,b);\nif(h!=null)return h===\"\"||h===\"auto\"?\"0px\":h}if(h<0||h==null){h=d.style[b];return h===\"\"||h===\"auto\"?\"0px\":h}return typeof h===\"string\"?h:h+\"px\"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+\"px\"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||\"\")?parseFloat(RegExp.$1)/100+\"\":b?\"1\":\"\"},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?\"\":\"alpha(opacity=\"+b*100+\")\",f=\nd.filter||\"\";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+\" \"+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,\"-$1\").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===\"\"&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left;\ne=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b===\"fontSize\"?\"1em\":f||0;f=h.pixelLeft+\"px\";h.left=d;a.runtimeStyle.left=e}return f===\"\"?\"auto\":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,\"display\"))===\"none\"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,\nob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\\[\\]$/,T=/\\=\\?(&|$)/,ja=/\\?/,rb=/([?&])_=[^&]*/,sb=/^(\\w+:)?\\/\\/([^\\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==\"string\"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(\" \");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e=\"GET\";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b===\n\"object\"){b=c.param(b,c.ajaxSettings.traditional);e=\"POST\"}var h=this;c.ajax({url:a,type:e,dataType:\"html\",data:b,complete:function(l,k){if(k===\"success\"||k===\"notmodified\")h.html(f?c(\"<div>\").append(l.responseText.replace(nb,\"\")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&\n!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each(\"ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend\".split(\" \"),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:\"GET\",url:a,data:b,success:d,dataType:e})},\ngetScript:function(a,b){return c.get(a,null,b,\"script\")},getJSON:function(a,b,d){return c.get(a,b,d,\"json\")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:\"POST\",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:\"GET\",contentType:\"application/x-www-form-urlencoded\",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:\"application/xml, text/xml\",html:\"text/html\",\nscript:\"text/javascript, application/javascript\",json:\"application/json, text/javascript\",text:\"text/plain\",_default:\"*/*\"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,\"\");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!==\"string\")b.data=c.param(b.data,b.traditional);if(b.dataType===\"jsonp\"){if(h===\"GET\")T.test(b.url)||(b.url+=(ja.test(b.url)?\"&\":\"?\")+(b.jsonp||\"callback\")+\"=?\");else if(!b.data||\n!T.test(b.data))b.data=(b.data?b.data+\"&\":\"\")+(b.jsonp||\"callback\")+\"=?\";b.dataType=\"json\"}if(b.dataType===\"json\"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||\"jsonp\"+mb++;if(b.data)b.data=(b.data+\"\").replace(T,\"=\"+d+\"$1\");b.url=b.url.replace(T,\"=\"+d+\"$1\");b.dataType=\"script\";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType===\"script\"&&b.cache===null)b.cache=\nfalse;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,\"$1_=\"+o);b.url=x+(x===b.url?(ja.test(b.url)?\"&\":\"?\")+\"_=\"+o:\"\")}if(b.data&&l)b.url+=(ja.test(b.url)?\"&\":\"?\")+b.data;b.global&&c.active++===0&&c.event.trigger(\"ajaxStart\");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType===\"script\"&&h===\"GET\"&&o){var r=t.getElementsByTagName(\"head\")[0]||t.documentElement,A=t.createElement(\"script\");if(b.scriptCharset)A.charset=b.scriptCharset;\nA.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState===\"loaded\"||this.readyState===\"complete\")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader(\"Content-Type\",\nb.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader(\"If-Modified-Since\",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader(\"If-None-Match\",c.etag[b.url])}o||w.setRequestHeader(\"X-Requested-With\",\"XMLHttpRequest\");w.setRequestHeader(\"Accept\",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+\", */*; q=0.01\":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger(\"ajaxStop\");w.abort();return false}b.global&&\nc.triggerGlobal(b,\"ajaxSend\",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m===\"abort\"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m===\"timeout\")){J=true;w.onreadystatechange=c.noop;e=m===\"timeout\"?\"timeout\":!c.httpSuccess(w)?\"error\":b.ifModified&&c.httpNotModified(w,b.url)?\"notmodified\":\"success\";var p;if(e===\"success\")try{f=c.httpData(w,b.dataType,b)}catch(q){e=\"parsererror\";p=q}if(e===\"success\"||e===\"notmodified\")d||\nc.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m===\"timeout\"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L(\"abort\")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L(\"timeout\")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]=\nencodeURIComponent(h)+\"=\"+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join(\"&\").replace(tb,\"+\")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,\"ajaxError\",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,\"ajaxSuccess\",\n[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,\"ajaxComplete\",[b,a]);a.global&&c.active--===1&&c.event.trigger(\"ajaxStop\")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol===\"file:\"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader(\"Last-Modified\"),\ne=a.getResponseHeader(\"Etag\");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader(\"content-type\")||\"\",f=b===\"xml\"||!b&&e.indexOf(\"xml\")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName===\"parsererror\"&&c.error(\"parsererror\");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a===\"string\")if(b===\"json\"||!b&&e.indexOf(\"json\")>=0)a=c.parseJSON(a);else if(b===\"script\"||!b&&e.indexOf(\"javascript\")>=0)c.globalEval(a);return a}});\nif(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!==\"file:\")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\\-]=)?([\\d+.\\-]+)(.*)$/,ba,pa=[[\"height\",\"marginTop\",\"marginBottom\",\"paddingTop\",\"paddingBottom\"],[\"width\",\"marginLeft\",\"marginRight\",\"paddingLeft\",\"paddingRight\"],[\"opacity\"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S(\"show\",\n3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,\"olddisplay\")&&b===\"none\")b=a.style.display=\"\";b===\"\"&&c.css(a,\"display\")===\"none\"&&c.data(a,\"olddisplay\",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===\"\"||b===\"none\")a.style.display=c.data(a,\"olddisplay\")||\"\"}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S(\"hide\",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],\"display\");d!==\"none\"&&c.data(this[a],\"olddisplay\",\nd)}for(a=0;a<b;a++)this[a].style.display=\"none\";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a===\"boolean\";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(\":hidden\");c(this)[f?\"show\":\"hide\"]()}):this.animate(S(\"toggle\",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(\":hidden\").css(\"opacity\",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,\nd,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?\"each\":\"queue\"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(\":hidden\"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]===\"hide\"&&o||a[l]===\"show\"&&!o)return h.complete.call(this);if(k&&(l===\"height\"||l===\"width\")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,\"display\")===\"inline\"&&c.css(this,\"float\")===\"none\")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)===\n\"inline\")this.style.display=\"inline-block\";else{this.style.display=\"inline\";this.style.zoom=1}else this.style.display=\"inline-block\"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow=\"hidden\";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C===\"toggle\"?o?\"show\":\"hide\":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||\"px\";if(g!==\"px\"){c.style(x,A,(L||1)+g);I=(L||\n1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]===\"-=\"?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,\"\")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S(\"show\",1),slideUp:S(\"hide\",1),slideToggle:S(\"toggle\",1),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,\nd,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a===\"object\"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration===\"number\"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*\nMath.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)}\nvar f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||\"px\";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop===\"width\"||this.prop===\"height\"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;\nthis.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each([\"\",\"X\",\"Y\"],function(k,o){f.style[\"overflow\"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||\nthis.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?\"swing\":\"linear\");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=\nc.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,\"opacity\",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop===\"width\"||a.prop===\"height\"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===\nb.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset=\"getBoundingClientRect\"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&\nh.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle;\nfor(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position===\"fixed\")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!==\"visible\"){k+=\nparseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position===\"relative\"||d.position===\"static\"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position===\"fixed\"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement(\"div\"),d,e,f,h=parseFloat(c.css(a,\"marginTop\"))||0;c.extend(b.style,{position:\"absolute\",top:0,left:0,margin:0,border:0,width:\"1px\",\nheight:\"1px\",visibility:\"hidden\"});b.innerHTML=\"<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>\";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=\nf.offsetTop===5;e.style.position=\"fixed\";e.style.top=\"20px\";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top=\"\";d.style.overflow=\"hidden\";d.style.position=\"relative\";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,\n\"marginTop\"))||0;d+=parseFloat(c.css(a,\"marginLeft\"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,\"position\");if(e===\"static\")a.style.position=\"relative\";var f=c(a),h=f.offset(),l=c.css(a,\"top\"),k=c.css(a,\"left\"),o=e===\"absolute\"&&c.inArray(\"auto\",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;\"using\"in b?b.using.call(a,\ne):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,\"marginTop\"))||0;d.left-=parseFloat(c.css(a,\"marginLeft\"))||0;e.top+=parseFloat(c.css(b[0],\"borderTopWidth\"))||0;e.left+=parseFloat(c.css(b[0],\"borderLeftWidth\"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&&\nc.css(a,\"position\")===\"static\";)a=a.offsetParent;return a})}});c.each([\"Left\",\"Top\"],function(a,b){var d=\"scroll\"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?\"pageXOffset\"in h?h[a?\"pageYOffset\":\"pageXOffset\"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each([\"Height\",\"Width\"],function(a,b){var d=b.toLowerCase();\nc.fn[\"inner\"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,\"padding\")):null};c.fn[\"outer\"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?\"margin\":\"border\")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode===\"CSS1Compat\"&&f.document.documentElement[\"client\"+b]||f.document.body[\"client\"+b];else if(f.nodeType===9)return Math.max(f.documentElement[\"client\"+\nb],f.body[\"scroll\"+b],f.documentElement[\"scroll\"+b],f.body[\"offset\"+b],f.documentElement[\"offset\"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e===\"string\"?e:e+\"px\")}})})(window);\n"
  },
  {
    "path": "vendor/plugins/jrails/javascripts/jrails.js",
    "content": "(function($){$.ajaxSettings.accepts._default=\"text/javascript, text/html, application/xml, text/xml, */*\"})(jQuery);(function($){$.fn.reset=function(){return this.each(function(){if(typeof this.reset==\"function\"||(typeof this.reset==\"object\"&&!this.reset.nodeType)){this.reset()}})};$.fn.enable=function(){return this.each(function(){this.disabled=false})};$.fn.disable=function(){return this.each(function(){this.disabled=true})}})(jQuery);(function($){$.extend({fieldEvent:function(el,obs){var field=el[0]||el,e=\"change\";if(field.type==\"radio\"||field.type==\"checkbox\"){e=\"click\"}else{if(obs&&(field.type==\"text\"||field.type==\"textarea\"||field.type==\"password\")){e=\"keyup\"}}return e}});$.fn.extend({delayedObserver:function(delay,callback){var el=$(this);if(typeof window.delayedObserverStack==\"undefined\"){window.delayedObserverStack=[]}if(typeof window.delayedObserverCallback==\"undefined\"){window.delayedObserverCallback=function(stackPos){var observed=window.delayedObserverStack[stackPos];if(observed.timer){clearTimeout(observed.timer)}observed.timer=setTimeout(function(){observed.timer=null;observed.callback(observed.obj,observed.obj.formVal())},observed.delay*1000);observed.oldVal=observed.obj.formVal()}}window.delayedObserverStack.push({obj:el,timer:null,delay:delay,oldVal:el.formVal(),callback:callback});var stackPos=window.delayedObserverStack.length-1;if(el[0].tagName==\"FORM\"){$(\":input\",el).each(function(){var field=$(this);field.bind($.fieldEvent(field,delay),function(){var observed=window.delayedObserverStack[stackPos];if(observed.obj.formVal()==observed.oldVal){return}else{window.delayedObserverCallback(stackPos)}})})}else{el.bind($.fieldEvent(el,delay),function(){var observed=window.delayedObserverStack[stackPos];if(observed.obj.formVal()==observed.oldVal){return}else{window.delayedObserverCallback(stackPos)}})}},formVal:function(){var el=this[0];if(el.tagName==\"FORM\"){return this.serialize()}if(el.type==\"checkbox\"||el.type==\"radio\"){return this.filter(\"input:checked\").val()||\"\"}else{return this.val()}}})})(jQuery);(function($){$.fn.extend({visualEffect:function(o,options){if(options){speed=options.duration*1000}else{speed=null}e=o.replace(/\\_(.)/g,function(m,l){return l.toUpperCase()});return eval(\"$(this).\"+e+\"(\"+speed+\")\")},appear:function(speed,callback){return this.fadeIn(speed,callback)},blindDown:function(speed,callback){return this.show(\"blind\",{direction:\"vertical\"},speed,callback)},blindUp:function(speed,callback){return this.hide(\"blind\",{direction:\"vertical\"},speed,callback)},blindRight:function(speed,callback){return this.show(\"blind\",{direction:\"horizontal\"},speed,callback)},blindLeft:function(speed,callback){this.hide(\"blind\",{direction:\"horizontal\"},speed,callback);return this},dropOut:function(speed,callback){return this.hide(\"drop\",{direction:\"down\"},speed,callback)},dropIn:function(speed,callback){return this.show(\"drop\",{direction:\"up\"},speed,callback)},fade:function(speed,callback){return this.fadeOut(speed,callback)},fadeToggle:function(speed,callback){return this.animate({opacity:\"toggle\"},speed,callback)},fold:function(speed,callback){return this.hide(\"fold\",{},speed,callback)},foldOut:function(speed,callback){return this.show(\"fold\",{},speed,callback)},grow:function(speed,callback){return this.show(\"scale\",{},speed,callback)},highlight:function(speed,callback){return this.show(\"highlight\",{},speed,callback)},puff:function(speed,callback){return this.hide(\"puff\",{},speed,callback)},pulsate:function(speed,callback){return this.show(\"pulsate\",{},speed,callback)},shake:function(speed,callback){return this.show(\"shake\",{},speed,callback)},shrink:function(speed,callback){return this.hide(\"scale\",{},speed,callback)},squish:function(speed,callback){return this.hide(\"scale\",{origin:[\"top\",\"left\"]},speed,callback)},slideUp:function(speed,callback){return this.hide(\"slide\",{direction:\"up\"},speed,callback)},slideDown:function(speed,callback){return this.show(\"slide\",{direction:\"up\"},speed,callback)},switchOff:function(speed,callback){return this.hide(\"clip\",{},speed,callback)},switchOn:function(speed,callback){return this.show(\"clip\",{},speed,callback)}})})(jQuery);"
  },
  {
    "path": "vendor/plugins/jrails/javascripts/sources/jrails.js",
    "content": "/*\n*\n* jRails ajax extras\n* version 0.1\n* <aaron@ennerchi.com> | http://www.ennerchi.com\n*\n*/\n\n(function($) {\n\t$.ajaxSettings.accepts._default = \"text/javascript, text/html, application/xml, text/xml, */*\";\n})(jQuery);\n\n\n/*\n*\n* jRails form extras\n* <aaron@ennerchi.com> | http://www.ennerchi.com\n*\n*/\n\n\n(function($) {\n\t// reset a form\n\t$.fn.reset = function() {\n\t\treturn this.each(function() {\n\t\t\t// guard against an input with the name of 'reset'\n\t\t\t// note that IE reports the reset function as an 'object'\n\t\t\tif (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))\n\t\t\t\tthis.reset();\n\t\t});\n\t};\n\t// enable a form element\n\t$.fn.enable = function() {\n\t\treturn this.each(function() {\n\t\t\tthis.disabled = false;\n\t\t});\n\t};\n\t// disable a form element\n\t$.fn.disable = function() {\n\t\treturn this.each(function() {\n\t\t\tthis.disabled = true;\n\t\t});\n\t};\n\n})(jQuery);\n\n/*\n*\n* jRails form observer plugin\n* version 0.2\n* <aaron@ennerchi.com> | http://www.ennerchi.com\n*\n*/\n\n(function($) {\n\t$.extend({ // Translate field to event\n\t\tfieldEvent: function(el, obs) {\n\t\t\tvar field = el[0] || el, e = 'change';\n\t\t\tif (field.type == 'radio' || field.type == 'checkbox') e = 'click';\n\t\t\telse if (obs && (field.type == 'text' || field.type == 'textarea' || field.type == 'password')) e = 'keyup';\n\t\t\treturn e;\n\t\t}\n\t});\n\t$.fn.extend({ // Delayed observer for fields and forms\n\t\tdelayedObserver: function(delay, callback){\n\t\t\tvar el = $(this);\n\t\t\tif (typeof window.delayedObserverStack == 'undefined') window.delayedObserverStack = [];\n\t\t\tif (typeof window.delayedObserverCallback == 'undefined') {\n\t\t\t\twindow.delayedObserverCallback = function(stackPos) {\n\t\t\t\t\tvar observed = window.delayedObserverStack[stackPos];\n\t\t\t\t\tif (observed.timer) clearTimeout(observed.timer);\n\t\t\t\t\tobserved.timer = setTimeout(function(){\n\t\t\t\t\t\tobserved.timer = null;\n\t\t\t\t\t\tobserved.callback(observed.obj, observed.obj.formVal());\n\t\t\t\t\t}, observed.delay * 1000);\n\t\t\t\t\tobserved.oldVal = observed.obj.formVal();\n\t\t\t\t};\n\t\t\t}\n\t\t\twindow.delayedObserverStack.push({\n\t\t\t\tobj: el, timer: null, delay: delay,\n\t\t\t\toldVal: el.formVal(), callback: callback\n\t\t\t});\n\t\t\tvar stackPos = window.delayedObserverStack.length-1;\n\t\t\tif (el[0].tagName == 'FORM') {\n\t\t\t\t$(':input', el).each(function(){\n\t\t\t\t\tvar field = $(this);\n\t\t\t\t\tfield.bind($.fieldEvent(field, delay), function(){\n\t\t\t\t\t\tvar observed = window.delayedObserverStack[stackPos];\n\t\t\t\t\t\tif (observed.obj.formVal() == observed.oldVal) return;\n\t\t\t\t\t\telse window.delayedObserverCallback(stackPos);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tel.bind($.fieldEvent(el, delay), function(){\n\t\t\t\t\tvar observed = window.delayedObserverStack[stackPos];\n\t\t\t\t\tif (observed.obj.formVal() == observed.oldVal) return;\n\t\t\t\t\telse window.delayedObserverCallback(stackPos);\n\t\t\t\t});\n\t\t\t};\n\t\t},\n\t\tformVal: function() { // Gets form values\n\t\t\tvar el = this[0];\n\t\t\tif(el.tagName == 'FORM') return this.serialize();\n\t\t\tif(el.type == 'checkbox' || el.type == 'radio') return this.filter('input:checked').val() || '';\n\t\t\telse return this.val();\n\t\t}\n\t});\n})(jQuery);\n\n/*\n*\n* jRails visual effects stubs\n* version 0.2\n* <aaron@ennerchi.com> | http://www.ennerchi.com\n*\n*/\n\n(function($) {\n\t$.fn.extend({\n\t\tvisualEffect : function(o, options) {\n\t\t\tif (options) {\n        speed = options.duration * 1000;\n      } else {\n        speed = null;\n      }\n\t\t\te = o.replace(/\\_(.)/g, function(m, l){return l.toUpperCase()});\n\t\t\treturn eval('$(this).'+e+'('+ speed + ')');\n\t\t},\n\t\tappear : function(speed, callback) {\n\t\t\treturn this.fadeIn(speed, callback);\n\t\t},\n\t\tblindDown : function(speed, callback) {\n\t\t\treturn this.show('blind', { direction: 'vertical' }, speed, callback);\n\t\t},\n\t\tblindUp : function(speed, callback) {\n\t\t\treturn this.hide('blind', { direction: 'vertical' }, speed, callback);\n\t\t},\n\t\tblindRight : function(speed, callback) {\n\t\t\treturn this.show('blind', { direction: 'horizontal' }, speed, callback);\n\t\t},\n\t\tblindLeft : function(speed, callback) {\n\t\t\tthis.hide('blind', { direction: 'horizontal' }, speed, callback);\n\t\t\treturn this;\n\t\t},\n\t\tdropOut : function(speed, callback) {\n\t\t\treturn this.hide('drop', {direction: 'down' }, speed, callback);\n\t\t},\n\t\tdropIn : function(speed, callback) {\n\t\t\treturn this.show('drop', { direction: 'up' }, speed, callback);\n\t\t},\n\t\tfade : function(speed, callback) {\n\t\t\treturn this.fadeOut(speed, callback);\n\t\t},\n\t\tfadeToggle : function(speed, callback) {\n\t\t\treturn this.animate({opacity: 'toggle'}, speed, callback);\n\t\t},\n\t\tfold : function(speed, callback) {\n\t\t\treturn this.hide('fold', {}, speed, callback);\n\t\t},\n\t\tfoldOut : function(speed, callback) {\n\t\t\treturn this.show('fold', {}, speed, callback);\n\t\t},\n\t\tgrow : function(speed, callback) {\n\t\t\treturn this.show('scale', {}, speed, callback);\n\t\t},\n\t\thighlight : function(speed, callback) {\n\t\t\treturn this.show('highlight', {}, speed, callback);\n\t\t},\n\t\tpuff : function(speed, callback) {\n\t\t\treturn this.hide('puff', {}, speed, callback);\n\t\t},\n\t\tpulsate : function(speed, callback) {\n\t\t\treturn this.show('pulsate', {}, speed, callback);\n\t\t},\n\t\tshake : function(speed, callback) {\n\t\t\treturn this.show('shake', {}, speed, callback);\n\t\t},\n\t\tshrink : function(speed, callback) {\n\t\t\treturn this.hide('scale', {}, speed, callback);\n\t\t},\n\t\tsquish : function(speed, callback) {\n\t\t\treturn this.hide('scale', { origin: ['top', 'left'] }, speed, callback);\n\t\t},\n\t\tslideUp : function(speed, callback) {\n\t\t\treturn this.hide('slide', { direction: 'up'}, speed, callback);\n\t\t},\n\t\tslideDown : function(speed, callback) {\n\t\t\treturn this.show('slide', { direction: 'up'}, speed, callback);\n\t\t},\n\t\tswitchOff : function(speed, callback) {\n\t\t\treturn this.hide('clip', {}, speed, callback);\n\t\t},\n\t\tswitchOn : function(speed, callback) {\n\t\t\treturn this.show('clip', {}, speed, callback);\n\t\t}\n\t});\n})(jQuery);\n"
  },
  {
    "path": "vendor/plugins/jrails/jrails.gemspec",
    "content": "# Generated by jeweler\n# DO NOT EDIT THIS FILE DIRECTLY\n# Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command\n# -*- encoding: utf-8 -*-\n\nGem::Specification.new do |s|\n  s.name = %q{jrails}\n  s.version = \"0.6.0\"\n\n  s.required_rubygems_version = Gem::Requirement.new(\">= 0\") if s.respond_to? :required_rubygems_version=\n  s.authors = [\"Aaron Eisenberger\", \"Patrick Hurley\"]\n  s.date = %q{2009-10-20}\n  s.default_executable = %q{jrails}\n  s.description = %q{Using jRails, you can get all of the same default Rails helpers for javascript functionality using the lighter jQuery library.}\n  s.email = %q{aaronchi@gmail.com}\n  s.executables = [\"jrails\"]\n  s.extra_rdoc_files = [\n    \"CHANGELOG\",\n     \"LICENSE\",\n     \"README.rdoc\"\n  ]\n  s.files = [\n    \"bin/jrails\",\n     \"init.rb\",\n     \"install.rb\",\n     \"javascripts/jquery-ui.js\",\n     \"javascripts/jquery.js\",\n     \"javascripts/jrails.js\",\n     \"javascripts/sources/jrails.js\",\n     \"lib/jquery_selector_assertions.rb\",\n     \"lib/jrails.rb\",\n     \"rails/init.rb\",\n     \"tasks/jrails.rake\"\n  ]\n  s.homepage = %q{http://ennerchi.com/projects/jrails}\n  s.rdoc_options = [\"--charset=UTF-8\"]\n  s.require_paths = [\"lib\"]\n  s.rubyforge_project = %q{jrails}\n  s.rubygems_version = %q{1.3.5}\n  s.summary = %q{jRails is a drop-in jQuery replacement for the Rails Prototype/script.aculo.us helpers.}\n\n  if s.respond_to? :specification_version then\n    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION\n    s.specification_version = 3\n\n    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then\n    else\n    end\n  else\n  end\nend\n\n"
  },
  {
    "path": "vendor/plugins/jrails/lib/jquery_selector_assertions.rb",
    "content": "#\n#  jQuery Selector Assertions (modifications to the prototype/scriptaculous assertions)\n#\n#   From http://pastie.org/303776\n#\n# 1. Make sure to use '#' prefix when referring to element IDs in assert_select_rjs(),\n#    like this:\n#            assert_select_rjs :replace_html, '#someid'\n#    instead of prototype convention:\n#             assert_select_rjs :replace_html, 'someid' \n#\n# We monkey-patch some RJS-matching constants for assert_select_rjs to work \n# with jQuery-based code as opposed to Prototype's:\n#\nmodule ActionController\n   module Assertions\n      module SelectorAssertions\n         silence_warnings do\n            RJS_PATTERN_HTML  = \"\\\"((\\\\\\\\\\\"|[^\\\"])*)\\\"\"\n#            RJS_ANY_ID      = \"\\\"([^\\\"])*\\\"\"\n#\tbetter match with single or double quoted ids\n            RJS_ANY_ID      = \"[\\\"']([^\\\"])*[\\\"']\"\n            \n            RJS_STATEMENTS   = {\n               :chained_replace      => \"\\(jQuery|$\\)\\\\(#{RJS_ANY_ID}\\\\)\\\\.replaceWith\\\\(#{RJS_PATTERN_HTML}\\\\)\",\n               :chained_replace_html => \"\\(jQuery|$\\)\\\\(#{RJS_ANY_ID}\\\\)\\\\.updateWith\\\\(#{RJS_PATTERN_HTML}\\\\)\",\n               :replace_html         => \"\\(jQuery|$\\)\\\\(#{RJS_ANY_ID}\\\\)\\\\.html\\\\(#{RJS_PATTERN_HTML}\\\\)\",\n               :replace              => \"\\(jQuery|$\\)\\\\(#{RJS_ANY_ID}\\\\)\\\\.replaceWith\\\\(#{RJS_PATTERN_HTML}\\\\)\",\n               :insert_top           => \"\\(jQuery|$\\)\\\\(#{RJS_ANY_ID}\\\\)\\\\.prepend\\\\(#{RJS_PATTERN_HTML}\\\\)\",\n               :insert_bottom        => \"\\(jQuery|$\\)\\\\(#{RJS_ANY_ID}\\\\)\\\\.append\\\\(#{RJS_PATTERN_HTML}\\\\)\",\n               :effect               => \"\\(jQuery|$\\)\\\\(#{RJS_ANY_ID}\\\\)\\\\.effect\\\\(\",\n               :highlight            => \"\\(jQuery|$\\)\\\\(#{RJS_ANY_ID}\\\\)\\\\.effect\\\\('highlight'\"\n               \n=begin TODO: \n\nI've never used the chained_* so I don't know if they work.\n\nI couldn't seem to get assert_select_rjs to actually match the single quoted ids\nwhich are created by some of the effects like ... \n ... jQuery('#item_1559').effect('highlight',{},1000);\nso I modified jrails/lib/jrails.rb line 337 \n ... javascript = \"#{JQUERY_VAR}('#{jquery_id(element_id)}').#{mode || 'effect'}('#{name}'\"\nto\n ... javascript = \"#{JQUERY_VAR}(\\\"#{jquery_id(element_id)}\\\").#{mode || 'effect'}('#{name}'\"\nso it writes double quotes like most of the others.  This change should probably be \ndone to the others, but as I don't use them so haven't tested them.\n\nMy other option seemed to require modifying rails' selector_assertions.rb line 427\n ... id ? statement.gsub(RJS_ANY_ID, \"\\\"#{id}\\\"\") : statement\nwhich forces the expectation that the id is double quoted.  If I changed it to \n ... statement.gsub(RJS_ANY_ID, \"[\\\"']{1}#{id}[\\\"']{1}\")\nI believe that it would work as the logic seemed to work in some testing.\nI have not actually tried to modify rails, as this file doesn't seem to\nactually be in the git repository.\n\n\njrails now uses a nonconflict option so $ is jQuery.  I put both in the pattern in case it gets changed.\n\n              :insert_after => \"\",\n              :insert_before => \"\",\n=end\n               \n            }\n            \n            [:remove, :show, :hide, :toggle, :reset ].each do |action|\n               RJS_STATEMENTS[action] = \"\\(jQuery|$\\)\\\\(#{RJS_ANY_ID}\\\\)\\\\.#{action}\\\\(\\\\)\"\n            end\n            \n            # TODO: \n            #RJS_STATEMENTS[:insert_html] = \"Element.insert\\\\(#{RJS_ANY_ID}, \\\\{ (#{RJS_INSERTIONS.join('|')}):            \n\t\t\t\t\t\t\t#{RJS_PATTERN_HTML} \\\\}\\\\)\"\n            \n            RJS_STATEMENTS[:any] = Regexp.new(\"(#{RJS_STATEMENTS.values.join('|')})\")\n            RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\\\u([0-9a-zA-Z]{4})/\n         end\n      end\n   end\nend\n"
  },
  {
    "path": "vendor/plugins/jrails/lib/jrails.rb",
    "content": "module ActionView\n  module Helpers\n    \n    module JavaScriptHelper\n      \n      # This function can be used to render rjs inline\n      #\n      # <%= javascript_function do |page|\n      #   page.replace_html :list, :partial => 'list', :object => @list\n      # end %>\n      #\n      def javascript_function(*args, &block)\n        html_options = args.extract_options!\n        function = args[0] || ''\n\n        html_options.symbolize_keys!\n        function = update_page(&block) if block_given?\n        javascript_tag(function)\n      end\n      \n      def jquery_id(id)\n        id.to_s.count('#.*,>+~:[/ ') == 0 ? \"##{id}\" : id\n      end\n          \n      def jquery_ids(ids)\n        Array(ids).map{|id| jquery_id(id)}.join(',')\n      end\n\n    end\n    \n    module PrototypeHelper\n      \n      USE_PROTECTION = const_defined?(:DISABLE_JQUERY_FORGERY_PROTECTION) ? !DISABLE_JQUERY_FORGERY_PROTECTION : true\n\n      unless const_defined? :JQUERY_VAR\n        JQUERY_VAR = 'jQuery'\n      end\n          \n      unless const_defined? :JQCALLBACKS\n        JQCALLBACKS = Set.new([ :beforeSend, :complete, :error, :success ] + (100..599).to_a)\n        #instance_eval { remove_const :AJAX_OPTIONS }\n        remove_const(:AJAX_OPTIONS) if const_defined?(:AJAX_OPTIONS)\n        AJAX_OPTIONS = Set.new([ :before, :after, :condition, :url,\n                         :asynchronous, :method, :insertion, :position,\n                         :form, :with, :update, :script ]).merge(JQCALLBACKS)\n      end\n      \n      def periodically_call_remote(options = {})\n        frequency = options[:frequency] || 10 # every ten seconds by default\n        code = \"setInterval(function() {#{remote_function(options)}}, #{frequency} * 1000)\"\n        javascript_tag(code)\n      end\n      \n      def remote_function(options)\n        javascript_options = options_for_ajax(options)\n\n        update = ''\n        if options[:update] && options[:update].is_a?(Hash)\n          update  = []\n          update << \"success:'#{options[:update][:success]}'\" if options[:update][:success]\n          update << \"failure:'#{options[:update][:failure]}'\" if options[:update][:failure]\n          update  = '{' + update.join(',') + '}'\n        elsif options[:update]\n          update << \"'#{options[:update]}'\"\n        end\n\n        function = \"#{JQUERY_VAR}.ajax(#{javascript_options})\"\n\n        function = \"#{options[:before]}; #{function}\" if options[:before]\n        function = \"#{function}; #{options[:after]}\"  if options[:after]\n        function = \"if (#{options[:condition]}) { #{function}; }\" if options[:condition]\n        function = \"if (confirm('#{escape_javascript(options[:confirm])}')) { #{function}; }\" if options[:confirm]\n        return function\n      end\n      \n      class JavaScriptGenerator\n        module GeneratorMethods\n          \n          def insert_html(position, id, *options_for_render)\n            insertion = position.to_s.downcase\n            insertion = 'append' if insertion == 'bottom'\n            insertion = 'prepend' if insertion == 'top'\n            call \"#{JQUERY_VAR}(\\\"#{jquery_id(id)}\\\").#{insertion}\", render(*options_for_render)\n          end\n          \n          def replace_html(id, *options_for_render)\n            insert_html(:html, id, *options_for_render)\n          end\n          \n          def replace(id, *options_for_render)\n            call \"#{JQUERY_VAR}(\\\"#{jquery_id(id)}\\\").replaceWith\", render(*options_for_render)\n          end\n          \n          def remove(*ids)\n            call \"#{JQUERY_VAR}(\\\"#{jquery_ids(ids)}\\\").remove\"\n          end\n          \n          def show(*ids)\n            call \"#{JQUERY_VAR}(\\\"#{jquery_ids(ids)}\\\").show\"\n          end\n          \n          def hide(*ids)\n            call \"#{JQUERY_VAR}(\\\"#{jquery_ids(ids)}\\\").hide\"\n          end\n\n          def toggle(*ids)\n            call \"#{JQUERY_VAR}(\\\"#{jquery_ids(ids)}\\\").toggle\"\n          end\n          \n          def jquery_id(id)\n            id.to_s.count('#.*,>+~:[/ ') == 0 ? \"##{id}\" : id\n          end\n          \n          def jquery_ids(ids)\n            Array(ids).map{|id| jquery_id(id)}.join(',')\n          end\n          \n        end\n      end\n      \n    protected\n      def options_for_ajax(options)\n        js_options = build_callbacks(options)\n        \n        url_options = options[:url]\n        url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash)\n        js_options['url'] = \"'#{url_for(url_options)}'\"\n        js_options['async'] = false if options[:type] == :synchronous\n        js_options['type'] = options[:method] ? method_option_to_s(options[:method]) : ( options[:form] ? \"'post'\" : nil )\n        js_options['dataType'] = options[:datatype] ? \"'#{options[:datatype]}'\" : (options[:update] ? nil : \"'script'\")\n        \n        if options[:form]\n          js_options['data'] = \"#{JQUERY_VAR}.param(#{JQUERY_VAR}(this).serializeArray())\"\n        elsif options[:submit]\n          js_options['data'] = \"#{JQUERY_VAR}(\\\"##{options[:submit]} :input\\\").serialize()\"\n        elsif options[:with]\n          js_options['data'] = options[:with].gsub(\"Form.serialize(this.form)\",\"#{JQUERY_VAR}.param(#{JQUERY_VAR}(this.form).serializeArray())\")\n        end\n        \n        js_options['type'] ||= \"'post'\"\n        if options[:method]\n          if method_option_to_s(options[:method]) == \"'put'\" || method_option_to_s(options[:method]) == \"'delete'\"\n            js_options['type'] = \"'post'\"\n            if js_options['data']\n              js_options['data'] << \" + '&\"\n            else\n              js_options['data'] = \"'\"\n            end\n            js_options['data'] << \"_method=#{options[:method]}'\"\n          end\n        end\n        \n        if USE_PROTECTION && respond_to?('protect_against_forgery?') && protect_against_forgery?\n          if js_options['data']\n            js_options['data'] << \" + '&\"\n          else\n            js_options['data'] = \"'\"\n          end\n          js_options['data'] << \"#{request_forgery_protection_token}=' + encodeURIComponent('#{escape_javascript form_authenticity_token}')\"\n        end\n        js_options['data'] = \"''\" if js_options['type'] == \"'post'\" && js_options['data'].nil?\n        options_for_javascript(js_options.reject {|key, value| value.nil?})\n      end\n      \n      def build_update_for_success(html_id, insertion=nil)\n        insertion = build_insertion(insertion)\n        \"#{JQUERY_VAR}('#{jquery_id(html_id)}').#{insertion}(request);\"\n      end\n\n      def build_update_for_error(html_id, insertion=nil)\n        insertion = build_insertion(insertion)\n        \"#{JQUERY_VAR}('#{jquery_id(html_id)}').#{insertion}(request.responseText);\"\n      end\n\n      def build_insertion(insertion)\n        insertion = insertion ? insertion.to_s.downcase : 'html'\n        insertion = 'append' if insertion == 'bottom'\n        insertion = 'prepend' if insertion == 'top'\n        insertion\n      end\n\n      def build_observer(klass, name, options = {})\n        if options[:with] && (options[:with] !~ /[\\{=(.]/)\n          options[:with] = \"'#{options[:with]}=' + value\"\n        else\n          options[:with] ||= 'value' unless options[:function]\n        end\n\n        callback = options[:function] || remote_function(options)\n        javascript  = \"#{JQUERY_VAR}('#{jquery_id(name)}').delayedObserver(\"\n        javascript << \"#{options[:frequency] || 0}, \"\n        javascript << \"function(element, value) {\"\n        javascript << \"#{callback}}\"\n        #javascript << \", '#{options[:on]}'\" if options[:on]\n        javascript << \")\"\n        javascript_tag(javascript)\n      end\n      \n      def build_callbacks(options)\n        callbacks = {}\n        options[:beforeSend] = '';\n        [:uninitialized,:loading].each do |key|\n          options[:beforeSend] << (options[key].last == ';' ? options.delete(key) : options.delete(key) << ';') if options[key]\n        end\n        options.delete(:beforeSend) if options[:beforeSend].blank?\n        options[:complete] = options.delete(:loaded) if options[:loaded] \n        options[:error] = options.delete(:failure) if options[:failure]\n        if options[:update]\n          if options[:update].is_a?(Hash)\n            options[:update][:error] = options[:update].delete(:failure) if options[:update][:failure]\n            if options[:update][:success]\n              options[:success] = build_update_for_success(options[:update][:success], options[:position]) << (options[:success] ? options[:success] : '')\n            end\n            if options[:update][:error]\n              options[:error] = build_update_for_error(options[:update][:error], options[:position]) << (options[:error] ? options[:error] : '')\n            end\n          else\n            options[:success] = build_update_for_success(options[:update], options[:position]) << (options[:success] ? options[:success] : '')\n          end\n        end\n        options.each do |callback, code|\n          if JQCALLBACKS.include?(callback)\n            callbacks[callback] = \"function(request){#{code}}\"\n          end\n        end\n        callbacks\n      end\n      \n    end\n    \n    class JavaScriptElementProxy < JavaScriptProxy #:nodoc:\n      \n      unless const_defined? :JQUERY_VAR\n        JQUERY_VAR = PrototypeHelper::JQUERY_VAR\n      end\n      \n      def initialize(generator, id)\n        id = id.to_s.count('#.*,>+~:[/ ') == 0 ? \"##{id}\" : id\n        @id = id\n        super(generator, \"#{JQUERY_VAR}(\\\"#{id}\\\")\")\n      end\n      \n      def replace_html(*options_for_render)\n        call 'html', @generator.send(:render, *options_for_render)\n      end\n\n      def replace(*options_for_render)\n        call 'replaceWith', @generator.send(:render, *options_for_render)\n      end\n      \n      def reload(options_for_replace={})\n        replace(options_for_replace.merge({ :partial => @id.to_s.sub(/^#/,'') }))\n      end\n      \n      def value()\n        call 'val()'\n      end\n\n      def value=(value)\n        call 'val', value\n      end\n      \n    end\n    \n    class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\\\n      \n      unless const_defined? :JQUERY_VAR\n        JQUERY_VAR = PrototypeHelper::JQUERY_VAR\n      end\n      \n      def initialize(generator, pattern)\n        super(generator, \"#{JQUERY_VAR}(#{pattern.to_json})\")\n      end\n    end\n    \n    module ScriptaculousHelper\n      \n      unless const_defined? :JQUERY_VAR\n        JQUERY_VAR = PrototypeHelper::JQUERY_VAR\n      end\n      \n      unless const_defined? :SCRIPTACULOUS_EFFECTS\n        SCRIPTACULOUS_EFFECTS = {\n          :appear => {:method => 'fadeIn'},\n          :blind_down => {:method => 'blind', :mode => 'show', :options => {:direction => 'vertical'}},\n          :blind_up => {:method => 'blind', :mode => 'hide', :options => {:direction => 'vertical'}},\n          :blind_right => {:method => 'blind', :mode => 'show', :options => {:direction => 'horizontal'}},\n          :blind_left => {:method => 'blind', :mode => 'hide', :options => {:direction => 'horizontal'}},\n          :bounce_in => {:method => 'bounce', :mode => 'show', :options => {:direction => 'up'}},\n          :bounce_out => {:method => 'bounce', :mode => 'hide', :options => {:direction => 'up'}},\n          :drop_in => {:method => 'drop', :mode => 'show', :options => {:direction => 'up'}},\n          :drop_out => {:method => 'drop', :mode => 'hide', :options => {:direction => 'down'}},\n          :fade => {:method => 'fadeOut'},\n          :fold_in => {:method => 'fold', :mode => 'hide'},\n          :fold_out => {:method => 'fold', :mode => 'show'},\n          :grow => {:method => 'scale', :mode => 'show'},\n          :shrink => {:method => 'scale', :mode => 'hide'},\n          :slide_down => {:method => 'slide', :mode => 'show', :options => {:direction => 'up'}},\n          :slide_up => {:method => 'slide', :mode => 'hide', :options => {:direction => 'up'}},\n          :slide_right => {:method => 'slide', :mode => 'show', :options => {:direction => 'left'}},\n          :slide_left => {:method => 'slide', :mode => 'hide', :options => {:direction => 'left'}},\n          :squish => {:method => 'scale', :mode => 'hide', :options => {:origin => \"['top','left']\"}},\n          :switch_on => {:method => 'clip', :mode => 'show', :options => {:direction => 'vertical'}},\n          :switch_off => {:method => 'clip', :mode => 'hide', :options => {:direction => 'vertical'}},\n          :toggle_appear => {:method => 'fadeToggle'},\n          :toggle_slide => {:method => 'slide', :mode => 'toggle', :options => {:direction => 'up'}},\n          :toggle_blind => {:method => 'blind', :mode => 'toggle', :options => {:direction => 'vertical'}},\n        }\n      end\n      \n      def visual_effect(name, element_id = false, js_options = {})\n        element = element_id ? element_id : \"this\"\n        \n        if SCRIPTACULOUS_EFFECTS.has_key? name.to_sym\n          effect = SCRIPTACULOUS_EFFECTS[name.to_sym]\n          name = effect[:method]\n          mode = effect[:mode]\n          js_options = js_options.merge(effect[:options]) if effect[:options]\n        end\n        \n        [:color, :direction, :startcolor, :endcolor].each do |option|\n          js_options[option] = \"'#{js_options[option]}'\" if js_options[option]\n        end\n        \n        if js_options.has_key? :duration\n          speed = js_options.delete :duration\n          speed = (speed * 1000).to_i unless speed.nil?\n        else\n          speed = js_options.delete :speed\n        end\n        \n        if ['fadeIn','fadeOut','fadeToggle'].include?(name)\n          #\t090905 - Jake - changed ' to \\\" so it passes assert_select_rjs with an id\n          javascript = \"#{JQUERY_VAR}(\\\"#{jquery_id(element_id)}\\\").#{name}(\"\n          javascript << \"#{speed}\" unless speed.nil?\n          javascript << \");\"\n        else\n          #\t090905 - Jake - changed ' to \\\" so it passes \"assert_select_rjs :effect, ID\"\n          javascript = \"#{JQUERY_VAR}(\\\"#{jquery_id(element_id)}\\\").#{mode || 'effect'}('#{name}'\"\n          javascript << \",#{options_for_javascript(js_options)}\" unless speed.nil? && js_options.empty?\n          javascript << \",#{speed}\" unless speed.nil?\n          javascript << \");\"\n        end\n        \n      end\n      \n      def sortable_element_js(element_id, options = {}) #:nodoc:\n        #convert similar attributes\n        options[:handle] = \".#{options[:handle]}\" if options[:handle]\n        if options[:tag] || options[:only]\n          options[:items] = \"> \"\n          options[:items] << options.delete(:tag) if options[:tag]\n          options[:items] << \".#{options.delete(:only)}\" if options[:only]\n        end\n        options[:connectWith] = options.delete(:containment).map {|x| \"##{x}\"} if options[:containment]\n        options[:containment] = options.delete(:container) if options[:container]\n        options[:dropOnEmpty] = false unless options[:dropOnEmpty]\n        options[:helper] = \"'clone'\" if options[:ghosting] == true\n        options[:axis] = case options.delete(:constraint)\n          when \"vertical\", :vertical\n            \"y\"\n          when \"horizontal\", :horizontal\n            \"x\"\n          when false\n            nil\n          when nil\n            \"y\"\n        end\n        options.delete(:axis) if options[:axis].nil?\n        options.delete(:overlap)\n        options.delete(:ghosting)\n        \n        if options[:onUpdate] || options[:url]\n          if options[:format]\n            options[:with] ||= \"#{JQUERY_VAR}(this).sortable('serialize',{key:'#{element_id}[]', expression:#{options[:format]}})\"\n            options.delete(:format)\n          else\n            options[:with] ||= \"#{JQUERY_VAR}(this).sortable('serialize',{key:'#{element_id}[]'})\"\n          end\n          \n          options[:onUpdate] ||= \"function(){\" + remote_function(options) + \"}\"\n        end\n        \n        options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }\n        options[:update] = options.delete(:onUpdate) if options[:onUpdate]\n        \n        [:axis, :cancel, :containment, :cursor, :handle, :tolerance, :items, :placeholder].each do |option|\n          options[option] = \"'#{options[option]}'\" if options[option]\n        end\n        \n        options[:connectWith] = array_or_string_for_javascript(options[:connectWith]) if options[:connectWith]\n        \n        %(#{JQUERY_VAR}('#{jquery_id(element_id)}').sortable(#{options_for_javascript(options)});)\n      end\n      \n      def draggable_element_js(element_id, options = {})\n        %(#{JQUERY_VAR}(\"#{jquery_id(element_id)}\").draggable(#{options_for_javascript(options)});)\n      end\n      \n      def drop_receiving_element_js(element_id, options = {})\n        #convert similar options\n        options[:hoverClass] = options.delete(:hoverclass) if options[:hoverclass]\n        options[:drop] = options.delete(:onDrop) if options[:onDrop]\n        \n        if options[:drop] || options[:url]\n          options[:with] ||= \"'id=' + encodeURIComponent(#{JQUERY_VAR}(ui.draggable).attr('id'))\"\n          options[:drop] ||= \"function(ev, ui){\" + remote_function(options) + \"}\"\n        end\n        \n        options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }\n\n        options[:accept] = array_or_string_for_javascript(options[:accept]) if options[:accept]    \n        [:activeClass, :hoverClass, :tolerance].each do |option|\n          options[option] = \"'#{options[option]}'\" if options[option]\n        end\n        \n        %(#{JQUERY_VAR}('#{jquery_id(element_id)}').droppable(#{options_for_javascript(options)});)\n      end\n      \n    end\n    \n  end\nend\n"
  },
  {
    "path": "vendor/plugins/jrails/lib/tasks/jrails.rake",
    "content": "namespace :jrails do\n\n\tnamespace :js do\n\t\tdesc \"Copies the jQuery and jRails javascripts to public/javascripts\"\n\t\ttask :install do\n\t\t\tputs \"Copying files...\"\n\t\t\tproject_dir = RAILS_ROOT + '/public/javascripts/'\n\t\t\tscripts = Dir[File.join(File.dirname(__FILE__), '..', '/javascripts/', '*.js')]\n\t\t\tFileUtils.cp(scripts, project_dir)\n\t\t\tputs \"files copied successfully.\"\n\t\tend\n\n    desc 'Remove the prototype / script.aculo.us javascript files'\n    task :scrub do\n      puts \"Removing files...\"\n      files = %W[controls.js dragdrop.js effects.js prototype.js]\n      project_dir = File.join(RAILS_ROOT, 'public', 'javascripts')\n      files.each do |fname|\n        FileUtils.rm(File.join(project_dir, fname)) if File.exists?(File.join(project_dir, fname))\n      end\n      puts \"files removed successfully.\"\n    end\n  end\n  \nend\n"
  },
  {
    "path": "vendor/plugins/jrails/rails/init.rb",
    "content": "# The following options can be changed by creating an initializer in config/initializers/jrails.rb\n\n# jRails uses jQuery.noConflict() by default\n# to use the default jQuery varibale, use:\n# ActionView::Helpers::PrototypeHelper::JQUERY_VAR = '$'\n\n# ActionView::Helpers::PrototypeHelper:: DISABLE_JQUERY_FORGERY_PROTECTION\n# Set this to disable forgery protection in ajax calls\n# This is handy if you want to use caching with ajax by injecting the forgery token via another means\n# for an example, see http://henrik.nyh.se/2008/05/rails-authenticity-token-with-jquery\n# ActionView::Helpers::PrototypeHelper::DISABLE_JQUERY_FORGERY_PROTECTION = true\n\nActionView::Helpers::AssetTagHelper::JAVASCRIPT_DEFAULT_SOURCES = ['jquery','jquery-ui','jrails']\nActionView::Helpers::AssetTagHelper::reset_javascript_include_default\nrequire 'jrails'\nrequire 'jquery_selector_assertions' if RAILS_ENV == 'test'\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/CHANGELOG",
    "content": "* Fake HTTP method from OpenID server since they only support a GET. Eliminates the need to set an extra route to match the server's reply. [Josh Peek]\n\n* OpenID 2.0 recommends that forms should use the field name \"openid_identifier\" rather than \"openid_url\" [Josh Peek]\n\n* Return open_id_response.display_identifier to the application instead of .endpoints.claimed_id. [nbibler]\n\n* Add Timeout protection [Rick]\n\n* An invalid identity url passed through authenticate_with_open_id will no longer raise an InvalidOpenId exception. Instead it will return Result[:missing] to the completion block.\n\n* Allow a return_to option to be used instead of the requested url [Josh Peek]\n\n* Updated plugin to use Ruby OpenID 2.x.x [Josh Peek]\n\n* Tied plugin to ruby-openid 1.1.4 gem until we can make it compatible with 2.x [DHH]\n\n* Use URI instead of regexps to normalize the URL and gain free, better matching #8136 [dkubb]\n\n* Allow -'s in #normalize_url [Rick]\n\n* remove instance of mattr_accessor, it was breaking tests since they don't load ActiveSupport.  Fix Timeout test [Rick]\n\n* Throw a InvalidOpenId exception instead of just a RuntimeError when the URL can't be normalized [DHH]\n\n* Just use the path for the return URL, so extra query parameters don't interfere [DHH]\n\n* Added a new default database-backed store after experiencing trouble with the filestore on NFS. The file store is still available as an option [DHH]\n\n* Added normalize_url and applied it to all operations going through the plugin [DHH]\n\n* Removed open_id? as the idea of using the same input box for both OpenID and username has died -- use using_open_id? instead (which checks for the presence of params[:openid_url] by default) [DHH]\n\n* Added OpenIdAuthentication::Result to make it easier to deal with default situations where you don't care to do something particular for each error state [DHH]\n\n* Stop relying on root_url being defined, we can just grab the current url instead [DHH]"
  },
  {
    "path": "vendor/plugins/open_id_authentication/README",
    "content": "OpenIdAuthentication\n====================\n\nProvides a thin wrapper around the excellent ruby-openid gem from JanRan. Be sure to install that first:\n\n  gem install ruby-openid\n\nTo understand what OpenID is about and how it works, it helps to read the documentation for lib/openid/consumer.rb\nfrom that gem.\n\nThe specification used is http://openid.net/specs/openid-authentication-2_0.html.\n\n\nPrerequisites\n=============\n\nOpenID authentication uses the session, so be sure that you haven't turned that off. It also relies on a number of\ndatabase tables to store the authentication keys. So you'll have to run the migration to create these before you get started:\n\n  rake open_id_authentication:db:create\n\nOr, use the included generators to install or upgrade:\n\n  ./script/generate open_id_authentication_tables MigrationName\n  ./script/generate upgrade_open_id_authentication_tables MigrationName\n\nAlternatively, you can use the file-based store, which just relies on on tmp/openids being present in RAILS_ROOT. But be aware that this store only works if you have a single application server. And it's not safe to use across NFS. It's recommended that you use the database store if at all possible. To use the file-based store, you'll also have to add this line to your config/environment.rb:\n\n  OpenIdAuthentication.store = :file\n\nThis particular plugin also relies on the fact that the authentication action allows for both POST and GET operations.\nIf you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb. \n\nThe plugin also expects to find a root_url method that points to the home page of your site. You can accomplish this by using a root route in config/routes.rb:\n\n  map.root :controller => 'articles'\n\nThis plugin relies on Rails Edge revision 6317 or newer.\n\n\nExample\n=======\n\nThis example is just to meant to demonstrate how you could use OpenID authentication. You might well want to add\nsalted hash logins instead of plain text passwords and other requirements on top of this. Treat it as a starting point,\nnot a destination.\n\nNote that the User model referenced in the simple example below has an 'identity_url' attribute. You will want to add the same or similar field to whatever\nmodel you are using for authentication.\n\nAlso of note is the following code block used in the example below:\n\n  authenticate_with_open_id do |result, identity_url|\n    ...\n  end\n  \nIn the above code block, 'identity_url' will need to match user.identity_url exactly. 'identity_url' will be a string in the form of 'http://example.com' -\nIf you are storing just 'example.com' with your user, the lookup will fail.\n\nThere is a handy method in this plugin called 'normalize_url' that will help with validating OpenID URLs.\n\n  OpenIdAuthentication.normalize_url(user.identity_url)\n\nThe above will return a standardized version of the OpenID URL - the above called with 'example.com' will return 'http://example.com/'\nIt will also raise an InvalidOpenId exception if the URL is determined to not be valid.\nUse the above code in your User model and validate OpenID URLs before saving them.\n\nconfig/routes.rb\n\n  map.root :controller => 'articles'\n  map.resource :session\n\n\napp/views/sessions/new.erb\n\n  <% form_tag(session_url) do %>\n    <p>\n      <label for=\"name\">Username:</label>\n      <%= text_field_tag \"name\" %>\n    </p>\n\n    <p>\n      <label for=\"password\">Password:</label>\n      <%= password_field_tag %>\n    </p>\n\n    <p>\n      ...or use:\n    </p>\n\n    <p>\n      <label for=\"openid_identifier\">OpenID:</label>\n      <%= text_field_tag \"openid_identifier\" %>\n    </p>\n\n    <p>\n      <%= submit_tag 'Sign in', :disable_with => \"Signing in&hellip;\" %>\n    </p>\n  <% end %>\n\napp/controllers/sessions_controller.rb\n  class SessionsController < ApplicationController\n    def create\n      if using_open_id?\n        open_id_authentication\n      else\n        password_authentication(params[:name], params[:password])\n      end\n    end\n\n\n    protected\n      def password_authentication(name, password)\n        if @current_user = @account.users.authenticate(params[:name], params[:password])\n          successful_login\n        else\n          failed_login \"Sorry, that username/password doesn't work\"\n        end\n      end\n\n      def open_id_authentication\n        authenticate_with_open_id do |result, identity_url|\n          if result.successful?\n            if @current_user = @account.users.find_by_identity_url(identity_url)\n              successful_login\n            else\n              failed_login \"Sorry, no user by that identity URL exists (#{identity_url})\"\n            end\n          else\n            failed_login result.message\n          end\n        end\n      end\n    \n    \n    private\n      def successful_login\n        session[:user_id] = @current_user.id\n        redirect_to(root_url)\n      end\n\n      def failed_login(message)\n        flash.now[:error] = message\n        redirect_to(new_session_url)\n      end\n  end\n\n\n\nIf you're fine with the result messages above and don't need individual logic on a per-failure basis,\nyou can collapse the case into a mere boolean:\n\n    def open_id_authentication\n      authenticate_with_open_id do |result, identity_url|\n        if result.successful? && @current_user = @account.users.find_by_identity_url(identity_url)\n          successful_login\n        else\n          failed_login(result.message || \"Sorry, no user by that identity URL exists (#{identity_url})\")\n        end\n      end\n    end\n\n\nSimple Registration OpenID Extension\n====================================\n\nSome OpenID Providers support this lightweight profile exchange protocol.  See more: http://www.openidenabled.com/openid/simple-registration-extension\n\nYou can support it in your app by changing #open_id_authentication\n\n      def open_id_authentication(identity_url)\n        # Pass optional :required and :optional keys to specify what sreg fields you want.\n        # Be sure to yield registration, a third argument in the #authenticate_with_open_id block.\n        authenticate_with_open_id(identity_url, \n            :required => [ :nickname, :email ],\n            :optional => :fullname) do |result, identity_url, registration|\n          case result.status\n          when :missing\n            failed_login \"Sorry, the OpenID server couldn't be found\"\n          when :invalid\n            failed_login \"Sorry, but this does not appear to be a valid OpenID\"\n          when :canceled\n            failed_login \"OpenID verification was canceled\"\n          when :failed\n            failed_login \"Sorry, the OpenID verification failed\"\n          when :successful\n            if @current_user = @account.users.find_by_identity_url(identity_url)\n              assign_registration_attributes!(registration)\n\n              if current_user.save\n                successful_login\n              else\n                failed_login \"Your OpenID profile registration failed: \" +\n                  @current_user.errors.full_messages.to_sentence\n              end\n            else\n              failed_login \"Sorry, no user by that identity URL exists\"\n            end\n          end\n        end\n      end\n      \n      # registration is a hash containing the valid sreg keys given above\n      # use this to map them to fields of your user model\n      def assign_registration_attributes!(registration)\n        model_to_registration_mapping.each do |model_attribute, registration_attribute|\n          unless registration[registration_attribute].blank?\n            @current_user.send(\"#{model_attribute}=\", registration[registration_attribute])\n          end\n        end\n      end\n\n      def model_to_registration_mapping\n        { :login => 'nickname', :email => 'email', :display_name => 'fullname' }\n      end\n\nAttribute Exchange OpenID Extension\n===================================\n\nSome OpenID providers also support the OpenID AX (attribute exchange) protocol for exchanging identity information between endpoints.  See more: http://openid.net/specs/openid-attribute-exchange-1_0.html\n\nAccessing AX data is very similar to the Simple Registration process, described above -- just add the URI identifier for the AX field to your :optional or :required parameters.  For example:\n\n        authenticate_with_open_id(identity_url, \n            :required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration|\n      \nThis would provide the sreg data for :email, and the AX data for 'http://schema.openid.net/birthDate'\n\n\n\nCopyright (c) 2007 David Heinemeier Hansson, released under the MIT license"
  },
  {
    "path": "vendor/plugins/open_id_authentication/Rakefile",
    "content": "require 'rake'\nrequire 'rake/testtask'\nrequire 'rake/rdoctask'\n\ndesc 'Default: run unit tests.'\ntask :default => :test\n\ndesc 'Test the open_id_authentication plugin.'\nRake::TestTask.new(:test) do |t|\n  t.libs << 'lib'\n  t.pattern = 'test/**/*_test.rb'\n  t.verbose = true\nend\n\ndesc 'Generate documentation for the open_id_authentication plugin.'\nRake::RDocTask.new(:rdoc) do |rdoc|\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title    = 'OpenIdAuthentication'\n  rdoc.options << '--line-numbers' << '--inline-source'\n  rdoc.rdoc_files.include('README')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb",
    "content": "class OpenIdAuthenticationTablesGenerator < Rails::Generator::NamedBase\n  def initialize(runtime_args, runtime_options = {})\n    super\n  end\n\n  def manifest\n    record do |m|\n      m.migration_template 'migration.rb', 'db/migrate'\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb",
    "content": "class <%= class_name %> < ActiveRecord::Migration\n  def self.up\n    create_table :open_id_authentication_associations, :force => true do |t|\n      t.integer :issued, :lifetime\n      t.string :handle, :assoc_type\n      t.binary :server_url, :secret\n    end\n\n    create_table :open_id_authentication_nonces, :force => true do |t|\n      t.integer :timestamp, :null => false\n      t.string :server_url, :null => true\n      t.string :salt, :null => false\n    end\n  end\n\n  def self.down\n    drop_table :open_id_authentication_associations\n    drop_table :open_id_authentication_nonces\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb",
    "content": "class <%= class_name %> < ActiveRecord::Migration\n  def self.up\n    drop_table :open_id_authentication_settings\n    drop_table :open_id_authentication_nonces\n\n    create_table :open_id_authentication_nonces, :force => true do |t|\n      t.integer :timestamp, :null => false\n      t.string :server_url, :null => true\n      t.string :salt, :null => false\n    end\n  end\n\n  def self.down\n    drop_table :open_id_authentication_nonces\n\n    create_table :open_id_authentication_nonces, :force => true do |t|\n      t.integer :created\n      t.string :nonce\n    end\n\n    create_table :open_id_authentication_settings, :force => true do |t|\n      t.string :setting\n      t.binary :value\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb",
    "content": "class UpgradeOpenIdAuthenticationTablesGenerator < Rails::Generator::NamedBase\n  def initialize(runtime_args, runtime_options = {})\n    super\n  end\n\n  def manifest\n    record do |m|\n      m.migration_template 'migration.rb', 'db/migrate'\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/init.rb",
    "content": "begin\n  require 'openid'\nrescue LoadError\n  begin\n    gem 'ruby-openid', '>=2.1.4'\n  rescue Gem::LoadError\n    # no openid support\n  end\nend\n\nif Object.const_defined?(:OpenID)\n  config.to_prepare do\n    OpenID::Util.logger = Rails.logger\n    ActionController::Base.send :include, OpenIdAuthentication\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/lib/open_id_authentication/association.rb",
    "content": "module OpenIdAuthentication\n  class Association < ActiveRecord::Base\n    set_table_name :open_id_authentication_associations\n\n    def from_record\n      OpenID::Association.new(handle, secret, issued, lifetime, assoc_type)\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb",
    "content": "require 'openid/store/interface'\n\nmodule OpenIdAuthentication\n  class DbStore < OpenID::Store::Interface\n    def self.cleanup_nonces\n      now = Time.now.to_i\n      Nonce.delete_all([\"timestamp > ? OR timestamp < ?\", now + OpenID::Nonce.skew, now - OpenID::Nonce.skew])\n    end\n\n    def self.cleanup_associations\n      now = Time.now.to_i\n      Association.delete_all(['issued + lifetime > ?',now])\n    end\n\n    def store_association(server_url, assoc)\n      remove_association(server_url, assoc.handle)\n      Association.create(:server_url => server_url,\n                         :handle     => assoc.handle,\n                         :secret     => assoc.secret,\n                         :issued     => assoc.issued,\n                         :lifetime   => assoc.lifetime,\n                         :assoc_type => assoc.assoc_type)\n    end\n\n    def get_association(server_url, handle = nil)\n      assocs = if handle.blank?\n          Association.find_all_by_server_url(server_url)\n        else\n          Association.find_all_by_server_url_and_handle(server_url, handle)\n        end\n\n      assocs.reverse.each do |assoc|\n        a = assoc.from_record\n        if a.expires_in == 0\n          assoc.destroy\n        else\n          return a\n        end\n      end if assocs.any?\n\n      return nil\n    end\n\n    def remove_association(server_url, handle)\n      Association.delete_all(['server_url = ? AND handle = ?', server_url, handle]) > 0\n    end\n\n    def use_nonce(server_url, timestamp, salt)\n      return false if Nonce.find_by_server_url_and_timestamp_and_salt(server_url, timestamp, salt)\n      return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew\n      Nonce.create(:server_url => server_url, :timestamp => timestamp, :salt => salt)\n      return true\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/lib/open_id_authentication/mem_cache_store.rb",
    "content": "require 'digest/sha1'\nrequire 'openid/store/interface'\n\nmodule OpenIdAuthentication\n  class MemCacheStore < OpenID::Store::Interface\n    def initialize(*addresses)\n      @connection = ActiveSupport::Cache::MemCacheStore.new(addresses)\n    end\n\n    def store_association(server_url, assoc)\n      server_key = association_server_key(server_url)\n      assoc_key = association_key(server_url, assoc.handle)\n\n      assocs = @connection.read(server_key) || {}\n      assocs[assoc.issued] = assoc_key\n\n      @connection.write(server_key, assocs)\n      @connection.write(assoc_key, assoc, :expires_in => assoc.lifetime)\n    end\n\n    def get_association(server_url, handle = nil)\n      if handle\n        @connection.read(association_key(server_url, handle))\n      else\n        server_key = association_server_key(server_url)\n        assocs = @connection.read(server_key)\n        return if assocs.nil?\n\n        last_key = assocs[assocs.keys.sort.last]\n        @connection.read(last_key)\n      end\n    end\n\n    def remove_association(server_url, handle)\n      server_key = association_server_key(server_url)\n      assoc_key = association_key(server_url, handle)\n      assocs = @connection.read(server_key)\n\n      return false unless assocs && assocs.has_value?(assoc_key)\n\n      assocs = assocs.delete_if { |key, value| value == assoc_key }\n\n      @connection.write(server_key, assocs)\n      @connection.delete(assoc_key)\n\n      return true\n    end\n\n    def use_nonce(server_url, timestamp, salt)\n      return false if @connection.read(nonce_key(server_url, salt))\n      return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew\n      @connection.write(nonce_key(server_url, salt), timestamp, :expires_in => OpenID::Nonce.skew)\n      return true\n    end\n\n    private\n      def association_key(server_url, handle = nil)\n        \"openid_association_#{digest(server_url)}_#{digest(handle)}\"\n      end\n\n      def association_server_key(server_url)\n        \"openid_association_server_#{digest(server_url)}\"\n      end\n\n      def nonce_key(server_url, salt)\n        \"openid_nonce_#{digest(server_url)}_#{digest(salt)}\"\n      end\n\n      def digest(text)\n        Digest::SHA1.hexdigest(text)\n      end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb",
    "content": "module OpenIdAuthentication\n  class Nonce < ActiveRecord::Base\n    set_table_name :open_id_authentication_nonces\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/lib/open_id_authentication/request.rb",
    "content": "module OpenIdAuthentication\n  module Request\n    def self.included(base)\n      base.alias_method_chain :request_method, :openid\n    end\n\n    def request_method_with_openid\n      if !parameters[:_method].blank? && parameters[:open_id_complete] == '1'\n        parameters[:_method].to_sym\n      else\n        request_method_without_openid\n      end\n    end\n  end\nend\n\n# In Rails 2.3, the request object has been renamed\n# from AbstractRequest to Request\nif defined? ActionController::Request\n  ActionController::Request.send :include, OpenIdAuthentication::Request\nelse\n  ActionController::AbstractRequest.send :include, OpenIdAuthentication::Request\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/lib/open_id_authentication/tasks/open_id_authentication_tasks.rake",
    "content": "namespace :open_id_authentication do\n  namespace :db do\n    desc \"Creates authentication tables for use with OpenIdAuthentication\"\n    task :create => :environment do\n      generate_migration([\"open_id_authentication_tables\", \"add_open_id_authentication_tables\"])\n    end\n\n    desc \"Upgrade authentication tables from ruby-openid 1.x.x to 2.x.x\"\n    task :upgrade => :environment do\n      generate_migration([\"upgrade_open_id_authentication_tables\", \"upgrade_open_id_authentication_tables\"])\n    end\n\n    def generate_migration(args)\n      require 'rails_generator'\n      require 'rails_generator/scripts/generate'\n\n      if ActiveRecord::Base.connection.supports_migrations?\n        Rails::Generator::Scripts::Generate.new.run(args)\n      else\n        raise \"Task unavailable to this database (no migration support)\"\n      end\n    end\n\n    desc \"Clear the authentication tables\"\n    task :clear => :environment do\n      OpenIdAuthentication::DbStore.cleanup_nonces\n      OpenIdAuthentication::DbStore.cleanup_associations\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb",
    "content": "# http://trac.openidenabled.com/trac/ticket/156\nmodule OpenID\n  @@timeout_threshold = 20\n\n  def self.timeout_threshold\n    @@timeout_threshold\n  end\n\n  def self.timeout_threshold=(value)\n    @@timeout_threshold = value\n  end\n\n  class StandardFetcher\n    def make_http(uri)\n      http = @proxy.new(uri.host, uri.port)\n      http.read_timeout = http.open_timeout = OpenID.timeout_threshold\n      http\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/open_id_authentication/lib/open_id_authentication.rb",
    "content": "require 'uri'\nrequire 'openid/extensions/sreg'\nrequire 'openid/extensions/ax'\nrequire 'openid/store/filesystem'\n\nrequire File.dirname(__FILE__) + '/open_id_authentication/db_store'\nrequire File.dirname(__FILE__) + '/open_id_authentication/mem_cache_store'\nrequire File.dirname(__FILE__) + '/open_id_authentication/request'\nrequire File.dirname(__FILE__) + '/open_id_authentication/timeout_fixes' if OpenID::VERSION == \"2.0.4\"\n\nmodule OpenIdAuthentication\n  OPEN_ID_AUTHENTICATION_DIR = RAILS_ROOT + \"/tmp/openids\"\n\n  def self.store\n    @@store\n  end\n\n  def self.store=(*store_option)\n    store, *parameters = *([ store_option ].flatten)\n\n    @@store = case store\n    when :db\n      OpenIdAuthentication::DbStore.new\n    when :mem_cache\n      OpenIdAuthentication::MemCacheStore.new(*parameters)\n    when :file\n      OpenID::Store::Filesystem.new(OPEN_ID_AUTHENTICATION_DIR)\n    else\n      raise \"Unknown store: #{store}\"\n    end\n  end\n\n  self.store = :db\n\n  class InvalidOpenId < StandardError\n  end\n\n  class Result\n    ERROR_MESSAGES = {\n      :missing      => \"Sorry, the OpenID server couldn't be found\",\n      :invalid      => \"Sorry, but this does not appear to be a valid OpenID\",\n      :canceled     => \"OpenID verification was canceled\",\n      :failed       => \"OpenID verification failed\",\n      :setup_needed => \"OpenID verification needs setup\"\n    }\n\n    def self.[](code)\n      new(code)\n    end\n\n    def initialize(code)\n      @code = code\n    end\n\n    def status\n      @code\n    end\n\n    ERROR_MESSAGES.keys.each { |state| define_method(\"#{state}?\") { @code == state } }\n\n    def successful?\n      @code == :successful\n    end\n\n    def unsuccessful?\n      ERROR_MESSAGES.keys.include?(@code)\n    end\n\n    def message\n      ERROR_MESSAGES[@code]\n    end\n  end\n\n  # normalizes an OpenID according to http://openid.net/specs/openid-authentication-2_0.html#normalization\n  def self.normalize_identifier(identifier)\n    # clean up whitespace\n    identifier = identifier.to_s.strip\n\n    # if an XRI has a prefix, strip it.\n    identifier.gsub!(/xri:\\/\\//i, '')\n\n    # dodge XRIs -- TODO: validate, don't just skip.\n    unless ['=', '@', '+', '$', '!', '('].include?(identifier.at(0))\n      # does it begin with http?  if not, add it.\n      identifier = \"http://#{identifier}\" unless identifier =~ /^http/i\n\n      # strip any fragments\n      identifier.gsub!(/\\#(.*)$/, '')\n\n      begin\n        uri = URI.parse(identifier)\n        uri.scheme = uri.scheme.downcase  # URI should do this\n        identifier = uri.normalize.to_s\n      rescue URI::InvalidURIError\n        raise InvalidOpenId.new(\"#{identifier} is not an OpenID identifier\")\n      end\n    end\n\n    return identifier\n  end\n\n  # deprecated for OpenID 2.0, where not all OpenIDs are URLs\n  def self.normalize_url(url)\n    ActiveSupport::Deprecation.warn \"normalize_url has been deprecated, use normalize_identifier instead\"\n    self.normalize_identifier(url)\n  end\n\n  protected\n    def normalize_url(url)\n      OpenIdAuthentication.normalize_url(url)\n    end\n\n    def normalize_identifier(url)\n      OpenIdAuthentication.normalize_identifier(url)\n    end\n\n    # The parameter name of \"openid_identifier\" is used rather than the Rails convention \"open_id_identifier\"\n    # because that's what the specification dictates in order to get browser auto-complete working across sites\n    def using_open_id?(identity_url = nil) #:doc:\n      identity_url ||= params[:openid_identifier] || params[:openid_url]\n      !identity_url.blank? || params[:open_id_complete]\n    end\n\n    def authenticate_with_open_id(identity_url = nil, options = {}, &block) #:doc:\n      identity_url ||= params[:openid_identifier] || params[:openid_url]\n\n      if params[:open_id_complete].nil?\n        begin_open_id_authentication(identity_url, options, &block)\n      else\n        complete_open_id_authentication(&block)\n      end\n    end\n\n  private\n    def begin_open_id_authentication(identity_url, options = {})\n      identity_url = normalize_identifier(identity_url)\n      return_to    = options.delete(:return_to)\n      method       = options.delete(:method)\n      \n      options[:required] ||= []  # reduces validation later\n      options[:optional] ||= []\n\n      open_id_request = open_id_consumer.begin(identity_url)\n      add_simple_registration_fields(open_id_request, options)\n      add_ax_fields(open_id_request, options)\n      redirect_to(open_id_redirect_url(open_id_request, return_to, method))\n    rescue OpenIdAuthentication::InvalidOpenId => e\n      yield Result[:invalid], identity_url, nil\n    rescue OpenID::OpenIDError, Timeout::Error => e\n      logger.error(\"[OPENID] #{e}\")\n      yield Result[:missing], identity_url, nil\n    end\n\n    def complete_open_id_authentication\n      params_with_path = params.reject { |key, value| request.path_parameters[key] }\n      params_with_path.delete(:format)\n      open_id_response = timeout_protection_from_identity_server { open_id_consumer.complete(params_with_path, requested_url) }\n      identity_url     = normalize_identifier(open_id_response.display_identifier) if open_id_response.display_identifier\n\n      case open_id_response.status\n      when OpenID::Consumer::SUCCESS\n        profile_data = {}\n\n        # merge the SReg data and the AX data into a single hash of profile data\n        [ OpenID::SReg::Response, OpenID::AX::FetchResponse ].each do |data_response|\n          if data_response.from_success_response( open_id_response )\n            profile_data.merge! data_response.from_success_response( open_id_response ).data\n          end\n        end\n        \n        yield Result[:successful], identity_url, profile_data\n      when OpenID::Consumer::CANCEL\n        yield Result[:canceled], identity_url, nil\n      when OpenID::Consumer::FAILURE\n        yield Result[:failed], identity_url, nil\n      when OpenID::Consumer::SETUP_NEEDED\n        yield Result[:setup_needed], open_id_response.setup_url, nil\n      end\n    end\n\n    def open_id_consumer\n      OpenID::Consumer.new(session, OpenIdAuthentication.store)\n    end\n\n    def add_simple_registration_fields(open_id_request, fields)\n      sreg_request = OpenID::SReg::Request.new\n      \n      # filter out AX identifiers (URIs)\n      required_fields = fields[:required].collect { |f| f.to_s unless f =~ /^https?:\\/\\// }.compact\n      optional_fields = fields[:optional].collect { |f| f.to_s unless f =~ /^https?:\\/\\// }.compact\n      \n      sreg_request.request_fields(required_fields, true) unless required_fields.blank?\n      sreg_request.request_fields(optional_fields, false) unless optional_fields.blank?\n      sreg_request.policy_url = fields[:policy_url] if fields[:policy_url]\n      open_id_request.add_extension(sreg_request)\n    end\n    \n    def add_ax_fields( open_id_request, fields )\n      ax_request = OpenID::AX::FetchRequest.new\n      \n      # look through the :required and :optional fields for URIs (AX identifiers)\n      fields[:required].each do |f|\n        next unless f =~ /^https?:\\/\\//\n        ax_request.add( OpenID::AX::AttrInfo.new( f, nil, true ) )\n      end\n\n      fields[:optional].each do |f|\n        next unless f =~ /^https?:\\/\\//\n        ax_request.add( OpenID::AX::AttrInfo.new( f, nil, false ) )\n      end\n      \n      open_id_request.add_extension( ax_request )\n    end\n        \n    def open_id_redirect_url(open_id_request, return_to = nil, method = nil)\n      open_id_request.return_to_args['_method'] = (method || request.method).to_s\n      open_id_request.return_to_args['open_id_complete'] = '1'\n      open_id_request.redirect_url(root_url, return_to || requested_url)\n    end\n\n    def requested_url\n      relative_url_root = self.class.respond_to?(:relative_url_root) ?\n        self.class.relative_url_root.to_s :\n        request.relative_url_root\n      \"#{request.protocol}#{request.host_with_port}#{relative_url_root}#{request.path}\"\n    end\n\n    def timeout_protection_from_identity_server\n      yield\n    rescue Timeout::Error\n      Class.new do\n        def status\n          OpenID::FAILURE\n        end\n\n        def msg\n          \"Identity server timed out\"\n        end\n      end.new\n    end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/test/mem_cache_store_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\nrequire File.dirname(__FILE__) + '/../lib/open_id_authentication/mem_cache_store'\n\n# Mock MemCacheStore with MemoryStore for testing\nclass OpenIdAuthentication::MemCacheStore < OpenID::Store::Interface\n  def initialize(*addresses)\n    @connection = ActiveSupport::Cache::MemoryStore.new\n  end\nend\n\nclass MemCacheStoreTest < Test::Unit::TestCase\n  ALLOWED_HANDLE = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`{|}~'\n\n  def setup\n    @store = OpenIdAuthentication::MemCacheStore.new\n  end\n\n  def test_store\n    server_url = \"http://www.myopenid.com/openid\"\n    assoc = gen_assoc(0)\n\n    # Make sure that a missing association returns no result\n    assert_retrieve(server_url)\n\n    # Check that after storage, getting returns the same result\n    @store.store_association(server_url, assoc)\n    assert_retrieve(server_url, nil, assoc)\n\n    # more than once\n    assert_retrieve(server_url, nil, assoc)\n\n    # Storing more than once has no ill effect\n    @store.store_association(server_url, assoc)\n    assert_retrieve(server_url, nil, assoc)\n\n    # Removing an association that does not exist returns not present\n    assert_remove(server_url, assoc.handle + 'x', false)\n\n    # Removing an association that does not exist returns not present\n    assert_remove(server_url + 'x', assoc.handle, false)\n\n    # Removing an association that is present returns present\n    assert_remove(server_url, assoc.handle, true)\n\n    # but not present on subsequent calls\n    assert_remove(server_url, assoc.handle, false)\n\n    # Put assoc back in the store\n    @store.store_association(server_url, assoc)\n\n    # More recent and expires after assoc\n    assoc2 = gen_assoc(1)\n    @store.store_association(server_url, assoc2)\n\n    # After storing an association with a different handle, but the\n    # same server_url, the handle with the later expiration is returned.\n    assert_retrieve(server_url, nil, assoc2)\n\n    # We can still retrieve the older association\n    assert_retrieve(server_url, assoc.handle, assoc)\n\n    # Plus we can retrieve the association with the later expiration\n    # explicitly\n    assert_retrieve(server_url, assoc2.handle, assoc2)\n\n    # More recent, and expires earlier than assoc2 or assoc. Make sure\n    # that we're picking the one with the latest issued date and not\n    # taking into account the expiration.\n    assoc3 = gen_assoc(2, 100)\n    @store.store_association(server_url, assoc3)\n\n    assert_retrieve(server_url, nil, assoc3)\n    assert_retrieve(server_url, assoc.handle, assoc)\n    assert_retrieve(server_url, assoc2.handle, assoc2)\n    assert_retrieve(server_url, assoc3.handle, assoc3)\n\n    assert_remove(server_url, assoc2.handle, true)\n\n    assert_retrieve(server_url, nil, assoc3)\n    assert_retrieve(server_url, assoc.handle, assoc)\n    assert_retrieve(server_url, assoc2.handle, nil)\n    assert_retrieve(server_url, assoc3.handle, assoc3)\n\n    assert_remove(server_url, assoc2.handle, false)\n    assert_remove(server_url, assoc3.handle, true)\n\n    assert_retrieve(server_url, nil, assoc)\n    assert_retrieve(server_url, assoc.handle, assoc)\n    assert_retrieve(server_url, assoc2.handle, nil)\n    assert_retrieve(server_url, assoc3.handle, nil)\n\n    assert_remove(server_url, assoc2.handle, false)\n    assert_remove(server_url, assoc.handle, true)\n    assert_remove(server_url, assoc3.handle, false)\n\n    assert_retrieve(server_url, nil, nil)\n    assert_retrieve(server_url, assoc.handle, nil)\n    assert_retrieve(server_url, assoc2.handle, nil)\n    assert_retrieve(server_url, assoc3.handle, nil)\n\n    assert_remove(server_url, assoc2.handle, false)\n    assert_remove(server_url, assoc.handle, false)\n    assert_remove(server_url, assoc3.handle, false)\n  end\n\n  def test_nonce\n    server_url = \"http://www.myopenid.com/openid\"\n\n    [server_url, ''].each do |url|\n      nonce1 = OpenID::Nonce::mk_nonce\n\n      assert_nonce(nonce1, true, url, \"#{url}: nonce allowed by default\")\n      assert_nonce(nonce1, false, url, \"#{url}: nonce not allowed twice\")\n      assert_nonce(nonce1, false, url, \"#{url}: nonce not allowed third time\")\n\n      # old nonces shouldn't pass\n      old_nonce = OpenID::Nonce::mk_nonce(3600)\n      assert_nonce(old_nonce, false, url, \"Old nonce #{old_nonce.inspect} passed\")\n    end\n  end\n\n  private\n    def gen_assoc(issued, lifetime = 600)\n      secret = OpenID::CryptUtil.random_string(20, nil)\n      handle = OpenID::CryptUtil.random_string(128, ALLOWED_HANDLE)\n      OpenID::Association.new(handle, secret, Time.now + issued, lifetime, 'HMAC-SHA1')\n    end\n\n    def assert_retrieve(url, handle = nil, expected = nil)\n      assoc = @store.get_association(url, handle)\n\n      if expected.nil?\n        assert_nil(assoc)\n      else\n        assert_equal(expected, assoc)\n        assert_equal(expected.handle, assoc.handle)\n        assert_equal(expected.secret, assoc.secret)\n      end\n    end\n\n    def assert_remove(url, handle, expected)\n      present = @store.remove_association(url, handle)\n      assert_equal(expected, present)\n    end\n\n    def assert_nonce(nonce, expected, server_url, msg = \"\")\n      stamp, salt = OpenID::Nonce::split_nonce(nonce)\n      actual = @store.use_nonce(server_url, stamp, salt)\n      assert_equal(expected, actual, msg)\n    end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/test/normalize_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\n\nclass NormalizeTest < Test::Unit::TestCase\n  include OpenIdAuthentication\n\n  NORMALIZATIONS = {\n    \"openid.aol.com/nextangler\"             => \"http://openid.aol.com/nextangler\",\n    \"http://openid.aol.com/nextangler\"      => \"http://openid.aol.com/nextangler\",\n    \"https://openid.aol.com/nextangler\"     => \"https://openid.aol.com/nextangler\",\n    \"HTTP://OPENID.AOL.COM/NEXTANGLER\"      => \"http://openid.aol.com/NEXTANGLER\",\n    \"HTTPS://OPENID.AOL.COM/NEXTANGLER\"     => \"https://openid.aol.com/NEXTANGLER\",\n    \"loudthinking.com\"                      => \"http://loudthinking.com/\",\n    \"http://loudthinking.com\"               => \"http://loudthinking.com/\",\n    \"http://loudthinking.com:80\"            => \"http://loudthinking.com/\",\n    \"https://loudthinking.com:443\"          => \"https://loudthinking.com/\",\n    \"http://loudthinking.com:8080\"          => \"http://loudthinking.com:8080/\",\n    \"techno-weenie.net\"                     => \"http://techno-weenie.net/\",\n    \"http://techno-weenie.net\"              => \"http://techno-weenie.net/\",\n    \"http://techno-weenie.net  \"            => \"http://techno-weenie.net/\",\n    \"=name\"                                 => \"=name\"\n  }\n\n  def test_normalizations\n    NORMALIZATIONS.each do |from, to|\n      assert_equal to, normalize_identifier(from)\n    end\n  end\n\n  def test_broken_open_id\n    assert_raises(InvalidOpenId) { normalize_identifier(nil) }\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/test/open_id_authentication_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\n\nclass OpenIdAuthenticationTest < Test::Unit::TestCase\n  def setup\n    @controller = Class.new do\n      include OpenIdAuthentication\n      def params() {} end\n    end.new\n  end\n\n  def test_authentication_should_fail_when_the_identity_server_is_missing\n    open_id_consumer = mock()\n    open_id_consumer.expects(:begin).raises(OpenID::OpenIDError)\n    @controller.expects(:open_id_consumer).returns(open_id_consumer)\n    @controller.expects(:logger).returns(mock(:error => true))\n\n    @controller.send(:authenticate_with_open_id, \"http://someone.example.com\") do |result, identity_url|\n      assert result.missing?\n      assert_equal \"Sorry, the OpenID server couldn't be found\", result.message\n    end\n  end\n\n  def test_authentication_should_be_invalid_when_the_identity_url_is_invalid\n    @controller.send(:authenticate_with_open_id, \"!\") do |result, identity_url|\n      assert result.invalid?, \"Result expected to be invalid but was not\"\n      assert_equal \"Sorry, but this does not appear to be a valid OpenID\", result.message\n    end\n  end\n\n  def test_authentication_should_fail_when_the_identity_server_times_out\n    open_id_consumer = mock()\n    open_id_consumer.expects(:begin).raises(Timeout::Error, \"Identity Server took too long.\")\n    @controller.expects(:open_id_consumer).returns(open_id_consumer)\n    @controller.expects(:logger).returns(mock(:error => true))\n\n    @controller.send(:authenticate_with_open_id, \"http://someone.example.com\") do |result, identity_url|\n      assert result.missing?\n      assert_equal \"Sorry, the OpenID server couldn't be found\", result.message\n    end\n  end\n\n  def test_authentication_should_begin_when_the_identity_server_is_present\n    @controller.expects(:begin_open_id_authentication)\n    @controller.send(:authenticate_with_open_id, \"http://someone.example.com\")\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/open_id_authentication/test/status_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\n\nclass StatusTest < Test::Unit::TestCase\n  include OpenIdAuthentication\n\n  def test_state_conditional\n    assert Result[:missing].missing?\n    assert Result[:missing].unsuccessful?\n    assert !Result[:missing].successful?\n\n    assert Result[:successful].successful?\n    assert !Result[:successful].unsuccessful?\n  end\nend"
  },
  {
    "path": "vendor/plugins/open_id_authentication/test/test_helper.rb",
    "content": "require 'test/unit'\nrequire 'rubygems'\n\ngem 'activesupport'\nrequire 'active_support'\n\ngem 'actionpack'\nrequire 'action_controller'\n\ngem 'mocha'\nrequire 'mocha'\n\ngem 'ruby-openid'\nrequire 'openid'\n\nRAILS_ROOT = File.dirname(__FILE__) unless defined? RAILS_ROOT\nrequire File.dirname(__FILE__) + \"/../lib/open_id_authentication\"\n"
  },
  {
    "path": "vendor/plugins/pickle/History.txt",
    "content": "== master\n\n* 1 minor improvement\n  * docs: more links\n  \n\n== 0.1.22 - 7 Nov 2009\n\n* 2 minor enhancements\n  * Improved docs to include instructions for FactoryGirl users, and links/resources for pickle users\n  * Ruby 1.9.1 compatibility changes\n\n\n== 0.1.21\n\n* 1 minor enhancement\n  * Added 'should not' steps corresponding to model existence, and association exitsence [schlick]\n\n\n== 0.1.20\n\n* 1 minor enhancement\n  * Pickle now matches numeric field values preceded with a positive and negative sign eg +1.5 and -1 [schlick]\n\n\n== 0.1.19\n\n* 1 minor enhancement\n  * Add support for Cucumber tables [Tobi Knaup]\n  \n\n== 0.1.16, 0.1.17, 0.1.18 - 13 Oct 2009\n\n* 1 minor enhancement\n  * release gem on gemcutter and code on github\n\n\n== 0.1.15 - 28 Aug 2009\n\n* 1 minor enhancement\n  * avoid namespace collision on replace by renaming mapping#replace -> mapping#replacement [nruth]\n\n\n== 0.1.14 - 9 July 2009\n\n* 1 minor enhancement\n  * update specs and features for latest cucumber and machinist changes\n\n\n== 0.1.13 - 16 June 2009    \n\n* 2 minor enhancements\n  * model! and created_model! raise an error if pickle name can't be found\n  * path_to_pickle uses the above to give back a better error message\n\n\n== 0.1.12 - 7 Apr 2009\n\n* 2 minor enhancements\n  * rationalised Rakefile\n  * update World extensions for latest cucumber changes\n\n\n== 0.1.11 - 22 Feb 2009\n\n* 2 minor enhancements\n  * Pickle now supports multiple machinist blueprints\n  * Fix confusing adapter/adaptor comment generator comment \n\n\n== 0.1.10 - 13 Feb 2009\n\n* 2 minor enhancements\n  * Made pickle paths generator compatible with latest cucumber\n  * Simplified and Rakefile, including auto push api docs to gh-pages on ci build\n\n\n== 0.1.9 - 29 Jan 2009\n\n* 1 minor enhancement\n  * Pickle::Adapter.model_classes excludes those without tables\n\n\n== 0.1.8 - 29 Jan 2009\n\n* API change\n  * pickle_path becomes path_to_pickle, to avoid named route clashes\n\n* 2 minor enhancements\n  * Updated features for cucumber 0.2 compat\n  * Made paths allow for optional possesives\n\n\n== 0,1,7\n\n* 2 API changes\n  * script/generate pickle path[s] now amends the features/support/paths.rb file\n    instead of creating pge_to_path and path_steps.\n    \n  * pickle_email_steps is renamed email_steps\n\n\n== 0.1.6\n\n* 1 API change\n  * to use pickle env.rb should contain \"require 'pickle/world'\".  You should remove all trace of\n    pickle from features/support/env.rb and re run script/generate pickle\n\n* 2 major enhancements\n\n  * generate email steps with `script/generate pickle email`\n    email steps allow you to do things like this:\n    \n      Then 2 emails should be delivered\n      And the first email should be delivered to fred@gmail.com\n      And the 2nd email should be delivered to the user: \"ethel\"\n      \n      Then 1 email should be delivered with subject: \"Activate your account\"\n      And the email should link to the user's page\n    \n    take a look at features/step_definitions/pickle_email_steps.rb\n      \n  * generate path steps with `script/generate pickle path`\n    path steps allow you to do things like this\n    \n      When I go to the comment's page\n      Then I should be at the user's new comment page\n    \n    take a look at features/step_definitions/pickle_path_steps.rb, and modify page_to_path to suit your needs\n\n* 4 minor enhancements\n  * Improved documentation\n  * abstract models no longer kill pickle\n  * Actually test that the generators work\n  * Made Pickle::Session a plain ole mixin, as a separate class was unnecessary\n  * Pickle uses the cucumber World API\n\n\n== 0.1.5\n\n* API change\n  * CaptureModel, etc are now 'capture_model' methods\n\n* 3 major enhancements\n  * Steps for asserting that <n> models exist, matching certain criteria\n  * Steps for asserting associations added to generated pickle steps\n      'Then the user should be in the post's commenters'\n      'Then the forum: \"awesome\" should be the 2nd post's forum'\n  * configuration can now occur any time before a step is defined, which makes\n    for much more intuitive env.rb\n\n* 2 minor enhancement\n  * predicate matching is less prone to step conflicts because we preload a \n    big list of all the predicate and column methods\n  * field values now handle booleans and numerics\n\n\n== 0.1.4\n\n* 1 major enhancement\n  * You can create multiple models with ease, for eg.\n      'Given 10 users exist with role: \"admin\"'\n\n* 1 minor enhancement\n  * You can do Pickle.configure (just like Webrat.configure)\n\n\n== 0.1.3 - Bugfix release\n\n* 1 minor enhancement\n  * make generated steps compatible with Rails 2.1\n\n\n== 0.1.2\n\n* 2 major enhancements\n  * create your pickle steps with script/generate pickle\n  * Adapter based architecture, supports Machinist, FactoryGirl, and vanilla ActiveRecord\n  \n* 1 minor enhancement\n  * model_names now defaults to subclasses of AR::Base\n  * #original_model => #created_model\n\n\n== 0.1.1\n\n* 1 major enhancement:\n  * made pickle a github gem\n\n* 1 minor enhancement:\n  * Added intentions for pickle in README.textile\n\n\n== Prior to gems\n\n* Initial release: everything is subject to sweeping change"
  },
  {
    "path": "vendor/plugins/pickle/License.txt",
    "content": "Copyright (c) 2008-2009 Ian White - ian.w.white@gmail.com\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "vendor/plugins/pickle/README.rdoc",
    "content": "= pickle\n\nPickle gives you cucumber steps that create your models easily from factory-girl or\nmachinist factories/blueprints.  You can also just use ActiveRecord but it's not as cool.\n\nReferences to the models are stored in the current world, not necessarily for the purpose of checking the db\n(although you could use it for that), but for enabling easy reference to urls, and for\nbuilding complex givens which require a bunch of models collaborating\n\n== Resources\n\n<b>Github</b> for code: http://github.com/ianwhite/pickle\n\n<b>API</b> docs: http://ianwhite.github.com/pickle/doc\n\n<b>Google group</b> for questions: http://groups.google.com/group/pickle-cucumber\n\n<b>Lighthouse</b> for bugs: http://ianwhite.lighthouseapp.com/projects/25941-pickle\n\n<b>Railscast</b> presentation: http://railscasts.com/episodes/186-pickle-with-cucumber\n\n<b>Blog articles</b>: {dynamic50: Integration testing with cucumber and pickle}[http://blog.dynamic50.com/index.php/2009/04/integration-testing-with-cucumber-and-pickle/], {rubyflare: pickle my cucumber}[http://rubyflare.com/2009/10/28/pickle-my-cucumber/]\n\n== Install\n\nInstall pickle either as a rails plugin, or a gem\n\n  # gem from gemcutter\n  sudo gem install pickle\n\n  # gem dependency (in config/environments/cucumber.rb)\n  gem 'pickle'\n\n  # plugin\n  script/plugin install git://github.com/ianwhite/pickle.git\n  \n  # or, plugin as submodule\n  git submodule add git://github.com/ianwhite/pickle.git vendor/plugins/pickle\n\n== CI\n\nIt's tested against all stable branches of 2.x rails, and edge, with the latest versions of rspec, cucumber, factory_girl, machinist.\n\n== Contributors\n\nThe following people have made Pickle better:\n\n* {Nick Rutherford}[http://github.com/nruth]\n* Tobi Knaup\n* {Michael MacDonald}[http://github.com/schlick]\n\n== Get Started\n\n(you'd better install cucumber)\n\n  script/generate pickle [paths] [email]\n\nNow have a look at <tt>features/step_definitions/pickle_steps.rb</tt>\n\nIf you want path steps and email steps then just add 'paths' and/or 'email'.  The code/steps will be\nwritten to <tt>features/env/paths.rb</tt> and\n<tt>features/step_definitions/email_steps.rb</tt> respectively.\n\n=== Using with plain ole Active Record\n\nIf you have an AR called 'Post', with required fields 'title', and 'body', then you can now write \nsteps like this\n\n  Given a post exists with title: \"My Post\", body: \"My body\"\n\n=== Using with factory-girl or machinist\n\nBut you're using Machinist or FactoryGirl right?!  To leverage all of the factories/blueprints\nyou've written, you can just do stuff like\n\n  Given a user exists\n  And another user exists with role: \"admin\"\n\n  # later\n  Then a user should exist with name: \"Fred\"\n  And that user should be activated # this uses rspec predicate matchers\n\n==== Machinst: require your blueprints and reset Shams\n\n(The latest version of pickle supports {multiple blueprints}[http://github.com/notahat/machinist/commit/d6492e6927a8aa1819926e48b22377171fd20496], for \nearlier versions of machinist use pickle <= 0.1.10)\n\nIn your <tt>features/support/env.rb</tt> add the following lines at the bottom\n\n  require \"#{Rails.root}/spec/blueprints\" # or wherever they live\n  Before { Sham.reset } # reset Shams in between scenarios\n\n==== FactoryGirl: make sure factories are loaded\n\nIn your config/environments/cucumber.rb file, make sure the factory-girl gem is included (unless it's installed as a plugin).\n\nIf that doesn't solve loading issues then require your factories.rb file directly in a file called 'features/support/factory_girl.rb'\n\n  # example features/support/factory_girl.rb\n  require File.dirname(__FILE__) + '/../../spec/factories'\n\n=== Configuring Pickle\n\nYou can tell pickle to use another factory adapter (see Pickle::Adapter), or\ncreate mappings from english expressions to pickle model names.  You can also\noverride many of the options on the Pickle::Config object if you so choose\n\n  require 'pickle/world'\n\n  Pickle.configure do |config|\n    config.adapters = [:machinist, YourOwnAdapterClass]\n    config.map 'me', 'myself', 'my', 'I', :to => 'user: \"me\"'\n  end\n  \nOut of the box pickle looks for machinist, then factory-girl, then finally active-record 'factories'.\nIf you find that your steps aren't working with your factories, it's probably the case that your factory\nsetup is not being included in your cucumber environment (see comments above regarding machinist and factory-girl).\n\n== API\n\n=== Steps\n\nWhen you run <tt>script/generate pickle</tt> you get the following steps\n\n==== Given steps\n\n\"Given <b>a model</b> exists\",  e.g.\n\n  Given a user exists\n  Given a user: \"fred\" exists\n  Given the user exists\n  \n\"Given <b>a model</b> exists with <b>fields</b>\",  e.g.\n\n  Given a user exists with name: \"Fred\"\n  Given a user exists with name: \"Fred\", activated: false\n  \nYou can refer to other models in the fields\n\n  Given a user exists\n  And a post exists with author: the user\n  \n  Given a person: \"fred\" exists\n  And a person: \"ethel\" exists\n  And a fatherhood exists with parent: user \"fred\", child: user \"ethel\"\n  \n\"Given <b>n models</b> exist\", e.g.\n  \n  Given 10 users exist\n  \n\"Given <b>n models</b> exist with <b>fields</b>\", examples:\n\n  Given 10 users exist with activated: false\n\n==== Then steps\n\n===== Asserting existence of models\n\n\"Then <b>a model</b> should exist\",  e.g.\n\n  Then a user should exist\n\n\"Then <b>a model</b> should exist with <b>fields</b>\", e.g.\n\n  Then a user: \"fred\" should exist with name: \"Fred\" # we can label the found user for later use\n  \nYou can use other models, booleans, numerics, and strings as fields\n\n  Then a person should exist with child: person \"ethel\"\n  Then a user should exist with activated: false\n  Then a user should exist with activated: true, email: \"fred@gmail.com\"\n  \n\"Then <b>n models</b> should exist\", e.g.\n\n  Then 10 events should exist\n  \n\"Then <b>n models</b> should exist with <b>fields</b>\", e.g.\n\n  Then 2 people should exist with father: person \"fred\"\n  \n===== Asserting associations\n\nOne-to-one assocs: \"Then <b>a model</b> should be <b>other model</b>'s <b>association</b>\", e.g.\n\n  Then the person: \"fred\" should be person: \"ethel\"'s father\n  \nMany-to-one assocs: \"Then <b>a model</b> should be [in|one of] <b>other model</b>'s <b>association</b>\", e.g.\n\n  Then the person: \"ethel\" should be one of person: \"fred\"'s children\n  Then the comment should be in the post's comments\n  \n===== Asserting predicate methods\n\n\"Then <b>a model</b> should [be|have] [a|an] <b>predicate</b>\", e.g.\n\n  Then the user should have a status # => user.status?.should == true\n  Then the car: \"batmobile\" should be fast # => car.fast?.should == true\n  \n\"Then <b>a model</b> should not [be|have] [a|an] <b>predicate</b>\", e.g.\n\n  Then person: \"fred\" should not be childless # => fred.childless?.should == false\n  \n=== Regexps for use in your own steps\n\nBy default you get some regexps available in the main namespace for use\nin creating your own steps: `capture_model`, `capture_fields`, and others (see lib/pickle.rb)\n\n(You can use any of the regexps that Pickle uses by using the Pickle.parser namespace, see\nPickle::Parser::Matchers for the methods available)\n\n*capture_model*\n\n  Given /^#{capture_model} exists$/ do |model_name|\n    model(model_name).should_not == nil\n  end\n\n  Then /^I should be at the (.*?) page$/ |page|\n    if page =~ /#{capture_model}'s/\n      url_for(model($1))\n    else\n      # ...\n    end\n  end\n\n  Then /^#{capture_model} should be one of #{capture_model}'s posts$/ do |post, forum|\n    post = model!(post)\n    forum = model!(forum)\n    forum.posts.should include(post)\n  end \n\n*capture_fields*\n\nThis is useful for setting attributes, and knows about pickle model names so that you\ncan build up composite objects with ease\n\n  Given /^#{capture_model} exists with #{capture_fields}$/ do |model_name, fields|\n    create_model(model_name, fields)\n  end\n\n  # example of use\n  Given a user exists\n  And a post exists with author: the user # this step will assign the above user as :author on the post"
  },
  {
    "path": "vendor/plugins/pickle/Rakefile",
    "content": "# use pluginized rpsec if it exists\nrspec_base = File.expand_path(File.dirname(__FILE__) + '/../rspec/lib')\n$LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base) and !$LOAD_PATH.include?(rspec_base)\n\nrequire 'spec/rake/spectask'\nrequire 'spec/rake/verify_rcov'\n\n$LOAD_PATH.unshift File.dirname(__FILE__) + '/lib'\nrequire 'pickle/version'\n\nPluginName = 'pickle'\n\ntask :default => [:spec]\n\ndesc \"Run the specs for #{PluginName}\"\nSpec::Rake::SpecTask.new(:spec) do |t|\n  t.spec_files = FileList['spec/**/*_spec.rb']\n  t.spec_opts  = [\"--colour\"]\nend\n\ndesc \"Generate RCov report for #{PluginName}\"\nSpec::Rake::SpecTask.new(:rcov) do |t|\n  t.spec_files  = FileList['spec/**/*_spec.rb']\n  t.rcov        = true\n  t.rcov_dir    = 'doc/coverage'\n  t.rcov_opts   = ['--text-report', '--exclude', \"spec/,rcov.rb,#{File.expand_path(File.join(File.dirname(__FILE__),'../../..'))}\"] \nend\n\nnamespace :rcov do\n  desc \"Verify RCov threshold for #{PluginName}\"\n  RCov::VerifyTask.new(:verify => :rcov) do |t|\n    t.threshold = 100.0\n    t.index_html = File.join(File.dirname(__FILE__), 'doc/coverage/index.html')\n  end\nend\n\n# cucumber features require an enclosing rails app\nplugins_base = File.expand_path(File.join(File.dirname(__FILE__), '..'))\ncucumber_base = File.join(plugins_base, 'cucumber/lib')\nif File.exists?(cucumber_base) && plugins_base =~ /\\/vendor\\/plugins$/ # if we're in rails app\n  $:.unshift(cucumber_base)\n  require 'cucumber/rake/task'\n\n  desc \"Run features for #{PluginName} (progress)\"\n  Cucumber::Rake::Task.new(:features) do |t|\n    t.fork = true\n    t.cucumber_opts = ['--format', 'progress', '--require', 'features']\n  end\n  \n  desc \"Run features for #{PluginName} (full output)\"\n  namespace :features do\n    Cucumber::Rake::Task.new(:full) do |t|\n      t.cucumber_opts = ['--format', 'pretty', '--require', 'features']\n    end\n  end\nend\n\n# the following optional tasks are for CI, gems and doc building\nbegin\n  require 'hanna/rdoctask'\n  require 'garlic/tasks'\n  require 'grancher/task'\n  \n  task :cruise => ['garlic:all', 'doc:publish']\n  \n  Rake::RDocTask.new(:doc) do |d|\n    d.options << '--all'\n    d.rdoc_dir = 'doc'\n    d.main     = 'README.rdoc'\n    d.title    = \"#{PluginName} API docs\"\n    d.rdoc_files.include('README.rdoc', 'History.txt', 'License.txt', 'Todo.txt', 'lib/**/*.rb')\n  end\n\n  namespace :doc do\n    task :publish => :doc do\n      Rake::Task['doc:push'].invoke unless uptodate?('.git/refs/heads/gh-pages', 'doc')\n    end\n    \n    Grancher::Task.new(:push) do |g|\n      g.keep_all\n      g.directory 'doc', 'doc'\n      g.branch = 'gh-pages'\n      g.push_to = 'origin'\n    end\n  end\nrescue LoadError\nend\n\nbegin\n  require 'jeweler'\n  \n  Jeweler::Tasks.new do |s|\n    s.name = \"pickle\"\n    s.version = Pickle::Version::String\n    s.summary = \"Easy model creation and reference in your cucumber features\"\n    s.description = \"Easy model creation and reference in your cucumber features\"\n    s.email = \"ian.w.white@gmail.com\"\n    s.homepage = \"http://github.com/ianwhite/pickle/tree\"\n    s.authors = [\"Ian White\"]\n  end\n\n  Jeweler::GemcutterTasks.new\n\n  namespace :release do\n    task :all => ['release', 'gemcutter:release']\n  end\n  \nrescue LoadError\n  puts \"Jeweler not available for gem tasks. Install it with: sudo gem install jeweler\"\nend"
  },
  {
    "path": "vendor/plugins/pickle/Todo.txt",
    "content": "* Add email_for (same concept as path_to)\n* fix problem with save_and_open_emails\n* Translations\n* Investigate using Treetop for pre-parsing"
  },
  {
    "path": "vendor/plugins/pickle/VERSION",
    "content": "0.1.22\n"
  },
  {
    "path": "vendor/plugins/pickle/features/app/app.rb",
    "content": "# Routes\nActionController::Routing::Routes.draw do |map|\n  map.resources :spoons, :controller => 'default'\n  map.resources :forks, :controller => 'default' do |fork|\n    fork.resources :tines, :controller => 'default' do |tine|\n      tine.resources :comments, :controller => 'default'\n    end\n  end\n  map.resources :users, :controller => 'default'\nend\n\n# Migrations\nActiveRecord::Migration.suppress_messages do\n  ActiveRecord::Schema.define(:version => 0) do\n    create_table :forks, :force => true do |t|\n      t.string :name\n    end\n    \n    create_table :spoons, :force => true do |t|\n      t.string :name\n      t.boolean :round, :default => true, :null => false\n    end\n    \n    create_table :tines, :force => true do |t|\n      t.belongs_to :fork\n      t.boolean :rusty, :default => false, :null => false\n    end\n    \n    create_table :users, :force => true do |t|\n      t.string :name, :status, :email\n      t.decimal :attitude_score, :precision => 4, :scale => 2\n    end\n  end\nend\n\n\n# Factories for these Fork & Spoon\nclass Fork < ActiveRecord::Base\n  validates_presence_of :name\n  has_many :tines\n  \n  def completely_rusty?\n    tines.map(&:rusty?).uniq == [true]\n  end\n  \n  def fancy?\n    name =~ /fancy/i\n  end\nend\n\nclass Tine < ActiveRecord::Base\n  validates_presence_of :fork\n  belongs_to :fork\nend\n\n# Machinist blueprint for this\nclass Spoon < ActiveRecord::Base\n  validates_presence_of :name\nend\n\n# we don't want abstract classes getting in there\nclass AbstractUser < ActiveRecord::Base\n  self.abstract_class = true\nend\n\n# No factory or blueprint for this\nclass User < AbstractUser\n  validates_presence_of :name\n  def positive_person?\n    !attitude_score.nil? && attitude_score > 0\n  end\nend\n\n# controllers\nclass DefaultController < ActionController::Base\n  def index\n    render :text => \"index: I was invoked with #{request.path}\"\n  end\n  \n  def show\n    render :text => \"show: I was invoked with #{request.path}\"\n  end\n  \n  def new\n    render :text => \"new: I was invoked with #{request.path}\"\n  end\n  \n  def edit\n    render :text => \"edit: I was invoked with #{request.path}\"\n  end\nend\n\n# notifiers\nclass Notifier < ActionMailer::Base\n  include ActionController::UrlWriter\n  \n  # BC 2.1\n  if respond_to?(:view_paths)\n    view_paths << \"#{File.dirname(__FILE__)}/views\"\n  else\n    self.template_root = \"#{File.dirname(__FILE__)}/views\"\n  end\n  \n  def user_email(user)\n    @recipients  = user.email\n    @subject     = 'A user email'\n    @body[:user] = user\n    @body[:path] = user_path(user)\n  end\n  \n  def email(to, subject, body)\n    @recipients  = to\n    @subject     = subject\n    @body[:body] = body\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/features/app/blueprints.rb",
    "content": "# Blueprints\nrequire 'machinist/active_record'\n\nSham.spoon_name { |i| \"Spoon #{i}\" }\n\nSpoon.blueprint do\n  name { Sham.spoon_name }\nend\n\n# reset shams between scenarios\nBefore { Sham.reset }"
  },
  {
    "path": "vendor/plugins/pickle/features/app/factories.rb",
    "content": "# Factories\nrequire 'factory_girl'\n\nFactory.sequence :fork_name do |n|\n  \"fork %d04\" % n\nend\n\nFactory.define :fork do |f|\n  f.name { Factory.next(:fork_name) }\nend\n\nFactory.define :tine do |t|\n  t.association :fork\nend\n\nFactory.define :rusty_tine, :class => Tine do |t|\n  t.association :fork\n  t.rusty true\nend\n\nFactory.define :fancy_fork, :class => Fork do |t|\n  t.name { \"Fancy \" + Factory.next(:fork_name) }\nend\n"
  },
  {
    "path": "vendor/plugins/pickle/features/app/views/notifier/email.erb",
    "content": "<%= @body %>"
  },
  {
    "path": "vendor/plugins/pickle/features/app/views/notifier/user_email.erb",
    "content": "Dear <%= @user.name %>,\n\nThis is where you should go: <%= @path %>\n\nCheers,\nThe Pickle Team"
  },
  {
    "path": "vendor/plugins/pickle/features/email/email.feature",
    "content": "Feature: I can test emails are sent\n  In order write features with emails as outcomes\n  As a feature writer\n  I want to easily see what emails have been delivered\n  \n  Scenario: Deliver an email, and test it's properties\n    Given an email \"Gday\" with body: \"Gday Mate\" is delivered to fred@gmail.com\n    Then 1 email should be delivered\n    And the email should have subject: \"Gday\", to: \"fred@gmail.com\"\n    And the email should contain \"Mate\"\n    And the email should not contain \"Foo\"\n    \n  Scenario: Deliver some emails, restrict scope\n    Given an email \"cool\" with body: \"body1\" is delivered to fred@gmail.com\n    And an email \"tasty\" with body: \"body2\" is delivered to fred@gmail.com\n    And an email \"cool\" with body: \"body3\" is delivered to joe@gmail.com\n    \n    Then 2 emails should be delivered to fred@gmail.com\n    And the 1st email should have subject: \"cool\"\n    And the 2nd email should have subject: \"tasty\"\n    \n    And 2 emails should be delivered with subject: \"cool\"\n    And the 1st email should be delivered to fred@gmail.com\n    And the 2nd email should be delivered to joe@gmail.com\n    \n    And 1 email should be delivered with subject: \"cool\", to: \"fred@gmail.com\"\n    \n  Scenario: Deliver some emails, reset deliveries\n    Given an email \"cool\" with body: \"body1\" is delivered to fred@gmail.com\n    And all emails have been delivered\n    Then 0 emails should be delivered\n    \n  Scenario: Deliver emails to user\n    Given a user exists with name: \"Fred\", email: \"fred@gmail.com\"\n    And the user's email is delivered\n    Then 1 email should be delivered to the user\n    And the email should contain \"Dear Fred\"\n    And the email should link to the user's page"
  },
  {
    "path": "vendor/plugins/pickle/features/generator/generators.feature",
    "content": "Feature: allow pickle to generate steps\n  In order to get going with pickle\n  As a dev\n  I want to be able to generate steps\n\n  Scenario: cucumber is not yet installed\n    When I run \"script/generate pickle\"\n    Then I should see \"try running script/generate cucumber\"\n    \n  Scenario Outline: script/generate pickle on fresh cuc install\n    Given cucumber has been freshly generated\n    When I run \"<GENERATE PICKLE>\"\n    Then the file <STEPS FILE> should exist\n    And the file features/support/env.rb should match /<ENV.RB SHOULD MATCH>/\n    \n  Examples:\n    | GENERATE PICKLE             | STEPS FILE                                | ENV.RB SHOULD MATCH             |\n    | script/generate pickle      | features/step_definitions/pickle_steps.rb | require 'pickle\\/world'         |\n    | script/generate pickle      | features/step_definitions/pickle_steps.rb | Example of configuring pickle:  |\n    | script/generate pickle email| features/step_definitions/email_steps.rb  | require 'pickle\\/email\\/world'  |\n    \n  Scenario: script/generate pickle path on fresh cuc install\n    Given cucumber has been freshly generated\n    When I run \"script/generate pickle path\"\n    Then the file features/support/env.rb should match /require 'pickle\\/world'/\n    And the file features/support/paths.rb should match /added by script/generate pickle path/\n    And the file features/support/paths.rb should be identical to the local support/paths.rb\n\n  Scenario Outline: script/generate pickle, when env.rb has already requires pickle\n    Given cucumber has been freshly generated\n    And env.rb already requires <ENV.RB CONTAINS>\n    When I run \"<GENERATE PICKLE>\"\n    Then the file features/support/env.rb should not match /<ENV.RB SHOULD NOT MATCH>/\n  \n  Examples:\n    | ENV.RB CONTAINS   | GENERATE PICKLE               | ENV.RB SHOULD NOT MATCH                                       |\n    | pickle/world      | script/generate pickle        | Example of configuring pickle:                                |\n    | pickle/world      | script/generate pickle        | require 'pickle\\/world'.*require 'pickle\\/world'              |\n    | pickle/path/world | script/generate pickle path   | require 'pickle\\/path\\/world'.*require 'pickle\\/path\\/world'  |\n    | pickle/email/world| script/generate pickle email  | require 'pickle\\/email\\/world'.*require 'pickle\\/email\\/world'|\n    \n  Scenario: script/generate pickle page email\n    Given cucumber has been freshly generated\n    When I run \"script/generate pickle path email\"\n    Then the file features/step_definitions/email_steps.rb should exist\n    And the file features/step_definitions/pickle_steps.rb should exist\n    And the file features/support/env.rb should match /require 'pickle\\/world'/\n    And the file features/support/env.rb should match /require 'pickle\\/path\\/world'/\n    And the file features/support/env.rb should match /require 'pickle\\/email\\/world'/\n    And the file features/support/paths.rb should match /added by script/generate pickle path/\n\n\n\n  \n"
  },
  {
    "path": "vendor/plugins/pickle/features/path/models_page.feature",
    "content": "Feature: I can visit a page for a model\n  In order to easily go to pages for models I've created\n  As a feature writer\n  I want to be able visit pages their model\n\n  Scenario: create a spoon, go its page\n    Given a spoon exists\n    When I go to the spoon's page\n    Then I should be at the spoon's page\n    And the spoon's page should match route /spoons/:id\n    \n  Scenario: create a spoon, go to its edit page, check lots of different refs to it\n    Given a spoon: \"fred\" exists\n    When I go to spoon: \"fred\"'s edit page\n    Then I should be at the 1st spoon's edit page\n    And the 1st spoon's edit page should match route /spoons/:id/edit\n    And the spoon's edit page should match route /spoons/:id/edit\n    And the spoon: \"fred\"'s edit page should match route /spoons/:id/edit\n    \n  Scenario: go to a fork's nested tines page\n    Given a fork exists\n    When I go to the fork's tines page\n    Then I should be at the fork's tines page\n    And the fork's tines page should match route /forks/:fork_id/tines\n  \n  Scenario: go to a fork's new tine page\n    Given a fork exists\n    When I go to the fork's new tine page\n    Then I should be at the fork's new tine page\n    And the fork's new tine page should match route /forks/:fork_id/tines/new\n    \n  Scenario: go to a tine in fork context page\n    Given a fork exists\n    And a tine exists with fork: the fork\n    When I go to the fork's tine's page\n    Then I should be at the fork's tine's page\n    And the fork's tine's page should match route /forks/:fork_id/tines/:id\n    \n  Scenario: go to a tine's comments in fork context\n    Given a fork exists\n    And a tine exists with fork: the fork\n    When I go to the fork's tine's comments page\n    Then I should be at the fork's tine's comments page\n    And the fork's tine's comments page should match route /forks/:fork_id/tines/:tine_id/comments"
  },
  {
    "path": "vendor/plugins/pickle/features/path/named_route_page.feature",
    "content": "Feature: I can visit a page by named route\n  In order to nav in my features\n  As a feature writer\n  I want to be able visit named routes\n\n  Scenario: visit the new spoons page\n    When I go to the new spoon page\n    Then I should be at the new spoon page\n    And the new spoon page should match route /spoons/new\n   "
  },
  {
    "path": "vendor/plugins/pickle/features/pickle/create_from_active_record.feature",
    "content": "Feature: I can easily create models from my blueprints\n\n  As a plain old AR user\n  I want to be able to create models with fields\n  So that I can create models quickly and easily in my features\n  \n  Scenario: I create a user, and see if it looks right\n    Given a user exists with name: \"Fred\"\n    Then the user should not have a status\n\n  Scenario: I create a user, and see if it looks right\n    Given a user exists with name: \"Fred\", status: \"crayzee\"\n    Then a user should exist with name: \"Fred\"\n    And a user should exist with status: \"crayzee\"\n    But a user should not exist with name: \"Wilma\"\n  \n  Scenario: I create a user via a mapping\n    Given I exist with status: \"pwned\", name: \"fred\"\n    Then I should have a status\n    And the user: \"me\" should have a status\n  \n  Scenario: I create positive and negative users\n    Given a user exists with name: \"Fred\", attitude_score: +5.42\n    And another user exists with name: \"Ethel\", attitude_score: -1.46\n    Then 2 users should exist\n    And the 1st user should be a positive person\n    And the 2nd user should not be a positive person"
  },
  {
    "path": "vendor/plugins/pickle/features/pickle/create_from_factory_girl.feature",
    "content": "Feature: I can easily create models from my factories\n\n  As a pickle user\n  I want to be able to leverage my factories\n  So that I can create models quickly and easily in my features\n  \n  Scenario: I create a fork, and see if it looks right\n    Given a fork exists\n    Then the fork should not be completely rusty\n    \n  Scenario: I create a fork, and see if it looks right\n    Given a fork exists with name: \"Forky\"\n    Then a fork should exist with name: \"Forky\"\n    And the fork should not be completely rusty\n    \n  Scenario: I create some forks, and some tines\n    Given a fork: \"one\" exists\n    And a tine exists with fork: fork \"one\"\n    And another tine exists with fork: fork \"one\"\n    \n    And a fancy fork exists\n    And a tine exists with fork: the fancy fork\n    \n    Then the first tine should be tine of the fork: \"one\"\n    And the 2nd tine should be tine of fork: \"one\"\n    And the last tine should be tine of the fancy fork\n\n    Then the first tine should be in fork \"one\"'s tines\n    And the 2nd tine should be in fork: \"one\"'s tines\n    And the last tine should be in the fancy fork's tines\n    And the fancy fork should be the last tine's fork\n    \n    But the first tine should not be in the fancy fork's tines\n    And the last tine should not be in fork \"one\"'s tines\n    And the fancy fork should not be the first tine's fork\n    \n  Scenario: I create a fork with a tine, and find the tine by the fork\n    Given a fork exists\n    And a tine exists with fork: the fork\n    \n    Then a tine should exist with fork: the fork\n\n    And the fork should be the tine's fork\n\n  Scenario: I create fork via a mapping\n    Given killah fork exists\n    Then the fork should be fancy\n    And the fancy fork: \"of cornwood\" should be fancy"
  },
  {
    "path": "vendor/plugins/pickle/features/pickle/create_from_machinist.feature",
    "content": "Feature: I can easily create models from my blueprints\n\n  As a machinist user\n  I want to be able to leverage my blueprints\n  So that I can create models quickly and easily in my features\n  \n  Scenario: I create a spoon, and see if it looks right\n    Given a spoon exists\n    Then the spoon should be round\n\n  Scenario: I create a non round spoon, and see if it looks right\n    Given a spoon exists with round: false\n    Then the spoon should not be round\n\n  Scenario: I create a named spoon, and see if it has the name\n    Given a spoon exists with name: \"Pete\", round: false\n    Then a spoon should exist with name: \"Pete\"\n    And the spoon should not be round\n  \n  Scenario: I create 7 spoons of various roundness\n    Given 2 spoons exist with round: false\n    And 2 spoons exist with round: true\n    And a spoon exists with round: false\n    \n    Then the 1st spoon should not be round\n    And the 2nd spoon should not be round\n    And the 3rd spoon should be round\n    And the 4th spoon should be round\n    And the 5th spoon should not be round\n    \n    And 3 spoons should exist with round: false\n    And the 1st spoon should not be round\n    And the 2nd spoon should not be round\n    And the last spoon should not be round\n    \n    And 2 spoons should exist with round: true\n    And the first spoon should be round\n    And the last spoon should be round"
  },
  {
    "path": "vendor/plugins/pickle/features/step_definitions/email_steps.rb",
    "content": "# this file generated by script/generate pickle email\n\nActionMailer::Base.delivery_method = :test\nActionMailer::Base.perform_deliveries = true\n\nBefore do\n  ActionMailer::Base.deliveries.clear\nend\n\nGiven(/^all emails? (?:have|has) been delivered$/) do\n  ActionMailer::Base.deliveries.clear\nend\n\nGiven(/^(\\d)+ emails? should be delivered$/) do |count|\n  emails.size.should == count.to_i\nend\n\nThen(/^(\\d)+ emails? should be delivered to (.*)$/) do |count, to|\n  to =~ /^#{capture_model}$/ && to = model($1).email\n  emails(\"to: \\\"#{to}\\\"\").size.should == count.to_i\nend\n\nThen(/^(\\d)+ emails? should be delivered with #{capture_fields}$/) do |count, fields|\n  emails(fields).size.should == count.to_i\nend\n\nThen(/^#{capture_email} should be delivered to (.+)$/) do |email_ref, to|\n  to =~ /^#{capture_model}$/ && to = model($1).email\n  email(email_ref, \"to: \\\"#{to}\\\"\").should_not be_nil\nend\n\nThen(/^#{capture_email} should have #{capture_fields}$/) do |email_ref, fields|\n  email(email_ref, fields).should_not be_nil\nend\n\nThen(/^#{capture_email} should contain \"(.*)\"$/) do |email_ref, text|\n  email(email_ref).body.should =~ /#{text}/\nend\n\nThen(/^#{capture_email} should not contain \"(.*)\"$/) do |email_ref, text|\n  email(email_ref).body.should_not =~ /#{text}/\nend\n\nThen(/^#{capture_email} should link to (.+)$/) do |email_ref, page|\n  email(email_ref).body.should =~ /#{path_to(page)}/\nend\n\nThen(/^show me the emails?$/) do\n   save_and_open_emails\nend"
  },
  {
    "path": "vendor/plugins/pickle/features/step_definitions/extra_email_steps.rb",
    "content": "Given(/^an email \"(.*?)\" with body: \"(.*?)\" is delivered to (.+?)$/) do |subject, body, to|\n  Notifier.deliver_email(to, subject, body)\nend\n\nGiven(/^#{capture_model}'s email is delivered$/) do |model|\n  Notifier.deliver_user_email(model(model))\nend"
  },
  {
    "path": "vendor/plugins/pickle/features/step_definitions/fork_steps.rb",
    "content": "# example of making your own matcher with the pickle backend\nThen(/^#{capture_model} should be tine of #{capture_model}$/) do |tine, fork|\n  model(fork).tines.should include(model(tine))\nend"
  },
  {
    "path": "vendor/plugins/pickle/features/step_definitions/generator_steps.rb",
    "content": "Before do\n  `mv #{Rails.root}/features/ #{Rails.root}/features.orig/ > /dev/null 2>&1`\nend\n\nAfter do\n  `rm -rf #{Rails.root}/features`\n  `mv #{Rails.root}/features.orig/ #{Rails.root}/features/ > /dev/null 2>&1`\nend\n\nGiven(/^cucumber has been freshly generated$/) do\n  `cd #{Rails.root}; script/generate cucumber -f`\nend\n\nGiven(/^env\\.rb already requires (.+)$/) do |file|\n  File.open(\"#{Rails.root}/features/support/env.rb\", \"a\") do |env|\n    env << \"require '#{file}'\\n\"\n  end\nend\n\nWhen(/^I run \"(.*)\"$/) do |command|\n  @output = `cd #{Rails.root}; #{command}`\nend\n\nThen(/^I should see \"(.*)\"$/) do |text|\n  @output.should include(text)\nend\n\nThen(/^the file (.+?) should exist$/) do |file|\n  File.exist?(\"#{Rails.root}/#{file}\").should == true\nend\n\nThen(/^the file (.+?) should match \\/(.*?)\\/$/) do |file, regexp|\n  File.read(\"#{Rails.root}/#{file}\").should match(/#{regexp}/m)\nend\n\nThen(/^the file (.+?) should not match \\/(.*?)\\/$/) do |file, regexp|\n  File.read(\"#{Rails.root}/#{file}\").should_not match(/#{regexp}/m)\nend\n\nThen /^the file features\\/support\\/paths\\.rb should be identical to the local support\\/paths\\.rb$/ do\n  File.read(\"#{Rails.root}/features/support/paths.rb\").should == File.read(\"#{File.dirname(__FILE__)}/../support/paths.rb\")\nend\n"
  },
  {
    "path": "vendor/plugins/pickle/features/step_definitions/path_steps.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), \"..\", \"support\", \"paths\"))\n\nThen(/^(.+?) should match route \\/(.+?)$/) do |page, route|\n  regexp = route.gsub(/:(\\w*?)id/,'\\d+')\n  path_to(page).should =~ /#{regexp}/\nend\n\nWhen(/^I go to (.+)$/) do |page|\n  visit path_to(page)\nend\n\nThen(/^I should be at (.+)$/) do |page|\n  request.path.should =~ /#{path_to(page)}/\nend"
  },
  {
    "path": "vendor/plugins/pickle/features/step_definitions/pickle_steps.rb",
    "content": "# this file generated by script/generate pickle\n\n# create a model\nGiven(/^#{capture_model} exists?(?: with #{capture_fields})?$/) do |name, fields|\n  create_model(name, fields)\nend\n\n# create n models\nGiven(/^(\\d+) #{capture_plural_factory} exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|\n  count.to_i.times { create_model(plural_factory.singularize, fields) }\nend\n\n# create models from a table\nGiven /^the following #{capture_plural_factory} exist$/ do |plural_factory, table|\n  name = plural_factory.singularize\n  table.hashes.each { |hash| create_model(name, hash) }\nend\n\n# find a model\nThen(/^#{capture_model} should exist(?: with #{capture_fields})?$/) do |name, fields|\n  find_model(name, fields).should_not be_nil\nend\n\n# not find a model\nThen(/^#{capture_model} should not exist(?: with #{capture_fields})?$/) do |name, fields|\n  find_model(name, fields).should be_nil\nend\n\n# find exactly n models\nThen(/^(\\d+) #{capture_plural_factory} should exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|\n  find_models(plural_factory.singularize, fields).size.should == count.to_i\nend\n\n# assert model is in another model's has_many assoc\nThen(/^#{capture_model} should be (?:in|one of|amongst) #{capture_model}'s (\\w+)$/) do |target, owner, association|\n  model(owner).send(association).should include(model(target))\nend\n\n# assert model is not in another model's has_many assoc\nThen(/^#{capture_model} should not be (?:in|one of|amongst) #{capture_model}'s (\\w+)$/) do |target, owner, association|\n  model(owner).send(association).should_not include(model(target))\nend\n\n# assert model is another model's has_one/belongs_to assoc\nThen(/^#{capture_model} should be #{capture_model}'s (\\w+)$/) do |target, owner, association|\n  model(owner).send(association).should == model(target)\nend\n\n# assert model is not another model's has_one/belongs_to assoc\nThen(/^#{capture_model} should not be #{capture_model}'s (\\w+)$/) do |target, owner, association|\n  model(owner).send(association).should_not == model(target)\nend\n\n# assert model.predicate? \nThen(/^#{capture_model} should (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|\n  model(name).should send(\"be_#{predicate.gsub(' ', '_')}\")\nend\n\n# assert not model.predicate?\nThen(/^#{capture_model} should not (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|\n  model(name).should_not send(\"be_#{predicate.gsub(' ', '_')}\")\nend"
  },
  {
    "path": "vendor/plugins/pickle/features/support/env.rb",
    "content": "# Sets up the Rails environment for Cucumber\nENV[\"RAILS_ENV\"] = \"test\"\nrequire File.expand_path(File.dirname(__FILE__) + '../../../../../../config/environment')\nrequire 'cucumber/rails/world'\n\nrequire 'cucumber/formatter/unicode'\n\nrequire 'webrat'\n\nWebrat.configure do |config|\n  config.mode = :rails\nend\n\n\n# Comment out the next line if you're not using RSpec's matchers (should / should_not) in your steps.\nrequire 'cucumber/rails/rspec'\nrequire 'webrat/core/matchers'\n\nCucumber::Rails::World.use_transactional_fixtures = true\n\n# Pickle\nrequire 'pickle/world'\nrequire 'pickle/path/world'\nrequire 'pickle/email/world'\n\nPickle.configure do |c|\n  c.map 'I', :to => 'user: \"me\"'\n  c.map 'killah fork', :to => 'fancy fork: \"of cornwood\"'\nend\n\n# test app setup\n__APP__ = File.expand_path(File.join(File.dirname(__FILE__), '../app'))\nrequire \"#{__APP__}/app\"\nrequire \"#{__APP__}/factories\"\nrequire \"#{__APP__}/blueprints\"\n"
  },
  {
    "path": "vendor/plugins/pickle/features/support/paths.rb",
    "content": "module NavigationHelpers\n  # Maps a name to a path. Used by the\n  #\n  #   When /^I go to (.+)$/ do |page_name|\n  #\n  # step definition in webrat_steps.rb\n  #\n  def path_to(page_name)\n    case page_name\n    \n    when /the home\\s?page/\n      '/'\n    \n    # Add more mappings here.\n    # Here is a more fancy example:\n    #\n    #   when /^(.*)'s profile page$/i\n    #     user_profile_path(User.find_by_login($1))\n\n    # added by script/generate pickle path\n\n    when /^#{capture_model}(?:'s)? page$/                           # eg. the forum's page\n      path_to_pickle $1\n\n    when /^#{capture_model}(?:'s)? #{capture_model}(?:'s)? page$/   # eg. the forum's post's page\n      path_to_pickle $1, $2\n\n    when /^#{capture_model}(?:'s)? #{capture_model}'s (.+?) page$/  # eg. the forum's post's comments page\n      path_to_pickle $1, $2, :extra => $3                           #  or the forum's post's edit page\n\n    when /^#{capture_model}(?:'s)? (.+?) page$/                     # eg. the forum's posts page\n      path_to_pickle $1, :extra => $2                               #  or the forum's edit page\n\n    when /^the (.+?) page$/                                         # translate to named route\n      send \"#{$1.downcase.gsub(' ','_')}_path\"\n  \n    # end added by pickle path\n\n    else\n      raise \"Can't find mapping from \\\"#{page_name}\\\" to a path.\\n\" +\n        \"Now, go and add a mapping in #{__FILE__}\"\n    end\n  end\nend\n\nWorld(NavigationHelpers)\n"
  },
  {
    "path": "vendor/plugins/pickle/garlic.rb",
    "content": "garlic do\n  repo 'rails', :url => 'git://github.com/rails/rails'\n  repo 'rspec', :url => 'git://github.com/dchelimsky/rspec'\n  repo 'rspec-rails', :url => 'git://github.com/dchelimsky/rspec-rails'\n  repo 'factory_girl', :url => 'git://github.com/thoughtbot/factory_girl'\n  repo 'machinist', :url => 'git://github.com/notahat/machinist'\n  repo 'cucumber', :url => 'git://github.com/aslakhellesoy/cucumber'\n  repo 'webrat', :url => 'git://github.com/brynary/webrat'\n  repo 'pickle', :path => '.'\n\n  ['2-3-stable', '2-2-stable', '2-1-stable'].each do |rails|\n  \n    target rails, :tree_ish => \"origin/#{rails}\" do\n      prepare do\n        plugin 'pickle', :clone => true\n        plugin 'rspec'\n        plugin 'rspec-rails' do\n          `script/generate rspec -f`\n        end\n        plugin 'factory_girl'\n        plugin 'cucumber' do\n          `script/generate cucumber -f`\n        end\n        plugin 'machinist'\n        plugin 'webrat'\n      end\n  \n      run do\n        cd \"vendor/plugins/pickle\" do\n          sh \"rake rcov:verify && rake features\"\n        end\n      end\n    end\n    \n  end\nend\n"
  },
  {
    "path": "vendor/plugins/pickle/init.rb",
    "content": ""
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/adapter.rb",
    "content": "module Pickle\n  # Abstract Factory adapter class, if you have a factory type setup, you\n  # can easily create an adaptor to make it work with Pickle.\n  #\n  # The factory adaptor must have a #factories class method that returns \n  # its instances, and each instance must respond to:\n  #\n  #   #name : identifies the factory by name (default is attr_reader)\n  #   #klass : returns the associated model class for this factory (default is attr_reader)\n  #   #create(attrs = {}) : returns a newly created object\n  class Adapter\n    attr_reader :name, :klass\n    \n    def self.factories\n      raise NotImplementedError, \"return an array of factory adapter objects\"\n    end\n  \n    def create(attrs = {})\n      raise NotImplementedError, \"create and return an object with the given attributes\"\n    end\n  \n    cattr_writer :model_classes\n    self.model_classes = nil\n    \n    def self.model_classes\n      # remove abstract, framework, and non-table classes\n      @@model_classes ||= ::ActiveRecord::Base.send(:subclasses).reject do |klass|\n        klass.abstract_class? || !klass.table_exists? ||\n         (defined?(CGI::Session::ActiveRecordStore::Session) && klass == CGI::Session::ActiveRecordStore::Session) ||\n         (defined?(::ActiveRecord::SessionStore::Session) && klass == ::ActiveRecord::SessionStore::Session)\n      end\n    end\n  \n    # machinist adapter\n    class Machinist < Adapter\n      def self.factories\n        factories = []\n        model_classes.each do |klass|\n          if blueprints = klass.instance_variable_get('@blueprints')\n            blueprints.keys.each {|blueprint| factories << new(klass, blueprint)}\n          end\n        end\n        factories\n      end\n      \n      def initialize(klass, blueprint)\n        @klass, @blueprint = klass, blueprint\n        @name = @klass.name.underscore.gsub('/','_')\n        @name = \"#{@blueprint}_#{@name}\" unless @blueprint == :master\n      end\n      \n      def create(attrs = {})\n        @klass.send(:make, @blueprint, attrs)\n      end\n    end\n    \n    # factory-girl adapter\n    class FactoryGirl < Adapter\n      def self.factories\n        (::Factory.factories.values rescue []).map {|factory| new(factory)}\n      end\n      \n      def initialize(factory)\n        @klass, @name = factory.build_class, factory.factory_name.to_s\n      end\n    \n      def create(attrs = {})\n        Factory.create(@name, attrs)\n      end\n    end\n        \n    # fallback active record adapter\n    class ActiveRecord < Adapter\n      def self.factories\n        model_classes.map {|klass| new(klass) }\n      end\n\n      def initialize(klass)\n        @klass, @name = klass, klass.name.underscore.gsub('/','_')\n      end\n\n      def create(attrs = {})\n        @klass.send(:create!, attrs)\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/config.rb",
    "content": "require 'ostruct'\n\nmodule Pickle\n  class Config\n    attr_writer :adapters, :factories, :mappings, :predicates\n    \n    def initialize(&block)\n      configure(&block) if block_given?\n    end\n    \n    def configure(&block)\n      yield(self)\n    end\n    \n    def adapters\n      @adapters ||= [:machinist, :factory_girl, :active_record]\n    end\n    \n    def adapter_classes\n      adapters.map {|a| a.is_a?(Class) ? a : \"pickle/adapter/#{a}\".classify.constantize}\n    end\n    \n    def factories\n      @factories ||= adapter_classes.reverse.inject({}) do |factories, adapter|\n        factories.merge(adapter.factories.inject({}){|h, f| h.merge(f.name => f)})\n      end\n    end\n    \n    def predicates\n      @predicates ||= Pickle::Adapter.model_classes.map do |k|\n        k.public_instance_methods.select{|m| m =~ /\\?$/} + k.column_names\n      end.flatten.uniq\n    end\n    \n    def mappings\n      @mappings ||= []\n    end\n    \n    # Usage: map 'me', 'myself', 'I', :to => 'user: \"me\"'\n    def map(*args)\n      options = args.extract_options!\n      raise ArgumentError, \"Usage: map 'search' [, 'search2', ...] :to => 'replace'\" unless args.any? && options[:to].is_a?(String)\n      args.each do |search|\n        self.mappings << OpenStruct.new(:search => search, :replacement => options[:to])\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/email/parser.rb",
    "content": "module Pickle\n  module Email\n    # add ability to parse emails\n    module Parser\n      def match_email\n        \"(?:#{match_prefix}?(?:#{match_index} )?email)\"\n      end\n\n      def capture_email\n        \"(#{match_email})\"\n      end\n      \n      def capture_index_in_email\n        \"(?:#{match_prefix}?(?:#{capture_index} )?email)\"\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/email/world.rb",
    "content": "require 'pickle'\nrequire 'pickle/email'\nrequire 'pickle/email/parser'\n\n# add email parser expressions\nPickle::Parser.send :include, Pickle::Email::Parser\n\nWorld(Pickle::Email)\n\n# shortcuts for use in step regexps\nclass << self\n  delegate :capture_email, :to => 'Pickle.parser'\nend"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/email.rb",
    "content": "module Pickle\n  module Email\n    # return the deliveries array, optionally selected by the passed fields\n    def emails(fields = nil)\n      @emails = ActionMailer::Base.deliveries.select {|m| email_has_fields?(m, fields)}\n    end\n\n    def email(ref, fields = nil)\n      (match = ref.match(/^#{capture_index_in_email}$/)) or raise ArgumentError, \"argument should match #{match_email}\"\n      @emails or raise RuntimeError, \"Call #emails before calling #email\"\n      index = parse_index(match[1])\n      email_has_fields?(@emails[index], fields) ? @emails[index] : nil\n    end\n    \n    def email_has_fields?(email, fields)\n      parse_fields(fields).each do |key, val|\n        return false unless (Array(email.send(key)) & Array(val)).any?\n      end\n      true\n    end\n    \n  protected\n    # Saves the emails out to RAILS_ROOT/tmp/ and opens it in the default\n    # web browser if on OS X. (depends on webrat)\n    def save_and_open_emails\n      emails_to_open = @emails || emails\n      filename = \"#{RAILS_ROOT}/tmp/webrat-email-#{Time.now.to_i}.html\"\n      File.open(filename, \"w\") do |f|\n        emails_to_open.each_with_index do |e, i|\n          f.write \"<h1>Email #{i+1}</h1><pre>#{e}</pre><hr />\"\n        end\n      end\n      open_in_browser(filename)\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/parser/matchers.rb",
    "content": "module Pickle\n  class Parser\n    module Matchers\n      def match_ordinal\n        '(?:\\d+(?:st|nd|rd|th))'\n      end\n  \n      def match_index\n        \"(?:first|last|#{match_ordinal})\"\n      end\n  \n      def match_prefix\n        '(?:(?:a|an|another|the|that) )'\n      end\n  \n      def match_quoted\n        '(?:[^\\\\\"]|\\\\.)*'\n      end\n  \n      def match_label\n        \"(?::? \\\"#{match_quoted}\\\")\"\n      end\n\n      def match_value\n        \"(?:\\\"#{match_quoted}\\\"|true|false|[+-]?\\\\d+(?:\\\\.\\\\d+)?)\"\n      end\n\n      def match_field\n        \"(?:\\\\w+: #{match_value})\"\n      end\n  \n      def match_fields\n        \"(?:#{match_field}, )*#{match_field}\"\n      end\n  \n      def match_mapping\n        \"(?:#{config.mappings.map(&:search).join('|')})\"\n      end\n  \n      def match_factory\n        \"(?:#{config.factories.keys.map{|n| n.gsub('_','[_ ]')}.join('|')})\"\n      end\n      \n      def match_plural_factory\n        \"(?:#{config.factories.keys.map{|n| n.pluralize.gsub('_','[_ ]')}.join('|')})\"\n      end\n      \n      def match_indexed_model\n        \"(?:(?:#{match_index} )?#{match_factory})\"\n      end\n  \n      def match_labeled_model\n        \"(?:#{match_factory}#{match_label})\"\n      end\n  \n      def match_model\n        \"(?:#{match_mapping}|#{match_prefix}?(?:#{match_indexed_model}|#{match_labeled_model}))\"\n      end\n  \n      def match_predicate\n        \"(?:#{config.predicates.map{|m| m.to_s.sub(/\\?$/,'').gsub('_','[_ ]')}.join('|')})\"\n      end\n      \n      # create capture analogues of match methods\n      instance_methods.select{|m| m =~ /^match_/}.each do |method|\n        eval <<-end_eval                   \n          def #{method.to_s.sub('match_', 'capture_')}         # def capture_field\n            \"(\" + #{method} + \")\"                         #   \"(\" + match_field + \")\"\n          end                                             # end\n        end_eval\n      end\n  \n      # special capture methods\n      def capture_number_in_ordinal\n        '(?:(\\d+)(?:st|nd|rd|th))'\n      end\n  \n      def capture_name_in_label\n        \"(?::? \\\"(#{match_quoted})\\\")\"\n      end\n  \n      def capture_key_and_value_in_field\n        \"(?:(\\\\w+): #{capture_value})\"\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/parser.rb",
    "content": "require 'pickle/parser/matchers'\n\nmodule Pickle\n  class Parser\n    include Matchers\n    \n    attr_reader :config\n    \n    def initialize(options = {})\n      @config = options[:config] || raise(ArgumentError, \"Parser.new requires a :config\")\n    end\n    \n    # given a string like 'foo: \"bar\", bar: \"baz\"' returns {\"foo\" => \"bar\", \"bar\" => \"baz\"}\n    def parse_fields(fields)\n      if fields.blank?\n        {}\n      elsif fields =~ /^#{match_fields}$/\n        fields.scan(/(#{match_field})(?:,|$)/).inject({}) do |m, match|\n          m.merge(parse_field(match[0]))\n        end\n      else\n        raise ArgumentError, \"The fields string is not in the correct format.\\n\\n'#{fields}' did not match: #{match_fields}\" \n      end\n    end\n    \n    # given a string like 'foo: expr' returns {key => value}\n    def parse_field(field)\n      if field =~ /^#{capture_key_and_value_in_field}$/\n        { $1 => eval($2) }\n      else\n        raise ArgumentError, \"The field argument is not in the correct format.\\n\\n'#{field}' did not match: #{match_field}\"\n      end\n    end\n    \n    # returns really underscored name\n    def canonical(str)\n      str.to_s.underscore.gsub(' ','_').gsub('/','_')\n    end\n    \n    # return [factory_name, name or integer index]\n    def parse_model(model_name)\n      apply_mappings!(model_name)\n      if /#{capture_index} #{capture_factory}$/ =~ model_name\n        [canonical($2), parse_index($1)]\n      elsif /#{capture_factory}#{capture_name_in_label}?$/ =~ model_name\n        [canonical($1), canonical($2)]\n      end\n    end\n  \n    def parse_index(index)\n      case index\n      when nil, '', 'last' then -1\n      when /#{capture_number_in_ordinal}/ then $1.to_i - 1\n      when 'first' then 0\n      end\n    end\n\n  private\n    def apply_mappings!(string)\n      config.mappings.each do |mapping|\n        string.sub! /^#{mapping.search}$/, mapping.replacement\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/path/world.rb",
    "content": "require 'pickle'\nrequire 'pickle/path'\n\n# make world pickle/path aware\nWorld(Pickle::Path)"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/path.rb",
    "content": "module Pickle\n  module Path\n    # given args of pickle model name, and an optional extra action, or segment, will attempt to find\n    # a matching named route\n    #\n    #   path_to_pickle 'the user', :action => 'edit'       # => /users/3/edit\n    #   path_to_pickle 'the user', 'the comment'           # => /users/3/comments/1\n    #   path_to_pickle 'the user', :segment => 'comments'  # => /users/3/comments\n    #\n    # If you don;t know if the 'extra' part of the path is an action or a segment, then just\n    # pass it as 'extra' and this method will run through the possibilities\n    #\n    #   path_to_pickle 'the user', :extra => 'new comment' # => /users/3/comments/new\n    def path_to_pickle(*pickle_names)\n      options = pickle_names.extract_options!\n      models = pickle_names.map{|m| model!(m)}\n      if options[:extra]\n        parts = options[:extra].underscore.gsub(' ','_').split(\"_\")\n        find_pickle_path_using_action_segment_combinations(models, parts)\n      else\n        pickle_path_for_models_action_segment(models, options[:action], options[:segment])\n      end or raise \"Could not figure out a path for #{pickle_names.inspect} #{options.inspect}\"\n    end\n    \n  protected\n    def find_pickle_path_using_action_segment_combinations(models, parts)\n      path = nil\n      (0..parts.length).each do |idx|\n        action  = parts.slice(0, idx).join('_')\n        segment = parts.slice(idx, parts.length).join('_')\n        path = pickle_path_for_models_action_segment(models, action, segment) and break\n      end\n      path\n    end\n    \n    def pickle_path_for_models_action_segment(models, action, segment)\n      action.blank? or action = action.downcase.gsub(' ','_')\n      segment.blank? or segment = segment.downcase.gsub(' ','_')\n      model_names = models.map{|m| m.class.name.underscore}.join(\"_\")\n      parts = [action, model_names, segment].reject(&:blank?)\n      send(\"#{parts.join('_')}_path\", *models) rescue nil\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/session/parser.rb",
    "content": "module Pickle\n  module Session\n    # add ability to parse model names as fields, using a session\n    module Parser\n      def self.included(parser_class)\n        parser_class.alias_method_chain :parse_field, :model\n      end\n\n      attr_accessor :session\n\n      def match_field\n        \"(?:\\\\w+: (?:#{match_model}|#{match_value}))\"\n      end\n\n      def parse_field_with_model(field)\n        if session && field =~ /^(\\w+): #{capture_model}$/\n          {$1 => session.model($2)}\n        else\n          parse_field_without_model(field)\n        end\n      end    \n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/session.rb",
    "content": "module Pickle\n  module Session\n    class << self\n      def included(world_class)\n        proxy_to_pickle_parser(world_class)\n      end\n      \n      def extended(world_object)\n        proxy_to_pickle_parser(class << world_object; self; end) # metaclass is not 2.1 compatible\n      end\n      \n    protected\n      def proxy_to_pickle_parser(world_class)\n        world_class.class_eval do\n          unless methods.include?('method_missing_with_pickle_parser')\n            alias_method_chain :method_missing, :pickle_parser\n            alias_method_chain :respond_to?, :pickle_parser\n          end\n        end\n      end\n    end\n    \n    def create_model(a_model_name, fields = nil)\n      factory, label = *parse_model(a_model_name)\n      raise ArgumentError, \"Can't create with an ordinal (e.g. 1st user)\" if label.is_a?(Integer)\n      fields = fields.instance_of?(Hash) ? fields.dup : parse_fields(fields)\n      record = pickle_config.factories[factory].create(fields)\n      store_model(factory, label, record)\n    end\n\n    def find_model(a_model_name, fields = nil)\n      factory, name = *parse_model(a_model_name)\n      raise ArgumentError, \"Can't find a model with an ordinal (e.g. 1st user)\" if name.is_a?(Integer)\n      model_class = pickle_config.factories[factory].klass\n      if record = model_class.find(:first, :conditions => convert_models_to_attributes(model_class, parse_fields(fields)))\n        store_model(factory, name, record)\n      end\n    end\n    \n    def find_models(factory, fields = nil)\n      models_by_index(factory).clear\n      model_class = pickle_config.factories[factory].klass\n      records = model_class.find(:all, :conditions => convert_models_to_attributes(model_class, parse_fields(fields)))\n      records.each {|record| store_model(factory, nil, record)}\n    end\n      \n    # return the original model stored by create_model or find_model\n    def created_model(name)\n      factory, name_or_index = *parse_model(name)\n      \n      if name_or_index.blank?\n        models_by_index(factory).last\n      elsif name_or_index.is_a?(Integer)\n        models_by_index(factory)[name_or_index]\n      else\n        models_by_name(factory)[name_or_index] or raise \"model: #{name} does not refer to known model in this scenario\"\n      end\n    end\n\n    # predicate version which raises no errors\n    def created_model?(name)\n      (created_model(name) rescue nil) ? true : false\n    end\n    \n    # return a newly selected model\n    def model(name)\n      (model = created_model(name)) && model.class.find(model.id)\n    end\n    \n    # predicate version which raises no errors\n    def model?(name)\n      (model(name) rescue nil) ? true : false\n    end\n    \n    # like model, but raise an error if it can't be found\n    def model!(name)\n      model(name) or raise \"Can't find pickle model: '#{name}' in this scenario\"\n    end\n    \n    # like created_model, but raise an error if it can't be found\n    def created_model!(name)\n      created_model(name) or raise \"Can't find pickle model: '#{name}' in this scenario\"\n    end\n    \n    # return all original models of specified type\n    def created_models(factory)\n      models_by_index(factory)\n    end\n      \n    # return all models of specified type (freshly selected from the database)\n    def models(factory)\n      created_models(factory).map{|model| model.class.find(model.id) }\n    end\n    \n    def respond_to_with_pickle_parser?(method, include_private = false)\n      respond_to_without_pickle_parser?(method, include_private) || pickle_parser.respond_to?(method, include_private)\n    end\n    \n  protected\n    def method_missing_with_pickle_parser(method, *args, &block)\n      if pickle_parser.respond_to?(method)\n        pickle_parser.send(method, *args, &block)\n      else\n        method_missing_without_pickle_parser(method, *args, &block)\n      end\n    end\n    \n    def pickle_parser=(parser)\n      parser.session = self\n      @pickle_parser = parser\n    end\n    \n    def pickle_parser\n      @pickle_parser or self.pickle_parser = Pickle.parser\n    end\n    \n    def pickle_config\n      pickle_parser.config\n    end\n\n    def convert_models_to_attributes(ar_class, attrs)\n      attrs.each do |key, val|\n        if val.is_a?(ActiveRecord::Base) && ar_class.column_names.include?(\"#{key}_id\")\n          attrs[\"#{key}_id\"] = val.id\n          attrs[\"#{key}_type\"] = val.class.name if ar_class.column_names.include?(\"#{key}_type\")\n          attrs.delete(key)\n        end\n      end\n    end\n    \n    def models_by_name(factory)\n      @models_by_name ||= {}\n      @models_by_name[pickle_parser.canonical(factory)] ||= {}\n    end\n    \n    def models_by_index(factory)\n      @models_by_index ||= {}\n      @models_by_index[pickle_parser.canonical(factory)] ||= []\n    end\n    \n    # if the factory name != the model name, store under both names\n    def store_model(factory, name, record)\n      store_record(record.class.name, name, record) unless pickle_parser.canonical(factory) == pickle_parser.canonical(record.class.name)\n      store_record(factory, name, record)\n    end\n    \n    def store_record(factory, name, record)\n      models_by_name(factory)[name] = record\n      models_by_index(factory) << record\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/version.rb",
    "content": "module Pickle\n  module Version\n    String = File.read(File.dirname(File.dirname(__FILE__)) + '/../VERSION').strip\n    Major, Minor, Patch = String.split('.').map{|i| i.to_i}\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle/world.rb",
    "content": "require 'pickle'\n\n# make cucumber world pickle aware\nWorld(Pickle::Session)\n\n# shortcuts to regexps for use in step definition regexps\nclass << self\n  delegate :capture_model, :capture_fields, :capture_factory, :capture_plural_factory, :capture_predicate, :to => 'Pickle.parser'\nend\n"
  },
  {
    "path": "vendor/plugins/pickle/lib/pickle.rb",
    "content": "require 'active_support'\nrequire 'pickle/version'\nrequire 'pickle/adapter'\nrequire 'pickle/config'\nrequire 'pickle/parser'\nrequire 'pickle/session'\nrequire 'pickle/session/parser'\n\n# make the parser aware of models in the session (for fields refering to models)\nPickle::Parser.send :include, Pickle::Session::Parser\n\nmodule Pickle\n  class << self\n    def config\n      @config ||= Config.new\n    end\n    \n    def configure(&block)\n      config.configure(&block)\n    end\n  \n    def parser(options = {})\n      @parser ||= Parser.new({:config => config}.merge(options))\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/pickle.gemspec",
    "content": "# Generated by jeweler\n# DO NOT EDIT THIS FILE\n# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`\n# -*- encoding: utf-8 -*-\n\nGem::Specification.new do |s|\n  s.name = %q{pickle}\n  s.version = \"0.1.22\"\n\n  s.required_rubygems_version = Gem::Requirement.new(\">= 0\") if s.respond_to? :required_rubygems_version=\n  s.authors = [\"Ian White\"]\n  s.date = %q{2009-11-07}\n  s.description = %q{Easy model creation and reference in your cucumber features}\n  s.email = %q{ian.w.white@gmail.com}\n  s.extra_rdoc_files = [\n    \"README.rdoc\"\n  ]\n  s.files = [\n    \".gitignore\",\n     \"History.txt\",\n     \"License.txt\",\n     \"README.rdoc\",\n     \"Rakefile\",\n     \"Todo.txt\",\n     \"VERSION\",\n     \"features/app/app.rb\",\n     \"features/app/blueprints.rb\",\n     \"features/app/factories.rb\",\n     \"features/app/views/notifier/email.erb\",\n     \"features/app/views/notifier/user_email.erb\",\n     \"features/email/email.feature\",\n     \"features/generator/generators.feature\",\n     \"features/path/models_page.feature\",\n     \"features/path/named_route_page.feature\",\n     \"features/pickle/create_from_active_record.feature\",\n     \"features/pickle/create_from_factory_girl.feature\",\n     \"features/pickle/create_from_machinist.feature\",\n     \"features/step_definitions/email_steps.rb\",\n     \"features/step_definitions/extra_email_steps.rb\",\n     \"features/step_definitions/fork_steps.rb\",\n     \"features/step_definitions/generator_steps.rb\",\n     \"features/step_definitions/path_steps.rb\",\n     \"features/step_definitions/pickle_steps.rb\",\n     \"features/support/env.rb\",\n     \"features/support/paths.rb\",\n     \"garlic.rb\",\n     \"init.rb\",\n     \"lib/pickle.rb\",\n     \"lib/pickle/adapter.rb\",\n     \"lib/pickle/config.rb\",\n     \"lib/pickle/email.rb\",\n     \"lib/pickle/email/parser.rb\",\n     \"lib/pickle/email/world.rb\",\n     \"lib/pickle/parser.rb\",\n     \"lib/pickle/parser/matchers.rb\",\n     \"lib/pickle/path.rb\",\n     \"lib/pickle/path/world.rb\",\n     \"lib/pickle/session.rb\",\n     \"lib/pickle/session/parser.rb\",\n     \"lib/pickle/version.rb\",\n     \"lib/pickle/world.rb\",\n     \"pickle.gemspec\",\n     \"rails_generators/pickle/pickle_generator.rb\",\n     \"rails_generators/pickle/templates/email_steps.rb\",\n     \"rails_generators/pickle/templates/env.rb\",\n     \"rails_generators/pickle/templates/paths.rb\",\n     \"rails_generators/pickle/templates/pickle_steps.rb\",\n     \"spec/lib/pickle_adapter_spec.rb\",\n     \"spec/lib/pickle_config_spec.rb\",\n     \"spec/lib/pickle_email_parser_spec.rb\",\n     \"spec/lib/pickle_email_spec.rb\",\n     \"spec/lib/pickle_parser_matchers_spec.rb\",\n     \"spec/lib/pickle_parser_spec.rb\",\n     \"spec/lib/pickle_path_spec.rb\",\n     \"spec/lib/pickle_session_spec.rb\",\n     \"spec/lib/pickle_spec.rb\",\n     \"spec/spec_helper.rb\"\n  ]\n  s.homepage = %q{http://github.com/ianwhite/pickle/tree}\n  s.rdoc_options = [\"--charset=UTF-8\"]\n  s.require_paths = [\"lib\"]\n  s.rubygems_version = %q{1.3.5}\n  s.summary = %q{Easy model creation and reference in your cucumber features}\n  s.test_files = [\n    \"spec/lib/pickle_adapter_spec.rb\",\n     \"spec/lib/pickle_config_spec.rb\",\n     \"spec/lib/pickle_email_parser_spec.rb\",\n     \"spec/lib/pickle_email_spec.rb\",\n     \"spec/lib/pickle_parser_matchers_spec.rb\",\n     \"spec/lib/pickle_parser_spec.rb\",\n     \"spec/lib/pickle_path_spec.rb\",\n     \"spec/lib/pickle_session_spec.rb\",\n     \"spec/lib/pickle_spec.rb\",\n     \"spec/spec_helper.rb\"\n  ]\n\n  if s.respond_to? :specification_version then\n    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION\n    s.specification_version = 3\n\n    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then\n    else\n    end\n  else\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/pickle/rails_generators/pickle/pickle_generator.rb",
    "content": "class PickleGenerator < Rails::Generator::Base\n  def initialize(args, options)\n    super(args, options)\n    File.exists?('features/support/env.rb') or raise \"features/support/env.rb not found, try running script/generate cucumber\"\n    @generate_email_steps = args.include?('email')\n    if @generate_path_steps = args.include?('path') || args.include?('paths')\n      File.exists?('features/support/paths.rb') or raise \"features/support/paths.rb not found, is your cucumber up to date?\"\n    end\n  end\n  \n  def manifest\n    record do |m|\n      m.directory File.join('features/step_definitions')\n      \n      current_env = File.read('features/support/env.rb')\n      env_assigns = {:current_env => current_env, :pickle => false, :pickle_path => false, :pickle_email => false}\n      \n      if @generate_path_steps\n        env_assigns[:pickle_path] = true unless current_env.include?(\"require 'pickle/path/world'\")\n        current_paths = File.read('features/support/paths.rb')\n        unless current_paths.include?('#{capture_model}')\n          if current_paths =~ /^(.*)(\\n\\s+else\\n\\s+raise \"Can't find.*\".*$)/m\n            env_assigns[:current_paths_header] = $1\n            env_assigns[:current_paths_footer] = $2\n            m.template 'paths.rb', File.join('features/support', \"paths.rb\"), :assigns => env_assigns, :collision => :force\n          end\n        end\n      end\n      \n      if @generate_email_steps\n        env_assigns[:pickle_email] = true unless current_env.include?(\"require 'pickle/email/world'\")\n        m.template 'email_steps.rb', File.join('features/step_definitions', \"email_steps.rb\") \n      end\n      \n      env_assigns[:pickle] = true unless current_env.include?(\"require 'pickle/world'\")\n      m.template 'pickle_steps.rb', File.join('features/step_definitions', \"pickle_steps.rb\")\n      \n      m.template 'env.rb', File.join('features/support', \"env.rb\"), :assigns => env_assigns, :collision => :force\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/rails_generators/pickle/templates/email_steps.rb",
    "content": "# this file generated by script/generate pickle email\n\nActionMailer::Base.delivery_method = :test\nActionMailer::Base.perform_deliveries = true\n\nBefore do\n  ActionMailer::Base.deliveries.clear\nend\n\nGiven(/^all emails? (?:have|has) been delivered$/) do\n  ActionMailer::Base.deliveries.clear\nend\n\nGiven(/^(\\d)+ emails? should be delivered$/) do |count|\n  emails.size.should == count.to_i\nend\n\nThen(/^(\\d)+ emails? should be delivered to (.*)$/) do |count, to|\n  to =~ /^#{capture_model}$/ && to = model($1).email\n  emails(\"to: \\\"#{to}\\\"\").size.should == count.to_i\nend\n\nThen(/^(\\d)+ emails? should be delivered with #{capture_fields}$/) do |count, fields|\n  emails(fields).size.should == count.to_i\nend\n\nThen(/^#{capture_email} should be delivered to (.+)$/) do |email_ref, to|\n  to =~ /^#{capture_model}$/ && to = model($1).email\n  email(email_ref, \"to: \\\"#{to}\\\"\").should_not be_nil\nend\n\nThen(/^#{capture_email} should have #{capture_fields}$/) do |email_ref, fields|\n  email(email_ref, fields).should_not be_nil\nend\n\nThen(/^#{capture_email} should contain \"(.*)\"$/) do |email_ref, text|\n  email(email_ref).body.should =~ /#{text}/\nend\n\nThen(/^#{capture_email} should not contain \"(.*)\"$/) do |email_ref, text|\n  email(email_ref).body.should_not =~ /#{text}/\nend\n\nThen(/^#{capture_email} should link to (.+)$/) do |email_ref, page|\n  email(email_ref).body.should =~ /#{path_to(page)}/\nend\n\nThen(/^show me the emails?$/) do\n   save_and_open_emails\nend"
  },
  {
    "path": "vendor/plugins/pickle/rails_generators/pickle/templates/env.rb",
    "content": "<%= current_env -%>\n<%- if pickle -%>\nrequire 'pickle/world'\n# Example of configuring pickle:\n#\n# Pickle.configure do |config|\n#   config.adapters = [:machinist]\n#   config.map 'I', 'myself', 'me', 'my', :to => 'user: \"me\"'\n# end\n<%- end -%>\n<%- if pickle_path -%>require 'pickle/path/world'\n<%- end -%>\n<%- if pickle_email -%>require 'pickle/email/world'\n<%- end -%>"
  },
  {
    "path": "vendor/plugins/pickle/rails_generators/pickle/templates/paths.rb",
    "content": "<%= current_paths_header %>\n    # added by script/generate pickle path\n\n    when /^#{capture_model}(?:'s)? page$/                           # eg. the forum's page\n      path_to_pickle $1\n\n    when /^#{capture_model}(?:'s)? #{capture_model}(?:'s)? page$/   # eg. the forum's post's page\n      path_to_pickle $1, $2\n\n    when /^#{capture_model}(?:'s)? #{capture_model}'s (.+?) page$/  # eg. the forum's post's comments page\n      path_to_pickle $1, $2, :extra => $3                           #  or the forum's post's edit page\n\n    when /^#{capture_model}(?:'s)? (.+?) page$/                     # eg. the forum's posts page\n      path_to_pickle $1, :extra => $2                               #  or the forum's edit page\n\n    when /^the (.+?) page$/                                         # translate to named route\n      send \"#{$1.downcase.gsub(' ','_')}_path\"\n  \n    # end added by pickle path\n<%= current_paths_footer %>"
  },
  {
    "path": "vendor/plugins/pickle/rails_generators/pickle/templates/pickle_steps.rb",
    "content": "# this file generated by script/generate pickle\n\n# create a model\nGiven(/^#{capture_model} exists?(?: with #{capture_fields})?$/) do |name, fields|\n  create_model(name, fields)\nend\n\n# create n models\nGiven(/^(\\d+) #{capture_plural_factory} exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|\n  count.to_i.times { create_model(plural_factory.singularize, fields) }\nend\n\n# create models from a table\nGiven /^the following #{capture_plural_factory} exist$/ do |plural_factory, table|\n  name = plural_factory.singularize\n  table.hashes.each { |hash| create_model(name, hash) }\nend\n\n# find a model\nThen(/^#{capture_model} should exist(?: with #{capture_fields})?$/) do |name, fields|\n  find_model(name, fields).should_not be_nil\nend\n\n# not find a model\nThen(/^#{capture_model} should not exist(?: with #{capture_fields})?$/) do |name, fields|\n  find_model(name, fields).should be_nil\nend\n\n# find exactly n models\nThen(/^(\\d+) #{capture_plural_factory} should exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|\n  find_models(plural_factory.singularize, fields).size.should == count.to_i\nend\n\n# assert model is in another model's has_many assoc\nThen(/^#{capture_model} should be (?:in|one of|amongst) #{capture_model}'s (\\w+)$/) do |target, owner, association|\n  model(owner).send(association).should include(model(target))\nend\n\n# assert model is not in another model's has_many assoc\nThen(/^#{capture_model} should not be (?:in|one of|amongst) #{capture_model}'s (\\w+)$/) do |target, owner, association|\n  model(owner).send(association).should_not include(model(target))\nend\n\n# assert model is another model's has_one/belongs_to assoc\nThen(/^#{capture_model} should be #{capture_model}'s (\\w+)$/) do |target, owner, association|\n  model(owner).send(association).should == model(target)\nend\n\n# assert model is not another model's has_one/belongs_to assoc\nThen(/^#{capture_model} should not be #{capture_model}'s (\\w+)$/) do |target, owner, association|\n  model(owner).send(association).should_not == model(target)\nend\n\n# assert model.predicate? \nThen(/^#{capture_model} should (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|\n  model(name).should send(\"be_#{predicate.gsub(' ', '_')}\")\nend\n\n# assert not model.predicate?\nThen(/^#{capture_model} should not (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|\n  model(name).should_not send(\"be_#{predicate.gsub(' ', '_')}\")\nend"
  },
  {
    "path": "vendor/plugins/pickle/spec/lib/pickle_adapter_spec.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))\n\ndescribe Pickle::Adapter do\n  it \".factories should raise NotImplementedError\" do\n    lambda{ Pickle::Adapter.factories }.should raise_error(NotImplementedError)\n  end\n  \n  it \"#create should raise NotImplementedError\" do\n    lambda{ Pickle::Adapter.new.create }.should raise_error(NotImplementedError)\n  end\n  \n  describe \".model_classes\" do\n    before do\n      Pickle::Adapter.model_classes = nil\n    end\n    \n    if defined?(CGI::Session::ActiveRecordStore::Session)\n      it \"should not include CGI::Session::ActiveRecordStore::Session\" do\n        Pickle::Adapter.model_classes.should_not include(CGI::Session::ActiveRecordStore)\n      end\n    end\n  \n    if defined?(ActiveRecord::SessionStore::Session)\n      it \"should not include ActiveRecord::SessionStore::Session\" do\n        Pickle::Adapter.model_classes.should_not include(ActiveRecord::SessionStore::Session)\n      end\n    end\n  \n    it \"should not include classes without a table\" do\n      klass = Class.new(ActiveRecord::Base)\n      Pickle::Adapter.model_classes.should_not include(klass)\n    end\n\n    it \"should not include abstract classes without a table\" do\n      klass = Class.new(ActiveRecord::Base)\n      klass.abstract_class = true\n      Pickle::Adapter.model_classes.should_not include(klass)\n    end\n  end\n  \n  describe \"adapters: \" do\n    before do\n      @klass1 = returning(Class.new(ActiveRecord::Base)) {|k| k.stub!(:name).and_return('One')}\n      @klass2 = returning(Class.new(ActiveRecord::Base)) {|k| k.stub!(:name).and_return('One::Two')}\n      @klass3 = returning(Class.new(ActiveRecord::Base)) {|k| k.stub!(:name).and_return('Three')}\n    end\n    \n    describe 'ActiveRecord' do\n      before do\n        Pickle::Adapter::ActiveRecord.stub!(:model_classes).and_return([@klass1, @klass2, @klass3])\n      end\n      \n      it \".factories should create one for each active record class\" do\n        Pickle::Adapter::ActiveRecord.should_receive(:new).with(@klass1).once\n        Pickle::Adapter::ActiveRecord.should_receive(:new).with(@klass2).once\n        Pickle::Adapter::ActiveRecord.should_receive(:new).with(@klass3).once\n        Pickle::Adapter::ActiveRecord.factories\n      end\n      \n      describe \".new(Class)\" do\n        before do\n          @factory = Pickle::Adapter::ActiveRecord.new(@klass2)\n        end\n      \n        it \"should have underscored (s/_) name of Class as #name\" do\n          @factory.name.should == 'one_two'\n        end\n      \n        it \"#create(attrs) should call Class.create!(attrs)\" do\n          @klass2.should_receive(:create!).with({:key => \"val\"})\n          @factory.create(:key => \"val\")\n        end\n      end\n    end\n  \n    describe 'FactoryGirl' do\n      before do\n        Pickle::Adapter::FactoryGirl.stub!(:model_classes).and_return([@klass1, @klass2, @klass3])\n        @orig_factories, Factory.factories = Factory.factories, {}\n        \n        Factory.define(:one, :class => @klass1) {}\n        Factory.define(:two, :class => @klass2) {}\n        @factory1 = Factory.factories[:one]\n        @factory2 = Factory.factories[:two]\n      end\n      \n      after do\n        Factory.factories = @orig_factories\n      end\n    \n      it \".factories should create one for each factory\" do\n        Pickle::Adapter::FactoryGirl.should_receive(:new).with(@factory1).once\n        Pickle::Adapter::FactoryGirl.should_receive(:new).with(@factory2).once\n        Pickle::Adapter::FactoryGirl.factories\n      end\n    \n      describe \".new(factory)\" do\n        before do\n          @factory = Pickle::Adapter::FactoryGirl.new(@factory1)\n        end\n      \n        it \"should have name of factory_name\" do\n          @factory.name.should == 'one'\n        end\n      \n        it \"should have klass of build_class\" do\n          @factory.klass.should == @klass1\n        end\n      \n        it \"#create(attrs) should call Factory(<:key>, attrs)\" do\n          Factory.should_receive(:create).with(\"one\", {:key => \"val\"})\n          @factory.create(:key => \"val\")\n        end\n      end\n    end\n  \n    describe 'Machinist' do\n      before do\n        Pickle::Adapter::Machinist.stub!(:model_classes).and_return([@klass1, @klass2, @klass3])\n        \n        @klass1.blueprint {}\n        @klass3.blueprint {}\n        @klass3.blueprint(:special) {}\n      end\n      \n      it \".factories should create one for each master blueprint, and special case\" do\n        Pickle::Adapter::Machinist.should_receive(:new).with(@klass1, :master).once\n        Pickle::Adapter::Machinist.should_receive(:new).with(@klass3, :master).once\n        Pickle::Adapter::Machinist.should_receive(:new).with(@klass3, :special).once\n        Pickle::Adapter::Machinist.factories\n      end\n        \n      describe \".new(Class, :master)\" do\n        before do\n          @factory = Pickle::Adapter::Machinist.new(@klass1, :master)\n        end\n        \n        it \"should have underscored (s/_) name of Class as #name\" do\n          @factory.name.should == 'one'\n        end\n        \n        it \"#create(attrs) should call Class.make(:master, attrs)\" do\n          @klass1.should_receive(:make).with(:master, {:key => \"val\"})\n          @factory.create(:key => \"val\")\n        end\n      end\n      \n      describe \".new(Class, :special)\" do\n        before do\n          @factory = Pickle::Adapter::Machinist.new(@klass3, :special)\n        end\n        \n        it \"should have 'special_<Class name>' as #name\" do\n          @factory.name.should == 'special_three'\n        end\n        \n        it \"#create(attrs) should call Class.make(:special, attrs)\" do\n          @klass3.should_receive(:make).with(:special, {:key => \"val\"})\n          @factory.create(:key => \"val\")\n        end\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/spec/lib/pickle_config_spec.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))\n\ndescribe Pickle::Config do\n  before do\n    @config = Pickle::Config.new\n  end\n  \n  it \"#adapters should default to :machinist, :factory_girl, :active_record\" do\n    @config.adapters.should == [:machinist, :factory_girl, :active_record]\n  end\n  \n  it \"#adapter_classes should default to Adapter::Machinist, Adapter::FactoryGirl, Adapter::ActiveRecord\" do\n    @config.adapter_classes.should == [Pickle::Adapter::Machinist, Pickle::Adapter::FactoryGirl, Pickle::Adapter::ActiveRecord]\n  end\n  \n  describe \"setting adapters to [:machinist, SomeAdapter]\" do\n    class SomeAdapter; end\n    \n    before do\n      @config.adapters = [:machinist, SomeAdapter]\n    end\n    \n    it \"#adapter_classes should be Adapter::Machinist, SomeAdapter\" do\n      @config.adapter_classes.should == [Pickle::Adapter::Machinist, SomeAdapter]\n    end\n  end\n  \n  describe \"#factories\" do\n    it \"should call adaptor.factories for each adaptor\" do\n      Pickle::Adapter::Machinist.should_receive(:factories).and_return([])\n      Pickle::Adapter::FactoryGirl.should_receive(:factories).and_return([])\n      Pickle::Adapter::ActiveRecord.should_receive(:factories).and_return([])\n      @config.factories\n    end\n    \n    it \"should aggregate factories into a hash using factory name as key\" do\n      Pickle::Adapter::Machinist.should_receive(:factories).and_return([@machinist = mock('machinist', :name => 'machinist')])\n      Pickle::Adapter::FactoryGirl.should_receive(:factories).and_return([@factory_girl = mock('factory_girl', :name => 'factory_girl')])\n      Pickle::Adapter::ActiveRecord.should_receive(:factories).and_return([@active_record = mock('active_record', :name => 'active_record')])\n      @config.factories.should == {'machinist' => @machinist, 'factory_girl' => @factory_girl, 'active_record' => @active_record}\n    end\n    \n    it \"should give preference to adaptors first in the list\" do\n      Pickle::Adapter::Machinist.should_receive(:factories).and_return([@machinist_one = mock('one', :name => 'one')])\n      Pickle::Adapter::FactoryGirl.should_receive(:factories).and_return([@factory_girl_one = mock('one', :name => 'one'), @factory_girl_two = mock('two', :name => 'two')])\n      Pickle::Adapter::ActiveRecord.should_receive(:factories).and_return([@active_record_two = mock('two', :name => 'two'), @active_record_three = mock('three', :name => 'three')])\n      @config.factories.should == {'one' => @machinist_one, 'two' => @factory_girl_two, 'three' => @active_record_three}\n    end\n  end\n  \n  it \"#mappings should default to []\" do\n    @config.mappings.should == []\n  end\n\n  describe '#predicates' do\n    it \"should be list of all non object ? public instance methods + columns methods of Adapter.model_classes\" do\n      class1 = mock('Class1', :public_instance_methods => ['nope', 'foo?', 'bar?'], :column_names => ['one', 'two'])\n      class2 = mock('Class2', :public_instance_methods => ['not', 'foo?', 'faz?'], :column_names => ['two', 'three'])\n      Pickle::Adapter.stub!(:model_classes).and_return([class1, class2])\n      \n      @config.predicates.to_set.should == ['foo?', 'faz?', 'bar?', 'one', 'two', 'three'].to_set\n    end\n    \n    it \"should be overridable\" do\n      @config.predicates = %w(lame?)\n      @config.predicates.should == %w(lame?)\n    end\n  end\n  \n  describe \"#map 'foo', :to => 'faz'\" do\n    before do\n      @config.map 'foo', :to => 'faz'\n    end\n    \n    it \"should create OpenStruct(search: 'foo', replace: 'faz') mapping\" do\n      @config.mappings.first.should == OpenStruct.new(:search => 'foo', :replacement => 'faz')\n    end\n  end\n  \n  describe \"#map 'foo', 'bar' :to => 'faz'\" do\n    before do\n      @config.map 'foo', 'bar', :to => 'faz'\n    end\n    \n    it \"should create 2 mappings\" do\n      @config.mappings.first.should == OpenStruct.new(:search => 'foo', :replacement => 'faz')\n      @config.mappings.last.should == OpenStruct.new(:search => 'bar', :replacement => 'faz')\n    end\n  end\n  \n  it \"#configure(&block) should execiute on self\" do\n    @config.should_receive(:foo).with(:bar)\n    @config.configure do |c|\n      c.foo :bar\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/spec/lib/pickle_email_parser_spec.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))\n\ndescribe Pickle::Email::Parser do\n  include Pickle::Parser::Matchers\n  include Pickle::Email::Parser\n  \n  describe \"#match_email\" do\n    it \"should match 'the email'\" do\n      'the email'.should match(/^#{match_email}$/)\n    end\n    \n    it \"should match 'the first email'\" do\n      'the first email'.should match(/^#{match_email}$/)\n    end\n    \n    it \"should match 'the last email'\" do\n      'the last email'.should match(/^#{match_email}$/)\n    end\n    \n    it \"should match 'the 3rd email'\" do\n      'the 3rd email'.should match(/^#{match_email}$/)\n    end\n    \n    it \"should match 'an email'\" do\n      'an email'.should match(/^#{match_email}$/)\n    end\n  end\n  \n  it \"#capture_email should just capture match_email\" do\n    capture_email.should == \"(#{match_email})\"\n  end\n  \n  describe \"#capture_index_in_email\" do\n    it \"should extract the '2nd' from 'the 2nd email'\" do\n      match = 'the 2nd email'.match(/^#{capture_index_in_email}$/)\n      match[1].should == '2nd'\n    end\n    \n    it \"should extract nil from 'the email'\" do\n      match = 'the email'.match(/^#{capture_index_in_email}$/)\n      match[1].should == nil\n    end\n    \n    it \"should extract the 'last' from 'the last email'\" do\n      match = 'the last email'.match(/^#{capture_index_in_email}$/)\n      match[1].should == 'last'\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/spec/lib/pickle_email_spec.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))\n\ndescribe Pickle::Email do\n  include Pickle::Session\n  include Pickle::Email\n  include Pickle::Email::Parser\n\n  before do\n    @email1 = mock(\"Email 1\")\n    @email2 = mock(\"Email 2\")\n    ActionMailer::Base.stub!(:deliveries).and_return([@email1, @email2])\n  end\n  \n  describe \"#emails\" do\n    it \"should return ordered deliveries\" do\n      emails.should == [@email1, @email2]\n    end\n    \n    describe \"(after)\" do\n      before do\n        emails\n      end\n      \n      it \"#email('the email') should return the last delivery\" do\n        email('the email').should == @email2\n      end\n      \n      it \"#email('the 1st email') should return the first delivery\" do\n        email('the 1st email').should == @email1\n      end\n\n      it \"#email('the first email') should return the first delivery\" do\n        email('the first email').should == @email1\n      end\n\n      it \"#email('the 2nd email') should return the second delivery\" do\n        email('the 2nd email').should == @email2\n      end\n      \n      it \"#email('the last email') should return the second delivery\" do\n        email('the last email').should == @email2\n      end\n      \n      it \"#email2('the 3rd email') should be nil\" do\n        email('the 3rd email').should == nil\n      end\n    end\n    \n    describe \"when email1 is to fred & joe, and email2 is to joe\" do\n      before do\n        @email1.stub!(:to).and_return(['fred@gmail.com', 'joe@gmail.com'])\n        @email2.stub!(:to).and_return('joe@gmail.com')\n      end\n      \n      it \"#emails('to: \\\"fred@gmail.com\\\"') should just return email1\" do\n        emails('to: \"fred@gmail.com\"').should == [@email1]\n      end\n      \n      describe \"after #emails('to: \\\"fred@gmail.com\\\"')\" do\n        before do\n          emails('to: \"fred@gmail.com\"')\n        end\n        \n        it \"#email('first') should be #email('last')\" do\n          email('first email').should == email('last email')\n          email('first email').should == @email1\n        end\n        \n        it \"#email('the email', 'to: \\\"blah\\\") should be nil\" do\n          email('the email', 'to: \"blah\"').should == nil\n        end\n\n        it \"#email('the email', 'to: \\\"fred@gmail.com\\\") should be email1\" do\n          email('the email', 'to: \"fred@gmail.com\"').should == @email1\n        end\n      end\n      \n      it \"#emails('to: \\\"joe@gmail.com\\\"') should return both emails\" do\n        emails('to: \"joe@gmail.com\"').should == [@email1, @email2]\n      end\n      \n      describe \"and emails have subjects 'email1', 'email2'\" do\n        before do\n          @email1.stub!(:subject).and_return('email1')\n          @email2.stub!(:subject).and_return('email2')\n        end\n        \n        it \"#emails('to: \\\"joe@gmail.com\\\", subject: \\\"email1\\\"') should return email1\" do\n          emails('to: \"joe@gmail.com\", subject: \"email1\"').should == [@email1]\n        end\n        \n        it \"#emails('to: \\\"fred@gmail.com\\\", subject: \\\"email2\\\"') should return empty array\" do\n          emails('to: \"fred@gmail.com\", subject: \"email2\"').should == []\n        end\n      end\n    end\n  end\n  \n  describe \"#save_and_open_emails\" do\n    before do\n      stub!(:open_in_browser)\n      stub!(:emails).and_return([\"Contents of Email 1\"])\n      @now = \"2008-01-01\".to_time\n      Time.stub!(:now).and_return(@now)\n    end\n    \n    it \"should call #emails to get emails\" do\n      should_receive(:emails).and_return([])\n      save_and_open_emails\n    end\n    \n    describe \"when emails have been already been found\" do\n      before { @emails = [] }\n      \n      it \"should not call #emails\" do\n        should_not_receive(:emails)\n        save_and_open_emails\n      end\n    end\n    \n    it \"should create a file in Rails/tmp with the emails in it\" do\n      save_and_open_emails\n      File.read(\"#{RAILS_ROOT}/tmp/webrat-email-#{@now.to_i}.html\").should == \"<h1>Email 1</h1><pre>Contents of Email 1</pre><hr />\"\n    end\n\n    it \"should call open_in_browser on created tmp file\" do\n      should_receive(:open_in_browser).with(\"#{RAILS_ROOT}/tmp/webrat-email-#{@now.to_i}.html\")\n      save_and_open_emails\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/spec/lib/pickle_parser_matchers_spec.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))\n\ndescribe Pickle::Parser::Matchers do\n  include Pickle::Parser::Matchers\n\n  describe \"(config: [factories: user, car, fast_car] [predicates: name, status, fancy?, super_fancy?]\" do\n    def config\n      @config ||= Pickle::Config.new do |c|\n        c.factories = {\n          'user'      => mock('factory'),\n          'car'       => mock('factory'),\n          'fast_car'  => mock('factory')\n        }\n        c.predicates = %w(name status fancy? super_fancy?)\n      end\n    end\n  \n    describe \"Match atoms\" do\n      def self.atom_should_match(atom, strings)\n        Array(strings).each do |string|\n          it \"#{atom} should match '#{string}'\" do\n            string.should match(/^#{send atom}$/)\n          end\n        end\n      end\n\n      def self.atom_should_not_match(atom, strings)\n        Array(strings).each do |string|\n          it \"#{atom} should NOT match '#{string}'\" do\n            string.should_not match(/^#{send atom}$/)\n          end\n        end\n      end\n  \n      atom_should_match     :match_ordinal, ['1st', '2nd', '23rd', '104th']\n      atom_should_not_match :match_ordinal, ['1', '2']\n\n      atom_should_match     :match_index, ['first', 'last', '23rd', '104th']\n      atom_should_not_match :match_index, ['1', '2', 'foo']\n\n      atom_should_match     :match_label, [': \"gday\"', ': \"gday mate\"']\n      atom_should_not_match :match_label, [': \"gday\"\"', ': gday']\n  \n      atom_should_match     :match_field, ['foo: \"this is the life\"', 'bar_man: \"and so is this\"', 'boolean: false', 'boolean: true', 'numeric: 10', 'numeric: 12.5', 'numeric: +10', 'numeric: +12.5', 'numeric: -10', 'numeric: -12.5']\n      atom_should_not_match :match_field, ['foo bar: \"this aint workin\"', 'not_numeric: --10', 'not_numeric: -ten']\n  \n      atom_should_match     :match_fields, ['foo: \"bar\"', 'foo: \"bar\", baz: \"bah\"']\n      atom_should_not_match :match_fields, ['foo bar: \"baz\"', 'email: \"a\", password: \"b\", and password_confirmation: \"c\"']\n\n      atom_should_match     :match_model, ['a user', '1st fast car', 'the 23rd fast_car', 'the user: \"fred flinstone\"']\n      atom_should_not_match :match_model, ['a giraffe', 'a 1st faster car: \"jim\"', 'an event created']\n  \n      atom_should_match     :match_predicate, ['name', 'status', 'fancy', 'super fancy', 'super_fancy']\n      atom_should_not_match :match_predicate, ['nameo', 'increment', 'not a predicate']\n    \n      atom_should_match     :match_factory, ['user', 'fast car', 'fast_car', 'car']\n      atom_should_not_match :match_factory, ['users', 'faster car', 'event created']\n    \n      atom_should_match     :match_plural_factory, ['users', 'fast cars']\n      atom_should_not_match :match_plural_factory, ['usereres', 'fasts cars']\n    end\n  end\n  \n  describe \"capture methods\" do\n    it \"capture_field should == '(' + match_field + ')'\" do\n      should_receive(:match_field).and_return('MATCH_FIELD')\n      capture_field.should == '(MATCH_FIELD)'\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/spec/lib/pickle_parser_spec.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))\n\ndescribe Pickle::Parser do\n  before do\n    @parser = Pickle::Parser.new(:config => Pickle::Config.new)\n  end\n  \n  it \"should raise error when created with no config\" do\n    lambda{ Pickle::Parser.new }.should raise_error(ArgumentError)\n  end\n  \n  describe 'misc regexps' do\n    describe '/^#{capture_model} exists/' do\n      before do\n        @regexp = /^(#{@parser.capture_model}) exists$/\n      end\n      \n      it \"should match 'a user exists'\" do\n        'a user exists'.should match(@regexp)\n      end\n      \n      it \"should caputure 'a user' from  'a user exists'\" do\n        'a user exists'.match(@regexp)[1].should == 'a user'\n      end\n    end\n  end\n  \n  describe '#parse_field' do\n    it \"should return {'a' => 'b'} for 'a: \\\"b\\\"'\" do\n      @parser.parse_field('a: \"b\"').should == {'a' => 'b'}\n    end\n  \n    it \"should raise error for invalid field 'a : b'\" do\n      lambda { @parser.parse_field('a : b') }.should raise_error(ArgumentError)\n    end\n  end\n  \n  describe '#parse_fields' do\n    it 'should return {} for blank argument' do\n      @parser.parse_fields(nil).should == {}\n      @parser.parse_fields('').should == {}\n    end\n    \n    it 'should raise error for invalid argument' do\n      lambda { @parser.parse_fields('foo foo') }.should raise_error(ArgumentError)\n    end\n    \n    it '(\\'foo: \"bar\"\\') should == { \"foo\" => \"bar\"}' do\n      @parser.parse_fields('foo: \"bar\"').should == { \"foo\" => \"bar\"}\n    end\n    \n    it '(\"bool: true\") should == { \"bool\" => true}' do\n      @parser.parse_fields('bool: true').should == {\"bool\" => true}\n    end\n    \n    it '(\"bool: false\") should == { \"bool\" => false}' do\n      @parser.parse_fields('bool: false').should == {\"bool\" => false}\n    end\n    \n    it '(\"int: 10\") should == { \"int\" => 10 }' do\n      @parser.parse_fields('int: 10').should == {\"int\" => 10}\n    end\n\n    it '(\"float: 10.1\") should == { \"float\" => 10.1 }' do\n      @parser.parse_fields('float: 10.1').should == {\"float\" => 10.1}\n    end\n\n    it '(\\'foo: \"bar\", bar_man: \"wonga wonga\", gump: 123\\') should == {\"foo\" => \"bar\", \"bar_man\" => \"wonga wonga\", \"gump\" => 123}' do\n      @parser.parse_fields('foo: \"bar\", bar_man: \"wonga wonga\", gump: 123').should == {\"foo\" => \"bar\", \"bar_man\" => \"wonga wonga\", \"gump\" => 123}\n    end\n  end\n  \n  describe '#parse_model' do\n    it '(\"a user\") should == [\"user\", \"\"]' do\n      @parser.parse_model(\"a user\").should == [\"user\", \"\"]\n    end\n  \n    it '(\"the user\") should == [\"user\", \"\"]' do\n      @parser.parse_model(\"the user\").should == [\"user\", \"\"]\n    end\n  \n    it '(\"1 fast car\") should == [\"fast_car\", \"\"]' do\n      @parser.parse_model(\"1 fast car\").should == [\"fast_car\", \"\"]\n    end\n    \n    it '(\\'an user: \"jim jones\"\\') should == [\"user\", \"jim_jones\"]' do\n      @parser.parse_model('an user: \"jim jones\"').should == [\"user\", \"jim_jones\"]\n    end\n    \n    it '(\\'that fast car: \"herbie\"\\') should == [\"fast_car\", \"herbie\"]' do\n      @parser.parse_model('that fast car: \"herbie\"').should == [\"fast_car\", \"herbie\"]\n    end\n    \n    it '(\\'the 12th user\\') should == [\"user\", 11]' do\n      @parser.parse_model('the 12th user').should == [\"user\", 11]\n    end\n  \n    it '(\\'the last user\\') should == [\"user\", -1]' do\n      @parser.parse_model('the last user').should == [\"user\", -1]\n    end\n    \n    it '(\"the first user\") should == [\"user\", 0]' do\n      @parser.parse_model('the first user').should == [\"user\", 0]\n    end\n  \n    it '(\"the 1st user\") should == [\"user\", 0]' do\n      @parser.parse_model('the 1st user').should == [\"user\", 0]\n    end\n  end\n  \n  describe \"#parse_index\" do\n    it '(\"1st\") should == 0' do\n      @parser.parse_index(\"1st\").should == 0\n    end\n  \n    it '(\"24th\") should == 23' do\n      @parser.parse_index(\"24th\").should == 23\n    end\n    it '(\"first\") should == 0' do\n      @parser.parse_index(\"first\").should == 0\n    end\n    \n    it '(\"last\") should == -1' do\n      @parser.parse_index(\"last\").should == -1\n    end\n  end\n  \n  describe \"customised mappings\" do\n    describe \"config maps 'I|myself' to 'user: \\\"me\\\"'\" do\n      before do\n        @config = Pickle::Config.new do |c|\n          c.map 'I', 'myself', :to => 'user: \"me\"'\n        end\n        @parser = Pickle::Parser.new(:config => @config)\n      end\n\n      it \"'I' should match /\\#{match_model}/\" do\n        'I'.should match(/#{@parser.match_model}/)\n      end\n    \n      it \"'myself' should match /\\#{match_model}/\" do\n        'myself'.should match(/#{@parser.match_model}/)\n      end\n    \n      it \"parse_model('I') should == ['user', 'me']\" do\n        @parser.parse_model('I').should == [\"user\", \"me\"]\n      end\n\n      it \"parse_model('myself') should == ['user', 'me']\" do\n        @parser.parse_model('myself').should == [\"user\", \"me\"]\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/spec/lib/pickle_path_spec.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))\n\ndescribe Pickle::Path do\n  include Pickle::Path\n  \n  describe \"#path_to_pickle, when the model doesn't exist\" do\n    before do\n      stub!(:model!).and_raise(\"foo\")\n    end\n    it \"('that user', :extra => 'new comment') should raise the error raised by model!\" do\n      lambda { path_to_pickle \"that user\", \"new comment\" }.should raise_error(\"foo\")\n    end\n    \n  end\n  \n  describe \"#path_to_pickle\" do\n    before do\n      stub!(:model!).and_return(@user = mock_model(User))\n    end\n    it \"('a user', 'the user: \\\"fred\\\"') should retrieve 'a user', and 'the user: \\\"fred\\\"' models\" do\n      should_receive(:model!).with('a user')\n      should_receive(:model!).with('the user: \"fred\"')\n      stub!(:user_user_path).and_return('the path')\n      path_to_pickle 'a user', 'the user: \"fred\"'\n    end\n    \n    it \"('a user', :action => 'foo') should return foo_user_path(<user>)\" do\n      should_receive(:foo_user_path).with(@user).and_return('the path')\n      path_to_pickle('a user', :action => 'foo').should == 'the path'\n    end\n    \n    it \"('a user', :action => 'foo') should raise informative error if foo_user_path not defined\" do\n      should_receive(:foo_user_path).with(@user).and_raise(NoMethodError)\n      lambda { path_to_pickle('a user', :action => 'foo') }.should raise_error(Exception, /Could not figure out a path for/)\n    end\n    \n    it \"('a user', :segment => 'foo') should return user_foo_path(<user>)\" do\n      should_receive(:user_foo_path).with(@user).and_return('the path')\n      path_to_pickle('a user', :segment => 'foo').should == 'the path'\n    end\n    \n    it \"('a user', :segment => 'foo') should raise informative error if foo_user_path not defined\" do\n      should_receive(:user_foo_path).with(@user).and_raise(NoMethodError)\n      lambda { path_to_pickle('a user', :segment => 'foo') }.should raise_error(Exception, /Could not figure out a path for/)\n    end\n    \n    it \"('a user', :action => 'new', :segment => 'comment') should return new_user_comment_path(<user>)\" do\n      should_receive(:new_user_comment_path).with(@user).and_return('the path')\n      path_to_pickle('a user', :segment => 'comment', :action => 'new').should == 'the path'\n    end\n    \n    it \"('a user', :action => 'new', :segment => 'comment') should raise informative error if new_user_comment_path not defined\" do\n      should_receive(:new_user_comment_path).with(@user).and_raise(NoMethodError)\n      lambda { path_to_pickle('a user', :action => 'new', :segment => 'comment') }.should raise_error(Exception, /Could not figure out a path for/)\n    end\n    \n    it \"('a user', :extra => 'new comment') should return new_user_comment_path(<user>)\" do\n      should_receive(:new_user_comment_path).with(@user).and_return('the path')\n      path_to_pickle('a user', :extra => 'new comment').should == 'the path'\n    end\n    \n    it \"('a user', :extra => 'new comment') should raise informative error if new_user_comment_path not defined\" do\n      should_receive(:new_user_comment_path).with(@user).and_raise(NoMethodError)\n      lambda { path_to_pickle('a user', :extra => 'new comment') }.should raise_error(Exception, /Could not figure out a path for/)\n    end\n    \n    describe \"(private API)\" do\n      it \"('a user', :extra => 'new ish comment') should try combinations of 'new', 'ish', 'comment'\" do\n        should_receive(:pickle_path_for_models_action_segment).with([@user], '', 'new_ish_comment').once\n        should_receive(:pickle_path_for_models_action_segment).with([@user], 'new', 'ish_comment').once\n        should_receive(:pickle_path_for_models_action_segment).with([@user], 'new_ish', 'comment').once\n        should_receive(:pickle_path_for_models_action_segment).with([@user], 'new_ish_comment', '').once\n        lambda { path_to_pickle('a user', :extra => 'new ish comment') }.should raise_error(Exception, /Could not figure out a path for/)\n      end\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/spec/lib/pickle_session_spec.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))\n\ndescribe Pickle::Session do\n  include Pickle::Session\n  \n  describe \"Pickle::Session proxy missing methods to parser\", :shared => true do\n    it \"should forward to pickle_parser it responds_to them\" do\n      @it.pickle_parser.should_receive(:parse_model)\n      @it.parse_model\n    end\n\n    it \"should raise error if pickle_parser don't know about em\" do\n      lambda { @it.parse_infinity }.should raise_error\n    end\n  end\n\n  describe \"including Pickle::Session\" do\n    before do \n      @it = self\n    end\n    \n    it_should_behave_like \"Pickle::Session proxy missing methods to parser\"\n  end\n\n  describe \"extending Pickle::Session\" do\n    before do \n      @it = Object.new\n      @it.extend Pickle::Session\n    end\n    \n    it_should_behave_like \"Pickle::Session proxy missing methods to parser\"\n  end\n\n  describe \"after storing a single user\", :shared => true do\n    it \"created_models('user') should be array containing the original user\" do\n      created_models('user').should == [@user]\n    end\n\n    describe \"the original user should be retrievable with\" do\n      it \"created_model('the user')\" do\n        created_model('the user').should == @user\n      end\n\n      it \"created_model('1st user')\" do\n        created_model('1st user').should == @user\n      end\n\n      it \"created_model('last user')\" do\n        created_model('last user').should == @user\n      end\n    end\n\n    describe \"(found from db)\" do\n      before do\n        @user.stub!(:id).and_return(100)\n        @user.class.should_receive(:find).with(100).and_return(@user_from_db = @user.dup)\n      end\n    \n      it \"models('user') should be array containing user\" do\n        models('user').should == [@user_from_db]\n      end\n  \n      describe \"user should be retrievable with\" do\n        it \"model('the user')\" do\n          model('the user').should == @user_from_db\n        end\n\n        it \"model('1st user')\" do\n          model('1st user').should == @user_from_db\n        end\n\n        it \"model('last user')\" do\n          model('last user').should == @user_from_db\n        end\n        \n        it \"model!('last user')\" do\n          model('last user').should == @user_from_db\n        end\n      end\n    end\n  end\n  \n  describe \"#create_model\" do\n    before do\n      @user = mock_model(User)\n      Factory.stub!(:create).and_return(@user)\n    end\n    \n    describe \"('a user')\" do\n      def do_create_model\n        create_model('a user')\n      end\n  \n      it \"should call Factory.create('user', {})\" do\n        Factory.should_receive(:create).with('user', {}).and_return(@user)\n        do_create_model\n      end\n      \n      describe \"after create,\" do\n        before { do_create_model }\n        \n        it_should_behave_like \"after storing a single user\"\n      end\n    end\n    \n    describe \"('1 user', 'foo: \\\"bar\\\", baz: \\\"bing bong\\\"')\" do\n      def do_create_model\n        create_model('1 user', 'foo: \"bar\", baz: \"bing bong\"')\n      end\n  \n      it \"should call Factory.create('user', {'foo' => 'bar', 'baz' => 'bing bong'})\" do\n        Factory.should_receive(:create).with('user', {'foo' => 'bar', 'baz' => 'bing bong'}).and_return(@user)\n        do_create_model\n      end\n      \n      describe \"after create,\" do\n        before { do_create_model }\n        \n        it_should_behave_like \"after storing a single user\"\n      end\n    end  \n\n    describe \"('an user: \\\"fred\\\")\" do\n      def do_create_model\n        create_model('an user: \"fred\"')\n      end\n  \n      it \"should call Factory.create('user', {})\" do\n        Factory.should_receive(:create).with('user', {}).and_return(@user)\n        do_create_model\n      end\n      \n      describe \"after create,\" do\n        before { do_create_model }\n        \n        it_should_behave_like \"after storing a single user\"\n              \n        it \"created_model('the user: \\\"fred\\\"') should retrieve the user\" do\n          created_model('the user: \"fred\"').should == @user\n        end\n      \n        it \"created_model?('the user: \\\"shirl\\\"') should be false\" do\n          created_model?('the user: \"shirl\"').should == false\n        end\n        \n        it \"model?('the user: \\\"shirl\\\"') should be false\" do\n          model?('the user: \"shirl\"').should == false\n        end\n      end\n    end\n    \n    describe \"with hash\" do\n      def do_create_model\n        create_model('a user', {'foo' => 'bar'})\n      end\n  \n      it \"should call Factory.create('user', {'foo' => 'bar'})\" do\n        Factory.should_receive(:create).with('user', {'foo' => 'bar'}).and_return(@user)\n        do_create_model\n      end\n      \n      describe \"after create,\" do\n        before { do_create_model }\n        \n        it_should_behave_like \"after storing a single user\"\n      end\n    end\n    \n  end\n\n  describe '#find_model' do\n    before do\n      @user = mock_model(User)\n      User.stub!(:find).and_return(@user)\n    end\n    \n    def do_find_model\n      find_model('a user', 'hair: \"pink\"')\n    end\n    \n    it \"should call User.find :first, :conditions => {'hair' => 'pink'}\" do\n      User.should_receive(:find).with(:first, :conditions => {'hair' => 'pink'}).and_return(@user)\n      do_find_model\n    end\n    \n    describe \"after find,\" do\n      before { do_find_model }\n      \n      it_should_behave_like \"after storing a single user\"\n    end\n  end\n  \n  describe \"#find_models\" do\n    before do\n      @user = mock_model(User)\n      User.stub!(:find).and_return([@user])\n    end\n\n    def do_find_models\n      find_models('user', 'hair: \"pink\"')\n    end\n\n    it \"should call User.find :all, :conditions => {'hair' => 'pink'}\" do\n      User.should_receive(:find).with(:all, :conditions => {'hair' => 'pink'}).and_return([@user])\n      do_find_models\n    end\n\n    describe \"after find,\" do\n      before { do_find_models }\n\n      it_should_behave_like \"after storing a single user\"\n    end\n  end\n    \n  describe 'creating \\'a super admin: \"fred\"\\', then \\'a user: \"shirl\"\\', \\'then 1 super_admin\\'' do\n    before do\n      @user = @fred = mock_model(User)\n      @shirl  = mock_model(User)\n      @noname = mock_model(User)\n      Factory.stub!(:create).and_return(@fred, @shirl, @noname)\n    end\n    \n    def do_create_users\n      create_model('a super admin: \"fred\"')\n      create_model('a user: \"shirl\"')\n      create_model('1 super_admin')\n    end\n    \n    it \"should call Factory.create with <'super_admin'>, <'user'>, <'super_admin'>\" do\n      Factory.should_receive(:create).with('super_admin', {}).twice\n      Factory.should_receive(:create).with('user', {}).once\n      do_create_users\n    end\n    \n    describe \"after create,\" do\n      before do\n        do_create_users\n      end\n      \n      it \"created_models('user') should == [@fred, @shirl, @noname]\" do\n        created_models('user').should == [@fred, @shirl, @noname]\n      end\n      \n      it \"created_models('super_admin') should == [@fred, @noname]\" do\n        created_models('super_admin').should == [@fred, @noname]\n      end\n      \n      describe \"#created_model\" do\n        it \"'that user' should be @noname (the last user created - as super_admins are users)\" do\n          created_model('that user').should == @noname\n        end\n\n        it \"'the super admin' should be @noname (the last super admin created)\" do\n          created_model('that super admin').should == @noname\n        end\n        \n        it \"'the 1st super admin' should be @fred\" do\n          created_model('the 1st super admin').should == @fred\n        end\n        \n        it \"'the first user' should be @fred\" do\n          created_model('the first user').should == @fred\n        end\n        \n        it \"'the 2nd user' should be @shirl\" do\n          created_model('the 2nd user').should == @shirl\n        end\n        \n        it \"'the last user' should be @noname\" do\n          created_model('the last user').should == @noname\n        end\n        \n        it \"'the user: \\\"fred\\\" should be @fred\" do\n          created_model('the user: \"fred\"').should == @fred\n        end\n        \n        it \"'the user: \\\"shirl\\\" should be @shirl\" do\n          created_model('the user: \"shirl\"').should == @shirl\n        end\n      end\n    end\n  end\n\n  describe \"when 'the user: \\\"me\\\"' exists and there is a mapping from 'I', 'myself' => 'user: \\\"me\\\"\" do\n    before do\n      @user = mock_model(User)\n      User.stub!(:find).and_return(@user)\n      Factory.stub!(:create).and_return(@user)\n      self.pickle_parser = Pickle::Parser.new(:config => Pickle::Config.new {|c| c.map 'I', 'myself', :to => 'user: \"me\"'})\n      create_model('the user: \"me\"')\n    end\n  \n    it 'model(\"I\") should return the user' do\n      model('I').should == @user\n    end\n\n    it 'model(\"myself\") should return the user' do\n      model('myself').should == @user\n    end\n    \n    it \"#parser.parse_fields 'author: user \\\"JIM\\\"' should raise Error, as model deos not refer\" do\n      lambda { pickle_parser.parse_fields('author: user \"JIM\"') }.should raise_error\n    end\n    \n    it \"#parser.parse_fields 'author: the user' should return {\\\"author\\\" => <user>}\" do\n      pickle_parser.parse_fields('author: the user').should == {\"author\" => @user}\n    end\n\n    it \"#parser.parse_fields 'author: myself' should return {\\\"author\\\" => <user>}\" do\n      pickle_parser.parse_fields('author: myself').should == {\"author\" => @user}\n    end\n    \n    it \"#parser.parse_fields 'author: the user, approver: I, rating: \\\"5\\\"' should return {'author' => <user>, 'approver' => <user>, 'rating' => '5'}\" do\n      pickle_parser.parse_fields('author: the user, approver: I, rating: \"5\"').should == {'author' => @user, 'approver' => @user, 'rating' => '5'}\n    end\n    \n    it \"#parser.parse_fields 'author: user: \\\"me\\\", approver: \\\"\\\"' should return {'author' => <user>, 'approver' => \\\"\\\"}\" do\n      pickle_parser.parse_fields('author: user: \"me\", approver: \"\"').should == {'author' => @user, 'approver' => \"\"}\n    end\n  end\n  \n  describe \"convert_models_to_attributes(ar_class, :user => <a user>)\" do\n    before do \n      @user = mock_model(User)\n    end\n    \n    describe \"(when ar_class has column 'user_id')\" do\n      before do\n        @ar_class = mock('ActiveRecord', :column_names => ['user_id'])\n      end\n      \n      it \"should return {'user_id' => <the user.id>}\" do\n        convert_models_to_attributes(@ar_class, :user => @user).should == {'user_id' => @user.id}\n      end\n    end\n    \n    describe \"(when ar_class has columns 'user_id', 'user_type')\" do\n      before do\n        @ar_class = mock('ActiveRecord', :column_names => ['user_id', 'user_type'])\n      end\n      \n      it \"should return {'user_id' => <the user.id>, 'user_type' => <the user.type>}\" do\n        convert_models_to_attributes(@ar_class, :user => @user).should == {'user_id' => @user.id, 'user_type' => @user.class.name}\n      end\n    end\n  end\n  \n  it \"#model!('unknown') should raise informative error message\" do\n    lambda { model!('unknown') }.should raise_error(\"Can't find pickle model: 'unknown' in this scenario\")\n  end\n\n  it \"#created_model!('unknown') should raise informative error message\" do\n    lambda { created_model!('unknown') }.should raise_error(\"Can't find pickle model: 'unknown' in this scenario\")\n  end\nend"
  },
  {
    "path": "vendor/plugins/pickle/spec/lib/pickle_spec.rb",
    "content": "require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))\n\ndescribe Pickle do\n  it \".config should be same object on multiple calls\" do\n    Pickle.config.should == Pickle.config\n  end\n  \n  it \".configure should configure the .config object\" do\n    Pickle.config.should_receive(:foo).with(:bar)\n    Pickle.configure do |c|\n      c.foo :bar\n    end\n  end\n\n  it \".parser should create a parser with the default config\" do\n    Pickle.instance_variable_set('@parser', nil)\n    Pickle::Parser.should_receive(:new).with(:config => Pickle.config)\n    Pickle.parser\n  end\n  \n  it \".parser should be same object on multiple calls\" do\n    Pickle.parser.should == Pickle.parser\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/pickle/spec/spec_helper.rb",
    "content": "# This file is copied to ~/spec when you run 'ruby script/generate rspec'\n# from the project root directory.\nENV[\"RAILS_ENV\"] ||= \"test\"\nrequire File.expand_path(File.join(File.dirname(__FILE__), \"../../../../config/environment\"))\nrequire 'spec/rails'\n\n# APP SETUP\n\n# Models\nclass User < ActiveRecord::Base\nend\n\nclass FastCar < ActiveRecord::Base\nend\n\nclass Event < ActiveRecord::Base\n  class Create < Event\n  end\n  \n  class Update < Event\n  end\nend\n\n# Factories\nrequire 'factory_girl'\n\nFactory.define :user do |u|\nend\n\nFactory.define :super_admin, :class => User do |u|\nend\n\nFactory.define :fast_car do |c|\nend\n\n# Machinist\nrequire 'machinist/active_record'\n\n"
  },
  {
    "path": "vendor/plugins/prepend_engine_views/init.rb",
    "content": "module PrependEngineViews\n  def self.included(base)\n    base.send(:include, InstanceMethods)\n    base.class_eval do\n      alias_method_chain :add_engine_view_paths, :prepend\n    end\n  end\n\n  module InstanceMethods\n    # Patch Rails so engine's views are prepended to the view_path,\n    # thereby letting plugins override application views\n    def add_engine_view_paths_with_prepend\n      paths = ActionView::PathSet.new(engines.collect(&:view_path))\n      ActionController::Base.view_paths.unshift(*paths)\n      ActionMailer::Base.view_paths.unshift(*paths) if configuration.frameworks.include?(:action_mailer)\n    end\n  end\nend\n\nRails::Plugin::Loader.send :include, PrependEngineViews\n\n"
  },
  {
    "path": "vendor/plugins/redmine_s3/README.rdoc",
    "content": "= S3 plugin for Redmine\n\n== Description\nThis Redmine[http://www.redmine.org] plugin makes file attachments be stored on Amazon S3 rather than on the local filesystem.\n\n== Installation\n1. Make sure Redmine is installed and cd into it's root directory\n2. git clone git://github.com/tigrish/redmine_s3.git vendor/plugins/redmine_s3\n3. cp vendor/plugins/redmine_s3/config/s3.yml.example config/s3.yml\n4. Edit config/s3.yml with your favourite editor\n5. Restart mongrel/upload to production/whatever\n\n== Options\n* The bucket specified in s3.yml will be created automatically when the plugin is loaded (this is generally when the server starts).\n* If you have created a CNAME entry for your bucket set the cname_bucket option to true in s3.yml and your files will be served from that domain. \n* After files are uploaded they are made public. This seems acceptable as it is also Redmine's policy for file storage.\n\n== Reporting Bugs and Getting Help\n\nBugs and feature requests may be filed at http://projects.tigrish.com/projects/redmine-s3/issues\n"
  },
  {
    "path": "vendor/plugins/redmine_s3/config/locales/en.yml",
    "content": "# English strings go here for Rails i18n\nen:\n  my_label: \"My label\"\n"
  },
  {
    "path": "vendor/plugins/redmine_s3/config/s3.yml.example",
    "content": "production:\n  access_key_id: \n  secret_access_key: \n  bucket: \n  cname_bucket: false\n\ndevelopment:\n  access_key_id: \n  secret_access_key: \n  bucket:\n  cname_bucket: false\n"
  },
  {
    "path": "vendor/plugins/redmine_s3/init.rb",
    "content": "require 'redmine'\nrequire 'dispatcher' # Patches to the Redmine core.\n \nDispatcher.to_prepare :redmine_s3 do\n\n  # RedmineS3::Connection.create_bucket\nend\n\nRedmine::Plugin.register :redmine_s3_attachments do\n  name 'S3'\n  author 'Chris Dell'\n  description 'Use Amazon S3 as a storage engine for attachemnts'\n  version '0.0.2'\nend\n"
  },
  {
    "path": "vendor/plugins/redmine_s3/lang/en.yml",
    "content": "# English strings go here\nmy_label: \"My label\"\n"
  },
  {
    "path": "vendor/plugins/redmine_s3/lib/S3.rb",
    "content": "#!/usr/bin/env ruby\n\n#  This software code is made available \"AS IS\" without warranties of any\n#  kind.  You may copy, display, modify and redistribute the software\n#  code either by itself or as incorporated into your code; provided that\n#  you do not remove any proprietary notices.  Your use of this software\n#  code is at your own risk and you waive any claim against Amazon\n#  Digital Services, Inc. or its affiliates with respect to your use of\n#  this software code. (c) 2006-2007 Amazon Digital Services, Inc. or its\n#  affiliates.\n\nrequire 'base64'\nrequire 'cgi'\nrequire 'openssl'\nrequire 'digest/sha1'\nrequire 'net/https'\nrequire 'rexml/document'\nrequire 'time'\nrequire 'uri'\n\n# this wasn't added until v 1.8.3\nif (RUBY_VERSION < '1.8.3')\n  class Net::HTTP::Delete < Net::HTTPRequest\n    METHOD = 'DELETE'\n    REQUEST_HAS_BODY = false\n    RESPONSE_HAS_BODY = true\n  end\nend\n\n# this module has two big classes: AWSAuthConnection and\n# QueryStringAuthGenerator.  both use identical apis, but the first actually\n# performs the operation, while the second simply outputs urls with the\n# appropriate authentication query string parameters, which could be used\n# in another tool (such as your web browser for GETs).\nmodule S3\n  DEFAULT_HOST = 's3.amazonaws.com'\n  PORTS_BY_SECURITY = { true => 443, false => 80 }\n  METADATA_PREFIX = 'x-amz-meta-'\n  AMAZON_HEADER_PREFIX = 'x-amz-'\n\n  # Location constraint for CreateBucket\n  module BucketLocation \n    DEFAULT = nil\n    EU = 'EU'\n  end\n  \n  # builds the canonical string for signing.\n  def S3.canonical_string(method, bucket=\"\", path=\"\", path_args={}, headers={}, expires=nil)\n    interesting_headers = {}\n    headers.each do |key, value|\n      lk = key.downcase\n      if (lk == 'content-md5' or\n          lk == 'content-type' or\n          lk == 'date' or\n          lk =~ /^#{AMAZON_HEADER_PREFIX}/o)\n        interesting_headers[lk] = value.to_s.strip\n      end\n    end\n\n    # these fields get empty strings if they don't exist.\n    interesting_headers['content-type'] ||= ''\n    interesting_headers['content-md5'] ||= ''\n\n    # just in case someone used this.  it's not necessary in this lib.\n    if interesting_headers.has_key? 'x-amz-date'\n      interesting_headers['date'] = ''\n    end\n\n    # if you're using expires for query string auth, then it trumps date\n    # (and x-amz-date)\n    if not expires.nil?\n      interesting_headers['date'] = expires\n    end\n\n    buf = \"#{method}\\n\"\n    interesting_headers.sort { |a, b| a[0] <=> b[0] }.each do |key, value|\n      if key =~ /^#{AMAZON_HEADER_PREFIX}/o\n        buf << \"#{key}:#{value}\\n\"\n      else\n        buf << \"#{value}\\n\"\n      end\n    end\n    \n    # build the path using the bucket and key\n    if not bucket.empty?\n      buf << \"/#{bucket}\"\n    end\n    # append the key (it might be empty string) \n    # append a slash regardless\n    buf << \"/#{path}\"\n\n    # if there is an acl, logging, or torrent parameter\n    # add them to the string\n    if path_args.has_key?('acl')\n      buf << '?acl'\n    elsif path_args.has_key?('torrent')\n      buf << '?torrent'\n    elsif path_args.has_key?('logging')\n      buf << '?logging'\n    elsif path_args.has_key?('location')\n      buf << '?location'\n    end\n    \n    return buf\n  end\n\n  # encodes the given string with the aws_secret_access_key, by taking the\n  # hmac-sha1 sum, and then base64 encoding it.  optionally, it will also\n  # url encode the result of that to protect the string if it's going to\n  # be used as a query string parameter.\n  def S3.encode(aws_secret_access_key, str, urlencode=false)\n    digest = OpenSSL::Digest::Digest.new('sha1')\n    b64_hmac =\n      Base64.encode64(\n        OpenSSL::HMAC.digest(digest, aws_secret_access_key, str)).strip\n\n    if urlencode\n      return CGI::escape(b64_hmac)\n    else\n      return b64_hmac\n    end\n  end\n\n  # build the path_argument string\n  def S3.path_args_hash_to_string(path_args={})\n    arg_string = ''\n    path_args.each { |k, v|\n      arg_string << (arg_string.empty? ? '?' : '&')\n      arg_string << k\n      if not v.nil?\n        arg_string << \"=#{CGI::escape(v)}\"\n      end\n    }\n    return arg_string\n  end\n\n  # uses Net::HTTP to interface with S3.  note that this interface should only\n  # be used for smaller objects, as it does not stream the data.  if you were\n  # to download a 1gb file, it would require 1gb of memory.  also, this class\n  # creates a new http connection each time.  it would be greatly improved with\n  # some connection pooling.\n  class AWSAuthConnection\n    attr_accessor :calling_format\n    \n    def initialize(aws_access_key_id, aws_secret_access_key, is_secure=true,\n                   server=DEFAULT_HOST, port=PORTS_BY_SECURITY[is_secure],\n                   calling_format=CallingFormat::SUBDOMAIN)\n      @aws_access_key_id = aws_access_key_id\n      @aws_secret_access_key = aws_secret_access_key\n      @server = server\n      @is_secure = is_secure\n      @calling_format = calling_format\n      @port = port\n    end\n\n    def create_bucket(bucket, headers={})\n      begin\n        return Response.new(make_request('PUT', bucket, '', {}, headers))\n      rescue\n        puts(\"Failed to create bucket #{bucket}\")\n      end\n    end\n\n    def create_located_bucket(bucket, location=BucketLocation::DEFAULT, headers={})\n      if (location != BucketLocation::DEFAULT)\n          xmlbody = \"<CreateBucketConstraint><LocationConstraint>#{location}</LocationConstraint></CreateBucketConstraint>\"\n      end\n      return Response.new(make_request('PUT', bucket, '', {}, headers, xmlbody))\n    end\n\n    def check_bucket_exists(bucket)\n      begin\n        make_request('HEAD', bucket, '', {}, {})\n        return true\n      rescue Net::HTTPServerException\n        response = $!.response\n        return false if (response.code.to_i == 404)\n        raise\n      end\n    end\n      \n    # takes options :prefix, :marker, :max_keys, and :delimiter\n    def list_bucket(bucket, options={}, headers={})\n      path_args = {}\n      options.each { |k, v|\n          path_args[k] = v.to_s\n      }\n\n      return ListBucketResponse.new(make_request('GET', bucket, '', path_args, headers))\n    end\n\n    def delete_bucket(bucket, headers={})\n      return Response.new(make_request('DELETE', bucket, '', {}, headers))\n    end\n\n    def put(bucket, key, object, headers={})\n      object = S3Object.new(object) if not object.instance_of? S3Object\n\n      return Response.new(\n        make_request('PUT', bucket, CGI::escape(key), {}, headers, object.data, object.metadata)\n      )\n    end\n\n    def get(bucket, key, headers={})\n      return GetResponse.new(make_request('GET', bucket, CGI::escape(key), {}, headers))\n    end\n\n    def delete(bucket, key, headers={})\n      return Response.new(make_request('DELETE', bucket, CGI::escape(key), {}, headers))\n    end\n\n    def get_bucket_logging(bucket, headers={})\n      return GetResponse.new(make_request('GET', bucket, '', {'logging' => nil}, headers))\n    end\n\n    def put_bucket_logging(bucket, logging_xml_doc, headers={})\n      return Response.new(make_request('PUT', bucket, '', {'logging' => nil}, headers, logging_xml_doc))\n    end\n\n    def get_bucket_acl(bucket, headers={})\n      return get_acl(bucket, '', headers)\n    end\n\n    # returns an xml document representing the access control list.\n    # this could be parsed into an object.\n    def get_acl(bucket, key, headers={})\n      return GetResponse.new(make_request('GET', bucket, CGI::escape(key), {'acl' => nil}, headers))\n    end\n\n    def put_bucket_acl(bucket, acl_xml_doc, headers={})\n      return put_acl(bucket, '', acl_xml_doc, headers)\n    end\n\n    # sets the access control policy for the given resource.  acl_xml_doc must\n    # be a string in the acl xml format.\n    def put_acl(bucket, key, acl_xml_doc, headers={})\n      return Response.new(\n        make_request('PUT', bucket, CGI::escape(key), {'acl' => nil}, headers, acl_xml_doc, {})\n      )\n    end\n\n    def get_bucket_location(bucket)\n      return LocationResponse.new(make_request('GET', bucket, '', {'location' => nil}, {}))\n    end\n\n    def list_all_my_buckets(headers={})\n      return ListAllMyBucketsResponse.new(make_request('GET', '', '', {}, headers))\n    end\n\n    private\n    def make_request(method, bucket='', key='', path_args={}, headers={}, data='', metadata={})\n      \n      # build the domain based on the calling format\n      server = ''\n      if bucket.empty?\n        # for a bucketless request (i.e. list all buckets)\n        # revert to regular domain case since this operation\n        # does not make sense for vanity domains\n        server = @server\n      elsif @calling_format == CallingFormat::SUBDOMAIN\n        server = \"#{bucket}.#{@server}\" \n      elsif @calling_format == CallingFormat::VANITY\n        server = bucket \n      else\n        server = @server\n      end\n\n      # build the path based on the calling format\n      path = ''\n      if (not bucket.empty?) and (@calling_format == CallingFormat::PATH)\n        path << \"/#{bucket}\"\n      end\n      # add the slash after the bucket regardless\n      # the key will be appended if it is non-empty\n      path << \"/#{key}\"\n\n      # build the path_argument string\n      # add the ? in all cases since \n      # signature and credentials follow path args\n      path << S3.path_args_hash_to_string(path_args) \n\n      while true\n        http = Net::HTTP.new(server, @port)\n        http.use_ssl = @is_secure\n        http.start do\n          req = method_to_request_class(method).new(path)\n\n          set_headers(req, headers)\n          set_headers(req, metadata, METADATA_PREFIX)\n\n          set_aws_auth_header(req, @aws_access_key_id, @aws_secret_access_key, bucket, key, path_args)\n          if req.request_body_permitted?\n            resp = http.request(req, data)\n          else\n            resp = http.request(req)\n          end\n\n          case resp.code.to_i\n          when 100..299\n            return resp\n          when 300..399 # redirect\n\t    location = resp['location']\n\t    # handle missing location like a normal http error response\n\t    resp.error! if !location\n            uri = URI.parse(resp['location'])\n            server = uri.host\n            path = uri.request_uri\n            # try again...\n          else\n            resp.error!\n          end\n        end # http.start\n      end # while\n    end\n\n    def method_to_request_class(method)\n      case method\n      when 'GET'\n        return Net::HTTP::Get\n      when 'HEAD'\n        return Net::HTTP::Head\n      when 'PUT'\n        return Net::HTTP::Put\n      when 'DELETE'\n        return Net::HTTP::Delete\n      else\n        raise \"Unsupported method #{method}\"\n      end\n    end\n\n    # set the Authorization header using AWS signed header authentication\n    def set_aws_auth_header(request, aws_access_key_id, aws_secret_access_key, bucket='', key='', path_args={})\n      # we want to fix the date here if it's not already been done.\n      request['Date'] ||= Time.now.httpdate\n\n      # ruby will automatically add a random content-type on some verbs, so\n      # here we add a dummy one to 'supress' it.  change this logic if having\n      # an empty content-type header becomes semantically meaningful for any\n      # other verb.\n      request['Content-Type'] ||= ''\n\n      canonical_string =\n        S3.canonical_string(request.method, bucket, key, path_args, request.to_hash, nil)\n      encoded_canonical = S3.encode(aws_secret_access_key, canonical_string)\n\n      request['Authorization'] = \"AWS #{aws_access_key_id}:#{encoded_canonical}\"\n    end\n\n    def set_headers(request, headers, prefix='')\n      headers.each do |key, value|\n        request[prefix + key] = value\n      end\n    end\n  end\n\n\n  # This interface mirrors the AWSAuthConnection class above, but instead\n  # of performing the operations, this class simply returns a url that can\n  # be used to perform the operation with the query string authentication\n  # parameters set.\n  class QueryStringAuthGenerator\n    attr_accessor :calling_format\n    attr_accessor :expires\n    attr_accessor :expires_in\n    attr_reader :server\n    attr_reader :port\n    attr_reader :is_secure\n\n    # by default, expire in 1 minute\n    DEFAULT_EXPIRES_IN = 60\n\n    def initialize(aws_access_key_id, aws_secret_access_key, is_secure=true, \n                   server=DEFAULT_HOST, port=PORTS_BY_SECURITY[is_secure], \n                   format=CallingFormat::SUBDOMAIN)\n      @aws_access_key_id = aws_access_key_id\n      @aws_secret_access_key = aws_secret_access_key\n      @protocol = is_secure ? 'https' : 'http'\n      @server = server\n      @port = port\n      @calling_format = format \n      @is_secure = is_secure\n      # by default expire\n      @expires_in = DEFAULT_EXPIRES_IN\n    end\n\n    # set the expires value to be a fixed time.  the argument can\n    # be either a Time object or else seconds since epoch.\n    def expires=(value)\n      @expires = value\n      @expires_in = nil\n    end\n\n    # set the expires value to expire at some point in the future\n    # relative to when the url is generated.  value is in seconds.\n    def expires_in=(value)\n      @expires_in = value\n      @expires = nil\n    end\n\n    def create_bucket(bucket, headers={})\n      return generate_url('PUT', bucket, '', {}, headers)\n    end\n\n    # takes options :prefix, :marker, :max_keys, and :delimiter\n    def list_bucket(bucket, options={}, headers={})\n      path_args = {}\n      options.each { |k, v|\n        path_args[k] = v.to_s\n      }\n      return generate_url('GET', bucket, '', path_args, headers)\n    end\n\n    def delete_bucket(bucket, headers={})\n      return generate_url('DELETE', bucket, '', {}, headers)\n    end\n\n    # don't really care what object data is.  it's just for conformance with the\n    # other interface.  If this doesn't work, check tcpdump to see if the client is\n    # putting a Content-Type header on the wire.\n    def put(bucket, key, object=nil, headers={})\n      object = S3Object.new(object) if not object.instance_of? S3Object\n      return generate_url('PUT', bucket, CGI::escape(key), {}, merge_meta(headers, object))\n    end\n\n    def get(bucket, key, headers={})\n      return generate_url('GET', bucket, CGI::escape(key), {}, headers)\n    end\n\n    def delete(bucket, key, headers={})\n      return generate_url('DELETE', bucket, CGI::escape(key), {}, headers)\n    end\n\n    def get_bucket_logging(bucket, headers={})\n      return generate_url('GET', bucket, '', {'logging' => nil}, headers)\n    end\n\n    def put_bucket_logging(bucket, logging_xml_doc, headers={})\n      return generate_url('PUT', bucket, '', {'logging' => nil}, headers)\n    end\n\n    def get_acl(bucket, key='', headers={})\n      return generate_url('GET', bucket, CGI::escape(key), {'acl' => nil}, headers)\n    end\n\n    def get_bucket_acl(bucket, headers={})\n      return get_acl(bucket, '', headers)\n    end\n\n    # don't really care what acl_xml_doc is.\n    # again, check the wire for Content-Type if this fails.\n    def put_acl(bucket, key, acl_xml_doc, headers={})\n      return generate_url('PUT', bucket, CGI::escape(key), {'acl' => nil}, headers)\n    end\n\n    def put_bucket_acl(bucket, acl_xml_doc, headers={})\n      return put_acl(bucket, '', acl_xml_doc, headers)\n    end\n\n    def list_all_my_buckets(headers={})\n      return generate_url('GET', '', '', {}, headers)\n    end\n\n\n    private\n    # generate a url with the appropriate query string authentication\n    # parameters set.\n    def generate_url(method, bucket=\"\", key=\"\", path_args={}, headers={})\n      expires = 0\n      if not @expires_in.nil?\n        expires = Time.now.to_i + @expires_in\n      elsif not @expires.nil?\n        expires = @expires\n      else\n        raise \"invalid expires state\"\n      end\n\n      canonical_string =\n        S3::canonical_string(method, bucket, key, path_args, headers, expires)\n      encoded_canonical =\n        S3::encode(@aws_secret_access_key, canonical_string)\n      \n      url = CallingFormat.build_url_base(@protocol, @server, @port, bucket, @calling_format)\n      \n      path_args[\"Signature\"] = encoded_canonical.to_s\n      path_args[\"Expires\"] = expires.to_s\n      path_args[\"AWSAccessKeyId\"] = @aws_access_key_id.to_s\n      arg_string = S3.path_args_hash_to_string(path_args) \n\n      return \"#{url}/#{key}#{arg_string}\"\n    end\n\n    def merge_meta(headers, object)\n      final_headers = headers.clone\n      if not object.nil? and not object.metadata.nil?\n        object.metadata.each do |k, v|\n          final_headers[METADATA_PREFIX + k] = v\n        end\n      end\n      return final_headers\n    end\n  end\n\n  class S3Object\n    attr_accessor :data\n    attr_accessor :metadata\n    def initialize(data, metadata={})\n      @data, @metadata = data, metadata\n    end\n  end\n\n  # class for storing calling format constants\n  module CallingFormat \n    PATH      = 0 # http://s3.amazonaws.com/bucket/key\n    SUBDOMAIN = 1 # http://bucket.s3.amazonaws.com/key\n    VANITY    = 2  # http://<vanity_domain>/key  -- vanity_domain resolves to s3.amazonaws.com\n\n    # build the url based on the calling format, and bucket\n    def CallingFormat.build_url_base(protocol, server, port, bucket, format)\n      build_url_base = \"#{protocol}://\"\n      if bucket.empty?\n        build_url_base << \"#{server}:#{port}\"\n      elsif format == SUBDOMAIN\n        build_url_base << \"#{bucket}.#{server}:#{port}\"\n      elsif format == VANITY\n        build_url_base << \"#{bucket}:#{port}\"\n      else\n        build_url_base << \"#{server}:#{port}/#{bucket}\"\n      end\n      return build_url_base \n    end\n  end\n\n  class Owner\n    attr_accessor :id\n    attr_accessor :display_name\n  end\n\n  class ListEntry\n    attr_accessor :key\n    attr_accessor :last_modified\n    attr_accessor :etag\n    attr_accessor :size\n    attr_accessor :storage_class\n    attr_accessor :owner\n  end\n\n  class ListProperties\n    attr_accessor :name\n    attr_accessor :prefix\n    attr_accessor :marker\n    attr_accessor :max_keys\n    attr_accessor :delimiter\n    attr_accessor :is_truncated\n    attr_accessor :next_marker\n  end\n\n  class CommonPrefixEntry\n    attr_accessor :prefix\n  end\n\n  # Parses the list bucket output into a list of ListEntry objects, and\n  # a list of CommonPrefixEntry objects if applicable.\n  class ListBucketParser\n    attr_reader :properties\n    attr_reader :entries\n    attr_reader :common_prefixes\n\n    def initialize\n      reset\n    end\n\n    def tag_start(name, attributes)\n      if name == 'ListBucketResult'\n        @properties = ListProperties.new\n      elsif name == 'Contents'\n        @curr_entry = ListEntry.new\n      elsif name == 'Owner'\n        @curr_entry.owner = Owner.new\n      elsif name == 'CommonPrefixes'\n        @common_prefix_entry = CommonPrefixEntry.new\n      end      \n    end\n\n    # we have one, add him to the entries list\n    def tag_end(name)\n      text = @curr_text.strip\n      # this prefix is the one we echo back from the request\n      if name == 'Name'\n        @properties.name = text\n      elsif name == 'Prefix' and @is_echoed_prefix\n        @properties.prefix = text       \n        @is_echoed_prefix = nil\n      elsif name == 'Marker'\n        @properties.marker = text\n      elsif name == 'MaxKeys'\n        @properties.max_keys = text.to_i\n      elsif name == 'Delimiter'\n        @properties.delimiter = text\n      elsif name == 'IsTruncated'\n        @properties.is_truncated = text == 'true'\n      elsif name == 'NextMarker'        \n        @properties.next_marker = text\n      elsif name == 'Contents'\n        @entries << @curr_entry\n      elsif name == 'Key'\n        @curr_entry.key = text\n      elsif name == 'LastModified'\n        @curr_entry.last_modified = text\n      elsif name == 'ETag'\n        @curr_entry.etag = text\n      elsif name == 'Size'\n        @curr_entry.size = text.to_i\n      elsif name == 'StorageClass'\n        @curr_entry.storage_class = text\n      elsif name == 'ID'\n        @curr_entry.owner.id = text\n      elsif name == 'DisplayName'\n        @curr_entry.owner.display_name = text\n      elsif name == 'CommonPrefixes'\n        @common_prefixes << @common_prefix_entry         \n      elsif name == 'Prefix'\n        # this is the common prefix for keys that match up to the delimiter\n        @common_prefix_entry.prefix = text\n      end\n      @curr_text = ''\n    end\n\n    def text(text)\n        @curr_text += text\n    end\n\n    def xmldecl(version, encoding, standalone)\n      # ignore\n    end\n\n    # get ready for another parse\n    def reset\n      @is_echoed_prefix = true;\n      @entries = []\n      @curr_entry = nil\n      @common_prefixes = []\n      @common_prefix_entry = nil\n      @curr_text = ''\n    end\n  end\n\n  class ListAllMyBucketsParser\n    attr_reader :entries\n\n    def initialize\n      reset\n    end\n\n    def tag_start(name, attributes)\n      if name == 'Bucket'\n        @curr_bucket = Bucket.new\n      end\n    end\n\n    # we have one, add him to the entries list\n    def tag_end(name)\n      text = @curr_text.strip\n      if name == 'Bucket'\n        @entries << @curr_bucket\n      elsif name == 'Name'\n        @curr_bucket.name = text\n      elsif name == 'CreationDate'\n        @curr_bucket.creation_date = text\n      end\n      @curr_text = ''\n    end\n\n    def text(text)\n        @curr_text += text\n    end\n\n    def xmldecl(version, encoding, standalone)\n      # ignore\n    end\n\n    # get ready for another parse\n    def reset\n      @entries = []\n      @owner = nil\n      @curr_bucket = nil\n      @curr_text = ''\n    end\n  end\n\n  class ErrorResponseParser\n    attr_reader :code\n\n    def self.parse(msg)\n        parser = ErrorResponseParser.new\n        REXML::Document.parse_stream(msg, parser)\n        parser.code\n    end\n\n    def initialize\n      @state = :init\n      @code = nil\n    end\n\n    def tag_start(name, attributes)\n      case @state\n      when :init\n        if name == 'Error'\n          @state = :tag_error\n        else\n          @state = :bad\n        end\n      when :tag_error\n        if name == 'Code'\n          @state = :tag_code\n          @code = ''\n        else\n          @state = :bad\n        end\n      end\n    end\n\n    # we have one, add him to the entries list\n    def tag_end(name)\n      case @state\n      when :tag_code\n        @state = :done\n      end\n    end\n\n    def text(text)\n      @code += text if @state == :tag_code\n    end\n\n    def xmldecl(version, encoding, standalone)\n      # ignore\n    end\n  end\n\n  class LocationParser\n    attr_reader :location\n\n    def self.parse(msg)\n        parser = LocationParser.new\n        REXML::Document.parse_stream(msg, parser)\n        return parser.location\n    end\n\n    def initialize\n      @state = :init\n      @location = nil\n    end\n\n    def tag_start(name, attributes)\n      if @state == :init\n        if name == 'LocationConstraint'\n          @state = :tag_locationconstraint\n          @location = ''\n        else\n          @state = :bad\n        end\n      end\n    end\n\n    # we have one, add him to the entries list\n    def tag_end(name)\n      case @state\n      when :tag_locationconstraint\n        @state = :done\n      end\n    end\n\n    def text(text)\n      @location += text if @state == :tag_locationconstraint\n    end\n\n    def xmldecl(version, encoding, standalone)\n      # ignore\n    end\n  end\n\n  class Response\n    attr_reader :http_response\n    def initialize(response)\n      @http_response = response\n    end\n    \n    def message\n      if @http_response.body\n        @http_response.body\n      else\n        \"#{@http_response.code} #{@http_response.message}\"\n      end\n    end\n  end\n\n  class Bucket\n    attr_accessor :name\n    attr_accessor :creation_date\n  end\n\n  class GetResponse < Response\n    attr_reader :object\n    def initialize(response)\n      super(response)\n      metadata = get_aws_metadata(response)\n      data = response.body\n      @object = S3Object.new(data, metadata)\n    end\n\n    # parses the request headers and pulls out the s3 metadata into a hash\n    def get_aws_metadata(response)\n      metadata = {}\n      response.each do |key, value|\n        if key =~ /^#{METADATA_PREFIX}(.*)$/oi\n          metadata[$1] = value\n        end\n      end\n      return metadata\n    end\n  end\n\n  class ListBucketResponse < Response\n    attr_reader :properties\n    attr_reader :entries\n    attr_reader :common_prefix_entries\n\n    def initialize(response)\n      super(response)\n      if response.is_a? Net::HTTPSuccess\n        parser = ListBucketParser.new\n        REXML::Document.parse_stream(response.body, parser)\n        @properties = parser.properties\n        @entries = parser.entries\n        @common_prefix_entries = parser.common_prefixes\n      else\n        @entries = []\n      end\n    end\n  end\n\n  class ListAllMyBucketsResponse < Response\n    attr_reader :entries\n    def initialize(response)\n      super(response)\n      if response.is_a? Net::HTTPSuccess\n        parser = ListAllMyBucketsParser.new\n        REXML::Document.parse_stream(response.body, parser)\n        @entries = parser.entries\n      else\n        @entries = []\n      end\n    end\n  end\n\n  class LocationResponse < Response\n    attr_reader :location\n\n    def initialize(response)\n      super(response)\n      if response.is_a? Net::HTTPSuccess\n        @location = LocationParser.parse(response.body)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/redmine_s3/lib/redmine_s3/connection.rb",
    "content": "require 'S3'\nmodule RedmineS3\n  class Connection\n    @@access_key_id     = nil\n    @@secret_acces_key  = nil\n    @@bucket            = nil\n    @@uri              = nil\n    @@conn              = nil\n    \n    def self.load_options\n      yaml_string = ERB.new(File.read(\"#{RAILS_ROOT}/config/s3.yml\")).result\n      options = YAML.load(yaml_string)\n      @@access_key_id     = options[Rails.env]['access_key_id']\n      @@secret_acces_key  = options[Rails.env]['secret_access_key']\n      @@bucket            = options[Rails.env]['bucket']\n\n      if options[Rails.env]['cname_bucket'] == true\n        @@uri = \"http://#{@@bucket}\"\n      else\n        @@uri = \"http://s3.amazonaws.com/#{@@bucket}\"\n      end\n    end\n\n    def self.establish_connection\n      load_options unless @@access_key_id && @@secret_acces_key\n      @@conn = S3::AWSAuthConnection.new(@@access_key_id, @@secret_acces_key, false)\n    end\n\n    def self.conn\n      @@conn || establish_connection\n    end\n\n    def self.bucket\n      load_options unless @@bucket\n      @@bucket\n    end\n\n    def self.uri\n      load_options unless @@uri\n      @@uri\n    end\n\n    def self.create_bucket\n      begin\n        conn.create_bucket(bucket).http_response.message\n      rescue\n        puts(\"Failed to created bucket #{bucket}\")\n      end\n    end\n\n    def self.put(filename, data)\n      conn.put(bucket, filename, data)\n    end\n\n    def self.publicly_readable!(filename)\n      acl_xml = conn.get_acl(bucket, filename).object.data\n      updated_acl = S3Helper.set_acl_public_read(acl_xml)\n      conn.put_acl(bucket, filename, updated_acl).http_response.message\n    end\n\n    def self.delete(filename)\n      conn.delete(bucket, filename)\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/redmine_s3/lib/s3_helper.rb",
    "content": "require 'S3'\nrequire 'rexml/document' # for ACL Document manipulation\n\nmodule S3Helper\n\ninclude REXML\n\n  # returns public URL for key\n  def public_link(bucket_name, key='')\n    url = File.join('http://', S3::DEFAULT_HOST, bucket_name, key)\n    str = link_to(key, url)\n    str\n  end\n  \n  # sets an ACL to public-read\n  def self.set_acl_public_read(acl_doc)\n        # create Document\n        doc = Document.new(acl_doc)\n  \n        # get AccessControlList node\n        acl_node = XPath.first(doc, '//AccessControlList')\n  \n        # delete existing 'AllUsers' Grantee\n        acl_node.delete_element \"//Grant[descendant::URI[text()='http://acs.amazonaws.com/groups/global/AllUsers']]\"\n  \n        # create a new READ grant node\n        grant_node = Element.new('Grant')\n        grantee = Element.new('Grantee')\n        grantee.attributes['xmlns:xsi'] = 'http://www.w3.org/2001/XMLSchema-instance'\n        grantee.attributes['xsi:type'] = 'Group'\n  \n        uri = Element.new('URI')\n        uri << Text.new('http://acs.amazonaws.com/groups/global/AllUsers')\n        grantee.add_element(uri)\n        grant_node.add_element(grantee)\n        \n        perm = Element.new('Permission')\n        perm << Text.new('READ')\n        grant_node.add_element(perm)\n  \n        # attach the new READ grant node\n        acl_node.add_element(grant_node)\n  \n        return doc.to_s\n  end\n\n  # sets an ACL to private\n  def self.set_acl_private(acl_doc)\n        # create Document\n        doc = Document.new(acl_doc)\n  \n        # get AccessControlList node\n        acl_node = XPath.first(doc, '//AccessControlList')\n  \n        # delete existing 'AllUsers' Grantee\n        acl_node.delete_element \"//Grant[descendant::URI[text()='http://acs.amazonaws.com/groups/global/AllUsers']]\"\n  \n        return doc.to_s\n  end\n\n  # sets an ACL to public-read-write\n  def self.set_acl_public_read_write(acl_doc)\n        # create Document\n        doc = Document.new(acl_doc)\n  \n        # get AccessControlList node\n        acl_node = XPath.first(doc, '//AccessControlList')\n  \n        # delete existing 'AllUsers' Grantee\n        acl_node.delete_element \"//Grant[descendant::URI[text()='http://acs.amazonaws.com/groups/global/AllUsers']]\"\n  \n        # create a new READ grant node\n        grant_node = Element.new('Grant')\n        grantee = Element.new('Grantee')\n        grantee.attributes['xmlns:xsi'] = 'http://www.w3.org/2001/XMLSchema-instance'\n        grantee.attributes['xsi:type'] = 'Group'\n  \n        uri = Element.new('URI')\n        uri << Text.new('http://acs.amazonaws.com/groups/global/AllUsers')\n        grantee.add_element(uri)\n        grant_node.add_element(grantee)\n        \n        perm = Element.new('Permission')\n        perm << Text.new('READ')\n        grant_node.add_element(perm)\n  \n        # attach the new grant node\n        acl_node.add_element(grant_node)\n  \n        # create a new WRITE grant node\n        grant_node = Element.new('Grant')\n        grantee = Element.new('Grantee')\n        grantee.attributes['xmlns:xsi'] = 'http://www.w3.org/2001/XMLSchema-instance'\n        grantee.attributes['xsi:type'] = 'Group'\n  \n        uri = Element.new('URI')\n        uri << Text.new('http://acs.amazonaws.com/groups/global/AllUsers')\n        grantee.add_element(uri)\n        grant_node.add_element(grantee)\n        \n        perm = Element.new('Permission')\n        perm << Text.new('WRITE')\n        grant_node.add_element(perm)\n  \n        # attach the new grant tree\n        acl_node.add_element(grant_node)\n  \n        return doc.to_s\n  end\n  \nend\n"
  },
  {
    "path": "vendor/plugins/redmine_s3/test/test_helper.rb",
    "content": "# Load the normal Rails helper\nrequire File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')\n\n# Ensure that we are using the temporary fixture path\nEngines::Testing.set_fixture_path\n"
  },
  {
    "path": "vendor/plugins/rfpdf/CHANGELOG",
    "content": "1.00 Added view template functionality\n1.10 Added Chinese support\n1.11 Added Japanese support\n1.12 Added Korean support\n1.13 Updated to fpdf.rb 1.53d.\n     Added makefont and fpdf_eps.\n     Handle \\n at the beginning of a string in MultiCell.\n     Tried to fix clipping issue in MultiCell - still needs some work.\n1.14 2006-09-26\n* Added support for @options_for_rfpdf hash for configuration:\n  * Added :filename option in this hash\nIf you're using the same settings for @options_for_rfpdf often, you might want to \nput your assignment in a before_filter (perhaps overriding :filename, etc in your actions).\n"
  },
  {
    "path": "vendor/plugins/rfpdf/MIT-LICENSE",
    "content": "Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND\nNONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "vendor/plugins/rfpdf/README",
    "content": "= RFPDF Template Plugin\n\nA template plugin allowing the inclusion of ERB-enabled RFPDF template files.\n\n== Example .rb method Usage\n\nIn the controller, something like:\n\n  def mypdf\n\t\tpdf = FPDF.new()\n\n\t\t#\n\t\t# Chinese\n\t\t#\n\t\tpdf.extend(PDF_Chinese)\n\t\tpdf.AddPage\n\t\tpdf.AddBig5Font\n\t\tpdf.SetFont('Big5','',18)\n\t\tpdf.Write(5, '²{®É®ð·Å 18 C Àã«× 83 %')\n\t\ticBig5 = Iconv.new('Big5', 'UTF-8')\n\t\tpdf.Write(15, icBig5.iconv(\"宋体 should be working\"))\n\t\tsend_data pdf.Output, :filename => \"something.pdf\", :type => \"application/pdf\"\n  end\n\n== Example .rfdf Usage\n\nIn the controller, something like:\n\n  def mypdf\n\t  @options_for_rfpdf ||= {}\n\t  @options_for_rfpdf[:file_name] = \"nice_looking.pdf\"\n  end\n\nIn the layout (make sure this is the only item in the layout):\n<%= @content_for_layout %>\n  \nIn the view (mypdf.rfpdf):\n\n<%\n\tpdf = FPDF.new()\n\t#\n\t# Chinese\n\t#\n \tpdf.extend(PDF_Chinese)\n \tpdf.AddPage\n \tpdf.AddBig5Font\n \tpdf.SetFont('Big5','',18)\n \tpdf.Write(5, '²{®É®ð·Å 18 C Àã«× 83 %')\n \ticBig5 = Iconv.new('Big5', 'UTF-8')\n \tpdf.Write(15, icBig5.iconv(\"宋体 should be working\"))\n\n\t#\n\t# Japanese\n\t#\n \tpdf.extend(PDF_Japanese)\n \tpdf.AddSJISFont();\n \tpdf.AddPage();\n \tpdf.SetFont('SJIS','',18);\n \tpdf.Write(5,'9ÉñåéÇÃåˆäJÉeÉXÉgÇåoÇƒPHP 3.0ÇÕ1998îN6åéÇ…åˆéÆÇ…ÉäÉäÅ[ÉXÇ≥ÇÍÇ‹ÇµÇΩÅB');\n \ticSJIS = Iconv.new('SJIS', 'UTF-8')\n \tpdf.Write(15, icSJIS.iconv(\"これはテキストである should be working\"))\n\n\t#\n\t# Korean\n\t#\n \tpdf.extend(PDF_Korean)\n \tpdf.AddUHCFont();\n \tpdf.AddPage();\n \tpdf.SetFont('UHC','',18);\n \tpdf.Write(5,'PHP 3.0Àº 1998³â 6¿ù¿¡ °ø½ÄÀûÀ¸·Î ¸±¸®ÁîµÇ¾ú´Ù. °ø°³ÀûÀÎ Å×½ºÆ® ÀÌÈÄ¾à 9°³¿ù¸¸ÀÌ¾ú´Ù.');\n \ticUHC = Iconv.new('UHC', 'UTF-8')\n \tpdf.Write(15, icUHC.iconv(\"이것은 원본 이다\"))\n\n\t#\n\t# English\n\t#\n \tpdf.AddPage();\n\tpdf.SetFont('Arial', '', 10)\n\tpdf.Write(5, \"should be working\")\n%>\n<%=\tpdf.Output() %>\n\t  \n\t\n== Configuring\n\nYou can configure Rfpdf by using an @options_for_rfpdf hash in your controllers.\n\nHere are a few options:\n\n:filename (default: action_name.pdf)\n  Filename of PDF to generate\n\nNote: If you're using the same settings for @options_for_rfpdf often, you might want to \nput your assignment in a before_filter (perhaps overriding :filename, etc in your actions).\n\n== Problems\n\nLayouts and partials are currently not supported; just need\nto wrap the PDF generation differently.\n"
  },
  {
    "path": "vendor/plugins/rfpdf/init.rb",
    "content": "require 'rfpdf'\n\nbegin\n  ActionView::Template::register_template_handler 'rfpdf', RFPDF::View\nrescue NameError\n  # Rails < 2.1\n  RFPDF::View.backward_compatibility_mode = true\n  ActionView::Base::register_template_handler 'rfpdf', RFPDF::View\nend\n"
  },
  {
    "path": "vendor/plugins/rfpdf/lib/rfpdf/bookmark.rb",
    "content": "# Translation of the bookmark class from the PHP FPDF script from Olivier Plathey\n# Translated by Sylvain Lafleur and ?? with the help of Brian Ollenberger\n#\n# First added in 1.53b\n#\n# Usage is as follows:\n#\n# require 'fpdf'\n# require 'bookmark'\n# pdf = FPDF.new\n# pdf.extend(PDF_Bookmark)\n#\n# This allows it to be combined with other extensions, such as the Chinese\n# module.\n\nmodule PDF_Bookmark\n    def PDF_Bookmark.extend_object(o)\n        o.instance_eval('@outlines,@OutlineRoot=[],0')\n        super(o)\n    end\n\n    def Bookmark(txt,level=0,y=0)\n        y=self.GetY() if y==-1\n        @outlines.push({'t'=>txt,'l'=>level,'y'=>y,'p'=>self.PageNo()})\n    end\n\n    def putbookmarks\n        @nb=@outlines.size\n        return if @nb==0\n        lru=[]\n        level=0\n        @outlines.each_index do |i|\n            o=@outlines[i]\n            if o['l']>0\n                parent=lru[o['l']-1]\n                # Set parent and last pointers\n                @outlines[i]['parent']=parent\n                @outlines[parent]['last']=i\n                if o['l']>level\n                    # Level increasing: set first pointer\n                    @outlines[parent]['first']=i\n                end\n            else\n                @outlines[i]['parent']=@nb\n            end\n            if o['l']<=level and i>0\n                # Set prev and next pointers\n                prev=lru[o['l']]\n                @outlines[prev]['next']=i\n                @outlines[i]['prev']=prev\n            end\n            lru[o['l']]=i\n            level=o['l']\n        end\n        # Outline items\n        n=@n+1\n        @outlines.each_index do |i|\n            o=@outlines[i]\n            newobj\n            out('<</Title '+(textstring(o['t'])))\n            out('/Parent '+(n+o['parent']).to_s+' 0 R')\n            if o['prev']\n                out('/Prev '+(n+o['prev']).to_s+' 0 R')\n            end\n            if o['next']\n                out('/Next '+(n+o['next']).to_s+' 0 R')\n            end\n            if o['first']\n                out('/First '+(n+o['first']).to_s+' 0 R')\n            end\n            if o['last']\n                out('/Last '+(n+o['last']).to_s+' 0 R')\n            end\n            out(sprintf('/Dest [%d 0 R /XYZ 0 %.2f\nnull]',1+2*o['p'],(@h-o['y'])*@k))\n            out('/Count 0>>')\n            out('endobj')\n        end\n        # Outline root\n        newobj\n        @OutlineRoot=@n\n        out('<</Type /Outlines /First '+n.to_s+' 0 R')\n           out('/Last '+(n+lru[0]).to_s+' 0 R>>')\n           out('endobj')\n    end\n\n    def putresources\n        super\n        putbookmarks\n    end\n\n    def putcatalog\n        super\n        if not @outlines.empty?\n            out('/Outlines '+@OutlineRoot.to_s+' 0 R')\n            out('/PageMode /UseOutlines')\n        end\n    end\nend\n"
  },
  {
    "path": "vendor/plugins/rfpdf/lib/rfpdf/chinese.rb",
    "content": "# Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>\n# 1.12 contributed by Ed Moss.\n#\n# The MIT License\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n#\n# This is direct port of chinese.php\n#\n# Chinese PDF support.\n#\n# Usage is as follows:\n#\n# require 'fpdf'\n# require 'chinese'\n# pdf = FPDF.new\n# pdf.extend(PDF_Chinese)\n#\n# This allows it to be combined with other extensions, such as the bookmark\n# module.\n\nmodule PDF_Chinese\n\n  Big5_widths={' '=>250,'!'=>250,'\"'=>408,'#'=>668,''=>490,'%'=>875,'&'=>698,'\\''=>250,\n  \t'('=>240,')'=>240,'*'=>417,'+'=>667,','=>250,'-'=>313,'.'=>250,'/'=>520,'0'=>500,'1'=>500,\n  \t'2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>250,''=>250,\n  \t'<'=>667,'='=>667,'>'=>667,'?'=>396,'@'=>921,'A'=>677,'B'=>615,'C'=>719,'D'=>760,'E'=>625,\n  \t'F'=>552,'G'=>771,'H'=>802,'I'=>354,'J'=>354,'K'=>781,'L'=>604,'M'=>927,'N'=>750,'O'=>823,\n  \t'P'=>563,'Q'=>823,'R'=>729,'S'=>542,'T'=>698,'U'=>771,'V'=>729,'W'=>948,'X'=>771,'Y'=>677,\n  \t'Z'=>635,'['=>344,'\\\\'=>520,']'=>344,'^'=>469,'_'=>500,'`'=>250,'a'=>469,'b'=>521,'c'=>427,\n  \t'd'=>521,'e'=>438,'f'=>271,'g'=>469,'h'=>531,'i'=>250,'j'=>250,'k'=>458,'l'=>240,'m'=>802,\n  \t'n'=>531,'o'=>500,'p'=>521,'q'=>521,'r'=>365,'s'=>333,'t'=>292,'u'=>521,'v'=>458,'w'=>677,\n  \t'x'=>479,'y'=>458,'z'=>427,'{'=>480,'|'=>496,'end'=>480,'~'=>667}\n\n  GB_widths={' '=>207,'!'=>270,'\"'=>342,'#'=>467,''=>462,'%'=>797,'&'=>710,'\\''=>239,\n  \t'('=>374,')'=>374,'*'=>423,'+'=>605,','=>238,'-'=>375,'.'=>238,'/'=>334,'0'=>462,'1'=>462,\n  \t'2'=>462,'3'=>462,'4'=>462,'5'=>462,'6'=>462,'7'=>462,'8'=>462,'9'=>462,':'=>238,''=>238,\n  \t'<'=>605,'='=>605,'>'=>605,'?'=>344,'@'=>748,'A'=>684,'B'=>560,'C'=>695,'D'=>739,'E'=>563,\n  \t'F'=>511,'G'=>729,'H'=>793,'I'=>318,'J'=>312,'K'=>666,'L'=>526,'M'=>896,'N'=>758,'O'=>772,\n  \t'P'=>544,'Q'=>772,'R'=>628,'S'=>465,'T'=>607,'U'=>753,'V'=>711,'W'=>972,'X'=>647,'Y'=>620,\n  \t'Z'=>607,'['=>374,'\\\\'=>333,']'=>374,'^'=>606,'_'=>500,'`'=>239,'a'=>417,'b'=>503,'c'=>427,\n  \t'd'=>529,'e'=>415,'f'=>264,'g'=>444,'h'=>518,'i'=>241,'j'=>230,'k'=>495,'l'=>228,'m'=>793,\n  \t'n'=>527,'o'=>524,'p'=>524,'q'=>504,'r'=>338,'s'=>336,'t'=>277,'u'=>517,'v'=>450,'w'=>652,\n  \t'x'=>466,'y'=>452,'z'=>407,'{'=>370,'|'=>258,'end'=>370,'~'=>605}\n\n  def AddCIDFont(family,style,name,cw,cMap,registry)\n#ActionController::Base::logger.debug registry.to_a.join(\":\").to_s\n  \tfontkey=family.downcase+style.upcase\n  \tunless @fonts[fontkey].nil?\n  \t\tError(\"Font already added: family style\")\n\t\tend\n  \ti=@fonts.length+1\n  \tname=name.gsub(' ','')\n    @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,'ut'=>40,'cw'=>cw, 'CMap'=>cMap,'registry'=>registry}\n  end\n\n  def AddCIDFonts(family,name,cw,cMap,registry)\n  \tAddCIDFont(family,'',name,cw,cMap,registry)\n  \tAddCIDFont(family,'B',name+',Bold',cw,cMap,registry)\n  \tAddCIDFont(family,'I',name+',Italic',cw,cMap,registry)\n  \tAddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry)\n  end\n\n  def AddBig5Font(family='Big5',name='MSungStd-Light-Acro')\n  \t#Add Big5 font with proportional Latin\n  \tcw=Big5_widths\n  \tcMap='ETenms-B5-H'\n  \tregistry={'ordering'=>'CNS1','supplement'=>0}\n#ActionController::Base::logger.debug registry.to_a.join(\":\").to_s\n  \tAddCIDFonts(family,name,cw,cMap,registry)\n  end\n\n  def AddBig5hwFont(family='Big5-hw',name='MSungStd-Light-Acro')\n  \t#Add Big5 font with half-witdh Latin\n    cw = {}\n    32.upto(126) do |i|\n  \t\tcw[i.chr]=500\n\t\tend\n  \tcMap='ETen-B5-H'\n  \tregistry={'ordering'=>'CNS1','supplement'=>0}\n  \tAddCIDFonts(family,name,cw,cMap,registry)\n  end\n\n  def AddGBFont(family='GB',name='STSongStd-Light-Acro')\n  \t#Add GB font with proportional Latin\n  \tcw=GB_widths\n  \tcMap='GBKp-EUC-H'\n  \tregistry={'ordering'=>'GB1','supplement'=>2}\n  \tAddCIDFonts(family,name,cw,cMap,registry)\n  end\n\n  def AddGBhwFont(family='GB-hw',name='STSongStd-Light-Acro')\n  \t#Add GB font with half-width Latin\n    32.upto(126) do |i|\n  \t\tcw[i.chr]=500\n\t\tend\n  \tcMap='GBK-EUC-H'\n  \tregistry={'ordering'=>'GB1','supplement'=>2}\n  \tAddCIDFonts(family,name,cw,cMap,registry)\n  end\n\n  def GetStringWidth(s)\n  \tif(@CurrentFont['type']=='Type0')\n  \t\treturn GetMBStringWidth(s)\n  \telse\n  \t\treturn super(s)\n\t\tend\n  end\n\n  def GetMBStringWidth(s)\n  \t#Multi-byte version of GetStringWidth()\n  \tl=0\n  \tcw=@CurrentFont['cw']\n  \tnb=s.length\n  \ti=0\n  \twhile(i<nb)\n  \t\tc=s[i]\n  \t\tif(c<128)\n  \t\t\tl+=cw[c.chr] if cw[c.chr]\n  \t\t\ti+=1\n  \t\telse\n  \t\t\tl+=1000\n  \t\t\ti+=2\n  \t\tend\n  \tend\n  \treturn l*@FontSize/1000\n  end\n\n  def MultiCell(w,h,txt,border=0,align='L',fill=0)\n  \tif(@CurrentFont['type']=='Type0')\n  \t\tMBMultiCell(w,h,txt,border,align,fill)\n  \telse\n  \t\tsuper(w,h,txt,border,align,fill)\n\t\tend\n  end\n\n  def MBMultiCell(w,h,txt,border=0,align='L',fill=0)\n  \t#Multi-byte version of MultiCell()\n  \tcw=@CurrentFont['cw']\n  \tif(w==0)\n  \t\tw=@w-@rMargin-@x\n\t\tend\n  \twmax=(w-2*@cMargin)*1000/@FontSize\n  \ts=txt.gsub(\"\\r\",'')\n  \tnb=s.length\n  \tif(nb>0 and s[nb-1]==\"\\n\")\n  \t\tnb-=1\n\t\tend\n  \tb=0\n  \tif(border)\n  \t\tif(border==1)\n  \t\t\tborder='LTRB'\n  \t\t\tb='LRT'\n  \t\t\tb2='LR'\n  \t\telse\n  \t\t\tb2=''\n  \t\t\tif(border.to_s.index('L'))\n  \t\t\t\tb2+='L'\n\t\t\t\tend\n  \t\t\tif(border.to_s.index('R'))\n  \t\t\t\tb2+='R'\n\t\t\t\tend\n  \t\t\tb=border.to_s.index('T') ? b2+'T' : b2\n  \t\tend\n  \tend\n  \tsep=-1\n  \ti=0\n  \tj=0\n  \tl=0\n  \tnl=1\n  \twhile(i<nb)\n  \t\t#Get next character\n  \t\tc=s[i]\n  \t\t#Check if ASCII or MB\n  \t\tascii=(c<128)\n  \t\tif(c.chr==\"\\n\")\n  \t\t\t#Explicit line break\n  \t\t\tCell(w,h,s[j,i-j],b,2,align,fill)\n  \t\t\ti+=1\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n  \t\t\tnl+=1\n  \t\t\tif(border and nl==2)\n  \t\t\t\tb=b2\n\t\t\t\tend\n  \t\t\tnext\n  \t\tend\n  \t\tif(!ascii)\n  \t\t\tsep=i\n  \t\t\tls=l\n  \t\telsif(c==' ')\n  \t\t\tsep=i\n  \t\t\tls=l\n  \t\tend\n  \t\tl+=ascii ? (cw[c.chr] || 0) : 1100\n  \t\tif(l>wmax)\n  \t\t\t#Automatic line break\n  \t\t\tif(sep==-1 or i==j)\n  \t\t\t\tif(i==j)\n  \t\t\t\t\ti+=ascii ? 1 : 3\n\t\t\t\t\tend\n  \t\t\t\tCell(w,h,s[j,i-j],b,2,align,fill)\n  \t\t\telse\n  \t\t\t\tCell(w,h,s[j,sep-j],b,2,align,fill)\n  \t\t\t\ti=(s[sep]==' ') ? sep+1 : sep\n  \t\t\tend\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n#  \t\t\tnl+=1\n  \t\t\tif(border and nl==2)\n  \t\t\t\tb=b2\n  \t\t\tend\n  \t\telse\n  \t\t\ti+=ascii ? 1 : 3\n  \t\tend\n  \tend\n  \t#Last chunk\n  \tif(border and not border.to_s.index('B').nil?)\n  \t\tb+='B'\n\t\tend\n  \tCell(w,h,s[j,i-j],b,2,align,fill)\n  \t@x=@lMargin\n  end\n\n  def Write(h,txt,link='')\n  \tif(@CurrentFont['type']=='Type0')\n  \t\tMBWrite(h,txt,link)\n  \telse\n  \t\tsuper(h,txt,link)\n\t\tend\n  end\n\n  def MBWrite(h,txt,link)\n  \t#Multi-byte version of Write()\n  \tcw=@CurrentFont['cw']\n  \tw=@w-@rMargin-@x\n  \twmax=(w-2*@cMargin)*1000/@FontSize\n  \ts=txt.gsub(\"\\r\",'')\n  \tnb=s.length\n  \tsep=-1\n  \ti=0\n  \tj=0\n  \tl=0\n  \tnl=1\n  \twhile(i<nb)\n  \t\t#Get next character\n  \t\tc=s[i]\n  \t\t#Check if ASCII or MB\n  \t\tascii=(c<128)\n  \t\tif(c.chr==\"\\n\")\n  \t\t\t#Explicit line break\n  \t\t\tCell(w,h,s[j,i-j],0,2,'',0,link)\n  \t\t\ti+=1\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n  \t\t\tif(nl==1)\n  \t\t\t\t@x=@lMargin\n  \t\t\t\tw=@w-@rMargin-@x\n  \t\t\t\twmax=(w-2*@cMargin)*1000/@FontSize\n  \t\t\tend\n  \t\t\tnl+=1\n  \t\t\tnext\n  \t\tend\n  \t\tif(!ascii or c==' ')\n  \t\t\tsep=i\n\t\t\tend\n  \t\tl+=ascii ? cw[c.chr] : 1100\n  \t\tif(l>wmax)\n  \t\t\t#Automatic line break\n  \t\t\tif(sep==-1 or i==j)\n  \t\t\t\tif(@x>@lMargin)\n  \t\t\t\t\t#Move to next line\n  \t\t\t\t\t@x=@lMargin\n  \t\t\t\t\t@y+=h\n  \t\t\t\t\tw=@w-@rMargin-@x\n  \t\t\t\t\twmax=(w-2*@cMargin)*1000/@FontSize\n  \t\t\t\t\ti+=1\n  \t\t\t\t\tnl+=1\n  \t\t\t\t\tnext\n  \t\t\t\tend\n  \t\t\t\tif(i==j)\n  \t\t\t\t\ti+=ascii ? 1 : 3\n\t\t\t\t\tend\n  \t\t\t\tCell(w,h,s[j,i-j],0,2,'',0,link)\n  \t\t\telse\n  \t\t\t\tCell(w,h,s[j,sep-j],0,2,'',0,link)\n  \t\t\t\ti=(s[sep]==' ') ? sep+1 : sep\n  \t\t\tend\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n  \t\t\tif(nl==1)\n  \t\t\t\t@x=@lMargin\n  \t\t\t\tw=@w-@rMargin-@x\n  \t\t\t\twmax=(w-2*@cMargin)*1000/@FontSize\n  \t\t\tend\n  \t\t\tnl+=1\n  \t\telse\n  \t\t\ti+=ascii ? 1 : 3\n\t\t\tend\n  \tend\n  \t#Last chunk\n  \tif(i!=j)\n  \t\tCell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link)\n\t\tend\n  end\n\nprivate\n\n  def putfonts()\n  \tnf=@n\n    @diffs.each do |diff|\n  \t\t#Encodings\n  \t\tnewobj()\n  \t\tout('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['+diff+']>>')\n  \t\tout('endobj')\n  \tend\n  \t# mqr=get_magic_quotes_runtime()\n  \t# set_magic_quotes_runtime(0)\n    @FontFiles.each_pair do |file, info|\n  \t\t#Font file embedding\n  \t\tnewobj()\n  \t\t@FontFiles[file]['n']=@n\n  \t\tif(defined('FPDF_FONTPATH'))\n  \t\t\tfile=FPDF_FONTPATH+file\n\t\t\tend\n  \t\tsize=filesize(file)\n  \t\tif(!size)\n  \t\t\tError('Font file not found')\n\t\t\tend\n  \t\tout('<</Length '+size)\n  \t\tif(file[-2]=='.z')\n  \t\t\tout('/Filter /FlateDecode')\n\t\t\tend\n  \t\tout('/Length1 '+info['length1'])\n  \t\tunless info['length2'].nil?\n  \t\t\tout('/Length2 '+info['length2']+' /Length3 0')\n\t\t\tend\n  \t\tout('>>')\n  \t\tf=fopen(file,'rb')\n  \t\tputstream(fread(f,size))\n  \t\tfclose(f)\n  \t\tout('endobj')\n  \tend\n#\n  \t# set_magic_quotes_runtime(mqr)\n#\n    @fonts.each_pair do |k, font|\n  \t\t#Font objects\n  \t\tnewobj()\n  \t\t@fonts[k]['n']=@n\n  \t\tout('<</Type /Font')\n  \t\tif(font['type']=='Type0')\n  \t\t\tputType0(font)\n  \t\telse\n  \t\t\tname=font['name']\n  \t\t\tout('/BaseFont /'+name)\n  \t\t\tif(font['type']=='core')\n  \t\t\t\t#Standard font\n  \t\t\t\tout('/Subtype /Type1')\n  \t\t\t\tif(name!='Symbol' and name!='ZapfDingbats')\n  \t\t\t\t\tout('/Encoding /WinAnsiEncoding')\n  \t\t\tend\n  \t\t\telse\n  \t\t\t\t#Additional font\n  \t\t\t\tout('/Subtype /'+font['type'])\n  \t\t\t\tout('/FirstChar 32')\n  \t\t\t\tout('/LastChar 255')\n  \t\t\t\tout('/Widths '+(@n+1)+' 0 R')\n  \t\t\t\tout('/FontDescriptor '+(@n+2)+' 0 R')\n  \t\t\t\tif(font['enc'])\n  \t\t\t\t\tif !font['diff'].nil?\n  \t\t\t\t\t\tout('/Encoding '+(nf+font['diff'])+' 0 R')\n  \t\t\t\t\telse\n  \t\t\t\t\t\tout('/Encoding /WinAnsiEncoding')\n  \t\t\t\t\tend\n  \t\t\t\tend\n  \t\t\tend\n  \t\t\tout('>>')\n  \t\t\tout('endobj')\n  \t\t\tif(font['type']!='core')\n  \t\t\t\t#Widths\n  \t\t\t\tnewobj()\n  \t\t\t\tcw=font['cw']\n  \t\t\t\ts='['\n          32.upto(255) do |i|\n  \t\t\t\t\ts+=cw[i.chr]+' '\n  \t\t\t\tend\n  \t\t\t\tout(s+']')\n  \t\t\t\tout('endobj')\n  \t\t\t\t#Descriptor\n  \t\t\t\tnewobj()\n  \t\t\t\ts='<</Type /FontDescriptor /FontName /'+name\n  \t\t\t\tfont['desc'].each_pair do |k, v|\n  \t\t\t\t\ts+=' /'+k+' '+v\n  \t\t\t\tend\n  \t\t\t\tfile=font['file']\n  \t\t\t\tif(file)\n  \t\t\t\t\ts+=' /FontFile'+(font['type']=='Type1' ? '' : '2')+' '+@FontFiles[file]['n']+' 0 R'\n  \t\t\t\tend\n  \t\t\t\tout(s+'>>')\n  \t\t\t\tout('endobj')\n  \t\t\tend\n  \t\tend\n  \tend\n  end\n\n  def putType0(font)\n  \t#Type0\n  \tout('/Subtype /Type0')\n  \tout('/BaseFont /'+font['name']+'-'+font['CMap'])\n  \tout('/Encoding /'+font['CMap'])\n  \tout('/DescendantFonts ['+(@n+1).to_s+' 0 R]')\n  \tout('>>')\n  \tout('endobj')\n  \t#CIDFont\n  \tnewobj()\n  \tout('<</Type /Font')\n  \tout('/Subtype /CIDFontType0')\n  \tout('/BaseFont /'+font['name'])\n  \tout('/CIDSystemInfo <</Registry '+textstring('Adobe')+' /Ordering '+textstring(font['registry']['ordering'])+' /Supplement '+font['registry']['supplement'].to_s+'>>')\n  \tout('/FontDescriptor '+(@n+1).to_s+' 0 R')\n  \tif(font['CMap']=='ETen-B5-H')\n  \t\tw='13648 13742 500'\n  \telsif(font['CMap']=='GBK-EUC-H')\n  \t\tw='814 907 500 7716 [500]'\n  \telse\n      # ActionController::Base::logger.debug font['cw'].keys.sort.join(' ').to_s\n      # ActionController::Base::logger.debug font['cw'].values.join(' ').to_s\n  \t\tw='1 ['\n  \t\tfont['cw'].keys.sort.each {|key|\n  \t\t  w+=font['cw'][key].to_s + \" \"\n# ActionController::Base::logger.debug key.to_s\n# ActionController::Base::logger.debug font['cw'][key].to_s\n  \t\t}\n  \t\tw +=']'\n  \tend\n  \tout('/W ['+w+']>>')\n  \tout('endobj')\n  \t#Font descriptor\n  \tnewobj()\n  \tout('<</Type /FontDescriptor')\n  \tout('/FontName /'+font['name'])\n  \tout('/Flags 6')\n  \tout('/FontBBox [0 -200 1000 900]')\n  \tout('/ItalicAngle 0')\n  \tout('/Ascent 800')\n  \tout('/Descent -200')\n  \tout('/CapHeight 800')\n  \tout('/StemV 50')\n  \tout('>>')\n  \tout('endobj')\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/rfpdf/lib/rfpdf/errors.rb",
    "content": "module RFPDF\n  class GenerationError < StandardError #:nodoc:\n  end\nend"
  },
  {
    "path": "vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb",
    "content": "# Ruby FPDF 1.53d\n# FPDF 1.53 by Olivier Plathey ported to Ruby by Brian Ollenberger\n# Copyright 2005 Brian Ollenberger\n# Please retain this entire copyright notice. If you distribute any\n# modifications, place an additional comment here that clearly indicates\n# that it was modified. You may (but are not  send any useful modifications that you make\n# back to me at http://zeropluszero.com/software/fpdf/\n\n# Bug fixes, examples, external fonts, JPEG support, and upgrade to version\n# 1.53 contributed by Kim Shrier.\n#\n# Bookmark support contributed by Sylvain Lafleur.\n#\n# EPS support contributed by Thiago Jackiw, ported from the PHP version by Valentin Schmidt.\n#\n# Bookmarks contributed by Sylvain Lafleur.\n#\n# 1.53 contributed by Ed Moss\n#   Handle '\\n' at the beginning of a string\n# Bookmarks contributed by Sylvain Lafleur.\n\nrequire 'date'\nrequire 'zlib'\n\nclass FPDF\n    FPDF_VERSION = '1.53d'\n\n    Charwidths =  {\n        'courier'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],\n        \n        'courierB'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],\n        \n        'courierI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],\n        \n        'courierBI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],\n        \n        'helvetica'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500],\n        \n        'helveticaB'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556],\n        \n        'helveticaI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500],\n        \n        'helveticaBI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556],\n        \n        'times'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 408, 500, 500, 833, 778, 180, 333, 333, 500, 564, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444, 921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722, 556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500, 333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500, 500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 350, 500, 350, 333, 500, 444, 1000, 500, 500, 333, 1000, 556, 333, 889, 350, 611, 350, 350, 333, 333, 444, 444, 350, 500, 1000, 333, 980, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 333, 760, 333, 400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444, 722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500, 444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500],\n        \n        'timesB'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 555, 500, 500, 1000, 833, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778, 611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500, 333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500, 556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 1000, 350, 667, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 333, 747, 333, 400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500],\n        \n        'timesI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 420, 500, 500, 833, 778, 214, 333, 333, 500, 675, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500, 920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722, 611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500, 333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500, 500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 350, 500, 350, 333, 500, 556, 889, 500, 500, 333, 1000, 500, 333, 944, 350, 556, 350, 350, 333, 333, 556, 556, 350, 500, 889, 333, 980, 389, 333, 667, 350, 389, 556, 250, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 333, 760, 333, 400, 675, 300, 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500, 611, 611, 611, 611, 611, 611, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 667, 722, 722, 722, 722, 722, 675, 722, 722, 722, 722, 722, 556, 611, 500, 500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500, 444],\n        \n        'timesBI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 389, 555, 500, 500, 833, 778, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 832, 667, 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611, 889, 722, 722, 611, 722, 667, 556, 611, 722, 667, 889, 667, 611, 611, 333, 278, 333, 570, 500, 333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778, 556, 500, 500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 944, 350, 611, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 389, 611, 250, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 606, 333, 747, 333, 400, 570, 300, 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500, 667, 667, 667, 667, 667, 667, 944, 667, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 722, 722, 722, 722, 722, 570, 722, 722, 722, 722, 722, 611, 611, 500, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500, 444],\n        \n        'symbol'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 713, 500, 549, 833, 778, 439, 333, 333, 500, 549, 250, 549, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444, 549, 722, 667, 722, 612, 611, 763, 603, 722, 333, 631, 722, 686, 889, 722, 722, 768, 741, 556, 592, 611, 690, 439, 768, 645, 795, 611, 333, 863, 333, 658, 500, 500, 631, 549, 549, 494, 439, 521, 411, 603, 329, 603, 549, 549, 576, 521, 549, 549, 521, 549, 603, 439, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 750, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603, 400, 549, 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658, 823, 686, 795, 987, 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713, 768, 713, 790, 790, 890, 823, 549, 250, 713, 603, 603, 1042, 987, 603, 987, 603, 494, 329, 790, 790, 786, 713, 384, 384, 384, 384, 384, 384, 494, 494, 494, 494, 0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494, 494, 494, 0],\n        \n        'zapfdingbats'=>[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933, 911, 945, 974, 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537, 577, 692, 786, 788, 788, 790, 793, 794, 816, 823, 789, 841, 823, 833, 816, 831, 923, 744, 723, 749, 790, 792, 695, 776, 768, 792, 759, 707, 708, 682, 701, 826, 815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785, 791, 873, 761, 762, 762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668, 0, 390, 390, 317, 317, 276, 276, 509, 509, 410, 410, 234, 234, 334, 334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834, 873, 828, 924, 924, 917, 930, 931, 463, 883, 836, 836, 867, 867, 696, 696, 874, 0, 874, 760, 946, 771, 865, 771, 888, 967, 888, 831, 873, 927, 970, 918, 0]\n    }\n\n    def initialize(orientation='P', unit='mm', format='A4')\n        # Initialization of properties\n        @page=0\n        @n=2\n        @buffer=''\n        @pages=[]\n        @OrientationChanges=[]\n        @state=0\n        @fonts={}\n        @FontFiles={}\n        @diffs=[]\n        @images={}\n        @links=[]\n        @PageLinks={}\n        @InFooter=false\n        @FontFamily=''\n        @FontStyle=''\n        @FontSizePt=12\n        @underline= false\n        @DrawColor='0 G'\n        @FillColor='0 g'\n        @TextColor='0 g'\n        @ColorFlag=false\n        @ws=0\n        @offsets=[]\n\n        # Standard fonts\n        @CoreFonts={}\n        @CoreFonts['courier']='Courier'\n        @CoreFonts['courierB']='Courier-Bold'\n        @CoreFonts['courierI']='Courier-Oblique'\n        @CoreFonts['courierBI']='Courier-BoldOblique'\n        @CoreFonts['helvetica']='Helvetica'\n        @CoreFonts['helveticaB']='Helvetica-Bold'\n        @CoreFonts['helveticaI']='Helvetica-Oblique'\n        @CoreFonts['helveticaBI']='Helvetica-BoldOblique'\n        @CoreFonts['times']='Times-Roman'\n        @CoreFonts['timesB']='Times-Bold'\n        @CoreFonts['timesI']='Times-Italic'\n        @CoreFonts['timesBI']='Times-BoldItalic'\n        @CoreFonts['symbol']='Symbol'\n        @CoreFonts['zapfdingbats']='ZapfDingbats'\n\n        # Scale factor\n        if unit=='pt'\n            @k=1\n        elsif unit=='mm'\n            @k=72/25.4\n        elsif unit=='cm'\n            @k=72/2.54;\n        elsif unit=='in'\n            @k=72\n        else\n            raise 'Incorrect unit: '+unit\n        end\n\n        # Page format\n        if format.is_a? String\n            format.downcase!\n            if format=='a3'\n                format=[841.89,1190.55]\n            elsif format=='a4'\n                format=[595.28,841.89]\n            elsif format=='a5'\n                format=[420.94,595.28]\n            elsif format=='letter'\n                format=[612,792]\n            elsif format=='legal'\n                format=[612,1008]\n            else\n                raise 'Unknown page format: '+format\n            end\n            @fwPt,@fhPt=format\n        else\n            @fwPt=format[0]*@k\n            @fhPt=format[1]*@k\n        end\n        @fw=@fwPt/@k;\n        @fh=@fhPt/@k;\n\n        # Page orientation\n        orientation.downcase!\n        if orientation=='p' or orientation=='portrait'\n            @DefOrientation='P'\n            @wPt=@fwPt\n            @hPt=@fhPt\n        elsif orientation=='l' or orientation=='landscape'\n            @DefOrientation='L'\n            @wPt=@fhPt\n            @hPt=@fwPt\n        else\n            raise 'Incorrect orientation: '+orientation\n        end\n        @CurOrientation=@DefOrientation\n        @w=@wPt/@k\n        @h=@hPt/@k\n\n        # Page margins (1 cm)\n        margin=28.35/@k\n        SetMargins(margin,margin)\n        # Interior cell margin (1 mm)\n        @cMargin=margin/10\n        # Line width (0.2 mm)\n        @LineWidth=0.567/@k\n        # Automatic page break\n        SetAutoPageBreak(true,2*margin)\n        # Full width display mode\n        SetDisplayMode('fullwidth')\n        # Enable compression\n        SetCompression(true)\n        # Set default PDF version number\n        @PDFVersion='1.3'\n    end\n\n    def SetMargins(left, top, right=-1)\n        # Set left, top and right margins\n        @lMargin=left\n        @tMargin=top\n        right=left if right==-1\n        @rMargin=right\n    end\n\n    def SetLeftMargin(margin)\n        # Set left margin\n        @lMargin=margin\n        @x=margin if @page>0 and @x<margin\n    end\n\n    def SetTopMargin(margin)\n        # Set top margin\n        @tMargin=margin\n    end\n\n    def SetRightMargin(margin)\n        #Set right margin\n        @rMargin=margin\n    end\n\n    def SetAutoPageBreak(auto, margin=0)\n        # Set auto page break mode and triggering margin\n        @AutoPageBreak=auto\n        @bMargin=margin\n        @PageBreakTrigger=@h-margin\n    end\n\n    def SetDisplayMode(zoom, layout='continuous')\n        # Set display mode in viewer\n        if zoom=='fullpage' or zoom=='fullwidth' or zoom=='real' or\n            zoom=='default' or not zoom.kind_of? String\n\n            @ZoomMode=zoom;\n        elsif zoom=='zoom'\n            @ZoomMode=layout\n        else\n            raise 'Incorrect zoom display mode: '+zoom\n        end\n        if layout=='single' or layout=='continuous' or layout=='two' or\n            layout=='default'\n\n            @LayoutMode=layout\n        elsif zoom!='zoom'\n            raise 'Incorrect layout display mode: '+layout\n        end\n    end\n\n    def SetCompression(compress)\n        # Set page compression\n        @compress = compress\n    end\n\n    def SetTitle(title)\n        # Title of document\n        @title=title\n    end\n\n    def SetSubject(subject)\n        # Subject of document\n        @subject=subject\n    end\n\n    def SetAuthor(author)\n        # Author of document\n        @author=author\n    end\n\n    def SetKeywords(keywords)\n        # Keywords of document\n        @keywords=keywords\n    end\n\n    def SetCreator(creator)\n        # Creator of document\n        @creator=creator\n    end\n\n    def AliasNbPages(aliasnb='{nb}')\n        # Define an alias for total number of pages\n        @AliasNbPages=aliasnb\n    end\n    \n    def Error(msg)\n        raise 'FPDF error: '+msg\n    end\n\n    def Open\n        # Begin document\n        @state=1\n    end\n\n    def Close\n        # Terminate document\n        return if @state==3\n        self.AddPage if @page==0\n        # Page footer\n        @InFooter=true\n        self.Footer\n        @InFooter=false\n        # Close page\n        endpage\n        # Close document\n        enddoc\n    end\n\n    def AddPage(orientation='')\n        # Start a new page\n        self.Open if @state==0\n        family=@FontFamily\n        style=@FontStyle+(@underline ? 'U' : '')\n        size=@FontSizePt\n        lw=@LineWidth\n        dc=@DrawColor\n        fc=@FillColor\n        tc=@TextColor\n        cf=@ColorFlag\n        if @page>0\n            # Page footer\n            @InFooter=true\n            self.Footer\n            @InFooter=false\n            # Close page\n            endpage\n        end\n        # Start new page\n        beginpage(orientation)\n        # Set line cap style to square\n        out('2 J')\n        # Set line width\n        @LineWidth=lw\n        out(sprintf('%.2f w',lw*@k))\n        # Set font\n        SetFont(family,style,size) if family\n        # Set colors\n        @DrawColor=dc\n        out(dc) if dc!='0 G'\n        @FillColor=fc\n        out(fc) if fc!='0 g'\n        @TextColor=tc\n        @ColorFlag=cf\n        # Page header\n        self.Header\n        # Restore line width\n        if @LineWidth!=lw\n            @LineWidth=lw\n            out(sprintf('%.2f w',lw*@k))\n        end\n        # Restore font\n        self.SetFont(family,style,size) if family\n        # Restore colors\n        if @DrawColor!=dc\n            @DrawColor=dc\n            out(dc)\n        end\n        if @FillColor!=fc\n            @FillColor=fc\n            out(fc)\n        end\n        @TextColor=tc\n        @ColorFlag=cf\n    end\n\n    def Header\n        # To be implemented in your inherited class\n    end\n\n    def Footer\n        # To be implemented in your inherited class\n    end\n\n    def PageNo\n        # Get current page number\n        @page\n    end\n\n    def SetDrawColor(r,g=-1,b=-1)\n        # Set color for all stroking operations\n        if (r==0 and g==0 and b==0) or g==-1\n            @DrawColor=sprintf('%.3f G',r/255.0)\n        else\n            @DrawColor=sprintf('%.3f %.3f %.3f RG',r/255.0,g/255.0,b/255.0)\n        end\n        out(@DrawColor) if(@page>0)\n    end\n\n    def SetFillColor(r,g=-1,b=-1)\n        # Set color for all filling operations\n        if (r==0 and g==0 and b==0) or g==-1\n            @FillColor=sprintf('%.3f g',r/255.0)\n        else\n            @FillColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0)\n        end\n        @ColorFlag=(@FillColor!=@TextColor)\n        out(@FillColor) if(@page>0)\n    end\n\n    def SetTextColor(r,g=-1,b=-1)\n        # Set color for text\n        if (r==0 and g==0 and b==0) or g==-1\n            @TextColor=sprintf('%.3f g',r/255.0)\n        else\n            @TextColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0)\n        end\n        @ColorFlag=(@FillColor!=@TextColor)\n    end\n\n    def GetStringWidth(s)\n        # Get width of a string in the current font\n        cw=@CurrentFont['cw']\n        w=0\n        s.each_byte do |c|\n            w=w+cw[c]\n        end\n        w*@FontSize/1000.0\n    end\n\n    def SetLineWidth(width)\n        # Set line width\n        @LineWidth=width\n        out(sprintf('%.2f w',width*@k)) if @page>0\n    end\n\n    def Line(x1, y1, x2, y2)\n        # Draw a line\n        out(sprintf('%.2f %.2f m %.2f %.2f l S',\n            x1*@k,(@h-y1)*@k,x2*@k,(@h-y2)*@k))\n    end\n\n    def Rect(x, y, w, h, style='')\n        # Draw a rectangle\n        if style=='F'\n            op='f'\n        elsif style=='FD' or style=='DF'\n            op='B'\n        else\n            op='S'\n        end\n        out(sprintf('%.2f %.2f %.2f %.2f re %s', x*@k,(@h-y)*@k,w*@k,-h*@k,op))\n    end\n\n    def AddFont(family, style='', file='')\n         # Add a TrueType or Type1 font\n         family = family.downcase\n         family = 'helvetica' if family == 'arial'\n\n         style = style.upcase\n         style = 'BI' if style == 'IB'\n\n        fontkey = family + style\n\n        if @fonts.has_key?(fontkey)\n             self.Error(\"Font already added: #{family} #{style}\")\n        end\n\n        file = family.gsub(' ', '') + style.downcase + '.rb' if file == ''\n\n        if self.class.const_defined? 'FPDF_FONTPATH'\n            if FPDF_FONTPATH[-1,1] == '/'\n                file = FPDF_FONTPATH + file\n            else\n                file = FPDF_FONTPATH + '/' + file\n            end\n        end\n        \n        # Changed from \"require file\" to fix bug reported by Hans Allis.\n        load file\n\n        if FontDef.desc.nil?\n           self.Error(\"Could not include font definition file #{file}\")\n        end\n\n        i = @fonts.length + 1\n\n        @fonts[fontkey] = {'i'   => i,\n                          'type' => FontDef.type,\n                          'name' => FontDef.name,\n                          'desc' => FontDef.desc,\n                            'up' => FontDef.up,\n                            'ut' => FontDef.ut,\n                            'cw' => FontDef.cw,\n                           'enc' => FontDef.enc,\n                          'file' => FontDef.file\n                       }\n\n        if FontDef.diff\n            # Search existing encodings\n            unless @diffs.include?(FontDef.diff)\n                @diffs.push(FontDef.diff)\n                @fonts[fontkey]['diff'] = @diffs.length - 1\n            end\n        end\n\n        if FontDef.file\n             if FontDef.type == 'TrueType'\n                 @FontFiles[FontDef.file] = {'length1' => FontDef.originalsize}\n             else\n                 @FontFiles[FontDef.file] = {'length1' => FontDef.size1, 'length2' => FontDef.size2}\n            end\n        end\n\n        return self\n    end\n\n    def SetFont(family, style='', size=0)\n        # Select a font; size given in points\n        family.downcase!\n        family=@FontFamily if family==''\n        if family=='arial'\n            family='helvetica'\n        elsif family=='symbol' or family=='zapfdingbats'\n            style=''\n        end\n        style.upcase!\n        unless style.index('U').nil?\n            @underline=true\n            style.gsub!('U','')\n        else\n            @underline=false;\n        end\n        style='BI' if style=='IB'\n        size=@FontSizePt if size==0\n        # Test if font is already selected\n        return if @FontFamily==family and\n            @FontStyle==style and @FontSizePt==size\n        # Test if used for the first time\n        fontkey=family+style\n        unless @fonts.has_key?(fontkey)\n            if @CoreFonts.has_key?(fontkey)\n                unless Charwidths.has_key?(fontkey)\n                    raise 'Font unavailable'\n                end\n                @fonts[fontkey]={\n                    'i'=>@fonts.size,\n                    'type'=>'core',\n                    'name'=>@CoreFonts[fontkey],\n                    'up'=>-100,\n                    'ut'=>50,\n                    'cw'=>Charwidths[fontkey]}\n            else\n                raise 'Font unavailable'\n            end\n        end\n\n        #Select it\n        @FontFamily=family\n        @FontStyle=style;\n        @FontSizePt=size\n        @FontSize=size/@k;\n        @CurrentFont=@fonts[fontkey]\n        if @page>0\n            out(sprintf('BT /F%d %.2f Tf ET', @CurrentFont['i'], @FontSizePt))\n        end\n    end\n\n    def SetFontSize(size)\n        # Set font size in points\n        return if @FontSizePt==size\n        @FontSizePt=size\n        @FontSize=size/@k\n        if @page>0\n            out(sprintf('BT /F%d %.2f Tf ET',@CurrentFont['i'],@FontSizePt))\n        end\n    end\n\n    def AddLink\n        # Create a new internal link\n        @links.push([0, 0])\n        @links.size\n    end\n\n    def SetLink(link, y=0, page=-1)\n        # Set destination of internal link\n        y=@y if y==-1\n        page=@page if page==-1\n        @links[link]=[page, y]\n    end\n\n    def Link(x, y, w, h, link)\n        # Put a link on the page\n        @PageLinks[@page]=Array.new unless @PageLinks.has_key?(@Page)\n        @PageLinks[@page].push([x*@k,@hPt-y*@k,w*@k,h*@k,link])\n    end\n\n    def Text(x, y, txt)\n        # Output a string\n        txt.gsub!(')', '\\\\)')\n        txt.gsub!('(', '\\\\(')\n        txt.gsub!('\\\\', '\\\\\\\\')\n        s=sprintf('BT %.2f %.2f Td (%s) Tj ET',x*@k,(@h-y)*@k,txt);\n        s=s+' '+dounderline(x,y,txt) if @underline and txt!=''\n        s='q '+@TextColor+' '+s+' Q' if @ColorFlag\n        out(s)\n    end\n\n    def AcceptPageBreak\n        # Accept automatic page break or not\n        @AutoPageBreak\n    end\n\n    def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='')\n        # Output a cell\n        if @y+h>@PageBreakTrigger and !@InFooter and self.AcceptPageBreak\n            # Automatic page break\n            x=@x\n            ws=@ws\n            if ws>0\n                @ws=0\n                out('0 Tw')\n            end\n            self.AddPage(@CurOrientation)\n            @x=x\n            if ws>0\n                @ws=ws\n                out(sprintf('%.3f Tw',ws*@k))\n            end\n        end\n        w=@w-@rMargin-@x if w==0\n        s=''\n        if fill==1 or border==1\n            if fill==1\n                op=(border==1) ? 'B' : 'f'\n            else\n                op='S'\n            end\n            s=sprintf('%.2f %.2f %.2f %.2f re %s ',@x*@k,(@h-@y)*@k,w*@k,-h*@k,op)\n        end\n        if border.is_a? String\n            x=@x\n            y=@y\n            unless border.index('L').nil?\n                s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',\n                    x*@k,(@h-y)*@k,x*@k,(@h-(y+h))*@k)\n            end\n            unless border.index('T').nil?\n                s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',\n                    x*@k,(@h-y)*@k,(x+w)*@k,(@h-y)*@k)\n            end\n            unless border.index('R').nil?\n                s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',\n                    (x+w)*@k,(@h-y)*@k,(x+w)*@k,(@h-(y+h))*@k)\n            end\n            unless border.index('B').nil?\n                s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',\n                    x*@k,(@h-(y+h))*@k,(x+w)*@k,(@h-(y+h))*@k)\n            end\n        end\n        if txt!=''\n            if align=='R'\n                dx=w-@cMargin-self.GetStringWidth(txt)\n            elsif align=='C'\n                dx=(w-self.GetStringWidth(txt))/2\n            else\n                dx=@cMargin\n            end\n            txt = txt.gsub(')', '\\\\)')\n            txt.gsub!('(', '\\\\(')\n            txt.gsub!('\\\\', '\\\\\\\\')\n            if @ColorFlag\n                s=s+'q '+@TextColor+' '\n            end\n            s=s+sprintf('BT %.2f %.2f Td (%s) Tj ET',\n                (@x+dx)*@k,(@h-(@y+0.5*h+0.3*@FontSize))*@k,txt)\n            s=s+' '+dounderline(@x+dx,@y+0.5*h+0.3*@FontSize,txt) if @underline\n            s=s+' Q' if @ColorFlag\n            if link and link != ''\n                Link(@x+dx,@y+0.5*h-0.5*@FontSize,GetStringWidth(txt),@FontSize,link)\n            end\n        end\n        out(s) if s\n        @lasth=h\n        if ln>0\n            # Go to next line\n            @y=@y+h\n            @x=@lMargin if ln==1\n        else\n            @x=@x+w\n        end\n    end\n\n    def MultiCell(w,h,txt,border=0,align='J',fill=0)\n        # Output text with automatic or explicit line breaks\n        cw=@CurrentFont['cw']\n        w=@w-@rMargin-@x if w==0\n        wmax=(w-2*@cMargin)*1000/@FontSize\n        s=txt.gsub('\\r','')\n        nb=s.length\n        nb=nb-1 if nb>0 and s[nb-1].chr=='\\n'\n        b=0\n        if border!=0\n            if border==1\n                border='LTRB'\n                b='LRT'\n                b2='LR'\n            else\n                b2=''\n                b2='L' unless border.index('L').nil?\n                b2=b2+'R' unless border.index('R').nil?\n                b=(not border.index('T').nil?) ? (b2+'T') : b2\n            end\n        end\n        sep=-1\n        i=0\n        j=0\n        l=0\n        ns=0\n        nl=1\n        while i<nb\n            # Get next character\n            c=s[i].chr\n            if c==\"\\n\"\n                # Explicit line break\n                if @ws>0\n                    @ws=0\n                    out('0 Tw')\n                end\n#Ed Moss               \n# Don't let i go negative\n                end_i = i == 0 ? 0 : i - 1\n                # Changed from s[j..i] to fix bug reported by Hans Allis.\n                self.Cell(w,h,s[j..end_i],b,2,align,fill) \n#                \n                i=i+1\n                sep=-1\n                j=i\n                l=0\n                ns=0\n                nl=nl+1\n                b=b2 if border and nl==2\n            else\n                if c==' '\n                    sep=i\n                    ls=l\n                    ns=ns+1\n                end\n                l=l+cw[c[0]]\n                if l>wmax\n                    # Automatic line break\n                    if sep==-1\n                        i=i+1 if i==j\n                        if @ws>0\n                            @ws=0\n                            out('0 Tw')\n                        end\n                        self.Cell(w,h,s[j..i],b,2,align,fill)\n#Ed Moss\n# Added so that it wouldn't print the last character of the string if it got close\n#FIXME 2006-07-18 Level=0 - but it still puts out an extra new line\n                        i += 1\n#\n                    else\n                        if align=='J'\n                            @ws=(ns>1) ? (wmax-ls)/1000.0*@FontSize/(ns-1) : 0\n                            out(sprintf('%.3f Tw',@ws*@k))\n                        end\n                        self.Cell(w,h,s[j..sep],b,2,align,fill)\n                        i=sep+1\n                    end\n                    sep=-1\n                    j=i\n                    l=0\n                    ns=0\n                    nl=nl+1\n                    b=b2 if border and nl==2\n                else\n                    i=i+1\n                end\n            end\n        end\n\n        # Last chunk\n        if @ws>0\n            @ws=0\n            out('0 Tw')\n        end\n        b=b+'B' if border!=0 and not border.index('B').nil?\n        self.Cell(w,h,s[j..i],b,2,align,fill)\n        @x=@lMargin\n    end\n    \n    def Write(h,txt,link='')\n        # Output text in flowing mode\n        cw=@CurrentFont['cw']\n        w=@w-@rMargin-@x\n        wmax=(w-2*@cMargin)*1000/@FontSize\n        s=txt.gsub(\"\\r\",'')\n        nb=s.length\n        sep=-1\n        i=0\n        j=0\n        l=0\n        nl=1\n        while i<nb\n            # Get next character\n            c=s[i]\n            if c==\"\\n\"[0]\n                # Explicit line break\n                self.Cell(w,h,s[j,i-j],0,2,'',0,link)\n                i=i+1\n                sep=-1\n                j=i\n                l=0\n                if nl==1\n                    @x=@lMargin\n                    w=@w-@rMargin-@x\n                    wmax=(w-2*@cMargin)*1000/@FontSize\n                end\n                nl=nl+1\n                next\n            end\n            if c==' '[0]\n                sep=i\n                ls=l\n            end\n            l=l+cw[c];\n            if l>wmax\n                # Automatic line break\n                if sep==-1\n                    if @x>@lMargin\n                        # Move to next line\n                        @x=@lMargin\n                        @y=@y+h\n                        w=@w-@rMargin-@x\n                        wmax=(w-2*@cMargin)*1000/@FontSize\n                        i=i+1\n                        nl=nl+1\n                        next\n                    end\n                    i=i+1 if i==j\n                    self.Cell(w,h,s[j,i-j],0,2,'',0,link)\n                else\n                    self.Cell(w,h,s[j,sep-j],0,2,'',0,link)\n                    i=sep+1\n                end\n                sep=-1\n                j=i\n                l=0\n                if nl==1\n                    @x=@lMargin\n                    w=@w-@rMargin-@x\n                    wmax=(w-2*@cMargin)*1000/@FontSize\n                end\n                nl=nl+1\n            else\n                i=i+1\n            end\n        end\n        # Last chunk\n        self.Cell(l/1000.0*@FontSize,h,s[j,i],0,0,'',0,link) if i!=j\n    end\n    \n    def Image(file,x,y,w=0,h=0,type='',link='')\n        # Put an image on the page\n        unless @images.has_key?(file)\n            # First use of image, get info\n            if type==''\n                pos=file.rindex('.')\n                if pos.nil?\n                    self.Error('Image file has no extension and no type was '+\n                        'specified: '+file)\n                end\n                type=file[pos+1..-1]\n            end\n            type.downcase!\n            if type=='jpg' or type=='jpeg'\n                info=parsejpg(file)\n            elsif type=='png'\n                info=parsepng(file)\n            else\n                self.Error('Unsupported image file type: '+type)\n            end\n            info['i']=@images.length+1\n            @images[file]=info\n        else\n            info=@images[file]\n        end\n#Ed Moss\n        if(w==0 && h==0)\n      \t\t#Put image at 72 dpi\n      \t\tw=info['w']/@k;\n      \t\th=info['h']/@k;\n      \tend\n#\n        # Automatic width or height calculation\n        w=h*info['w']/info['h'] if w==0\n        h=w*info['h']/info['w'] if h==0\n        out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q',\n            w*@k,h*@k,x*@k,(@h-(y+h))*@k,info['i']))\n        Link(x,y,w,h,link) if link and link != ''\n    end\n    \n    def Ln(h='')\n        # Line feed; default value is last cell height\n        @x=@lMargin\n        if h.kind_of?(String)\n            @y=@y+@lasth\n        else\n            @y=@y+h\n        end\n    end\n\n    def GetX\n        # Get x position\n        @x\n    end\n\n    def SetX(x)\n        # Set x position\n        if x>=0\n            @x=x\n        else\n            @x=@w+x\n        end\n    end\n\n    def GetY\n        # Get y position\n        @y\n    end\n\n    def SetY(y)\n        # Set y position and reset x\n        @x=@lMargin\n        if y>=0\n            @y=y\n        else\n            @y=@h+y\n        end\n    end\n\n    def SetXY(x,y)\n        # Set x and y positions\n        SetY(y)\n        SetX(x)\n    end\n    \n    def Output(file=nil)\n        # Output PDF to file or return as a string\n        \n        # Finish document if necessary\n        self.Close if(@state<3)\n        \n        if file.nil?\n            # Return as a string\n            return @buffer\n        else\n            # Save file locally\n            open(file,'wb') do |f|\n                f.write(@buffer)\n            end\n        end\n    end\n\n    private\n  \n    def putpages\n        nb=@page\n        unless @AliasNbPages.nil? or @AliasNbPages==''\n            # Replace number of pages\n            1.upto(nb) do |n|\n                @pages[n].gsub!(@AliasNbPages,nb.to_s)\n            end\n        end\n        if @DefOrientation=='P'\n            wPt=@fwPt\n            hPt=@fhPt\n        else\n            wPt=@fhPt\n            hPt=@fwPt\n        end\n        filter=(@compress) ? '/Filter /FlateDecode ' : ''\n        1.upto(nb) do |n|\n            # Page\n            newobj\n            out('<</Type /Page')\n            out('/Parent 1 0 R')\n            unless @OrientationChanges[n].nil?\n                out(sprintf('/MediaBox [0 0 %.2f %.2f]',hPt,wPt))\n            end\n            out('/Resources 2 0 R')\n            if @PageLinks[n]\n                # Links\n                annots='/Annots ['\n                @PageLinks[n].each do |pl|\n                    rect=sprintf('%.2f %.2f %.2f %.2f',\n                        pl[0],pl[1],pl[0]+pl[2],pl[1]-pl[3])\n                    annots=annots+'<</Type /Annot /Subtype /Link /Rect ['+rect+\n                        '] /Border [0 0 0] '\n                    if pl[4].kind_of?(String)\n                        annots=annots+'/A <</S /URI /URI '+textstring(pl[4])+\n                            '>>>>'\n                    else\n                        l=@links[pl[4]]\n                        h=@OrientationChanges[l[0]].nil? ? hPt : wPt\n                        annots=annots+sprintf(\n                            '/Dest [%d 0 R /XYZ 0 %.2f null]>>',\n                            1+2*l[0],h-l[1]*@k)\n                    end\n                end\n                out(annots+']')\n            end\n            out('/Contents '+(@n+1).to_s+' 0 R>>')\n            out('endobj')\n            # Page content\n            p=(@compress) ? Zlib::Deflate.deflate(@pages[n]) : @pages[n]\n            newobj\n            out('<<'+filter+'/Length '+p.length.to_s+'>>')\n            putstream(p)\n            out('endobj')\n        end\n        # Pages root\n        @offsets[1]=@buffer.length\n        out('1 0 obj')\n        out('<</Type /Pages')\n        kids='/Kids ['\n        nb.times do |i|\n            kids=kids+(3+2*i).to_s+' 0 R '\n        end\n        out(kids+']')\n        out('/Count '+nb.to_s)\n        out(sprintf('/MediaBox [0 0 %.2f %.2f]',wPt,hPt))\n        out('>>')\n        out('endobj')\n    end\n    \n    def putfonts\n        nf=@n\n        @diffs.each do |diff|\n            # Encodings\n            newobj\n            out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences '+\n                '['+diff+']>>')\n            out('endobj')\n        end\n\n        @FontFiles.each do |file, info|\n            # Font file embedding\n            newobj\n            @FontFiles[file]['n'] = @n\n\n            if self.class.const_defined? 'FPDF_FONTPATH' then\n                if FPDF_FONTPATH[-1,1] == '/' then\n                    file = FPDF_FONTPATH + file\n                else\n                    file = FPDF_FONTPATH + '/' + file\n                end\n            end\n\n            size = File.size(file)\n            unless File.exists?(file)\n                Error('Font file not found')\n            end\n\n            out('<</Length ' + size.to_s)\n\n            if file[-2, 2] == '.z' then\n                out('/Filter /FlateDecode')\n            end\n            out('/Length1 ' + info['length1'])\n            out('/Length2 ' + info['length2'] + ' /Length3 0') if info['length2']\n            out('>>')\n            open(file, 'rb') do |f|\n                putstream(f.read())\n            end\n            out('endobj')\n        end\n\n        file = 0\n        @fonts.each do |k, font|\n            # Font objects\n            @fonts[k]['n']=@n+1\n            type=font['type']\n            name=font['name']\n            if type=='core'\n                # Standard font\n                newobj\n                out('<</Type /Font')\n                out('/BaseFont /'+name)\n                out('/Subtype /Type1')\n                if name!='Symbol' and name!='ZapfDingbats'\n                    out('/Encoding /WinAnsiEncoding')\n                end\n                out('>>')\n                out('endobj')\n            elsif type=='Type1' or type=='TrueType'\n                # Additional Type1 or TrueType font\n                newobj\n                out('<</Type /Font')\n                out('/BaseFont /'+name)\n                out('/Subtype /'+type)\n                out('/FirstChar 32 /LastChar 255')\n                out('/Widths '+(@n+1).to_s+' 0 R')\n                out('/FontDescriptor '+(@n+2).to_s+' 0 R')\n                if font['enc'] and font['enc'] != ''\n                    unless font['diff'].nil?\n                        out('/Encoding '+(nf+font['diff']).to_s+' 0 R')\n                    else\n                        out('/Encoding /WinAnsiEncoding')\n                    end\n                end\n                out('>>')\n                out('endobj')\n                # Widths\n                newobj\n                cw=font['cw']\n                s='['\n                32.upto(255) do |i|\n                    s << cw[i].to_s+' '\n                end\n                out(s+']')\n                out('endobj')\n                # Descriptor\n                newobj\n                s='<</Type /FontDescriptor /FontName /'+name\n                font['desc'].each do |k, v|\n                    s << ' /'+k+' '+v\n                end\n                file=font['file']\n                if file\n                    s << ' /FontFile'+(type=='Type1' ? '' : '2')+' '+\n                        @FontFiles[file]['n'].to_s+' 0 R'\n                end\n                out(s+'>>')\n                out('endobj')\n            else\n                # Allow for additional types\n                mtd='put'+type.downcase\n                unless self.respond_to?(mtd)\n                    self.Error('Unsupported font type: '+type)\n                end\n                self.send(mtd, font)\n            end\n        end\n    end\n    \n    def putimages\n        filter=(@compress) ? '/Filter /FlateDecode ' : ''\n        @images.each do |file, info|\n            newobj\n            @images[file]['n']=@n\n            out('<</Type /XObject')\n            out('/Subtype /Image')\n            out('/Width '+info['w'].to_s)\n            out('/Height '+info['h'].to_s)\n            if info['cs']=='Indexed'\n                out(\"/ColorSpace [/Indexed /DeviceRGB #{info['pal'].length/3-1} #{(@n+1)} 0 R]\")\n            else\n                out('/ColorSpace /'+info['cs'])\n                if info['cs']=='DeviceCMYK'\n                    out('/Decode [1 0 1 0 1 0 1 0]')\n                end\n            end\n            out('/BitsPerComponent '+info['bpc'].to_s)\n            out('/Filter /'+info['f']) if info['f']\n            unless info['parms'].nil?\n                out(info['parms'])\n            end\n            if info['trns'] and info['trns'].kind_of?(Array)\n                trns=''\n                info['trns'].length.times do |i|\n                    trns=trns+info['trns'][i].to_s+' '+info['trns'][i].to_s+' '\n                end\n                out('/Mask ['+trns+']')\n            end\n            out('/Length '+info['data'].length.to_s+'>>')\n            putstream(info['data'])\n            @images[file]['data']=nil\n            out('endobj')\n            # Palette\n            if info['cs']=='Indexed'\n                newobj\n                pal=(@compress) ? Zlib::Deflate.deflate(info['pal']) : info['pal']\n                out('<<'+filter+'/Length '+pal.length.to_s+'>>')\n                putstream(pal)\n                out('endobj')\n            end\n        end\n    end\n\n    def putxobjectdict\n        @images.each_value do |image|\n            out('/I'+image['i'].to_s+' '+image['n'].to_s+' 0 R')\n        end\n    end\n\n    def putresourcedict\n        out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]')\n        out('/Font <<')\n        @fonts.each_value do |font|\n            out('/F'+font['i'].to_s+' '+font['n'].to_s+' 0 R')\n        end\n        out('>>')\n        out('/XObject <<')\n        putxobjectdict\n        out('>>')\n    end\n\n    def putresources\n        putfonts\n        putimages\n        # Resource dictionary\n        @offsets[2]=@buffer.length\n        out('2 0 obj')\n        out('<<')\n        putresourcedict\n        out('>>')\n        out('endobj')\n    end\n    \n    def putinfo\n        out('/Producer '+textstring('Ruby FPDF '+FPDF_VERSION));\n        unless @title.nil?\n            out('/Title '+textstring(@title))\n        end\n        unless @subject.nil?\n            out('/Subject '+textstring(@subject))\n        end\n        unless @author.nil?\n            out('/Author '+textstring(@author))\n        end\n        unless @keywords.nil?\n            out('/Keywords '+textstring(@keywords))\n        end\n        unless @creator.nil?\n            out('/Creator '+textstring(@creator))\n        end\n        out('/CreationDate '+textstring('D: '+DateTime.now.to_s))\n    end\n    \n    def putcatalog\n        out('/Type /Catalog')\n        out('/Pages 1 0 R')\n        if @ZoomMode=='fullpage'\n            out('/OpenAction [3 0 R /Fit]')\n        elsif @ZoomMode=='fullwidth'\n            out('/OpenAction [3 0 R /FitH null]')\n        elsif @ZoomMode=='real'\n            out('/OpenAction [3 0 R /XYZ null null 1]')\n        elsif not @ZoomMode.kind_of?(String)\n            out('/OpenAction [3 0 R /XYZ null null '+(@ZoomMode/100)+']')\n        end\n        \n        if @LayoutMode=='single'\n            out('/PageLayout /SinglePage')\n        elsif @LayoutMode=='continuous'\n            out('/PageLayout /OneColumn')\n        elsif @LayoutMode=='two'\n            out('/PageLayout /TwoColumnLeft')\n        end\n    end\n\n    def putheader\n        out('%PDF-'+@PDFVersion)\n    end\n\n    def puttrailer\n        out('/Size '+(@n+1).to_s)\n        out('/Root '+@n.to_s+' 0 R')\n        out('/Info '+(@n-1).to_s+' 0 R')\n    end\n\n    def enddoc\n        putheader\n        putpages\n        putresources\n        # Info\n        newobj\n        out('<<')\n        putinfo\n        out('>>')\n        out('endobj')\n        # Catalog\n        newobj\n        out('<<')\n        putcatalog\n        out('>>')\n        out('endobj')\n        # Cross-ref\n        o=@buffer.length\n        out('xref')\n        out('0 '+(@n+1).to_s)\n        out('0000000000 65535 f ')\n        1.upto(@n) do |i|\n            out(sprintf('%010d 00000 n ',@offsets[i]))\n        end\n        # Trailer\n        out('trailer')\n        out('<<')\n        puttrailer\n        out('>>')\n        out('startxref')\n        out(o)\n        out('%%EOF')\n        state=3\n    end\n\n    def beginpage(orientation)\n        @page=@page+1\n        @pages[@page]=''\n        @state=2\n        @x=@lMargin\n        @y=@tMargin\n        @lasth=0\n        @FontFamily=''\n        # Page orientation\n        if orientation==''\n            orientation=@DefOrientation\n        else\n            orientation=orientation[0].chr.upcase\n            if orientation!=@DefOrientation\n                @OrientationChanges[@page]=true\n            end\n        end\n        if orientation!=@CurOrientation\n            # Change orientation\n            if orientation=='P'\n                @wPt=@fwPt\n                @hPt=@fhPt\n                @w=@fw\n                @h=@fh\n            else\n                @wPt=@fhPt\n                @hPt=@fwPt\n                @w=@fh\n                @h=@fw\n            end\n            @PageBreakTrigger=@h-@bMargin\n            @CurOrientation=orientation\n        end\n    end\n    \n    def endpage\n        # End of page contents\n        @state=1\n    end\n    \n    def newobj\n        # Begin a new object\n        @n=@n+1\n        @offsets[@n]=@buffer.length\n        out(@n.to_s+' 0 obj')\n    end\n\n    def dounderline(x,y,txt)\n        # Underline text\n        up=@CurrentFont['up']\n        ut=@CurrentFont['ut']\n        w=GetStringWidth(txt)+@ws*txt.count(' ')\n        sprintf('%.2f %.2f %.2f %.2f re f',\n            x*@k,(@h-(y-up/1000.0*@FontSize))*@k,w*@k,-ut/1000.0*@FontSizePt)\n    end\n    \n    def parsejpg(file)\n        # Extract info from a JPEG file\n        a=extractjpginfo(file)\n        raise \"Missing or incorrect JPEG file: #{file}\" if a.nil?\n\n        if a['channels'].nil? || a['channels']==3 then\n            colspace='DeviceRGB'\n        elsif a['channels']==4 then\n            colspace='DeviceCMYK'\n        else\n            colspace='DeviceGray'\n        end\n        bpc= a['bits'] ? a['bits'].to_i : 8\n\n        # Read whole file\n        data = nil\n        open(file, 'rb') do |f|\n            data = f.read\n        end\n        return {'w'=>a['width'],'h'=>a['height'],'cs'=>colspace,'bpc'=>bpc,'f'=>'DCTDecode','data'=>data}\n    end\n\n    def parsepng(file)\n        # Extract info from a PNG file\n        f=open(file,'rb')\n        # Check signature\n        unless f.read(8)==137.chr+'PNG'+13.chr+10.chr+26.chr+10.chr\n            self.Error('Not a PNG file: '+file)\n        end\n        # Read header chunk\n        f.read(4)\n        if f.read(4)!='IHDR'\n            self.Error('Incorrect PNG file: '+file)\n        end\n        w=freadint(f)\n        h=freadint(f)\n        bpc=f.read(1)[0]\n        if bpc>8\n            self.Error('16-bit depth not supported: '+file)\n        end\n        ct=f.read(1)[0]\n        if ct==0\n            colspace='DeviceGray'\n        elsif ct==2\n            colspace='DeviceRGB'\n        elsif ct==3\n            colspace='Indexed'\n        else\n            self.Error('Alpha channel not supported: '+file)\n        end\n        if f.read(1)[0]!=0\n            self.Error('Unknown compression method: '+file)\n        end\n        if f.read(1)[0]!=0\n            self.Error('Unknown filter method: '+file)\n        end\n        if f.read(1)[0]!=0\n            self.Error('Interlacing not supported: '+file)\n        end\n        f.read(4)\n        parms='/DecodeParms <</Predictor 15 /Colors '+(ct==2 ? '3' : '1')+\n            ' /BitsPerComponent '+bpc.to_s+' /Columns '+w.to_s+'>>'\n        # Scan chunks looking for palette, transparency and image data\n        pal=''\n        trns=''\n        data=''\n        begin\n            n=freadint(f)\n            type=f.read(4)\n            if type=='PLTE'\n                # Read palette\n                pal=f.read(n)\n                f.read(4)\n            elsif type=='tRNS'\n                # Read transparency info\n                t=f.read(n)\n                if ct==0\n                    trns=[t[1]]\n                elsif ct==2\n                    trns=[t[1],t[3],t[5]]\n                else\n                    pos=t.index(0)\n                    trns=[pos] unless pos.nil?\n                end\n                f.read(4)\n            elsif type=='IDAT'\n                # Read image data block\n                data << f.read(n)\n                f.read(4)\n            elsif type=='IEND'\n                break\n            else\n                f.read(n+4)\n            end\n        end while n\n        if colspace=='Indexed' and pal==''\n            self.Error('Missing palette in '+file)\n        end\n        f.close\n        {'w'=>w,'h'=>h,'cs'=>colspace,'bpc'=>bpc,'f'=>'FlateDecode',\n            'parms'=>parms,'pal'=>pal,'trns'=>trns,'data'=>data}\n    end\n\n    def freadint(f)\n        # Read a 4-byte integer from file\n        a = f.read(4).unpack('N')\n        return a[0]\n    end\n\n    def freadshort(f)\n        a = f.read(2).unpack('n')\n        return a[0]\n    end\n\n    def freadbyte(f)\n        a = f.read(1).unpack('C')\n        return a[0]\n    end\n\n    def textstring(s)\n        # Format a text string\n        '('+escape(s)+')'\n    end\n\n    def escape(s)\n        # Add \\ before \\, ( and )\n        s.gsub('\\\\','\\\\\\\\').gsub('(','\\\\(').gsub(')','\\\\)')\n    end\n\n    def putstream(s)\n        out('stream')\n        out(s)\n        out('endstream')\n    end\n\n    def out(s)\n        # Add a line to the document\n        if @state==2\n            @pages[@page]=@pages[@page]+s+\"\\n\"\n        else\n            @buffer=@buffer+s.to_s+\"\\n\"\n        end\n    end\n\n    # jpeg marker codes\n\n    M_SOF0  = 0xc0\n    M_SOF1  = 0xc1\n    M_SOF2  = 0xc2\n    M_SOF3  = 0xc3\n\n    M_SOF5  = 0xc5\n    M_SOF6  = 0xc6\n    M_SOF7  = 0xc7\n\n    M_SOF9  = 0xc9\n    M_SOF10 = 0xca\n    M_SOF11 = 0xcb\n\n    M_SOF13 = 0xcd\n    M_SOF14 = 0xce\n    M_SOF15 = 0xcf\n\n    M_SOI   = 0xd8\n    M_EOI   = 0xd9\n    M_SOS   = 0xda\n\n    def extractjpginfo(file)\n        result = nil\n\n        open(file, \"rb\") do |f|\n            marker = jpegnextmarker(f)\n\n            if marker != M_SOI\n                return nil\n            end\n\n            while true\n                marker = jpegnextmarker(f)\n\n                case marker\n                  when M_SOF0,  M_SOF1,  M_SOF2,  M_SOF3,\n                       M_SOF5,  M_SOF6,  M_SOF7,  M_SOF9,\n                     M_SOF10, M_SOF11, M_SOF13, M_SOF14,\n                     M_SOF15 then\n\n                    length = freadshort(f)\n\n                    if result.nil?\n                        result = {}\n\n                        result['bits']     = freadbyte(f)\n                        result['height']   = freadshort(f)\n                        result['width']    = freadshort(f)\n                        result['channels'] = freadbyte(f)\n\n                        f.seek(length - 8, IO::SEEK_CUR)\n                    else\n                        f.seek(length - 2, IO::SEEK_CUR)\n                    end\n                when M_SOS, M_EOI then\n                    return result\n                else\n                    length = freadshort(f)\n                    f.seek(length - 2, IO::SEEK_CUR)\n                end\n            end\n        end\n    end\n\n    def jpegnextmarker(f)\n        while true\n            # look for 0xff\n            while (c = freadbyte(f)) != 0xff\n            end\n\n            c = freadbyte(f)\n\n            if c != 0\n                return c\n            end\n        end\n    end\nend\n"
  },
  {
    "path": "vendor/plugins/rfpdf/lib/rfpdf/fpdf_eps.rb",
    "content": "# Information\n# \n# PDF_EPS class from Valentin Schmidt ported to ruby by Thiago Jackiw (tjackiw@gmail.com) \n# working for Mingle LLC (www.mingle.com)\n# Release Date: July 13th, 2006\n# \n# Description\n# \n# This script allows to embed vector-based Adobe Illustrator (AI) or AI-compatible EPS files. \n# Only vector drawing is supported, not text or bitmap. Although the script was successfully \n# tested with various AI format versions, best results are probably achieved with files that \n# were exported in the AI3 format (tested with Illustrator CS2, Freehand MX and Photoshop CS2).\n# \n# ImageEps(string file, float x, float y [, float w [, float h [, string link [, boolean useBoundingBox]]]])\n# \n# Same parameters as for regular FPDF::Image() method, with an additional one:\n# \n# useBoundingBox: specifies whether to position the bounding box (true) or the complete canvas (false) \n# at location (x,y). Default value is true.\n#\n# First added to the Ruby FPDF distribution in 1.53c\n#\n# Usage is as follows:\n#\n# require 'fpdf'\n# require 'fpdf_eps'\n# pdf = FPDF.new\n# pdf.extend(PDF_EPS)\n# pdf.ImageEps(...)\n#\n# This allows it to be combined with other extensions, such as the bookmark\n# module.\n\nmodule PDF_EPS\n    def ImageEps(file, x, y, w=0, h=0, link='', use_bounding_box=true)\n        data = nil\n        if File.exists?(file)\n            File.open(file, 'rb') do |f|\n                data = f.read()\n            end\n        else\n            Error('EPS file not found: '+file)\n        end\n        \n        # Find BoundingBox param\n        regs = data.scan(/%%BoundingBox: [^\\r\\n]*/m)\n        regs << regs[0].gsub(/%%BoundingBox: /, '')\n        if regs.size > 1\n            tmp = regs[1].to_s.split(' ')\n            @x1 = tmp[0].to_i\n            @y1 = tmp[1].to_i\n            @x2 = tmp[2].to_i\n            @y2 = tmp[3].to_i\n        else\n            Error('No BoundingBox found in EPS file: '+file)\n        end\n        f_start = data.index('%%EndSetup')\n        f_start = data.index('%%EndProlog') if f_start === false\n        f_start = data.index('%%BoundingBox') if f_start === false\n        \n        data = data.slice(f_start, data.length)\n        \n        f_end = data.index('%%PageTrailer')\n        f_end = data.index('showpage') if f_end === false\n        data = data.slice(0, f_end) if f_end\n        \n        # save the current graphic state\n        out('q')\n        \n        k = @k\n        \n        # Translate\n        if use_bounding_box\n            dx = x*k-@x1\n            dy = @hPt-@y2-y*k\n        else\n            dx = x*k\n            dy = -y*k\n        end\n        tm = [1,0,0,1,dx,dy]\n        out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm',\n            tm[0], tm[1], tm[2], tm[3], tm[4], tm[5]))\n        \n        if w > 0\n            scale_x = w/((@x2-@x1)/k)\n            if h > 0\n                scale_y = h/((@y2-@y1)/k)\n            else\n                scale_y = scale_x\n                h = (@y2-@y1)/k * scale_y\n            end\n        else\n            if h > 0\n                scale_y = $h/((@y2-@y1)/$k)\n                scale_x = scale_y\n                w = (@x2-@x1)/k * scale_x\n            else\n                w = (@x2-@x1)/k\n                h = (@y2-@y1)/k\n            end\n        end\n        \n        if !scale_x.nil?\n            # Scale\n            tm = [scale_x,0,0,scale_y,0,@hPt*(1-scale_y)]\n            out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm',\n                tm[0], tm[1], tm[2], tm[3], tm[4], tm[5]))\n        end\n        \n        data.split(/\\r\\n|[\\r\\n]/).each do |line|\n            next if line == '' || line[0,1] == '%'\n            len = line.length\n            # next if (len > 2 && line[len-2,len] != ' ')\n            cmd = line[len-2,len].strip\n            case cmd\n                when 'm', 'l', 'v', 'y', 'c', 'k', 'K', 'g', 'G', 's', 'S', 'J', 'j', 'w', 'M', 'd':\n                    out(line)\n                \n                when 'L':\n                    line[len-1,len]='l'\n                    out(line)\n                \n                when 'C':\n                    line[len-1,len]='c'\n                    out(line)\n                \n                when 'f', 'F':\n                    out('f*')\n                \n                when 'b', 'B':\n                    out(cmd + '*')\n            end\n        end\n        \n        # restore previous graphic state\n        out('Q')\n        Link(x,y,w,h,link) if link\n    end\nend\n"
  },
  {
    "path": "vendor/plugins/rfpdf/lib/rfpdf/japanese.rb",
    "content": "# Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>\n# 1.12 contributed by Ed Moss.\n#\n# The MIT License\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n#\n# This is direct port of japanese.php\n#\n# Japanese PDF support.\n#\n# Usage is as follows:\n#\n# require 'fpdf'\n# require 'chinese'\n# pdf = FPDF.new\n# pdf.extend(PDF_Japanese)\n#\n# This allows it to be combined with other extensions, such as the bookmark\n# module.\n\nmodule PDF_Japanese\n\n  SJIS_widths={' ' => 278, '!' => 299, '\"' => 353, '#' => 614, '$' => 614, '%' => 721, '&' => 735, '\\'' => 216, \n  \t'(' => 323, ')' => 323, '*' => 449, '+' => 529, ',' => 219, '-' => 306, '.' => 219, '/' => 453, '0' => 614, '1' => 614, \n  \t'2' => 614, '3' => 614, '4' => 614, '5' => 614, '6' => 614, '7' => 614, '8' => 614, '9' => 614, ':' => 219, ';' => 219, \n  \t'<' => 529, '=' => 529, '>' => 529, '?' => 486, '@' => 744, 'A' => 646, 'B' => 604, 'C' => 617, 'D' => 681, 'E' => 567, \n  \t'F' => 537, 'G' => 647, 'H' => 738, 'I' => 320, 'J' => 433, 'K' => 637, 'L' => 566, 'M' => 904, 'N' => 710, 'O' => 716, \n  \t'P' => 605, 'Q' => 716, 'R' => 623, 'S' => 517, 'T' => 601, 'U' => 690, 'V' => 668, 'W' => 990, 'X' => 681, 'Y' => 634, \n  \t'Z' => 578, '[' => 316, '\\\\' => 614, ']' => 316, '^' => 529, '_' => 500, '`' => 387, 'a' => 509, 'b' => 566, 'c' => 478, \n  \t'd' => 565, 'e' => 503, 'f' => 337, 'g' => 549, 'h' => 580, 'i' => 275, 'j' => 266, 'k' => 544, 'l' => 276, 'm' => 854, \n  \t'n' => 579, 'o' => 550, 'p' => 578, 'q' => 566, 'r' => 410, 's' => 444, 't' => 340, 'u' => 575, 'v' => 512, 'w' => 760, \n  \t'x' => 503, 'y' => 529, 'z' => 453, '{' => 326, '|' => 380, '}' => 326, '~' => 387}\n\n  def AddCIDFont(family,style,name,cw,cMap,registry)  \t\n    fontkey=family.downcase+style.upcase\n  \tunless @fonts[fontkey].nil?\n  \t\tError(\"CID font already added: family style\")\n  \tend  \n  \ti=@fonts.length+1\n  \t@fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-120,'ut'=>40,'cw'=>cw,\n  \t  'CMap'=>cMap,'registry'=>registry}\n  end\n\n  def AddCIDFonts(family,name,cw,cMap,registry)\n  \tAddCIDFont(family,'',name,cw,cMap,registry)\n  \tAddCIDFont(family,'B',name+',Bold',cw,cMap,registry)\n  \tAddCIDFont(family,'I',name+',Italic',cw,cMap,registry)\n  \tAddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry)\n  end\n\n  def AddSJISFont(family='SJIS')\n  \t#Add SJIS font with proportional Latin\n  \tname='KozMinPro-Regular-Acro'\n  \tcw=SJIS_widths\n  \tcMap='90msp-RKSJ-H'\n  \tregistry={'ordering'=>'Japan1','supplement'=>2}\n  \tAddCIDFonts(family,name,cw,cMap,registry)\n  end\n\n  def AddSJIShwFont(family='SJIS-hw')\n  \t#Add SJIS font with half-width Latin\n  \tname='KozMinPro-Regular-Acro'\n    32.upto(126) do |i|\n  \t\tcw[i.chr]=500\n  \tend  \n  \tcMap='90ms-RKSJ-H'\n  \tregistry={'ordering'=>'Japan1','supplement'=>2}\n  \tAddCIDFonts(family,name,cw,cMap,registry)\n  end\n\n  def GetStringWidth(s)\n  \tif(@CurrentFont['type']=='Type0')\n  \t\treturn GetSJISStringWidth(s)\n  \telse\n  \t\treturn super(s)\n  \tend  \n  end\n\n  def GetSJISStringWidth(s)\n  \t#SJIS version of GetStringWidth()\n  \tl=0\n  \tcw=@CurrentFont['cw']\n  \tnb=s.length\n  \ti=0\n  \twhile(i<nb)\n  \t\to=s[i]\n  \t\tif(o<128)\n  \t\t\t#ASCII\n  \t\t\tl+=cw[o.chr]\n  \t\t\ti+=1\n  \t\telsif(o>=161 and o<=223)\n  \t\t\t#Half-width katakana\n  \t\t\tl+=500\n  \t\t\ti+=1\n  \t\telse\n  \t\t\t#Full-width character\n  \t\t\tl+=1000\n  \t\t\ti+=2\n  \t\tend\n  \tend\n  \treturn l*@FontSize/1000\n  end\n\n  def MultiCell(w,h,txt,border=0,align='L',fill=0)\n  \tif(@CurrentFont['type']=='Type0')\n  \t\tSJISMultiCell(w,h,txt,border,align,fill)\n  \telse\n  \t\tsuper(w,h,txt,border,align,fill)\n  \tend  \n  end\n\n  def SJISMultiCell(w,h,txt,border=0,align='L',fill=0)\n  \t#Output text with automatic or explicit line breaks\n  \tcw=@CurrentFont['cw']\n  \tif(w==0)\n  \t\tw=@w-@rMargin-@x\n  \tend  \n  \twmax=(w-2*@cMargin)*1000/@FontSize\n  \ts=txt.gsub(\"\\r\",'')\n  \tnb=s.length\n  \tif(nb>0 and s[nb-1]==\"\\n\")\n  \t\tnb-=1\n  \tend  \n  \tb=0\n  \tif(border)\n  \t\tif(border==1)\n  \t\t\tborder='LTRB'\n  \t\t\tb='LRT'\n  \t\t\tb2='LR'\n  \t\telse\n  \t\t\tb2=''\n  \t\t\tif(border.to_s.index('L'))\n  \t\t\t\tb2+='L'\n      \tend  \n  \t\t\tif(border.to_s.index('R'))\n  \t\t\t\tb2+='R'\n      \tend  \n  \t\t\tb=border.to_s.index('T') ? b2+'T' : b2\n  \t\tend\n  \tend\n  \tsep=-1\n  \ti=0\n  \tj=0\n  \tl=0\n  \tnl=1\n  \twhile(i<nb)\n  \t\t#Get next character\n  \t\tc=s[i]\n  \t\to=c #o=ord(c)\n  \t\tif(o==10)\n  \t\t\t#Explicit line break\n  \t\t\tCell(w,h,s[j,i-j],b,2,align,fill)\n  \t\t\ti+=1\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n  \t\t\tnl+=1\n  \t\t\tif(border and nl==2)\n  \t\t\t\tb=b2\n      \tend  \n  \t\t\tnext\n  \t\tend\n  \t\tif(o<128)\n  \t\t\t#ASCII\n  \t\t\tl+=cw[c.chr]\n  \t\t\tn=1\n  \t\t\tif(o==32)\n  \t\t\t\tsep=i\n      \tend  \n  \t\telsif(o>=161 and o<=223)\n  \t\t\t#Half-width katakana\n  \t\t\tl+=500\n  \t\t\tn=1\n  \t\t\tsep=i\n  \t\telse\n  \t\t\t#Full-width character\n  \t\t\tl+=1000\n  \t\t\tn=2\n  \t\t\tsep=i\n  \t\tend\n  \t\tif(l>wmax)\n  \t\t\t#Automatic line break\n  \t\t\tif(sep==-1 or i==j)\n  \t\t\t\tif(i==j)\n  \t\t\t\t\ti+=n\n        \tend  \n  \t\t\t\tCell(w,h,s[j,i-j],b,2,align,fill)\n  \t\t\telse\n  \t\t\t\tCell(w,h,s[j,sep-j],b,2,align,fill)\n  \t\t\t\ti=(s[sep]==' ') ? sep+1 : sep\n  \t\t\tend\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n  \t\t\tnl+=1\n  \t\t\tif(border and nl==2)\n  \t\t\t\tb=b2\n      \tend  \n  \t\telse\n  \t\t\ti+=n\n  \t\t\tif(o>=128)\n  \t\t\t\tsep=i\n  \t\t\tend\n  \t\tend\n  \tend\n  \t#Last chunk\n  \tif(border and not border.to_s.index('B').nil?)\n  \t\tb+='B'\n  \tend  \n  \tCell(w,h,s[j,i-j],b,2,align,fill)\n  \t@x=@lMargin\n  end\n\n  def Write(h,txt,link='')\n  \tif(@CurrentFont['type']=='Type0')\n  \t\tSJISWrite(h,txt,link)\n  \telse\n  \t\tsuper(h,txt,link)\n  \tend  \n  end\n\n  def SJISWrite(h,txt,link)\n  \t#SJIS version of Write()\n  \tcw=@CurrentFont['cw']\n  \tw=@w-@rMargin-@x\n  \twmax=(w-2*@cMargin)*1000/@FontSize\n  \ts=txt.gsub(\"\\r\",'')\n  \tnb=s.length\n  \tsep=-1\n  \ti=0\n  \tj=0\n  \tl=0\n  \tnl=1\n  \twhile(i<nb)\n  \t\t#Get next character\n  \t\tc=s[i]\n  \t\to=c\n  \t\tif(o==10)\n  \t\t\t#Explicit line break\n  \t\t\tCell(w,h,s[j,i-j],0,2,'',0,link)\n  \t\t\ti+=1\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n  \t\t\tif(nl==1)\n  \t\t\t\t#Go to left margin\n  \t\t\t\t@x=@lMargin\n  \t\t\t\tw=@w-@rMargin-@x\n  \t\t\t\twmax=(w-2*@cMargin)*1000/@FontSize\n  \t\t\tend\n  \t\t\tnl+=1\n  \t\t\tnext\n  \t\tend\n  \t\tif(o<128)\n  \t\t\t#ASCII\n  \t\t\tl+=cw[c.chr]\n  \t\t\tn=1\n  \t\t\tif(o==32)\n  \t\t\t\tsep=i\n      \tend  \n  \t\telsif(o>=161 and o<=223)\n  \t\t\t#Half-width katakana\n  \t\t\tl+=500\n  \t\t\tn=1\n  \t\t\tsep=i\n  \t\telse\n  \t\t\t#Full-width character\n  \t\t\tl+=1000\n  \t\t\tn=2\n  \t\t\tsep=i\n  \t\tend\n  \t\tif(l>wmax)\n  \t\t\t#Automatic line break\n  \t\t\tif(sep==-1 or i==j)\n  \t\t\t\tif(@x>@lMargin)\n  \t\t\t\t\t#Move to next line\n  \t\t\t\t\t@x=@lMargin\n  \t\t\t\t\t@y+=h\n  \t\t\t\t\tw=@w-@rMargin-@x\n  \t\t\t\t\twmax=(w-2*@cMargin)*1000/@FontSize\n  \t\t\t\t\ti+=n\n  \t\t\t\t\tnl+=1\n  \t\t\t\t\tnext\n  \t\t\t\tend\n  \t\t\t\tif(i==j)\n  \t\t\t\t\ti+=n\n        \tend  \n  \t\t\t\tCell(w,h,s[j,i-j],0,2,'',0,link)\n  \t\t\telse\n  \t\t\t\tCell(w,h,s[j,sep-j],0,2,'',0,link)\n  \t\t\t\ti=(s[sep]==' ') ? sep+1 : sep\n  \t\t\tend\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n  \t\t\tif(nl==1)\n  \t\t\t\t@x=@lMargin\n  \t\t\t\tw=@w-@rMargin-@x\n  \t\t\t\twmax=(w-2*@cMargin)*1000/@FontSize\n  \t\t\tend\n  \t\t\tnl+=1\n  \t\telse\n  \t\t\ti+=n\n  \t\t\tif(o>=128)\n  \t\t\t\tsep=i\n      \tend  \n  \t\tend\n  \tend\n  \t#Last chunk\n  \tif(i!=j)\n  \t\tCell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link)\n  \tend  \n  end\n  \nprivate\n\n  def putfonts()\n  \tnf=@n\n    @diffs.each do |diff|\n  \t\t#Encodings\n  \t\tnewobj()\n  \t\tout('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['+diff+']>>')\n  \t\tout('endobj')\n  \tend\n  \t# mqr=get_magic_quotes_runtime()\n  \t# set_magic_quotes_runtime(0)\n    @FontFiles.each_pair do |file, info|\n  \t\t#Font file embedding\n  \t\tnewobj()\n  \t\t@FontFiles[file]['n']=@n\n  \t\tif(defined('FPDF_FONTPATH'))\n  \t\t\tfile=FPDF_FONTPATH+file\n    \tend  \n  \t\tsize=filesize(file)\n  \t\tif(!size)\n  \t\t\tError('Font file not found')\n    \tend  \n  \t\tout('<</Length '+size)\n  \t\tif(file[-2]=='.z')\n  \t\t\tout('/Filter /FlateDecode')\n    \tend  \n  \t\tout('/Length1 '+info['length1'])\n  \t\tunless info['length2'].nil?\n  \t\t\tout('/Length2 '+info['length2']+' /Length3 0')\n    \tend  \n  \t\tout('>>')\n  \t\tf=fopen(file,'rb')\n  \t\tputstream(fread(f,size))\n  \t\tfclose(f)\n  \t\tout('endobj')\n  \tend\n  \t# set_magic_quotes_runtime(mqr)\n    @fonts.each_pair do |k, font|\n  \t\t#Font objects\n  \t\tnewobj()\n  \t\t@fonts[k]['n']=@n\n  \t\tout('<</Type /Font')\n  \t\tif(font['type']=='Type0')\n  \t\t\tputType0(font)\n  \t\telse\n  \t\t\tname=font['name']\n  \t\t\tout('/BaseFont /'+name)\n  \t\t\tif(font['type']=='core')\n  \t\t\t\t#Standard font\n  \t\t\t\tout('/Subtype /Type1')\n  \t\t\t\tif(name!='Symbol' and name!='ZapfDingbats')\n  \t\t\t\t\tout('/Encoding /WinAnsiEncoding')\n  \t\t\t\tend\n  \t\t\telse\n  \t\t\t\t#Additional font\n  \t\t\t\tout('/Subtype /'+font['type'])\n  \t\t\t\tout('/FirstChar 32')\n  \t\t\t\tout('/LastChar 255')\n  \t\t\t\tout('/Widths '+(@n+1)+' 0 R')\n  \t\t\t\tout('/FontDescriptor '+(@n+2)+' 0 R')\n  \t\t\t\tif(font['enc'])\n  \t\t\t\t\tif !font['diff'].nil?\n  \t\t\t\t\t\tout('/Encoding '+(nf+font['diff'])+' 0 R')\n  \t\t\t\t\telse\n  \t\t\t\t\t\tout('/Encoding /WinAnsiEncoding')\n          \tend  \n  \t\t\t\tend\n  \t\t\tend\n  \t\t\tout('>>')\n  \t\t\tout('endobj')\n  \t\t\tif(font['type']!='core')\n  \t\t\t\t#Widths\n  \t\t\t\tnewobj()\n  \t\t\t\tcw=font['cw']\n  \t\t\t\ts='['\n          32.upto(255) do |i|\n  \t\t\t\t\ts+=cw[i.chr]+' '\n        \tend  \n  \t\t\t\tout(s+']')\n  \t\t\t\tout('endobj')\n  \t\t\t\t#Descriptor\n  \t\t\t\tnewobj()\n  \t\t\t\ts='<</Type /FontDescriptor /FontName /'+name\n  \t\t\t\tfont['desc'].each_pair do |k, v|\n  \t\t\t\t\ts+=' /'+k+' '+v\n        \tend  \n  \t\t\t\tfile=font['file']\n  \t\t\t\tif(file)\n  \t\t\t\t\ts+=' /FontFile'+(font['type']=='Type1' ? '' : '2')+' '+@FontFiles[file]['n']+' 0 R'\n        \tend  \n  \t\t\t\tout(s+'>>')\n  \t\t\t\tout('endobj')\n  \t\t\tend\n  \t\tend\n  \tend\n  end\n\n  def putType0(font)\n  \t#Type0\n  \tout('/Subtype /Type0')\n  \tout('/BaseFont /'+font['name']+'-'+font['CMap'])\n  \tout('/Encoding /'+font['CMap'])\n  \tout('/DescendantFonts ['+(@n+1).to_s+' 0 R]')\n  \tout('>>')\n  \tout('endobj')\n  \t#CIDFont\n  \tnewobj()\n  \tout('<</Type /Font')\n  \tout('/Subtype /CIDFontType0')\n  \tout('/BaseFont /'+font['name'])\n  \tout('/CIDSystemInfo <</Registry (Adobe) /Ordering ('+font['registry']['ordering']+') /Supplement '+font['registry']['supplement'].to_s+'>>')\n  \tout('/FontDescriptor '+(@n+1).to_s+' 0 R')\n  \tw='/W [1 ['\n\t\tfont['cw'].keys.sort.each {|key|\n\t\t  w+=font['cw'][key].to_s + \" \"\n# ActionController::Base::logger.debug key.to_s\n# ActionController::Base::logger.debug font['cw'][key].to_s\n\t\t}\n  \tout(w+'] 231 325 500 631 [500] 326 389 500]')\n  \tout('>>')\n  \tout('endobj')\n  \t#Font descriptor\n  \tnewobj()\n  \tout('<</Type /FontDescriptor')\n  \tout('/FontName /'+font['name'])\n  \tout('/Flags 6')\n  \tout('/FontBBox [0 -200 1000 900]')\n  \tout('/ItalicAngle 0')\n  \tout('/Ascent 800')\n  \tout('/Descent -200')\n  \tout('/CapHeight 800')\n  \tout('/StemV 60')\n  \tout('>>')\n  \tout('endobj')\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/rfpdf/lib/rfpdf/korean.rb",
    "content": "# Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>\n# 1.12 contributed by Ed Moss.\n#\n# The MIT License\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n#\n# This is direct port of korean.php\n#\n# Korean PDF support.\n#\n# Usage is as follows:\n#\n# require 'fpdf'\n# require 'chinese'\n# pdf = FPDF.new\n# pdf.extend(PDF_Korean)\n#\n# This allows it to be combined with other extensions, such as the bookmark\n# module.\n\nmodule PDF_Korean\n\nUHC_widths={' ' => 333, '!' => 416, '\"' => 416, '#' => 833, '$' => 625, '%' => 916, '&' => 833, '\\'' => 250, \n\t'(' => 500, ')' => 500, '*' => 500, '+' => 833, ',' => 291, '-' => 833, '.' => 291, '/' => 375, '0' => 625, '1' => 625, \n\t'2' => 625, '3' => 625, '4' => 625, '5' => 625, '6' => 625, '7' => 625, '8' => 625, '9' => 625, ':' => 333, ';' => 333, \n\t'<' => 833, '=' => 833, '>' => 916, '?' => 500, '@' => 1000, 'A' => 791, 'B' => 708, 'C' => 708, 'D' => 750, 'E' => 708, \n\t'F' => 666, 'G' => 750, 'H' => 791, 'I' => 375, 'J' => 500, 'K' => 791, 'L' => 666, 'M' => 916, 'N' => 791, 'O' => 750, \n\t'P' => 666, 'Q' => 750, 'R' => 708, 'S' => 666, 'T' => 791, 'U' => 791, 'V' => 750, 'W' => 1000, 'X' => 708, 'Y' => 708, \n\t'Z' => 666, '[' => 500, '\\\\' => 375, ']' => 500, '^' => 500, '_' => 500, '`' => 333, 'a' => 541, 'b' => 583, 'c' => 541, \n\t'd' => 583, 'e' => 583, 'f' => 375, 'g' => 583, 'h' => 583, 'i' => 291, 'j' => 333, 'k' => 583, 'l' => 291, 'm' => 875, \n\t'n' => 583, 'o' => 583, 'p' => 583, 'q' => 583, 'r' => 458, 's' => 541, 't' => 375, 'u' => 583, 'v' => 583, 'w' => 833, \n\t'x' => 625, 'y' => 625, 'z' => 500, '{' => 583, '|' => 583, '}' => 583, '~' => 750}\n\n  def AddCIDFont(family,style,name,cw,cMap,registry)\n    fontkey=family.downcase+style.upcase\n    unless @fonts[fontkey].nil?\n  \t\tError(\"Font already added: family style\")\n    end\n  \ti=@fonts.length+1\n  \tname=name.gsub(' ','')\n  \t@fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,'ut'=>40,'cw'=>cw,\n  \t  'CMap'=>cMap,'registry'=>registry}\n  end\n\n  def AddCIDFonts(family,name,cw,cMap,registry)\n  \tAddCIDFont(family,'',name,cw,cMap,registry)\n  \tAddCIDFont(family,'B',name+',Bold',cw,cMap,registry)\n  \tAddCIDFont(family,'I',name+',Italic',cw,cMap,registry)\n  \tAddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry)\n  end\n\n  def AddUHCFont(family='UHC',name='HYSMyeongJoStd-Medium-Acro')\n  \t#Add UHC font with proportional Latin\n  \tcw=UHC_widths\n  \tcMap='KSCms-UHC-H'\n  \tregistry={'ordering'=>'Korea1','supplement'=>1}\n  \tAddCIDFonts(family,name,cw,cMap,registry)\n  end\n\n  def AddUHChwFont(family='UHC-hw',name='HYSMyeongJoStd-Medium-Acro')\n  \t#Add UHC font with half-witdh Latin\n    32.upto(126) do |i|\n  \t\tcw[i.chr]=500\n    end\n  \tcMap='KSCms-UHC-HW-H'\n  \tregistry={'ordering'=>'Korea1','supplement'=>1}\n  \tAddCIDFonts(family,name,cw,cMap,registry)\n  end\n\n  def GetStringWidth(s)\n  \tif(@CurrentFont['type']=='Type0')\n  \t\treturn GetMBStringWidth(s)\n  \telse\n  \t\treturn super(s)\n    end\n  end\n\n  def GetMBStringWidth(s)\n  \t#Multi-byte version of GetStringWidth()\n  \tl=0\n  \tcw=@CurrentFont['cw']\n  \tnb=s.length\n  \ti=0\n  \twhile(i<nb)\n  \t\tc=s[i]\n  \t\tif(c<128)\n  \t\t\tl+=cw[c.chr]\n  \t\t\ti+=1\n  \t\telse\n  \t\t\tl+=1000\n  \t\t\ti+=2\n  \t\tend\n  \tend\n  \treturn l*@FontSize/1000\n  end\n\n  def MultiCell(w,h,txt,border=0,align='L',fill=0)\n  \tif(@CurrentFont['type']=='Type0')\n  \t\tMBMultiCell(w,h,txt,border,align,fill)\n  \telse\n  \t\tsuper(w,h,txt,border,align,fill)\n    end\n  end\n\n  def MBMultiCell(w,h,txt,border=0,align='L',fill=0)\n  \t#Multi-byte version of MultiCell()\n  \tcw=@CurrentFont['cw']\n  \tif(w==0)\n  \t\tw=@w-@rMargin-@x\n    end\n  \twmax=(w-2*@cMargin)*1000/@FontSize\n  \ts=txt.gsub(\"\\r\",'')\n  \tnb=s.length\n  \tif(nb>0 and s[nb-1]==\"\\n\")\n  \t\tnb-=1\n    end\n  \tb=0\n  \tif(border)\n  \t\tif(border==1)\n  \t\t\tborder='LTRB'\n  \t\t\tb='LRT'\n  \t\t\tb2='LR'\n  \t\telse\n  \t\t\tb2=''\n  \t\t\tif(border.index('L').nil?)\n  \t\t\t\tb2+='L'\n        end\n  \t\t\tif(border.index('R').nil?)\n  \t\t\t\tb2+='R'\n        end\n  \t\t\tb=border.index('T').nil? ? b2+'T' : b2\n  \t\tend\n  \tend\n  \tsep=-1\n  \ti=0\n  \tj=0\n  \tl=0\n  \tnl=1\n  \twhile(i<nb)\n  \t\t#Get next character\n  \t\tc=s[i]\n  \t\t#Check if ASCII or MB\n  \t\tascii=(c<128)\n  \t\tif(c==\"\\n\")\n  \t\t\t#Explicit line break\n  \t\t\tCell(w,h,s[j,i-j],b,2,align,fill)\n  \t\t\ti+=1\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n  \t\t\tnl+=1\n  \t\t\tif(border and nl==2)\n  \t\t\t\tb=b2\n        end\n  \t\t\tnext\n  \t\tend\n  \t\tif(!ascii)\n  \t\t\tsep=i\n  \t\t\tls=l\n  \t\telsif(c==' ')\n  \t\t\tsep=i\n  \t\t\tls=l\n  \t\tend\n  \t\tl+=ascii ? cw[c.chr] : 1000\n  \t\tif(l>wmax)\n  \t\t\t#Automatic line break\n  \t\t\tif(sep==-1 or i==j)\n  \t\t\t\tif(i==j)\n  \t\t\t\t\ti+=ascii ? 1 : 2\n          end\n  \t\t\t\tCell(w,h,s[j,i-j],b,2,align,fill)\n  \t\t\telse\n  \t\t\t\tCell(w,h,s[j,sep-j],b,2,align,fill)\n  \t\t\t\ti=(s[sep]==' ') ? sep+1 : sep\n  \t\t\tend\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n  \t\t\tnl+=1\n  \t\t\tif(border and nl==2)\n  \t\t\t\tb=b2\n        end\n  \t\telse\n  \t\t\ti+=ascii ? 1 : 2\n      end\n  \tend\n  \t#Last chunk\n  \tif(border and not border.index('B').nil?)\n  \t\tb+='B'\n    end\n  \tCell(w,h,s[j,i-j],b,2,align,fill)\n  \t@x=@lMargin\n  end\n\n  def Write(h,txt,link='')\n  \tif(@CurrentFont['type']=='Type0')\n  \t\tMBWrite(h,txt,link)\n  \telse\n  \t\tsuper(h,txt,link)\n    end\n  end\n\n  def MBWrite(h,txt,link)\n  \t#Multi-byte version of Write()\n  \tcw=@CurrentFont['cw']\n  \tw=@w-@rMargin-@x\n  \twmax=(w-2*@cMargin)*1000/@FontSize\n  \ts=txt.gsub(\"\\r\",'')\n  \tnb=s.length\n  \tsep=-1\n  \ti=0\n  \tj=0\n  \tl=0\n  \tnl=1\n  \twhile(i<nb)\n  \t\t#Get next character\n  \t\tc=s[i]\n  \t\t#Check if ASCII or MB\n  \t\tascii=(c<128)\n  \t\tif(c==\"\\n\")\n  \t\t\t#Explicit line break\n  \t\t\tCell(w,h,s[j,i-j],0,2,'',0,link)\n  \t\t\ti+=1\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n  \t\t\tif(nl==1)\n  \t\t\t\t@x=@lMargin\n  \t\t\t\tw=@w-@rMargin-@x\n  \t\t\t\twmax=(w-2*@cMargin)*1000/@FontSize\n  \t\t\tend\n  \t\t\tnl+=1\n  \t\t\tnext\n  \t\tend\n  \t\tif(!ascii or c==' ')\n  \t\t\tsep=i\n      end\n  \t\tl+=ascii ? cw[c.chr] : 1000\n  \t\tif(l>wmax)\n  \t\t\t#Automatic line break\n  \t\t\tif(sep==-1 or i==j)\n  \t\t\t\tif(@x>@lMargin)\n  \t\t\t\t\t#Move to next line\n  \t\t\t\t\t@x=@lMargin\n  \t\t\t\t\t@y+=h\n  \t\t\t\t\tw=@w-@rMargin-@x\n  \t\t\t\t\twmax=(w-2*@cMargin)*1000/@FontSize\n  \t\t\t\t\ti+=1\n  \t\t\t\t\tnl+=1\n  \t\t\t\t\tnext\n  \t\t\t\tend\n  \t\t\t\tif(i==j)\n  \t\t\t\t\ti+=ascii ? 1 : 2\n          end\n  \t\t\t\tCell(w,h,s[j,i-j],0,2,'',0,link)\n  \t\t\telse\n  \t\t\t\tCell(w,h,s[j,sep-j],0,2,'',0,link)\n  \t\t\t\ti=(s[sep]==' ') ? sep+1 : sep\n  \t\t\tend\n  \t\t\tsep=-1\n  \t\t\tj=i\n  \t\t\tl=0\n  \t\t\tif(nl==1)\n  \t\t\t\t@x=@lMargin\n  \t\t\t\tw=@w-@rMargin-@x\n  \t\t\t\twmax=(w-2*@cMargin)*1000/@FontSize\n  \t\t\tend\n  \t\t\tnl+=1\n  \t\telse\n  \t\t\ti+=ascii ? 1 : 2\n      end\n  \tend\n  \t#Last chunk\n  \tif(i!=j)\n  \t\tCell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link)\n    end\n  end\n\nprivate\n\n  def putfonts()\n  \tnf=@n\n    @diffs.each do |diff|\n  \t\t#Encodings\n  \t\tnewobj()\n  \t\tout('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['+diff+']>>')\n  \t\tout('endobj')\n  \tend\n  \t# mqr=get_magic_quotes_runtime()\n  \t# set_magic_quotes_runtime(0)\n    @FontFiles.each_pair do |file, info|\n  \t\t#Font file embedding\n  \t\tnewobj()\n  \t\t@FontFiles[file]['n']=@n\n  \t\tif(defined('FPDF_FONTPATH'))\n  \t\t\tfile=FPDF_FONTPATH+file\n      end\n  \t\tsize=filesize(file)\n  \t\tif(!size)\n  \t\t\tError('Font file not found')\n      end\n  \t\tout('<</Length '+size)\n  \t\tif(file[-2]=='.z')\n  \t\t\tout('/Filter /FlateDecode')\n      end\n  \t\tout('/Length1 '+info['length1'])\n  \t\tif(not info['length2'].nil?)\n  \t\t\tout('/Length2 '+info['length2']+' /Length3 0')\n      end\n  \t\tout('>>')\n  \t\tf=fopen(file,'rb')\n  \t\tputstream(fread(f,size))\n  \t\tfclose(f)\n  \t\tout('endobj')\n  \tend\n  \t# set_magic_quotes_runtime(mqr)\n    @fonts.each_pair do |k, font|\n  \t\t#Font objects\n  \t\tnewobj()\n  \t\t@fonts[k]['n']=@n\n  \t\tout('<</Type /Font')\n  \t\tif(font['type']=='Type0')\n  \t\t\tputType0(font)\n  \t\telse\n  \t\t\tname=font['name']\n  \t\t\tout('/BaseFont /'+name)\n  \t\t\tif(font['type']=='core')\n  \t\t\t\t#Standard font\n  \t\t\t\tout('/Subtype /Type1')\n  \t\t\t\tif(name!='Symbol' and name!='ZapfDingbats')\n  \t\t\t\t\tout('/Encoding /WinAnsiEncoding')\n  \t\t\t\tend\n  \t\t\telse\n  \t\t\t\t#Additional font\n  \t\t\t\tout('/Subtype /'+font['type'])\n  \t\t\t\tout('/FirstChar 32')\n  \t\t\t\tout('/LastChar 255')\n  \t\t\t\tout('/Widths '+(@n+1)+' 0 R')\n  \t\t\t\tout('/FontDescriptor '+(@n+2)+' 0 R')\n  \t\t\t\tif(font['enc'])\n  \t\t\t\t\tif(not font['diff'].nil?)\n  \t\t\t\t\t\tout('/Encoding '+(nf+font['diff'])+' 0 R')\n  \t\t\t\t\telse\n  \t\t\t\t\t\tout('/Encoding /WinAnsiEncoding')\n            end\n  \t\t\t\tend\n  \t\t\tend\n  \t\t\tout('>>')\n  \t\t\tout('endobj')\n  \t\t\tif(font['type']!='core')\n  \t\t\t\t#Widths\n  \t\t\t\tnewobj()\n  \t\t\t\tcw=font['cw']\n  \t\t\t\ts='['\n          32.upto(255) do |i|\n  \t\t\t\t\ts+=cw[i.chr]+' '\n          end\n  \t\t\t\tout(s+']')\n  \t\t\t\tout('endobj')\n  \t\t\t\t#Descriptor\n  \t\t\t\tnewobj()\n  \t\t\t\ts='<</Type /FontDescriptor /FontName /'+name\n  \t\t\t\tfont['desc'].each_pair do |k, v|  \t\t\t\t\n  \t\t\t\t\ts+=' /'+k+' '+v\n          end\n  \t\t\t\tfile=font['file']\n  \t\t\t\tif(file)\n  \t\t\t\t\ts+=' /FontFile'+(font['type']=='Type1' ? '' : '2')+' '+@FontFiles[file]['n']+' 0 R'\n          end\n  \t\t\t\tout(s+'>>')\n  \t\t\t\tout('endobj')\n  \t\t\tend\n  \t\tend\n  \tend\n  end\n  \n  def putType0(font)\n  \t#Type0\n  \tout('/Subtype /Type0')\n  \tout('/BaseFont /'+font['name']+'-'+font['CMap'])\n  \tout('/Encoding /'+font['CMap'])\n  \tout('/DescendantFonts ['+(@n+1).to_s+' 0 R]')\n  \tout('>>')\n  \tout('endobj')\n  \t#CIDFont\n  \tnewobj()\n  \tout('<</Type /Font')\n  \tout('/Subtype /CIDFontType0')\n  \tout('/BaseFont /'+font['name'])\n  \tout('/CIDSystemInfo <</Registry (Adobe) /Ordering ('+font['registry']['ordering']+') /Supplement '+font['registry']['supplement'].to_s+'>>')\n  \tout('/FontDescriptor '+(@n+1).to_s+' 0 R')\n  \tif(font['CMap']=='KSCms-UHC-HW-H')\n  \t\tw='8094 8190 500'\n  \telse\n  \t\tw='1 ['\n  \t\tfont['cw'].keys.sort.each {|key|\n  \t\t  w+=font['cw'][key].to_s + \" \"\n  # ActionController::Base::logger.debug key.to_s\n  # ActionController::Base::logger.debug font['cw'][key].to_s\n  \t\t}\n  \t\tw +=']'\n    end\n  \tout('/W ['+w+']>>')\n  \tout('endobj')\n  \t#Font descriptor\n  \tnewobj()\n  \tout('<</Type /FontDescriptor')\n  \tout('/FontName /'+font['name'])\n  \tout('/Flags 6')\n  \tout('/FontBBox [0 -200 1000 900]')\n  \tout('/ItalicAngle 0')\n  \tout('/Ascent 800')\n  \tout('/Descent -200')\n  \tout('/CapHeight 800')\n  \tout('/StemV 50')\n  \tout('>>')\n  \tout('endobj')\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/rfpdf/lib/rfpdf/makefont.rb",
    "content": "#!/usr/bin/env ruby\n#\n# Utility to generate font definition files\n# Version: 1.1\n# Date:    2006-07-19\n#\n# Changelog:\n#  Version 1.1 - Brian Ollenberger\n#   - Fixed a very small bug in MakeFont for generating FontDef.diff.\n\nCharencodings = {\n# Central Europe\n    'cp1250' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        'Euro',           '.notdef',        'quotesinglbase', '.notdef',\n        'quotedblbase',   'ellipsis',       'dagger',         'daggerdbl',\n        '.notdef',        'perthousand',    'Scaron',         'guilsinglleft',\n        'Sacute',         'Tcaron',         'Zcaron',         'Zacute',\n        '.notdef',        'quoteleft',      'quoteright',     'quotedblleft',\n        'quotedblright',  'bullet',         'endash',         'emdash',\n        '.notdef',        'trademark',      'scaron',         'guilsinglright',\n        'sacute',         'tcaron',         'zcaron',         'zacute',\n        'space',          'caron',          'breve',          'Lslash',\n        'currency',       'Aogonek',        'brokenbar',      'section',\n        'dieresis',       'copyright',      'Scedilla',       'guillemotleft',\n        'logicalnot',     'hyphen',         'registered',     'Zdotaccent',\n        'degree',         'plusminus',      'ogonek',         'lslash',\n        'acute',          'mu',             'paragraph',      'periodcentered',\n        'cedilla',        'aogonek',        'scedilla',       'guillemotright',\n        'Lcaron',         'hungarumlaut',   'lcaron',         'zdotaccent',\n        'Racute',         'Aacute',         'Acircumflex',    'Abreve',\n        'Adieresis',      'Lacute',         'Cacute',         'Ccedilla',\n        'Ccaron',         'Eacute',         'Eogonek',        'Edieresis',\n        'Ecaron',         'Iacute',         'Icircumflex',    'Dcaron',\n        'Dcroat',         'Nacute',         'Ncaron',         'Oacute',\n        'Ocircumflex',    'Ohungarumlaut',  'Odieresis',      'multiply',\n        'Rcaron',         'Uring',          'Uacute',         'Uhungarumlaut',\n        'Udieresis',      'Yacute',         'Tcommaaccent',   'germandbls',\n        'racute',         'aacute',         'acircumflex',    'abreve',\n        'adieresis',      'lacute',         'cacute',         'ccedilla',\n        'ccaron',         'eacute',         'eogonek',        'edieresis',\n        'ecaron',         'iacute',         'icircumflex',    'dcaron',\n        'dcroat',         'nacute',         'ncaron',         'oacute',\n        'ocircumflex',    'ohungarumlaut',  'odieresis',      'divide',\n        'rcaron',         'uring',          'uacute',         'uhungarumlaut',\n        'udieresis',      'yacute',         'tcommaaccent',   'dotaccent'\n    ],\n# Cyrillic\n    'cp1251' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        'afii10051',      'afii10052',      'quotesinglbase', 'afii10100',\n        'quotedblbase',   'ellipsis',       'dagger',         'daggerdbl',\n        'Euro',           'perthousand',    'afii10058',      'guilsinglleft',\n        'afii10059',      'afii10061',      'afii10060',      'afii10145',\n        'afii10099',      'quoteleft',      'quoteright',     'quotedblleft',\n        'quotedblright',  'bullet',         'endash',         'emdash',\n        '.notdef',        'trademark',      'afii10106',      'guilsinglright',\n        'afii10107',      'afii10109',      'afii10108',      'afii10193',\n        'space',          'afii10062',      'afii10110',      'afii10057',\n        'currency',       'afii10050',      'brokenbar',      'section',\n        'afii10023',      'copyright',      'afii10053',      'guillemotleft',\n        'logicalnot',     'hyphen',         'registered',     'afii10056',\n        'degree',         'plusminus',      'afii10055',      'afii10103',\n        'afii10098',      'mu',             'paragraph',      'periodcentered',\n        'afii10071',      'afii61352',      'afii10101',      'guillemotright',\n        'afii10105',      'afii10054',      'afii10102',      'afii10104',\n        'afii10017',      'afii10018',      'afii10019',      'afii10020',\n        'afii10021',      'afii10022',      'afii10024',      'afii10025',\n        'afii10026',      'afii10027',      'afii10028',      'afii10029',\n        'afii10030',      'afii10031',      'afii10032',      'afii10033',\n        'afii10034',      'afii10035',      'afii10036',      'afii10037',\n        'afii10038',      'afii10039',      'afii10040',      'afii10041',\n        'afii10042',      'afii10043',      'afii10044',      'afii10045',\n        'afii10046',      'afii10047',      'afii10048',      'afii10049',\n        'afii10065',      'afii10066',      'afii10067',      'afii10068',\n        'afii10069',      'afii10070',      'afii10072',      'afii10073',\n        'afii10074',      'afii10075',      'afii10076',      'afii10077',\n        'afii10078',      'afii10079',      'afii10080',      'afii10081',\n        'afii10082',      'afii10083',      'afii10084',      'afii10085',\n        'afii10086',      'afii10087',      'afii10088',      'afii10089',\n        'afii10090',      'afii10091',      'afii10092',      'afii10093',\n        'afii10094',      'afii10095',      'afii10096',      'afii10097'\n    ],\n# Western Europe\n    'cp1252' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        'Euro',           '.notdef',        'quotesinglbase', 'florin',\n        'quotedblbase',   'ellipsis',       'dagger',         'daggerdbl',\n        'circumflex',     'perthousand',    'Scaron',         'guilsinglleft',\n        'OE',             '.notdef',        'Zcaron',         '.notdef',\n        '.notdef',        'quoteleft',      'quoteright',     'quotedblleft',\n        'quotedblright',  'bullet',         'endash',         'emdash',\n        'tilde',          'trademark',      'scaron',         'guilsinglright',\n        'oe',             '.notdef',        'zcaron',         'Ydieresis',\n        'space',          'exclamdown',     'cent',           'sterling',\n        'currency',       'yen',            'brokenbar',      'section',\n        'dieresis',       'copyright',      'ordfeminine',    'guillemotleft',\n        'logicalnot',     'hyphen',         'registered',     'macron',\n        'degree',         'plusminus',      'twosuperior',    'threesuperior',\n        'acute',          'mu',             'paragraph',      'periodcentered',\n        'cedilla',        'onesuperior',    'ordmasculine',   'guillemotright',\n        'onequarter',     'onehalf',        'threequarters',  'questiondown',\n        'Agrave',         'Aacute',         'Acircumflex',    'Atilde',\n        'Adieresis',      'Aring',          'AE',             'Ccedilla',\n        'Egrave',         'Eacute',         'Ecircumflex',    'Edieresis',\n        'Igrave',         'Iacute',         'Icircumflex',    'Idieresis',\n        'Eth',            'Ntilde',         'Ograve',         'Oacute',\n        'Ocircumflex',    'Otilde',         'Odieresis',      'multiply',\n        'Oslash',         'Ugrave',         'Uacute',         'Ucircumflex',\n        'Udieresis',      'Yacute',         'Thorn',          'germandbls',\n        'agrave',         'aacute',         'acircumflex',    'atilde',\n        'adieresis',      'aring',          'ae',             'ccedilla',\n        'egrave',         'eacute',         'ecircumflex',    'edieresis',\n        'igrave',         'iacute',         'icircumflex',    'idieresis',\n        'eth',            'ntilde',         'ograve',         'oacute',\n        'ocircumflex',    'otilde',         'odieresis',      'divide',\n        'oslash',         'ugrave',         'uacute',         'ucircumflex',\n        'udieresis',      'yacute',         'thorn',          'ydieresis'\n    ],\n# Greek\n    'cp1253' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        'Euro',           '.notdef',        'quotesinglbase', 'florin',\n        'quotedblbase',   'ellipsis',       'dagger',         'daggerdbl',\n        '.notdef',        'perthousand',    '.notdef',        'guilsinglleft',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        'quoteleft',      'quoteright',     'quotedblleft',\n        'quotedblright',  'bullet',         'endash',         'emdash',\n        '.notdef',        'trademark',      '.notdef',        'guilsinglright',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'dieresistonos',  'Alphatonos',     'sterling',\n        'currency',       'yen',            'brokenbar',      'section',\n        'dieresis',       'copyright',      '.notdef',        'guillemotleft',\n        'logicalnot',     'hyphen',         'registered',     'afii00208',\n        'degree',         'plusminus',      'twosuperior',    'threesuperior',\n        'tonos',          'mu',             'paragraph',      'periodcentered',\n        'Epsilontonos',   'Etatonos',       'Iotatonos',      'guillemotright',\n        'Omicrontonos',   'onehalf',        'Upsilontonos',   'Omegatonos',\n        'iotadieresistonos','Alpha',          'Beta',           'Gamma',\n        'Delta',          'Epsilon',        'Zeta',           'Eta',\n        'Theta',          'Iota',           'Kappa',          'Lambda',\n        'Mu',             'Nu',             'Xi',             'Omicron',\n        'Pi',             'Rho',            '.notdef',        'Sigma',\n        'Tau',            'Upsilon',        'Phi',            'Chi',\n        'Psi',            'Omega',          'Iotadieresis',   'Upsilondieresis',\n        'alphatonos',     'epsilontonos',   'etatonos',       'iotatonos',\n        'upsilondieresistonos','alpha',          'beta',           'gamma',\n        'delta',          'epsilon',        'zeta',           'eta',\n        'theta',          'iota',           'kappa',          'lambda',\n        'mu',             'nu',             'xi',             'omicron',\n        'pi',             'rho',            'sigma1',         'sigma',\n        'tau',            'upsilon',        'phi',            'chi',\n        'psi',            'omega',          'iotadieresis',   'upsilondieresis',\n        'omicrontonos',   'upsilontonos',   'omegatonos',     '.notdef'\n    ],\n# Turkish\n    'cp1254' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        'Euro',           '.notdef',        'quotesinglbase', 'florin',\n        'quotedblbase',   'ellipsis',       'dagger',         'daggerdbl',\n        'circumflex',     'perthousand',    'Scaron',         'guilsinglleft',\n        'OE',             '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        'quoteleft',      'quoteright',     'quotedblleft',\n        'quotedblright',  'bullet',         'endash',         'emdash',\n        'tilde',          'trademark',      'scaron',         'guilsinglright',\n        'oe',             '.notdef',        '.notdef',        'Ydieresis',\n        'space',          'exclamdown',     'cent',           'sterling',\n        'currency',       'yen',            'brokenbar',      'section',\n        'dieresis',       'copyright',      'ordfeminine',    'guillemotleft',\n        'logicalnot',     'hyphen',         'registered',     'macron',\n        'degree',         'plusminus',      'twosuperior',    'threesuperior',\n        'acute',          'mu',             'paragraph',      'periodcentered',\n        'cedilla',        'onesuperior',    'ordmasculine',   'guillemotright',\n        'onequarter',     'onehalf',        'threequarters',  'questiondown',\n        'Agrave',         'Aacute',         'Acircumflex',    'Atilde',\n        'Adieresis',      'Aring',          'AE',             'Ccedilla',\n        'Egrave',         'Eacute',         'Ecircumflex',    'Edieresis',\n        'Igrave',         'Iacute',         'Icircumflex',    'Idieresis',\n        'Gbreve',         'Ntilde',         'Ograve',         'Oacute',\n        'Ocircumflex',    'Otilde',         'Odieresis',      'multiply',\n        'Oslash',         'Ugrave',         'Uacute',         'Ucircumflex',\n        'Udieresis',      'Idotaccent',     'Scedilla',       'germandbls',\n        'agrave',         'aacute',         'acircumflex',    'atilde',\n        'adieresis',      'aring',          'ae',             'ccedilla',\n        'egrave',         'eacute',         'ecircumflex',    'edieresis',\n        'igrave',         'iacute',         'icircumflex',    'idieresis',\n        'gbreve',         'ntilde',         'ograve',         'oacute',\n        'ocircumflex',    'otilde',         'odieresis',      'divide',\n        'oslash',         'ugrave',         'uacute',         'ucircumflex',\n        'udieresis',      'dotlessi',       'scedilla',       'ydieresis'\n    ],\n# Hebrew\n    'cp1255' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        'Euro',           '.notdef',        'quotesinglbase', 'florin',\n        'quotedblbase',   'ellipsis',       'dagger',         'daggerdbl',\n        'circumflex',     'perthousand',    '.notdef',        'guilsinglleft',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        'quoteleft',      'quoteright',     'quotedblleft',\n        'quotedblright',  'bullet',         'endash',         'emdash',\n        'tilde',          'trademark',      '.notdef',        'guilsinglright',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclamdown',     'cent',           'sterling',\n        'afii57636',      'yen',            'brokenbar',      'section',\n        'dieresis',       'copyright',      'multiply',       'guillemotleft',\n        'logicalnot',     'sfthyphen',      'registered',     'macron',\n        'degree',         'plusminus',      'twosuperior',    'threesuperior',\n        'acute',          'mu',             'paragraph',      'middot',\n        'cedilla',        'onesuperior',    'divide',         'guillemotright',\n        'onequarter',     'onehalf',        'threequarters',  'questiondown',\n        'afii57799',      'afii57801',      'afii57800',      'afii57802',\n        'afii57793',      'afii57794',      'afii57795',      'afii57798',\n        'afii57797',      'afii57806',      '.notdef',        'afii57796',\n        'afii57807',      'afii57839',      'afii57645',      'afii57841',\n        'afii57842',      'afii57804',      'afii57803',      'afii57658',\n        'afii57716',      'afii57717',      'afii57718',      'gereshhebrew',\n        'gershayimhebrew','.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'afii57664',      'afii57665',      'afii57666',      'afii57667',\n        'afii57668',      'afii57669',      'afii57670',      'afii57671',\n        'afii57672',      'afii57673',      'afii57674',      'afii57675',\n        'afii57676',      'afii57677',      'afii57678',      'afii57679',\n        'afii57680',      'afii57681',      'afii57682',      'afii57683',\n        'afii57684',      'afii57685',      'afii57686',      'afii57687',\n        'afii57688',      'afii57689',      'afii57690',      '.notdef',\n        '.notdef',        'afii299',        'afii300',        '.notdef'\n    ],\n# Baltic\n    'cp1257' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        'Euro',           '.notdef',        'quotesinglbase', '.notdef',\n        'quotedblbase',   'ellipsis',       'dagger',         'daggerdbl',\n        '.notdef',        'perthousand',    '.notdef',        'guilsinglleft',\n        '.notdef',        'dieresis',       'caron',          'cedilla',\n        '.notdef',        'quoteleft',      'quoteright',     'quotedblleft',\n        'quotedblright',  'bullet',         'endash',         'emdash',\n        '.notdef',        'trademark',      '.notdef',        'guilsinglright',\n        '.notdef',        'macron',         'ogonek',         '.notdef',\n        'space',          '.notdef',        'cent',           'sterling',\n        'currency',       '.notdef',        'brokenbar',      'section',\n        'Oslash',         'copyright',      'Rcommaaccent',   'guillemotleft',\n        'logicalnot',     'hyphen',         'registered',     'AE',\n        'degree',         'plusminus',      'twosuperior',    'threesuperior',\n        'acute',          'mu',             'paragraph',      'periodcentered',\n        'oslash',         'onesuperior',    'rcommaaccent',   'guillemotright',\n        'onequarter',     'onehalf',        'threequarters',  'ae',\n        'Aogonek',        'Iogonek',        'Amacron',        'Cacute',\n        'Adieresis',      'Aring',          'Eogonek',        'Emacron',\n        'Ccaron',         'Eacute',         'Zacute',         'Edotaccent',\n        'Gcommaaccent',   'Kcommaaccent',   'Imacron',        'Lcommaaccent',\n        'Scaron',         'Nacute',         'Ncommaaccent',   'Oacute',\n        'Omacron',        'Otilde',         'Odieresis',      'multiply',\n        'Uogonek',        'Lslash',         'Sacute',         'Umacron',\n        'Udieresis',      'Zdotaccent',     'Zcaron',         'germandbls',\n        'aogonek',        'iogonek',        'amacron',        'cacute',\n        'adieresis',      'aring',          'eogonek',        'emacron',\n        'ccaron',         'eacute',         'zacute',         'edotaccent',\n        'gcommaaccent',   'kcommaaccent',   'imacron',        'lcommaaccent',\n        'scaron',         'nacute',         'ncommaaccent',   'oacute',\n        'omacron',        'otilde',         'odieresis',      'divide',\n        'uogonek',        'lslash',         'sacute',         'umacron',\n        'udieresis',      'zdotaccent',     'zcaron',         'dotaccent'\n    ],\n# Vietnamese\n    'cp1258' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        'Euro',           '.notdef',        'quotesinglbase', 'florin',\n        'quotedblbase',   'ellipsis',       'dagger',         'daggerdbl',\n        'circumflex',     'perthousand',    '.notdef',        'guilsinglleft',\n        'OE',             '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        'quoteleft',      'quoteright',     'quotedblleft',\n        'quotedblright',  'bullet',         'endash',         'emdash',\n        'tilde',          'trademark',      '.notdef',        'guilsinglright',\n        'oe',             '.notdef',        '.notdef',        'Ydieresis',\n        'space',          'exclamdown',     'cent',           'sterling',\n        'currency',       'yen',            'brokenbar',      'section',\n        'dieresis',       'copyright',      'ordfeminine',    'guillemotleft',\n        'logicalnot',     'hyphen',         'registered',     'macron',\n        'degree',         'plusminus',      'twosuperior',    'threesuperior',\n        'acute',          'mu',             'paragraph',      'periodcentered',\n        'cedilla',        'onesuperior',    'ordmasculine',   'guillemotright',\n        'onequarter',     'onehalf',        'threequarters',  'questiondown',\n        'Agrave',         'Aacute',         'Acircumflex',    'Abreve',\n        'Adieresis',      'Aring',          'AE',             'Ccedilla',\n        'Egrave',         'Eacute',         'Ecircumflex',    'Edieresis',\n        'gravecomb',      'Iacute',         'Icircumflex',    'Idieresis',\n        'Dcroat',         'Ntilde',         'hookabovecomb',  'Oacute',\n        'Ocircumflex',    'Ohorn',          'Odieresis',      'multiply',\n        'Oslash',         'Ugrave',         'Uacute',         'Ucircumflex',\n        'Udieresis',      'Uhorn',          'tildecomb',      'germandbls',\n        'agrave',         'aacute',         'acircumflex',    'abreve',\n        'adieresis',      'aring',          'ae',             'ccedilla',\n        'egrave',         'eacute',         'ecircumflex',    'edieresis',\n        'acutecomb',      'iacute',         'icircumflex',    'idieresis',\n        'dcroat',         'ntilde',         'dotbelowcomb',   'oacute',\n        'ocircumflex',    'ohorn',          'odieresis',      'divide',\n        'oslash',         'ugrave',         'uacute',         'ucircumflex',\n        'udieresis',      'uhorn',          'dong',           'ydieresis'\n    ],\n# Thai\n    'cp874' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        'Euro',           '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        'ellipsis',       '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        'quoteleft',      'quoteright',     'quotedblleft',\n        'quotedblright',  'bullet',         'endash',         'emdash',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'kokaithai',      'khokhaithai',    'khokhuatthai',\n        'khokhwaithai',   'khokhonthai',    'khorakhangthai', 'ngonguthai',\n        'chochanthai',    'chochingthai',   'chochangthai',   'sosothai',\n        'chochoethai',    'yoyingthai',     'dochadathai',    'topatakthai',\n        'thothanthai',    'thonangmonthothai', 'thophuthaothai', 'nonenthai',\n        'dodekthai',      'totaothai',      'thothungthai',   'thothahanthai',\n        'thothongthai',   'nonuthai',       'bobaimaithai',   'poplathai',\n        'phophungthai',   'fofathai',       'phophanthai',    'fofanthai',\n        'phosamphaothai', 'momathai',       'yoyakthai',      'roruathai',\n        'ruthai',         'lolingthai',     'luthai',         'wowaenthai',\n        'sosalathai',     'sorusithai',     'sosuathai',      'hohipthai',\n        'lochulathai',    'oangthai',       'honokhukthai',   'paiyannoithai',\n        'saraathai',      'maihanakatthai', 'saraaathai',     'saraamthai',\n        'saraithai',      'saraiithai',     'sarauethai',     'saraueethai',\n        'sarauthai',      'sarauuthai',     'phinthuthai',    '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        'bahtthai',\n        'saraethai',      'saraaethai',     'saraothai',      'saraaimaimuanthai',\n        'saraaimaimalaithai', 'lakkhangyaothai', 'maiyamokthai', 'maitaikhuthai',\n        'maiekthai',      'maithothai',     'maitrithai',     'maichattawathai',\n        'thanthakhatthai', 'nikhahitthai',  'yamakkanthai',   'fongmanthai',\n        'zerothai',       'onethai',        'twothai',        'threethai',\n        'fourthai',       'fivethai',       'sixthai',        'seventhai',\n        'eightthai',      'ninethai',       'angkhankhuthai', 'khomutthai',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef'\n    ],\n# Western Europe\n    'ISO-8859-1' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclamdown',     'cent',           'sterling',\n        'currency',       'yen',            'brokenbar',      'section',\n        'dieresis',       'copyright',      'ordfeminine',    'guillemotleft',\n        'logicalnot',     'hyphen',         'registered',     'macron',\n        'degree',         'plusminus',      'twosuperior',    'threesuperior',\n        'acute',          'mu',             'paragraph',      'periodcentered',\n        'cedilla',        'onesuperior',    'ordmasculine',   'guillemotright',\n        'onequarter',     'onehalf',        'threequarters',  'questiondown',\n        'Agrave',         'Aacute',         'Acircumflex',    'Atilde',\n        'Adieresis',      'Aring',          'AE',             'Ccedilla',\n        'Egrave',         'Eacute',         'Ecircumflex',    'Edieresis',\n        'Igrave',         'Iacute',         'Icircumflex',    'Idieresis',\n        'Eth',            'Ntilde',         'Ograve',         'Oacute',\n        'Ocircumflex',    'Otilde',         'Odieresis',      'multiply',\n        'Oslash',         'Ugrave',         'Uacute',         'Ucircumflex',\n        'Udieresis',      'Yacute',         'Thorn',          'germandbls',\n        'agrave',         'aacute',         'acircumflex',    'atilde',\n        'adieresis',      'aring',          'ae',             'ccedilla',\n        'egrave',         'eacute',         'ecircumflex',    'edieresis',\n        'igrave',         'iacute',         'icircumflex',    'idieresis',\n        'eth',            'ntilde',         'ograve',         'oacute',\n        'ocircumflex',    'otilde',         'odieresis',      'divide',\n        'oslash',         'ugrave',         'uacute',         'ucircumflex',\n        'udieresis',      'yacute',         'thorn',          'ydieresis'\n    ],\n# Central Europe\n    'ISO-8859-2' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'Aogonek',        'breve',          'Lslash',\n        'currency',       'Lcaron',         'Sacute',         'section',\n        'dieresis',       'Scaron',         'Scedilla',       'Tcaron',\n        'Zacute',         'hyphen',         'Zcaron',         'Zdotaccent',\n        'degree',         'aogonek',        'ogonek',         'lslash',\n        'acute',          'lcaron',         'sacute',         'caron',\n        'cedilla',        'scaron',         'scedilla',       'tcaron',\n        'zacute',         'hungarumlaut',   'zcaron',         'zdotaccent',\n        'Racute',         'Aacute',         'Acircumflex',    'Abreve',\n        'Adieresis',      'Lacute',         'Cacute',         'Ccedilla',\n        'Ccaron',         'Eacute',         'Eogonek',        'Edieresis',\n        'Ecaron',         'Iacute',         'Icircumflex',    'Dcaron',\n        'Dcroat',         'Nacute',         'Ncaron',         'Oacute',\n        'Ocircumflex',    'Ohungarumlaut',  'Odieresis',      'multiply',\n        'Rcaron',         'Uring',          'Uacute',         'Uhungarumlaut',\n        'Udieresis',      'Yacute',         'Tcommaaccent',   'germandbls',\n        'racute',         'aacute',         'acircumflex',    'abreve',\n        'adieresis',      'lacute',         'cacute',         'ccedilla',\n        'ccaron',         'eacute',         'eogonek',        'edieresis',\n        'ecaron',         'iacute',         'icircumflex',    'dcaron',\n        'dcroat',         'nacute',         'ncaron',         'oacute',\n        'ocircumflex',    'ohungarumlaut',  'odieresis',      'divide',\n        'rcaron',         'uring',          'uacute',         'uhungarumlaut',\n        'udieresis',      'yacute',         'tcommaaccent',   'dotaccent'\n    ],\n# Baltic\n    'ISO-8859-4' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'Aogonek',        'kgreenlandic',   'Rcommaaccent',\n        'currency',       'Itilde',         'Lcommaaccent',   'section',\n        'dieresis',       'Scaron',         'Emacron',        'Gcommaaccent',\n        'Tbar',           'hyphen',         'Zcaron',         'macron',\n        'degree',         'aogonek',        'ogonek',         'rcommaaccent',\n        'acute',          'itilde',         'lcommaaccent',   'caron',\n        'cedilla',        'scaron',         'emacron',        'gcommaaccent',\n        'tbar',           'Eng',            'zcaron',         'eng',\n        'Amacron',        'Aacute',         'Acircumflex',    'Atilde',\n        'Adieresis',      'Aring',          'AE',             'Iogonek',\n        'Ccaron',         'Eacute',         'Eogonek',        'Edieresis',\n        'Edotaccent',     'Iacute',         'Icircumflex',    'Imacron',\n        'Dcroat',         'Ncommaaccent',   'Omacron',        'Kcommaaccent',\n        'Ocircumflex',    'Otilde',         'Odieresis',      'multiply',\n        'Oslash',         'Uogonek',        'Uacute',         'Ucircumflex',\n        'Udieresis',      'Utilde',         'Umacron',        'germandbls',\n        'amacron',        'aacute',         'acircumflex',    'atilde',\n        'adieresis',      'aring',          'ae',             'iogonek',\n        'ccaron',         'eacute',         'eogonek',        'edieresis',\n        'edotaccent',     'iacute',         'icircumflex',    'imacron',\n        'dcroat',         'ncommaaccent',   'omacron',        'kcommaaccent',\n        'ocircumflex',    'otilde',         'odieresis',      'divide',\n        'oslash',         'uogonek',        'uacute',         'ucircumflex',\n        'udieresis',      'utilde',         'umacron',        'dotaccent'\n    ],\n# Cyrillic\n    'ISO-8859-5' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'afii10023',      'afii10051',      'afii10052',\n        'afii10053',      'afii10054',      'afii10055',      'afii10056',\n        'afii10057',      'afii10058',      'afii10059',      'afii10060',\n        'afii10061',      'hyphen',         'afii10062',      'afii10145',\n        'afii10017',      'afii10018',      'afii10019',      'afii10020',\n        'afii10021',      'afii10022',      'afii10024',      'afii10025',\n        'afii10026',      'afii10027',      'afii10028',      'afii10029',\n        'afii10030',      'afii10031',      'afii10032',      'afii10033',\n        'afii10034',      'afii10035',      'afii10036',      'afii10037',\n        'afii10038',      'afii10039',      'afii10040',      'afii10041',\n        'afii10042',      'afii10043',      'afii10044',      'afii10045',\n        'afii10046',      'afii10047',      'afii10048',      'afii10049',\n        'afii10065',      'afii10066',      'afii10067',      'afii10068',\n        'afii10069',      'afii10070',      'afii10072',      'afii10073',\n        'afii10074',      'afii10075',      'afii10076',      'afii10077',\n        'afii10078',      'afii10079',      'afii10080',      'afii10081',\n        'afii10082',      'afii10083',      'afii10084',      'afii10085',\n        'afii10086',      'afii10087',      'afii10088',      'afii10089',\n        'afii10090',      'afii10091',      'afii10092',      'afii10093',\n        'afii10094',      'afii10095',      'afii10096',      'afii10097',\n        'afii61352',      'afii10071',      'afii10099',      'afii10100',\n        'afii10101',      'afii10102',      'afii10103',      'afii10104',\n        'afii10105',      'afii10106',      'afii10107',      'afii10108',\n        'afii10109',      'section',        'afii10110',      'afii10193'\n    ],\n# Greek\n    'ISO-8859-7' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'quoteleft',      'quoteright',     'sterling',\n        '.notdef',        '.notdef',        'brokenbar',      'section',\n        'dieresis',       'copyright',      '.notdef',        'guillemotleft',\n        'logicalnot',     'hyphen',         '.notdef',        'afii00208',\n        'degree',         'plusminus',      'twosuperior',    'threesuperior',\n        'tonos',          'dieresistonos',  'Alphatonos',     'periodcentered',\n        'Epsilontonos',   'Etatonos',       'Iotatonos',      'guillemotright',\n        'Omicrontonos',   'onehalf',        'Upsilontonos',   'Omegatonos',\n        'iotadieresistonos','Alpha',          'Beta',           'Gamma',\n        'Delta',          'Epsilon',        'Zeta',           'Eta',\n        'Theta',          'Iota',           'Kappa',          'Lambda',\n        'Mu',             'Nu',             'Xi',             'Omicron',\n        'Pi',             'Rho',            '.notdef',        'Sigma',\n        'Tau',            'Upsilon',        'Phi',            'Chi',\n        'Psi',            'Omega',          'Iotadieresis',   'Upsilondieresis',\n        'alphatonos',     'epsilontonos',   'etatonos',       'iotatonos',\n        'upsilondieresistonos','alpha',          'beta',           'gamma',\n        'delta',          'epsilon',        'zeta',           'eta',\n        'theta',          'iota',           'kappa',          'lambda',\n        'mu',             'nu',             'xi',             'omicron',\n        'pi',             'rho',            'sigma1',         'sigma',\n        'tau',            'upsilon',        'phi',            'chi',\n        'psi',            'omega',          'iotadieresis',   'upsilondieresis',\n        'omicrontonos',   'upsilontonos',   'omegatonos',     '.notdef'\n    ],\n# Turkish\n    'ISO-8859-9' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclamdown',     'cent',           'sterling',\n        'currency',       'yen',            'brokenbar',      'section',\n        'dieresis',       'copyright',      'ordfeminine',    'guillemotleft',\n        'logicalnot',     'hyphen',         'registered',     'macron',\n        'degree',         'plusminus',      'twosuperior',    'threesuperior',\n        'acute',          'mu',             'paragraph',      'periodcentered',\n        'cedilla',        'onesuperior',    'ordmasculine',   'guillemotright',\n        'onequarter',     'onehalf',        'threequarters',  'questiondown',\n        'Agrave',         'Aacute',         'Acircumflex',    'Atilde',\n        'Adieresis',      'Aring',          'AE',             'Ccedilla',\n        'Egrave',         'Eacute',         'Ecircumflex',    'Edieresis',\n        'Igrave',         'Iacute',         'Icircumflex',    'Idieresis',\n        'Gbreve',         'Ntilde',         'Ograve',         'Oacute',\n        'Ocircumflex',    'Otilde',         'Odieresis',      'multiply',\n        'Oslash',         'Ugrave',         'Uacute',         'Ucircumflex',\n        'Udieresis',      'Idotaccent',     'Scedilla',       'germandbls',\n        'agrave',         'aacute',         'acircumflex',    'atilde',\n        'adieresis',      'aring',          'ae',             'ccedilla',\n        'egrave',         'eacute',         'ecircumflex',    'edieresis',\n        'igrave',         'iacute',         'icircumflex',    'idieresis',\n        'gbreve',         'ntilde',         'ograve',         'oacute',\n        'ocircumflex',    'otilde',         'odieresis',      'divide',\n        'oslash',         'ugrave',         'uacute',         'ucircumflex',\n        'udieresis',      'dotlessi',       'scedilla',       'ydieresis'\n    ],\n# Thai\n    'ISO-8859-11' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'kokaithai',      'khokhaithai',    'khokhuatthai',\n        'khokhwaithai',   'khokhonthai',    'khorakhangthai', 'ngonguthai',\n        'chochanthai',    'chochingthai',   'chochangthai',   'sosothai',\n        'chochoethai',    'yoyingthai',     'dochadathai',    'topatakthai',\n        'thothanthai',    'thonangmonthothai','thophuthaothai', 'nonenthai',\n        'dodekthai',      'totaothai',      'thothungthai',   'thothahanthai',\n        'thothongthai',   'nonuthai',       'bobaimaithai',   'poplathai',\n        'phophungthai',   'fofathai',       'phophanthai',    'fofanthai',\n        'phosamphaothai', 'momathai',       'yoyakthai',      'roruathai',\n        'ruthai',         'lolingthai',     'luthai',         'wowaenthai',\n        'sosalathai',     'sorusithai',     'sosuathai',      'hohipthai',\n        'lochulathai',    'oangthai',       'honokhukthai',   'paiyannoithai',\n        'saraathai',      'maihanakatthai', 'saraaathai',     'saraamthai',\n        'saraithai',      'saraiithai',     'sarauethai',     'saraueethai',\n        'sarauthai',      'sarauuthai',     'phinthuthai',    '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        'bahtthai',\n        'saraethai',      'saraaethai',     'saraothai',      'saraaimaimuanthai',\n        'saraaimaimalaithai','lakkhangyaothai','maiyamokthai',   'maitaikhuthai',\n        'maiekthai',      'maithothai',     'maitrithai',     'maichattawathai',\n        'thanthakhatthai','nikhahitthai',   'yamakkanthai',   'fongmanthai',\n        'zerothai',       'onethai',        'twothai',        'threethai',\n        'fourthai',       'fivethai',       'sixthai',        'seventhai',\n        'eightthai',      'ninethai',       'angkhankhuthai', 'khomutthai',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef'\n    ],\n# Western Europe\n    'ISO-8859-15' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclamdown',     'cent',           'sterling',\n        'Euro',           'yen',            'Scaron',         'section',\n        'scaron',         'copyright',      'ordfeminine',    'guillemotleft',\n        'logicalnot',     'hyphen',         'registered',     'macron',\n        'degree',         'plusminus',      'twosuperior',    'threesuperior',\n        'Zcaron',         'mu',             'paragraph',      'periodcentered',\n        'zcaron',         'onesuperior',    'ordmasculine',   'guillemotright',\n        'OE',             'oe',             'Ydieresis',      'questiondown',\n        'Agrave',         'Aacute',         'Acircumflex',    'Atilde',\n        'Adieresis',      'Aring',          'AE',             'Ccedilla',\n        'Egrave',         'Eacute',         'Ecircumflex',    'Edieresis',\n        'Igrave',         'Iacute',         'Icircumflex',    'Idieresis',\n        'Eth',            'Ntilde',         'Ograve',         'Oacute',\n        'Ocircumflex',    'Otilde',         'Odieresis',      'multiply',\n        'Oslash',         'Ugrave',         'Uacute',         'Ucircumflex',\n        'Udieresis',      'Yacute',         'Thorn',          'germandbls',\n        'agrave',         'aacute',         'acircumflex',    'atilde',\n        'adieresis',      'aring',          'ae',             'ccedilla',\n        'egrave',         'eacute',         'ecircumflex',    'edieresis',\n        'igrave',         'iacute',         'icircumflex',    'idieresis',\n        'eth',            'ntilde',         'ograve',         'oacute',\n        'ocircumflex',    'otilde',         'odieresis',      'divide',\n        'oslash',         'ugrave',         'uacute',         'ucircumflex',\n        'udieresis',      'yacute',         'thorn',          'ydieresis'\n    ],\n# Central Europe\n    'ISO-8859-16' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'Aogonek',        'aogonek',        'Lslash',\n        'Euro',           'quotedblbase',   'Scaron',         'section',\n        'scaron',         'copyright',      'Scommaaccent',   'guillemotleft',\n        'Zacute',         'hyphen',         'zacute',         'Zdotaccent',\n        'degree',         'plusminus',      'Ccaron',         'lslash',\n        'Zcaron',         'quotedblright',  'paragraph',      'periodcentered',\n        'zcaron',         'ccaron',         'scommaaccent',   'guillemotright',\n        'OE',             'oe',             'Ydieresis',      'zdotaccent',\n        'Agrave',         'Aacute',         'Acircumflex',    'Abreve',\n        'Adieresis',      'Cacute',         'AE',             'Ccedilla',\n        'Egrave',         'Eacute',         'Ecircumflex',    'Edieresis',\n        'Igrave',         'Iacute',         'Icircumflex',    'Idieresis',\n        'Dcroat',         'Nacute',         'Ograve',         'Oacute',\n        'Ocircumflex',    'Ohungarumlaut',  'Odieresis',      'Sacute',\n        'Uhungarumlaut',  'Ugrave',         'Uacute',         'Ucircumflex',\n        'Udieresis',      'Eogonek',        'Tcommaaccent',   'germandbls',\n        'agrave',         'aacute',         'acircumflex',    'abreve',\n        'adieresis',      'cacute',         'ae',             'ccedilla',\n        'egrave',         'eacute',         'ecircumflex',    'edieresis',\n        'igrave',         'iacute',         'icircumflex',    'idieresis',\n        'dcroat',         'nacute',         'ograve',         'oacute',\n        'ocircumflex',    'ohungarumlaut',  'odieresis',      'sacute',\n        'uhungarumlaut',  'ugrave',         'uacute',         'ucircumflex',\n        'udieresis',      'eogonek',        'tcommaaccent',   'ydieresis'\n    ],\n# Russian\n    'KOI8-R' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        'SF100000',       'SF110000',       'SF010000',       'SF030000',\n        'SF020000',       'SF040000',       'SF080000',       'SF090000',\n        'SF060000',       'SF070000',       'SF050000',       'upblock',\n        'dnblock',        'block',          'lfblock',        'rtblock',\n        'ltshade',        'shade',          'dkshade',        'integraltp',\n        'filledbox',      'periodcentered', 'radical',        'approxequal',\n        'lessequal',      'greaterequal',   'space',          'integralbt',\n        'degree',         'twosuperior',    'periodcentered', 'divide',\n        'SF430000',       'SF240000',       'SF510000',       'afii10071',\n        'SF520000',       'SF390000',       'SF220000',       'SF210000',\n        'SF250000',       'SF500000',       'SF490000',       'SF380000',\n        'SF280000',       'SF270000',       'SF260000',       'SF360000',\n        'SF370000',       'SF420000',       'SF190000',       'afii10023',\n        'SF200000',       'SF230000',       'SF470000',       'SF480000',\n        'SF410000',       'SF450000',       'SF460000',       'SF400000',\n        'SF540000',       'SF530000',       'SF440000',       'copyright',\n        'afii10096',      'afii10065',      'afii10066',      'afii10088',\n        'afii10069',      'afii10070',      'afii10086',      'afii10068',\n        'afii10087',      'afii10074',      'afii10075',      'afii10076',\n        'afii10077',      'afii10078',      'afii10079',      'afii10080',\n        'afii10081',      'afii10097',      'afii10082',      'afii10083',\n        'afii10084',      'afii10085',      'afii10072',      'afii10067',\n        'afii10094',      'afii10093',      'afii10073',      'afii10090',\n        'afii10095',      'afii10091',      'afii10089',      'afii10092',\n        'afii10048',      'afii10017',      'afii10018',      'afii10040',\n        'afii10021',      'afii10022',      'afii10038',      'afii10020',\n        'afii10039',      'afii10026',      'afii10027',      'afii10028',\n        'afii10029',      'afii10030',      'afii10031',      'afii10032',\n        'afii10033',      'afii10049',      'afii10034',      'afii10035',\n        'afii10036',      'afii10037',      'afii10024',      'afii10019',\n        'afii10046',      'afii10045',      'afii10025',      'afii10042',\n        'afii10047',      'afii10043',      'afii10041',      'afii10044'\n    ],\n# Ukrainian\n    'KOI8-U' => [\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        '.notdef',        '.notdef',        '.notdef',        '.notdef',\n        'space',          'exclam',         'quotedbl',       'numbersign',\n        'dollar',         'percent',        'ampersand',      'quotesingle',\n        'parenleft',      'parenright',     'asterisk',       'plus',\n        'comma',          'hyphen',         'period',         'slash',\n        'zero',           'one',            'two',            'three',\n        'four',           'five',           'six',            'seven',\n        'eight',          'nine',           'colon',          'semicolon',\n        'less',           'equal',          'greater',        'question',\n        'at',             'A',              'B',              'C',\n        'D',              'E',              'F',              'G',\n        'H',              'I',              'J',              'K',\n        'L',              'M',              'N',              'O',\n        'P',              'Q',              'R',              'S',\n        'T',              'U',              'V',              'W',\n        'X',              'Y',              'Z',              'bracketleft',\n        'backslash',      'bracketright',   'asciicircum',    'underscore',\n        'grave',          'a',              'b',              'c',\n        'd',              'e',              'f',              'g',\n        'h',              'i',              'j',              'k',\n        'l',              'm',              'n',              'o',\n        'p',              'q',              'r',              's',\n        't',              'u',              'v',              'w',\n        'x',              'y',              'z',              'braceleft',\n        'bar',            'braceright',     'asciitilde',     '.notdef',\n        'SF100000',       'SF110000',       'SF010000',       'SF030000',\n        'SF020000',       'SF040000',       'SF080000',       'SF090000',\n        'SF060000',       'SF070000',       'SF050000',       'upblock',\n        'dnblock',        'block',          'lfblock',        'rtblock',\n        'ltshade',        'shade',          'dkshade',        'integraltp',\n        'filledbox',      'bullet',         'radical',        'approxequal',\n        'lessequal',      'greaterequal',   'space',          'integralbt',\n        'degree',         'twosuperior',    'periodcentered', 'divide',\n        'SF430000',       'SF240000',       'SF510000',       'afii10071',\n        'afii10101',      'SF390000',       'afii10103',      'afii10104',\n        'SF250000',       'SF500000',       'SF490000',       'SF380000',\n        'SF280000',       'afii10098',      'SF260000',       'SF360000',\n        'SF370000',       'SF420000',       'SF190000',       'afii10023',\n        'afii10053',      'SF230000',       'afii10055',      'afii10056',\n        'SF410000',       'SF450000',       'SF460000',       'SF400000',\n        'SF540000',       'afii10050',      'SF440000',       'copyright',\n        'afii10096',      'afii10065',      'afii10066',      'afii10088',\n        'afii10069',      'afii10070',      'afii10086',      'afii10068',\n        'afii10087',      'afii10074',      'afii10075',      'afii10076',\n        'afii10077',      'afii10078',      'afii10079',      'afii10080',\n        'afii10081',      'afii10097',      'afii10082',      'afii10083',\n        'afii10084',      'afii10085',      'afii10072',      'afii10067',\n        'afii10094',      'afii10093',      'afii10073',      'afii10090',\n        'afii10095',      'afii10091',      'afii10089',      'afii10092',\n        'afii10048',      'afii10017',      'afii10018',      'afii10040',\n        'afii10021',      'afii10022',      'afii10038',      'afii10020',\n        'afii10039',      'afii10026',      'afii10027',      'afii10028',\n        'afii10029',      'afii10030',      'afii10031',      'afii10032',\n        'afii10033',      'afii10049',      'afii10034',      'afii10035',\n        'afii10036',      'afii10037',      'afii10024',      'afii10019',\n        'afii10046',      'afii10045',      'afii10025',      'afii10042',\n        'afii10047',      'afii10043',      'afii10041',      'afii10044'\n    ]\n}\n\ndef ReadAFM(file, map)\n\n    # Read a font metric file\n    a = IO.readlines(file)\n\n    raise \"File no found: #{file}\" if a.size == 0\n\n    widths = {}\n    fm = {}\n    fix = { 'Edot' => 'Edotaccent', 'edot' => 'edotaccent',\n            'Idot' => 'Idotaccent',\n            'Zdot' => 'Zdotaccent', 'zdot' => 'zdotaccent',\n            'Odblacute' => 'Ohungarumlaut', 'odblacute' => 'ohungarumlaut',\n            'Udblacute' => 'Uhungarumlaut', 'udblacute' => 'uhungarumlaut',\n            'Gcedilla' => 'Gcommaaccent', 'gcedilla' => 'gcommaaccent',\n            'Kcedilla' => 'Kcommaaccent', 'kcedilla' => 'kcommaaccent',\n            'Lcedilla' => 'Lcommaaccent', 'lcedilla' => 'lcommaaccent',\n            'Ncedilla' => 'Ncommaaccent', 'ncedilla' => 'ncommaaccent',\n            'Rcedilla' => 'Rcommaaccent', 'rcedilla' => 'rcommaaccent',\n            'Scedilla' => 'Scommaaccent',' scedilla' => 'scommaaccent',\n            'Tcedilla' => 'Tcommaaccent',' tcedilla' => 'tcommaaccent',\n            'Dslash' => 'Dcroat', 'dslash' => 'dcroat',\n            'Dmacron' => 'Dcroat', 'dmacron' => 'dcroat',\n            'combininggraveaccent' => 'gravecomb',\n            'combininghookabove' => 'hookabovecomb',\n            'combiningtildeaccent' => 'tildecomb',\n            'combiningacuteaccent' => 'acutecomb',\n            'combiningdotbelow' => 'dotbelowcomb',\n            'dongsign' => 'dong'\n        }\n\n    a.each do |line|\n\n        e = line.rstrip.split(' ')\n\tnext if e.size < 2\n\n\tcode  = e[0]\n\tparam = e[1]\n\n\tif code == 'C' then\n\n\t    # Character metrics\n\t    cc = e[1].to_i\n\t    w  = e[4]\n\t    gn = e[7]\n\n\t    gn = 'Euro' if gn[-4, 4] == '20AC'\n\n\t    if fix[gn] then\n\n\t\t# Fix incorrect glyph name\n\t\t0.upto(map.size - 1) do |i|\n\t\t    if map[i] == fix[gn] then\n\t\t\tmap[i] = gn\n\t\t    end\n\t\tend\n\t    end\n\n\t    if map.size == 0 then\n\t\t# Symbolic font: use built-in encoding\n\t\twidths[cc] = w\n\t    else\n\t\twidths[gn] = w\n\t\tfm['CapXHeight'] = e[13].to_i if gn == 'X'\n\t    end\n\n\t    fm['MissingWidth'] = w if gn == '.notdef'\n\n\telsif code == 'FontName' then\n\t    fm['FontName'] = param\n\telsif code == 'Weight' then\n\t    fm['Weight'] = param\n\telsif code == 'ItalicAngle' then\n\t    fm['ItalicAngle'] = param.to_f\n\telsif code == 'Ascender' then\n\t    fm['Ascender'] = param.to_i\n\telsif code == 'Descender' then\n\t    fm['Descender'] = param.to_i\n\telsif code == 'UnderlineThickness' then\n\t    fm['UnderlineThickness'] = param.to_i\n\telsif code == 'UnderlinePosition' then\n\t    fm['UnderlinePosition'] = param.to_i\n\telsif code == 'IsFixedPitch' then\n\t    fm['IsFixedPitch'] = (param == 'true')\n\telsif code == 'FontBBox' then\n\t    fm['FontBBox'] = \"[#{e[1]},#{e[2]},#{e[3]},#{e[4]}]\"\n\telsif code == 'CapHeight' then\n\t    fm['CapHeight'] = param.to_i\n\telsif code == 'StdVW' then\n\t    fm['StdVW'] = param.to_i\n\tend\n    end\n\n    raise 'FontName not found' unless fm['FontName']\n\n    if map.size > 0 then\n\twidths['.notdef'] = 600 unless widths['.notdef']\n\n\tif (widths['Delta'] == nil) && widths['increment'] then\n\t    widths['Delta'] = widths['increment']\n\tend\n\n\t# Order widths according to map\n\t0.upto(255) do |i|\n\t    if widths[map[i]] == nil\n\t\tputs \"Warning: character #{map[i]} is missing\"\n\t\twidths[i] = widths['.notdef']\n\t    else\n\t\twidths[i] = widths[map[i]]\n\t    end\n\tend\n    end\n\n    fm['Widths'] = widths\n\n    return fm\nend\n\ndef MakeFontDescriptor(fm, symbolic)\n\n    # Ascent\n    asc = fm['Ascender'] ? fm['Ascender'] : 1000\n    fd = \"{\\n        'Ascent' => '#{asc}'\"\n\n    # Descent\n    desc = fm['Descender'] ? fm['Descender'] : -200\n    fd += \", 'Descent' => '#{desc}'\"\n\n    # CapHeight\n    if fm['CapHeight'] then\n        ch = fm['CapHeight']\n    elsif fm['CapXHeight']\n        ch = fm['CapXHeight']\n    else\n        ch = asc\n    end\n    fd += \", 'CapHeight' => '#{ch}'\"\n\n    # Flags\n    flags = 0\n\n    if fm['IsFixedPitch'] then\n        flags += 1 << 0\n    end\n\n    if symbolic then\n        flags += 1 << 2\n    else\n        flags += 1 << 5\n    end\n\n    if fm['ItalicAngle'] && (fm['ItalicAngle'] != 0) then\n        flags += 1 << 6\n    end\n\n    fd += \",\\n        'Flags' => '#{flags}'\"\n\n    # FontBBox\n    if fm['FontBBox'] then\n        fbb = fm['FontBBox'].gsub(/,/, ' ')\n    else\n        fbb = \"[0 #{desc - 100} 1000 #{asc + 100}]\"\n    end\n\n    fd += \", 'FontBBox' => '#{fbb}'\"\n\n    # ItalicAngle\n    ia = fm['ItalicAngle'] ? fm['ItalicAngle'] : 0\n    fd += \",\\n        'ItalicAngle' => '#{ia}'\"\n\n    # StemV\n    if fm['StdVW'] then\n        stemv = fm['StdVW']\n    elsif fm['Weight'] && (/bold|black/i =~ fm['Weight'])\n        stemv = 120\n    else\n        stemv = 70\n    end\n\n    fd += \", 'StemV' => '#{stemv}'\"\n\n    # MissingWidth\n    if fm['MissingWidth'] then\n        fd += \", 'MissingWidth' => '#{fm['MissingWidth']}'\"\n    end\n\n    fd += \"\\n        }\"\n    return fd\nend\n\ndef MakeWidthArray(fm)\n\n    # Make character width array\n    s = \"        [\\n        \"\n\n    cw = fm['Widths']\n\n    0.upto(255) do |i|\n        s += \"%5d\" % cw[i]\n        s += \",\" if i != 255\n        s += \"\\n        \" if (i % 8) == 7\n    end\n\n    s += ']'\n\n    return s\nend\n\ndef MakeFontEncoding(map)\n\n    # Build differences from reference encoding\n    ref = Charencodings['cp1252']\n    s = ''\n    last = 0\n    32.upto(255) do |i|\n\tif map[i] != ref[i] then\n\t    if i != last + 1 then\n\t\ts += i.to_s + ' '\n            end\n\t    last = i\n\t    s += '/' + map[i] + ' '\n\tend\n    end\n    return s.rstrip\nend\n\ndef ReadShort(f)\n    a = f.read(2).unpack('n')\n    return a[0]\nend\n\ndef ReadLong(f)\n    a = f.read(4).unpack('N')\n    return a[0]\nend\n\ndef CheckTTF(file)\n\n    rl = false\n    pp = false\n    e  = false\n\n    # Check if font license allows embedding\n    File.open(file, 'rb') do |f|\n\n        # Extract number of tables\n        f.seek(4, IO::SEEK_CUR)\n\tnb = ReadShort(f)\n        f.seek(6, IO::SEEK_CUR)\n\n        # Seek OS/2 table\n\tfound = false\n        0.upto(nb - 1) do |i|\n            if f.read(4) == 'OS/2' then\n                found = true\n                break\n            end\n\n           f.seek(12, IO::SEEK_CUR)\n        end\n\n\tif ! found then\n            return\n        end\n\n        f.seek(4, IO::SEEK_CUR)\n        offset = ReadLong(f)\n        f.seek(offset, IO::SEEK_SET)\n\n        # Extract fsType flags\n        f.seek(8, IO::SEEK_CUR)\n\tfsType = ReadShort(f)\n\n\trl = (fsType & 0x02) != 0\n\tpp = (fsType & 0x04) != 0\n\te  = (fsType & 0x08) != 0\n    end\n\n    if rl && ( ! pp) && ( ! e) then\n        puts 'Warning: font license does not allow embedding'\n    end\nend\n\n#\n# fontfile: path to TTF file (or empty string if not to be embedded)\n# afmfile:  path to AFM file\n# enc:      font encoding (or empty string for symbolic fonts)\n# patch:    optional patch for encoding\n# type :    font type if $fontfile is empty\n#\ndef MakeFont(fontfile, afmfile, enc = 'cp1252', patch = {}, type = 'TrueType')\n    # Generate a font definition file\n    if (enc != nil) && (enc != '') then\n\tmap = Charencodings[enc]\n\tpatch.each { |cc, gn| map[cc] = gn }\n    else\n\tmap = []\n    end\n\n    raise \"Error: AFM file not found: #{afmfile}\" unless File.exists?(afmfile)\n\n    fm = ReadAFM(afmfile, map)\n\n    if (enc != nil) && (enc != '') then\n\tdiff = MakeFontEncoding(map)\n    else\n\tdiff = ''\n    end\n\n    fd = MakeFontDescriptor(fm, (map.size == 0))\n\n    # Find font type\n    if fontfile then\n        ext = File.extname(fontfile).downcase.sub(/^\\./, '')\n\n        if ext == 'ttf' then\n            type = 'TrueType'\n        elsif ext == 'pfb'\n            type = 'Type1'\n        else\n            raise \"Error: unrecognized font file extension: #{ext}\"\n        end\n    else\n\t    raise \"Error: incorrect font type: #{type}\" if (type != 'TrueType') && (type != 'Type1')\n    end\n    printf \"type = #{type}\\n\"\n    # Start generation\n    s  = \"# #{fm['FontName']} font definition\\n\\n\"\n    s += \"module FontDef\\n\"\n    s += \"    def FontDef.type\\n        '#{type}'\\n    end\\n\"\n    s += \"    def FontDef.name\\n        '#{fm['FontName']}'\\n    end\\n\"\n    s += \"    def FontDef.desc\\n        #{fd}\\n    end\\n\"\n\n    if fm['UnderlinePosition'] == nil then\n        fm['UnderlinePosition'] = -100\n    end\n\n    if fm['UnderlineThickness'] == nil then\n        fm['UnderlineThickness'] = 50\n    end\n\n    s += \"    def FontDef.up\\n        #{fm['UnderlinePosition']}\\n    end\\n\"\n    s += \"    def FontDef.ut\\n        #{fm['UnderlineThickness']}\\n    end\\n\"\n\n    w = MakeWidthArray(fm)\n    s += \"    def FontDef.cw\\n#{w}\\n    end\\n\"\n\n    s += \"    def FontDef.enc\\n        '#{enc}'\\n    end\\n\"\n    s += \"    def FontDef.diff\\n        #{(diff == nil) || (diff == '') ? 'nil' : '\\'' + diff + '\\''}\\n    end\\n\"\n\n    basename = File.basename(afmfile, '.*')\n\n    if fontfile then\n        # Embedded font\n        if ! File.exist?(fontfile) then\n            raise \"Error: font file not found: #{fontfile}\"\n        end\n\n        if type == 'TrueType' then\n            CheckTTF(fontfile)\n        end\n\n\tfile = ''\n        File.open(fontfile, 'rb') do |f|\n            file = f.read()\n        end\n\n        if type == 'Type1' then\n            # Find first two sections and discard third one\n            header = file[0] == 128\n            file = file[6, file.length - 6] if header\n\n            pos = file.index('eexec')\n            raise 'Error: font file does not seem to be valid Type1' if pos == nil\n\n            size1 = pos + 6\n\n            file = file[0, size1] + file[size1 + 6, file.length - (size1 + 6)] if header && file[size1] == 128\n\n            pos = file.index('00000000')\n            raise 'Error: font file does not seem to be valid Type1' if pos == nil\n\n            size2 = pos - size1\n            file = file[0, size1 + size2]\n        end\n\n        if require 'zlib' then\n            File.open(basename + '.z', 'wb') { |f| f.write(Zlib::Deflate.deflate(file)) }\n            s += \"    def FontDef.file\\n        '#{basename}.z'\\n    end\\n\"\n            puts \"Font file compressed ('#{basename}.z')\"\n        else\n            s += \"    def FontDef.file\\n        '#{File.basename(fontfile)}'\\n    end\\n\"\n            puts 'Notice: font file could not be compressed (zlib not available)'\n        end\n\n        if type == 'Type1' then\n            s += \"    def FontDef.size1\\n        '#{size1}'\\n    end\\n\"\n            s += \"    def FontDef.size2\\n        '#{size2}'\\n    end\\n\"\n        else\n            s += \"    def FontDef.originalsize\\n        '#{File.size(fontfile)}'\\n    end\\n\"\n        end\n\n    else\n        # Not embedded font\n        s += \"    def FontDef.file\\n        ''\\n    end\\n\"\n    end\n\n    s += \"end\\n\"\n    File.open(basename + '.rb', 'w') { |file| file.write(s)}\n    puts \"Font definition file generated (#{basename}.rb)\"\nend\n\n\nif $0 == __FILE__ then\n    if ARGV.length >= 3 then\n        enc = ARGV[2]\n    else\n        enc = 'cp1252'\n    end\n\n    if ARGV.length >= 4 then\n        patch = ARGV[3]\n    else\n        patch = {}\n    end\n\n    if ARGV.length >= 5 then\n        type = ARGV[4]\n    else\n        type = 'TrueType'\n    end\n\n    MakeFont(ARGV[0], ARGV[1], enc, patch, type)\nend\n"
  },
  {
    "path": "vendor/plugins/rfpdf/lib/rfpdf/rfpdf.rb",
    "content": "module RFPDF\n  COLOR_PALETTE = {\n\t  :black => [0x00, 0x00, 0x00],\n\t  :white => [0xff, 0xff, 0xff],\n  }.freeze\n\n  # Draw a line from (<tt>x1, y1</tt>) to (<tt>x2, y2</tt>).\n  # \n  # Options are:\n  # * <tt>:line_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.\n  # * <tt>:line_width</tt> - Default value is <tt>0.5</tt>.\n  #\n  # Example:\n  #\n\t#   draw_line(x1, y1, x1, y1+h, :line_color => ReportHelper::COLOR_PALETTE[:dark_blue], :line_width => 1)\n\t#\n  def draw_line(x1, y1, x2, y2, options = {})\n    options[:line_color] ||= COLOR_PALETTE[:black]\n    options[:line_width] ||= 0.5\n    set_draw_color(options[:line_color])\n    SetLineWidth(options[:line_width])\n    Line(x1, y1, x2, y2)\n  end\n\n  # Draw a string of <tt>text</tt> at (<tt>x, y</tt>).\n  # \n  # Options are:\n  # * <tt>:font_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.\n  # * <tt>:font_size</tt> - Default value is <tt>10</tt>.\n  # * <tt>:font_style</tt> - Default value is nothing or <tt>''</tt>.\n  #\n  # Example:\n  #\n\t#   draw_text(x, y, header_left, :font_size => 10)\n\t#\n  def draw_text(x, y, text, options = {})\n    options[:font_color] ||= COLOR_PALETTE[:black]\n    options[:font_size] ||= 10\n    options[:font_style] ||= ''\n    set_text_color(options[:font_color])\n    SetFont('Arial', options[:font_style], options[:font_size])\n    SetXY(x, y)\n    Write(options[:font_size] + 4, text)\n  end\n\n  # Draw a block of <tt>text</tt> at (<tt>x, y</tt>) bounded by <tt>left_margin</tt> and <tt>right_margin</tt>. Both\n  # margins are measured from their corresponding edge.\n  # \n  # Options are:\n  # * <tt>:font_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.\n  # * <tt>:font_size</tt> - Default value is <tt>10</tt>.\n  # * <tt>:font_style</tt> - Default value is nothing or <tt>''</tt>.\n  #\n  # Example:\n  #\n\t#   draw_text_block(left_margin, 85, \"question\", left_margin, 280,\n  #       :font_color => ReportHelper::COLOR_PALETTE[:dark_blue],\n  #       :font_size => 12,\n  #       :font_style => 'I')\n\t#\n  def draw_text_block(x, y, text, left_margin, right_margin, options = {})\n    options[:font_color] ||= COLOR_PALETTE[:black]\n    options[:font_size] ||= 10\n    options[:font_style] ||= ''\n    set_text_color(options[:font_color])\n    SetFont('Arial', options[:font_style], options[:font_size])\n    SetXY(x, y)\n    SetLeftMargin(left_margin)\n    SetRightMargin(right_margin)\n    Write(options[:font_size] + 4, text)\n    SetMargins(0,0,0)\n  end\n\n  # Draw a box at (<tt>x, y</tt>), <tt>w</tt> wide and <tt>h</tt> high.\n  # \n  # Options are:\n  # * <tt>:border</tt> - Draw a border, 0 = no, 1 = yes? Default value is <tt>1</tt>.\n  # * <tt>:border_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.\n  # * <tt>:border_width</tt> - Default value is <tt>0.5</tt>.\n  # * <tt>:fill</tt> - Fill the box, 0 = no, 1 = yes? Default value is <tt>1</tt>.\n  # * <tt>:fill_color</tt> - Default value is nothing or <tt>COLOR_PALETTE[:white]</tt>.\n  #\n  # Example:\n  #\n\t#   draw_box(x, y - 1, 38, 22)\n\t#\n  def draw_box(x, y, w, h, options = {})\n    options[:border] ||= 1\n    options[:border_color] ||= COLOR_PALETTE[:black]\n    options[:border_width] ||= 0.5\n    options[:fill] ||= 1\n    options[:fill_color] ||= COLOR_PALETTE[:white]\n    SetLineWidth(options[:border_width])\n    set_draw_color(options[:border_color])\n    set_fill_color(options[:fill_color])\n    fd = \"\"\n    fd = \"D\" if options[:border] == 1\n    fd += \"F\" if options[:fill] == 1\n    Rect(x, y, w, h, fd)\n  end\n  \n  # Draw a string of <tt>text</tt> at (<tt>x, y</tt>) in a box <tt>w</tt> wide and <tt>h</tt> high.\n  # \n  # Options are:\n  # * <tt>:align</tt> - Vertical alignment 'C' = center, 'L' = left, 'R' = right. Default value is <tt>'C'</tt>.\n  # * <tt>:border</tt> - Draw a border, 0 = no, 1 = yes? Default value is <tt>0</tt>.\n  # * <tt>:border_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.\n  # * <tt>:border_width</tt> - Default value is <tt>0.5</tt>.\n  # * <tt>:fill</tt> - Fill the box, 0 = no, 1 = yes? Default value is <tt>1</tt>.\n  # * <tt>:fill_color</tt> - Default value is nothing or <tt>COLOR_PALETTE[:white]</tt>.\n  # * <tt>:font_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.\n  # * <tt>:font_size</tt> - Default value is nothing or <tt>8</tt>.\n  # * <tt>:font_style</tt> - 'B' = bold, 'I' = italic, 'U' = underline. Default value is nothing <tt>''</tt>.\n  # * <tt>:padding</tt> - Default value is nothing or <tt>2</tt>.\n  # * <tt>:valign</tt> - 'M' = middle, 'T' = top, 'B' = bottom. Default value is nothing or <tt>'M'</tt>.\n  #\n  # Example:\n  #\n\t#   draw_text_box(x, y - 1, 38, 22, \n  #                 \"your_score_title\", \n  #                 :fill => 0,\n  #                 :font_color => ReportHelper::COLOR_PALETTE[:blue], \n  #                 :font_line_spacing => 0,\n  #                 :font_style => \"B\",\n  #                 :valign => \"M\")\n\t#\n  def draw_text_box(x, y, w, h, text, options = {})\n    options[:align] ||= 'C'\n    options[:border] ||= 0\n    options[:border_color] ||= COLOR_PALETTE[:black]\n    options[:border_width] ||= 0.5\n    options[:fill] ||= 1\n    options[:fill_color] ||= COLOR_PALETTE[:white]\n    options[:font_color] ||= COLOR_PALETTE[:black]\n    options[:font_size] ||= 8\n    options[:font_line_spacing] ||= options[:font_size] * 0.3\n    options[:font_style] ||= ''\n    options[:padding] ||= 2\n    options[:valign] ||= \"M\"\n\t\tif options[:fill] == 1 or options[:border] == 1\n      draw_box(x, y, w, h, options)\n  \tend    \n    SetMargins(0,0,0)\n    set_text_color(options[:font_color])\n  \tfont_size = options[:font_size]\n    SetFont('Arial', options[:font_style], font_size)\n  \tfont_size += options[:font_line_spacing]\n  \tcase options[:valign]\n  \t  when \"B\"\n  \t    y -= options[:padding]\n        text = \"\\n\" + text if text[\"\\n\"].nil?\n  \t  when \"T\"\n  \t    y += options[:padding]\n  \tend\n    SetXY(x, y)\n  \tif GetStringWidth(text) > w or not text[\"\\n\"].nil? or options[:valign] == \"T\"\n    \tfont_size += options[:font_size] * 0.1\n    \t#TODO 2006-07-21 Level=1 - this is assuming a 2 line text\n    \tSetXY(x, y + ((h - (font_size * 2)) / 2)) if options[:valign] == \"M\"\n      MultiCell(w, font_size, text, 0, options[:align])\n    else\n      Cell(w, h, text, 0, 0, options[:align])\n    end\n  end\n  \n  # Draw a string of <tt>text</tt> at (<tt>x, y</tt>) as a title.\n  # \n  # Options are:\n  # * <tt>:font_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.\n  # * <tt>:font_size</tt> - Default value is <tt>18</tt>.\n  # * <tt>:font_style</tt> - Default value is nothing or <tt>''</tt>.\n  #\n  # Example:\n  #\n\t#   draw_title(left_margin, 60, \n\t#       \"title:\", \n\t#       :font_color => ReportHelper::COLOR_PALETTE[:dark_blue])\n\t#\n  def draw_title(x, y, title, options = {})\n    options[:font_color] ||= COLOR_PALETTE[:black]\n    options[:font_size] ||= 18\n    options[:font_style] ||= ''\n    set_text_color(options[:font_color])\n    SetFont('Arial', options[:font_style], options[:font_size])\n  \tSetXY(x, y)\n  \tWrite(options[:font_size] + 2, title)\n  end\n\n  # Set the draw color. Default value is <tt>COLOR_PALETTE[:black]</tt>.\n  #\n  # Example:\n  #\n\t#   set_draw_color(ReportHelper::COLOR_PALETTE[:dark_blue])\n\t#\n  def set_draw_color(color = COLOR_PALETTE[:black])\n    SetDrawColor(color[0], color[1], color[2])\n  end\n\n  # Set the fill color. Default value is <tt>COLOR_PALETTE[:white]</tt>.\n  #\n  # Example:\n  #\n\t#   set_fill_color(ReportHelper::COLOR_PALETTE[:dark_blue])\n\t#\n  def set_fill_color(color = COLOR_PALETTE[:white])\n    SetFillColor(color[0], color[1], color[2])\n  end\n\n  # Set the text color. Default value is <tt>COLOR_PALETTE[:white]</tt>.\n  #\n  # Example:\n  #\n\t#   set_text_color(ReportHelper::COLOR_PALETTE[:dark_blue])\n\t#\n  def set_text_color(color = COLOR_PALETTE[:black])\n    SetTextColor(color[0], color[1], color[2])\n  end\n    \n  # Write a string containing html characters. Default value is <tt>COLOR_PALETTE[:white]</tt>.\n  #\n  # Options are:\n  # * <tt>:height</tt> - Line height. Default value is <tt>20</tt>.\n  #\n  # Example:\n  #\n\t#   write_html(html, :height => 12)\n\t#\n  def write_html(html, options = {})\n    options[:height] ||= 20\n    #HTML parser\n    @href = nil\n    @style = {}\n    html.gsub!(\"\\n\",' ')\n    re = %r{ ( <!--.*?--> |\n               <  (?:\n                  [^<>\"] +\n                  |\n                  \"  (?: \\\\.  |  [^\\\\\"]+  ) *  \"\n                  ) *\n               >\n             )  }xm\n\n    html.split(re).each do |value|\n      if \"<\" == value[0,1]\n        #Tag\n        if (value[1, 1] == '/')\n          close_tag(value[2..-2], options)\n        else\n          tag = value[1..-2]\n          open_tag(tag, options)\n        end\n      else\n        #Text\n        if @href\n          put_link(@href,value)\n        else\n          Write(options[:height], value)\n        end\n      end\n    end\n  end\n\n  def open_tag(tag, options = {}) #:nodoc:\n    #Opening tag\n    tag = tag.to_s.upcase\n    set_style(tag, true) if tag == 'B' or tag == 'I' or tag == 'U'\n    @href = options['HREF'] if tag == 'A'\n    Ln(options[:height]) if tag == 'BR'\n  end\n\n  def close_tag(tag, options = {}) #:nodoc:\n    #Closing tag\n    tag = tag.to_s.upcase\n    set_style(tag, false) if tag == 'B' or tag == 'I' or  tag == 'U'\n    @href = '' if $tag == 'A'\n  end\n\n  def set_style(tag, enable = true) #:nodoc:\n    #Modify style and select corresponding font\n    style = \"\"\n    @style[tag] = enable\n    ['B','I','U'].each do |s|\n      style += s if not @style[s].nil? and @style[s]\n    end\n    SetFont('', style)\n  end\n\n  def put_link(url, txt) #:nodoc:\n    #Put a hyperlink\n    SetTextColor(0,0,255)\n    set_style('U',true)\n    Write(5, txt, url)\n    set_style('U',false)\n    SetTextColor(0)\n  end \nend\n\n# class FPDF\n#   alias_method :set_margins         , :SetMargins\n#   alias_method :set_left_margin      , :SetLeftMargin\n#   alias_method :set_top_margin       , :SetTopMargin\n#   alias_method :set_right_margin     , :SetRightMargin\n#   alias_method :set_auto_pagebreak   , :SetAutoPageBreak\n#   alias_method :set_display_mode     , :SetDisplayMode\n#   alias_method :set_compression     , :SetCompression\n#   alias_method :set_title           , :SetTitle\n#   alias_method :set_subject         , :SetSubject\n#   alias_method :set_author          , :SetAuthor\n#   alias_method :set_keywords        , :SetKeywords\n#   alias_method :set_creator         , :SetCreator\n#   alias_method :set_draw_color       , :SetDrawColor\n#   alias_method :set_fill_color       , :SetFillColor\n#   alias_method :set_text_color       , :SetTextColor\n#   alias_method :set_line_width       , :SetLineWidth\n#   alias_method :set_font            , :SetFont\n#   alias_method :set_font_size        , :SetFontSize\n#   alias_method :set_link            , :SetLink\n#   alias_method :set_y               , :SetY\n#   alias_method :set_xy              , :SetXY\n#   alias_method :get_string_width     , :GetStringWidth\n#   alias_method :get_x               , :GetX\n#   alias_method :set_x               , :SetX\n#   alias_method :get_y               , :GetY\n#   alias_method :accept_pagev_break    , :AcceptPageBreak\n#   alias_method :add_font            , :AddFont\n#   alias_method :add_link            , :AddLink\n#   alias_method :add_page            , :AddPage\n#   alias_method :alias_nb_pages       , :AliasNbPages\n#   alias_method :cell               , :Cell\n#   alias_method :close              , :Close\n#   alias_method :error              , :Error\n#   alias_method :footer             , :Footer\n#   alias_method :header             , :Header\n#   alias_method :image              , :Image\n#   alias_method :line               , :Line\n#   alias_method :link               , :Link\n#   alias_method :ln                 , :Ln\n#   alias_method :multi_cell          , :MultiCell\n#   alias_method :open               , :Open\n#   alias_method :Open               , :open\n#   alias_method :output             , :Output\n#   alias_method :page_no             , :PageNo\n#   alias_method :rect               , :Rect\n#   alias_method :text               , :Text\n#   alias_method :write              , :Write\n# end\n"
  },
  {
    "path": "vendor/plugins/rfpdf/lib/rfpdf/view.rb",
    "content": "# Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>\n#\n# The MIT License\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n#\n# Thanks go out to Bruce Williams of codefluency who created RTex. This \n# template handler is modification of his work.\n#\n# Example Registration\n# \n#   ActionView::Base::register_template_handler 'rfpdf', RFpdfView\n\nmodule RFPDF\n  \n  class View\n    @@backward_compatibility_mode = false\n    cattr_accessor :backward_compatibility_mode\n    \n    def initialize(action_view)\n      @action_view = action_view\n      # Override with @options_for_rfpdf Hash in your controller\n      @options = {\n        # Run through latex first? (for table of contents, etc)\n        :pre_process => false,\n        # Debugging mode; raises exception\n        :debug => false,\n        # Filename of pdf to generate\n        :file_name => \"#{@action_view.controller.action_name}.pdf\",\n        # Temporary Directory\n        :temp_dir => \"#{File.expand_path(RAILS_ROOT)}/tmp\"\n      }.merge(@action_view.controller.instance_eval{ @options_for_rfpdf } || {}).with_indifferent_access\n    end\n    \n    def self.compilable?\n      false\n    end\n\n    def compilable?\n      self.class.compilable?\n    end\n\n    def render(template, local_assigns = {})\n\t\t\t@pdf_name = \"Default.pdf\" if @pdf_name.nil?\n\t\t  unless @action_view.controller.headers[\"Content-Type\"] == 'application/pdf'\n\t\t\t  @generate = true\n\t\t\t\t@action_view.controller.headers[\"Content-Type\"] = 'application/pdf'\n\t\t\t\t@action_view.controller.headers[\"Content-disposition:\"] = \"inline; filename=\\\"#{@options[:file_name]}\\\"\"\n\t\t\tend\n      assigns = @action_view.assigns.dup\n    \n      if content_for_layout = @action_view.instance_variable_get(\"@content_for_layout\")\n        assigns['content_for_layout'] = content_for_layout\n      end\n\n      result = @action_view.instance_eval do\n\t\t\t  assigns.each do |key,val|\n\t\t\t    instance_variable_set \"@#{key}\", val\n\t\t    end\n\t\t\t  local_assigns.each do |key,val|\n\t\t  \t\tclass << self; self; end.send(:define_method,key){ val }\n\t\t\t\tend\n        ERB.new(@@backward_compatibility_mode == true ? template : template.source).result(binding) \n      end\n    end\n\n  end\n  \nend"
  },
  {
    "path": "vendor/plugins/rfpdf/lib/rfpdf.rb",
    "content": "# Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>\n#\n# The MIT License\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\n$LOAD_PATH.unshift(File.dirname(__FILE__))\n\nrequire 'rfpdf/errors'\nrequire 'rfpdf/view'\nrequire 'rfpdf/fpdf'\nrequire 'rfpdf/rfpdf'\nrequire 'rfpdf/chinese'\nrequire 'rfpdf/japanese'\nrequire 'rfpdf/korean'\n"
  },
  {
    "path": "vendor/plugins/rfpdf/test/test_helper.rb",
    "content": "#!/usr/bin/env ruby"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/COPYING",
    "content": "              GNU GENERAL PUBLIC LICENSE\n                Version 2, June 1991\n\nCopyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street,\nFifth Floor, Boston, MA  02110-1301  USA Everyone is permitted to copy and\ndistribute verbatim copies of this license document, but changing it is not\nallowed.\n\n               Preamble\n\nThe licenses for most software are designed to take away your freedom to\nshare and change it.  By contrast, the GNU General Public License is\nintended to guarantee your freedom to share and change free software--to\nmake sure the software is free for all its users.  This General Public\nLicense applies to most of the Free Software Foundation's software and to\nany other program whose authors commit to using it.  (Some other Free\nSoftware Foundation software is covered by the GNU Lesser General Public\nLicense instead.)  You can apply it to your programs, too.\n\nWhen we speak of free software, we are referring to freedom, not price.  Our\nGeneral Public Licenses are designed to make sure that you have the freedom\nto distribute copies of free software (and charge for this service if you\nwish), that you receive source code or can get it if you want it, that you\ncan change the software or use pieces of it in new free programs; and that\nyou know you can do these things.\n\nTo protect your rights, we need to make restrictions that forbid anyone to\ndeny you these rights or to ask you to surrender the rights. These\nrestrictions translate to certain responsibilities for you if you distribute\ncopies of the software, or if you modify it.\n\nFor example, if you distribute copies of such a program, whether gratis or\nfor a fee, you must give the recipients all the rights that you have.  You\nmust make sure that they, too, receive or can get the source code.  And you\nmust show them these terms so they know their rights.\n\nWe protect your rights with two steps: (1) copyright the software, and (2)\noffer you this license which gives you legal permission to copy, distribute\nand/or modify the software.\n\nAlso, for each author's protection and ours, we want to make certain that\neveryone understands that there is no warranty for this free software.  If\nthe software is modified by someone else and passed on, we want its\nrecipients to know that what they have is not the original, so that any\nproblems introduced by others will not reflect on the original authors'\nreputations.\n\nFinally, any free program is threatened constantly by software patents.  We\nwish to avoid the danger that redistributors of a free program will\nindividually obtain patent licenses, in effect making the program\nproprietary. To prevent this, we have made it clear that any patent must be\nlicensed for everyone's free use or not licensed at all.\n\nThe precise terms and conditions for copying, distribution and modification\nfollow.\n\n           GNU GENERAL PUBLIC LICENSE\n  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n0. This License applies to any program or other work which contains a notice\n   placed by the copyright holder saying it may be distributed under the\n   terms of this General Public License.  The \"Program\", below, refers to\n   any such program or work, and a \"work based on the Program\" means either\n   the Program or any derivative work under copyright law: that is to say, a\n   work containing the Program or a portion of it, either verbatim or with\n   modifications and/or translated into another language.  (Hereinafter,\n   translation is included without limitation in the term \"modification\".)\n   Each licensee is addressed as \"you\".\n\n   Activities other than copying, distribution and modification are not\n   covered by this License; they are outside its scope.  The act of running\n   the Program is not restricted, and the output from the Program is covered\n   only if its contents constitute a work based on the Program (independent\n   of having been made by running the Program). Whether that is true depends\n   on what the Program does.\n\n1. You may copy and distribute verbatim copies of the Program's source code\n   as you receive it, in any medium, provided that you conspicuously and\n   appropriately publish on each copy an appropriate copyright notice and\n   disclaimer of warranty; keep intact all the notices that refer to this\n   License and to the absence of any warranty; and give any other recipients\n   of the Program a copy of this License along with the Program.\n\n   You may charge a fee for the physical act of transferring a copy, and you\n   may at your option offer warranty protection in exchange for a fee.\n\n2. You may modify your copy or copies of the Program or any portion of it,\n   thus forming a work based on the Program, and copy and distribute such\n   modifications or work under the terms of Section 1 above, provided that\n   you also meet all of these conditions:\n\n   a) You must cause the modified files to carry prominent notices stating\n      that you changed the files and the date of any change.\n\n   b) You must cause any work that you distribute or publish, that in whole\n      or in part contains or is derived from the Program or any part\n      thereof, to be licensed as a whole at no charge to all third parties\n      under the terms of this License.\n\n   c) If the modified program normally reads commands interactively when\n      run, you must cause it, when started running for such interactive use\n      in the most ordinary way, to print or display an announcement\n      including an appropriate copyright notice and a notice that there is\n      no warranty (or else, saying that you provide a warranty) and that\n      users may redistribute the program under these conditions, and telling\n      the user how to view a copy of this License.  (Exception: if the\n      Program itself is interactive but does not normally print such an\n      announcement, your work based on the Program is not required to print\n      an announcement.)\n\n   These requirements apply to the modified work as a whole.  If\n   identifiable sections of that work are not derived from the Program, and\n   can be reasonably considered independent and separate works in\n   themselves, then this License, and its terms, do not apply to those\n   sections when you distribute them as separate works.  But when you\n   distribute the same sections as part of a whole which is a work based on\n   the Program, the distribution of the whole must be on the terms of this\n   License, whose permissions for other licensees extend to the entire\n   whole, and thus to each and every part regardless of who wrote it.\n\n   Thus, it is not the intent of this section to claim rights or contest\n   your rights to work written entirely by you; rather, the intent is to\n   exercise the right to control the distribution of derivative or\n   collective works based on the Program.\n\n   In addition, mere aggregation of another work not based on the Program\n   with the Program (or with a work based on the Program) on a volume of a\n   storage or distribution medium does not bring the other work under the\n   scope of this License.\n\n3. You may copy and distribute the Program (or a work based on it, under\n   Section 2) in object code or executable form under the terms of Sections\n   1 and 2 above provided that you also do one of the following:\n\n   a) Accompany it with the complete corresponding machine-readable source\n      code, which must be distributed under the terms of Sections 1 and 2\n      above on a medium customarily used for software interchange; or,\n\n   b) Accompany it with a written offer, valid for at least three years, to\n      give any third party, for a charge no more than your cost of\n      physically performing source distribution, a complete machine-readable\n      copy of the corresponding source code, to be distributed under the\n      terms of Sections 1 and 2 above on a medium customarily used for\n      software interchange; or,\n\n   c) Accompany it with the information you received as to the offer to\n      distribute corresponding source code.  (This alternative is allowed\n      only for noncommercial distribution and only if you received the\n      program in object code or executable form with such an offer, in\n      accord with Subsection b above.)\n\n   The source code for a work means the preferred form of the work for\n   making modifications to it.  For an executable work, complete source code\n   means all the source code for all modules it contains, plus any\n   associated interface definition files, plus the scripts used to control\n   compilation and installation of the executable.  However, as a special\n   exception, the source code distributed need not include anything that is\n   normally distributed (in either source or binary form) with the major\n   components (compiler, kernel, and so on) of the operating system on which\n   the executable runs, unless that component itself accompanies the\n   executable.\n\n   If distribution of executable or object code is made by offering access\n   to copy from a designated place, then offering equivalent access to copy\n   the source code from the same place counts as distribution of the source\n   code, even though third parties are not compelled to copy the source\n   along with the object code.\n\n4. You may not copy, modify, sublicense, or distribute the Program except as\n   expressly provided under this License.  Any attempt otherwise to copy,\n   modify, sublicense or distribute the Program is void, and will\n   automatically terminate your rights under this License. However, parties\n   who have received copies, or rights, from you under this License will not\n   have their licenses terminated so long as such parties remain in full\n   compliance.\n\n5. You are not required to accept this License, since you have not signed\n   it.  However, nothing else grants you permission to modify or distribute\n   the Program or its derivative works.  These actions are prohibited by law\n   if you do not accept this License.  Therefore, by modifying or\n   distributing the Program (or any work based on the Program), you indicate\n   your acceptance of this License to do so, and all its terms and\n   conditions for copying, distributing or modifying the Program or works\n   based on it.\n\n6. Each time you redistribute the Program (or any work based on the\n   Program), the recipient automatically receives a license from the\n   original licensor to copy, distribute or modify the Program subject to\n   these terms and conditions.  You may not impose any further restrictions\n   on the recipients' exercise of the rights granted herein. You are not\n   responsible for enforcing compliance by third parties to this License.\n\n7. If, as a consequence of a court judgment or allegation of patent\n   infringement or for any other reason (not limited to patent issues),\n   conditions are imposed on you (whether by court order, agreement or\n   otherwise) that contradict the conditions of this License, they do not\n   excuse you from the conditions of this License.  If you cannot distribute\n   so as to satisfy simultaneously your obligations under this License and\n   any other pertinent obligations, then as a consequence you may not\n   distribute the Program at all.  For example, if a patent license would\n   not permit royalty-free redistribution of the Program by all those who\n   receive copies directly or indirectly through you, then the only way you\n   could satisfy both it and this License would be to refrain entirely from\n   distribution of the Program.\n\n   If any portion of this section is held invalid or unenforceable under any\n   particular circumstance, the balance of the section is intended to apply\n   and the section as a whole is intended to apply in other circumstances.\n\n   It is not the purpose of this section to induce you to infringe any\n   patents or other property right claims or to contest validity of any such\n   claims; this section has the sole purpose of protecting the integrity of\n   the free software distribution system, which is implemented by public\n   license practices.  Many people have made generous contributions to the\n   wide range of software distributed through that system in reliance on\n   consistent application of that system; it is up to the author/donor to\n   decide if he or she is willing to distribute software through any other\n   system and a licensee cannot impose that choice.\n\n   This section is intended to make thoroughly clear what is believed to be\n   a consequence of the rest of this License.\n\n8. If the distribution and/or use of the Program is restricted in certain\n   countries either by patents or by copyrighted interfaces, the original\n   copyright holder who places the Program under this License may add an\n   explicit geographical distribution limitation excluding those countries,\n   so that distribution is permitted only in or among countries not thus\n   excluded. In such case, this License incorporates the limitation as if\n   written in the body of this License.\n\n9. The Free Software Foundation may publish revised and/or new versions of\n   the General Public License from time to time.  Such new versions will be\n   similar in spirit to the present version, but may differ in detail to\n   address new problems or concerns.\n\n   Each version is given a distinguishing version number.  If the Program\n   specifies a version number of this License which applies to it and \"any\n   later version\", you have the option of following the terms and conditions\n   either of that version or of any later version published by the Free\n   Software Foundation.  If the Program does not specify a version number of\n   this License, you may choose any version ever published by the Free\n   Software Foundation.\n\n10. If you wish to incorporate parts of the Program into other free programs\n    whose distribution conditions are different, write to the author to ask\n    for permission.  For software which is copyrighted by the Free Software\n    Foundation, write to the Free Software Foundation; we sometimes make\n    exceptions for this.  Our decision will be guided by the two goals of\n    preserving the free status of all derivatives of our free software and\n    of promoting the sharing and reuse of software generally.\n\n                     NO WARRANTY\n\n11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR\n    THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n    PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER\n    EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE\n    ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH\n    YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL\n    NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR\n    DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL\n    DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM\n    (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED\n    INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF\n    THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR\n    OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/ChangeLog",
    "content": "= Net::LDAP Changelog\n\n== Net::LDAP 0.0.4: August 15, 2006\n* Undeprecated Net::LDAP#modify. Thanks to Justin Forder for\n  providing the rationale for this.\n* Added a much-expanded set of special characters to the parser\n  for RFC-2254 filters. Thanks to Andre Nathan.\n* Changed Net::LDAP#search so you can pass it a filter in string form.\n  The conversion to a Net::LDAP::Filter now happens automatically.\n* Implemented Net::LDAP#bind_as (preliminary and subject to change).\n  Thanks for Simon Claret for valuable suggestions and for helping test.\n* Fixed bug in Net::LDAP#open that was preventing #open from being\n  called more than one on a given Net::LDAP object.\n\n== Net::LDAP 0.0.3: July 26, 2006\n* Added simple TLS encryption.\n  Thanks to Garett Shulman for suggestions and for helping test.\n\n== Net::LDAP 0.0.2: July 12, 2006\n* Fixed malformation in distro tarball and gem.\n* Improved documentation.\n* Supported \"paged search control.\"\n* Added a range of API improvements.\n* Thanks to Andre Nathan, andre@digirati.com.br, for valuable\n  suggestions.\n* Added support for LE and GE search filters.\n* Added support for Search referrals.\n* Fixed a regression with openldap 2.2.x and higher caused\n  by the introduction of RFC-2696 controls. Thanks to Andre\n  Nathan for reporting the problem.\n* Added support for RFC-2254 filter syntax.\n\n== Net::LDAP 0.0.1: May 1, 2006\n* Initial release.\n* Client functionality is near-complete, although the APIs\n  are not guaranteed and may change depending on feedback\n  from the community.\n* We're internally working on a Ruby-based implementation\n  of a full-featured, production-quality LDAP server,\n  which will leverage the underlying LDAP and BER functionality\n  in Net::LDAP.\n* Please tell us if you would be interested in seeing a public\n  release of the LDAP server.\n* Grateful acknowledgement to Austin Ziegler, who reviewed\n  this code and provided the release framework, including\n  minitar.\n\n#--\n# Net::LDAP for Ruby.\n#   http://rubyforge.org/projects/net-ldap/\n#   Copyright (C) 2006 by Francis Cianfrocca\n#\n#   Available under the same terms as Ruby. See LICENCE in the main\n#   distribution for full licensing information.\n#\n# $Id: ChangeLog,v 1.17.2.4 2005/09/09 12:36:42 austin Exp $\n#++\n# vim: sts=2 sw=2 ts=4 et ai tw=77\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/LICENCE",
    "content": "Net::LDAP is copyrighted free software by Francis Cianfrocca\n<garbagecat10@gmail.com>. You can redistribute it and/or modify it under either\nthe terms of the GPL (see the file COPYING), or the conditions below:\n\n1. You may make and give away verbatim copies of the source form of the\n   software without restriction, provided that you duplicate all of the\n   original copyright notices and associated disclaimers.\n\n2. You may modify your copy of the software in any way, provided that you do\n   at least ONE of the following:\n\n   a) place your modifications in the Public Domain or otherwise make them\n      Freely Available, such as by posting said modifications to Usenet or\n      an equivalent medium, or by allowing the author to include your\n      modifications in the software.\n\n   b) use the modified software only within your corporation or\n      organization.\n\n   c) rename any non-standard executables so the names do not conflict with\n      standard executables, which must also be provided.\n\n   d) make other distribution arrangements with the author.\n\n3. You may distribute the software in object code or executable form,\n   provided that you do at least ONE of the following:\n\n   a) distribute the executables and library files of the software, together\n      with instructions (in the manual page or equivalent) on where to get\n      the original distribution.\n\n   b) accompany the distribution with the machine-readable source of the\n      software.\n\n   c) give non-standard executables non-standard names, with instructions on\n      where to get the original software distribution.\n\n   d) make other distribution arrangements with the author.\n\n4. You may modify and include the part of the software into any other\n   software (possibly commercial).  But some files in the distribution are\n   not written by the author, so that they are not under this terms.\n\n   They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some\n   files under the ./missing directory.  See each file for the copying\n   condition.\n\n5. The scripts and library files supplied as input to or produced as output\n   from the software do not automatically fall under the copyright of the\n   software, but belong to whomever generated them, and may be sold\n   commercially, and may be aggregated with this software.\n\n6. THIS SOFTWARE IS PROVIDED \"AS IS\" AND WITHOUT ANY EXPRESS OR IMPLIED\n   WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF\n   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/README",
    "content": "= Net::LDAP for Ruby\nNet::LDAP is an LDAP support library written in pure Ruby. It supports all\nLDAP client features, and a subset of server features as well.\n\nHomepage::  http://rubyforge.org/projects/net-ldap/\nCopyright:: (C) 2006 by Francis Cianfrocca\n\nOriginal developer: Francis Cianfrocca\nContributions by Austin Ziegler gratefully acknowledged.\n\n== LICENCE NOTES\nPlease read the file LICENCE for licensing restrictions on this library. In\nthe simplest terms, this library is available under the same terms as Ruby\nitself.\n\n== Requirements\nNet::LDAP requires Ruby 1.8.2 or better.\n\n== Documentation\nSee Net::LDAP for documentation and usage samples.\n\n#--\n# Net::LDAP for Ruby.\n#   http://rubyforge.org/projects/net-ldap/\n#   Copyright (C) 2006 by Francis Cianfrocca\n#\n#   Available under the same terms as Ruby. See LICENCE in the main\n#   distribution for full licensing information.\n#\n# $Id: README 141 2006-07-12 10:37:37Z blackhedd $\n#++\n# vim: sts=2 sw=2 ts=4 et ai tw=77\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/lib/net/ber.rb",
    "content": "# $Id: ber.rb 142 2006-07-26 12:20:33Z blackhedd $\n#\n# NET::BER\n# Mixes ASN.1/BER convenience methods into several standard classes.\n# Also provides BER parsing functionality.\n#\n#----------------------------------------------------------------------------\n#\n# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.\n#\n# Gmail: garbagecat10\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n#\n#---------------------------------------------------------------------------\n#\n#\n\n\n\n\nmodule Net\n\n  module BER\n\n  class BerError < Exception; end\n\n\n  # This module is for mixing into IO and IO-like objects.\n  module BERParser\n\n    # The order of these follows the class-codes in BER.\n    # Maybe this should have been a hash.\n    TagClasses = [:universal, :application, :context_specific, :private]\n\n    BuiltinSyntax = {\n      :universal => {\n        :primitive => {\n          1 => :boolean,\n          2 => :integer,\n          4 => :string,\n          10 => :integer,\n        },\n        :constructed => {\n          16 => :array,\n          17 => :array\n        }\n      }\n    }\n\n    #\n    # read_ber\n    # TODO: clean this up so it works properly with partial\n    # packets coming from streams that don't block when\n    # we ask for more data (like StringIOs). At it is,\n    # this can throw TypeErrors and other nasties.\n    #\n    def read_ber syntax=nil\n      return nil if (StringIO == self.class) and  eof?\n\n      id = getc  # don't trash this value, we'll use it later\n      tag = id & 31\n      tag < 31 or raise BerError.new( \"unsupported tag encoding: #{id}\" )\n      tagclass = TagClasses[ id >> 6 ]\n      encoding = (id & 0x20 != 0) ? :constructed : :primitive\n\n      n = getc\n      lengthlength,contentlength = if n <= 127\n        [1,n]\n      else\n        j = (0...(n & 127)).inject(0) {|mem,x| mem = (mem << 8) + getc}\n        [1 + (n & 127), j]\n      end\n\n      newobj = read contentlength\n\n      objtype = nil\n      [syntax, BuiltinSyntax].each {|syn|\n        if syn && (ot = syn[tagclass]) && (ot = ot[encoding]) && ot[tag]\n          objtype = ot[tag]\n          break\n        end\n      }\n      \n      obj = case objtype\n      when :boolean\n        newobj != \"\\000\"\n      when :string\n        (newobj || \"\").dup\n      when :integer\n        j = 0\n        newobj.each_byte {|b| j = (j << 8) + b}\n        j\n      when :array\n        seq = []\n        sio = StringIO.new( newobj || \"\" )\n        # Interpret the subobject, but note how the loop\n        # is built: nil ends the loop, but false (a valid\n        # BER value) does not!\n        while (e = sio.read_ber(syntax)) != nil\n          seq << e\n        end\n        seq\n      else\n        raise BerError.new( \"unsupported object type: class=#{tagclass}, encoding=#{encoding}, tag=#{tag}\" )\n      end\n\n      # Add the identifier bits into the object if it's a String or an Array.\n      # We can't add extra stuff to Fixnums and booleans, not that it makes much sense anyway.\n      obj and ([String,Array].include? obj.class) and obj.instance_eval \"def ber_identifier; #{id}; end\"\n      obj\n\n    end\n\n  end # module BERParser\n  end # module BER\n\nend # module Net\n\n\nclass IO\n  include Net::BER::BERParser\nend\n\nrequire \"stringio\"\nclass StringIO\n  include Net::BER::BERParser\nend\n\nbegin\n  require 'openssl'\n  class OpenSSL::SSL::SSLSocket\n    include Net::BER::BERParser\n  end\nrescue LoadError\n# Ignore LoadError.\n# DON'T ignore NameError, which means the SSLSocket class\n# is somehow unavailable on this implementation of Ruby's openssl.\n# This may be WRONG, however, because we don't yet know how Ruby's\n# openssl behaves on machines with no OpenSSL library. I suppose\n# it's possible they do not fail to require 'openssl' but do not\n# create the classes. So this code is provisional.\n# Also, you might think that OpenSSL::SSL::SSLSocket inherits from\n# IO so we'd pick it up above. But you'd be wrong.\nend\n\nclass String\n  def read_ber syntax=nil\n    StringIO.new(self).read_ber(syntax)\n  end\nend\n\n\n\n#----------------------------------------------\n\n\nclass FalseClass\n  #\n  # to_ber\n  #\n  def to_ber\n    \"\\001\\001\\000\"\n  end\nend\n\n\nclass TrueClass\n  #\n  # to_ber\n  #\n  def to_ber\n    \"\\001\\001\\001\"\n  end\nend\n\n\n\nclass Fixnum\n  #\n  # to_ber\n  #\n  def to_ber\n    i = [self].pack('w')\n    [2, i.length].pack(\"CC\") + i\n  end\n\n  #\n  # to_ber_enumerated\n  #\n  def to_ber_enumerated\n    i = [self].pack('w')\n    [10, i.length].pack(\"CC\") + i\n  end\n\n  #\n  # to_ber_length_encoding\n  #\n  def to_ber_length_encoding\n    if self <= 127\n      [self].pack('C')\n    else\n      i = [self].pack('N').sub(/^[\\0]+/,\"\")\n      [0x80 + i.length].pack('C') + i\n    end\n  end\n\nend # class Fixnum\n\n\nclass Bignum\n\n  def to_ber\n    i = [self].pack('w')\n    i.length > 126 and raise Net::BER::BerError.new( \"range error in bignum\" )\n    [2, i.length].pack(\"CC\") + i\n  end\n\nend\n\n\n\nclass String\n  #\n  # to_ber\n  # A universal octet-string is tag number 4,\n  # but others are possible depending on the context, so we\n  # let the caller give us one.\n  # The preferred way to do this in user code is via to_ber_application_sring\n  # and to_ber_contextspecific.\n  #\n  def to_ber code = 4\n    [code].pack('C') + length.to_ber_length_encoding + self\n  end\n\n  #\n  # to_ber_application_string\n  #\n  def to_ber_application_string code\n    to_ber( 0x40 + code )\n  end\n\n  #\n  # to_ber_contextspecific\n  #\n  def to_ber_contextspecific code\n    to_ber( 0x80 + code )\n  end\n\nend # class String\n\n\n\nclass Array\n  #\n  # to_ber_appsequence\n  # An application-specific sequence usually gets assigned\n  # a tag that is meaningful to the particular protocol being used.\n  # This is different from the universal sequence, which usually\n  # gets a tag value of 16.\n  # Now here's an interesting thing: We're adding the X.690\n  # \"application constructed\" code at the top of the tag byte (0x60),\n  # but some clients, notably ldapsearch, send \"context-specific\n  # constructed\" (0xA0). The latter would appear to violate RFC-1777,\n  # but what do I know? We may need to change this.\n  #\n\n  def to_ber                 id = 0; to_ber_seq_internal( 0x30 + id ); end\n  def to_ber_set             id = 0; to_ber_seq_internal( 0x31 + id ); end\n  def to_ber_sequence        id = 0; to_ber_seq_internal( 0x30 + id ); end\n  def to_ber_appsequence     id = 0; to_ber_seq_internal( 0x60 + id ); end\n  def to_ber_contextspecific id = 0; to_ber_seq_internal( 0xA0 + id ); end\n\n  private\n  def to_ber_seq_internal code\n    s = self.to_s\n    [code].pack('C') + s.length.to_ber_length_encoding + s\n  end\n\nend # class Array\n\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/lib/net/ldap/dataset.rb",
    "content": "# $Id: dataset.rb 78 2006-04-26 02:57:34Z blackhedd $\n#\n#\n#----------------------------------------------------------------------------\n#\n# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.\n#\n# Gmail: garbagecat10\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n#\n#---------------------------------------------------------------------------\n#\n#\n\n\n\n\nmodule Net\nclass LDAP\n\nclass Dataset < Hash\n\n  attr_reader :comments\n\n\n  def Dataset::read_ldif io\n    ds = Dataset.new\n\n    line = io.gets && chomp\n    dn = nil\n\n    while line\n      io.gets and chomp\n      if $_ =~ /^[\\s]+/\n        line << \" \" << $'\n      else\n        nextline = $_\n\n        if line =~ /^\\#/\n          ds.comments << line\n        elsif line =~ /^dn:[\\s]*/i\n          dn = $'\n          ds[dn] = Hash.new {|k,v| k[v] = []}\n        elsif line.length == 0\n          dn = nil\n        elsif line =~ /^([^:]+):([\\:]?)[\\s]*/\n          # $1 is the attribute name\n          # $2 is a colon iff the attr-value is base-64 encoded\n          # $' is the attr-value\n          # Avoid the Base64 class because not all Ruby versions have it.\n          attrvalue = ($2 == \":\") ? $'.unpack('m').shift : $'\n          ds[dn][$1.downcase.intern] << attrvalue\n        end\n\n        line = nextline\n      end\n    end\n  \n    ds\n  end\n\n\n  def initialize\n    @comments = []\n  end\n\n\n  def to_ldif\n    ary = []\n    ary += (@comments || [])\n\n    keys.sort.each {|dn|\n      ary << \"dn: #{dn}\"\n\n      self[dn].keys.map {|sym| sym.to_s}.sort.each {|attr|\n        self[dn][attr.intern].each {|val|\n          ary << \"#{attr}: #{val}\"\n        }\n      }\n\n      ary << \"\"\n    }\n\n    block_given? and ary.each {|line| yield line}\n\n    ary\n  end\n\n\nend # Dataset\n\nend # LDAP\nend # Net\n\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/lib/net/ldap/entry.rb",
    "content": "# $Id: entry.rb 123 2006-05-18 03:52:38Z blackhedd $\n#\n# LDAP Entry (search-result) support classes\n#\n#\n#----------------------------------------------------------------------------\n#\n# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.\n#\n# Gmail: garbagecat10\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n#\n#---------------------------------------------------------------------------\n#\n\n\n\n\nmodule Net\nclass LDAP\n\n\n  # Objects of this class represent individual entries in an LDAP\n  # directory. User code generally does not instantiate this class.\n  # Net::LDAP#search provides objects of this class to user code,\n  # either as block parameters or as return values.\n  #\n  # In LDAP-land, an \"entry\" is a collection of attributes that are\n  # uniquely and globally identified by a DN (\"Distinguished Name\").\n  # Attributes are identified by short, descriptive words or phrases.\n  # Although a directory is\n  # free to implement any attribute name, most of them follow rigorous\n  # standards so that the range of commonly-encountered attribute\n  # names is not large.\n  #\n  # An attribute name is case-insensitive. Most directories also\n  # restrict the range of characters allowed in attribute names.\n  # To simplify handling attribute names, Net::LDAP::Entry\n  # internally converts them to a standard format. Therefore, the\n  # methods which take attribute names can take Strings or Symbols,\n  # and work correctly regardless of case or capitalization.\n  #\n  # An attribute consists of zero or more data items called\n  # <i>values.</i> An entry is the combination of a unique DN, a set of attribute\n  # names, and a (possibly-empty) array of values for each attribute.\n  #\n  # Class Net::LDAP::Entry provides convenience methods for dealing\n  # with LDAP entries.\n  # In addition to the methods documented below, you may access individual\n  # attributes of an entry simply by giving the attribute name as\n  # the name of a method call. For example:\n  #  ldap.search( ... ) do |entry|\n  #    puts \"Common name: #{entry.cn}\"\n  #    puts \"Email addresses:\"\n  #      entry.mail.each {|ma| puts ma}\n  #  end\n  # If you use this technique to access an attribute that is not present\n  # in a particular Entry object, a NoMethodError exception will be raised.\n  #\n  #--\n  # Ugly problem to fix someday: We key off the internal hash with\n  # a canonical form of the attribute name: convert to a string,\n  # downcase, then take the symbol. Unfortunately we do this in\n  # at least three places. Should do it in ONE place.\n  class Entry\n\n    # This constructor is not generally called by user code.\n    def initialize dn = nil # :nodoc:\n      @myhash = Hash.new {|k,v| k[v] = [] }\n      @myhash[:dn] = [dn]\n    end\n\n\n    def []= name, value # :nodoc:\n      sym = name.to_s.downcase.intern\n      @myhash[sym] = value\n    end\n\n\n    #--\n    # We have to deal with this one as we do with []=\n    # because this one and not the other one gets called\n    # in formulations like entry[\"CN\"] << cn.\n    #\n    def [] name # :nodoc:\n      name = name.to_s.downcase.intern unless name.is_a?(Symbol)\n      @myhash[name]\n    end\n\n    # Returns the dn of the Entry as a String.\n    def dn\n      self[:dn][0]\n    end\n\n    # Returns an array of the attribute names present in the Entry.\n    def attribute_names\n      @myhash.keys\n    end\n\n    # Accesses each of the attributes present in the Entry.\n    # Calls a user-supplied block with each attribute in turn,\n    # passing two arguments to the block: a Symbol giving\n    # the name of the attribute, and a (possibly empty)\n    # Array of data values.\n    #\n    def each\n      if block_given?\n        attribute_names.each {|a|\n          attr_name,values = a,self[a]\n          yield attr_name, values\n        }\n      end\n    end\n\n    alias_method :each_attribute, :each\n\n\n    #--\n    # Convenience method to convert unknown method names\n    # to attribute references. Of course the method name\n    # comes to us as a symbol, so let's save a little time\n    # and not bother with the to_s.downcase two-step.\n    # Of course that means that a method name like mAIL\n    # won't work, but we shouldn't be encouraging that\n    # kind of bad behavior in the first place.\n    # Maybe we should thow something if the caller sends\n    # arguments or a block...\n    #\n    def method_missing *args, &block # :nodoc:\n      s = args[0].to_s.downcase.intern\n      if attribute_names.include?(s)\n        self[s]\n      elsif s.to_s[-1] == 61 and s.to_s.length > 1\n        value = args[1] or raise RuntimeError.new( \"unable to set value\" )\n        value = [value] unless value.is_a?(Array)\n        name = s.to_s[0..-2].intern\n        self[name] = value\n      else\n        raise NoMethodError.new( \"undefined method '#{s}'\" )\n      end\n    end\n\n    def write\n    end\n\n  end # class Entry\n\n\nend # class LDAP\nend # module Net\n\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/lib/net/ldap/filter.rb",
    "content": "# $Id: filter.rb 151 2006-08-15 08:34:53Z blackhedd $\n#\n#\n#----------------------------------------------------------------------------\n#\n# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.\n#\n# Gmail: garbagecat10\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n#\n#---------------------------------------------------------------------------\n#\n#\n\n\nmodule Net\nclass LDAP\n\n\n# Class Net::LDAP::Filter is used to constrain\n# LDAP searches. An object of this class is\n# passed to Net::LDAP#search in the parameter :filter.\n#\n# Net::LDAP::Filter supports the complete set of search filters\n# available in LDAP, including conjunction, disjunction and negation\n# (AND, OR, and NOT). This class supplants the (infamous) RFC-2254\n# standard notation for specifying LDAP search filters.\n#\n# Here's how to code the familiar \"objectclass is present\" filter:\n#  f = Net::LDAP::Filter.pres( \"objectclass\" )\n# The object returned by this code can be passed directly to\n# the <tt>:filter</tt> parameter of Net::LDAP#search.\n#\n# See the individual class and instance methods below for more examples.\n#\nclass Filter\n\n  def initialize op, a, b\n    @op = op\n    @left = a\n    @right = b\n  end\n\n  # #eq creates a filter object indicating that the value of\n  # a paticular attribute must be either <i>present</i> or must\n  # match a particular string.\n  #\n  # To specify that an attribute is \"present\" means that only\n  # directory entries which contain a value for the particular\n  # attribute will be selected by the filter. This is useful\n  # in case of optional attributes such as <tt>mail.</tt>\n  # Presence is indicated by giving the value \"*\" in the second\n  # parameter to #eq. This example selects only entries that have\n  # one or more values for <tt>sAMAccountName:</tt>\n  #  f = Net::LDAP::Filter.eq( \"sAMAccountName\", \"*\" )\n  #\n  # To match a particular range of values, pass a string as the\n  # second parameter to #eq. The string may contain one or more\n  # \"*\" characters as wildcards: these match zero or more occurrences\n  # of any character. Full regular-expressions are <i>not</i> supported\n  # due to limitations in the underlying LDAP protocol.\n  # This example selects any entry with a <tt>mail</tt> value containing\n  # the substring \"anderson\":\n  #  f = Net::LDAP::Filter.eq( \"mail\", \"*anderson*\" )\n  #--\n  # Removed gt and lt. They ain't in the standard!\n  #\n  def Filter::eq attribute, value; Filter.new :eq, attribute, value; end\n  def Filter::ne attribute, value; Filter.new :ne, attribute, value; end\n  #def Filter::gt attribute, value; Filter.new :gt, attribute, value; end\n  #def Filter::lt attribute, value; Filter.new :lt, attribute, value; end\n  def Filter::ge attribute, value; Filter.new :ge, attribute, value; end\n  def Filter::le attribute, value; Filter.new :le, attribute, value; end\n\n  # #pres( attribute ) is a synonym for #eq( attribute, \"*\" )\n  #\n  def Filter::pres attribute; Filter.eq attribute, \"*\"; end\n\n  # operator & (\"AND\") is used to conjoin two or more filters.\n  # This expression will select only entries that have an <tt>objectclass</tt>\n  # attribute AND have a <tt>mail</tt> attribute that begins with \"George\":\n  #  f = Net::LDAP::Filter.pres( \"objectclass\" ) & Net::LDAP::Filter.eq( \"mail\", \"George*\" )\n  #\n  def & filter; Filter.new :and, self, filter; end\n\n  # operator | (\"OR\") is used to disjoin two or more filters.\n  # This expression will select entries that have either an <tt>objectclass</tt>\n  # attribute OR a <tt>mail</tt> attribute that begins with \"George\":\n  #  f = Net::LDAP::Filter.pres( \"objectclass\" ) | Net::LDAP::Filter.eq( \"mail\", \"George*\" )\n  #\n  def | filter; Filter.new :or, self, filter; end\n\n\n  #\n  # operator ~ (\"NOT\") is used to negate a filter.\n  # This expression will select only entries that <i>do not</i> have an <tt>objectclass</tt>\n  # attribute:\n  #  f = ~ Net::LDAP::Filter.pres( \"objectclass\" )\n  #\n  #--\n  # This operator can't be !, evidently. Try it.\n  # Removed GT and LT. They're not in the RFC.\n  def ~@; Filter.new :not, self, nil; end\n\n\n  def to_s\n    case @op\n    when :ne\n      \"(!(#{@left}=#{@right}))\"\n    when :eq\n      \"(#{@left}=#{@right})\"\n    #when :gt\n     # \"#{@left}>#{@right}\"\n    #when :lt\n     # \"#{@left}<#{@right}\"\n    when :ge\n      \"#{@left}>=#{@right}\"\n    when :le\n      \"#{@left}<=#{@right}\"\n    when :and\n      \"(&(#{@left})(#{@right}))\"\n    when :or\n      \"(|(#{@left})(#{@right}))\"\n    when :not\n      \"(!(#{@left}))\"\n    else\n      raise \"invalid or unsupported operator in LDAP Filter\"\n    end\n  end\n\n\n  #--\n  # to_ber\n  # Filter ::=\n  #     CHOICE {\n  #         and            [0] SET OF Filter,\n  #         or             [1] SET OF Filter,\n  #         not            [2] Filter,\n  #         equalityMatch  [3] AttributeValueAssertion,\n  #         substrings     [4] SubstringFilter,\n  #         greaterOrEqual [5] AttributeValueAssertion,\n  #         lessOrEqual    [6] AttributeValueAssertion,\n  #         present        [7] AttributeType,\n  #         approxMatch    [8] AttributeValueAssertion\n  #     }\n  #\n  # SubstringFilter\n  #     SEQUENCE {\n  #         type               AttributeType,\n  #         SEQUENCE OF CHOICE {\n  #             initial        [0] LDAPString,\n  #             any            [1] LDAPString,\n  #             final          [2] LDAPString\n  #         }\n  #     }\n  #\n  # Parsing substrings is a little tricky.\n  # We use the split method to break a string into substrings\n  # delimited by the * (star) character. But we also need\n  # to know whether there is a star at the head and tail\n  # of the string. A Ruby particularity comes into play here:\n  # if you split on * and the first character of the string is\n  # a star, then split will return an array whose first element\n  # is an _empty_ string. But if the _last_ character of the\n  # string is star, then split will return an array that does\n  # _not_ add an empty string at the end. So we have to deal\n  # with all that specifically.\n  #\n  def to_ber\n    case @op\n    when :eq\n      if @right == \"*\"          # present\n        @left.to_s.to_ber_contextspecific 7\n      elsif @right =~ /[\\*]/    #substring\n        ary = @right.split( /[\\*]+/ )\n        final_star = @right =~ /[\\*]$/\n        initial_star = ary.first == \"\" and ary.shift\n\n        seq = []\n        unless initial_star\n          seq << ary.shift.to_ber_contextspecific(0)\n        end\n        n_any_strings = ary.length - (final_star ? 0 : 1)\n        #p n_any_strings\n        n_any_strings.times {\n          seq << ary.shift.to_ber_contextspecific(1)\n        }\n        unless final_star\n          seq << ary.shift.to_ber_contextspecific(2)\n        end\n        [@left.to_s.to_ber, seq.to_ber].to_ber_contextspecific 4\n      else                      #equality\n        [@left.to_s.to_ber, @right.to_ber].to_ber_contextspecific 3\n      end\n    when :ge\n      [@left.to_s.to_ber, @right.to_ber].to_ber_contextspecific 5\n    when :le\n      [@left.to_s.to_ber, @right.to_ber].to_ber_contextspecific 6\n    when :and\n      ary = [@left.coalesce(:and), @right.coalesce(:and)].flatten\n      ary.map {|a| a.to_ber}.to_ber_contextspecific( 0 )\n    when :or\n      ary = [@left.coalesce(:or), @right.coalesce(:or)].flatten\n      ary.map {|a| a.to_ber}.to_ber_contextspecific( 1 )\n    when :not\n        [@left.to_ber].to_ber_contextspecific 2\n    else\n      # ERROR, we'll return objectclass=* to keep things from blowing up,\n      # but that ain't a good answer and we need to kick out an error of some kind.\n      raise \"unimplemented search filter\"\n    end\n  end\n\n  #--\n  # coalesce\n  # This is a private helper method for dealing with chains of ANDs and ORs\n  # that are longer than two. If BOTH of our branches are of the specified\n  # type of joining operator, then return both of them as an array (calling\n  # coalesce recursively). If they're not, then return an array consisting\n  # only of self.\n  #\n  def coalesce operator\n    if @op == operator\n      [@left.coalesce( operator ), @right.coalesce( operator )]\n    else\n      [self]\n    end\n  end\n\n\n\n  #--\n  # We get a Ruby object which comes from parsing an RFC-1777 \"Filter\"\n  # object. Convert it to a Net::LDAP::Filter.\n  # TODO, we're hardcoding the RFC-1777 BER-encodings of the various\n  # filter types. Could pull them out into a constant.\n  #\n  def Filter::parse_ldap_filter obj\n    case obj.ber_identifier\n    when 0x87         # present. context-specific primitive 7.\n      Filter.eq( obj.to_s, \"*\" )\n    when 0xa3         # equalityMatch. context-specific constructed 3.\n      Filter.eq( obj[0], obj[1] )\n    else\n      raise LdapError.new( \"unknown ldap search-filter type: #{obj.ber_identifier}\" )\n    end\n  end\n\n\n  #--\n  # We got a hash of attribute values.\n  # Do we match the attributes?\n  # Return T/F, and call match recursively as necessary.\n  def match entry\n    case @op\n    when :eq\n      if @right == \"*\"\n        l = entry[@left] and l.length > 0\n      else\n        l = entry[@left] and l = l.to_a and l.index(@right)\n      end\n    else\n      raise LdapError.new( \"unknown filter type in match: #{@op}\" )\n    end\n  end\n\n  # Converts an LDAP filter-string (in the prefix syntax specified in RFC-2254)\n  # to a Net::LDAP::Filter.\n  def self.construct ldap_filter_string\n    FilterParser.new(ldap_filter_string).filter\n  end\n\n  # Synonym for #construct.\n  # to a Net::LDAP::Filter.\n  def self.from_rfc2254 ldap_filter_string\n    construct ldap_filter_string\n  end\n\nend # class Net::LDAP::Filter\n\n\n\nclass FilterParser #:nodoc:\n\n  attr_reader :filter\n\n  def initialize str\n    require 'strscan'\n    @filter = parse( StringScanner.new( str )) or raise Net::LDAP::LdapError.new( \"invalid filter syntax\" )\n  end\n\n  def parse scanner\n    parse_filter_branch(scanner) or parse_paren_expression(scanner)\n  end\n\n  def parse_paren_expression scanner\n    if scanner.scan(/\\s*\\(\\s*/)\n      b = if scanner.scan(/\\s*\\&\\s*/)\n        a = nil\n        branches = []\n        while br = parse_paren_expression(scanner)\n          branches << br\n        end\n        if branches.length >= 2\n          a = branches.shift\n          while branches.length > 0\n            a = a & branches.shift\n          end\n          a\n        end\n      elsif scanner.scan(/\\s*\\|\\s*/)\n        # TODO: DRY!\n        a = nil\n        branches = []\n        while br = parse_paren_expression(scanner)\n          branches << br\n        end\n        if branches.length >= 2\n          a = branches.shift\n          while branches.length > 0\n            a = a | branches.shift\n          end\n          a\n        end\n      elsif scanner.scan(/\\s*\\!\\s*/)\n        br = parse_paren_expression(scanner)\n        if br\n          ~ br\n        end\n      else\n        parse_filter_branch( scanner )\n      end\n\n      if b and scanner.scan( /\\s*\\)\\s*/ )\n        b\n      end\n    end\n  end\n\n  # Added a greatly-augmented filter contributed by Andre Nathan\n  # for detecting special characters in values. (15Aug06)\n  def parse_filter_branch scanner\n    scanner.scan(/\\s*/)\n    if token = scanner.scan( /[\\w\\-_]+/ )\n      scanner.scan(/\\s*/)\n      if op = scanner.scan( /\\=|\\<\\=|\\<|\\>\\=|\\>|\\!\\=/ )\n        scanner.scan(/\\s*/)\n        #if value = scanner.scan( /[\\w\\*\\.]+/ ) (ORG)\n        if value = scanner.scan( /[\\w\\*\\.\\+\\-@=#\\$%&!]+/ )\n          case op\n          when \"=\"\n            Filter.eq( token, value )\n          when \"!=\"\n            Filter.ne( token, value )\n          when \"<\"\n            Filter.lt( token, value )\n          when \"<=\"\n            Filter.le( token, value )\n          when \">\"\n            Filter.gt( token, value )\n          when \">=\"\n            Filter.ge( token, value )\n          end\n        end\n      end\n    end\n  end\n\nend # class Net::LDAP::FilterParser\n\nend # class Net::LDAP\nend # module Net\n\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/lib/net/ldap/pdu.rb",
    "content": "# $Id: pdu.rb 126 2006-05-31 15:55:16Z blackhedd $\n#\n# LDAP PDU support classes\n#\n#\n#----------------------------------------------------------------------------\n#\n# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.\n#\n# Gmail: garbagecat10\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n#\n#---------------------------------------------------------------------------\n#\n\n\n\nmodule Net\n\n\nclass LdapPduError < Exception; end\n\n\nclass LdapPdu\n\n  BindResult = 1\n  SearchReturnedData = 4\n  SearchResult = 5\n  ModifyResponse = 7\n  AddResponse = 9\n  DeleteResponse = 11\n  ModifyRDNResponse = 13\n  SearchResultReferral = 19\n\n  attr_reader :msg_id, :app_tag\n  attr_reader :search_dn, :search_attributes, :search_entry\n  attr_reader :search_referrals\n\n  #\n  # initialize\n  # An LDAP PDU always looks like a BerSequence with\n  # at least two elements: an integer (message-id number), and\n  # an application-specific sequence.\n  # Some LDAPv3 packets also include an optional\n  # third element, which is a sequence of \"controls\"\n  # (See RFC 2251, section 4.1.12).\n  # The application-specific tag in the sequence tells\n  # us what kind of packet it is, and each kind has its\n  # own format, defined in RFC-1777.\n  # Observe that many clients (such as ldapsearch)\n  # do not necessarily enforce the expected application\n  # tags on received protocol packets. This implementation\n  # does interpret the RFC strictly in this regard, and\n  # it remains to be seen whether there are servers out\n  # there that will not work well with our approach.\n  #\n  # Added a controls-processor to SearchResult.\n  # Didn't add it everywhere because it just _feels_\n  # like it will need to be refactored.\n  #\n  def initialize ber_object\n    begin\n      @msg_id = ber_object[0].to_i\n      @app_tag = ber_object[1].ber_identifier - 0x60\n    rescue\n      # any error becomes a data-format error\n      raise LdapPduError.new( \"ldap-pdu format error\" )\n    end\n\n    case @app_tag\n    when BindResult\n      parse_ldap_result ber_object[1]\n    when SearchReturnedData\n      parse_search_return ber_object[1]\n    when SearchResultReferral\n      parse_search_referral ber_object[1]\n    when SearchResult\n      parse_ldap_result ber_object[1]\n      parse_controls(ber_object[2]) if ber_object[2]\n    when ModifyResponse\n      parse_ldap_result ber_object[1]\n    when AddResponse\n      parse_ldap_result ber_object[1]\n    when DeleteResponse\n      parse_ldap_result ber_object[1]\n    when ModifyRDNResponse\n      parse_ldap_result ber_object[1]\n    else\n      raise LdapPduError.new( \"unknown pdu-type: #{@app_tag}\" )\n    end\n  end\n\n  #\n  # result_code\n  # This returns an LDAP result code taken from the PDU,\n  # but it will be nil if there wasn't a result code.\n  # That can easily happen depending on the type of packet.\n  #\n  def result_code code = :resultCode\n    @ldap_result and @ldap_result[code]\n  end\n\n  # Return RFC-2251 Controls if any.\n  # Messy. Does this functionality belong somewhere else?\n  def result_controls\n    @ldap_controls || []\n  end\n\n\n  #\n  # parse_ldap_result\n  #\n  def parse_ldap_result sequence\n    sequence.length >= 3 or raise LdapPduError\n    @ldap_result = {:resultCode => sequence[0], :matchedDN => sequence[1], :errorMessage => sequence[2]}\n  end\n  private :parse_ldap_result\n\n  #\n  # parse_search_return\n  # Definition from RFC 1777 (we're handling application-4 here)\n  #\n  # Search Response ::=\n  #    CHOICE {\n  #         entry          [APPLICATION 4] SEQUENCE {\n  #                             objectName     LDAPDN,\n  #                             attributes     SEQUENCE OF SEQUENCE {\n  #                                                 AttributeType,\n  #                                                 SET OF AttributeValue\n  #                                            }\n  #                        },\n  #         resultCode     [APPLICATION 5] LDAPResult\n  #     }\n  #\n  # We concoct a search response that is a hash of the returned attribute values.\n  # NOW OBSERVE CAREFULLY: WE ARE DOWNCASING THE RETURNED ATTRIBUTE NAMES.\n  # This is to make them more predictable for user programs, but it\n  # may not be a good idea. Maybe this should be configurable.\n  # ALTERNATE IMPLEMENTATION: In addition to @search_dn and @search_attributes,\n  # we also return @search_entry, which is an LDAP::Entry object.\n  # If that works out well, then we'll remove the first two.\n  #\n  # Provisionally removed obsolete search_attributes and search_dn, 04May06.\n  #\n  def parse_search_return sequence\n    sequence.length >= 2 or raise LdapPduError\n    @search_entry = LDAP::Entry.new( sequence[0] )\n    #@search_dn = sequence[0]\n    #@search_attributes = {}\n    sequence[1].each {|seq|\n      @search_entry[seq[0]] = seq[1]\n      #@search_attributes[seq[0].downcase.intern] = seq[1]\n    }\n  end\n\n  #\n  # A search referral is a sequence of one or more LDAP URIs.\n  # Any number of search-referral replies can be returned by the server, interspersed\n  # with normal replies in any order.\n  # Until I can think of a better way to do this, we'll return the referrals as an array.\n  # It'll be up to higher-level handlers to expose something reasonable to the client.\n  def parse_search_referral uris\n    @search_referrals = uris\n  end\n\n\n  # Per RFC 2251, an LDAP \"control\" is a sequence of tuples, each consisting\n  # of an OID, a boolean criticality flag defaulting FALSE, and an OPTIONAL\n  # Octet String. If only two fields are given, the second one may be\n  # either criticality or data, since criticality has a default value.\n  # Someday we may want to come back here and add support for some of\n  # more-widely used controls. RFC-2696 is a good example.\n  #\n  def parse_controls sequence\n    @ldap_controls = sequence.map do |control|\n      o = OpenStruct.new\n      o.oid,o.criticality,o.value = control[0],control[1],control[2]\n      if o.criticality and o.criticality.is_a?(String)\n        o.value = o.criticality\n        o.criticality = false\n      end\n      o\n    end\n  end\n  private :parse_controls\n\n\nend\n\n\nend # module Net\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/lib/net/ldap/psw.rb",
    "content": "# $Id: psw.rb 73 2006-04-24 21:59:35Z blackhedd $\n#\n#\n#----------------------------------------------------------------------------\n#\n# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.\n#\n# Gmail: garbagecat10\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n#\n#---------------------------------------------------------------------------\n#\n#\n\n\nmodule Net\nclass LDAP\n\n\nclass Password\n  class << self\n\n  # Generate a password-hash suitable for inclusion in an LDAP attribute.\n  # Pass a hash type (currently supported: :md5 and :sha) and a plaintext\n  # password. This function will return a hashed representation.\n  # STUB: This is here to fulfill the requirements of an RFC, which one?\n  # TODO, gotta do salted-sha and (maybe) salted-md5.\n  # Should we provide sha1 as a synonym for sha1? I vote no because then\n  # should you also provide ssha1 for symmetry?\n  def generate( type, str )\n    case type\n    when :md5\n      require 'md5'\n      \"{MD5}#{ [MD5.new( str.to_s ).digest].pack(\"m\").chomp }\"\n    when :sha\n      require 'sha1'\n      \"{SHA}#{ [SHA1.new( str.to_s ).digest].pack(\"m\").chomp }\"\n    # when ssha\n    else\n      raise Net::LDAP::LdapError.new( \"unsupported password-hash type (#{type})\" )\n    end\n  end\n\n  end\nend\n\n\nend # class LDAP\nend # module Net\n\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/lib/net/ldap.rb",
    "content": "# $Id: ldap.rb 154 2006-08-15 09:35:43Z blackhedd $\n#\n# Net::LDAP for Ruby\n#\n#\n# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.\n#\n# Written and maintained by Francis Cianfrocca, gmail: garbagecat10.\n#\n# This program is free software.\n# You may re-distribute and/or modify this program under the same terms\n# as Ruby itself: Ruby Distribution License or GNU General Public License.\n#\n#\n# See Net::LDAP for documentation and usage samples.\n#\n\n\nrequire 'socket'\nrequire 'ostruct'\n\nbegin\n  require 'openssl'\n  $net_ldap_openssl_available = true\nrescue LoadError\nend\n\nrequire 'net/ber'\nrequire 'net/ldap/pdu'\nrequire 'net/ldap/filter'\nrequire 'net/ldap/dataset'\nrequire 'net/ldap/psw'\nrequire 'net/ldap/entry'\n\n\nmodule Net\n\n\n  # == Net::LDAP\n  #\n  # This library provides a pure-Ruby implementation of the\n  # LDAP client protocol, per RFC-2251.\n  # It can be used to access any server which implements the\n  # LDAP protocol.\n  #\n  # Net::LDAP is intended to provide full LDAP functionality\n  # while hiding the more arcane aspects\n  # the LDAP protocol itself, and thus presenting as Ruby-like\n  # a programming interface as possible.\n  # \n  # == Quick-start for the Impatient\n  # === Quick Example of a user-authentication against an LDAP directory:\n  #\n  #  require 'rubygems'\n  #  require 'net/ldap'\n  #  \n  #  ldap = Net::LDAP.new\n  #  ldap.host = your_server_ip_address\n  #  ldap.port = 389\n  #  ldap.auth \"joe_user\", \"opensesame\"\n  #  if ldap.bind\n  #    # authentication succeeded\n  #  else\n  #    # authentication failed\n  #  end\n  #\n  #\n  # === Quick Example of a search against an LDAP directory:\n  #\n  #  require 'rubygems'\n  #  require 'net/ldap'\n  #  \n  #  ldap = Net::LDAP.new :host => server_ip_address,\n  #       :port => 389,\n  #       :auth => {\n  #             :method => :simple,\n  #             :username => \"cn=manager,dc=example,dc=com\",\n  #             :password => \"opensesame\"\n  #       }\n  #\n  #  filter = Net::LDAP::Filter.eq( \"cn\", \"George*\" )\n  #  treebase = \"dc=example,dc=com\"\n  #  \n  #  ldap.search( :base => treebase, :filter => filter ) do |entry|\n  #    puts \"DN: #{entry.dn}\"\n  #    entry.each do |attribute, values|\n  #      puts \"   #{attribute}:\"\n  #      values.each do |value|\n  #        puts \"      --->#{value}\"\n  #      end\n  #    end\n  #  end\n  #  \n  #  p ldap.get_operation_result\n  #  \n  #\n  # == A Brief Introduction to LDAP\n  #\n  # We're going to provide a quick, informal introduction to LDAP\n  # terminology and\n  # typical operations. If you're comfortable with this material, skip\n  # ahead to \"How to use Net::LDAP.\" If you want a more rigorous treatment\n  # of this material, we recommend you start with the various IETF and ITU\n  # standards that relate to LDAP.\n  #\n  # === Entities\n  # LDAP is an Internet-standard protocol used to access directory servers.\n  # The basic search unit is the <i>entity,</i> which corresponds to\n  # a person or other domain-specific object.\n  # A directory service which supports the LDAP protocol typically\n  # stores information about a number of entities.\n  #\n  # === Principals\n  # LDAP servers are typically used to access information about people,\n  # but also very often about such items as printers, computers, and other\n  # resources. To reflect this, LDAP uses the term <i>entity,</i> or less\n  # commonly, <i>user,</i> to denote its basic data-storage unit.\n  # \n  #\n  # === Distinguished Names\n  # In LDAP's view of the world,\n  # an entity is uniquely identified by a globally-unique text string\n  # called a <i>Distinguished Name,</i> originally defined in the X.400\n  # standards from which LDAP is ultimately derived.\n  # Much like a DNS hostname, a DN is a \"flattened\" text representation\n  # of a string of tree nodes. Also like DNS (and unlike Java package\n  # names), a DN expresses a chain of tree-nodes written from left to right\n  # in order from the most-resolved node to the most-general one.\n  #\n  # If you know the DN of a person or other entity, then you can query\n  # an LDAP-enabled directory for information (attributes) about the entity.\n  # Alternatively, you can query the directory for a list of DNs matching\n  # a set of criteria that you supply.\n  #\n  # === Attributes\n  #\n  # In the LDAP view of the world, a DN uniquely identifies an entity.\n  # Information about the entity is stored as a set of <i>Attributes.</i>\n  # An attribute is a text string which is associated with zero or more\n  # values. Most LDAP-enabled directories store a well-standardized\n  # range of attributes, and constrain their values according to standard\n  # rules.\n  #\n  # A good example of an attribute is <tt>sn,</tt> which stands for \"Surname.\"\n  # This attribute is generally used to store a person's surname, or last name.\n  # Most directories enforce the standard convention that\n  # an entity's <tt>sn</tt> attribute have <i>exactly one</i> value. In LDAP\n  # jargon, that means that <tt>sn</tt> must be <i>present</i> and\n  # <i>single-valued.</i>\n  #\n  # Another attribute is <tt>mail,</tt> which is used to store email addresses.\n  # (No, there is no attribute called \"email,\" perhaps because X.400 terminology\n  # predates the invention of the term <i>email.</i>) <tt>mail</tt> differs\n  # from <tt>sn</tt> in that most directories permit any number of values for the\n  # <tt>mail</tt> attribute, including zero.\n  #\n  #\n  # === Tree-Base\n  # We said above that X.400 Distinguished Names are <i>globally unique.</i>\n  # In a manner reminiscent of DNS, LDAP supposes that each directory server\n  # contains authoritative attribute data for a set of DNs corresponding\n  # to a specific sub-tree of the (notional) global directory tree.\n  # This subtree is generally configured into a directory server when it is\n  # created. It matters for this discussion because most servers will not\n  # allow you to query them unless you specify a correct tree-base.\n  #\n  # Let's say you work for the engineering department of Big Company, Inc.,\n  # whose internet domain is bigcompany.com. You may find that your departmental\n  # directory is stored in a server with a defined tree-base of\n  #  ou=engineering,dc=bigcompany,dc=com\n  # You will need to supply this string as the <i>tree-base</i> when querying this\n  # directory. (Ou is a very old X.400 term meaning \"organizational unit.\"\n  # Dc is a more recent term meaning \"domain component.\")\n  #\n  # === LDAP Versions\n  # (stub, discuss v2 and v3)\n  #\n  # === LDAP Operations\n  # The essential operations are: #bind, #search, #add, #modify, #delete, and #rename.\n  # ==== Bind\n  # #bind supplies a user's authentication credentials to a server, which in turn verifies\n  # or rejects them. There is a range of possibilities for credentials, but most directories\n  # support a simple username and password authentication.\n  #\n  # Taken by itself, #bind can be used to authenticate a user against information\n  # stored in a directory, for example to permit or deny access to some other resource.\n  # In terms of the other LDAP operations, most directories require a successful #bind to\n  # be performed before the other operations will be permitted. Some servers permit certain\n  # operations to be performed with an \"anonymous\" binding, meaning that no credentials are\n  # presented by the user. (We're glossing over a lot of platform-specific detail here.)\n  #\n  # ==== Search\n  # Calling #search against the directory involves specifying a treebase, a set of <i>search filters,</i>\n  # and a list of attribute values.\n  # The filters specify ranges of possible values for particular attributes. Multiple\n  # filters can be joined together with AND, OR, and NOT operators.\n  # A server will respond to a #search by returning a list of matching DNs together with a\n  # set of attribute values for each entity, depending on what attributes the search requested.\n  # \n  # ==== Add\n  # #add specifies a new DN and an initial set of attribute values. If the operation\n  # succeeds, a new entity with the corresponding DN and attributes is added to the directory.\n  #\n  # ==== Modify\n  # #modify specifies an entity DN, and a list of attribute operations. #modify is used to change\n  # the attribute values stored in the directory for a particular entity.\n  # #modify may add or delete attributes (which are lists of values) or it change attributes by\n  # adding to or deleting from their values.\n  # Net::LDAP provides three easier methods to modify an entry's attribute values:\n  # #add_attribute, #replace_attribute, and #delete_attribute.\n  #\n  # ==== Delete\n  # #delete specifies an entity DN. If it succeeds, the entity and all its attributes\n  # is removed from the directory.\n  #\n  # ==== Rename (or Modify RDN)\n  # #rename (or #modify_rdn) is an operation added to version 3 of the LDAP protocol. It responds to\n  # the often-arising need to change the DN of an entity without discarding its attribute values.\n  # In earlier LDAP versions, the only way to do this was to delete the whole entity and add it\n  # again with a different DN.\n  #\n  # #rename works by taking an \"old\" DN (the one to change) and a \"new RDN,\" which is the left-most\n  # part of the DN string. If successful, #rename changes the entity DN so that its left-most\n  # node corresponds to the new RDN given in the request. (RDN, or \"relative distinguished name,\"\n  # denotes a single tree-node as expressed in a DN, which is a chain of tree nodes.)\n  #\n  # == How to use Net::LDAP\n  #\n  # To access Net::LDAP functionality in your Ruby programs, start by requiring\n  # the library:\n  #\n  #  require 'net/ldap'\n  #\n  # If you installed the Gem version of Net::LDAP, and depending on your version of\n  # Ruby and rubygems, you _may_ also need to require rubygems explicitly:\n  #\n  #  require 'rubygems'\n  #  require 'net/ldap'\n  #\n  # Most operations with Net::LDAP start by instantiating a Net::LDAP object.\n  # The constructor for this object takes arguments specifying the network location\n  # (address and port) of the LDAP server, and also the binding (authentication)\n  # credentials, typically a username and password.\n  # Given an object of class Net:LDAP, you can then perform LDAP operations by calling\n  # instance methods on the object. These are documented with usage examples below.\n  #\n  # The Net::LDAP library is designed to be very disciplined about how it makes network\n  # connections to servers. This is different from many of the standard native-code\n  # libraries that are provided on most platforms, which share bloodlines with the\n  # original Netscape/Michigan LDAP client implementations. These libraries sought to\n  # insulate user code from the workings of the network. This is a good idea of course,\n  # but the practical effect has been confusing and many difficult bugs have been caused\n  # by the opacity of the native libraries, and their variable behavior across platforms.\n  #\n  # In general, Net::LDAP instance methods which invoke server operations make a connection\n  # to the server when the method is called. They execute the operation (typically binding first)\n  # and then disconnect from the server. The exception is Net::LDAP#open, which makes a connection\n  # to the server and then keeps it open while it executes a user-supplied block. Net::LDAP#open\n  # closes the connection on completion of the block.\n  #\n\n  class LDAP\n\n    class LdapError < Exception; end\n\n    VERSION = \"0.0.4\"\n\n\n    SearchScope_BaseObject = 0\n    SearchScope_SingleLevel = 1\n    SearchScope_WholeSubtree = 2\n    SearchScopes = [SearchScope_BaseObject, SearchScope_SingleLevel, SearchScope_WholeSubtree]\n\n    AsnSyntax = {\n      :application => {\n        :constructed => {\n          0 => :array,              # BindRequest\n          1 => :array,              # BindResponse\n          2 => :array,              # UnbindRequest\n          3 => :array,              # SearchRequest\n          4 => :array,              # SearchData\n          5 => :array,              # SearchResult\n          6 => :array,              # ModifyRequest\n          7 => :array,              # ModifyResponse\n          8 => :array,              # AddRequest\n          9 => :array,              # AddResponse\n          10 => :array,             # DelRequest\n          11 => :array,             # DelResponse\n          12 => :array,             # ModifyRdnRequest\n          13 => :array,             # ModifyRdnResponse\n          14 => :array,             # CompareRequest\n          15 => :array,             # CompareResponse\n          16 => :array,             # AbandonRequest\n          19 => :array,             # SearchResultReferral\n          24 => :array,             # Unsolicited Notification\n        }\n      },\n      :context_specific => {\n        :primitive => {\n          0 => :string,             # password\n          1 => :string,             # Kerberos v4\n          2 => :string,             # Kerberos v5\n        },\n        :constructed => {\n          0 => :array,              # RFC-2251 Control\n          3 => :array,              # Seach referral\n        }\n      }\n    }\n\n    DefaultHost = \"127.0.0.1\"\n    DefaultPort = 389\n    DefaultAuth = {:method => :anonymous}\n    DefaultTreebase = \"dc=com\"\n\n\n    ResultStrings = {\n      0 => \"Success\",\n      1 => \"Operations Error\",\n      2 => \"Protocol Error\",\n      3 => \"Time Limit Exceeded\",\n      4 => \"Size Limit Exceeded\",\n      12 => \"Unavailable crtical extension\",\n      16 => \"No Such Attribute\",\n      17 => \"Undefined Attribute Type\",\n      20 => \"Attribute or Value Exists\",\n      32 => \"No Such Object\",\n      34 => \"Invalid DN Syntax\",\n      48 => \"Invalid DN Syntax\",\n      48 => \"Inappropriate Authentication\",\n      49 => \"Invalid Credentials\",\n      50 => \"Insufficient Access Rights\",\n      51 => \"Busy\",\n      52 => \"Unavailable\",\n      53 => \"Unwilling to perform\",\n      65 => \"Object Class Violation\",\n      68 => \"Entry Already Exists\"\n    }\n\n\n    module LdapControls\n      PagedResults = \"1.2.840.113556.1.4.319\" # Microsoft evil from RFC 2696\n    end\n\n\n    #\n    # LDAP::result2string\n    #\n    def LDAP::result2string code # :nodoc:\n      ResultStrings[code] || \"unknown result (#{code})\"\n    end \n\n\n    attr_accessor :host, :port, :base\n\n\n    # Instantiate an object of type Net::LDAP to perform directory operations.\n    # This constructor takes a Hash containing arguments, all of which are either optional or may be specified later with other methods as described below. The following arguments\n    # are supported:\n    # * :host => the LDAP server's IP-address (default 127.0.0.1)\n    # * :port => the LDAP server's TCP port (default 389)\n    # * :auth => a Hash containing authorization parameters. Currently supported values include:\n    #   {:method => :anonymous} and\n    #   {:method => :simple, :username => your_user_name, :password => your_password }\n    #   The password parameter may be a Proc that returns a String.\n    # * :base => a default treebase parameter for searches performed against the LDAP server. If you don't give this value, then each call to #search must specify a treebase parameter. If you do give this value, then it will be used in subsequent calls to #search that do not specify a treebase. If you give a treebase value in any particular call to #search, that value will override any treebase value you give here.\n    # * :encryption => specifies the encryption to be used in communicating with the LDAP server. The value is either a Hash containing additional parameters, or the Symbol :simple_tls, which is equivalent to specifying the Hash {:method => :simple_tls}. There is a fairly large range of potential values that may be given for this parameter. See #encryption for details.\n    #\n    # Instantiating a Net::LDAP object does <i>not</i> result in network traffic to\n    # the LDAP server. It simply stores the connection and binding parameters in the\n    # object.\n    #\n    def initialize args = {}\n      @host = args[:host] || DefaultHost\n      @port = args[:port] || DefaultPort\n      @verbose = false # Make this configurable with a switch on the class.\n      @auth = args[:auth] || DefaultAuth\n      @base = args[:base] || DefaultTreebase\n      encryption args[:encryption] # may be nil\n\n      if pr = @auth[:password] and pr.respond_to?(:call)\n        @auth[:password] = pr.call\n      end\n\n      # This variable is only set when we are created with LDAP::open.\n      # All of our internal methods will connect using it, or else\n      # they will create their own.\n      @open_connection = nil\n    end\n\n    # Convenience method to specify authentication credentials to the LDAP\n    # server. Currently supports simple authentication requiring\n    # a username and password.\n    #\n    # Observe that on most LDAP servers,\n    # the username is a complete DN. However, with A/D, it's often possible\n    # to give only a user-name rather than a complete DN. In the latter\n    # case, beware that many A/D servers are configured to permit anonymous\n    # (uncredentialled) binding, and will silently accept your binding\n    # as anonymous if you give an unrecognized username. This is not usually\n    # what you want. (See #get_operation_result.)\n    #\n    # <b>Important:</b> The password argument may be a Proc that returns a string.\n    # This makes it possible for you to write client programs that solicit\n    # passwords from users or from other data sources without showing them\n    # in your code or on command lines.\n    #\n    #  require 'net/ldap'\n    #  \n    #  ldap = Net::LDAP.new\n    #  ldap.host = server_ip_address\n    #  ldap.authenticate \"cn=Your Username,cn=Users,dc=example,dc=com\", \"your_psw\"\n    #\n    # Alternatively (with a password block):\n    #\n    #  require 'net/ldap'\n    #  \n    #  ldap = Net::LDAP.new\n    #  ldap.host = server_ip_address\n    #  psw = proc { your_psw_function }\n    #  ldap.authenticate \"cn=Your Username,cn=Users,dc=example,dc=com\", psw\n    #\n    def authenticate username, password\n      password = password.call if password.respond_to?(:call)\n      @auth = {:method => :simple, :username => username, :password => password}\n    end\n\n    alias_method :auth, :authenticate\n\n    # Convenience method to specify encryption characteristics for connections\n    # to LDAP servers. Called implicitly by #new and #open, but may also be called\n    # by user code if desired.\n    # The single argument is generally a Hash (but see below for convenience alternatives).\n    # This implementation is currently a stub, supporting only a few encryption\n    # alternatives. As additional capabilities are added, more configuration values\n    # will be added here.\n    #\n    # Currently, the only supported argument is {:method => :simple_tls}.\n    # (Equivalently, you may pass the symbol :simple_tls all by itself, without\n    # enclosing it in a Hash.)\n    #\n    # The :simple_tls encryption method encrypts <i>all</i> communications with the LDAP\n    # server.\n    # It completely establishes SSL/TLS encryption with the LDAP server \n    # before any LDAP-protocol data is exchanged.\n    # There is no plaintext negotiation and no special encryption-request controls\n    # are sent to the server. \n    # <i>The :simple_tls option is the simplest, easiest way to encrypt communications\n    # between Net::LDAP and LDAP servers.</i>\n    # It's intended for cases where you have an implicit level of trust in the authenticity\n    # of the LDAP server. No validation of the LDAP server's SSL certificate is\n    # performed. This means that :simple_tls will not produce errors if the LDAP\n    # server's encryption certificate is not signed by a well-known Certification\n    # Authority.\n    # If you get communications or protocol errors when using this option, check\n    # with your LDAP server administrator. Pay particular attention to the TCP port\n    # you are connecting to. It's impossible for an LDAP server to support plaintext\n    # LDAP communications and <i>simple TLS</i> connections on the same port.\n    # The standard TCP port for unencrypted LDAP connections is 389, but the standard\n    # port for simple-TLS encrypted connections is 636. Be sure you are using the\n    # correct port.\n    #\n    # <i>[Note: a future version of Net::LDAP will support the STARTTLS LDAP control,\n    # which will enable encrypted communications on the same TCP port used for\n    # unencrypted connections.]</i>\n    #\n    def encryption args\n      if args == :simple_tls\n        args = {:method => :simple_tls}\n      end\n      @encryption = args\n    end\n\n\n    # #open takes the same parameters as #new. #open makes a network connection to the\n    # LDAP server and then passes a newly-created Net::LDAP object to the caller-supplied block.\n    # Within the block, you can call any of the instance methods of Net::LDAP to\n    # perform operations against the LDAP directory. #open will perform all the\n    # operations in the user-supplied block on the same network connection, which\n    # will be closed automatically when the block finishes.\n    #\n    #  # (PSEUDOCODE)\n    #  auth = {:method => :simple, :username => username, :password => password}\n    #  Net::LDAP.open( :host => ipaddress, :port => 389, :auth => auth ) do |ldap|\n    #    ldap.search( ... )\n    #    ldap.add( ... )\n    #    ldap.modify( ... )\n    #  end\n    #\n    def LDAP::open args\n      ldap1 = LDAP.new args\n      ldap1.open {|ldap| yield ldap }\n    end\n\n    # Returns a meaningful result any time after\n    # a protocol operation (#bind, #search, #add, #modify, #rename, #delete)\n    # has completed.\n    # It returns an #OpenStruct containing an LDAP result code (0 means success),\n    # and a human-readable string.\n    #  unless ldap.bind\n    #    puts \"Result: #{ldap.get_operation_result.code}\"\n    #    puts \"Message: #{ldap.get_operation_result.message}\"\n    #  end\n    #\n    def get_operation_result\n      os = OpenStruct.new\n      if @result\n        os.code = @result\n      else\n        os.code = 0\n      end\n      os.message = LDAP.result2string( os.code )\n      os\n    end\n\n\n    # Opens a network connection to the server and then\n    # passes <tt>self</tt> to the caller-supplied block. The connection is\n    # closed when the block completes. Used for executing multiple\n    # LDAP operations without requiring a separate network connection\n    # (and authentication) for each one.\n    # <i>Note:</i> You do not need to log-in or \"bind\" to the server. This will\n    # be done for you automatically.\n    # For an even simpler approach, see the class method Net::LDAP#open.\n    #\n    #  # (PSEUDOCODE)\n    #  auth = {:method => :simple, :username => username, :password => password}\n    #  ldap = Net::LDAP.new( :host => ipaddress, :port => 389, :auth => auth )\n    #  ldap.open do |ldap|\n    #    ldap.search( ... )\n    #    ldap.add( ... )\n    #    ldap.modify( ... )\n    #  end\n    #--\n    # First we make a connection and then a binding, but we don't\n    # do anything with the bind results.\n    # We then pass self to the caller's block, where he will execute\n    # his LDAP operations. Of course they will all generate auth failures\n    # if the bind was unsuccessful.\n    def open\n      raise LdapError.new( \"open already in progress\" ) if @open_connection\n      @open_connection = Connection.new( :host => @host, :port => @port, :encryption => @encryption )\n      @open_connection.bind @auth\n      yield self\n      @open_connection.close\n      @open_connection = nil\n    end\n\n\n    # Searches the LDAP directory for directory entries.\n    # Takes a hash argument with parameters. Supported parameters include:\n    # * :base (a string specifying the tree-base for the search);\n    # * :filter (an object of type Net::LDAP::Filter, defaults to objectclass=*);\n    # * :attributes (a string or array of strings specifying the LDAP attributes to return from the server);\n    # * :return_result (a boolean specifying whether to return a result set).\n    # * :attributes_only (a boolean flag, defaults false)\n    # * :scope (one of: Net::LDAP::SearchScope_BaseObject, Net::LDAP::SearchScope_SingleLevel, Net::LDAP::SearchScope_WholeSubtree. Default is WholeSubtree.)\n    #\n    # #search queries the LDAP server and passes <i>each entry</i> to the\n    # caller-supplied block, as an object of type Net::LDAP::Entry.\n    # If the search returns 1000 entries, the block will\n    # be called 1000 times. If the search returns no entries, the block will\n    # not be called.\n    #\n    #--\n    # ORIGINAL TEXT, replaced 04May06.\n    # #search returns either a result-set or a boolean, depending on the\n    # value of the <tt>:return_result</tt> argument. The default behavior is to return\n    # a result set, which is a hash. Each key in the hash is a string specifying\n    # the DN of an entry. The corresponding value for each key is a Net::LDAP::Entry object.\n    # If you request a result set and #search fails with an error, it will return nil.\n    # Call #get_operation_result to get the error information returned by\n    # the LDAP server.\n    #++\n    # #search returns either a result-set or a boolean, depending on the\n    # value of the <tt>:return_result</tt> argument. The default behavior is to return\n    # a result set, which is an Array of objects of class Net::LDAP::Entry.\n    # If you request a result set and #search fails with an error, it will return nil.\n    # Call #get_operation_result to get the error information returned by\n    # the LDAP server.\n    #\n    # When <tt>:return_result => false,</tt> #search will\n    # return only a Boolean, to indicate whether the operation succeeded. This can improve performance\n    # with very large result sets, because the library can discard each entry from memory after\n    # your block processes it.\n    #\n    #\n    #  treebase = \"dc=example,dc=com\"\n    #  filter = Net::LDAP::Filter.eq( \"mail\", \"a*.com\" )\n    #  attrs = [\"mail\", \"cn\", \"sn\", \"objectclass\"]\n    #  ldap.search( :base => treebase, :filter => filter, :attributes => attrs, :return_result => false ) do |entry|\n    #    puts \"DN: #{entry.dn}\"\n    #    entry.each do |attr, values|\n    #      puts \".......#{attr}:\"\n    #      values.each do |value|\n    #        puts \"          #{value}\"\n    #      end\n    #    end\n    #  end\n    #\n    #--\n    # This is a re-implementation of search that replaces the\n    # original one (now renamed searchx and possibly destined to go away).\n    # The difference is that we return a dataset (or nil) from the\n    # call, and pass _each entry_ as it is received from the server\n    # to the caller-supplied block. This will probably make things\n    # far faster as we can do useful work during the network latency\n    # of the search. The downside is that we have no access to the\n    # whole set while processing the blocks, so we can't do stuff\n    # like sort the DNs until after the call completes.\n    # It's also possible that this interacts badly with server timeouts.\n    # We'll have to ensure that something reasonable happens if\n    # the caller has processed half a result set when we throw a timeout\n    # error.\n    # Another important difference is that we return a result set from\n    # this method rather than a T/F indication.\n    # Since this can be very heavy-weight, we define an argument flag\n    # that the caller can set to suppress the return of a result set,\n    # if he's planning to process every entry as it comes from the server.\n    #\n    # REINTERPRETED the result set, 04May06. Originally this was a hash\n    # of entries keyed by DNs. But let's get away from making users\n    # handle DNs. Change it to a plain array. Eventually we may\n    # want to return a Dataset object that delegates to an internal\n    # array, so we can provide sort methods and what-not.\n    #\n    def search args = {}\n      args[:base] ||= @base\n      result_set = (args and args[:return_result] == false) ? nil : []\n\n      if @open_connection\n        @result = @open_connection.search( args ) {|entry|\n          result_set << entry if result_set\n          yield( entry ) if block_given?\n        }\n      else\n        @result = 0\n        conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption )\n        if (@result = conn.bind( args[:auth] || @auth )) == 0\n          @result = conn.search( args ) {|entry|\n            result_set << entry if result_set\n            yield( entry ) if block_given?\n          }\n        end\n        conn.close\n      end\n\n      @result == 0 and result_set\n    end\n\n    # #bind connects to an LDAP server and requests authentication\n    # based on the <tt>:auth</tt> parameter passed to #open or #new.\n    # It takes no parameters.\n    #\n    # User code does not need to call #bind directly. It will be called\n    # implicitly by the library whenever you invoke an LDAP operation,\n    # such as #search or #add.\n    #\n    # It is useful, however, to call #bind in your own code when the\n    # only operation you intend to perform against the directory is\n    # to validate a login credential. #bind returns true or false\n    # to indicate whether the binding was successful. Reasons for\n    # failure include malformed or unrecognized usernames and\n    # incorrect passwords. Use #get_operation_result to find out\n    # what happened in case of failure.\n    #\n    # Here's a typical example using #bind to authenticate a\n    # credential which was (perhaps) solicited from the user of a\n    # web site:\n    #\n    #  require 'net/ldap'\n    #  ldap = Net::LDAP.new\n    #  ldap.host = your_server_ip_address\n    #  ldap.port = 389\n    #  ldap.auth your_user_name, your_user_password\n    #  if ldap.bind\n    #    # authentication succeeded\n    #  else\n    #    # authentication failed\n    #    p ldap.get_operation_result\n    #  end\n    #\n    # You don't have to create a new instance of Net::LDAP every time\n    # you perform a binding in this way. If you prefer, you can cache the Net::LDAP object\n    # and re-use it to perform subsequent bindings, <i>provided</i> you call\n    # #auth to specify a new credential before calling #bind. Otherwise, you'll\n    # just re-authenticate the previous user! (You don't need to re-set\n    # the values of #host and #port.) As noted in the documentation for #auth,\n    # the password parameter can be a Ruby Proc instead of a String.\n    #\n    #--\n    # If there is an @open_connection, then perform the bind\n    # on it. Otherwise, connect, bind, and disconnect.\n    # The latter operation is obviously useful only as an auth check.\n    #\n    def bind auth=@auth\n      if @open_connection\n        @result = @open_connection.bind auth\n      else\n        conn = Connection.new( :host => @host, :port => @port , :encryption => @encryption)\n        @result = conn.bind @auth\n        conn.close\n      end\n\n      @result == 0\n    end\n\n    #\n    # #bind_as is for testing authentication credentials.\n    #\n    # As described under #bind, most LDAP servers require that you supply a complete DN\n    # as a binding-credential, along with an authenticator such as a password.\n    # But for many applications (such as authenticating users to a Rails application),\n    # you often don't have a full DN to identify the user. You usually get a simple\n    # identifier like a username or an email address, along with a password.\n    # #bind_as allows you to authenticate these user-identifiers.\n    #\n    # #bind_as is a combination of a search and an LDAP binding. First, it connects and\n    # binds to the directory as normal. Then it searches the directory for an entry\n    # corresponding to the email address, username, or other string that you supply.\n    # If the entry exists, then #bind_as will <b>re-bind</b> as that user with the\n    # password (or other authenticator) that you supply.\n    #\n    # #bind_as takes the same parameters as #search, <i>with the addition of an\n    # authenticator.</i> Currently, this authenticator must be <tt>:password</tt>.\n    # Its value may be either a String, or a +proc+ that returns a String.\n    # #bind_as returns +false+ on failure. On success, it returns a result set,\n    # just as #search does. This result set is an Array of objects of\n    # type Net::LDAP::Entry. It contains the directory attributes corresponding to\n    # the user. (Just test whether the return value is logically true, if you don't\n    # need this additional information.)\n    #\n    # Here's how you would use #bind_as to authenticate an email address and password:\n    #\n    #  require 'net/ldap'\n    #  \n    #  user,psw = \"joe_user@yourcompany.com\", \"joes_psw\"\n    #  \n    #  ldap = Net::LDAP.new\n    #  ldap.host = \"192.168.0.100\"\n    #  ldap.port = 389\n    #  ldap.auth \"cn=manager,dc=yourcompany,dc=com\", \"topsecret\"\n    #  \n    #  result = ldap.bind_as(\n    #    :base => \"dc=yourcompany,dc=com\",\n    #    :filter => \"(mail=#{user})\",\n    #    :password => psw\n    #  )\n    #  if result\n    #    puts \"Authenticated #{result.first.dn}\"\n    #  else\n    #    puts \"Authentication FAILED.\"\n    #  end\n    def bind_as args={}\n      result = false\n      open {|me|\n        rs = search args\n        if rs and rs.first and dn = rs.first.dn\n          password = args[:password]\n          password = password.call if password.respond_to?(:call)\n          result = rs if bind :method => :simple, :username => dn, :password => password\n        end\n      }\n      result\n    end\n\n\n    # Adds a new entry to the remote LDAP server.\n    # Supported arguments:\n    # :dn :: Full DN of the new entry\n    # :attributes :: Attributes of the new entry.\n    #\n    # The attributes argument is supplied as a Hash keyed by Strings or Symbols\n    # giving the attribute name, and mapping to Strings or Arrays of Strings\n    # giving the actual attribute values. Observe that most LDAP directories\n    # enforce schema constraints on the attributes contained in entries.\n    # #add will fail with a server-generated error if your attributes violate\n    # the server-specific constraints.\n    # Here's an example:\n    #\n    #  dn = \"cn=George Smith,ou=people,dc=example,dc=com\"\n    #  attr = {\n    #    :cn => \"George Smith\",\n    #    :objectclass => [\"top\", \"inetorgperson\"],\n    #    :sn => \"Smith\",\n    #    :mail => \"gsmith@example.com\"\n    #  }\n    #  Net::LDAP.open (:host => host) do |ldap|\n    #    ldap.add( :dn => dn, :attributes => attr )\n    #  end\n    #\n    def add args\n      if @open_connection\n          @result = @open_connection.add( args )\n      else\n        @result = 0\n        conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption)\n        if (@result = conn.bind( args[:auth] || @auth )) == 0\n          @result = conn.add( args )\n        end\n        conn.close\n      end\n      @result == 0\n    end\n\n\n    # Modifies the attribute values of a particular entry on the LDAP directory.\n    # Takes a hash with arguments. Supported arguments are:\n    # :dn :: (the full DN of the entry whose attributes are to be modified)\n    # :operations :: (the modifications to be performed, detailed next)\n    #\n    # This method returns True or False to indicate whether the operation\n    # succeeded or failed, with extended information available by calling\n    # #get_operation_result.\n    #\n    # Also see #add_attribute, #replace_attribute, or #delete_attribute, which\n    # provide simpler interfaces to this functionality.\n    #\n    # The LDAP protocol provides a full and well thought-out set of operations\n    # for changing the values of attributes, but they are necessarily somewhat complex\n    # and not always intuitive. If these instructions are confusing or incomplete,\n    # please send us email or create a bug report on rubyforge.\n    #\n    # The :operations parameter to #modify takes an array of operation-descriptors.\n    # Each individual operation is specified in one element of the array, and\n    # most LDAP servers will attempt to perform the operations in order.\n    #\n    # Each of the operations appearing in the Array must itself be an Array\n    # with exactly three elements:\n    # an operator:: must be :add, :replace, or :delete\n    # an attribute name:: the attribute name (string or symbol) to modify\n    # a value:: either a string or an array of strings.\n    #\n    # The :add operator will, unsurprisingly, add the specified values to\n    # the specified attribute. If the attribute does not already exist,\n    # :add will create it. Most LDAP servers will generate an error if you\n    # try to add a value that already exists.\n    #\n    # :replace will erase the current value(s) for the specified attribute,\n    # if there are any, and replace them with the specified value(s).\n    #\n    # :delete will remove the specified value(s) from the specified attribute.\n    # If you pass nil, an empty string, or an empty array as the value parameter\n    # to a :delete operation, the _entire_ _attribute_ will be deleted, along\n    # with all of its values.\n    #\n    # For example:\n    #\n    #  dn = \"mail=modifyme@example.com,ou=people,dc=example,dc=com\"\n    #  ops = [\n    #    [:add, :mail, \"aliasaddress@example.com\"],\n    #    [:replace, :mail, [\"newaddress@example.com\", \"newalias@example.com\"]],\n    #    [:delete, :sn, nil]\n    #  ]\n    #  ldap.modify :dn => dn, :operations => ops\n    #\n    # <i>(This example is contrived since you probably wouldn't add a mail\n    # value right before replacing the whole attribute, but it shows that order\n    # of execution matters. Also, many LDAP servers won't let you delete SN\n    # because that would be a schema violation.)</i>\n    #\n    # It's essential to keep in mind that if you specify more than one operation in\n    # a call to #modify, most LDAP servers will attempt to perform all of the operations\n    # in the order you gave them.\n    # This matters because you may specify operations on the\n    # same attribute which must be performed in a certain order.\n    #\n    # Most LDAP servers will _stop_ processing your modifications if one of them\n    # causes an error on the server (such as a schema-constraint violation).\n    # If this happens, you will probably get a result code from the server that\n    # reflects only the operation that failed, and you may or may not get extended\n    # information that will tell you which one failed. #modify has no notion\n    # of an atomic transaction. If you specify a chain of modifications in one\n    # call to #modify, and one of them fails, the preceding ones will usually\n    # not be \"rolled back,\" resulting in a partial update. This is a limitation\n    # of the LDAP protocol, not of Net::LDAP.\n    #\n    # The lack of transactional atomicity in LDAP means that you're usually\n    # better off using the convenience methods #add_attribute, #replace_attribute,\n    # and #delete_attribute, which are are wrappers over #modify. However, certain\n    # LDAP servers may provide concurrency semantics, in which the several operations\n    # contained in a single #modify call are not interleaved with other\n    # modification-requests received simultaneously by the server.\n    # It bears repeating that this concurrency does _not_ imply transactional\n    # atomicity, which LDAP does not provide.\n    #\n    def modify args\n      if @open_connection\n          @result = @open_connection.modify( args )\n      else\n        @result = 0\n        conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption )\n        if (@result = conn.bind( args[:auth] || @auth )) == 0\n          @result = conn.modify( args )\n        end\n        conn.close\n      end\n      @result == 0\n    end\n\n\n    # Add a value to an attribute.\n    # Takes the full DN of the entry to modify,\n    # the name (Symbol or String) of the attribute, and the value (String or\n    # Array). If the attribute does not exist (and there are no schema violations),\n    # #add_attribute will create it with the caller-specified values.\n    # If the attribute already exists (and there are no schema violations), the\n    # caller-specified values will be _added_ to the values already present.\n    #\n    # Returns True or False to indicate whether the operation\n    # succeeded or failed, with extended information available by calling\n    # #get_operation_result. See also #replace_attribute and #delete_attribute.\n    #\n    #  dn = \"cn=modifyme,dc=example,dc=com\"\n    #  ldap.add_attribute dn, :mail, \"newmailaddress@example.com\"\n    #\n    def add_attribute dn, attribute, value\n      modify :dn => dn, :operations => [[:add, attribute, value]]\n    end\n\n    # Replace the value of an attribute.\n    # #replace_attribute can be thought of as equivalent to calling #delete_attribute\n    # followed by #add_attribute. It takes the full DN of the entry to modify,\n    # the name (Symbol or String) of the attribute, and the value (String or\n    # Array). If the attribute does not exist, it will be created with the\n    # caller-specified value(s). If the attribute does exist, its values will be\n    # _discarded_ and replaced with the caller-specified values.\n    #\n    # Returns True or False to indicate whether the operation\n    # succeeded or failed, with extended information available by calling\n    # #get_operation_result. See also #add_attribute and #delete_attribute.\n    #\n    #  dn = \"cn=modifyme,dc=example,dc=com\"\n    #  ldap.replace_attribute dn, :mail, \"newmailaddress@example.com\"\n    #\n    def replace_attribute dn, attribute, value\n      modify :dn => dn, :operations => [[:replace, attribute, value]]\n    end\n\n    # Delete an attribute and all its values.\n    # Takes the full DN of the entry to modify, and the\n    # name (Symbol or String) of the attribute to delete.\n    #\n    # Returns True or False to indicate whether the operation\n    # succeeded or failed, with extended information available by calling\n    # #get_operation_result. See also #add_attribute and #replace_attribute.\n    #\n    #  dn = \"cn=modifyme,dc=example,dc=com\"\n    #  ldap.delete_attribute dn, :mail\n    #\n    def delete_attribute dn, attribute\n      modify :dn => dn, :operations => [[:delete, attribute, nil]]\n    end\n\n\n    # Rename an entry on the remote DIS by changing the last RDN of its DN.\n    # _Documentation_ _stub_\n    #\n    def rename args\n      if @open_connection\n          @result = @open_connection.rename( args )\n      else\n        @result = 0\n        conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption )\n        if (@result = conn.bind( args[:auth] || @auth )) == 0\n          @result = conn.rename( args )\n        end\n        conn.close\n      end\n      @result == 0\n    end\n\n    # modify_rdn is an alias for #rename.\n    def modify_rdn args\n      rename args\n    end\n\n    # Delete an entry from the LDAP directory.\n    # Takes a hash of arguments.\n    # The only supported argument is :dn, which must\n    # give the complete DN of the entry to be deleted.\n    # Returns True or False to indicate whether the delete\n    # succeeded. Extended status information is available by\n    # calling #get_operation_result.\n    #\n    #  dn = \"mail=deleteme@example.com,ou=people,dc=example,dc=com\"\n    #  ldap.delete :dn => dn\n    #\n    def delete args\n      if @open_connection\n          @result = @open_connection.delete( args )\n      else\n        @result = 0\n        conn = Connection.new( :host => @host, :port => @port, :encryption => @encryption )\n        if (@result = conn.bind( args[:auth] || @auth )) == 0\n          @result = conn.delete( args )\n        end\n        conn.close\n      end\n      @result == 0\n    end\n\n  end # class LDAP\n\n\n\n  class LDAP\n  # This is a private class used internally by the library. It should not be called by user code.\n  class Connection # :nodoc:\n\n    LdapVersion = 3\n\n\n    #--\n    # initialize\n    #\n    def initialize server\n      begin\n        @conn = TCPsocket.new( server[:host], server[:port] )\n      rescue\n        raise LdapError.new( \"no connection to server\" )\n      end\n\n      if server[:encryption]\n        setup_encryption server[:encryption]\n      end\n\n      yield self if block_given?\n    end\n\n\n    #--\n    # Helper method called only from new, and only after we have a successfully-opened\n    # @conn instance variable, which is a TCP connection.\n    # Depending on the received arguments, we establish SSL, potentially replacing\n    # the value of @conn accordingly.\n    # Don't generate any errors here if no encryption is requested.\n    # DO raise LdapError objects if encryption is requested and we have trouble setting\n    # it up. That includes if OpenSSL is not set up on the machine. (Question:\n    # how does the Ruby OpenSSL wrapper react in that case?)\n    # DO NOT filter exceptions raised by the OpenSSL library. Let them pass back\n    # to the user. That should make it easier for us to debug the problem reports.\n    # Presumably (hopefully?) that will also produce recognizable errors if someone\n    # tries to use this on a machine without OpenSSL.\n    #\n    # The simple_tls method is intended as the simplest, stupidest, easiest solution\n    # for people who want nothing more than encrypted comms with the LDAP server.\n    # It doesn't do any server-cert validation and requires nothing in the way\n    # of key files and root-cert files, etc etc.\n    # OBSERVE: WE REPLACE the value of @conn, which is presumed to be a connected\n    # TCPsocket object.\n    #\n    def setup_encryption args\n      case args[:method]\n      when :simple_tls\n        raise LdapError.new(\"openssl unavailable\") unless $net_ldap_openssl_available\n        ctx = OpenSSL::SSL::SSLContext.new\n        @conn = OpenSSL::SSL::SSLSocket.new(@conn, ctx)\n        @conn.connect\n        @conn.sync_close = true\n      # additional branches requiring server validation and peer certs, etc. go here.\n      else\n        raise LdapError.new( \"unsupported encryption method #{args[:method]}\" )\n      end\n    end\n\n    #--\n    # close\n    # This is provided as a convenience method to make\n    # sure a connection object gets closed without waiting\n    # for a GC to happen. Clients shouldn't have to call it,\n    # but perhaps it will come in handy someday.\n    def close\n      @conn.close\n      @conn = nil\n    end\n\n    #--\n    # next_msgid\n    #\n    def next_msgid\n      @msgid ||= 0\n      @msgid += 1\n    end\n\n\n    #--\n    # bind\n    #\n    def bind auth\n      user,psw = case auth[:method]\n      when :anonymous\n        [\"\",\"\"]\n      when :simple\n        [auth[:username] || auth[:dn], auth[:password]]\n      end\n      raise LdapError.new( \"invalid binding information\" ) unless (user && psw)\n\n      msgid = next_msgid.to_ber\n      request = [LdapVersion.to_ber, user.to_ber, psw.to_ber_contextspecific(0)].to_ber_appsequence(0)\n      request_pkt = [msgid, request].to_ber_sequence\n      @conn.write request_pkt\n\n      (be = @conn.read_ber(AsnSyntax) and pdu = Net::LdapPdu.new( be )) or raise LdapError.new( \"no bind result\" )\n      pdu.result_code\n    end\n\n    #--\n    # search\n    # Alternate implementation, this yields each search entry to the caller\n    # as it are received.\n    # TODO, certain search parameters are hardcoded.\n    # TODO, if we mis-parse the server results or the results are wrong, we can block\n    # forever. That's because we keep reading results until we get a type-5 packet,\n    # which might never come. We need to support the time-limit in the protocol.\n    #--\n    # WARNING: this code substantially recapitulates the searchx method.\n    #\n    # 02May06: Well, I added support for RFC-2696-style paged searches.\n    # This is used on all queries because the extension is marked non-critical.\n    # As far as I know, only A/D uses this, but it's required for A/D. Otherwise\n    # you won't get more than 1000 results back from a query.\n    # This implementation is kindof clunky and should probably be refactored.\n    # Also, is it my imagination, or are A/Ds the slowest directory servers ever???\n    #\n    def search args = {}\n      search_filter = (args && args[:filter]) || Filter.eq( \"objectclass\", \"*\" )\n      search_filter = Filter.construct(search_filter) if search_filter.is_a?(String)\n      search_base = (args && args[:base]) || \"dc=example,dc=com\"\n      search_attributes = ((args && args[:attributes]) || []).map {|attr| attr.to_s.to_ber}\n      return_referrals = args && args[:return_referrals] == true\n\n      attributes_only = (args and args[:attributes_only] == true)\n      scope = args[:scope] || Net::LDAP::SearchScope_WholeSubtree\n      raise LdapError.new( \"invalid search scope\" ) unless SearchScopes.include?(scope)\n\n      # An interesting value for the size limit would be close to A/D's built-in\n      # page limit of 1000 records, but openLDAP newer than version 2.2.0 chokes\n      # on anything bigger than 126. You get a silent error that is easily visible\n      # by running slapd in debug mode. Go figure.\n      rfc2696_cookie = [126, \"\"]\n      result_code = 0\n\n      loop {\n        # should collect this into a private helper to clarify the structure\n\n        request = [\n          search_base.to_ber,\n          scope.to_ber_enumerated,\n          0.to_ber_enumerated,\n          0.to_ber,\n          0.to_ber,\n          attributes_only.to_ber,\n          search_filter.to_ber,\n          search_attributes.to_ber_sequence\n        ].to_ber_appsequence(3)\n  \n        controls = [\n          [\n          LdapControls::PagedResults.to_ber,\n          false.to_ber, # criticality MUST be false to interoperate with normal LDAPs.\n          rfc2696_cookie.map{|v| v.to_ber}.to_ber_sequence.to_s.to_ber\n          ].to_ber_sequence\n        ].to_ber_contextspecific(0)\n\n        pkt = [next_msgid.to_ber, request, controls].to_ber_sequence\n        @conn.write pkt\n\n        result_code = 0\n        controls = []\n\n        while (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be ))\n          case pdu.app_tag\n          when 4 # search-data\n            yield( pdu.search_entry ) if block_given?\n          when 19 # search-referral\n            if return_referrals\n              if block_given?\n                se = Net::LDAP::Entry.new\n                se[:search_referrals] = (pdu.search_referrals || [])\n                yield se\n              end\n            end\n            #p pdu.referrals\n          when 5 # search-result\n            result_code = pdu.result_code\n            controls = pdu.result_controls\n            break\n          else\n            raise LdapError.new( \"invalid response-type in search: #{pdu.app_tag}\" )\n          end\n        end\n\n        # When we get here, we have seen a type-5 response.\n        # If there is no error AND there is an RFC-2696 cookie,\n        # then query again for the next page of results.\n        # If not, we're done.\n        # Don't screw this up or we'll break every search we do.\n        more_pages = false\n        if result_code == 0 and controls\n          controls.each do |c|\n            if c.oid == LdapControls::PagedResults\n              more_pages = false # just in case some bogus server sends us >1 of these.\n              if c.value and c.value.length > 0\n                cookie = c.value.read_ber[1]\n                if cookie and cookie.length > 0\n                  rfc2696_cookie[1] = cookie\n                  more_pages = true\n                end\n              end\n            end\n          end\n        end\n\n        break unless more_pages\n      } # loop\n\n      result_code\n    end\n\n\n\n\n    #--\n    # modify\n    # TODO, need to support a time limit, in case the server fails to respond.\n    # TODO!!! We're throwing an exception here on empty DN.\n    # Should return a proper error instead, probaby from farther up the chain.\n    # TODO!!! If the user specifies a bogus opcode, we'll throw a\n    # confusing error here (\"to_ber_enumerated is not defined on nil\").\n    #\n    def modify args\n      modify_dn = args[:dn] or raise \"Unable to modify empty DN\"\n      modify_ops = []\n      a = args[:operations] and a.each {|op, attr, values|\n        # TODO, fix the following line, which gives a bogus error\n        # if the opcode is invalid.\n        op_1 = {:add => 0, :delete => 1, :replace => 2} [op.to_sym].to_ber_enumerated\n        modify_ops << [op_1, [attr.to_s.to_ber, values.to_a.map {|v| v.to_ber}.to_ber_set].to_ber_sequence].to_ber_sequence\n      }\n\n      request = [modify_dn.to_ber, modify_ops.to_ber_sequence].to_ber_appsequence(6)\n      pkt = [next_msgid.to_ber, request].to_ber_sequence\n      @conn.write pkt\n\n      (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 7) or raise LdapError.new( \"response missing or invalid\" )\n      pdu.result_code\n    end\n\n\n    #--\n    # add\n    # TODO, need to support a time limit, in case the server fails to respond.\n    #\n    def add args\n      add_dn = args[:dn] or raise LdapError.new(\"Unable to add empty DN\")\n      add_attrs = []\n      a = args[:attributes] and a.each {|k,v|\n        add_attrs << [ k.to_s.to_ber, v.to_a.map {|m| m.to_ber}.to_ber_set ].to_ber_sequence\n      }\n\n      request = [add_dn.to_ber, add_attrs.to_ber_sequence].to_ber_appsequence(8)\n      pkt = [next_msgid.to_ber, request].to_ber_sequence\n      @conn.write pkt\n\n      (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 9) or raise LdapError.new( \"response missing or invalid\" )\n      pdu.result_code\n    end\n\n\n    #--\n    # rename\n    # TODO, need to support a time limit, in case the server fails to respond.\n    #\n    def rename args\n      old_dn = args[:olddn] or raise \"Unable to rename empty DN\"\n      new_rdn = args[:newrdn] or raise \"Unable to rename to empty RDN\"\n      delete_attrs = args[:delete_attributes] ? true : false\n\n      request = [old_dn.to_ber, new_rdn.to_ber, delete_attrs.to_ber].to_ber_appsequence(12)\n      pkt = [next_msgid.to_ber, request].to_ber_sequence\n      @conn.write pkt\n\n      (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 13) or raise LdapError.new( \"response missing or invalid\" )\n      pdu.result_code\n    end\n\n\n    #--\n    # delete\n    # TODO, need to support a time limit, in case the server fails to respond.\n    #\n    def delete args\n      dn = args[:dn] or raise \"Unable to delete empty DN\"\n\n      request = dn.to_s.to_ber_application_string(10)\n      pkt = [next_msgid.to_ber, request].to_ber_sequence\n      @conn.write pkt\n\n      (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 11) or raise LdapError.new( \"response missing or invalid\" )\n      pdu.result_code\n    end\n\n\n  end # class Connection\n  end # class LDAP\n\n\nend # module Net\n\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/lib/net/ldif.rb",
    "content": "# $Id: ldif.rb 78 2006-04-26 02:57:34Z blackhedd $\n#\n# Net::LDIF for Ruby\n#\n#\n#\n# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.\n#\n# Gmail: garbagecat10\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n#\n#\n\n# THIS FILE IS A STUB.\n\nmodule Net\n\n  class LDIF\n\n\n  end # class LDIF\n\n\nend # module Net\n\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/tests/testber.rb",
    "content": "# $Id: testber.rb 57 2006-04-18 00:18:48Z blackhedd $\n#\n#\n\n\n$:.unshift \"lib\"\n\nrequire 'net/ldap'\nrequire 'stringio'\n\n\nclass TestBer < Test::Unit::TestCase\n\n  def setup\n  end\n\n  # TODO: Add some much bigger numbers\n  # 5000000000 is a Bignum, which hits different code.\n  def test_ber_integers\n    assert_equal( \"\\002\\001\\005\", 5.to_ber )\n    assert_equal( \"\\002\\002\\203t\", 500.to_ber )\n    assert_equal( \"\\002\\003\\203\\206P\", 50000.to_ber )\n    assert_equal( \"\\002\\005\\222\\320\\227\\344\\000\", 5000000000.to_ber )\n  end\n\n  def test_ber_parsing\n    assert_equal( 6, \"\\002\\001\\006\".read_ber( Net::LDAP::AsnSyntax ))\n    assert_equal( \"testing\", \"\\004\\007testing\".read_ber( Net::LDAP::AsnSyntax ))\n  end\n\n\n  def test_ber_parser_on_ldap_bind_request\n    s = StringIO.new \"0$\\002\\001\\001`\\037\\002\\001\\003\\004\\rAdministrator\\200\\vad_is_bogus\"\n    assert_equal( [1, [3, \"Administrator\", \"ad_is_bogus\"]], s.read_ber( Net::LDAP::AsnSyntax ))\n  end\n\n\n\n\nend\n\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/tests/testdata.ldif",
    "content": "# $Id: testdata.ldif 50 2006-04-17 17:57:33Z blackhedd $\n#\n# This is test-data for an LDAP server in LDIF format.\n#\ndn: dc=bayshorenetworks,dc=com\nobjectClass: dcObject\nobjectClass: organization\no: Bayshore Networks LLC\ndc: bayshorenetworks\n\ndn: cn=Manager,dc=bayshorenetworks,dc=com\nobjectClass: organizationalrole\ncn: Manager\n\ndn: ou=people,dc=bayshorenetworks,dc=com\nobjectClass: organizationalunit\nou: people\n\ndn: ou=privileges,dc=bayshorenetworks,dc=com\nobjectClass: organizationalunit\nou: privileges\n\ndn: ou=roles,dc=bayshorenetworks,dc=com\nobjectClass: organizationalunit\nou: roles\n\ndn: ou=office,dc=bayshorenetworks,dc=com\nobjectClass: organizationalunit\nou: office\n\ndn: mail=nogoodnik@steamheat.net,ou=people,dc=bayshorenetworks,dc=com\ncn: Bob Fosse\nmail: nogoodnik@steamheat.net\nsn: Fosse\nou: people\nobjectClass: top\nobjectClass: inetorgperson\nobjectClass: authorizedperson\nhasAccessRole: uniqueIdentifier=engineer,ou=roles\nhasAccessRole: uniqueIdentifier=ldapadmin,ou=roles\nhasAccessRole: uniqueIdentifier=ldapsuperadmin,ou=roles\nhasAccessRole: uniqueIdentifier=ogilvy_elephant_user,ou=roles\nhasAccessRole: uniqueIdentifier=ogilvy_eagle_user,ou=roles\nhasAccessRole: uniqueIdentifier=greenplug_user,ou=roles\nhasAccessRole: uniqueIdentifier=brandplace_logging_user,ou=roles\nhasAccessRole: uniqueIdentifier=brandplace_report_user,ou=roles\nhasAccessRole: uniqueIdentifier=workorder_user,ou=roles\nhasAccessRole: uniqueIdentifier=bayshore_eagle_user,ou=roles\nhasAccessRole: uniqueIdentifier=bayshore_eagle_superuser,ou=roles\nhasAccessRole: uniqueIdentifier=kledaras_user,ou=roles\n\ndn: mail=elephant@steamheat.net,ou=people,dc=bayshorenetworks,dc=com\ncn: Gwen Verdon\nmail: elephant@steamheat.net\nsn: Verdon\nou: people\nobjectClass: top\nobjectClass: inetorgperson\nobjectClass: authorizedperson\nhasAccessRole: uniqueIdentifier=brandplace_report_user,ou=roles\nhasAccessRole: uniqueIdentifier=engineer,ou=roles\nhasAccessRole: uniqueIdentifier=ogilvy_elephant_user,ou=roles\nhasAccessRole: uniqueIdentifier=ldapsuperadmin,ou=roles\nhasAccessRole: uniqueIdentifier=ldapadmin,ou=roles\n\ndn: uniqueIdentifier=engineering,ou=privileges,dc=bayshorenetworks,dc=com\nuniqueIdentifier: engineering\nou: privileges\nobjectClass: accessPrivilege\n\ndn: uniqueIdentifier=engineer,ou=roles,dc=bayshorenetworks,dc=com\nuniqueIdentifier: engineer\nou: roles\nobjectClass: accessRole\nhasAccessPrivilege: uniqueIdentifier=engineering,ou=privileges\n\ndn: uniqueIdentifier=ldapadmin,ou=roles,dc=bayshorenetworks,dc=com\nuniqueIdentifier: ldapadmin\nou: roles\nobjectClass: accessRole\n\ndn: uniqueIdentifier=ldapsuperadmin,ou=roles,dc=bayshorenetworks,dc=com\nuniqueIdentifier: ldapsuperadmin\nou: roles\nobjectClass: accessRole\n\ndn: mail=catperson@steamheat.net,ou=people,dc=bayshorenetworks,dc=com\ncn: Sid Sorokin\nmail: catperson@steamheat.net\nsn: Sorokin\nou: people\nobjectClass: top\nobjectClass: inetorgperson\nobjectClass: authorizedperson\nhasAccessRole: uniqueIdentifier=engineer,ou=roles\nhasAccessRole: uniqueIdentifier=ogilvy_elephant_user,ou=roles\nhasAccessRole: uniqueIdentifier=ldapsuperadmin,ou=roles\nhasAccessRole: uniqueIdentifier=ogilvy_eagle_user,ou=roles\nhasAccessRole: uniqueIdentifier=greenplug_user,ou=roles\nhasAccessRole: uniqueIdentifier=workorder_user,ou=roles\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/tests/testem.rb",
    "content": "# $Id: testem.rb 121 2006-05-15 18:36:24Z blackhedd $\n#\n#\n\nrequire 'test/unit'\nrequire 'tests/testber'\nrequire 'tests/testldif'\nrequire 'tests/testldap'\nrequire 'tests/testpsw'\nrequire 'tests/testfilter'\n\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/tests/testfilter.rb",
    "content": "# $Id: testfilter.rb 122 2006-05-15 20:03:56Z blackhedd $\n#\n#\n\nrequire 'test/unit'\n\n$:.unshift \"lib\"\n\nrequire 'net/ldap'\n\n\nclass TestFilter < Test::Unit::TestCase\n\n  def setup\n  end\n\n\n  def teardown\n  end\n\n  def test_rfc_2254\n    p Net::LDAP::Filter.from_rfc2254( \" ( uid=george*   ) \" )\n    p Net::LDAP::Filter.from_rfc2254( \"uid!=george*\" )\n    p Net::LDAP::Filter.from_rfc2254( \"uid<george*\" )\n    p Net::LDAP::Filter.from_rfc2254( \"uid <= george*\" )\n    p Net::LDAP::Filter.from_rfc2254( \"uid>george*\" )\n    p Net::LDAP::Filter.from_rfc2254( \"uid>=george*\" )\n    p Net::LDAP::Filter.from_rfc2254( \"uid!=george*\" )\n\n    p Net::LDAP::Filter.from_rfc2254( \"(& (uid!=george* ) (mail=*))\" )\n    p Net::LDAP::Filter.from_rfc2254( \"(| (uid!=george* ) (mail=*))\" )\n    p Net::LDAP::Filter.from_rfc2254( \"(! (mail=*))\" )\n  end\n\n\nend\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/tests/testldap.rb",
    "content": "# $Id: testldap.rb 65 2006-04-23 01:17:49Z blackhedd $\n#\n#\n\n\n$:.unshift \"lib\"\n\nrequire 'test/unit'\n\nrequire 'net/ldap'\nrequire 'stringio'\n\n\nclass TestLdapClient < Test::Unit::TestCase\n\n  # TODO: these tests crash and burn if the associated\n  # LDAP testserver isn't up and running.\n  # We rely on being able to read a file with test data\n  # in LDIF format.\n  # TODO, WARNING: for the moment, this data is in a file\n  # whose name and location are HARDCODED into the\n  # instance method load_test_data.\n\n  def setup\n    @host = \"127.0.0.1\"\n    @port = 3890\n    @auth = {\n      :method => :simple,\n      :username => \"cn=bigshot,dc=bayshorenetworks,dc=com\",\n      :password => \"opensesame\"\n    }\n\n    @ldif = load_test_data\n  end\n\n\n\n  # Get some test data which will be used to validate\n  # the responses from the test LDAP server we will\n  # connect to.\n  # TODO, Bogus: we are HARDCODING the location of the file for now.\n  #\n  def load_test_data\n    ary = File.readlines( \"tests/testdata.ldif\" )\n    hash = {}\n    while line = ary.shift and line.chomp!\n      if line =~ /^dn:[\\s]*/i\n        dn = $'\n        hash[dn] = {}\n        while attr = ary.shift and attr.chomp! and attr =~ /^([\\w]+)[\\s]*:[\\s]*/\n          hash[dn][$1.downcase.intern] ||= []\n          hash[dn][$1.downcase.intern] << $'\n        end\n      end\n    end\n    hash\n  end\n\n\n\n  # Binding tests.\n  # Need tests for all kinds of network failures and incorrect auth.\n  # TODO: Implement a class-level timeout for operations like bind.\n  # Search has a timeout defined at the protocol level, other ops do not.\n  # TODO, use constants for the LDAP result codes, rather than hardcoding them.\n  def test_bind\n    ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth\n    assert_equal( true, ldap.bind )\n    assert_equal( 0, ldap.get_operation_result.code )\n    assert_equal( \"Success\", ldap.get_operation_result.message )\n\n    bad_username = @auth.merge( {:username => \"cn=badguy,dc=imposters,dc=com\"} )\n    ldap = Net::LDAP.new :host => @host, :port => @port, :auth => bad_username\n    assert_equal( false, ldap.bind )\n    assert_equal( 48, ldap.get_operation_result.code )\n    assert_equal( \"Inappropriate Authentication\", ldap.get_operation_result.message )\n\n    bad_password = @auth.merge( {:password => \"cornhusk\"} )\n    ldap = Net::LDAP.new :host => @host, :port => @port, :auth => bad_password\n    assert_equal( false, ldap.bind )\n    assert_equal( 49, ldap.get_operation_result.code )\n    assert_equal( \"Invalid Credentials\", ldap.get_operation_result.message )\n  end\n\n\n\n  def test_search\n    ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth\n\n    search = {:base => \"dc=smalldomain,dc=com\"}\n    assert_equal( false, ldap.search( search ))\n    assert_equal( 32, ldap.get_operation_result.code )\n    \n    search = {:base => \"dc=bayshorenetworks,dc=com\"}\n    assert_equal( true, ldap.search( search ))\n    assert_equal( 0, ldap.get_operation_result.code )\n    \n    ldap.search( search ) {|res|\n      assert_equal( res, @ldif )\n    }\n  end\n    \n\n\n\n  # This is a helper routine for test_search_attributes.\n  def internal_test_search_attributes attrs_to_search\n    ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth\n    assert( ldap.bind )\n\n    search = {\n      :base => \"dc=bayshorenetworks,dc=com\",\n      :attributes => attrs_to_search\n    }\n\n    ldif = @ldif\n    ldif.each {|dn,entry|\n      entry.delete_if {|attr,value|\n        ! attrs_to_search.include?(attr)\n      }\n    }\n  \n    assert_equal( true, ldap.search( search ))\n    ldap.search( search ) {|res|\n      res_keys = res.keys.sort\n      ldif_keys = ldif.keys.sort\n      assert( res_keys, ldif_keys )\n      res.keys.each {|rk|\n        assert( res[rk], ldif[rk] )\n      }\n    }\n  end\n\n\n  def test_search_attributes\n    internal_test_search_attributes [:mail]\n    internal_test_search_attributes [:cn]\n    internal_test_search_attributes [:ou]\n    internal_test_search_attributes [:hasaccessprivilege]\n    internal_test_search_attributes [\"mail\"]\n    internal_test_search_attributes [\"cn\"]\n    internal_test_search_attributes [\"ou\"]\n    internal_test_search_attributes [\"hasaccessrole\"]\n\n    internal_test_search_attributes [:mail, :cn, :ou, :hasaccessrole]\n    internal_test_search_attributes [:mail, \"cn\", :ou, \"hasaccessrole\"]\n  end\n\n\n  def test_search_filters\n    ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth\n    search = {\n      :base => \"dc=bayshorenetworks,dc=com\",\n      :filter => Net::LDAP::Filter.eq( \"sn\", \"Fosse\" )\n    }\n\n    ldap.search( search ) {|res|\n      p res\n    }\n  end\n\n\n\n  def test_open\n    ldap = Net::LDAP.new :host => @host, :port => @port, :auth => @auth\n    ldap.open {|ldap|\n      10.times {\n        rc = ldap.search( :base => \"dc=bayshorenetworks,dc=com\" )\n        assert_equal( true, rc )\n      }\n    }\n  end\n\n\n  def test_ldap_open\n    Net::LDAP.open( :host => @host, :port => @port, :auth => @auth ) {|ldap|\n      10.times {\n        rc = ldap.search( :base => \"dc=bayshorenetworks,dc=com\" )\n        assert_equal( true, rc )\n      }\n    }\n  end\n\n\n\n\n\nend\n\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/tests/testldif.rb",
    "content": "# $Id: testldif.rb 61 2006-04-18 20:55:55Z blackhedd $\n#\n#\n\n\n$:.unshift \"lib\"\n\nrequire 'test/unit'\n\nrequire 'net/ldap'\nrequire 'net/ldif'\n\nrequire 'sha1'\nrequire 'base64'\n\nclass TestLdif < Test::Unit::TestCase\n\n  TestLdifFilename = \"tests/testdata.ldif\"\n\n  def test_empty_ldif\n    ds = Net::LDAP::Dataset::read_ldif( StringIO.new )\n    assert_equal( true, ds.empty? )\n  end\n\n  def test_ldif_with_comments\n    str = [\"# Hello from LDIF-land\", \"# This is an unterminated comment\"]\n    io = StringIO.new( str[0] + \"\\r\\n\" + str[1] )\n    ds = Net::LDAP::Dataset::read_ldif( io )\n    assert_equal( str, ds.comments )\n  end\n\n  def test_ldif_with_password\n    psw = \"goldbricks\"\n    hashed_psw = \"{SHA}\" + Base64::encode64( SHA1.new(psw).digest ).chomp\n\n    ldif_encoded = Base64::encode64( hashed_psw ).chomp\n    ds = Net::LDAP::Dataset::read_ldif( StringIO.new( \"dn: Goldbrick\\r\\nuserPassword:: #{ldif_encoded}\\r\\n\\r\\n\" ))\n    recovered_psw = ds[\"Goldbrick\"][:userpassword].shift\n    assert_equal( hashed_psw, recovered_psw )\n  end\n\n  def test_ldif_with_continuation_lines\n    ds = Net::LDAP::Dataset::read_ldif( StringIO.new( \"dn: abcdefg\\r\\n   hijklmn\\r\\n\\r\\n\" ))\n    assert_equal( true, ds.has_key?( \"abcdefg hijklmn\" ))\n  end\n\n  # TODO, INADEQUATE. We need some more tests\n  # to verify the content.\n  def test_ldif\n    File.open( TestLdifFilename, \"r\" ) {|f|\n      ds = Net::LDAP::Dataset::read_ldif( f )\n      assert_equal( 13, ds.length )\n    }\n  end\n\n  # TODO, need some tests.\n  # Must test folded lines and base64-encoded lines as well as normal ones.\n  def test_to_ldif\n    File.open( TestLdifFilename, \"r\" ) {|f|\n      ds = Net::LDAP::Dataset::read_ldif( f )\n      ds.to_ldif\n      assert_equal( true, false ) # REMOVE WHEN WE HAVE SOME TESTS HERE.\n    }\n  end\n\n\nend\n\n\n"
  },
  {
    "path": "vendor/plugins/ruby-net-ldap-0.0.4/tests/testpsw.rb",
    "content": "# $Id: testpsw.rb 72 2006-04-24 21:58:14Z blackhedd $\n#\n#\n\n\n$:.unshift \"lib\"\n\nrequire 'net/ldap'\nrequire 'stringio'\n\n\nclass TestPassword < Test::Unit::TestCase\n\n  def setup\n  end\n\n\n  def test_psw\n    assert_equal( \"{MD5}xq8jwrcfibi0sZdZYNkSng==\", Net::LDAP::Password.generate( :md5, \"cashflow\" ))\n    assert_equal( \"{SHA}YE4eGkN4BvwNN1f5R7CZz0kFn14=\", Net::LDAP::Password.generate( :sha, \"cashflow\" ))\n  end\n\n\n\n\nend\n\n\n"
  },
  {
    "path": "vendor/plugins/seed_dump/CHANGELOG.rdoc",
    "content": ""
  },
  {
    "path": "vendor/plugins/seed_dump/MIT-LICENSE",
    "content": "Copyright (c) 2010 Rob Halff\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "vendor/plugins/seed_dump/README.rdoc",
    "content": "= SeedDump\n\nSeed dump is a simple plugin that adds a rake task named db:seed:dump.\n\nIt allows you to create a db/seeds.rb from your existing data in the database.\nWhen there is no data in the database it will generate empty create statements.\n\nIt mainly exists for people who are too lazy writing create statements in db/seeds.rb themselves\nand need something (+seed_dump+) to dump data from the table(s) into seeds.rb\n\n== Example Usage\n\nDump all data directly to db/seeds.rb:\n\n  rake db:seed:dump\n\nDump only data from the users and products table and dump a maximum amount of 10 records:\n\n  $ rake db:seed:dump MODELS=User,Product LIMIT=2\n\nResult:\n\n  $ cat db/seeds.rb \n  # Autogenerated by the db:seed:dump task\n  # Do not hesitate to tweak this to your needs\n\n  products = Product.create([\n    { :category_id => 1, :description => \"Long Sleeve Shirt\", :name => \"Long Sleeve Shirt\" },\n    { :category_id => 3, :description => \"Plain White Tee Shirt\", :name => \"Plain T-Shirt\" }\n  ])\n\n  users = User.create([\n    { :id => 1, :password => \"123456\", :username => \"test_1\" },\n    { :id => 2, :password => \"234567\", :username => \"tes2\" }\n  ])\n\nAppend to db/seeds.rb instead of overwriting it:\n\n  rake db:seed:dump APPEND=true\n\nUse another output file instead of db/seeds.rb\n\n  rake db:seed:dump FILE=db/categories.rb\n\nBy default the :id column will not be added to the generated Create statements\nIf you do want the :id to be included use WITH_ID:\n\n  rake db:seed:dump WITH_ID=1\n\nIf you don't want +seed_dump+ to dump any data allready available in the database use NO_DATA.\n\nThis will generate the dump with only 1 empty create statement.\nIt's up to you to edit these and change the values into something meaningful:\n\n  rake db:seed:dump MODEL=User NO_DATA=1 APPEND=true \n\nHere is a full example using all of the options above:\n\n  rake db:seed:dump MODELS=Category LIMIT=10 APPEND=true FILE=db/categories.rb WITH_ID=1 NO_DATA=1\n\n== All environment variables\n\nAPPEND:\n Append the data to db/seeds.rb instead of overwriting it.\n\nFILE:\n Use a different output file, default: db/seeds.rb\n\nLIMIT:\n Dump no more then this amount of data, default: no limit\n\nMODEL(S):\n A model name or a comma seperated list of models, default: all models\n\nNO_DATA:\n Don't dump any data from the db, instead generate empty Create options \n\nWITH_ID:\n Inlcude the +:id+ in the create options\n\n== Note on Patches/Pull Requests\n \n* Fork the project.\n* Make your feature addition or bug fix.\n* Add tests for it. This is important so I don't break it in a\n  future version unintentionally.\n* Commit, do not mess with rakefile, version, or history.\n  (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)\n* Send me a pull request. Bonus points for topic branches.\n\nCopyright (c) 2010 Rob Halff, released under the MIT license\n"
  },
  {
    "path": "vendor/plugins/seed_dump/Rakefile",
    "content": "require 'rubygems'\nrequire 'rake'\n\nbegin\n  require 'jeweler'\n  Jeweler::Tasks.new do |gem|\n    gem.name = \"seed_dump\"\n    gem.summary = \"{Seed Dumper for Rails}\"\n    gem.description = %Q{Dump (parts) of your database to db/seeds.rb to get a headstart creating a meaningful seeds.rb file}\n    gem.email = \"rob.halff@gmail.com\"\n    gem.homepage = \"http://github.com/rhalff/seed_dump\"\n    gem.authors = [\"Rob Halff\"]\n  end\n  Jeweler::GemcutterTasks.new\nrescue LoadError\n  puts \"Jeweler (or a dependency) not available. Install it with: gem install jeweler\"\nend\n\nrequire 'rake/testtask'\nRake::TestTask.new(:test) do |test|\n  test.libs << 'lib' << 'test'\n  test.pattern = 'test/**/test_*.rb'\n  test.verbose = true\nend\n\nbegin\n  require 'rcov/rcovtask'\n  Rcov::RcovTask.new do |test|\n    test.libs << 'test'\n    test.pattern = 'test/**/test_*.rb'\n    test.verbose = true\n  end\nrescue LoadError\n  task :rcov do\n    abort \"RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov\"\n  end\nend\n\ntask :test => :check_dependencies\n\ntask :default => :test\n\nrequire 'rake/rdoctask'\nRake::RDocTask.new do |rdoc|\n  version = File.exist?('VERSION') ? File.read('VERSION') : \"\"\n\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title = \"seed_dump #{version}\"\n  rdoc.rdoc_files.include('README*')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n"
  },
  {
    "path": "vendor/plugins/seed_dump/VERSION",
    "content": "0.2.2\n"
  },
  {
    "path": "vendor/plugins/seed_dump/lib/seed_dump/railtie.rb",
    "content": "module SeedDump \n  class Railtie < Rails::Railtie\n\n    rake_tasks do\n      load \"tasks/seed_dump.rake\"\n    end \n\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/seed_dump/lib/seed_dump.rb",
    "content": "# SeedDump\nmodule SeedDump \n  require 'seed_dump/railtie' if defined?(Rails)\nend\n"
  },
  {
    "path": "vendor/plugins/seed_dump/lib/tasks/seed_dump.rake",
    "content": "namespace :db do\n  namespace :seed  do\n    desc \"Dump records from the database into db/seeds.rb\"\n    task :dump => :environment do\n\n      # config\n      opts = {}\n      opts['with_id'] = !ENV[\"WITH_ID\"].nil?\n      opts['no-data'] = !ENV['NO_DATA'].nil?\n      opts['models']  = ENV['MODELS'] || (ENV['MODEL'] ? ENV['MODEL'] : \"\")\n      opts['file']    = ENV['FILE'] || \"#{Rails.root}/db/seeds.rb\"\n      opts['append']  = (!ENV['APPEND'].nil? && File.exists?(opts['file']) )\n      ar_options      = ENV['LIMIT'].to_i > 0 ? { :limit => ENV['LIMIT'].to_i } : {}\n      indent          = \" \" * (ENV['INDENT'].nil? ? 2 : ENV['INDENT'].to_i)\n\n      models = opts['models'].split(',').collect {|x| x.underscore.singularize }\n\n      new_line = \"\\n\"\n\n      puts \"Appending seeds to #{opts['file']}.\" if opts['append']\n\n      seed_rb = \"\"\n      \n      if models\n        models.each do |model_name|\n\t        begin\n            puts \"Adding #{model_name.camelize} seeds.\"\n\n\t          create_hash = \"\"\n\n\t          model = model_name.camelize.constantize\n\t          arr = []\n\t          next unless defined? model.find\n            seed_rb << \"#{new_line}puts \\\"#{model_name.camelize}...\\\"\"\n            seed_rb << \"#{new_line}#{model_name.camelize}.delete_all\" unless opts['append']\n            \n\t          arr = model.find(:all, ar_options) unless opts['no-data'] \n        \t  arr = arr.empty? ? [model.new] : arr\n        \t  arr.each_with_index { |r,i| \n\n              attr_s = [];\n\n              r.attributes.each { |k,v|\n  \t            v = (v.class == Time || v.class == Date) ? \"\\\"#{v}\\\"\" : v.inspect\n                attr_s.push(\"#{k.to_sym.inspect} => #{v}\") unless k == 'id' && !opts['with_id']\n              }\n\n              create_hash << (i > 0 ? \",#{new_line}\" : new_line) << indent << '{ ' << attr_s.join(', ') << ' }'\n            } \n\n            seed_rb << \"#{new_line}#{model_name.pluralize} = #{model_name.camelize}.create([#{create_hash}#{new_line}])#{new_line}\"\n          rescue Exception => e\n            puts \"Exception ignored....#{e.inspect}\"\n          end\n        end\n            # begin\n            # \n            #               puts \"Adding #{model_name.camelize} seeds...\"\n            # \n            #   create_hash = \"\"\n            # \n            #   model = model_name.camelize.constantize\n            #   arr = []\n            #   next unless defined? model.find\n            #               seed_rb << \"#{new_line}puts \\\"#{model_name.camelize}\\\"...\"\n            #               seed_rb << \"#{new_line}#{model_name.camelize}.delete_all\" unless opts['append']\n            #               seed_rb << \"#{new_line}#{model_name.camelize}.protected_attributes.clear\"\n            #   \n            #   arr = model.find(:all, ar_options) unless opts['no-data'] \n            #               arr = arr.empty? ? [model.new] : arr\n            #               arr.each_with_index { |r,i| \n            #                 # puts r.id\n            # \n            #                 attr_s = [];\n            # \n            #                 r.attributes.each { |k,v|\n            #                   v = (v.class == Time || v.class == Date) ? \"\\\"#{v}\\\"\" : v.inspect\n            #                   attr_s.push(\"#{k.to_sym.inspect} => #{v}\") unless k == 'id' && !opts['with_id']\n            #                 }\n            # \n            #                 create_hash << (i > 0 ? \",#{new_line}\" : new_line) << indent << '{ ' << attr_s.join(', ') << ' }'\n            #                 seed_rb << \"#{new_line}@rec = #{model_name.camelize}.new(#{create_hash}#{new_line})\"\n            #                 seed_rb << \"#{new_line}@rec.id = #{r.id}\"\n            #                 seed_rb << \"#{new_line}@rec.save\"\n            #               } \n            # \n            #             rescue\n            #               puts \"Exception ignored....\"\n            #             end\n      # else\n      #   Dir['app/models/*.rb'].sort.each do |f|\n      #             model_name  = File.basename(f, '.*')\n      #             begin\n      #       if models.include?(model_name) || models.empty? \n      # \n      #         puts \"Adding #{model_name.camelize} seeds.\"\n      # \n      #               create_hash = \"\"\n      # \n      #               model = model_name.camelize.constantize\n      #               arr = []\n      #               next unless defined? model.find\n      #               arr = model.find(:all, ar_options) unless opts['no-data'] \n      #         arr = arr.empty? ? [model.new] : arr\n      #         arr.each_with_index { |r,i| \n      # \n      #           attr_s = [];\n      # \n      #           r.attributes.each { |k,v|\n      #                   v = (v.class == Time || v.class == Date) ? \"\\\"#{v}\\\"\" : v.inspect\n      #             attr_s.push(\"#{k.to_sym.inspect} => #{v}\") unless k == 'id' && !opts['with_id']\n      #           }\n      # \n      #           create_hash << (i > 0 ? \",#{new_line}\" : new_line) << indent << '{ ' << attr_s.join(', ') << ' }'\n      #         } \n      # \n      #         seed_rb << \"#{new_line}#{model_name.pluralize} = #{model_name.camelize}.create([#{create_hash}#{new_line}])#{new_line}\"\n      #       end\n      #       rescue\n      #         puts \"Exception ignored....\"\n      #       end\n      #   end\n      end\n\n      File.open(opts['file'], (opts['append'] ? \"a\" : \"w\")) { |f|\n\n      puts \"Writing #{opts['file']}.\"\n\n      unless opts['append']\n          cont =<<HERE\n# Autogenerated by the db:seed:dump task\n# Do not hesitate to tweak this to your needs\nHERE\n          f << cont\n        end\n\n\tcont =<<HERE\n#{seed_rb}\nHERE\n      f << cont\n\n      puts \"Done.\"\n\n}\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/seed_dump/seed_dump.gemspec",
    "content": "# Generated by jeweler\n# DO NOT EDIT THIS FILE DIRECTLY\n# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command\n# -*- encoding: utf-8 -*-\n\nGem::Specification.new do |s|\n  s.name = %q{seed_dump}\n  s.version = \"0.2.2\"\n\n  s.required_rubygems_version = Gem::Requirement.new(\">= 0\") if s.respond_to? :required_rubygems_version=\n  s.authors = [\"Rob Halff\"]\n  s.date = %q{2010-08-01}\n  s.description = %q{Dump (parts) of your database to db/seeds.rb to get a headstart creating a meaningful seeds.rb file}\n  s.email = %q{rob.halff@gmail.com}\n  s.extra_rdoc_files = [\n    \"README.rdoc\"\n  ]\n  s.files = [\n    \".gitignore\",\n     \"CHANGELOG.rdoc\",\n     \"MIT-LICENSE\",\n     \"README.rdoc\",\n     \"Rakefile\",\n     \"VERSION\",\n     \"lib/seed_dump.rb\",\n     \"lib/seed_dump/railtie.rb\",\n     \"lib/tasks/seed_dump.rake\",\n     \"seed_dump.gemspec\",\n     \"test/seed_dump_test.rb\",\n     \"test/test_helper.rb\"\n  ]\n  s.homepage = %q{http://github.com/rhalff/seed_dump}\n  s.rdoc_options = [\"--charset=UTF-8\"]\n  s.require_paths = [\"lib\"]\n  s.rubygems_version = %q{1.3.7}\n  s.summary = %q{{Seed Dumper for Rails}}\n  s.test_files = [\n    \"test/test_helper.rb\",\n     \"test/seed_dump_test.rb\"\n  ]\n\n  if s.respond_to? :specification_version then\n    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION\n    s.specification_version = 3\n\n    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then\n    else\n    end\n  else\n  end\nend\n\n"
  },
  {
    "path": "vendor/plugins/seed_dump/test/seed_dump_test.rb",
    "content": "require 'test_helper'\n\nclass SeedDumpTest < ActiveSupport::TestCase\n  # Replace this with your real tests.\n  test \"the truth\" do\n    assert true\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/seed_dump/test/test_helper.rb",
    "content": "require 'rubygems'\nrequire 'test/unit'\nrequire 'active_support'\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/CHANGELOG",
    "content": "== REVISION 38[http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=38]\n\n=== change made by Flanagan\n\n* SOR-13[http://jira.openqa.org/browse/SOR-13] Corrected an omission of require statements.\n\n== REVISION 37\n\n=== change made by Flanagan\n\n* Undone an unwanted commit of modified Rakefile.\n\n== REVISION 36[http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=36]\n\n=== change made by Flanagan\n\n* SOR-13[http://jira.openqa.org/browse/SOR-13] Added (experimental) support for user-extensions.js.\n\n== REVISION 35[http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=35]\n\n=== all changes made by Jonas\n\n* SOR-12[http://jira.openqa.org/browse/SOR-12] removed all support for selenium gem\n* Selenium Core 0.8.2 is now bundled with Selenium on Rails. If you want to use other version set the 'selenium_path' in config.yml\n* Updated installation instructions for Windows\n\n== REVISION 34[http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=34]\n\n=== all changes made by Flanagan\n\n* SOR-11[http://jira.openqa.org/browse/SOR-11] Fixed related assertions for store_checked to use only locator parameter\n\nWarning: Users must change tests that pass two parameters (locator, pattern) to +verify_checked+, +verify_not_checked+, +assert_checked+, +assert_not_checked+, +wait_for_checked+, or +wait_for_not_checked+.\n\nTest scripts that continue to use two parameters will be broken, only one parameter, the locator, should be passed.\n\nFor example, <tt>|verify_checked|my_checkbox|true|</tt> will be interpreted as <tt>|verify_checked|my_checkboxtrue||</tt> so change the test to <tt>|verify_checked|my_checkbox||</tt>\n\n* SOR-9[http://jira.openqa.org/browse/SOR-9] Added Mac OS X browsers to config.yml.example\n* SOR-10[http://jira.openqa.org/browse/SOR-10] Added support for baseUrl to acceptance_test_runner.rb as added to selenium-core 0.8.2\n* Added 'webrick' to SERVER_COMMAND in acceptance_test_runner.rb as parameters do not work with lighttpd\n* Reversed expected query string in test/renderer_testrb to make tests pass\n\nNote: On Mac OS X, at least, clear_tables comes before fixtures in the query string; this may be an environment-specific issue if the test now fails on other OSes.\n\n* Added this CHANGELOG file and amended the rake rdoc task to include it\n\n* Added support in rselenese for a long list of actions and accessors that are included in selenium-core (0.8.2 and possibly earlier) but were previously missing in selenium-on-rails.\n\nHere are the newly supported actions:\n\nUseful for debugging:\n* <tt>brake</tt> (alias for selenium-core's break, a reserved word in Ruby)\n* <tt>echo, :string</tt>\n* <tt>highlight, :locator</tt>\n\nKeyboard events:\n* <tt>alt_key_down</tt>\n* <tt>alt_key_up</tt>\n* <tt>control_key_down</tt>\n* <tt>control_key_up</tt>\n* <tt>meta_key_down</tt>\n* <tt>meta_key_up</tt>\n* <tt>shift_key_down</tt>\n* <tt>shift_key_up</tt>\n* <tt>type_keys, :locator, :string</tt>\n\nMouse events:\n* <tt>click_at, :locator, :coord_string</tt>\n* <tt>double_click, :locator</tt>\n* <tt>double_click_at, :locator, :coord_string</tt>\n* <tt>drag_and_drop, :locator, :movements_string</tt>\n* <tt>drag_and_drop_to_object, :locator, :locator</tt>\n* <tt>mouse_down_at, :locator, :coord_string</tt>\n* <tt>mouse_move, :locator</tt>\n* <tt>mouse_move_at, :locator, :coord_string</tt>\n* <tt>mouse_out, :locator</tt>\n* <tt>mouse_up, :locator</tt>\n* <tt>mouse_up_at, :locator, :coord_string</tt>\n* <tt>set_mouse_speed, :integer</tt>\n\nOther actions:\n* <tt>create_cookie, :name_value_pair, :options_string</tt>\n* <tt>delete_cookie, :string, :string</tt>\n* <tt>open_window, :url, :integer</tt>\n* <tt>pause, :timeout</tt>\n* <tt>remove_all_selections, :locator</tt>\n* <tt>select_frame, :locator</tt>\n* <tt>set_cursor_position, :locator, :integer</tt>\n* <tt>store, :script, :variable</tt>\n* <tt>window_focus, :window_name</tt>\n* <tt>window_maximize, :window_name</tt>\n\nHere are the newly supported accessors:\n\nThe following store_* accessors and their associated assert, verify and wait_for brethren are fully supported:\n* <tt>store_selected_id, :locator, :variable</tt>\n* <tt>store_selected_ids, :locator, :variable</tt>\n* <tt>store_selected_index, :locator, :variable</tt>\n* <tt>store_selected_indexes, :locator, :variable</tt>\n* <tt>store_selected_label, :locator, :variable</tt>\n* <tt>store_selected_labels, :locator, :variable</tt>\n* <tt>store_selected_value, :locator, :variable</tt>\n* <tt>store_selected_values, :locator, :variable</tt>\n* <tt>store_something_selected, :locator, :variable</tt>\n* <tt>store_all_window_ids, :variable</tt>\n* <tt>store_all_window_names, :variable</tt>\n* <tt>store_all_window_titles, :variable</tt>\n* <tt>store_cookie, :variable</tt>\n* <tt>store_log_messages, :variable</tt>\n* <tt>store_mouse_speed, :variable</tt>\n* <tt>store_cursor_position, :locator, :variable</tt>\n* <tt>store_attribute_from_all_windows, :attribute_name, :variable</tt>\n* <tt>store_element_height, :locator, :variable</tt>\n* <tt>store_element_index, :locator, :variable</tt>\n* <tt>store_element_width, :locator, :variable</tt>\n* <tt>store_element_position_left, :locator, :variable</tt>\n* <tt>store_element_position_top, :locator, :variable</tt>\n\nOnly the associated assert, verify and wait_for brethren of the following store_* accessors are supported by the selenium-core, so these store_* accessors create exceptions in SOR:\n* <tt>store_ordered, :locator, :locator, :variable</tt>\n* <tt>store_error_on_next, :string</tt>\n* <tt>store_failure_on_next, :string</tt>\n* <tt>store_whether_this_frame_match_frame_expression, :string, :string, :variable</tt>\n* <tt>store_whether_this_window_match_window_expression, :string, :string, :variable</tt>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/LICENSE-2.0.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/README.md",
    "content": "Welcome to the Selenium on Rails README.  Exciting isn't it?\n\n# Selenium on Rails #\n\n## Overview ##\n\nSelenium on Rails provides an easy way to test Rails application with \nSeleniumCore[http://www.openqa.org/selenium-core/].\n\nThis plugin does four things:\n\n1. The Selenium Core files don't have to pollute <tt>/public</tt>.\n2. No need to create suite files, they are generated on the fly -- one suite per directory in <tt>/test/selenium</tt> (suites can be nested).\n3. Instead of writing the test cases in HTML you can use a number of better formats (see <tt>Formats</tt>).\n4. Loading of fixtures and wiping of session (<tt>/selenium/setup</tt>).\n\n## Installation ##\n\nRails periodically changes the way that it renders pages, which unfortunately breaks backwards versions of Selenium on Rails.  Therefore there are different\ninstallation locations depending on your version of Rails:\n\n*Rails 2.2 and up:*\n\n\thttp://svn.openqa.org/svn/selenium-on-rails/stable/selenium-on-rails\n\n\n*Rails 2.1:*\n\n\thttp://svn.openqa.org/svn/selenium-on-rails/tags/rails_2_1/selenium-on-rails\n\n\n*Before Rails 2.1:*\n\n\thttp://svn.openqa.org/svn/selenium-on-rails/tags/pre-rails-2-1/selenium-on-rails\n\n\nThe latest release is always kept on GitHub at \n\n\tgit clone git://github.com/paytonrules/selenium-on-rails.git\n\n\nTo install:\n\n1. Install Selenium on Rails: script/plugin install <URL>\n2. If you‘re on Windows, gem install win32-open3\n3. If the RedCloth gem is available the Selenese test cases can use it for better markup.\n4. Run the Rakefile in the plugin‘s directory to run the tests in order to see that everything works. (If RedCloth isn‘t installed a few tests will fail since they assume RedCloth is installed.)\n5. Create a test case: script/generate selenium <TestName>\n6. Start the server: script/server -e test\n7. Point your browser to localhost:3000/selenium\n8. If everything works as expected you should see the Selenium test runner. The north east frame contains all your test cases (just one for now), and the north frame contains your test case.\n\n## Formats ##\n\nThe test cases can be written in a number of formats. Which one you choose is a matter of taste. You can generate your test files by running script/generate selenium or by creating them manually in your /test/selenium directory.\n\n## RSelenese, .rsel ##\n\nRSelenese lets you write your tests in Ruby. This is my favorite format.\n\n\tsetup :fixtures => :all\n\topen '/'\n\tassert_title 'Home'\n\t('a'..'z').each {|c| open :controller => 'user', :action => 'create', :name => c }\n\nSee SeleniumOnRails::TestBuilder for available commands. *IMPORTANT NOTE:* RSelenese generates the HTML tables for Selenium behind the scenes when the page is loaded - ONCE. That means code like this:\n\n\t(1..10).each do |index|\n\t\tdo something\n\tend\n\nWill only be executed when the test is loaded, not when the test is run. This is a common error and leads to tests that work the first time and fail the second time.\n\n## Selenese, .sel ##\n\nSelenese is the dumbest format (in a good way). You just write your commands delimited by | characters.\n\n\t|open|/selenium/setup|\n\t|open|/|\n\t|goBack|\n\nIf you don‘t want to write Selenese tests by hand you can use SeleniumIDE which has support for Selenese.\n\n## HTML/RHTML ##\n\nYou can write your tests in HTML/RHTML but that‘s mostly useful if you have existing tests you want to reuse.\n\n## Partial test cases ##\n\nIf you have some common actions you want to do in several test cases you can put them in a separate partial test case and include them in your other test cases. This is highly recommended, just as small functions would be recommended in structured programming.\n\nA partial test case is just like a normal test case besides that its filename has to start with _:\n\n\t#_login.rsel\n\topen '/login'\n\ttype 'name', name\n\ttype 'password', password\n\tclick 'submit', :wait=>true\n\nTo include a partial test case in a RSelenese test case:\n\n\tinclude_partial 'login', :name => 'Jane Doe', :password => 'Jane Doe'.reverse\n\nin a Selenese test case:\n\n\t|includePartial|login|name=John Doe|password=eoD nhoJ|\n\nand in a RHTML test case:\n\n\t<%= render :partial => 'login', :locals => {:name = 'Joe Schmo', :password => 'Joe Schmo'.reverse} %>\n\n## Configuration ##\n\nThere are a number of settings available. You make them by renaming selenium.yml.example to selenium.yml and placing it in your rails app's config \nfile.  Make your changes in that file.\n\n## Environments ##\n\nPer default this plugin is only available in test environment. You can change this by setting environments, such as:\n\n\t#selenium.yml\n\tenvironments:\n\t\t- test\n\t\t- development\n\n## Selenium Core path ##\n\nIf you don‘t want to use the bundled Selenium Core version you can set selenium_path to the directory where Selenium Core is stored.\n\n\t#config.yml\n\tselenium_path: 'c:\\selenium'\n\n## Rake Task ##\n\nYou can run all your Selenium tests as a Rake task. If you're using a continuous builder this is a great way to integrate selenium into your build process.  First, if you‘re on Windows, you have to make sure win32-open3 is installed. Then you have to configure which browsers you want to run, like this:\n\n\n\t#config.yml\n\tbrowsers:\n\t\tfirefox: 'c:\\Program Files\\Mozilla Firefox\\firefox.exe'\n\t\tie: 'c:\\Program Files\\Internet Explorer\\iexplore.exe'\n\nNow you‘re all set. First start a server:\n\n\tscript/server -e test\n\nThen run the tests:\n\t\n\trake test:acceptance\n\t\nNow it should work, otherwise let me know!\n\n## Store results ##\n\nIf you want to store the results from a test:acceptance you just need to set in which directory they should be stored:\n\n\t#config.yml\n\tresult_dir: 'c:\\result'\n\t\nSo when you run rake test:acceptance the tables with the results will be stored as .html files in that directory.\n\n## user_extension.js ##\n\nSelenium has support for user_extension.js which is a way to extend the functionality of Selenium Core. Selenium on Rails now provides the means for you to extend it's functionality to match.\n\nTo get you started, we've included the example files lib/test\\_builder\\_user\\_accessors.rb.example and lib/test\\_builder\\_user\\_actions.rb.example that replicate the sample extensions in Selenium Core's user-extensions.js.sample.\n\nTo get these examples running, simply remove the .example and .sample extensions \nfrom the files and restart your server.\n\n## Todo ##\n\n* Standalone mode\n\tMore work is needed on test:acceptance< on Windows to be able to start the server when needed.\n\n* Documentation update\n\n\n## Not todo ##\n\n* Editor\n\tCreating an editor for the test cases is currently considered out of scope for this plugin. SeleniumIDE[http://www.openqa.org/selenium-ide/] does such a good  job and has support[http://wiki.openqa.org/display/SIDE/SeleniumOnRails] for both the Selenese and RSelenese formats.\n\n## Credits ##\n\n* Jonas Bengston -- original creator\n* Eric Smith, http://blog.8thlight.com/eric -- Current Maintainer\n* Jon Tirsen, http://jutopia.tirsen.com -- initial inspiration[http://wiki.rubyonrails.com/rails/pages/SeleniumIntegration]\n* Eric Kidd, http://www.randomhacks.net -- contribution of RSelenese\n* Marcos Tapajós http://www.improveit.com.br/en/company/tapajos -- Several useful features, current committer\n* Ryan Bates, http://railscasts.com -- Fixes for Rails 2.1\n* Nando Vieira, http://simplesideias.com.br\n* Gordon McCreight, a neat script that lists any unsupported methods\n\n## Contributing ## \n\nContributing is simple.  Fork this repo, make your changes, then issue a pull request.  *IMPORTANT* I will not take forks that do not have associated unit tests.  There must be tests, and they must pass, so I can bring the changes in.\n\n\n## Information ##\n\nFor more information, check out the [website](http://seleniumhq.org/projects/on-rails/).\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/Rakefile",
    "content": "require 'rake'\nrequire 'rake/testtask'\nrequire 'rdoc/rdoc'\n\ndesc 'Default: run unit tests.'\ntask :default => :test\n\ndesc 'Test the Selenium on Rails plugin.'\nRake::TestTask.new(:test) do |t|\n  t.libs << 'lib'\n  t.pattern = 'test/**/*_test.rb'\n  t.verbose = true\nend\n\ndesc 'Test the Selenium on Rails plugin, and run the _authortest.rb files, too'\nRake::TestTask.new(:alltests) do |t|\n  t.libs << 'lib'\n  # note: Both pattern and test_files are used, so the list of test files is\n  # the union of the two. \n  t.pattern = 'test/**/*_test.rb'\n  t.test_files = FileList['test/**/*_authortest.rb']\n  t.verbose = true\nend\n\ndesc 'Generate documentation for the Selenium on Rails plugin.'\ntask :rdoc do\n  rm_rf 'doc'\n  RDoc::RDoc.new.document(%w(--line-numbers --inline-source --title SeleniumOnRails README CHANGELOG lib))\nend\n\nbegin\n  require 'rcov/rcovtask'\n  Rcov::RcovTask.new do |t|\n    t.test_files = FileList['test/*_test.rb']\n    t.rcov_opts = ['-x /site_ruby/ -x .*gems.* --rails']\n  end\nrescue LoadError #if rcov isn't available, ignore\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumController.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Class: SeleniumController</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\".././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Class</strong></td>\n          <td class=\"class-name-in-header\">SeleniumController</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../files/lib/controllers/selenium_controller_rb.html\">\n                lib/controllers/selenium_controller.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        <tr class=\"top-aligned-row\">\n            <td><strong>Parent:</strong></td>\n            <td>\n                ActionController::Base\n            </td>\n        </tr>\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000006\">record</a>&nbsp;&nbsp;\n      <a href=\"#M000003\">setup</a>&nbsp;&nbsp;\n      <a href=\"#M000005\">support_file</a>&nbsp;&nbsp;\n      <a href=\"#M000004\">test_file</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n    <div id=\"includes\">\n      <h3 class=\"section-bar\">Included Modules</h3>\n\n      <div id=\"includes-list\">\n        <span class=\"include-name\"><a href=\"SeleniumOnRails/FixtureLoader.html\">SeleniumOnRails::FixtureLoader</a></span>\n        <span class=\"include-name\"><a href=\"SeleniumOnRails/Renderer.html\">SeleniumOnRails::Renderer</a></span>\n      </div>\n    </div>\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000006\" class=\"method-detail\">\n        <a name=\"M000006\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000006\" class=\"method-signature\">\n          <span class=\"method-name\">record</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000006-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000006-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/controllers/selenium_controller.rb, line 50</span>\n50:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">record</span>\n51:     <span class=\"ruby-identifier\">dir</span> = <span class=\"ruby-identifier\">record_table</span>\n52: \n53:     <span class=\"ruby-ivar\">@result</span> = {<span class=\"ruby-value str\">'resultDir'</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">dir</span>}\n54:     <span class=\"ruby-keyword kw\">for</span> <span class=\"ruby-identifier\">p</span> <span class=\"ruby-keyword kw\">in</span> [<span class=\"ruby-value str\">'result'</span>, <span class=\"ruby-value str\">'numTestFailures'</span>, <span class=\"ruby-value str\">'numTestPasses'</span>, <span class=\"ruby-value str\">'numCommandFailures'</span>, <span class=\"ruby-value str\">'numCommandPasses'</span>, <span class=\"ruby-value str\">'numCommandErrors'</span>, <span class=\"ruby-value str\">'totalTime'</span>]\n55:       <span class=\"ruby-ivar\">@result</span>[<span class=\"ruby-identifier\">p</span>] = <span class=\"ruby-identifier\">params</span>[<span class=\"ruby-identifier\">p</span>]\n56:     <span class=\"ruby-keyword kw\">end</span>\n57:     <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">open</span>(<span class=\"ruby-identifier\">log_path</span>(<span class=\"ruby-identifier\">params</span>[<span class=\"ruby-identifier\">:logFile</span>] <span class=\"ruby-operator\">||</span> <span class=\"ruby-value str\">'default.yml'</span>), <span class=\"ruby-value str\">'w'</span>) {<span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">f</span><span class=\"ruby-operator\">|</span> <span class=\"ruby-constant\">YAML</span>.<span class=\"ruby-identifier\">dump</span>(<span class=\"ruby-ivar\">@result</span>, <span class=\"ruby-identifier\">f</span>)}\n58:     \n59:     <span class=\"ruby-identifier\">render</span> <span class=\"ruby-identifier\">:file</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">view_path</span>(<span class=\"ruby-value str\">'record.rhtml'</span>), <span class=\"ruby-identifier\">:layout</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">layout_path</span>\n60:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000003\" class=\"method-detail\">\n        <a name=\"M000003\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000003\" class=\"method-signature\">\n          <span class=\"method-name\">setup</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000003-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000003-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/controllers/selenium_controller.rb, line 7</span>\n 7:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">setup</span>\n 8:     <span class=\"ruby-keyword kw\">unless</span> <span class=\"ruby-identifier\">params</span>.<span class=\"ruby-identifier\">has_key?</span> <span class=\"ruby-identifier\">:keep_session</span>\n 9:       <span class=\"ruby-identifier\">reset_session</span>\n10:       <span class=\"ruby-ivar\">@session_wiped</span> = <span class=\"ruby-keyword kw\">true</span>\n11:     <span class=\"ruby-keyword kw\">end</span>\n12:     <span class=\"ruby-ivar\">@cleared_tables</span> = <span class=\"ruby-identifier\">clear_tables</span> <span class=\"ruby-identifier\">params</span>[<span class=\"ruby-identifier\">:clear_tables</span>].<span class=\"ruby-identifier\">to_s</span>\n13:     <span class=\"ruby-ivar\">@loaded_fixtures</span> = <span class=\"ruby-identifier\">load_fixtures</span> <span class=\"ruby-identifier\">params</span>[<span class=\"ruby-identifier\">:fixtures</span>].<span class=\"ruby-identifier\">to_s</span>\n14:     <span class=\"ruby-identifier\">render</span> <span class=\"ruby-identifier\">:file</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">view_path</span>(<span class=\"ruby-value str\">'setup.rhtml'</span>), <span class=\"ruby-identifier\">:layout</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">layout_path</span>\n15:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000005\" class=\"method-detail\">\n        <a name=\"M000005\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000005\" class=\"method-signature\">\n          <span class=\"method-name\">support_file</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000005-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000005-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/controllers/selenium_controller.rb, line 34</span>\n34:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">support_file</span>\n35:     <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">params</span>[<span class=\"ruby-identifier\">:filename</span>].<span class=\"ruby-identifier\">empty?</span>\n36:       <span class=\"ruby-identifier\">redirect_to</span> <span class=\"ruby-identifier\">:filename</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value str\">'TestRunner.html'</span>, <span class=\"ruby-identifier\">:test</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value str\">'tests'</span>\n37:       <span class=\"ruby-keyword kw\">return</span>\n38:     <span class=\"ruby-keyword kw\">end</span>\n39: \n40:     <span class=\"ruby-identifier\">filename</span> = <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">join</span> <span class=\"ruby-identifier\">selenium_path</span>, <span class=\"ruby-identifier\">params</span>[<span class=\"ruby-identifier\">:filename</span>]\n41:     <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">file?</span> <span class=\"ruby-identifier\">filename</span>\n42:       <span class=\"ruby-identifier\">type</span> = <span class=\"ruby-constant\">WEBrick</span><span class=\"ruby-operator\">::</span><span class=\"ruby-constant\">HTTPUtils</span><span class=\"ruby-operator\">::</span><span class=\"ruby-constant\">DefaultMimeTypes</span>[<span class=\"ruby-identifier\">$1</span>.<span class=\"ruby-identifier\">downcase</span>] <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">filename</span> <span class=\"ruby-operator\">=~</span> <span class=\"ruby-regexp re\">/\\.(\\w+)$/</span>\n43:       <span class=\"ruby-identifier\">type</span> <span class=\"ruby-operator\">||=</span> <span class=\"ruby-value str\">'text/html'</span>\n44:       <span class=\"ruby-identifier\">send_file</span> <span class=\"ruby-identifier\">filename</span>, <span class=\"ruby-identifier\">:type</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">type</span>, <span class=\"ruby-identifier\">:disposition</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value str\">'inline'</span>, <span class=\"ruby-identifier\">:stream</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-keyword kw\">false</span>\n45:     <span class=\"ruby-keyword kw\">else</span>\n46:       <span class=\"ruby-identifier\">render</span> <span class=\"ruby-identifier\">:text</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value str\">'Not found'</span>, <span class=\"ruby-identifier\">:status</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value\">404</span>\n47:     <span class=\"ruby-keyword kw\">end</span>\n48:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000004\" class=\"method-detail\">\n        <a name=\"M000004\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000004\" class=\"method-signature\">\n          <span class=\"method-name\">test_file</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000004-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000004-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/controllers/selenium_controller.rb, line 17</span>\n17:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">test_file</span>\n18:     <span class=\"ruby-identifier\">params</span>[<span class=\"ruby-identifier\">:testname</span>] = <span class=\"ruby-value str\">''</span> <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">params</span>[<span class=\"ruby-identifier\">:testname</span>].<span class=\"ruby-identifier\">to_s</span> <span class=\"ruby-operator\">==</span> <span class=\"ruby-value str\">'TestSuite.html'</span>\n19:     <span class=\"ruby-identifier\">filename</span> = <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">join</span> <span class=\"ruby-identifier\">selenium_tests_path</span>, <span class=\"ruby-identifier\">params</span>[<span class=\"ruby-identifier\">:testname</span>]\n20:     <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">directory?</span> <span class=\"ruby-identifier\">filename</span>\n21:       <span class=\"ruby-ivar\">@suite_path</span> = <span class=\"ruby-identifier\">filename</span>\n22:       <span class=\"ruby-identifier\">render</span> <span class=\"ruby-identifier\">:file</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">view_path</span>(<span class=\"ruby-value str\">'test_suite.rhtml'</span>), <span class=\"ruby-identifier\">:layout</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">layout_path</span>\n23:     <span class=\"ruby-keyword kw\">elsif</span> <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">readable?</span> <span class=\"ruby-identifier\">filename</span>\n24:       <span class=\"ruby-identifier\">render_test_case</span> <span class=\"ruby-identifier\">filename</span>\n25:     <span class=\"ruby-keyword kw\">else</span>\n26:       <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">directory?</span> <span class=\"ruby-identifier\">selenium_tests_path</span>\n27:         <span class=\"ruby-identifier\">render</span> <span class=\"ruby-identifier\">:text</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value str\">'Not found'</span>, <span class=\"ruby-identifier\">:status</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value\">404</span>\n28:       <span class=\"ruby-keyword kw\">else</span>\n29:         <span class=\"ruby-identifier\">render</span> <span class=\"ruby-identifier\">:text</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-node\">&quot;Did not find the Selenium tests path (#{selenium_tests_path}). Run script/generate selenium&quot;</span>, <span class=\"ruby-identifier\">:status</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value\">404</span>\n30:       <span class=\"ruby-keyword kw\">end</span>\n31:     <span class=\"ruby-keyword kw\">end</span>\n32:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumHelper.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Module: SeleniumHelper</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\".././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Module</strong></td>\n          <td class=\"class-name-in-header\">SeleniumHelper</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../files/lib/selenium_helper_rb.html\">\n                lib/selenium_helper.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000008\">test_case_name</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n    <div id=\"includes\">\n      <h3 class=\"section-bar\">Included Modules</h3>\n\n      <div id=\"includes-list\">\n        <span class=\"include-name\"><a href=\"SeleniumOnRails/SuiteRenderer.html\">SeleniumOnRails::SuiteRenderer</a></span>\n        <span class=\"include-name\"><a href=\"SeleniumOnRails/FixtureLoader.html\">SeleniumOnRails::FixtureLoader</a></span>\n      </div>\n    </div>\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000008\" class=\"method-detail\">\n        <a name=\"M000008\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000008\" class=\"method-signature\">\n          <span class=\"method-name\">test_case_name</span><span class=\"method-args\">(filename)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000008-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000008-source\">\n<pre>\n   <span class=\"ruby-comment cmt\"># File lib/selenium_helper.rb, line 5</span>\n5:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">test_case_name</span> <span class=\"ruby-identifier\">filename</span>\n6:     <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">basename</span>(<span class=\"ruby-identifier\">filename</span>).<span class=\"ruby-identifier\">sub</span>(<span class=\"ruby-regexp re\">/\\..*/</span>,<span class=\"ruby-value str\">''</span>).<span class=\"ruby-identifier\">humanize</span>\n7:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/FixtureLoader.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Module: SeleniumOnRails::FixtureLoader</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Module</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::FixtureLoader</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/fixture_loader_rb.html\">\n                lib/selenium_on_rails/fixture_loader.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000083\">available_fixtures</a>&nbsp;&nbsp;\n      <a href=\"#M000085\">clear_tables</a>&nbsp;&nbsp;\n      <a href=\"#M000084\">load_fixtures</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n    <div id=\"includes\">\n      <h3 class=\"section-bar\">Included Modules</h3>\n\n      <div id=\"includes-list\">\n        <span class=\"include-name\"><a href=\"Paths.html\">SeleniumOnRails::Paths</a></span>\n      </div>\n    </div>\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000083\" class=\"method-detail\">\n        <a name=\"M000083\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000083\" class=\"method-signature\">\n          <span class=\"method-name\">available_fixtures</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000083-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000083-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/fixture_loader.rb, line 7</span>\n 7:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">available_fixtures</span>\n 8:     <span class=\"ruby-identifier\">fixtures</span> = {}\n 9:     <span class=\"ruby-identifier\">path</span> = <span class=\"ruby-identifier\">fixtures_path</span> <span class=\"ruby-operator\">+</span> <span class=\"ruby-value str\">'/'</span>\n10:     <span class=\"ruby-identifier\">files</span> = <span class=\"ruby-constant\">Dir</span>[<span class=\"ruby-node\">&quot;#{path}**/*.{yml,csv}&quot;</span>]\n11:     <span class=\"ruby-identifier\">files</span>.<span class=\"ruby-identifier\">each</span> <span class=\"ruby-keyword kw\">do</span> <span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">file</span><span class=\"ruby-operator\">|</span>\n12:       <span class=\"ruby-identifier\">rel_path</span> = <span class=\"ruby-identifier\">file</span>.<span class=\"ruby-identifier\">sub</span>(<span class=\"ruby-identifier\">path</span>, <span class=\"ruby-value str\">''</span>)\n13:       <span class=\"ruby-keyword kw\">next</span> <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">skip_file?</span> <span class=\"ruby-identifier\">rel_path</span>\n14:       <span class=\"ruby-identifier\">fixture_set</span> = <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">dirname</span>(<span class=\"ruby-identifier\">rel_path</span>)\n15:       <span class=\"ruby-identifier\">fixture_set</span> = <span class=\"ruby-value str\">''</span> <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">fixture_set</span> <span class=\"ruby-operator\">==</span> <span class=\"ruby-value str\">'.'</span>\n16:       <span class=\"ruby-identifier\">fixture</span> = <span class=\"ruby-identifier\">rel_path</span>.<span class=\"ruby-identifier\">sub</span> <span class=\"ruby-regexp re\">/\\.[^.]*$/</span>, <span class=\"ruby-value str\">''</span>\n17:       <span class=\"ruby-identifier\">fixtures</span>[<span class=\"ruby-identifier\">fixture_set</span>] <span class=\"ruby-operator\">||=</span> []\n18:       <span class=\"ruby-identifier\">fixtures</span>[<span class=\"ruby-identifier\">fixture_set</span>] <span class=\"ruby-operator\">&lt;&lt;</span> <span class=\"ruby-identifier\">fixture</span>\n19:     <span class=\"ruby-keyword kw\">end</span>\n20:     \n21:     <span class=\"ruby-identifier\">fixtures</span>\n22:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000085\" class=\"method-detail\">\n        <a name=\"M000085\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000085\" class=\"method-signature\">\n          <span class=\"method-name\">clear_tables</span><span class=\"method-args\">(tables)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000085-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000085-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/fixture_loader.rb, line 46</span>\n46:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">clear_tables</span> <span class=\"ruby-identifier\">tables</span>\n47:     <span class=\"ruby-identifier\">table_names</span> = <span class=\"ruby-identifier\">tables</span>.<span class=\"ruby-identifier\">split</span> <span class=\"ruby-regexp re\">/\\s*,\\s*/</span>\n48:     <span class=\"ruby-identifier\">connection</span> = <span class=\"ruby-constant\">ActiveRecord</span><span class=\"ruby-operator\">::</span><span class=\"ruby-constant\">Base</span>.<span class=\"ruby-identifier\">connection</span> \n49:     <span class=\"ruby-identifier\">table_names</span>.<span class=\"ruby-identifier\">each</span> <span class=\"ruby-keyword kw\">do</span> <span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">table</span><span class=\"ruby-operator\">|</span>\n50:       <span class=\"ruby-identifier\">connection</span>.<span class=\"ruby-identifier\">execute</span> <span class=\"ruby-node\">&quot;DELETE FROM #{table}&quot;</span> \n51:     <span class=\"ruby-keyword kw\">end</span>\n52:     <span class=\"ruby-identifier\">table_names</span>\n53:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000084\" class=\"method-detail\">\n        <a name=\"M000084\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000084\" class=\"method-signature\">\n          <span class=\"method-name\">load_fixtures</span><span class=\"method-args\">(fixtures_param)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000084-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000084-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/fixture_loader.rb, line 24</span>\n24:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">load_fixtures</span> <span class=\"ruby-identifier\">fixtures_param</span>\n25:     <span class=\"ruby-identifier\">available</span> = <span class=\"ruby-keyword kw\">nil</span>\n26:     <span class=\"ruby-identifier\">fixtures</span> = <span class=\"ruby-identifier\">fixtures_param</span>.<span class=\"ruby-identifier\">split</span>(<span class=\"ruby-regexp re\">/\\s*,\\s*/</span>).<span class=\"ruby-identifier\">collect</span> <span class=\"ruby-keyword kw\">do</span> <span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">f</span><span class=\"ruby-operator\">|</span>\n27:       <span class=\"ruby-identifier\">fixture_set</span> = <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">dirname</span> <span class=\"ruby-identifier\">f</span>\n28:       <span class=\"ruby-identifier\">fixture_set</span> = <span class=\"ruby-value str\">''</span> <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">fixture_set</span> <span class=\"ruby-operator\">==</span> <span class=\"ruby-value str\">'.'</span>\n29:       <span class=\"ruby-identifier\">fixture</span> = <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">basename</span> <span class=\"ruby-identifier\">f</span>\n30:       <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">fixture</span> <span class=\"ruby-operator\">==</span> <span class=\"ruby-value str\">'all'</span>\n31:         <span class=\"ruby-identifier\">available</span> <span class=\"ruby-operator\">||=</span> <span class=\"ruby-identifier\">available_fixtures</span>\n32:         <span class=\"ruby-identifier\">available</span>[<span class=\"ruby-identifier\">fixture_set</span>]\n33:       <span class=\"ruby-keyword kw\">else</span>\n34:         <span class=\"ruby-identifier\">f</span>\n35:       <span class=\"ruby-keyword kw\">end</span>\n36:     <span class=\"ruby-keyword kw\">end</span>\n37:     <span class=\"ruby-identifier\">fixtures</span>.<span class=\"ruby-identifier\">flatten!</span>\n38:     <span class=\"ruby-identifier\">fixtures</span>.<span class=\"ruby-identifier\">reject!</span> {<span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">f</span><span class=\"ruby-operator\">|</span> <span class=\"ruby-identifier\">f</span>.<span class=\"ruby-identifier\">blank?</span> }\n39: \n40:     <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">fixtures</span>.<span class=\"ruby-identifier\">any?</span>\n41:       <span class=\"ruby-constant\">Fixtures</span>.<span class=\"ruby-identifier\">create_fixtures</span> <span class=\"ruby-identifier\">fixtures_path</span>, <span class=\"ruby-identifier\">fixtures</span>\n42:     <span class=\"ruby-keyword kw\">end</span>\n43:     <span class=\"ruby-identifier\">fixtures</span>\n44:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/PartialsSupport.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Module: SeleniumOnRails::PartialsSupport</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Module</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::PartialsSupport</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/partials_support_rb.html\">\n                lib/selenium_on_rails/partials_support.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nProvides partials support to test cases so they can include other partial\ntest cases.\n</p>\n<p>\nThe partial&#8216;s commands are returned as html table rows.\n</p>\n\n    </div>\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000142\">extract_commands_from_partial</a>&nbsp;&nbsp;\n      <a href=\"#M000141\">render_partial</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n    <div id=\"includes\">\n      <h3 class=\"section-bar\">Included Modules</h3>\n\n      <div id=\"includes-list\">\n        <span class=\"include-name\"><a href=\"Paths.html\">SeleniumOnRails::Paths</a></span>\n      </div>\n    </div>\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000142\" class=\"method-detail\">\n        <a name=\"M000142\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000142\" class=\"method-signature\">\n          <span class=\"method-name\">extract_commands_from_partial</span><span class=\"method-args\">(partial)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nExtracts the commands from a partial. The partial must contain a html table\nand the first row is ignored since it cannot contain a command.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000142-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000142-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/partials_support.rb, line 19</span>\n19:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">extract_commands_from_partial</span> <span class=\"ruby-identifier\">partial</span>\n20:     <span class=\"ruby-identifier\">partial</span> = <span class=\"ruby-identifier\">partial</span>.<span class=\"ruby-identifier\">match</span>(<span class=\"ruby-regexp re\">/.*&lt;table&gt;.*?&lt;tr&gt;.*?&lt;\\/tr&gt;(.*?)&lt;\\/table&gt;/i</span><span class=\"ruby-identifier\">m</span>)[<span class=\"ruby-value\">1</span>]\n21:     <span class=\"ruby-identifier\">raise</span> <span class=\"ruby-node\">&quot;Partial '#{name}' doesn't contain any table&quot;</span> <span class=\"ruby-keyword kw\">unless</span> <span class=\"ruby-identifier\">partial</span>\n22:     <span class=\"ruby-identifier\">partial</span>\n23:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000141\" class=\"method-detail\">\n        <a name=\"M000141\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000141\" class=\"method-signature\">\n          <span class=\"method-name\">render_partial</span><span class=\"method-args\">(partial_path = default_template_name, object = nil, local_assigns = nil, status = nil)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nOverrides where the partial is searched for, and returns only the command\ntable rows.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000141-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000141-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/partials_support.rb, line 9</span>\n 9:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">render_partial</span> <span class=\"ruby-identifier\">partial_path</span> = <span class=\"ruby-identifier\">default_template_name</span>, <span class=\"ruby-identifier\">object</span> = <span class=\"ruby-keyword kw\">nil</span>, <span class=\"ruby-identifier\">local_assigns</span> = <span class=\"ruby-keyword kw\">nil</span>, <span class=\"ruby-identifier\">status</span> = <span class=\"ruby-keyword kw\">nil</span>\n10:     <span class=\"ruby-identifier\">pattern</span> = <span class=\"ruby-identifier\">partial_pattern</span> <span class=\"ruby-identifier\">partial_path</span>\n11:     <span class=\"ruby-identifier\">filename</span> = <span class=\"ruby-constant\">Dir</span>[<span class=\"ruby-identifier\">pattern</span>].<span class=\"ruby-identifier\">first</span>\n12:     <span class=\"ruby-identifier\">raise</span> <span class=\"ruby-node\">&quot;Partial '#{partial_path}' cannot be found! (Looking for file: '#{pattern}')&quot;</span> <span class=\"ruby-keyword kw\">unless</span> <span class=\"ruby-identifier\">filename</span>\n13:     <span class=\"ruby-identifier\">partial</span> = <span class=\"ruby-identifier\">render</span> <span class=\"ruby-identifier\">:file</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">filename</span>, <span class=\"ruby-identifier\">:use_full_path</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-keyword kw\">false</span>, <span class=\"ruby-identifier\">:locals</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">local_assigns</span>\n14:     <span class=\"ruby-identifier\">extract_commands_from_partial</span> <span class=\"ruby-identifier\">partial</span>\n15:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/Paths.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Module: SeleniumOnRails::Paths</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Module</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::Paths</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/paths_rb.html\">\n                lib/selenium_on_rails/paths.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000076\">fixtures_path</a>&nbsp;&nbsp;\n      <a href=\"#M000075\">layout_path</a>&nbsp;&nbsp;\n      <a href=\"#M000077\">log_path</a>&nbsp;&nbsp;\n      <a href=\"#M000072\">selenium_path</a>&nbsp;&nbsp;\n      <a href=\"#M000073\">selenium_tests_path</a>&nbsp;&nbsp;\n      <a href=\"#M000078\">skip_file?</a>&nbsp;&nbsp;\n      <a href=\"#M000074\">view_path</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000076\" class=\"method-detail\">\n        <a name=\"M000076\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000076\" class=\"method-signature\">\n          <span class=\"method-name\">fixtures_path</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000076-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000076-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/paths.rb, line 25</span>\n25:     <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">fixtures_path</span>\n26:       <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">expand_path</span> <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">join</span>(<span class=\"ruby-constant\">RAILS_ROOT</span>, <span class=\"ruby-value str\">'test/fixtures'</span>)\n27:     <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000075\" class=\"method-detail\">\n        <a name=\"M000075\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000075\" class=\"method-signature\">\n          <span class=\"method-name\">layout_path</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturns the path to the layout template. The path is relative in relation\nto the app/views/ directory since Rails doesn&#8216;t support absolute\npaths to layout templates.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000075-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000075-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/paths.rb, line 19</span>\n19:     <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">layout_path</span>\n20:       <span class=\"ruby-identifier\">rails_root</span> = <span class=\"ruby-constant\">Pathname</span>.<span class=\"ruby-identifier\">new</span> <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">expand_path</span>(<span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">join</span>(<span class=\"ruby-constant\">RAILS_ROOT</span>, <span class=\"ruby-value str\">'app/views'</span>))\n21:       <span class=\"ruby-identifier\">view_path</span> = <span class=\"ruby-constant\">Pathname</span>.<span class=\"ruby-identifier\">new</span> <span class=\"ruby-identifier\">view_path</span>(<span class=\"ruby-value str\">'layout'</span>)\n22:       <span class=\"ruby-identifier\">view_path</span>.<span class=\"ruby-identifier\">relative_path_from</span>(<span class=\"ruby-identifier\">rails_root</span>).<span class=\"ruby-identifier\">to_s</span>\n23:     <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000077\" class=\"method-detail\">\n        <a name=\"M000077\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000077\" class=\"method-signature\">\n          <span class=\"method-name\">log_path</span><span class=\"method-args\">(log_file)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000077-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000077-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/paths.rb, line 29</span>\n29:     <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">log_path</span> <span class=\"ruby-identifier\">log_file</span>\n30:       <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">expand_path</span>(<span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">dirname</span>(<span class=\"ruby-keyword kw\">__FILE__</span>) <span class=\"ruby-operator\">+</span> <span class=\"ruby-value str\">'/../../log/'</span> <span class=\"ruby-operator\">+</span> <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">basename</span>(<span class=\"ruby-identifier\">log_file</span>))\n31:     <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000072\" class=\"method-detail\">\n        <a name=\"M000072\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000072\" class=\"method-signature\">\n          <span class=\"method-name\">selenium_path</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000072-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000072-source\">\n<pre>\n   <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/paths.rb, line 3</span>\n3:     <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">selenium_path</span>\n4:       <span class=\"ruby-ivar\">@@selenium_path</span> <span class=\"ruby-operator\">||=</span> <span class=\"ruby-identifier\">find_selenium_path</span>\n5:       <span class=\"ruby-ivar\">@@selenium_path</span>\n6:     <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000073\" class=\"method-detail\">\n        <a name=\"M000073\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000073\" class=\"method-signature\">\n          <span class=\"method-name\">selenium_tests_path</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000073-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000073-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/paths.rb, line 8</span>\n 8:     <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">selenium_tests_path</span>\n 9:       <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">expand_path</span>(<span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">join</span>(<span class=\"ruby-constant\">RAILS_ROOT</span>, <span class=\"ruby-value str\">'test/selenium'</span>))\n10:     <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000078\" class=\"method-detail\">\n        <a name=\"M000078\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000078\" class=\"method-signature\">\n          <span class=\"method-name\">skip_file?</span><span class=\"method-args\">(file)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000078-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000078-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/paths.rb, line 33</span>\n33:     <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">skip_file?</span> <span class=\"ruby-identifier\">file</span>\n34:       <span class=\"ruby-identifier\">file</span>.<span class=\"ruby-identifier\">split</span>(<span class=\"ruby-value str\">'/'</span>).<span class=\"ruby-identifier\">each</span> <span class=\"ruby-keyword kw\">do</span> <span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">f</span><span class=\"ruby-operator\">|</span>\n35:         <span class=\"ruby-keyword kw\">return</span> <span class=\"ruby-keyword kw\">true</span> <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">f</span>.<span class=\"ruby-identifier\">upcase</span> <span class=\"ruby-operator\">==</span> <span class=\"ruby-value str\">'CVS'</span> <span class=\"ruby-keyword kw\">or</span> <span class=\"ruby-identifier\">f</span>.<span class=\"ruby-identifier\">starts_with?</span>(<span class=\"ruby-value str\">'.'</span>) <span class=\"ruby-keyword kw\">or</span> <span class=\"ruby-identifier\">f</span>.<span class=\"ruby-identifier\">ends_with?</span>(<span class=\"ruby-value str\">'~'</span>) <span class=\"ruby-keyword kw\">or</span> <span class=\"ruby-identifier\">f</span>.<span class=\"ruby-identifier\">starts_with?</span>(<span class=\"ruby-value str\">'_'</span>)\n36:       <span class=\"ruby-keyword kw\">end</span>\n37:       <span class=\"ruby-keyword kw\">false</span>\n38:     <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000074\" class=\"method-detail\">\n        <a name=\"M000074\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000074\" class=\"method-signature\">\n          <span class=\"method-name\">view_path</span><span class=\"method-args\">(view)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000074-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000074-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/paths.rb, line 12</span>\n12:     <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">view_path</span> <span class=\"ruby-identifier\">view</span>\n13:       <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">expand_path</span>(<span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">dirname</span>(<span class=\"ruby-keyword kw\">__FILE__</span>) <span class=\"ruby-operator\">+</span> <span class=\"ruby-value str\">'/../views/'</span> <span class=\"ruby-operator\">+</span> <span class=\"ruby-identifier\">view</span>)\n14:     <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/RSelenese.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Class: SeleniumOnRails::RSelenese</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Class</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::RSelenese</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/rselenese_rb.html\">\n                lib/selenium_on_rails/rselenese.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        <tr class=\"top-aligned-row\">\n            <td><strong>Parent:</strong></td>\n            <td>\n                <a href=\"TestBuilder.html\">\n                SeleniumOnRails::TestBuilder\n               </a>\n            </td>\n        </tr>\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nRenders Selenium test templates in a fashion analogous to <tt>rxml</tt> and\n<tt>rjs</tt> templates.\n</p>\n<pre>\n  setup\n  open :controller =&gt; 'customer', :action =&gt; 'list'\n  assert_title 'Customers'\n</pre>\n<p>\nSee <a href=\"TestBuilder.html\">SeleniumOnRails::TestBuilder</a> for a list\nof available commands.\n</p>\n\n    </div>\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000145\">new</a>&nbsp;&nbsp;\n      <a href=\"#M000146\">render</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n    <div id=\"attribute-list\">\n      <h3 class=\"section-bar\">Attributes</h3>\n\n      <div class=\"name-list\">\n        <table>\n        <tr class=\"top-aligned-row context-row\">\n          <td class=\"context-item-name\">view</td>\n          <td class=\"context-item-value\">&nbsp;[RW]&nbsp;</td>\n          <td class=\"context-item-desc\"></td>\n        </tr>\n        </table>\n      </div>\n    </div>\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Class methods</h3>\n\n      <div id=\"method-M000145\" class=\"method-detail\">\n        <a name=\"M000145\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000145\" class=\"method-signature\">\n          <span class=\"method-name\">new</span><span class=\"method-args\">(view)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nCreate a <a href=\"RSelenese.html#M000145\">new</a> <a\nhref=\"RSelenese.html\">RSelenese</a> renderer bound to <em>view</em>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000145-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000145-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/rselenese.rb, line 17</span>\n17:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">initialize</span> <span class=\"ruby-identifier\">view</span>\n18:     <span class=\"ruby-keyword kw\">super</span> <span class=\"ruby-identifier\">view</span>\n19:     <span class=\"ruby-ivar\">@view</span> = <span class=\"ruby-identifier\">view</span>\n20:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000146\" class=\"method-detail\">\n        <a name=\"M000146\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000146\" class=\"method-signature\">\n          <span class=\"method-name\">render</span><span class=\"method-args\">(template, local_assigns)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRender <em>template</em> using <em>local_assigns</em>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000146-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000146-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/rselenese.rb, line 23</span>\n23:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">render</span> <span class=\"ruby-identifier\">template</span>, <span class=\"ruby-identifier\">local_assigns</span>\n24:     <span class=\"ruby-identifier\">title</span> = (<span class=\"ruby-ivar\">@view</span>.<span class=\"ruby-identifier\">assigns</span>[<span class=\"ruby-value str\">'page_title'</span>] <span class=\"ruby-keyword kw\">or</span> <span class=\"ruby-identifier\">local_assigns</span>[<span class=\"ruby-value str\">'page_title'</span>])\n25:     <span class=\"ruby-identifier\">table</span>(<span class=\"ruby-identifier\">title</span>) <span class=\"ruby-keyword kw\">do</span>\n26:       <span class=\"ruby-identifier\">test</span> = <span class=\"ruby-keyword kw\">self</span> <span class=\"ruby-comment cmt\">#to enable test.command\r</span>\n27: \n28:       <span class=\"ruby-identifier\">assign_locals_code</span> = <span class=\"ruby-value str\">''</span>\n29:       <span class=\"ruby-identifier\">local_assigns</span>.<span class=\"ruby-identifier\">each_key</span> {<span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">key</span><span class=\"ruby-operator\">|</span> <span class=\"ruby-identifier\">assign_locals_code</span> <span class=\"ruby-operator\">&lt;&lt;</span> <span class=\"ruby-node\">&quot;#{key} = local_assigns[#{key.inspect}];&quot;</span>}\n30: \n31:       <span class=\"ruby-identifier\">eval</span> <span class=\"ruby-identifier\">assign_locals_code</span> <span class=\"ruby-operator\">+</span> <span class=\"ruby-value str\">&quot;\\n&quot;</span> <span class=\"ruby-operator\">+</span> <span class=\"ruby-identifier\">template</span>\n32:     <span class=\"ruby-keyword kw\">end</span>\n33:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/Renderer.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Module: SeleniumOnRails::Renderer</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Module</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::Renderer</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/renderer_rb.html\">\n                lib/selenium_on_rails/renderer.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000071\">render_test_case</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n    <div id=\"includes\">\n      <h3 class=\"section-bar\">Included Modules</h3>\n\n      <div id=\"includes-list\">\n        <span class=\"include-name\"><a href=\"Paths.html\">SeleniumOnRails::Paths</a></span>\n        <span class=\"include-name\"><a href=\"../SeleniumHelper.html\">SeleniumHelper</a></span>\n      </div>\n    </div>\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000071\" class=\"method-detail\">\n        <a name=\"M000071\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000071\" class=\"method-signature\">\n          <span class=\"method-name\">render_test_case</span><span class=\"method-args\">(filename)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000071-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000071-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/renderer.rb, line 5</span>\n 5:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">render_test_case</span> <span class=\"ruby-identifier\">filename</span>\n 6:     <span class=\"ruby-ivar\">@template</span>.<span class=\"ruby-identifier\">extend</span> <span class=\"ruby-constant\">SeleniumOnRails</span><span class=\"ruby-operator\">::</span><span class=\"ruby-constant\">PartialsSupport</span>\n 7:     <span class=\"ruby-ivar\">@page_title</span> = <span class=\"ruby-identifier\">test_case_name</span> <span class=\"ruby-identifier\">filename</span>\n 8:     <span class=\"ruby-identifier\">output</span> = <span class=\"ruby-identifier\">render_to_string</span> <span class=\"ruby-identifier\">:file</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">filename</span>\n 9:     <span class=\"ruby-identifier\">layout</span> = (<span class=\"ruby-identifier\">output</span> <span class=\"ruby-operator\">=~</span> <span class=\"ruby-regexp re\">/&lt;html&gt;/i</span> <span class=\"ruby-operator\">?</span> <span class=\"ruby-keyword kw\">false</span> <span class=\"ruby-operator\">:</span> <span class=\"ruby-identifier\">layout_path</span>)\n10:     <span class=\"ruby-identifier\">render</span> <span class=\"ruby-identifier\">:text</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">output</span>, <span class=\"ruby-identifier\">:layout</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">layout</span>\n11: \n12:     <span class=\"ruby-identifier\">headers</span>[<span class=\"ruby-value str\">'Cache-control'</span>] = <span class=\"ruby-value str\">'no-cache'</span>\n13:     <span class=\"ruby-identifier\">headers</span>[<span class=\"ruby-value str\">'Pragma'</span>] = <span class=\"ruby-value str\">'no-cache'</span>\n14:     <span class=\"ruby-identifier\">headers</span>[<span class=\"ruby-value str\">'Expires'</span>] = <span class=\"ruby-value str\">'-1'</span>\n15:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/Selenese.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Class: SeleniumOnRails::Selenese</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Class</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::Selenese</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/selenese_rb.html\">\n                lib/selenium_on_rails/selenese.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        <tr class=\"top-aligned-row\">\n            <td><strong>Parent:</strong></td>\n            <td>\n                Object\n            </td>\n        </tr>\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000143\">new</a>&nbsp;&nbsp;\n      <a href=\"#M000144\">render</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Class methods</h3>\n\n      <div id=\"method-M000143\" class=\"method-detail\">\n        <a name=\"M000143\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000143\" class=\"method-signature\">\n          <span class=\"method-name\">new</span><span class=\"method-args\">(view)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000143-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000143-source\">\n<pre>\n   <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/selenese.rb, line 7</span>\n7:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">initialize</span> <span class=\"ruby-identifier\">view</span>\n8:     <span class=\"ruby-ivar\">@view</span> = <span class=\"ruby-identifier\">view</span>\n9:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000144\" class=\"method-detail\">\n        <a name=\"M000144\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000144\" class=\"method-signature\">\n          <span class=\"method-name\">render</span><span class=\"method-args\">(template, local_assigns)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000144-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000144-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/selenese.rb, line 11</span>\n11:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">render</span> <span class=\"ruby-identifier\">template</span>, <span class=\"ruby-identifier\">local_assigns</span>\n12:     <span class=\"ruby-identifier\">name</span> = (<span class=\"ruby-ivar\">@view</span>.<span class=\"ruby-identifier\">assigns</span>[<span class=\"ruby-value str\">'page_title'</span>] <span class=\"ruby-keyword kw\">or</span> <span class=\"ruby-identifier\">local_assigns</span>[<span class=\"ruby-value str\">'page_title'</span>])\n13:     <span class=\"ruby-identifier\">lines</span> = <span class=\"ruby-identifier\">template</span>.<span class=\"ruby-identifier\">strip</span>.<span class=\"ruby-identifier\">split</span> <span class=\"ruby-value str\">&quot;\\n&quot;</span>\n14:     <span class=\"ruby-identifier\">html</span> = <span class=\"ruby-value str\">''</span>\n15:     <span class=\"ruby-identifier\">html</span> <span class=\"ruby-operator\">&lt;&lt;</span> <span class=\"ruby-identifier\">extract_comments</span>(<span class=\"ruby-identifier\">lines</span>)\n16:     <span class=\"ruby-identifier\">html</span> <span class=\"ruby-operator\">&lt;&lt;</span> <span class=\"ruby-identifier\">extract_commands</span>(<span class=\"ruby-identifier\">lines</span>, <span class=\"ruby-identifier\">name</span>)\n17:     <span class=\"ruby-identifier\">html</span> <span class=\"ruby-operator\">&lt;&lt;</span> <span class=\"ruby-identifier\">extract_comments</span>(<span class=\"ruby-identifier\">lines</span>)\n18:     <span class=\"ruby-identifier\">raise</span> <span class=\"ruby-value str\">'You cannot have comments in the middle of commands!'</span> <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">next_line</span> <span class=\"ruby-identifier\">lines</span>, <span class=\"ruby-identifier\">:any</span>\n19:     <span class=\"ruby-identifier\">html</span>\n20:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/SuiteRenderer.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Module: SeleniumOnRails::SuiteRenderer</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Module</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::SuiteRenderer</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/suite_renderer_rb.html\">\n                lib/selenium_on_rails/suite_renderer.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000082\">link_to_test_case</a>&nbsp;&nbsp;\n      <a href=\"#M000081\">test_cases</a>&nbsp;&nbsp;\n      <a href=\"#M000079\">test_suite_name</a>&nbsp;&nbsp;\n      <a href=\"#M000080\">test_suites</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000082\" class=\"method-detail\">\n        <a name=\"M000082\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000082\" class=\"method-signature\">\n          <span class=\"method-name\">link_to_test_case</span><span class=\"method-args\">(suite_name, filename)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000082-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000082-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/suite_renderer.rb, line 24</span>\n24:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">link_to_test_case</span> <span class=\"ruby-identifier\">suite_name</span>, <span class=\"ruby-identifier\">filename</span>\n25:     <span class=\"ruby-identifier\">name</span> = <span class=\"ruby-identifier\">suite_name</span> <span class=\"ruby-operator\">+</span> <span class=\"ruby-identifier\">test_case_name</span>(<span class=\"ruby-identifier\">filename</span>)\n26:     <span class=\"ruby-identifier\">link_to</span> <span class=\"ruby-identifier\">name</span>, <span class=\"ruby-identifier\">:action</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">:test_file</span>, <span class=\"ruby-identifier\">:testname</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">path_to_relative_url</span>(<span class=\"ruby-identifier\">filename</span>).<span class=\"ruby-identifier\">sub</span>(<span class=\"ruby-regexp re\">/^\\//</span>,<span class=\"ruby-value str\">''</span>)\n27:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000081\" class=\"method-detail\">\n        <a name=\"M000081\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000081\" class=\"method-signature\">\n          <span class=\"method-name\">test_cases</span><span class=\"method-args\">(path)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000081-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000081-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/suite_renderer.rb, line 18</span>\n18:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">test_cases</span> <span class=\"ruby-identifier\">path</span>\n19:     <span class=\"ruby-identifier\">tests</span> = []\n20:     <span class=\"ruby-identifier\">visit_all_tests</span> <span class=\"ruby-identifier\">path</span>, <span class=\"ruby-value str\">''</span>, <span class=\"ruby-keyword kw\">nil</span>, <span class=\"ruby-constant\">Proc</span>.<span class=\"ruby-identifier\">new</span> {<span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">n</span>, <span class=\"ruby-identifier\">p</span><span class=\"ruby-operator\">|</span> <span class=\"ruby-identifier\">tests</span> <span class=\"ruby-operator\">&lt;&lt;</span> [<span class=\"ruby-identifier\">n</span>,<span class=\"ruby-identifier\">p</span>]}\n21:     <span class=\"ruby-identifier\">tests</span>\n22:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000079\" class=\"method-detail\">\n        <a name=\"M000079\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000079\" class=\"method-signature\">\n          <span class=\"method-name\">test_suite_name</span><span class=\"method-args\">(path)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000079-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000079-source\">\n<pre>\n   <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/suite_renderer.rb, line 2</span>\n2:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">test_suite_name</span> <span class=\"ruby-identifier\">path</span>\n3:     <span class=\"ruby-keyword kw\">return</span> <span class=\"ruby-value str\">'All test cases'</span> <span class=\"ruby-keyword kw\">if</span> [<span class=\"ruby-keyword kw\">nil</span>, <span class=\"ruby-value str\">'/'</span>].<span class=\"ruby-identifier\">include?</span> <span class=\"ruby-identifier\">path_to_relative_url</span>(<span class=\"ruby-identifier\">path</span>)\n4:     <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">split</span>(<span class=\"ruby-identifier\">path</span>)[<span class=\"ruby-value\">-1</span>].<span class=\"ruby-identifier\">humanize</span>\n5:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000080\" class=\"method-detail\">\n        <a name=\"M000080\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000080\" class=\"method-signature\">\n          <span class=\"method-name\">test_suites</span><span class=\"method-args\">(path)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000080-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000080-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/suite_renderer.rb, line 7</span>\n 7:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">test_suites</span> <span class=\"ruby-identifier\">path</span>\n 8:     <span class=\"ruby-identifier\">suites</span> = []\n 9: \n10:     <span class=\"ruby-identifier\">parent_path</span> = <span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">join</span>(<span class=\"ruby-constant\">File</span>.<span class=\"ruby-identifier\">split</span>(<span class=\"ruby-identifier\">path</span>).<span class=\"ruby-identifier\">slice</span>(<span class=\"ruby-value\">0</span><span class=\"ruby-operator\">..</span><span class=\"ruby-value\">-2</span>)) <span class=\"ruby-comment cmt\">#all but last\r</span>\n11:     <span class=\"ruby-identifier\">parent_path</span> = <span class=\"ruby-identifier\">path_to_relative_url</span> <span class=\"ruby-identifier\">parent_path</span>\n12:     <span class=\"ruby-identifier\">suites</span> <span class=\"ruby-operator\">&lt;&lt;</span> [<span class=\"ruby-value str\">'..'</span>, <span class=\"ruby-identifier\">parent_path</span>] <span class=\"ruby-keyword kw\">unless</span> <span class=\"ruby-identifier\">parent_path</span>.<span class=\"ruby-identifier\">nil?</span>\n13: \n14:     <span class=\"ruby-identifier\">visit_all_tests</span> <span class=\"ruby-identifier\">path</span>, <span class=\"ruby-value str\">''</span>, <span class=\"ruby-constant\">Proc</span>.<span class=\"ruby-identifier\">new</span> {<span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">n</span>, <span class=\"ruby-identifier\">p</span><span class=\"ruby-operator\">|</span> <span class=\"ruby-identifier\">suites</span> <span class=\"ruby-operator\">&lt;&lt;</span> [<span class=\"ruby-identifier\">n</span>,<span class=\"ruby-identifier\">path_to_relative_url</span>(<span class=\"ruby-identifier\">p</span>)]}, <span class=\"ruby-keyword kw\">nil</span>\n15:     <span class=\"ruby-identifier\">suites</span>\n16:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilder.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Class: SeleniumOnRails::TestBuilder</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Class</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::TestBuilder</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/test_builder_rb.html\">\n                lib/selenium_on_rails/test_builder.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        <tr class=\"top-aligned-row\">\n            <td><strong>Parent:</strong></td>\n            <td>\n                Object\n            </td>\n        </tr>\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nBuilds Selenium test <a href=\"TestBuilder.html#M000150\">table</a> using a\nhigh-level Ruby interface. Normally invoked through <a\nhref=\"RSelenese.html\">SeleniumOnRails::RSelenese</a>.\n</p>\n<p>\nSee <a\nhref=\"TestBuilderActions.html\">SeleniumOnRails::TestBuilderActions</a> for\nthe available actions and <a\nhref=\"TestBuilderAccessors.html\">SeleniumOnRails::TestBuilderAccessors</a>\nfor the available checks.\n</p>\n<p>\nFor more information on the commands supported by <a\nhref=\"TestBuilder.html\">TestBuilder</a>, see the Selenium Commands\nDocumentation at <a\nhref=\"http://release.openqa.org/selenium-core/nightly/reference.html\">release.openqa.org/selenium-core/nightly/reference.html</a>.\n</p>\n\n    </div>\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000156\">collection_arg</a>&nbsp;&nbsp;\n      <a href=\"#M000151\">command</a>&nbsp;&nbsp;\n      <a href=\"#M000153\">command_and_wait</a>&nbsp;&nbsp;\n      <a href=\"#M000152\">command_verbatim</a>&nbsp;&nbsp;\n      <a href=\"#M000148\">exactize</a>&nbsp;&nbsp;\n      <a href=\"#M000154\">make_command_waiting</a>&nbsp;&nbsp;\n      <a href=\"#M000149\">new</a>&nbsp;&nbsp;\n      <a href=\"#M000147\">selenize</a>&nbsp;&nbsp;\n      <a href=\"#M000150\">table</a>&nbsp;&nbsp;\n      <a href=\"#M000155\">url_arg</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n    <div id=\"includes\">\n      <h3 class=\"section-bar\">Included Modules</h3>\n\n      <div id=\"includes-list\">\n        <span class=\"include-name\"><a href=\"TestBuilderActions.html\">SeleniumOnRails::TestBuilderActions</a></span>\n        <span class=\"include-name\"><a href=\"TestBuilderAccessors.html\">SeleniumOnRails::TestBuilderAccessors</a></span>\n        <span class=\"include-name\"><a href=\"TestBuilderUserActions.html\">SeleniumOnRails::TestBuilderUserActions</a></span>\n        <span class=\"include-name\"><a href=\"TestBuilderUserAccessors.html\">SeleniumOnRails::TestBuilderUserAccessors</a></span>\n      </div>\n    </div>\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Class methods</h3>\n\n      <div id=\"method-M000149\" class=\"method-detail\">\n        <a name=\"M000149\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000149\" class=\"method-signature\">\n          <span class=\"method-name\">new</span><span class=\"method-args\">(view)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nCreate a <a href=\"TestBuilder.html#M000149\">new</a> <a\nhref=\"TestBuilder.html\">TestBuilder</a> for <em>view</em>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000149-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000149-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder.rb, line 47</span>\n47:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">initialize</span> <span class=\"ruby-identifier\">view</span>\n48:     <span class=\"ruby-ivar\">@view</span> = <span class=\"ruby-identifier\">view</span>\n49:     <span class=\"ruby-ivar\">@output</span> = <span class=\"ruby-value str\">''</span>\n50:     <span class=\"ruby-ivar\">@xml</span> = <span class=\"ruby-constant\">Builder</span><span class=\"ruby-operator\">::</span><span class=\"ruby-constant\">XmlMarkup</span>.<span class=\"ruby-identifier\">new</span> <span class=\"ruby-identifier\">:indent</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value\">2</span>, <span class=\"ruby-identifier\">:target</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-ivar\">@output</span>\n51:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000147\" class=\"method-detail\">\n        <a name=\"M000147\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000147\" class=\"method-signature\">\n          <span class=\"method-name\">selenize</span><span class=\"method-args\">(str)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nConvert <em>str</em> to a Selenium <a\nhref=\"TestBuilder.html#M000151\">command</a> name.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000147-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000147-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder.rb, line 36</span>\n36:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-keyword kw\">self</span>.<span class=\"ruby-identifier\">selenize</span> <span class=\"ruby-identifier\">str</span>\n37:     <span class=\"ruby-identifier\">str</span>.<span class=\"ruby-identifier\">camelize</span>.<span class=\"ruby-identifier\">gsub</span>(<span class=\"ruby-regexp re\">/^[A-Z]/</span>) {<span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">s</span><span class=\"ruby-operator\">|</span> <span class=\"ruby-identifier\">s</span>.<span class=\"ruby-identifier\">downcase</span> }\n38:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000151\" class=\"method-detail\">\n        <a name=\"M000151\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000151\" class=\"method-signature\">\n          <span class=\"method-name\">command</span><span class=\"method-args\">(cmd, target=nil, value=nil)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nAdd a <a href=\"TestBuilder.html#M000149\">new</a> test <a\nhref=\"TestBuilder.html#M000151\">command</a> using <em>cmd</em>,\n<em>target</em> and <em>value</em>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000151-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000151-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder.rb, line 62</span>\n62:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">command</span> <span class=\"ruby-identifier\">cmd</span>, <span class=\"ruby-identifier\">target</span>=<span class=\"ruby-keyword kw\">nil</span>, <span class=\"ruby-identifier\">value</span>=<span class=\"ruby-keyword kw\">nil</span>\n63:     <span class=\"ruby-ivar\">@xml</span>.<span class=\"ruby-identifier\">tr</span> <span class=\"ruby-keyword kw\">do</span>\n64:       <span class=\"ruby-identifier\">_tdata</span> <span class=\"ruby-identifier\">cmd</span>\n65:       <span class=\"ruby-identifier\">_tdata</span> <span class=\"ruby-identifier\">target</span>\n66:       <span class=\"ruby-identifier\">_tdata</span> <span class=\"ruby-identifier\">value</span>\n67:     <span class=\"ruby-keyword kw\">end</span>\n68:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000153\" class=\"method-detail\">\n        <a name=\"M000153\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000153\" class=\"method-signature\">\n          <span class=\"method-name\">command_and_wait</span><span class=\"method-args\">(cmd, target=nil, value=nil)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSame as <em><a href=\"TestBuilder.html#M000151\">command</a></em> but add\n<em>AndWait</em> to the name of <em>cmd</em>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000153-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000153-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder.rb, line 73</span>\n73:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">command_and_wait</span> <span class=\"ruby-identifier\">cmd</span>, <span class=\"ruby-identifier\">target</span>=<span class=\"ruby-keyword kw\">nil</span>, <span class=\"ruby-identifier\">value</span>=<span class=\"ruby-keyword kw\">nil</span>\n74:     <span class=\"ruby-identifier\">command_verbatim</span> <span class=\"ruby-identifier\">cmd</span>.<span class=\"ruby-identifier\">to_s</span> <span class=\"ruby-operator\">+</span> <span class=\"ruby-value str\">'AndWait'</span>, <span class=\"ruby-identifier\">target</span>, <span class=\"ruby-identifier\">value</span>\n75:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000152\" class=\"method-detail\">\n        <a name=\"M000152\"></a>\n\n        <div class=\"method-heading\">\n          <span class=\"method-name\">command_verbatim</span><span class=\"method-args\">(cmd, target=nil, value=nil)</span>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nAlias for <a href=\"TestBuilder.html#M000151\">command</a>\n</p>\n        </div>\n      </div>\n\n      <div id=\"method-M000148\" class=\"method-detail\">\n        <a name=\"M000148\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000148\" class=\"method-signature\">\n          <span class=\"method-name\">exactize</span><span class=\"method-args\">(pattern)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nPrepends <em>pattern</em> with &#8216;exact:&#8217; if it would be\nconsidered containing string-match pattern otherwise.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000148-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000148-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder.rb, line 42</span>\n42:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">exactize</span> <span class=\"ruby-identifier\">pattern</span>\n43:     <span class=\"ruby-identifier\">pattern</span>.<span class=\"ruby-identifier\">include?</span>(<span class=\"ruby-value str\">':'</span>) <span class=\"ruby-operator\">?</span> <span class=\"ruby-node\">&quot;exact:#{pattern}&quot;</span> <span class=\"ruby-operator\">:</span> <span class=\"ruby-identifier\">pattern</span>\n44:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000154\" class=\"method-detail\">\n        <a name=\"M000154\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000154\" class=\"method-signature\">\n          <span class=\"method-name\">make_command_waiting</span><span class=\"method-args\">() {|| ...}</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRe routes commands in the provided block to <a\nhref=\"TestBuilder.html#M000153\">command_and_wait</a> instead of <a\nhref=\"TestBuilder.html#M000151\">command</a>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000154-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000154-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder.rb, line 79</span>\n79:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">make_command_waiting</span>\n80:     <span class=\"ruby-keyword kw\">self</span>.<span class=\"ruby-identifier\">class</span>.<span class=\"ruby-identifier\">send</span> <span class=\"ruby-identifier\">:alias_method</span>, <span class=\"ruby-identifier\">:command</span>, <span class=\"ruby-identifier\">:command_and_wait</span>\n81:     <span class=\"ruby-keyword kw\">yield</span>\n82:     <span class=\"ruby-keyword kw\">self</span>.<span class=\"ruby-identifier\">class</span>.<span class=\"ruby-identifier\">send</span> <span class=\"ruby-identifier\">:alias_method</span>, <span class=\"ruby-identifier\">:command</span>, <span class=\"ruby-identifier\">:command_verbatim</span> \n83:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000150\" class=\"method-detail\">\n        <a name=\"M000150\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000150\" class=\"method-signature\">\n          <span class=\"method-name\">table</span><span class=\"method-args\">(title) {|self| ...}</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nAdd a <a href=\"TestBuilder.html#M000149\">new</a> <a\nhref=\"TestBuilder.html#M000150\">table</a> of tests, and return the HTML.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000150-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000150-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder.rb, line 54</span>\n54:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">table</span> <span class=\"ruby-identifier\">title</span>\n55:     <span class=\"ruby-ivar\">@xml</span>.<span class=\"ruby-identifier\">table</span> <span class=\"ruby-keyword kw\">do</span>\n56:       <span class=\"ruby-ivar\">@xml</span>.<span class=\"ruby-identifier\">tr</span> <span class=\"ruby-keyword kw\">do</span> <span class=\"ruby-ivar\">@xml</span>.<span class=\"ruby-identifier\">th</span>(<span class=\"ruby-identifier\">title</span>, <span class=\"ruby-identifier\">:colspan</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value\">3</span>) <span class=\"ruby-keyword kw\">end</span>\n57:       <span class=\"ruby-keyword kw\">yield</span> <span class=\"ruby-keyword kw\">self</span>\n58:     <span class=\"ruby-keyword kw\">end</span>\n59:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <h3 class=\"section-bar\">Protected Instance methods</h3>\n\n      <div id=\"method-M000156\" class=\"method-detail\">\n        <a name=\"M000156\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000156\" class=\"method-signature\">\n          <span class=\"method-name\">collection_arg</span><span class=\"method-args\">(arg)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nIf <em>arg</em> is an array formats <em>arg</em> to a textual\nrepresentation. Otherwise return unchanged.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000156-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000156-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder.rb, line 95</span>\n 95:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">collection_arg</span> <span class=\"ruby-identifier\">arg</span>\n 96:     <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">arg</span>.<span class=\"ruby-identifier\">is_a?</span> <span class=\"ruby-constant\">Array</span>\n 97:       <span class=\"ruby-identifier\">arg</span>.<span class=\"ruby-identifier\">collect</span> {<span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">e</span><span class=\"ruby-operator\">|</span> <span class=\"ruby-identifier\">e</span>.<span class=\"ruby-identifier\">gsub</span>(<span class=\"ruby-regexp re\">/[\\\\,]/</span>) {<span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">s</span><span class=\"ruby-operator\">|</span> <span class=\"ruby-node\">&quot;\\\\#{s}&quot;</span> } }.<span class=\"ruby-identifier\">join</span>(<span class=\"ruby-value str\">','</span>)\n 98:     <span class=\"ruby-keyword kw\">else</span>\n 99:       <span class=\"ruby-identifier\">arg</span>\n100:     <span class=\"ruby-keyword kw\">end</span>\n101:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000155\" class=\"method-detail\">\n        <a name=\"M000155\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000155\" class=\"method-signature\">\n          <span class=\"method-name\">url_arg</span><span class=\"method-args\">(url)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nIf <em>url</em> is a string, return unchanged. Otherwise, pass it to\nActionView#UrlHelper#url_for.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000155-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000155-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder.rb, line 89</span>\n89:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">url_arg</span> <span class=\"ruby-identifier\">url</span>\n90:     <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">url</span>.<span class=\"ruby-identifier\">instance_of?</span>(<span class=\"ruby-constant\">String</span>) <span class=\"ruby-keyword kw\">then</span> <span class=\"ruby-identifier\">url</span> <span class=\"ruby-keyword kw\">else</span> <span class=\"ruby-identifier\">exactize</span>(<span class=\"ruby-ivar\">@view</span>.<span class=\"ruby-identifier\">url_for</span>(<span class=\"ruby-identifier\">url</span>)) <span class=\"ruby-keyword kw\">end</span>\n91:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderAccessors.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Module: SeleniumOnRails::TestBuilderAccessors</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Module</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::TestBuilderAccessors</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/test_builder_accessors_rb.html\">\n                lib/selenium_on_rails/test_builder_accessors.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nThe accessors available for <a\nhref=\"TestBuilder.html\">SeleniumOnRails::TestBuilder</a> tests.\n</p>\n<p>\nFor each <tt>store_foo</tt> there&#8216;s <tt>assert_foo</tt>,\n<tt>assert_not_foo</tt>, <tt>verify_foo</tt>, <tt>verify_not_foo</tt>,\n<tt>wait_for_foo</tt>, <tt>wait_for_not_foo</tt>.\n</p>\n\n    </div>\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000100\">store_absolute_location</a>&nbsp;&nbsp;\n      <a href=\"#M000097\">store_alert</a>&nbsp;&nbsp;\n      <a href=\"#M000091\">store_alert_present</a>&nbsp;&nbsp;\n      <a href=\"#M000134\">store_all_buttons</a>&nbsp;&nbsp;\n      <a href=\"#M000136\">store_all_fields</a>&nbsp;&nbsp;\n      <a href=\"#M000135\">store_all_links</a>&nbsp;&nbsp;\n      <a href=\"#M000088\">store_all_window_ids</a>&nbsp;&nbsp;\n      <a href=\"#M000089\">store_all_window_names</a>&nbsp;&nbsp;\n      <a href=\"#M000090\">store_all_window_titles</a>&nbsp;&nbsp;\n      <a href=\"#M000122\">store_attribute</a>&nbsp;&nbsp;\n      <a href=\"#M000092\">store_attribute_from_all_windows</a>&nbsp;&nbsp;\n      <a href=\"#M000104\">store_body_text</a>&nbsp;&nbsp;\n      <a href=\"#M000108\">store_checked</a>&nbsp;&nbsp;\n      <a href=\"#M000098\">store_confirmation</a>&nbsp;&nbsp;\n      <a href=\"#M000094\">store_confirmation_present</a>&nbsp;&nbsp;\n      <a href=\"#M000095\">store_cookie</a>&nbsp;&nbsp;\n      <a href=\"#M000096\">store_cursor_position</a>&nbsp;&nbsp;\n      <a href=\"#M000133\">store_editable</a>&nbsp;&nbsp;\n      <a href=\"#M000127\">store_element_height</a>&nbsp;&nbsp;\n      <a href=\"#M000128\">store_element_index</a>&nbsp;&nbsp;\n      <a href=\"#M000130\">store_element_position_left</a>&nbsp;&nbsp;\n      <a href=\"#M000131\">store_element_position_top</a>&nbsp;&nbsp;\n      <a href=\"#M000125\">store_element_present</a>&nbsp;&nbsp;\n      <a href=\"#M000129\">store_element_width</a>&nbsp;&nbsp;\n      <a href=\"#M000086\">store_error_on_next</a>&nbsp;&nbsp;\n      <a href=\"#M000107\">store_eval</a>&nbsp;&nbsp;\n      <a href=\"#M000138\">store_expression</a>&nbsp;&nbsp;\n      <a href=\"#M000087\">store_failure_on_next</a>&nbsp;&nbsp;\n      <a href=\"#M000137\">store_html_source</a>&nbsp;&nbsp;\n      <a href=\"#M000101\">store_location</a>&nbsp;&nbsp;\n      <a href=\"#M000132\">store_log_messages</a>&nbsp;&nbsp;\n      <a href=\"#M000102\">store_mouse_speed</a>&nbsp;&nbsp;\n      <a href=\"#M000123\">store_ordered</a>&nbsp;&nbsp;\n      <a href=\"#M000099\">store_prompt</a>&nbsp;&nbsp;\n      <a href=\"#M000093\">store_prompt_present</a>&nbsp;&nbsp;\n      <a href=\"#M000121\">store_select_options</a>&nbsp;&nbsp;\n      <a href=\"#M000110\">store_selected</a>&nbsp;&nbsp;\n      <a href=\"#M000111\">store_selected_id</a>&nbsp;&nbsp;\n      <a href=\"#M000112\">store_selected_ids</a>&nbsp;&nbsp;\n      <a href=\"#M000113\">store_selected_index</a>&nbsp;&nbsp;\n      <a href=\"#M000114\">store_selected_indexes</a>&nbsp;&nbsp;\n      <a href=\"#M000115\">store_selected_label</a>&nbsp;&nbsp;\n      <a href=\"#M000116\">store_selected_labels</a>&nbsp;&nbsp;\n      <a href=\"#M000120\">store_selected_options</a>&nbsp;&nbsp;\n      <a href=\"#M000117\">store_selected_value</a>&nbsp;&nbsp;\n      <a href=\"#M000118\">store_selected_values</a>&nbsp;&nbsp;\n      <a href=\"#M000119\">store_something_selected</a>&nbsp;&nbsp;\n      <a href=\"#M000109\">store_table</a>&nbsp;&nbsp;\n      <a href=\"#M000106\">store_text</a>&nbsp;&nbsp;\n      <a href=\"#M000124\">store_text_present</a>&nbsp;&nbsp;\n      <a href=\"#M000103\">store_title</a>&nbsp;&nbsp;\n      <a href=\"#M000105\">store_value</a>&nbsp;&nbsp;\n      <a href=\"#M000126\">store_visible</a>&nbsp;&nbsp;\n      <a href=\"#M000139\">store_whether_this_frame_match_frame_expression</a>&nbsp;&nbsp;\n      <a href=\"#M000140\">store_whether_this_window_match_window_expression</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000100\" class=\"method-detail\">\n        <a name=\"M000100\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000100\" class=\"method-signature\">\n          <span class=\"method-name\">store_absolute_location</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets the absolute URL of the current page.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_absolute_location(pattern)</tt>\n\n</li>\n<li><tt>assert_not_absolute_location(pattern)</tt>\n\n</li>\n<li><tt>verify_absolute_location_present(pattern)</tt>\n\n</li>\n<li><tt>verify_not_absolute_location(pattern)</tt>\n\n</li>\n<li><tt>wait_for_absolute_location(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_absolute_location(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000100-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000100-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 246</span>\n246:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_absolute_location</span> <span class=\"ruby-identifier\">variable_name</span>\n247:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeAbsoluteLocation'</span>, <span class=\"ruby-identifier\">variable_name</span>\n248:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000097\" class=\"method-detail\">\n        <a name=\"M000097\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000097\" class=\"method-signature\">\n          <span class=\"method-name\">store_alert</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRetrieves the message of a JavaScript alert generated during the previous\naction, or fail if there were no alerts.\n</p>\n<p>\nGetting an alert has the same effect as manually clicking OK. If an alert\nis generated but you do not get/verify it, the next Selenium action will\nfail.\n</p>\n<p>\nNOTE: under Selenium, JavaScript alerts will NOT pop up a visible alert\ndialog.\n</p>\n<p>\nNOTE: Selenium does NOT support JavaScript alerts that are generated in a\npage&#8216;s <tt>onload()</tt> event handler. In this case a visible dialog\nWILL be generated and Selenium will hang until someone manually clicks OK.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_alert(pattern)</tt>\n\n</li>\n<li><tt>assert_not_alert(pattern)</tt>\n\n</li>\n<li><tt>verify_alert_present(pattern)</tt>\n\n</li>\n<li><tt>verify_not_alert(pattern)</tt>\n\n</li>\n<li><tt>wait_for_alert(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_alert(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000097-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000097-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 183</span>\n183:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_alert</span> <span class=\"ruby-identifier\">variable_name</span>\n184:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeAlert'</span>, <span class=\"ruby-identifier\">variable_name</span>\n185:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000091\" class=\"method-detail\">\n        <a name=\"M000091\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000091\" class=\"method-signature\">\n          <span class=\"method-name\">store_alert_present</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nHas an alert occurred?\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_alert_present</tt>\n\n</li>\n<li><tt>assert_alert_not_present</tt>\n\n</li>\n<li><tt>verify_alert_present</tt>\n\n</li>\n<li><tt>verify_alert_not_present</tt>\n\n</li>\n<li><tt>wait_for_alert_present</tt>\n\n</li>\n<li><tt>wait_for_alert_not_present</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000091-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000091-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 89</span>\n89:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_alert_present</span> <span class=\"ruby-identifier\">variable_name</span>\n90:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeAlertPresent'</span>, <span class=\"ruby-identifier\">variable_name</span>\n91:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000134\" class=\"method-detail\">\n        <a name=\"M000134\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000134\" class=\"method-signature\">\n          <span class=\"method-name\">store_all_buttons</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturns the IDs of all buttons on the page.\n</p>\n<p>\nIf a given button has no ID, it will appear as &quot;&quot; in this array.\n</p>\n<p>\nThe <tt>pattern</tt> for the automatically generated assertions can either\ntake an array or a pattern.\n</p>\n<pre>\n assert_all_buttons ['but1', 'but2']\n assert_all_buttons 'but?,but?*'\n</pre>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_all_buttons(pattern)</tt>\n\n</li>\n<li><tt>assert_not_all_buttons(pattern)</tt>\n\n</li>\n<li><tt>verify_all_buttons(pattern)</tt>\n\n</li>\n<li><tt>verify_not_all_buttons(pattern)</tt>\n\n</li>\n<li><tt>wait_for_all_buttons(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_all_buttons(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000134-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000134-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 754</span>\n754:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_all_buttons</span> <span class=\"ruby-identifier\">variable_name</span>\n755:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeAllButtons'</span>, <span class=\"ruby-identifier\">variable_name</span>\n756:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000136\" class=\"method-detail\">\n        <a name=\"M000136\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000136\" class=\"method-signature\">\n          <span class=\"method-name\">store_all_fields</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturns the IDs of all input fields on the page.\n</p>\n<p>\nIf a given field has no ID, it will appear as &quot;&quot; in this array.\n</p>\n<p>\nThe <tt>pattern</tt> for the automatically generated assertions can either\ntake an array or a pattern.\n</p>\n<pre>\n assert_all_fields ['field1', 'field2']\n assert_all_fields 'field?,field?*'\n</pre>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_all_fields(pattern)</tt>\n\n</li>\n<li><tt>assert_not_all_fields(pattern)</tt>\n\n</li>\n<li><tt>verify_all_fields(pattern)</tt>\n\n</li>\n<li><tt>verify_not_all_fields(pattern)</tt>\n\n</li>\n<li><tt>wait_for_all_fields(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_all_fields(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000136-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000136-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 794</span>\n794:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_all_fields</span> <span class=\"ruby-identifier\">variable_name</span>\n795:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeAllFields'</span>, <span class=\"ruby-identifier\">variable_name</span>\n796:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000135\" class=\"method-detail\">\n        <a name=\"M000135\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000135\" class=\"method-signature\">\n          <span class=\"method-name\">store_all_links</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturns the IDs of all links on the page.\n</p>\n<p>\nIf a given link has no ID, it will appear as &quot;&quot; in this array.\n</p>\n<p>\nThe <tt>pattern</tt> for the automatically generated assertions can either\ntake an array or a pattern.\n</p>\n<pre>\n assert_all_links ['link1', 'link2']\n assert_all_links 'link?,link?*'\n</pre>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_all_links(pattern)</tt>\n\n</li>\n<li><tt>assert_not_all_links(pattern)</tt>\n\n</li>\n<li><tt>verify_all_links(pattern)</tt>\n\n</li>\n<li><tt>verify_not_all_links(pattern)</tt>\n\n</li>\n<li><tt>wait_for_all_links(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_all_links(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000135-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000135-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 774</span>\n774:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_all_links</span> <span class=\"ruby-identifier\">variable_name</span>\n775:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeAllLinks'</span>, <span class=\"ruby-identifier\">variable_name</span>\n776:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000088\" class=\"method-detail\">\n        <a name=\"M000088\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000088\" class=\"method-signature\">\n          <span class=\"method-name\">store_all_window_ids</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturns the IDs of all windows that the browser knows about.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assertAllWindowIds(pattern)</tt>\n\n</li>\n<li><tt>assertNotAllWindowIds(pattern)</tt>\n\n</li>\n<li><tt>verifyAllWindowIds(pattern)</tt>\n\n</li>\n<li><tt>verifyNotAllWindowIds(pattern)</tt>\n\n</li>\n<li><tt>waitForAllWindowIds(pattern)</tt>\n\n</li>\n<li><tt>waitForNotAllWindowIds(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000088-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000088-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 50</span>\n50:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_all_window_ids</span> <span class=\"ruby-identifier\">variable_name</span>\n51:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeAllWindowIds'</span>, <span class=\"ruby-identifier\">variable_name</span>\n52:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000089\" class=\"method-detail\">\n        <a name=\"M000089\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000089\" class=\"method-signature\">\n          <span class=\"method-name\">store_all_window_names</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturns the names of all windows that the browser knows about.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assertAllWindowNames(pattern)</tt>\n\n</li>\n<li><tt>assertNotAllWindowNames(pattern)</tt>\n\n</li>\n<li><tt>verifyAllWindowNames(pattern)</tt>\n\n</li>\n<li><tt>verifyNotAllWindowNames(pattern)</tt>\n\n</li>\n<li><tt>waitForAllWindowNames(pattern)</tt>\n\n</li>\n<li><tt>waitForNotAllWindowNames(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000089-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000089-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 63</span>\n63:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_all_window_names</span> <span class=\"ruby-identifier\">variable_name</span>\n64:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeAllWindowNames'</span>, <span class=\"ruby-identifier\">variable_name</span>\n65:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000090\" class=\"method-detail\">\n        <a name=\"M000090\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000090\" class=\"method-signature\">\n          <span class=\"method-name\">store_all_window_titles</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturns the titles of all windows that the browser knows about.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assertAllWindowTitles(pattern)</tt>\n\n</li>\n<li><tt>assertNotAllWindowTitles(pattern)</tt>\n\n</li>\n<li><tt>verifyAllWindowTitles(pattern)</tt>\n\n</li>\n<li><tt>verifyNotAllWindowTitles(pattern)</tt>\n\n</li>\n<li><tt>waitForAllWindowTitles(pattern)</tt>\n\n</li>\n<li><tt>waitForNotAllWindowTitles(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000090-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000090-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 76</span>\n76:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_all_window_titles</span> <span class=\"ruby-identifier\">variable_name</span>\n77:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeAllWindowTitles'</span>, <span class=\"ruby-identifier\">variable_name</span>\n78:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000122\" class=\"method-detail\">\n        <a name=\"M000122\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000122\" class=\"method-signature\">\n          <span class=\"method-name\">store_attribute</span><span class=\"method-args\">(locator, attribute_name, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets the value of an element attribute.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_attribute(locator, attribute_name, pattern)</tt>\n\n</li>\n<li><tt>assert_not_attribute(locator, attribute_name, pattern)</tt>\n\n</li>\n<li><tt>verify_attribute_present(locator, attribute_name, pattern)</tt>\n\n</li>\n<li><tt>verify_not_attribute(locator, attribute_name, pattern)</tt>\n\n</li>\n<li><tt>wait_for_attribute(locator, attribute_name, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_attribute(locator, attribute_name, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000122-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000122-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 577</span>\n577:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_attribute</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">attribute_name</span>, <span class=\"ruby-identifier\">variable_name</span>\n578:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeAttribute'</span>, <span class=\"ruby-node\">&quot;#{locator}@#{attribute_name}&quot;</span>, <span class=\"ruby-identifier\">variable_name</span>\n579:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000092\" class=\"method-detail\">\n        <a name=\"M000092\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000092\" class=\"method-signature\">\n          <span class=\"method-name\">store_attribute_from_all_windows</span><span class=\"method-args\">(attribute_name, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturns every instance of some attribute from all known windows.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_attribute_from_all_windows(attribute_name, pattern)</tt>\n\n</li>\n<li><tt>assert_not_attribute_from_all_windows(attribute_name, pattern)</tt>\n\n</li>\n<li><tt>verify_attribute_from_all_windows(attribute_name, pattern)</tt>\n\n</li>\n<li><tt>verify_not_attribute_from_all_windows(attribute_name, pattern)</tt>\n\n</li>\n<li><tt>wait_for_attribute_from_all_windows(attribute_name, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_attribute_from_all_windows(attribute_name, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000092-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000092-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 102</span>\n102:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_attribute_from_all_windows</span> <span class=\"ruby-identifier\">attribute_name</span>, <span class=\"ruby-identifier\">variable_name</span>\n103:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeAttributeFromAllWindows'</span>, <span class=\"ruby-identifier\">attribute_name</span>, <span class=\"ruby-identifier\">variable_name</span>\n104:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000104\" class=\"method-detail\">\n        <a name=\"M000104\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000104\" class=\"method-signature\">\n          <span class=\"method-name\">store_body_text</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets the entire text of the page.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_body_text(pattern)</tt>\n\n</li>\n<li><tt>assert_not_body_text(pattern)</tt>\n\n</li>\n<li><tt>verify_body_text_present(pattern)</tt>\n\n</li>\n<li><tt>verify_not_body_text(pattern)</tt>\n\n</li>\n<li><tt>wait_for_body_text(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_body_text(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000104-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000104-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 300</span>\n300:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_body_text</span> <span class=\"ruby-identifier\">variable_name</span>\n301:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeBodyText'</span>, <span class=\"ruby-identifier\">variable_name</span>\n302:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000108\" class=\"method-detail\">\n        <a name=\"M000108\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000108\" class=\"method-signature\">\n          <span class=\"method-name\">store_checked</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets whether a toggle-button (checkbox/radio) is checked. Fails if the\nspecified element doesn&#8216;t exist or isn&#8216;t a toggle-button.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_checked(locator)</tt>\n\n</li>\n<li><tt>assert_not_checked(locator)</tt>\n\n</li>\n<li><tt>verify_checked_present(locator)</tt>\n\n</li>\n<li><tt>verify_not_checked(locator)</tt>\n\n</li>\n<li><tt>wait_for_checked(locator)</tt>\n\n</li>\n<li><tt>wait_for_not_checked(locator)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000108-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000108-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 370</span>\n370:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_checked</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n371:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeChecked'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n372:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000098\" class=\"method-detail\">\n        <a name=\"M000098\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000098\" class=\"method-signature\">\n          <span class=\"method-name\">store_confirmation</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRetrieves the message of a JavaScript confirmation dialog generated during\nthe previous action.\n</p>\n<p>\nBy default, the confirm function will return <tt>true</tt>, having the same\neffect as manually clicking OK. This can be changed by prior execution of\nthe <tt>choose_cancel_on_next_confirmation</tt> command. If a confirmation\nis generated but you do not get/verify it, the next Selenium action will\nfail.\n</p>\n<p>\nNOTE: under Selenium, JavaScript confirmations will NOT pop up a visible\ndialog.\n</p>\n<p>\nNOTE: Selenium does NOT support JavaScript confirmations that are generated\nin a page&#8216;s <tt>onload()</tt> event handler. In this case a visible\ndialog WILL be generated and Selenium will hang until you manually click\nOK.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_confirmation(pattern)</tt>\n\n</li>\n<li><tt>assert_not_confirmation(pattern)</tt>\n\n</li>\n<li><tt>verify_confirmation_present(pattern)</tt>\n\n</li>\n<li><tt>verify_not_confirmation(pattern)</tt>\n\n</li>\n<li><tt>wait_for_confirmation(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_confirmation(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000098-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000098-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 209</span>\n209:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_confirmation</span> <span class=\"ruby-identifier\">variable_name</span>\n210:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeConfirmation'</span>, <span class=\"ruby-identifier\">variable_name</span>\n211:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000094\" class=\"method-detail\">\n        <a name=\"M000094\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000094\" class=\"method-signature\">\n          <span class=\"method-name\">store_confirmation_present</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nHas <tt>confirm()</tt> been called?\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_confirmation_present</tt>\n\n</li>\n<li><tt>assert_confirmation_not_present</tt>\n\n</li>\n<li><tt>verify_confirmation_present</tt>\n\n</li>\n<li><tt>verify_confirmation_not_present</tt>\n\n</li>\n<li><tt>wait_for_confirmation_present</tt>\n\n</li>\n<li><tt>wait_for_confirmation_not_present</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000094-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000094-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 128</span>\n128:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_confirmation_present</span> <span class=\"ruby-identifier\">variable_name</span>\n129:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeConfirmationPresent'</span>, <span class=\"ruby-identifier\">variable_name</span>\n130:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000095\" class=\"method-detail\">\n        <a name=\"M000095\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000095\" class=\"method-signature\">\n          <span class=\"method-name\">store_cookie</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturn all cookies of the current page under test.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_cookie(pattern)</tt>\n\n</li>\n<li><tt>assert_not_cookie(pattern)</tt>\n\n</li>\n<li><tt>verify_cookie(pattern)</tt>\n\n</li>\n<li><tt>verify_not_cookie(pattern)</tt>\n\n</li>\n<li><tt>wait_for_cookie(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_cookie(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000095-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000095-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 141</span>\n141:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_cookie</span> <span class=\"ruby-identifier\">variable_name</span>\n142:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeCookie'</span>, <span class=\"ruby-identifier\">variable_name</span>\n143:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000096\" class=\"method-detail\">\n        <a name=\"M000096\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000096\" class=\"method-signature\">\n          <span class=\"method-name\">store_cursor_position</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRetrieves the text cursor position in the given input element or textarea;\nbeware, this may not work perfectly on all browsers.\n</p>\n<p>\nThis method will fail if the specified element isn&#8216;t an input element\nor textarea, or there is no cursor in the element.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_cursor_position(locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_cursor_position(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_cursor_position(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_cursor_position(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_cursor_position(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_cursor_position(locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000096-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000096-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 158</span>\n158:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_cursor_position</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n159:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeCursorPosition'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n160:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000133\" class=\"method-detail\">\n        <a name=\"M000133\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000133\" class=\"method-signature\">\n          <span class=\"method-name\">store_editable</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nDetermines whether the specified input element is editable, i.e.\nhasn&#8216;t been disabled. This method will fail if the specified element\nisn&#8216;t an input element.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_editable(locator)</tt>\n\n</li>\n<li><tt>assert_not_editable(locator)</tt>\n\n</li>\n<li><tt>verify_editable(locator)</tt>\n\n</li>\n<li><tt>verify_not_editable(locator)</tt>\n\n</li>\n<li><tt>wait_for_editable(locator)</tt>\n\n</li>\n<li><tt>wait_for_not_editable(locator)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000133-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000133-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 734</span>\n734:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_editable</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n735:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeEditable'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n736:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000127\" class=\"method-detail\">\n        <a name=\"M000127\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000127\" class=\"method-signature\">\n          <span class=\"method-name\">store_element_height</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRetrieves the height of an element. This method will fail if the element is\nnot present.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_element_height(locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_element_height(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_element_height(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_element_height(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_element_height(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_element_height(locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000127-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000127-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 650</span>\n650:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_element_height</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n651:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeElementHeight'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n652:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000128\" class=\"method-detail\">\n        <a name=\"M000128\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000128\" class=\"method-signature\">\n          <span class=\"method-name\">store_element_index</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGet the relative index of an element to its parent (starting from 0). The\ncomment node and empty text node will be ignored.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_element_index(locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_element_index(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_element_index(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_element_index(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_element_index(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_element_index(locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000128-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000128-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 664</span>\n664:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_element_index</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n665:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeElementIndex'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n666:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000130\" class=\"method-detail\">\n        <a name=\"M000130\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000130\" class=\"method-signature\">\n          <span class=\"method-name\">store_element_position_left</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRetrieves the horizontal position of an element. This method will fail if\nthe element is not present.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_element_position_left(locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_element_position_left(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_element_position_left(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_element_position_left(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_element_position_left(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_element_position_left(locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000130-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000130-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 692</span>\n692:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_element_position_left</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n693:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeElementPositionLeft'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n694:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000131\" class=\"method-detail\">\n        <a name=\"M000131\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000131\" class=\"method-signature\">\n          <span class=\"method-name\">store_element_position_top</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRetrieves the vertical position of an element. This method will fail if the\nelement is not present.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_element_position_top(locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_element_position_top(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_element_position_top(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_element_position_top(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_element_position_top(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_element_position_top(locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000131-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000131-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 706</span>\n706:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_element_position_top</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n707:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeElementPositionTop'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n708:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000125\" class=\"method-detail\">\n        <a name=\"M000125\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000125\" class=\"method-signature\">\n          <span class=\"method-name\">store_element_present</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nVerifies that the specified element is somewhere on the page.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_element_present(locator)</tt>\n\n</li>\n<li><tt>assert_element_not_present(locator)</tt>\n\n</li>\n<li><tt>verify_element_present(locator)</tt>\n\n</li>\n<li><tt>verify_element_not_present(locator)</tt>\n\n</li>\n<li><tt>wait_for_element_present(locator)</tt>\n\n</li>\n<li><tt>wait_for_element_not_present(locator)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000125-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000125-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 620</span>\n620:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_element_present</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n621:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeElementPresent'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n622:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000129\" class=\"method-detail\">\n        <a name=\"M000129\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000129\" class=\"method-signature\">\n          <span class=\"method-name\">store_element_width</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRetrieves the width of an element. This method will fail if the element is\nnot present.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_element_width(locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_element_width(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_element_width(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_element_width(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_element_width(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_element_width(locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000129-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000129-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 678</span>\n678:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_element_width</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n679:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeElementWidth'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n680:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000086\" class=\"method-detail\">\n        <a name=\"M000086\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000086\" class=\"method-signature\">\n          <span class=\"method-name\">store_error_on_next</span><span class=\"method-args\">(message)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nTell Selenium to expect an error on the next command execution.\n</p>\n<p>\nNOTE: <tt><a\nhref=\"TestBuilderAccessors.html#M000086\">store_error_on_next</a></tt> is\ncurrently not supported by Selenium Core and is only added to here as a\nshortcut for generating the related assertions.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_error_on_next(message)</tt>\n\n</li>\n<li><tt>assert_not_error_on_next(message)</tt>\n\n</li>\n<li><tt>verify_error_on_next(message)</tt>\n\n</li>\n<li><tt>verify_not_error_on_next(message)</tt>\n\n</li>\n<li><tt>wait_for_error_on_next(message)</tt>\n\n</li>\n<li><tt>wait_for_not_error_on_next(message)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000086-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000086-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 20</span>\n20:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_error_on_next</span> <span class=\"ruby-identifier\">message</span>\n21:     <span class=\"ruby-identifier\">raise</span> <span class=\"ruby-value str\">'Not supported in Selenium Core at the moment'</span>\n22:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000107\" class=\"method-detail\">\n        <a name=\"M000107\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000107\" class=\"method-signature\">\n          <span class=\"method-name\">store_eval</span><span class=\"method-args\">(script, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets the result of evaluating the specified JavaScript snippet. The snippet\nmay have multiple lines, but only the result of the last line will be\nreturned.\n</p>\n<p>\nNote that, by default, the snippet will run in the context of the\n&quot;selenium&quot; object itself, so <tt>this</tt> will refer to the\nSelenium object, and <tt>window</tt> will refer to the top-level runner\ntest window, not the window of your application.\n</p>\n<p>\nIf you need a reference to the window of your application, you can refer to\n<tt>this.browserbot.getCurrentWindow()</tt> and if you need to use a\nlocator to refer to a single element in your application page, you can use\n<tt>this.page().findElement(&quot;foo&quot;)</tt> where\n<tt>&quot;foo&quot;</tt> is your locator.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_eval(script, pattern)</tt>\n\n</li>\n<li><tt>assert_not_eval(script, pattern)</tt>\n\n</li>\n<li><tt>verify_eval_present(script, pattern)</tt>\n\n</li>\n<li><tt>verify_not_eval(script, pattern)</tt>\n\n</li>\n<li><tt>wait_for_eval(script, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_eval(script, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000107-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000107-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 356</span>\n356:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_eval</span> <span class=\"ruby-identifier\">script</span>, <span class=\"ruby-identifier\">variable_name</span>\n357:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeEval'</span>, <span class=\"ruby-identifier\">script</span>, <span class=\"ruby-identifier\">variable_name</span>\n358:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000138\" class=\"method-detail\">\n        <a name=\"M000138\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000138\" class=\"method-signature\">\n          <span class=\"method-name\">store_expression</span><span class=\"method-args\">(expression, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturns the specified expression.\n</p>\n<p>\nThis is useful because of JavaScript preprocessing.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_expression(expression, pattern)</tt>\n\n</li>\n<li><tt>assert_not_expression(expression, pattern)</tt>\n\n</li>\n<li><tt>verify_expression(expression, pattern)</tt>\n\n</li>\n<li><tt>verify_not_expression(expression, pattern)</tt>\n\n</li>\n<li><tt>wait_for_expression(expression, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_expression(expression, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000138-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000138-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 822</span>\n822:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_expression</span> <span class=\"ruby-identifier\">expression</span>, <span class=\"ruby-identifier\">variable_name</span>\n823:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeExpression'</span>, <span class=\"ruby-identifier\">expression</span>, <span class=\"ruby-identifier\">variable_name</span>\n824:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000087\" class=\"method-detail\">\n        <a name=\"M000087\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000087\" class=\"method-signature\">\n          <span class=\"method-name\">store_failure_on_next</span><span class=\"method-args\">(message)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nTell Selenium to expect a failure on the next command execution.\n</p>\n<p>\nNOTE: <tt><a\nhref=\"TestBuilderAccessors.html#M000087\">store_failure_on_next</a></tt> is\ncurrently not supported by Selenium Core and is only added to here as a\nshortcut for generating the related assertions.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_failure_on_next(message)</tt>\n\n</li>\n<li><tt>assert_not_failure_on_next(message)</tt>\n\n</li>\n<li><tt>verify_failure_on_next(message)</tt>\n\n</li>\n<li><tt>verify_not_failure_on_next(message)</tt>\n\n</li>\n<li><tt>wait_for_failure_on_next(message)</tt>\n\n</li>\n<li><tt>wait_for_not_failure_on_next(message)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000087-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000087-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 37</span>\n37:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_failure_on_next</span> <span class=\"ruby-identifier\">message</span>\n38:     <span class=\"ruby-identifier\">raise</span> <span class=\"ruby-value str\">'Not supported in Selenium Core at the moment'</span>\n39:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000137\" class=\"method-detail\">\n        <a name=\"M000137\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000137\" class=\"method-signature\">\n          <span class=\"method-name\">store_html_source</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturns the entire HTML source between the opening and closing\n&quot;html&quot; tags.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_html_source(pattern)</tt>\n\n</li>\n<li><tt>assert_not_html_source(pattern)</tt>\n\n</li>\n<li><tt>verify_html_source(pattern)</tt>\n\n</li>\n<li><tt>verify_not_html_source(pattern)</tt>\n\n</li>\n<li><tt>wait_for_html_source(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_html_source(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000137-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000137-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 807</span>\n807:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_html_source</span> <span class=\"ruby-identifier\">variable_name</span>\n808:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeHtmlSource'</span>, <span class=\"ruby-identifier\">variable_name</span>\n809:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000101\" class=\"method-detail\">\n        <a name=\"M000101\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000101\" class=\"method-signature\">\n          <span class=\"method-name\">store_location</span><span class=\"method-args\">(expected_location, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nVerify the location of the current page ends with the expected location. If\nan URL querystring is provided, this is checked as well.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_location(pattern)</tt>\n\n</li>\n<li><tt>assert_not_location(pattern)</tt>\n\n</li>\n<li><tt>verify_location_present(pattern)</tt>\n\n</li>\n<li><tt>verify_not_location(pattern)</tt>\n\n</li>\n<li><tt>wait_for_location(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_location(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000101-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000101-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 260</span>\n260:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_location</span> <span class=\"ruby-identifier\">expected_location</span>, <span class=\"ruby-identifier\">variable_name</span>\n261:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeLocation'</span>, <span class=\"ruby-identifier\">expected_location</span>, <span class=\"ruby-identifier\">variable_name</span>\n262:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000132\" class=\"method-detail\">\n        <a name=\"M000132\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000132\" class=\"method-signature\">\n          <span class=\"method-name\">store_log_messages</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturn the contents of the log.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_log_messages(pattern)</tt>\n\n</li>\n<li><tt>assert_not_log_messages(pattern)</tt>\n\n</li>\n<li><tt>verify_log_messages(pattern)</tt>\n\n</li>\n<li><tt>verify_not_log_messages(pattern)</tt>\n\n</li>\n<li><tt>wait_for_log_messages(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_log_messages(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000132-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000132-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 719</span>\n719:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_log_messages</span> <span class=\"ruby-identifier\">variable_name</span>\n720:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeLogMessages'</span>, <span class=\"ruby-identifier\">variable_name</span>\n721:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000102\" class=\"method-detail\">\n        <a name=\"M000102\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000102\" class=\"method-signature\">\n          <span class=\"method-name\">store_mouse_speed</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nReturns the number of pixels between &quot;mousemove&quot; events during\ndrag_and_drop commands (default=10).\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_mouse_speed(pattern)</tt>\n\n</li>\n<li><tt>assert_not_mouse_speed(pattern)</tt>\n\n</li>\n<li><tt>verify_mouse_speed(pattern)</tt>\n\n</li>\n<li><tt>verify_not_mouse_speed(pattern)</tt>\n\n</li>\n<li><tt>wait_for_mouse_speed(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_mouse_speed(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000102-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000102-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 274</span>\n274:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_mouse_speed</span> <span class=\"ruby-identifier\">variable_name</span>\n275:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeMouseSpeed'</span>, <span class=\"ruby-identifier\">variable_name</span>\n276:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000123\" class=\"method-detail\">\n        <a name=\"M000123\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000123\" class=\"method-signature\">\n          <span class=\"method-name\">store_ordered</span><span class=\"method-args\">(locator_1, locator_2, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nCheck if these two elements have same parent and are ordered. Two same\nelements will not be considered ordered.\n</p>\n<p>\nNOTE: <tt><a\nhref=\"TestBuilderAccessors.html#M000123\">store_ordered</a></tt> is\ncurrently not supported by Selenium Core.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_ordered(locator_1, locator_2)</tt>\n\n</li>\n<li><tt>assert_not_ordered(locator_1, locator_2)</tt>\n\n</li>\n<li><tt>verify_ordered(locator_1, locator_2)</tt>\n\n</li>\n<li><tt>verify_not_ordered(locator_1, locator_2)</tt>\n\n</li>\n<li><tt>wait_for_ordered(locator_1, locator_2)</tt>\n\n</li>\n<li><tt>wait_for_not_ordered(locator_1, locator_2)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000123-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000123-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 593</span>\n593:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_ordered</span> <span class=\"ruby-identifier\">locator_1</span>, <span class=\"ruby-identifier\">locator_2</span>, <span class=\"ruby-identifier\">variable_name</span>\n594:     <span class=\"ruby-identifier\">raise</span> <span class=\"ruby-value str\">'Not supported in Selenium Core at the moment'</span>\n595:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000099\" class=\"method-detail\">\n        <a name=\"M000099\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000099\" class=\"method-signature\">\n          <span class=\"method-name\">store_prompt</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRetrieves the message of a JavaScript question prompt dialog generated\nduring the previous action.\n</p>\n<p>\nSuccessful handling of the prompt requires prior execution of the\n<tt>answer_on_next_prompt</tt> command. If a prompt is generated but you do\nnot get/verify it, the next Selenium action will fail.\n</p>\n<p>\nNOTE: under Selenium, JavaScript prompts will NOT pop up a visible dialog.\n</p>\n<p>\nNOTE: Selenium does NOT support JavaScript prompts that are generated in a\npage&#8216;s <tt>onload()</tt> event handler. In this case a visible dialog\nWILL be generated and Selenium will hang until someone manually clicks OK.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_prompt(pattern)</tt>\n\n</li>\n<li><tt>assert_not_prompt(pattern)</tt>\n\n</li>\n<li><tt>verify_prompt_present(pattern)</tt>\n\n</li>\n<li><tt>verify_not_prompt(pattern)</tt>\n\n</li>\n<li><tt>wait_for_prompt(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_prompt(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000099-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000099-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 233</span>\n233:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_prompt</span> <span class=\"ruby-identifier\">variable_name</span>\n234:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storePrompt'</span>, <span class=\"ruby-identifier\">variable_name</span>\n235:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000093\" class=\"method-detail\">\n        <a name=\"M000093\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000093\" class=\"method-signature\">\n          <span class=\"method-name\">store_prompt_present</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nHas a prompt occurred?\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_prompt_present</tt>\n\n</li>\n<li><tt>assert_prompt_not_present</tt>\n\n</li>\n<li><tt>verify_prompt_present</tt>\n\n</li>\n<li><tt>verify_prompt_not_present</tt>\n\n</li>\n<li><tt>wait_for_prompt_present</tt>\n\n</li>\n<li><tt>wait_for_prompt_not_present</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000093-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000093-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 115</span>\n115:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_prompt_present</span> <span class=\"ruby-identifier\">variable_name</span>\n116:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storePromptPresent'</span>, <span class=\"ruby-identifier\">variable_name</span>\n117:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000121\" class=\"method-detail\">\n        <a name=\"M000121\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000121\" class=\"method-signature\">\n          <span class=\"method-name\">store_select_options</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets all option labels in the specified select drop-down.\n</p>\n<p>\nThe <tt>pattern</tt> for the automatically generated assertions can either\ntake an array or a pattern.\n</p>\n<pre>\n assert_select_options 'fruits', ['apple', 'pear']\n assert_select_options 'fruits', 'a*,p*'\n</pre>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_select_options(locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_select_options(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_select_options_present(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_select_options(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_select_options(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_select_options(locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000121-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000121-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 564</span>\n564:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_select_options</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n565:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeSelectOptions'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n566:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000110\" class=\"method-detail\">\n        <a name=\"M000110\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000110\" class=\"method-signature\">\n          <span class=\"method-name\">store_selected</span><span class=\"method-args\">(locator, option_locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nVerifies that the selected option of a drop-down satisfies the\n<tt>option_locator</tt>.\n</p>\n<p>\n<tt>option_locator</tt> is typically just an option label (e.g. &quot;John\nSmith&quot;).\n</p>\n<p>\nSee the <tt>select</tt> command for more information about option locators.\n</p>\n<p>\nNOTE: <tt><a\nhref=\"TestBuilderAccessors.html#M000110\">store_selected</a></tt> is\ncurrently not supported by Selenium Core.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_selected(locator, option_locator)</tt>\n\n</li>\n<li><tt>assert_not_selected(locator, option_locator)</tt>\n\n</li>\n<li><tt>verify_selected_present(locator, option_locator)</tt>\n\n</li>\n<li><tt>verify_not_selected(locator, option_locator)</tt>\n\n</li>\n<li><tt>wait_for_selected(locator, option_locator)</tt>\n\n</li>\n<li><tt>wait_for_not_selected(locator, option_locator)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000110-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000110-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 403</span>\n403:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_selected</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">option_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n404:     <span class=\"ruby-identifier\">raise</span> <span class=\"ruby-value str\">'Not supported in Selenium Core at the moment'</span>\n405:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000111\" class=\"method-detail\">\n        <a name=\"M000111\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000111\" class=\"method-signature\">\n          <span class=\"method-name\">store_selected_id</span><span class=\"method-args\">(select_locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets option element ID for selected option in the specified select element.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_selected_id(select_locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_selected_id(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_selected_id(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_selected_id(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_selected_id(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_selected_id(select_locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000111-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000111-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 416</span>\n416:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_selected_id</span> <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n417:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeSelectedId'</span>, <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n418:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000112\" class=\"method-detail\">\n        <a name=\"M000112\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000112\" class=\"method-signature\">\n          <span class=\"method-name\">store_selected_ids</span><span class=\"method-args\">(select_locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets all option element IDs for selected options in the specified select or\nmulti-select element.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_selected_ids(select_locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_selected_ids(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_selected_ids(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_selected_ids(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_selected_ids(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_selected_ids(select_locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000112-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000112-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 430</span>\n430:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_selected_ids</span> <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n431:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeSelectedIds'</span>, <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n432:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000113\" class=\"method-detail\">\n        <a name=\"M000113\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000113\" class=\"method-signature\">\n          <span class=\"method-name\">store_selected_index</span><span class=\"method-args\">(select_locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets option index (option number, starting at 0) for selected option in the\nspecified select element.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_selected_index(select_locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_selected_index(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_selected_index(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_selected_index(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_selected_index(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_selected_index(select_locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000113-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000113-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 444</span>\n444:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_selected_index</span> <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n445:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeSelectedIndex'</span>, <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n446:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000114\" class=\"method-detail\">\n        <a name=\"M000114\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000114\" class=\"method-signature\">\n          <span class=\"method-name\">store_selected_indexes</span><span class=\"method-args\">(select_locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets all option indexes (option number, starting at 0) for selected options\nin the specified select or multi-select element.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_selected_indexes(select_locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_selected_indexes(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_selected_indexes(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_selected_indexes(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_selected_indexes(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_selected_indexes(select_locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000114-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000114-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 458</span>\n458:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_selected_indexes</span> <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n459:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeSelectedIndexes'</span>, <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n460:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000115\" class=\"method-detail\">\n        <a name=\"M000115\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000115\" class=\"method-signature\">\n          <span class=\"method-name\">store_selected_label</span><span class=\"method-args\">(select_locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets option label (visible text) for selected option in the specified\nselect element.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_selected_label(select_locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_selected_label(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_selected_label(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_selected_label(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_selected_label(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_selected_label(select_locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000115-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000115-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 472</span>\n472:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_selected_label</span> <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n473:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeSelectedLabel'</span>, <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n474:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000116\" class=\"method-detail\">\n        <a name=\"M000116\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000116\" class=\"method-signature\">\n          <span class=\"method-name\">store_selected_labels</span><span class=\"method-args\">(select_locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets all option labels (visible text) for selected options in the specified\nselect or multi-select element.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_selected_labels(select_locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_selected_labels(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_selected_labels(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_selected_labels(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_selected_labels(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_selected_labels(select_locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000116-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000116-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 486</span>\n486:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_selected_labels</span> <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n487:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeSelectedLabels'</span>, <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n488:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000120\" class=\"method-detail\">\n        <a name=\"M000120\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000120\" class=\"method-signature\">\n          <span class=\"method-name\">store_selected_options</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets all option labels for selected options in the specified select or\nmulti-select element.\n</p>\n<p>\nThe <tt>pattern</tt> for the automatically generated assertions can either\ntake an array or a pattern.\n</p>\n<pre>\n assert_selected_options 'fruits', ['apple', 'pear']\n assert_selected_options 'fruits', 'a*,p*'\n</pre>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_selected_options(locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_selected_options(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_selected_options_present(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_selected_options(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_selected_options(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_selected_options(locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000120-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000120-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 546</span>\n546:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_selected_options</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n547:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeSelectedOptions'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n548:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000117\" class=\"method-detail\">\n        <a name=\"M000117\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000117\" class=\"method-signature\">\n          <span class=\"method-name\">store_selected_value</span><span class=\"method-args\">(select_locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets option value (value attribute) for selected option in the specified\nselect element.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_selected_value(select_locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_selected_value(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_selected_value(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_selected_value(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_selected_value(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_selected_value(select_locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000117-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000117-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 500</span>\n500:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_selected_value</span> <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n501:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeSelectedValue'</span>, <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n502:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000118\" class=\"method-detail\">\n        <a name=\"M000118\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000118\" class=\"method-signature\">\n          <span class=\"method-name\">store_selected_values</span><span class=\"method-args\">(select_locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets all option values (value attribute) for selected options in the\nspecified select or multi-select element.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_selected_values(select_locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_selected_values(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_selected_values(select_locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_selected_values(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_selected_values(select_locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_selected_values(select_locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000118-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000118-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 514</span>\n514:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_selected_values</span> <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n515:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeSelectedValues'</span>, <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n516:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000119\" class=\"method-detail\">\n        <a name=\"M000119\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000119\" class=\"method-signature\">\n          <span class=\"method-name\">store_something_selected</span><span class=\"method-args\">(select_locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nDetermines whether some option in a drop-down menu is selected.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_something_selected(select_locator)</tt>\n\n</li>\n<li><tt>assert_not_something_selected(select_locator)</tt>\n\n</li>\n<li><tt>verify_something_selected(select_locator)</tt>\n\n</li>\n<li><tt>verify_not_something_selected(select_locator)</tt>\n\n</li>\n<li><tt>wait_for_something_selected(select_locator)</tt>\n\n</li>\n<li><tt>wait_for_not_something_selected(select_locator)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000119-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000119-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 527</span>\n527:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_something_selected</span> <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n528:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeSomethingSelected'</span>, <span class=\"ruby-identifier\">select_locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n529:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000109\" class=\"method-detail\">\n        <a name=\"M000109\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000109\" class=\"method-signature\">\n          <span class=\"method-name\">store_table</span><span class=\"method-args\">(locator, row, column, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets the text from a cell of a table.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_table(locator, row, column, pattern)</tt>\n\n</li>\n<li><tt>assert_not_table(locator, row, column, pattern)</tt>\n\n</li>\n<li><tt>verify_table_present(locator, row, column, pattern)</tt>\n\n</li>\n<li><tt>verify_not_table(locator, row, column, pattern)</tt>\n\n</li>\n<li><tt>wait_for_table(locator, row, column, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_table(locator, row, column, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000109-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000109-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 383</span>\n383:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_table</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">row</span>, <span class=\"ruby-identifier\">column</span>, <span class=\"ruby-identifier\">variable_name</span>\n384:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeTable'</span>, <span class=\"ruby-node\">&quot;#{locator}.#{row}.#{column}&quot;</span>, <span class=\"ruby-identifier\">variable_name</span>\n385:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000106\" class=\"method-detail\">\n        <a name=\"M000106\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000106\" class=\"method-signature\">\n          <span class=\"method-name\">store_text</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets the text of an element. This works for any element that contains text.\nThis command uses either the <tt>textContent</tt> (Mozilla-like browsers)\nor the <tt>innerText</tt> (IE-like browsers) of the element, which is the\nrendered text shown to the user.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_text(locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_text(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_text_present(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_text(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_text(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_text(locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000106-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000106-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 331</span>\n331:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_text</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n332:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeText'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n333:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000124\" class=\"method-detail\">\n        <a name=\"M000124\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000124\" class=\"method-signature\">\n          <span class=\"method-name\">store_text_present</span><span class=\"method-args\">(pattern, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nVerifies that the specified text pattern appears somewhere on the rendered\npage shown to the user.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_text_present(pattern)</tt>\n\n</li>\n<li><tt>assert_text_not_present(pattern)</tt>\n\n</li>\n<li><tt>verify_text_present(pattern)</tt>\n\n</li>\n<li><tt>verify_text_not_present(pattern)</tt>\n\n</li>\n<li><tt>wait_for_text_present(pattern)</tt>\n\n</li>\n<li><tt>wait_for_text_not_present(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000124-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000124-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 607</span>\n607:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_text_present</span> <span class=\"ruby-identifier\">pattern</span>, <span class=\"ruby-identifier\">variable_name</span>\n608:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeTextPresent'</span>, <span class=\"ruby-identifier\">pattern</span>, <span class=\"ruby-identifier\">variable_name</span>\n609:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000103\" class=\"method-detail\">\n        <a name=\"M000103\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000103\" class=\"method-signature\">\n          <span class=\"method-name\">store_title</span><span class=\"method-args\">(variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets the title of the current page.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_title(pattern)</tt>\n\n</li>\n<li><tt>assert_not_title(pattern)</tt>\n\n</li>\n<li><tt>verify_title_present(pattern)</tt>\n\n</li>\n<li><tt>verify_not_title(pattern)</tt>\n\n</li>\n<li><tt>wait_for_title(pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_title(pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000103-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000103-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 287</span>\n287:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_title</span> <span class=\"ruby-identifier\">variable_name</span>\n288:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeTitle'</span>, <span class=\"ruby-identifier\">variable_name</span>\n289:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000105\" class=\"method-detail\">\n        <a name=\"M000105\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000105\" class=\"method-signature\">\n          <span class=\"method-name\">store_value</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGets the (whitespace-trimmed) value of an input field (or anything else\nwith a value parameter). For checkbox/radio elements, the value will be\n&quot;on&quot; or &quot;off&quot; depending on whether the element is\nchecked or not.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_value(locator, pattern)</tt>\n\n</li>\n<li><tt>assert_not_value(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_value_present(locator, pattern)</tt>\n\n</li>\n<li><tt>verify_not_value(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_value(locator, pattern)</tt>\n\n</li>\n<li><tt>wait_for_not_value(locator, pattern)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000105-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000105-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 315</span>\n315:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_value</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n316:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeValue'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n317:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000126\" class=\"method-detail\">\n        <a name=\"M000126\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000126\" class=\"method-signature\">\n          <span class=\"method-name\">store_visible</span><span class=\"method-args\">(locator, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nDetermines if the specified element is visible. An element can be rendered\ninvisible by setting the CSS &quot;visibility&quot; property to\n&quot;hidden&quot;, or the &quot;display&quot; property to\n&quot;none&quot;, either for the element itself or one if its ancestors.\nThis method will fail if the element is not present.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_visible(locator)</tt>\n\n</li>\n<li><tt>assert_not_visible(locator)</tt>\n\n</li>\n<li><tt>verify_visible(locator)</tt>\n\n</li>\n<li><tt>verify_not_visible(locator)</tt>\n\n</li>\n<li><tt>wait_for_visible(locator)</tt>\n\n</li>\n<li><tt>wait_for_not_visible(locator)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000126-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000126-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 636</span>\n636:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_visible</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n637:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'storeVisible'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">variable_name</span>\n638:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000139\" class=\"method-detail\">\n        <a name=\"M000139\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000139\" class=\"method-signature\">\n          <span class=\"method-name\">store_whether_this_frame_match_frame_expression</span><span class=\"method-args\">(current_frame_string, target, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nDetermine whether current/locator identify the frame containing this\nrunning code.\n</p>\n<p>\nThis is useful in proxy injection mode, where this code runs in every\nbrowser frame and window, and sometimes the selenium server needs to\nidentify the &quot;current&quot; frame. In this case, when the test calls\nselect_frame, this routine is called for each frame to figure out which one\nhas been selected. The selected frame will return true, while all others\nwill return false.\n</p>\n<p>\nNOTE: <tt><a\nhref=\"TestBuilderAccessors.html#M000139\">store_whether_this_frame_match_frame_expression</a></tt>\nis currently not supported by Selenium Core.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_whether_this_frame_match_frame_expression(current_frame_string,\ntarget)</tt>\n\n</li>\n<li><tt>assert_not_whether_this_frame_match_frame_expression(current_frame_string,\ntarget)</tt>\n\n</li>\n<li><tt>verify_whether_this_frame_match_frame_expression(current_frame_string,\ntarget)</tt>\n\n</li>\n<li><tt>verify_not_whether_this_frame_match_frame_expression(current_frame_string,\ntarget)</tt>\n\n</li>\n<li><tt>wait_for_whether_this_frame_match_frame_expression(current_frame_string,\ntarget)</tt>\n\n</li>\n<li><tt>wait_for_not_whether_this_frame_match_frame_expression(current_frame_string,\ntarget)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000139-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000139-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 846</span>\n846:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_whether_this_frame_match_frame_expression</span> <span class=\"ruby-identifier\">current_frame_string</span>, <span class=\"ruby-identifier\">target</span>, <span class=\"ruby-identifier\">variable_name</span>\n847:     <span class=\"ruby-identifier\">raise</span> <span class=\"ruby-value str\">'Not supported in Selenium Core at the moment'</span>\n848:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000140\" class=\"method-detail\">\n        <a name=\"M000140\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000140\" class=\"method-signature\">\n          <span class=\"method-name\">store_whether_this_window_match_window_expression</span><span class=\"method-args\">(current_window_string, target, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nDetermine whether current_window_string plus target identify the window\ncontaining this running code.\n</p>\n<p>\nThis is useful in proxy injection mode, where this code runs in every\nbrowser frame and window, and sometimes the selenium server needs to\nidentify the &quot;current&quot; window. In this case, when the test calls\nselect_window, this routine is called for each window to figure out which\none has been selected. The selected window will return true, while all\nothers will return false.\n</p>\n<p>\nNOTE: <tt><a\nhref=\"TestBuilderAccessors.html#M000140\">store_whether_this_window_match_window_expression</a></tt>\nis currently not supported by Selenium Core.\n</p>\n<p>\nRelated Assertions, automatically generated:\n</p>\n<ul>\n<li><tt>assert_whether_this_window_match_window_expression(current_window_string,\ntarget)</tt>\n\n</li>\n<li><tt>assert_not_whether_this_window_match_window_expression(current_window_string,\ntarget)</tt>\n\n</li>\n<li><tt>verify_whether_this_window_match_window_expression(current_window_string,\ntarget)</tt>\n\n</li>\n<li><tt>verify_not_whether_this_window_match_window_expression(current_window_string,\ntarget)</tt>\n\n</li>\n<li><tt>wait_for_whether_this_window_match_window_expression(current_window_string,\ntarget)</tt>\n\n</li>\n<li><tt>wait_for_not_whether_this_window_match_window_expression(current_window_string,\ntarget)</tt>\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000140-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000140-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_accessors.rb, line 869</span>\n869:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store_whether_this_window_match_window_expression</span> <span class=\"ruby-identifier\">current_window_string</span>, <span class=\"ruby-identifier\">target</span>, <span class=\"ruby-identifier\">variable_name</span>\n870:     <span class=\"ruby-identifier\">raise</span> <span class=\"ruby-value str\">'Not supported in Selenium Core at the moment'</span>\n871:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderActions.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Module: SeleniumOnRails::TestBuilderActions</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Module</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::TestBuilderActions</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/test_builder_actions_rb.html\">\n                lib/selenium_on_rails/test_builder_actions.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nThe actions available for <a\nhref=\"TestBuilder.html\">SeleniumOnRails::TestBuilder</a> tests.\n</p>\n<p>\nFor each action <tt>foo</tt> there&#8216;s also an action\n<tt>foo_and_wait</tt>.\n</p>\n\n    </div>\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000023\">add_selection</a>&nbsp;&nbsp;\n      <a href=\"#M000034\">alt_key_down</a>&nbsp;&nbsp;\n      <a href=\"#M000035\">alt_key_up</a>&nbsp;&nbsp;\n      <a href=\"#M000030\">answer_on_next_prompt</a>&nbsp;&nbsp;\n      <a href=\"#M000036\">brake</a>&nbsp;&nbsp;\n      <a href=\"#M000020\">check</a>&nbsp;&nbsp;\n      <a href=\"#M000029\">choose_cancel_on_next_confirmation</a>&nbsp;&nbsp;\n      <a href=\"#M000011\">click</a>&nbsp;&nbsp;\n      <a href=\"#M000012\">click_at</a>&nbsp;&nbsp;\n      <a href=\"#M000033\">close</a>&nbsp;&nbsp;\n      <a href=\"#M000037\">control_key_down</a>&nbsp;&nbsp;\n      <a href=\"#M000038\">control_key_up</a>&nbsp;&nbsp;\n      <a href=\"#M000039\">create_cookie</a>&nbsp;&nbsp;\n      <a href=\"#M000040\">delete_cookie</a>&nbsp;&nbsp;\n      <a href=\"#M000041\">double_click</a>&nbsp;&nbsp;\n      <a href=\"#M000042\">double_click_at</a>&nbsp;&nbsp;\n      <a href=\"#M000043\">drag_and_drop</a>&nbsp;&nbsp;\n      <a href=\"#M000044\">drag_and_drop_to_object</a>&nbsp;&nbsp;\n      <a href=\"#M000045\">echo</a>&nbsp;&nbsp;\n      <a href=\"#M000013\">fire_event</a>&nbsp;&nbsp;\n      <a href=\"#M000031\">go_back</a>&nbsp;&nbsp;\n      <a href=\"#M000046\">highlight</a>&nbsp;&nbsp;\n      <a href=\"#M000010\">include_partial</a>&nbsp;&nbsp;\n      <a href=\"#M000015\">key_down</a>&nbsp;&nbsp;\n      <a href=\"#M000014\">key_press</a>&nbsp;&nbsp;\n      <a href=\"#M000016\">key_up</a>&nbsp;&nbsp;\n      <a href=\"#M000047\">meta_key_down</a>&nbsp;&nbsp;\n      <a href=\"#M000048\">meta_key_up</a>&nbsp;&nbsp;\n      <a href=\"#M000018\">mouse_down</a>&nbsp;&nbsp;\n      <a href=\"#M000049\">mouse_down_at</a>&nbsp;&nbsp;\n      <a href=\"#M000050\">mouse_move</a>&nbsp;&nbsp;\n      <a href=\"#M000051\">mouse_move_at</a>&nbsp;&nbsp;\n      <a href=\"#M000052\">mouse_out</a>&nbsp;&nbsp;\n      <a href=\"#M000017\">mouse_over</a>&nbsp;&nbsp;\n      <a href=\"#M000053\">mouse_up</a>&nbsp;&nbsp;\n      <a href=\"#M000054\">mouse_up_at</a>&nbsp;&nbsp;\n      <a href=\"#M000026\">open</a>&nbsp;&nbsp;\n      <a href=\"#M000055\">open_window</a>&nbsp;&nbsp;\n      <a href=\"#M000056\">pause</a>&nbsp;&nbsp;\n      <a href=\"#M000032\">refresh</a>&nbsp;&nbsp;\n      <a href=\"#M000057\">remove_all_selections</a>&nbsp;&nbsp;\n      <a href=\"#M000024\">remove_selection</a>&nbsp;&nbsp;\n      <a href=\"#M000022\">select</a>&nbsp;&nbsp;\n      <a href=\"#M000058\">select_frame</a>&nbsp;&nbsp;\n      <a href=\"#M000027\">select_window</a>&nbsp;&nbsp;\n      <a href=\"#M000067\">set_context</a>&nbsp;&nbsp;\n      <a href=\"#M000059\">set_cursor_position</a>&nbsp;&nbsp;\n      <a href=\"#M000060\">set_mouse_speed</a>&nbsp;&nbsp;\n      <a href=\"#M000069\">set_timeout</a>&nbsp;&nbsp;\n      <a href=\"#M000009\">setup</a>&nbsp;&nbsp;\n      <a href=\"#M000061\">shift_key_down</a>&nbsp;&nbsp;\n      <a href=\"#M000062\">shift_key_up</a>&nbsp;&nbsp;\n      <a href=\"#M000063\">store</a>&nbsp;&nbsp;\n      <a href=\"#M000025\">submit</a>&nbsp;&nbsp;\n      <a href=\"#M000019\">type</a>&nbsp;&nbsp;\n      <a href=\"#M000064\">type_keys</a>&nbsp;&nbsp;\n      <a href=\"#M000021\">uncheck</a>&nbsp;&nbsp;\n      <a href=\"#M000068\">wait_for_condition</a>&nbsp;&nbsp;\n      <a href=\"#M000070\">wait_for_page_to_load</a>&nbsp;&nbsp;\n      <a href=\"#M000028\">wait_for_popup</a>&nbsp;&nbsp;\n      <a href=\"#M000065\">window_focus</a>&nbsp;&nbsp;\n      <a href=\"#M000066\">window_maximize</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000023\" class=\"method-detail\">\n        <a name=\"M000023\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000023\" class=\"method-signature\">\n          <span class=\"method-name\">add_selection</span><span class=\"method-args\">(locator, option_locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nAdd a selection to the set of selected options in a multi-<a\nhref=\"TestBuilderActions.html#M000022\">select</a> element using an option\nlocator.\n</p>\n<p>\nSee the <tt><a href=\"TestBuilderActions.html#M000022\">select</a></tt>\ncommand for more information about option locators.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000023-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000023-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 148</span>\n148:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">add_selection</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">option_locator</span>\n149:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'addSelection'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">option_locator</span>\n150:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000034\" class=\"method-detail\">\n        <a name=\"M000034\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000034\" class=\"method-signature\">\n          <span class=\"method-name\">alt_key_down</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates the user pressing the alt key and hold it down until do_alt_up()\nis called or a new page is loaded.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000034-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000034-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 221</span>\n221:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">alt_key_down</span>\n222:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'altKeyDown'</span>\n223:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000035\" class=\"method-detail\">\n        <a name=\"M000035\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000035\" class=\"method-signature\">\n          <span class=\"method-name\">alt_key_up</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates the user releasing the alt key.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000035-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000035-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 226</span>\n226:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">alt_key_up</span>\n227:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'altKeyUp'</span>\n228:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000030\" class=\"method-detail\">\n        <a name=\"M000030\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000030\" class=\"method-signature\">\n          <span class=\"method-name\">answer_on_next_prompt</span><span class=\"method-args\">(answer)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nInstructs Selenium to return the specified answer string in response to the\nnext JavaScript prompt (<tt>window.prompt()</tt>).\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000030-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000030-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 199</span>\n199:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">answer_on_next_prompt</span> <span class=\"ruby-identifier\">answer</span>\n200:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'answerOnNextPrompt'</span>, <span class=\"ruby-identifier\">answer</span>\n201:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000036\" class=\"method-detail\">\n        <a name=\"M000036\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000036\" class=\"method-signature\">\n          <span class=\"method-name\">brake</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nHalt the currently running test, and wait for the user to press the\nContinue button. This command is useful for debugging, but be careful when\nusing it, because it will force automated tests to hang until a user\nintervenes manually.\n</p>\n<p>\nNOTE: <tt>break</tt> is a reserved word in Ruby, so we have to simulate\nSelenium core&#8216;s <tt>break()</tt> with <tt><a\nhref=\"TestBuilderActions.html#M000036\">brake</a>()</tt>\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000036-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000036-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 236</span>\n236:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">brake</span>\n237:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'break'</span>\n238:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000020\" class=\"method-detail\">\n        <a name=\"M000020\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000020\" class=\"method-signature\">\n          <span class=\"method-name\">check</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nCheck a toggle-button (checkbox/radio).\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000020-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000020-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 108</span>\n108:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">check</span> <span class=\"ruby-identifier\">locator</span>\n109:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'check'</span>, <span class=\"ruby-identifier\">locator</span>\n110:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000029\" class=\"method-detail\">\n        <a name=\"M000029\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000029\" class=\"method-signature\">\n          <span class=\"method-name\">choose_cancel_on_next_confirmation</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nBy default, Selenium&#8216;s overridden <tt>window.confirm()</tt> function\nwill return <tt>true</tt>, as if the user had manually clicked OK. After\nrunning this command, the next call to <tt>confirm()</tt> will return\n<tt>false</tt>, as if the user had clicked Cancel.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000029-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000029-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 193</span>\n193:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">choose_cancel_on_next_confirmation</span>\n194:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'chooseCancelOnNextConfirmation'</span>\n195:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000011\" class=\"method-detail\">\n        <a name=\"M000011\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000011\" class=\"method-signature\">\n          <span class=\"method-name\">click</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nClicks on a link, button, checkbox or radio button. If the <a\nhref=\"TestBuilderActions.html#M000011\">click</a> action causes a new page\nto load (like a link usually does), call <tt><a\nhref=\"TestBuilderActions.html#M000070\">wait_for_page_to_load</a></tt>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000011-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000011-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 47</span>\n47:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">click</span> <span class=\"ruby-identifier\">locator</span>\n48:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'click'</span>, <span class=\"ruby-identifier\">locator</span>\n49:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000012\" class=\"method-detail\">\n        <a name=\"M000012\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000012\" class=\"method-signature\">\n          <span class=\"method-name\">click_at</span><span class=\"method-args\">(locator, coord_string)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nClicks on a link, button, checkbox or radio button. If the <a\nhref=\"TestBuilderActions.html#M000011\">click</a> action causes a new page\nto load (like a link usually does), call <a\nhref=\"TestBuilderActions.html#M000070\">wait_for_page_to_load</a>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000012-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000012-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 53</span>\n53:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">click_at</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">coord_string</span>\n54:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'clickAt'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">coord_string</span>\n55:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000033\" class=\"method-detail\">\n        <a name=\"M000033\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000033\" class=\"method-signature\">\n          <span class=\"method-name\">close</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates the user clicking the &quot;<a\nhref=\"TestBuilderActions.html#M000033\">close</a>&quot; button in the\ntitlebar of a popup window or tab.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000033-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000033-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 215</span>\n215:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">close</span>\n216:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'close'</span>\n217:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000037\" class=\"method-detail\">\n        <a name=\"M000037\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000037\" class=\"method-signature\">\n          <span class=\"method-name\">control_key_down</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates the user pressing the alt key and hold it down until\ndo_control_up() is called or a new page is loaded.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000037-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000037-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 242</span>\n242:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">control_key_down</span>\n243:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'controlKeyDown'</span>\n244:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000038\" class=\"method-detail\">\n        <a name=\"M000038\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000038\" class=\"method-signature\">\n          <span class=\"method-name\">control_key_up</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates the user releasing the control key.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000038-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000038-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 247</span>\n247:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">control_key_up</span>\n248:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'controlKeyUp'</span>\n249:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000039\" class=\"method-detail\">\n        <a name=\"M000039\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000039\" class=\"method-signature\">\n          <span class=\"method-name\">create_cookie</span><span class=\"method-args\">(name_value_pair, options_string)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nCreate a new cookie whose path and domain are same with those of current\npage under test, unless you specified a path for this cookie explicitly.\n</p>\n<p>\nArguments:\n</p>\n<ul>\n<li><tt>name_value_pair</tt> - name and value of the cookie in a format\n&quot;name=value&quot;\n\n</li>\n<li><tt>options_string</tt> - options for the cookie. Currently supported\noptions include &#8216;path&#8217; and &#8216;max_age&#8217;. The\noptions_string&#8216;s format is <tt>&quot;path=/path/,\nmax_age=60&quot;</tt>. The order of options are irrelevant, the unit of the\nvalue of &#8216;max_age&#8217; is second.\n\n</li>\n</ul>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000039-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000039-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 260</span>\n260:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">create_cookie</span> <span class=\"ruby-identifier\">name_value_pair</span>, <span class=\"ruby-identifier\">options_string</span>\n261:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'createCookie'</span>, <span class=\"ruby-identifier\">name_value_pair</span>, <span class=\"ruby-identifier\">options_string</span>\n262:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000040\" class=\"method-detail\">\n        <a name=\"M000040\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000040\" class=\"method-signature\">\n          <span class=\"method-name\">delete_cookie</span><span class=\"method-args\">(name, path)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nDelete a named cookie with specified path.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000040-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000040-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 265</span>\n265:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">delete_cookie</span> <span class=\"ruby-identifier\">name</span>, <span class=\"ruby-identifier\">path</span>\n266:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'deleteCookie'</span>, <span class=\"ruby-identifier\">name</span>, <span class=\"ruby-identifier\">path</span>\n267:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000041\" class=\"method-detail\">\n        <a name=\"M000041\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000041\" class=\"method-signature\">\n          <span class=\"method-name\">double_click</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nDouble clicks on a link, button, checkbox or radio button. If the double <a\nhref=\"TestBuilderActions.html#M000011\">click</a> action causes a new page\nto load (like a link usually does), call <tt><a\nhref=\"TestBuilderActions.html#M000070\">wait_for_page_to_load</a></tt>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000041-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000041-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 271</span>\n271:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">double_click</span> <span class=\"ruby-identifier\">locator</span>\n272:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'doubleClick'</span>, <span class=\"ruby-identifier\">locator</span>\n273:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000042\" class=\"method-detail\">\n        <a name=\"M000042\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000042\" class=\"method-signature\">\n          <span class=\"method-name\">double_click_at</span><span class=\"method-args\">(locator, coord_string)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nDoubleclicks on a link, button, checkbox or radio button. If the action\ncauses a new page to load (like a link usually does), call <tt><a\nhref=\"TestBuilderActions.html#M000070\">wait_for_page_to_load</a></tt>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000042-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000042-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 277</span>\n277:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">double_click_at</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">coord_string</span>\n278:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'doubleClickAt'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">coord_string</span>\n279:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000043\" class=\"method-detail\">\n        <a name=\"M000043\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000043\" class=\"method-signature\">\n          <span class=\"method-name\">drag_and_drop</span><span class=\"method-args\">(locator, movements_string)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nDrags an element a certain distance and then drops it.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000043-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000043-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 282</span>\n282:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">drag_and_drop</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">movements_string</span>\n283:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'dragAndDrop'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">movements_string</span>\n284:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000044\" class=\"method-detail\">\n        <a name=\"M000044\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000044\" class=\"method-signature\">\n          <span class=\"method-name\">drag_and_drop_to_object</span><span class=\"method-args\">(locator_of_object_to_be_dragged, locator_of_drag_destination_object)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nDrags an element and drops it on another element.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000044-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000044-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 287</span>\n287:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">drag_and_drop_to_object</span> <span class=\"ruby-identifier\">locator_of_object_to_be_dragged</span>, <span class=\"ruby-identifier\">locator_of_drag_destination_object</span>\n288:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'dragAndDropToObject'</span>, <span class=\"ruby-identifier\">locator_of_object_to_be_dragged</span>, <span class=\"ruby-identifier\">locator_of_drag_destination_object</span>\n289:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000045\" class=\"method-detail\">\n        <a name=\"M000045\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000045\" class=\"method-signature\">\n          <span class=\"method-name\">echo</span><span class=\"method-args\">(message)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nPrints the specified message into the third table cell in your <a\nhref=\"Selenese.html\">Selenese</a> tables. Useful for debugging.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000045-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000045-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 294</span>\n294:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">echo</span> <span class=\"ruby-identifier\">message</span>\n295:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'echo'</span>, <span class=\"ruby-identifier\">message</span>\n296:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000013\" class=\"method-detail\">\n        <a name=\"M000013\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000013\" class=\"method-signature\">\n          <span class=\"method-name\">fire_event</span><span class=\"method-args\">(locator, event_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nExplicitly simulate an event (e.g. <tt>&quot;focus&quot;</tt>,\n<tt>&quot;blur&quot;</tt>), to trigger the corresponding\n<tt>&quot;on_event_&quot;</tt> handler.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000013-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000013-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 59</span>\n59:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">fire_event</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">event_name</span>\n60:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'fireEvent'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">event_name</span>\n61:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000031\" class=\"method-detail\">\n        <a name=\"M000031\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000031\" class=\"method-signature\">\n          <span class=\"method-name\">go_back</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates the user clicking the &quot;back&quot; button on their browser.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000031-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000031-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 204</span>\n204:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">go_back</span>\n205:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'goBack'</span>\n206:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000046\" class=\"method-detail\">\n        <a name=\"M000046\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000046\" class=\"method-signature\">\n          <span class=\"method-name\">highlight</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nBriefly changes the backgroundColor of the specified element yellow. Useful\nfor debugging.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000046-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000046-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 300</span>\n300:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">highlight</span> <span class=\"ruby-identifier\">locator</span>\n301:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'highlight'</span>, <span class=\"ruby-identifier\">locator</span>\n302:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000010\" class=\"method-detail\">\n        <a name=\"M000010\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000010\" class=\"method-signature\">\n          <span class=\"method-name\">include_partial</span><span class=\"method-args\">(path, local_assigns = {})</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nIncludes a partial. The path is relative to the Selenium tests root. The\nstarting _ and the file extension don&#8216;t have to be specified.\n</p>\n<pre>\n  #include test/selenium/_partial.*\n  include_partial 'partial'\n  #include test/selenium/suite/_partial.*\n  include_partial 'suite/partial'\n  #include test/selenium/suite/_partial.* and provide local assigns\n  include_partial 'suite/partial', :foo =&gt; bar\n</pre>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000010-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000010-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 39</span>\n39:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">include_partial</span> <span class=\"ruby-identifier\">path</span>, <span class=\"ruby-identifier\">local_assigns</span> = {}\n40:     <span class=\"ruby-identifier\">partial</span> = <span class=\"ruby-ivar\">@view</span>.<span class=\"ruby-identifier\">render</span> <span class=\"ruby-identifier\">:partial</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">path</span>, <span class=\"ruby-identifier\">:locals</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-identifier\">local_assigns</span>\n41:     <span class=\"ruby-ivar\">@output</span> <span class=\"ruby-operator\">&lt;&lt;</span> <span class=\"ruby-identifier\">partial</span>\n42:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000015\" class=\"method-detail\">\n        <a name=\"M000015\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000015\" class=\"method-signature\">\n          <span class=\"method-name\">key_down</span><span class=\"method-args\">(locator, keycode)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates a user pressing a key (without releasing it yet).\n</p>\n<p>\n<tt>keycode</tt> is the numeric keycode of the key to be pressed, normally\nthe ASCII value of that key.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000015-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000015-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 75</span>\n75:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">key_down</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">keycode</span>\n76:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'keyDown'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">keycode</span>\n77:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000014\" class=\"method-detail\">\n        <a name=\"M000014\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000014\" class=\"method-signature\">\n          <span class=\"method-name\">key_press</span><span class=\"method-args\">(locator, keycode)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates a user pressing and releasing a key.\n</p>\n<p>\n<tt>keycode</tt> is the numeric keycode of the key to be pressed, normally\nthe ASCII value of that key.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000014-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000014-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 67</span>\n67:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">key_press</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">keycode</span>\n68:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'keyPress'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">keycode</span>\n69:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000016\" class=\"method-detail\">\n        <a name=\"M000016\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000016\" class=\"method-signature\">\n          <span class=\"method-name\">key_up</span><span class=\"method-args\">(locator, keycode)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates a user releasing a key.\n</p>\n<p>\n<tt>keycode</tt> is the numeric keycode of the key to be released, normally\nthe ASCII value of that key.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000016-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000016-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 83</span>\n83:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">key_up</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">keycode</span>\n84:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'keyUp'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">keycode</span>\n85:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000047\" class=\"method-detail\">\n        <a name=\"M000047\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000047\" class=\"method-signature\">\n          <span class=\"method-name\">meta_key_down</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nPress the meta key and hold it down until <tt>doMetaUp()</tt> is called or\na new page is loaded.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000047-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000047-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 306</span>\n306:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">meta_key_down</span>\n307:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'metaKeyDown'</span>\n308:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000048\" class=\"method-detail\">\n        <a name=\"M000048\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000048\" class=\"method-signature\">\n          <span class=\"method-name\">meta_key_up</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRelease the meta key.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000048-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000048-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 311</span>\n311:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">meta_key_up</span>\n312:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'metaKeyUp'</span>\n313:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000018\" class=\"method-detail\">\n        <a name=\"M000018\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000018\" class=\"method-signature\">\n          <span class=\"method-name\">mouse_down</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates a user pressing the mouse button (without releasing it yet) on\nthe specified element.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000018-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000018-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 94</span>\n94:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">mouse_down</span> <span class=\"ruby-identifier\">locator</span>\n95:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'mouseDown'</span>, <span class=\"ruby-identifier\">locator</span>\n96:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000049\" class=\"method-detail\">\n        <a name=\"M000049\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000049\" class=\"method-signature\">\n          <span class=\"method-name\">mouse_down_at</span><span class=\"method-args\">(locator, coord_string)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates a user pressing the mouse button (without releasing it yet) on\nthe specified element.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000049-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000049-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 317</span>\n317:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">mouse_down_at</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">coord_string</span>\n318:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'mouseDownAt'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">coord_string</span>\n319:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000050\" class=\"method-detail\">\n        <a name=\"M000050\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000050\" class=\"method-signature\">\n          <span class=\"method-name\">mouse_move</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates a user moving the mouse.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000050-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000050-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 322</span>\n322:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">mouse_move</span> <span class=\"ruby-identifier\">locator</span>\n323:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'mouseMove'</span>, <span class=\"ruby-identifier\">locator</span>\n324:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000051\" class=\"method-detail\">\n        <a name=\"M000051\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000051\" class=\"method-signature\">\n          <span class=\"method-name\">mouse_move_at</span><span class=\"method-args\">(locator, coord_string)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates a user moving the mouse relative to the specified element.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000051-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000051-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 327</span>\n327:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">mouse_move_at</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">coord_string</span>\n328:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'mouseMoveAt'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">coord_string</span>\n329:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000052\" class=\"method-detail\">\n        <a name=\"M000052\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000052\" class=\"method-signature\">\n          <span class=\"method-name\">mouse_out</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates the user moving the mouse off the specified element.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000052-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000052-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 332</span>\n332:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">mouse_out</span> <span class=\"ruby-identifier\">locator</span>\n333:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'mouseOut'</span>, <span class=\"ruby-identifier\">locator</span>\n334:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000017\" class=\"method-detail\">\n        <a name=\"M000017\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000017\" class=\"method-signature\">\n          <span class=\"method-name\">mouse_over</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates a user hovering a mouse over the specified element.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000017-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000017-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 88</span>\n88:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">mouse_over</span> <span class=\"ruby-identifier\">locator</span>\n89:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'mouseOver'</span>, <span class=\"ruby-identifier\">locator</span>\n90:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000053\" class=\"method-detail\">\n        <a name=\"M000053\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000053\" class=\"method-signature\">\n          <span class=\"method-name\">mouse_up</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates the user releasing the mouse button on the specified element.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000053-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000053-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 337</span>\n337:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">mouse_up</span> <span class=\"ruby-identifier\">locator</span>\n338:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'mouseUp'</span>, <span class=\"ruby-identifier\">locator</span>\n339:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000054\" class=\"method-detail\">\n        <a name=\"M000054\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000054\" class=\"method-signature\">\n          <span class=\"method-name\">mouse_up_at</span><span class=\"method-args\">(locator, coord_string)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates a user pressing the mouse button (without releasing it yet) on\nthe specified element.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000054-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000054-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 343</span>\n343:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">mouse_up_at</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">coord_string</span>\n344:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'mouseUpAt'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">coord_string</span>\n345:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000026\" class=\"method-detail\">\n        <a name=\"M000026\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000026\" class=\"method-signature\">\n          <span class=\"method-name\">open</span><span class=\"method-args\">(url)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nOpens an URL in the test frame. This accepts both relative and absolute\nURLs. The <tt><a href=\"TestBuilderActions.html#M000026\">open</a></tt>\ncommand waits for the page to load before proceeding, i.e. you don&#8216;t\nhave to call <tt><a\nhref=\"TestBuilderActions.html#M000070\">wait_for_page_to_load</a></tt>.\n</p>\n<p>\nNote: The URL must be on the same domain as the runner HTML due to security\nrestrictions in the browser (Same Origin Policy).\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000026-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000026-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 172</span>\n172:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">open</span> <span class=\"ruby-identifier\">url</span>\n173:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'open'</span>, <span class=\"ruby-identifier\">url_arg</span>(<span class=\"ruby-identifier\">url</span>)\n174:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000055\" class=\"method-detail\">\n        <a name=\"M000055\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000055\" class=\"method-signature\">\n          <span class=\"method-name\">open_window</span><span class=\"method-args\">(url, window_id)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nOpens a popup window (if a window with that ID isn&#8216;t already <a\nhref=\"TestBuilderActions.html#M000026\">open</a>). After opening the window,\nyou&#8216;ll need to <a href=\"TestBuilderActions.html#M000022\">select</a>\nit using the <tt><a\nhref=\"TestBuilderActions.html#M000027\">select_window</a></tt> command.\n</p>\n<p>\nThis command can also be a useful workaround for bug SEL-339. In some\ncases, Selenium will be unable to intercept a call to window.open (if the\ncall occurs during or before the &quot;onLoad&quot; event, for example). In\nthose cases, you can force Selenium to notice the <a\nhref=\"TestBuilderActions.html#M000026\">open</a> window&#8216;s name by\nusing the Selenium openWindow command, using an empty (blank) url, like\nthis: <tt><a\nhref=\"TestBuilderActions.html#M000055\">open_window</a>(&quot;&quot;,\n&quot;myFunnyWindow&quot;)</tt>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000055-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000055-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 355</span>\n355:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">open_window</span> <span class=\"ruby-identifier\">url</span>, <span class=\"ruby-identifier\">window_id</span>\n356:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'openWindow'</span>, <span class=\"ruby-identifier\">url</span>, <span class=\"ruby-identifier\">window_id</span>\n357:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000056\" class=\"method-detail\">\n        <a name=\"M000056\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000056\" class=\"method-signature\">\n          <span class=\"method-name\">pause</span><span class=\"method-args\">(wait_time)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nWait for the specified amount of time (in milliseconds).\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000056-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000056-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 360</span>\n360:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">pause</span> <span class=\"ruby-identifier\">wait_time</span>\n361:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'pause'</span>, <span class=\"ruby-identifier\">wait_time</span>\n362:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000032\" class=\"method-detail\">\n        <a name=\"M000032\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000032\" class=\"method-signature\">\n          <span class=\"method-name\">refresh</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates the user clicking the &quot;Refresh&quot; button on their\nbrowser.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000032-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000032-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 209</span>\n209:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">refresh</span>\n210:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'refresh'</span>\n211:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000057\" class=\"method-detail\">\n        <a name=\"M000057\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000057\" class=\"method-signature\">\n          <span class=\"method-name\">remove_all_selections</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nUnselects all of the selected options in a multi-<a\nhref=\"TestBuilderActions.html#M000022\">select</a> element.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000057-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000057-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 365</span>\n365:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">remove_all_selections</span> <span class=\"ruby-identifier\">locator</span>\n366:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'removeAllSelections'</span>, <span class=\"ruby-identifier\">locator</span>\n367:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000024\" class=\"method-detail\">\n        <a name=\"M000024\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000024\" class=\"method-signature\">\n          <span class=\"method-name\">remove_selection</span><span class=\"method-args\">(locator, option_locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRemove a selection from the set of selected options in a multi-<a\nhref=\"TestBuilderActions.html#M000022\">select</a> element using an option\nlocator.\n</p>\n<p>\nSee the <tt><a href=\"TestBuilderActions.html#M000022\">select</a></tt>\ncommand for more information about option locators.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000024-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000024-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 156</span>\n156:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">remove_selection</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">option_locator</span>\n157:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'removeSelection'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">option_locator</span>\n158:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000022\" class=\"method-detail\">\n        <a name=\"M000022\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000022\" class=\"method-signature\">\n          <span class=\"method-name\">select</span><span class=\"method-args\">(locator, option_locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSelect an option from a drop-down using an option locator.\n</p>\n<p>\nOption locators provide different ways of specifying options of an HTML\nSelect element (e.g. for selecting a specific option, or for asserting that\nthe selected option satisfies a specification). There are several forms of\nSelect Option Locator.\n</p>\n<ul>\n<li>label=labelPattern matches options based on their labels, i.e. the visible\ntext. (This is the default.)\n\n<pre>\n  label=regexp:^[Oo]ther\n</pre>\n</li>\n<li>value=valuePattern matches options based on their values.\n\n<pre>\n  value=other\n</pre>\n</li>\n<li>id=id matches options based on their ids.\n\n<pre>\n  id=option1\n</pre>\n</li>\n<li>index=index matches an option based on its index (offset from zero).\n\n<pre>\n  index=2\n</pre>\n</li>\n</ul>\n<p>\nIf no option locator prefix is provided, the default behaviour is to match\non label.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000022-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000022-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 140</span>\n140:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">select</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">option_locator</span>\n141:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'select'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">option_locator</span>\n142:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000058\" class=\"method-detail\">\n        <a name=\"M000058\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000058\" class=\"method-signature\">\n          <span class=\"method-name\">select_frame</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSelects a frame within the current window. (You may invoke this command\nmultiple times to <a href=\"TestBuilderActions.html#M000022\">select</a>\nnested frames.) To <a href=\"TestBuilderActions.html#M000022\">select</a> the\nparent frame, use &quot;relative=parent&quot; as a locator; to <a\nhref=\"TestBuilderActions.html#M000022\">select</a> the top frame, use\n&quot;relative=top&quot;.\n</p>\n<p>\nYou may also use a DOM expression to identify the frame you want directly,\nlike this: <tt><a\nhref=\"http://\"subframe\"\">dom=frames[\"main\"].frames</a></tt>\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000058-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000058-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 375</span>\n375:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">select_frame</span> <span class=\"ruby-identifier\">locator</span>\n376:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'selectFrame'</span>, <span class=\"ruby-identifier\">locator</span>\n377:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000027\" class=\"method-detail\">\n        <a name=\"M000027\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000027\" class=\"method-signature\">\n          <span class=\"method-name\">select_window</span><span class=\"method-args\">(window_id)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSelects a popup window; once a popup window has been selected, all commands\ngo to that window. To <a href=\"TestBuilderActions.html#M000022\">select</a>\nthe main window again, use <tt>nil</tt> as the target.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000027-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000027-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 178</span>\n178:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">select_window</span> <span class=\"ruby-identifier\">window_id</span>\n179:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'selectWindow'</span>, <span class=\"ruby-identifier\">window_id</span><span class=\"ruby-operator\">||</span><span class=\"ruby-value str\">'null'</span>\n180:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000067\" class=\"method-detail\">\n        <a name=\"M000067\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000067\" class=\"method-signature\">\n          <span class=\"method-name\">set_context</span><span class=\"method-args\">(context, log_level_threshold = nil)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nWrites a message to the status bar and adds a note to the browser-side log.\n</p>\n<p>\n<tt>context</tt> is the message sent to the browser.\n</p>\n<p>\n<tt>log_level_threshold</tt> can be <tt>nil</tt>, <tt>:debug</tt>,\n<tt>:info</tt>, <tt>:warn</tt> or <tt>:error</tt>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000067-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000067-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 448</span>\n448:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">set_context</span> <span class=\"ruby-identifier\">context</span>, <span class=\"ruby-identifier\">log_level_threshold</span> = <span class=\"ruby-keyword kw\">nil</span>\n449:     <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">log_level_threshold</span>\n450:       <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'setContext'</span>, <span class=\"ruby-identifier\">context</span>, <span class=\"ruby-identifier\">log_level_threshold</span>.<span class=\"ruby-identifier\">to_s</span>\n451:     <span class=\"ruby-keyword kw\">else</span>\n452:       <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'setContext'</span>, <span class=\"ruby-identifier\">context</span>\n453:     <span class=\"ruby-keyword kw\">end</span>\n454:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000059\" class=\"method-detail\">\n        <a name=\"M000059\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000059\" class=\"method-signature\">\n          <span class=\"method-name\">set_cursor_position</span><span class=\"method-args\">(locator, position)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nMoves the text cursor to the specified position in the given input element\nor textarea. This method will fail if the specified element isn&#8216;t an\ninput element or textarea.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000059-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000059-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 381</span>\n381:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">set_cursor_position</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">position</span>\n382:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'setCursorPosition'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">position</span>\n383:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000060\" class=\"method-detail\">\n        <a name=\"M000060\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000060\" class=\"method-signature\">\n          <span class=\"method-name\">set_mouse_speed</span><span class=\"method-args\">(pixels)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nConfigure the number of pixels between &quot;mousemove&quot; events during\ndragAndDrop commands (default=10). Setting this value to 0 means that\nwe&#8216;ll send a &quot;mousemove&quot; event to every single pixel in\nbetween the start location and the end location; that can be very slow, and\nmay cause some browsers to force the JavaScript to timeout.\n</p>\n<p>\nIf the mouse speed is greater than the distance between the two dragged\nobjects, we&#8216;ll just send one &quot;mousemove&quot; at the start\nlocation and then one final one at the end location.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000060-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000060-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 393</span>\n393:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">set_mouse_speed</span> <span class=\"ruby-identifier\">pixels</span>\n394:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'setMouseSpeed'</span>, <span class=\"ruby-identifier\">pixels</span>\n395:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000069\" class=\"method-detail\">\n        <a name=\"M000069\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000069\" class=\"method-signature\">\n          <span class=\"method-name\">set_timeout</span><span class=\"method-args\">(timeout)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSpecifies the amount of time that Selenium will wait for actions to\ncomplete.\n</p>\n<p>\nActions that require waiting include <tt><a\nhref=\"TestBuilderActions.html#M000026\">open</a></tt> and the\n<tt>wait_for*</tt> actions.\n</p>\n<p>\nThe default timeout is 30 seconds.\n</p>\n<p>\n<tt>timeout</tt> is specified in milliseconds.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000069-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000069-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 480</span>\n480:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">set_timeout</span> <span class=\"ruby-identifier\">timeout</span>\n481:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'setTimeout'</span>, <span class=\"ruby-identifier\">timeout</span>\n482:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000009\" class=\"method-detail\">\n        <a name=\"M000009\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000009\" class=\"method-signature\">\n          <span class=\"method-name\">setup</span><span class=\"method-args\">(options = {})</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nTell Selenium on Rails to clear the session and load any fixtures. DO NOT\nCALL THIS AGAINST NON-TEST DATABASES. The supported <tt>options</tt> are\n<tt>:keep_session</tt>, <tt>:fixtures</tt> and <tt>:clear_tables</tt>\n</p>\n<pre>\n  setup\n  setup :keep_session\n  setup :fixtures =&gt; :all\n  setup :keep_session, :fixtures =&gt; [:foo, :bar]\n  setup :clear_tables =&gt; [:foo, :bar]\n</pre>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000009-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000009-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 14</span>\n14:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">setup</span> <span class=\"ruby-identifier\">options</span> = {}\n15:     <span class=\"ruby-identifier\">options</span> = {<span class=\"ruby-identifier\">options</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-keyword kw\">nil</span>} <span class=\"ruby-keyword kw\">unless</span> <span class=\"ruby-identifier\">options</span>.<span class=\"ruby-identifier\">is_a?</span> <span class=\"ruby-constant\">Hash</span>\n16: \n17:     <span class=\"ruby-identifier\">opts</span> = {<span class=\"ruby-identifier\">:controller</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value str\">'selenium'</span>, <span class=\"ruby-identifier\">:action</span> =<span class=\"ruby-operator\">&gt;</span> <span class=\"ruby-value str\">'setup'</span>}\n18:     <span class=\"ruby-identifier\">opts</span>[<span class=\"ruby-identifier\">:keep_session</span>] = <span class=\"ruby-keyword kw\">true</span> <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">options</span>.<span class=\"ruby-identifier\">has_key?</span> <span class=\"ruby-identifier\">:keep_session</span>\n19: \n20:     [<span class=\"ruby-identifier\">:fixtures</span>, <span class=\"ruby-identifier\">:clear_tables</span>].<span class=\"ruby-identifier\">each</span> <span class=\"ruby-keyword kw\">do</span> <span class=\"ruby-operator\">|</span><span class=\"ruby-identifier\">key</span><span class=\"ruby-operator\">|</span>\n21:       <span class=\"ruby-keyword kw\">if</span> (<span class=\"ruby-identifier\">f</span> = <span class=\"ruby-identifier\">options</span>[<span class=\"ruby-identifier\">key</span>])\n22:         <span class=\"ruby-identifier\">f</span> = [<span class=\"ruby-identifier\">f</span>] <span class=\"ruby-keyword kw\">unless</span> <span class=\"ruby-identifier\">f</span>.<span class=\"ruby-identifier\">is_a?</span> <span class=\"ruby-constant\">Array</span>\n23:         <span class=\"ruby-identifier\">opts</span>[<span class=\"ruby-identifier\">key</span>] = <span class=\"ruby-identifier\">f</span>.<span class=\"ruby-identifier\">join</span> <span class=\"ruby-value str\">','</span>\n24:       <span class=\"ruby-keyword kw\">end</span>\n25:     <span class=\"ruby-keyword kw\">end</span>\n26: \n27:     <span class=\"ruby-identifier\">open</span> <span class=\"ruby-identifier\">opts</span>\n28:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000061\" class=\"method-detail\">\n        <a name=\"M000061\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000061\" class=\"method-signature\">\n          <span class=\"method-name\">shift_key_down</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nPress the shift key and hold it down until <tt>doShiftUp()</tt> is called\nor a new page is loaded.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000061-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000061-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 399</span>\n399:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">shift_key_down</span>\n400:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'shiftKeyDown'</span>\n401:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000062\" class=\"method-detail\">\n        <a name=\"M000062\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000062\" class=\"method-signature\">\n          <span class=\"method-name\">shift_key_up</span><span class=\"method-args\">()</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRelease the shift key.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000062-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000062-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 404</span>\n404:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">shift_key_up</span>\n405:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'shiftKeyUp'</span>\n406:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000063\" class=\"method-detail\">\n        <a name=\"M000063\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000063\" class=\"method-signature\">\n          <span class=\"method-name\">store</span><span class=\"method-args\">(expression, variable_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nThis command is a synonym for <tt>store_expression</tt>.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000063-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000063-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 409</span>\n409:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">store</span> <span class=\"ruby-identifier\">expression</span>, <span class=\"ruby-identifier\">variable_name</span>\n410:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'store'</span>, <span class=\"ruby-identifier\">expression</span>, <span class=\"ruby-identifier\">variable_name</span>\n411:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000025\" class=\"method-detail\">\n        <a name=\"M000025\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000025\" class=\"method-signature\">\n          <span class=\"method-name\">submit</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSubmit the specified form. This is particularly useful for forms without <a\nhref=\"TestBuilderActions.html#M000025\">submit</a> buttons, e.g.\nsingle-input &quot;Search&quot; forms.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000025-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000025-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 162</span>\n162:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">submit</span> <span class=\"ruby-identifier\">locator</span>\n163:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'submit'</span>, <span class=\"ruby-identifier\">locator</span>\n164:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000019\" class=\"method-detail\">\n        <a name=\"M000019\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000019\" class=\"method-signature\">\n          <span class=\"method-name\">type</span><span class=\"method-args\">(locator, value)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSets the value of an input field, as though you typed it in.\n</p>\n<p>\nCan also be used to set the value of combo boxes, <a\nhref=\"TestBuilderActions.html#M000020\">check</a> boxes, etc. In these\ncases, <tt>value</tt> should be the value of the option selected, not the\nvisible text.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000019-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000019-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 103</span>\n103:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">type</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">value</span>\n104:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'type'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">value</span>\n105:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000064\" class=\"method-detail\">\n        <a name=\"M000064\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000064\" class=\"method-signature\">\n          <span class=\"method-name\">type_keys</span><span class=\"method-args\">(locator, value)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nSimulates keystroke events on the specified element, as though you typed\nthe value key-by-key.\n</p>\n<p>\nThis is a convenience method for calling <tt><a\nhref=\"TestBuilderActions.html#M000015\">key_down</a></tt>, <tt><a\nhref=\"TestBuilderActions.html#M000016\">key_up</a></tt>, <tt><a\nhref=\"TestBuilderActions.html#M000014\">key_press</a></tt> for every\ncharacter in the specified string; this is useful for dynamic UI widgets\n(like auto-completing combo boxes) that require explicit key events.\n</p>\n<p>\nUnlike the simple &quot;<a\nhref=\"TestBuilderActions.html#M000019\">type</a>&quot; command, which forces\nthe specified value into the page directly, this command may or may not\nhave any visible effect, even in cases where typing keys would normally\nhave a visible effect. For example, if you use &quot;<tt><a\nhref=\"TestBuilderActions.html#M000064\">type_keys</a></tt>&quot; on a form\nelement, you may or may not see the results of what you typed in the field.\n</p>\n<p>\nIn some cases, you may need to use the simple &quot;<a\nhref=\"TestBuilderActions.html#M000019\">type</a>&quot; command to set the\nvalue of the field and then the &quot;<tt><a\nhref=\"TestBuilderActions.html#M000064\">type_keys</a></tt>&quot; command to\nsend the keystroke events corresponding to what you just typed.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000064-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000064-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 428</span>\n428:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">type_keys</span> <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">value</span>\n429:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'typeKeys'</span>, <span class=\"ruby-identifier\">locator</span>, <span class=\"ruby-identifier\">value</span>\n430:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000021\" class=\"method-detail\">\n        <a name=\"M000021\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000021\" class=\"method-signature\">\n          <span class=\"method-name\">uncheck</span><span class=\"method-args\">(locator)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nUncheck a toggle-button (checkbox/radio).\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000021-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000021-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 113</span>\n113:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">uncheck</span> <span class=\"ruby-identifier\">locator</span>\n114:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'uncheck'</span>, <span class=\"ruby-identifier\">locator</span>\n115:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000068\" class=\"method-detail\">\n        <a name=\"M000068\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000068\" class=\"method-signature\">\n          <span class=\"method-name\">wait_for_condition</span><span class=\"method-args\">(script, timeout)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nRuns the specified JavaScript snippet repeatedly until it evaluates to\n<tt>true</tt>. The snippet may have multiple lines, but only the result of\nthe last line will be considered.\n</p>\n<p>\nNote that, by default, the snippet will be run in the runner&#8216;s test\nwindow, not in the window of your application. To get the window of your\napplication, you can use the JavaScript snippet\n<tt>selenium.browserbot.getCurrentWindow()</tt>, and then run your\nJavaScript in there.\n</p>\n<p>\n<tt>timeout</tt> is specified in milliseconds.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000068-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000068-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 467</span>\n467:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">wait_for_condition</span> <span class=\"ruby-identifier\">script</span>, <span class=\"ruby-identifier\">timeout</span>\n468:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'waitForCondition'</span>, <span class=\"ruby-identifier\">script</span>, <span class=\"ruby-identifier\">timeout</span>\n469:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000070\" class=\"method-detail\">\n        <a name=\"M000070\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000070\" class=\"method-signature\">\n          <span class=\"method-name\">wait_for_page_to_load</span><span class=\"method-args\">(timeout)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nWaits for a new page to load.\n</p>\n<p>\nYou can use this command instead of the <tt>and_wait</tt> suffixes,\n<tt>click_and_wait</tt>, <tt>select_and_wait</tt>, <tt>type_and_wait</tt>\netc. (which are only available in the JS API).\n</p>\n<p>\nSelenium constantly keeps track of new pages loading, and sets a\n<tt>newPageLoaded</tt> flag when it first notices a page load. Running any\nother Selenium command after turns the flag to <tt>false</tt>. Hence, if\nyou want to wait for a page to load, you must wait immediately after a\nSelenium command that caused a page-load.\n</p>\n<p>\n<tt>timeout</tt> is specified in milliseconds.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000070-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000070-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 497</span>\n497:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">wait_for_page_to_load</span> <span class=\"ruby-identifier\">timeout</span>\n498:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'waitForPageToLoad'</span>, <span class=\"ruby-identifier\">timeout</span>\n499:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000028\" class=\"method-detail\">\n        <a name=\"M000028\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000028\" class=\"method-signature\">\n          <span class=\"method-name\">wait_for_popup</span><span class=\"method-args\">(window_id, timeout)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nWaits for a popup window to appear and load up.\n</p>\n<p>\nThe <tt>timeout</tt> is specified in milliseconds.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000028-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000028-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 185</span>\n185:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">wait_for_popup</span> <span class=\"ruby-identifier\">window_id</span>, <span class=\"ruby-identifier\">timeout</span>\n186:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'waitForPopUp'</span>, <span class=\"ruby-identifier\">window_id</span><span class=\"ruby-operator\">||</span><span class=\"ruby-value str\">'null'</span>, <span class=\"ruby-identifier\">timeout</span>\n187:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000065\" class=\"method-detail\">\n        <a name=\"M000065\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000065\" class=\"method-signature\">\n          <span class=\"method-name\">window_focus</span><span class=\"method-args\">(window_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nGives focus to a window.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000065-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000065-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 433</span>\n433:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">window_focus</span> <span class=\"ruby-identifier\">window_name</span>\n434:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'windowFocus'</span>, <span class=\"ruby-identifier\">window_name</span>\n435:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000066\" class=\"method-detail\">\n        <a name=\"M000066\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000066\" class=\"method-signature\">\n          <span class=\"method-name\">window_maximize</span><span class=\"method-args\">(window_name)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p>\nResize window to take up the entire screen.\n</p>\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000066-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000066-source\">\n<pre>\n     <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/test_builder_actions.rb, line 438</span>\n438:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">window_maximize</span> <span class=\"ruby-identifier\">window_name</span>\n439:     <span class=\"ruby-identifier\">command</span> <span class=\"ruby-value str\">'windowMaximize'</span>, <span class=\"ruby-identifier\">window_name</span>\n440:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderUserAccessors.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Module: SeleniumOnRails::TestBuilderUserAccessors</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Module</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::TestBuilderUserAccessors</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/test_builder_rb.html\">\n                lib/selenium_on_rails/test_builder.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nCreate test_builder_user_accessors.rb to support accessors included in\nselenium-core&#8216;s user-extensions.js\n</p>\n<p>\nSee test_builder_user_accessors.rb.example for examples matching\nselenium-core&#8216;s user-extensions.js.sample\n</p>\n\n    </div>\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderUserActions.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Module: SeleniumOnRails::TestBuilderUserActions</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Module</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails::TestBuilderUserActions</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../../files/lib/selenium_on_rails/test_builder_rb.html\">\n                lib/selenium_on_rails/test_builder.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nCreate test_builder_user_actions.rb to support actions included in\nselenium-core&#8216;s user-extensions.js\n</p>\n<p>\nSee test_builder_user_actions.rb.example for examples matching\nselenium-core&#8216;s user-extensions.js.sample\n</p>\n\n    </div>\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Module: SeleniumOnRails</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\".././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Module</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRails</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../files/lib/selenium_on_rails/paths_rb.html\">\n                lib/selenium_on_rails/paths.rb\n                </a>\n        <br />\n                <a href=\"../files/lib/selenium_on_rails_rb.html\">\n                lib/selenium_on_rails.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n    <div id=\"class-list\">\n      <h3 class=\"section-bar\">Classes and Modules</h3>\n\n      Module <a href=\"SeleniumOnRails/FixtureLoader.html\" class=\"link\">SeleniumOnRails::FixtureLoader</a><br />\nModule <a href=\"SeleniumOnRails/PartialsSupport.html\" class=\"link\">SeleniumOnRails::PartialsSupport</a><br />\nModule <a href=\"SeleniumOnRails/Paths.html\" class=\"link\">SeleniumOnRails::Paths</a><br />\nModule <a href=\"SeleniumOnRails/Renderer.html\" class=\"link\">SeleniumOnRails::Renderer</a><br />\nModule <a href=\"SeleniumOnRails/SuiteRenderer.html\" class=\"link\">SeleniumOnRails::SuiteRenderer</a><br />\nModule <a href=\"SeleniumOnRails/TestBuilderAccessors.html\" class=\"link\">SeleniumOnRails::TestBuilderAccessors</a><br />\nModule <a href=\"SeleniumOnRails/TestBuilderActions.html\" class=\"link\">SeleniumOnRails::TestBuilderActions</a><br />\nModule <a href=\"SeleniumOnRails/TestBuilderUserAccessors.html\" class=\"link\">SeleniumOnRails::TestBuilderUserAccessors</a><br />\nModule <a href=\"SeleniumOnRails/TestBuilderUserActions.html\" class=\"link\">SeleniumOnRails::TestBuilderUserActions</a><br />\nClass <a href=\"SeleniumOnRails/RSelenese.html\" class=\"link\">SeleniumOnRails::RSelenese</a><br />\nClass <a href=\"SeleniumOnRails/Selenese.html\" class=\"link\">SeleniumOnRails::Selenese</a><br />\nClass <a href=\"SeleniumOnRails/TestBuilder.html\" class=\"link\">SeleniumOnRails::TestBuilder</a><br />\n\n    </div>\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRailsConfig.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Class: SeleniumOnRailsConfig</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\".././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n    <div id=\"classHeader\">\n        <table class=\"header-table\">\n        <tr class=\"top-aligned-row\">\n          <td><strong>Class</strong></td>\n          <td class=\"class-name-in-header\">SeleniumOnRailsConfig</td>\n        </tr>\n        <tr class=\"top-aligned-row\">\n            <td><strong>In:</strong></td>\n            <td>\n                <a href=\"../files/lib/selenium_on_rails_config_rb.html\">\n                lib/selenium_on_rails_config.rb\n                </a>\n        <br />\n            </td>\n        </tr>\n\n        <tr class=\"top-aligned-row\">\n            <td><strong>Parent:</strong></td>\n            <td>\n                Object\n            </td>\n        </tr>\n        </table>\n    </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000007\">get</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Class methods</h3>\n\n      <div id=\"method-M000007\" class=\"method-detail\">\n        <a name=\"M000007\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000007\" class=\"method-signature\">\n          <span class=\"method-name\">get</span><span class=\"method-args\">(var, default = nil) {|if block_given?| ...}</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000007-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000007-source\">\n<pre>\n    <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails_config.rb, line 5</span>\n 5:   <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-keyword kw\">self</span>.<span class=\"ruby-identifier\">get</span> <span class=\"ruby-identifier\">var</span>, <span class=\"ruby-identifier\">default</span> = <span class=\"ruby-keyword kw\">nil</span>\n 6:     <span class=\"ruby-identifier\">value</span> = <span class=\"ruby-identifier\">configs</span>[<span class=\"ruby-identifier\">var</span>.<span class=\"ruby-identifier\">to_s</span>]\n 7:     <span class=\"ruby-identifier\">value</span> <span class=\"ruby-operator\">||=</span> <span class=\"ruby-ivar\">@@defaults</span>[<span class=\"ruby-identifier\">var</span>]\n 8:     <span class=\"ruby-identifier\">value</span> <span class=\"ruby-operator\">||=</span> <span class=\"ruby-identifier\">default</span>\n 9:     <span class=\"ruby-identifier\">value</span> <span class=\"ruby-operator\">||=</span> <span class=\"ruby-keyword kw\">yield</span> <span class=\"ruby-keyword kw\">if</span> <span class=\"ruby-identifier\">block_given?</span>\n10:     <span class=\"ruby-identifier\">value</span>\n11:   <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/CHANGELOG.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: CHANGELOG</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\".././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>CHANGELOG</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>CHANGELOG\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 23:49:15 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <h2>REVISION <a href=\"http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=38\">38</a></h2>\n<h3>change made by Flanagan</h3>\n<ul>\n<li><a href=\"http://jira.openqa.org/browse/SOR-13\">SOR-13</a> Corrected an\nomission of require statements.\n\n</li>\n</ul>\n<h2>REVISION 37</h2>\n<h3>change made by Flanagan</h3>\n<ul>\n<li>Undone an unwanted commit of modified Rakefile.\n\n</li>\n</ul>\n<h2>REVISION <a href=\"http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=36\">36</a></h2>\n<h3>change made by Flanagan</h3>\n<ul>\n<li><a href=\"http://jira.openqa.org/browse/SOR-13\">SOR-13</a> Added\n(experimental) support for user-extensions.js.\n\n</li>\n</ul>\n<h2>REVISION <a href=\"http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=35\">35</a></h2>\n<h3>all changes made by Jonas</h3>\n<ul>\n<li><a href=\"http://jira.openqa.org/browse/SOR-12\">SOR-12</a> removed all\nsupport for selenium gem\n\n</li>\n<li>Selenium Core 0.8.2 is now bundled with Selenium on Rails. If you want to\nuse other version set the &#8216;selenium_path&#8217; in config.yml\n\n</li>\n<li>Updated installation instructions for Windows\n\n</li>\n</ul>\n<h2>REVISION <a href=\"http://svn.openqa.org/fisheye/changelog/selenium-on-rails/?cs=34\">34</a></h2>\n<h3>all changes made by Flanagan</h3>\n<ul>\n<li><a href=\"http://jira.openqa.org/browse/SOR-11\">SOR-11</a> Fixed related\nassertions for store_checked to use only locator parameter\n\n</li>\n</ul>\n<p>\nWarning: Users must change tests that pass two parameters (locator,\npattern) to <tt>verify_checked</tt>, <tt>verify_not_checked</tt>,\n<tt>assert_checked</tt>, <tt>assert_not_checked</tt>,\n<tt>wait_for_checked</tt>, or <tt>wait_for_not_checked</tt>.\n</p>\n<p>\nTest scripts that continue to use two parameters will be broken, only one\nparameter, the locator, should be passed.\n</p>\n<p>\nFor example, <tt>|verify_checked|my_checkbox|true|</tt> will be interpreted\nas <tt>|verify_checked|my_checkboxtrue||</tt> so change the test to\n<tt>|verify_checked|my_checkbox||</tt>\n</p>\n<ul>\n<li><a href=\"http://jira.openqa.org/browse/SOR-9\">SOR-9</a> Added Mac OS X\nbrowsers to config.yml.example\n\n</li>\n<li><a href=\"http://jira.openqa.org/browse/SOR-10\">SOR-10</a> Added support for\nbaseUrl to acceptance_test_runner.rb as added to selenium-core 0.8.2\n\n</li>\n<li>Added &#8216;webrick&#8217; to SERVER_COMMAND in acceptance_test_runner.rb\nas parameters do not work with lighttpd\n\n</li>\n<li>Reversed expected query string in test/renderer_testrb to make tests pass\n\n</li>\n</ul>\n<p>\nNote: On Mac OS X, at least, clear_tables comes before fixtures in the\nquery string; this may be an environment-specific issue if the test now\nfails on other OSes.\n</p>\n<ul>\n<li>Added this CHANGELOG file and amended the rake rdoc task to include it\n\n</li>\n<li>Added support in rselenese for a long list of actions and accessors that\nare included in selenium-core (0.8.2 and possibly earlier) but were\npreviously missing in selenium-on-rails.\n\n</li>\n</ul>\n<p>\nHere are the newly supported actions:\n</p>\n<p>\nUseful for debugging:\n</p>\n<ul>\n<li><tt>brake</tt> (alias for selenium-core&#8216;s break, a reserved word in\nRuby)\n\n</li>\n<li><tt>echo, :string</tt>\n\n</li>\n<li><tt>highlight, :locator</tt>\n\n</li>\n</ul>\n<p>\nKeyboard events:\n</p>\n<ul>\n<li><tt>alt_key_down</tt>\n\n</li>\n<li><tt>alt_key_up</tt>\n\n</li>\n<li><tt>control_key_down</tt>\n\n</li>\n<li><tt>control_key_up</tt>\n\n</li>\n<li><tt>meta_key_down</tt>\n\n</li>\n<li><tt>meta_key_up</tt>\n\n</li>\n<li><tt>shift_key_down</tt>\n\n</li>\n<li><tt>shift_key_up</tt>\n\n</li>\n<li><tt>type_keys, :locator, :string</tt>\n\n</li>\n</ul>\n<p>\nMouse events:\n</p>\n<ul>\n<li><tt>click_at, :locator, :coord_string</tt>\n\n</li>\n<li><tt>double_click, :locator</tt>\n\n</li>\n<li><tt>double_click_at, :locator, :coord_string</tt>\n\n</li>\n<li><tt>drag_and_drop, :locator, :movements_string</tt>\n\n</li>\n<li><tt>drag_and_drop_to_object, :locator, :locator</tt>\n\n</li>\n<li><tt>mouse_down_at, :locator, :coord_string</tt>\n\n</li>\n<li><tt>mouse_move, :locator</tt>\n\n</li>\n<li><tt>mouse_move_at, :locator, :coord_string</tt>\n\n</li>\n<li><tt>mouse_out, :locator</tt>\n\n</li>\n<li><tt>mouse_up, :locator</tt>\n\n</li>\n<li><tt>mouse_up_at, :locator, :coord_string</tt>\n\n</li>\n<li><tt>set_mouse_speed, :integer</tt>\n\n</li>\n</ul>\n<p>\nOther actions:\n</p>\n<ul>\n<li><tt>create_cookie, :name_value_pair, :options_string</tt>\n\n</li>\n<li><tt>delete_cookie, :string, :string</tt>\n\n</li>\n<li><tt>open_window, :url, :integer</tt>\n\n</li>\n<li><tt>pause, :timeout</tt>\n\n</li>\n<li><tt>remove_all_selections, :locator</tt>\n\n</li>\n<li><tt>select_frame, :locator</tt>\n\n</li>\n<li><tt>set_cursor_position, :locator, :integer</tt>\n\n</li>\n<li><tt>store, :script, :variable</tt>\n\n</li>\n<li><tt>window_focus, :window_name</tt>\n\n</li>\n<li><tt>window_maximize, :window_name</tt>\n\n</li>\n</ul>\n<p>\nHere are the newly supported accessors:\n</p>\n<p>\nThe following store_* accessors and their associated assert, verify and\nwait_for brethren are fully supported:\n</p>\n<ul>\n<li><tt>store_selected_id, :locator, :variable</tt>\n\n</li>\n<li><tt>store_selected_ids, :locator, :variable</tt>\n\n</li>\n<li><tt>store_selected_index, :locator, :variable</tt>\n\n</li>\n<li><tt>store_selected_indexes, :locator, :variable</tt>\n\n</li>\n<li><tt>store_selected_label, :locator, :variable</tt>\n\n</li>\n<li><tt>store_selected_labels, :locator, :variable</tt>\n\n</li>\n<li><tt>store_selected_value, :locator, :variable</tt>\n\n</li>\n<li><tt>store_selected_values, :locator, :variable</tt>\n\n</li>\n<li><tt>store_something_selected, :locator, :variable</tt>\n\n</li>\n<li><tt>store_all_window_ids, :variable</tt>\n\n</li>\n<li><tt>store_all_window_names, :variable</tt>\n\n</li>\n<li><tt>store_all_window_titles, :variable</tt>\n\n</li>\n<li><tt>store_cookie, :variable</tt>\n\n</li>\n<li><tt>store_log_messages, :variable</tt>\n\n</li>\n<li><tt>store_mouse_speed, :variable</tt>\n\n</li>\n<li><tt>store_cursor_position, :locator, :variable</tt>\n\n</li>\n<li><tt>store_attribute_from_all_windows, :attribute_name, :variable</tt>\n\n</li>\n<li><tt>store_element_height, :locator, :variable</tt>\n\n</li>\n<li><tt>store_element_index, :locator, :variable</tt>\n\n</li>\n<li><tt>store_element_width, :locator, :variable</tt>\n\n</li>\n<li><tt>store_element_position_left, :locator, :variable</tt>\n\n</li>\n<li><tt>store_element_position_top, :locator, :variable</tt>\n\n</li>\n</ul>\n<p>\nOnly the associated assert, verify and wait_for brethren of the following\nstore_* accessors are supported by the selenium-core, so these store_*\naccessors create exceptions in SOR:\n</p>\n<ul>\n<li><tt>store_ordered, :locator, :locator, :variable</tt>\n\n</li>\n<li><tt>store_error_on_next, :string</tt>\n\n</li>\n<li><tt>store_failure_on_next, :string</tt>\n\n</li>\n<li><tt>store_whether_this_frame_match_frame_expression, :string, :string,\n:variable</tt>\n\n</li>\n<li><tt>store_whether_this_window_match_window_expression, :string, :string,\n:variable</tt>\n\n</li>\n</ul>\n\n    </div>\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/README.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: README</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\".././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>README</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>README\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:11 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n<div id=\"description\">\n\t<p>Welcome to the Selenium on Rails README.  Exciting isn&#8217;t it?</p>\n\n\t<h1 id=\"selenium_on_rails\">Selenium on Rails</h1>\n\n\t<h2 id=\"overview\">Overview</h2>\n\n\t<p>Selenium on Rails provides an easy way to test Rails application with \n\tSeleniumCore[http://www.openqa.org/selenium-core/].</p>\n\n\t<p>This plugin does four things:</p>\n\n\t<ol>\n\t<li>The Selenium Core files don&#8217;t have to pollute <tt>/public</tt>.</li>\n\t<li>No need to create suite files, they are generated on the fly &#8212; one suite per directory in <tt>/test/selenium</tt> (suites can be nested).</li>\n\t<li>Instead of writing the test cases in HTML you can use a number of better formats (see <tt>Formats</tt>).</li>\n\t<li>Loading of fixtures and wiping of session (<tt>/selenium/setup</tt>).</li>\n\t</ol>\n\n\t<h2 id=\"installation\">Installation</h2>\n\n\t<p>Rails periodically changes the way that it renders pages, which unfortunately breaks backwards versions of Selenium on Rails.  Therefore there are different\n\tinstallation locations depending on your version of Rails:</p>\n\n\t<p><em>Rails 2.2 and up:</em></p>\n\n\t<pre><code>http://svn.openqa.org/svn/selenium-on-rails/stable/selenium-on-rails\n\t</code></pre>\n\n\t<p><em>Rails 2.1:</em></p>\n\n\t<pre><code>http://svn.openqa.org/svn/selenium-on-rails/tags/rails_2_1/selenium-on-rails\n\t</code></pre>\n\n\t<p><em>Before Rails 2.1:</em></p>\n\n\t<pre><code>http://svn.openqa.org/svn/selenium-on-rails/tags/pre-rails-2-1/selenium-on-rails\n\t</code></pre>\n\n\t<p>The latest release is always kept on GitHub at </p>\n\n\t<pre><code>git clone git://github.com/paytonrules/selenium-on-rails.git\n\t</code></pre>\n\n\t<p>To install:</p>\n\n\t<ol>\n\t<li>Install Selenium on Rails: script/plugin install <URL></li>\n\t<li>If you‘re on Windows, gem install win32-open3</li>\n\t<li>If the RedCloth gem is available the Selenese test cases can use it for better markup.</li>\n\t<li>Run the Rakefile in the plugin‘s directory to run the tests in order to see that everything works. (If RedCloth isn‘t installed a few tests will fail since they assume RedCloth is installed.)</li>\n\t<li>Create a test case: script/generate selenium <TestName></li>\n\t<li>Start the server: script/server -e test</li>\n\t<li>Point your browser to localhost:3000/selenium</li>\n\t<li>If everything works as expected you should see the Selenium test runner. The north east frame contains all your test cases (just one for now), and the north frame contains your test case.</li>\n\t</ol>\n\n\t<h2 id=\"formats\">Formats</h2>\n\n\t<p>The test cases can be written in a number of formats. Which one you choose is a matter of taste. You can generate your test files by running script/generate selenium or by creating them manually in your /test/selenium directory.</p>\n\n\t<h2 id=\"rselenese_rsel\">RSelenese, .rsel</h2>\n\n\t<p>RSelenese lets you write your tests in Ruby. This is my favorite format.</p>\n\n\t<pre><code>setup :fixtures =&gt; :all\n\topen '/'\n\tassert_title 'Home'\n\t('a'..'z').each {|c| open :controller =&gt; 'user', :action =&gt; 'create', :name =&gt; c }\n\t</code></pre>\n\n\t<p>See SeleniumOnRails::TestBuilder for available commands. <em>IMPORTANT NOTE:</em> RSelenese generates the HTML tables for Selenium behind the scenes when the page is loaded - ONCE. That means code like this:</p>\n\n\t<pre><code>(1..10).each do |index|\n\t    do something\n\tend\n\t</code></pre>\n\n\t<p>Will only be executed when the test is loaded, not when the test is run. This is a common error and leads to tests that work the first time and fail the second time.</p>\n\n\t<h2 id=\"selenese_sel\">Selenese, .sel</h2>\n\n\t<p>Selenese is the dumbest format (in a good way). You just write your commands delimited by | characters.</p>\n\n\t<pre><code>|open|/selenium/setup|\n\t|open|/|\n\t|goBack|\n\t</code></pre>\n\n\t<p>If you don‘t want to write Selenese tests by hand you can use SeleniumIDE which has support for Selenese.</p>\n\n\t<h2 id=\"html_rhtml\">HTML/RHTML</h2>\n\n\t<p>You can write your tests in HTML/RHTML but that‘s mostly useful if you have existing tests you want to reuse.</p>\n\n\t<h2 id=\"partial_test_cases\">Partial test cases</h2>\n\n\t<p>If you have some common actions you want to do in several test cases you can put them in a separate partial test case and include them in your other test cases. This is highly recommended, just as small functions would be recommended in structured programming.</p>\n\n\t<p>A partial test case is just like a normal test case besides that its filename has to start with _:</p>\n\n\t<pre><code>#_login.rsel\n\topen '/login'\n\ttype 'name', name\n\ttype 'password', password\n\tclick 'submit', :wait=&gt;true\n\t</code></pre>\n\n\t<p>To include a partial test case in a RSelenese test case:</p>\n\n\t<pre><code>include_partial 'login', :name =&gt; 'Jane Doe', :password =&gt; 'Jane Doe'.reverse\n\t</code></pre>\n\n\t<p>in a Selenese test case:</p>\n\n\t<pre><code>|includePartial|login|name=John Doe|password=eoD nhoJ|\n\t</code></pre>\n\n\t<p>and in a RHTML test case:</p>\n\n\t<pre><code>&lt;%= render :partial =&gt; 'login', :locals =&gt; {:name = 'Joe Schmo', :password =&gt; 'Joe Schmo'.reverse} %&gt;\n\t</code></pre>\n\n\t<h2 id=\"configuration\">Configuration</h2>\n\n\t<p>There are a number of settings available. You make them by renaming selenium.yml.example to selenium.yml and placing it in your rails app&#8217;s config \n\tfile.  Make your changes in that file.</p>\n\n\t<h2 id=\"environments\">Environments</h2>\n\n\t<p>Per default this plugin is only available in test environment. You can change this by setting environments, such as:</p>\n\n\t<pre><code>#selenium.yml\n\tenvironments:\n\t    - test\n\t    - development\n\t</code></pre>\n\n\t<h2 id=\"selenium_core_path\">Selenium Core path</h2>\n\n\t<p>If you don‘t want to use the bundled Selenium Core version you can set selenium_path to the directory where Selenium Core is stored.</p>\n\n\t<pre><code>#config.yml\n\tselenium_path: 'c:\\selenium'\n\t</code></pre>\n\n\t<h2 id=\"rake_task\">Rake Task</h2>\n\n\t<p>You can run all your Selenium tests as a Rake task. If you&#8217;re using a continuous builder this is a great way to integrate selenium into your build process.  First, if you‘re on Windows, you have to make sure win32-open3 is installed. Then you have to configure which browsers you want to run, like this:</p>\n\n\t<pre><code>#config.yml\n\tbrowsers:\n\t    firefox: 'c:\\Program Files\\Mozilla Firefox\\firefox.exe'\n\t    ie: 'c:\\Program Files\\Internet Explorer\\iexplore.exe'\n\t</code></pre>\n\n\t<p>Now you‘re all set. First start a server:</p>\n\n\t<pre><code>script/server -e test\n\t</code></pre>\n\n\t<p>Then run the tests:</p>\n\n\t<pre><code>rake test:acceptance\n\t</code></pre>\n\n\t<p>Now it should work, otherwise let me know!</p>\n\n\t<h2 id=\"store_results\">Store results</h2>\n\n\t<p>If you want to store the results from a test:acceptance you just need to set in which directory they should be stored:</p>\n\n\t<pre><code>#config.yml\n\tresult_dir: 'c:\\result'\n\t</code></pre>\n\n\t<p>So when you run rake test:acceptance the tables with the results will be stored as .html files in that directory.</p>\n\n\t<h2 id=\"user_extensionjs\">user_extension.js</h2>\n\n\t<p>Selenium has support for user_extension.js which is a way to extend the functionality of Selenium Core. Selenium on Rails now provides the means for you to extend it&#8217;s functionality to match.</p>\n\n\t<p>To get you started, we&#8217;ve included the example files lib/test_builder_user_accessors.rb.example and lib/test_builder_user_actions.rb.example that replicate the sample extensions in Selenium Core&#8217;s user-extensions.js.sample.</p>\n\n\t<p>To get these examples running, simply remove the .example and .sample extensions \n\tfrom the files and restart your server.</p>\n\n\t<h2 id=\"todo\">Todo</h2>\n\n\t<ul>\n\t<li><p>Standalone mode\n\tMore work is needed on test:acceptance&lt; on Windows to be able to start the server when needed.</p></li>\n\t<li><p>Documentation update</p></li>\n\t</ul>\n\n\t<h2 id=\"not_todo\">Not todo</h2>\n\n\t<ul>\n\t<li>Editor\n\tCreating an editor for the test cases is currently considered out of scope for this plugin. SeleniumIDE[http://www.openqa.org/selenium-ide/] does such a good  job and has support[http://wiki.openqa.org/display/SIDE/SeleniumOnRails] for both the Selenese and RSelenese formats.</li>\n\t</ul>\n\n\t<h2 id=\"credits\">Credits</h2>\n\n\t<ul>\n\t<li>Jonas Bengston &#8212; original creator</li>\n\t<li>Eric Smith, http://blog.8thlight.com/eric &#8212; Current Maintainer</li>\n\t<li>Jon Tirsen, http://jutopia.tirsen.com &#8212; initial inspiration[http://wiki.rubyonrails.com/rails/pages/SeleniumIntegration]</li>\n\t<li>Eric Kidd, http://www.randomhacks.net &#8212; contribution of RSelenese</li>\n\t<li>Marcos Tapajós http://www.improveit.com.br/en/company/tapajos &#8212; Several useful features, current committer</li>\n\t<li>Ryan Bates, http://railscasts.com &#8212; Fixes for Rails 2.1</li>\n\t<li>Nando Vieira, http://simplesideias.com.br</li>\n\t<li>Gordon McCreight, a neat script that lists any unsupported methods</li>\n\t</ul>\n\n\t<h2 id=\"contributing_\">Contributing ##</h2>\n\n\t<p>Contributing is simple.  Fork this repo, make your changes, then issue a pull request.  <em>IMPORTANT</em> I will not take forks that do not have associated unit tests.  There must be tests, and they must pass, so I can bring the changes in.</p>\n\n\t<h2 id=\"information\">Information</h2>\n\n\t<p>For more information, check out the <a href=\"http://seleniumhq.org/projects/on-rails/\">website</a>.</p>\n\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/controllers/selenium_controller_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: selenium_controller.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>selenium_controller.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/controllers/selenium_controller.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:05 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n    <div id=\"requires-list\">\n      <h3 class=\"section-bar\">Required files</h3>\n\n      <div class=\"name-list\">\n      webrick/httputils&nbsp;&nbsp;\n      </div>\n    </div>\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_helper_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: selenium_helper.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>selenium_helper.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_helper.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/acceptance_test_runner_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: acceptance_test_runner.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>acceptance_test_runner.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails/acceptance_test_runner.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n    <div id=\"requires-list\">\n      <h3 class=\"section-bar\">Required files</h3>\n\n      <div class=\"name-list\">\n      net/http&nbsp;&nbsp;\n      tempfile&nbsp;&nbsp;\n      </div>\n    </div>\n\n   </div>\n\n    <div id=\"method-list\">\n      <h3 class=\"section-bar\">Methods</h3>\n\n      <div class=\"name-list\">\n      <a href=\"#M000001\">c</a>&nbsp;&nbsp;\n      <a href=\"#M000002\">c_b</a>&nbsp;&nbsp;\n      </div>\n    </div>\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n    <div id=\"constants-list\">\n      <h3 class=\"section-bar\">Constants</h3>\n\n      <div class=\"name-list\">\n        <table summary=\"Constants\">\n        <tr class=\"top-aligned-row context-row\">\n          <td class=\"context-item-name\">BROWSERS</td>\n          <td>=</td>\n          <td class=\"context-item-value\">c :browsers, {}</td>\n        </tr>\n        <tr class=\"top-aligned-row context-row\">\n          <td class=\"context-item-name\">REUSE_EXISTING_SERVER</td>\n          <td>=</td>\n          <td class=\"context-item-value\">c :reuse_existing_server, true</td>\n        </tr>\n        <tr class=\"top-aligned-row context-row\">\n          <td class=\"context-item-name\">START_SERVER</td>\n          <td>=</td>\n          <td class=\"context-item-value\">c :start_server, false</td>\n        </tr>\n        <tr class=\"top-aligned-row context-row\">\n          <td class=\"context-item-name\">HOST</td>\n          <td>=</td>\n          <td class=\"context-item-value\">c :host, 'localhost'</td>\n        </tr>\n        <tr class=\"top-aligned-row context-row\">\n          <td class=\"context-item-name\">PORTS</td>\n          <td>=</td>\n          <td class=\"context-item-value\">c(:port_start, 3000)..c(:port_end, 3005)</td>\n        </tr>\n        <tr class=\"top-aligned-row context-row\">\n          <td class=\"context-item-name\">BASE_URL_PATH</td>\n          <td>=</td>\n          <td class=\"context-item-value\">c :base_url_path, '/'</td>\n        </tr>\n        <tr class=\"top-aligned-row context-row\">\n          <td class=\"context-item-name\">TEST_RUNNER_URL</td>\n          <td>=</td>\n          <td class=\"context-item-value\">c :test_runner_url, '/selenium/TestRunner.html'</td>\n        </tr>\n        <tr class=\"top-aligned-row context-row\">\n          <td class=\"context-item-name\">MAX_BROWSER_DURATION</td>\n          <td>=</td>\n          <td class=\"context-item-value\">c :max_browser_duration, 2*60</td>\n        </tr>\n        <tr class=\"top-aligned-row context-row\">\n          <td class=\"context-item-name\">MULTI_WINDOW</td>\n          <td>=</td>\n          <td class=\"context-item-value\">c :multi_window, false</td>\n        </tr>\n        <tr class=\"top-aligned-row context-row\">\n          <td class=\"context-item-name\">SERVER_COMMAND</td>\n          <td>=</td>\n          <td class=\"context-item-value\">c_b :server_command do\r   server_path = File.expand_path(File.dirname(__FILE__) + '/../../../../../script/server')</td>\n        </tr>\n        </table>\n      </div>\n    </div>\n\n\n\n      \n\n\n    <!-- if method_list -->\n    <div id=\"methods\">\n      <h3 class=\"section-bar\">Public Instance methods</h3>\n\n      <div id=\"method-M000001\" class=\"method-detail\">\n        <a name=\"M000001\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000001\" class=\"method-signature\">\n          <span class=\"method-name\">c</span><span class=\"method-args\">(var, default = nil)</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000001-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000001-source\">\n<pre>\n   <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/acceptance_test_runner.rb, line 7</span>\n7: <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">c</span>(<span class=\"ruby-identifier\">var</span>, <span class=\"ruby-identifier\">default</span> = <span class=\"ruby-keyword kw\">nil</span>) <span class=\"ruby-constant\">SeleniumOnRailsConfig</span>.<span class=\"ruby-identifier\">get</span> <span class=\"ruby-identifier\">var</span>, <span class=\"ruby-identifier\">default</span> <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n      <div id=\"method-M000002\" class=\"method-detail\">\n        <a name=\"M000002\"></a>\n\n        <div class=\"method-heading\">\n          <a href=\"#M000002\" class=\"method-signature\">\n          <span class=\"method-name\">c_b</span><span class=\"method-args\">(var, default = nil) {|| ...}</span>\n          </a>\n        </div>\n      \n        <div class=\"method-description\">\n          <p><a class=\"source-toggle\" href=\"#\"\n            onclick=\"toggleCode('M000002-source');return false;\">[Source]</a></p>\n          <div class=\"method-source-code\" id=\"M000002-source\">\n<pre>\n   <span class=\"ruby-comment cmt\"># File lib/selenium_on_rails/acceptance_test_runner.rb, line 8</span>\n8: <span class=\"ruby-keyword kw\">def</span> <span class=\"ruby-identifier\">c_b</span>(<span class=\"ruby-identifier\">var</span>, <span class=\"ruby-identifier\">default</span> = <span class=\"ruby-keyword kw\">nil</span>) <span class=\"ruby-constant\">SeleniumOnRailsConfig</span>.<span class=\"ruby-identifier\">get</span>(<span class=\"ruby-identifier\">var</span>, <span class=\"ruby-identifier\">default</span>) { <span class=\"ruby-keyword kw\">yield</span> } <span class=\"ruby-keyword kw\">end</span>\n</pre>\n          </div>\n        </div>\n      </div>\n\n\n    </div>\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/fixture_loader_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: fixture_loader.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>fixture_loader.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails/fixture_loader.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n    <div id=\"requires-list\">\n      <h3 class=\"section-bar\">Required files</h3>\n\n      <div class=\"name-list\">\n      test/unit&nbsp;&nbsp;\n      active_record/fixtures&nbsp;&nbsp;\n      </div>\n    </div>\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/partials_support_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: partials_support.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>partials_support.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails/partials_support.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nProvides partials support to test cases so they can include other partial\ntest cases.\n</p>\n<p>\nThe partial&#8216;s commands are returned as html table rows.\n</p>\n\n    </div>\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/paths_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: paths.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>paths.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails/paths.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/renderer_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: renderer.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>renderer.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails/renderer.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/rselenese_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: rselenese.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>rselenese.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails/rselenese.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nRenders Selenium test templates in a fashion analogous to <tt>rxml</tt> and\n<tt>rjs</tt> templates.\n</p>\n<pre>\n  setup\n  open :controller =&gt; 'customer', :action =&gt; 'list'\n  assert_title 'Customers'\n</pre>\n<p>\nSee <a\nhref=\"../../../classes/SeleniumOnRails/TestBuilder.html\">SeleniumOnRails::TestBuilder</a>\nfor a list of available commands.\n</p>\n\n    </div>\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/selenese_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: selenese.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>selenese.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails/selenese.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/suite_renderer_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: suite_renderer.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>suite_renderer.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails/suite_renderer.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/test_builder_accessors_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: test_builder_accessors.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>test_builder_accessors.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails/test_builder_accessors.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nThe accessors available for <a\nhref=\"../../../classes/SeleniumOnRails/TestBuilder.html\">SeleniumOnRails::TestBuilder</a>\ntests.\n</p>\n<p>\nFor each <tt>store_foo</tt> there&#8216;s <tt>assert_foo</tt>,\n<tt>assert_not_foo</tt>, <tt>verify_foo</tt>, <tt>verify_not_foo</tt>,\n<tt>wait_for_foo</tt>, <tt>wait_for_not_foo</tt>.\n</p>\n\n    </div>\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/test_builder_actions_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: test_builder_actions.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>test_builder_actions.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails/test_builder_actions.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nThe actions available for <a\nhref=\"../../../classes/SeleniumOnRails/TestBuilder.html\">SeleniumOnRails::TestBuilder</a>\ntests.\n</p>\n<p>\nFor each action <tt>foo</tt> there&#8216;s also an action\n<tt>foo_and_wait</tt>.\n</p>\n\n    </div>\n\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/test_builder_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: test_builder.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>test_builder.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails/test_builder.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 23:42:13 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n    <div id=\"description\">\n      <p>\nCreate test_builder_user_actions.rb to support actions included in\nselenium-core&#8216;s user-extensions.js\n</p>\n<p>\nSee test_builder_user_actions.rb.example for examples matching\nselenium-core&#8216;s user-extensions.js.sample\n</p>\n\n    </div>\n\n    <div id=\"requires-list\">\n      <h3 class=\"section-bar\">Required files</h3>\n\n      <div class=\"name-list\">\n      selenium_on_rails/test_builder_user_actions&nbsp;&nbsp;\n      selenium_on_rails/test_builder_user_accessors&nbsp;&nbsp;\n      </div>\n    </div>\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails_config_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: selenium_on_rails_config.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>selenium_on_rails_config.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails_config.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 22:54:06 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n    <div id=\"requires-list\">\n      <h3 class=\"section-bar\">Required files</h3>\n\n      <div class=\"name-list\">\n      yaml&nbsp;&nbsp;\n      </div>\n    </div>\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails_rb.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>File: selenium_on_rails.rb</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n  <link rel=\"stylesheet\" href=\"../.././rdoc-style.css\" type=\"text/css\" media=\"screen\" />\n  <script type=\"text/javascript\">\n  // <![CDATA[\n\n  function popupCode( url ) {\n    window.open(url, \"Code\", \"resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400\")\n  }\n\n  function toggleCode( id ) {\n    if ( document.getElementById )\n      elem = document.getElementById( id );\n    else if ( document.all )\n      elem = eval( \"document.all.\" + id );\n    else\n      return false;\n\n    elemStyle = elem.style;\n    \n    if ( elemStyle.display != \"block\" ) {\n      elemStyle.display = \"block\"\n    } else {\n      elemStyle.display = \"none\"\n    }\n\n    return true;\n  }\n  \n  // Make codeblocks hidden by default\n  document.writeln( \"<style type=\\\"text/css\\\">div.method-source-code { display: none }</style>\" )\n  \n  // ]]>\n  </script>\n\n</head>\n<body>\n\n\n\n  <div id=\"fileHeader\">\n    <h1>selenium_on_rails.rb</h1>\n    <table class=\"header-table\">\n    <tr class=\"top-aligned-row\">\n      <td><strong>Path:</strong></td>\n      <td>lib/selenium_on_rails.rb\n      </td>\n    </tr>\n    <tr class=\"top-aligned-row\">\n      <td><strong>Last Update:</strong></td>\n      <td>Sat Feb 03 23:38:50 +0100 2007</td>\n    </tr>\n    </table>\n  </div>\n  <!-- banner header -->\n\n  <div id=\"bodyContent\">\n\n\n\n  <div id=\"contextContent\">\n\n\n    <div id=\"requires-list\">\n      <h3 class=\"section-bar\">Required files</h3>\n\n      <div class=\"name-list\">\n      selenium_on_rails/selenese&nbsp;&nbsp;\n      selenium_on_rails/test_builder&nbsp;&nbsp;\n      selenium_on_rails/rselenese&nbsp;&nbsp;\n      selenium_on_rails/suite_renderer&nbsp;&nbsp;\n      selenium_on_rails/paths&nbsp;&nbsp;\n      selenium_on_rails/fixture_loader&nbsp;&nbsp;\n      selenium_on_rails/partials_support&nbsp;&nbsp;\n      selenium_on_rails/renderer&nbsp;&nbsp;\n      </div>\n    </div>\n\n   </div>\n\n\n  </div>\n\n\n    <!-- if includes -->\n\n    <div id=\"section\">\n\n\n\n\n\n      \n\n\n    <!-- if method_list -->\n\n\n  </div>\n\n\n<div id=\"validator-badges\">\n  <p><small><a href=\"http://validator.w3.org/check/referer\">[Validate]</a></small></p>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/fr_class_index.html",
    "content": "\n<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<!--\n\n    Classes\n\n  -->\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Classes</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <link rel=\"stylesheet\" href=\"rdoc-style.css\" type=\"text/css\" />\n  <base target=\"docwin\" />\n</head>\n<body>\n<div id=\"index\">\n  <h1 class=\"section-bar\">Classes</h1>\n  <div id=\"index-entries\">\n    <a href=\"classes/SeleniumController.html\">SeleniumController</a><br />\n    <a href=\"classes/SeleniumHelper.html\">SeleniumHelper</a><br />\n    <a href=\"classes/SeleniumOnRails.html\">SeleniumOnRails</a><br />\n    <a href=\"classes/SeleniumOnRails/FixtureLoader.html\">SeleniumOnRails::FixtureLoader</a><br />\n    <a href=\"classes/SeleniumOnRails/PartialsSupport.html\">SeleniumOnRails::PartialsSupport</a><br />\n    <a href=\"classes/SeleniumOnRails/Paths.html\">SeleniumOnRails::Paths</a><br />\n    <a href=\"classes/SeleniumOnRails/RSelenese.html\">SeleniumOnRails::RSelenese</a><br />\n    <a href=\"classes/SeleniumOnRails/Renderer.html\">SeleniumOnRails::Renderer</a><br />\n    <a href=\"classes/SeleniumOnRails/Selenese.html\">SeleniumOnRails::Selenese</a><br />\n    <a href=\"classes/SeleniumOnRails/SuiteRenderer.html\">SeleniumOnRails::SuiteRenderer</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilder.html\">SeleniumOnRails::TestBuilder</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html\">SeleniumOnRails::TestBuilderAccessors</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html\">SeleniumOnRails::TestBuilderActions</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderUserAccessors.html\">SeleniumOnRails::TestBuilderUserAccessors</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderUserActions.html\">SeleniumOnRails::TestBuilderUserActions</a><br />\n    <a href=\"classes/SeleniumOnRailsConfig.html\">SeleniumOnRailsConfig</a><br />\n  </div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/fr_file_index.html",
    "content": "\n<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<!--\n\n    Files\n\n  -->\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Files</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <link rel=\"stylesheet\" href=\"rdoc-style.css\" type=\"text/css\" />\n  <base target=\"docwin\" />\n</head>\n<body>\n<div id=\"index\">\n  <h1 class=\"section-bar\">Files</h1>\n  <div id=\"index-entries\">\n    <a href=\"files/CHANGELOG.html\">CHANGELOG</a><br />\n    <a href=\"files/README.html\">README</a><br />\n    <a href=\"files/lib/controllers/selenium_controller_rb.html\">lib/controllers/selenium_controller.rb</a><br />\n    <a href=\"files/lib/selenium_helper_rb.html\">lib/selenium_helper.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails_rb.html\">lib/selenium_on_rails.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails/acceptance_test_runner_rb.html\">lib/selenium_on_rails/acceptance_test_runner.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails/fixture_loader_rb.html\">lib/selenium_on_rails/fixture_loader.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails/partials_support_rb.html\">lib/selenium_on_rails/partials_support.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails/paths_rb.html\">lib/selenium_on_rails/paths.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails/renderer_rb.html\">lib/selenium_on_rails/renderer.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails/rselenese_rb.html\">lib/selenium_on_rails/rselenese.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails/selenese_rb.html\">lib/selenium_on_rails/selenese.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails/suite_renderer_rb.html\">lib/selenium_on_rails/suite_renderer.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails/test_builder_rb.html\">lib/selenium_on_rails/test_builder.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails/test_builder_accessors_rb.html\">lib/selenium_on_rails/test_builder_accessors.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails/test_builder_actions_rb.html\">lib/selenium_on_rails/test_builder_actions.rb</a><br />\n    <a href=\"files/lib/selenium_on_rails_config_rb.html\">lib/selenium_on_rails_config.rb</a><br />\n  </div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/fr_method_index.html",
    "content": "\n<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\n<!--\n\n    Methods\n\n  -->\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>Methods</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n  <link rel=\"stylesheet\" href=\"rdoc-style.css\" type=\"text/css\" />\n  <base target=\"docwin\" />\n</head>\n<body>\n<div id=\"index\">\n  <h1 class=\"section-bar\">Methods</h1>\n  <div id=\"index-entries\">\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000023\">add_selection (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000034\">alt_key_down (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000035\">alt_key_up (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000030\">answer_on_next_prompt (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/FixtureLoader.html#M000083\">available_fixtures (SeleniumOnRails::FixtureLoader)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000036\">brake (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"files/lib/selenium_on_rails/acceptance_test_runner_rb.html#M000001\">c (lib/selenium_on_rails/acceptance_test_runner.rb)</a><br />\n    <a href=\"files/lib/selenium_on_rails/acceptance_test_runner_rb.html#M000002\">c_b (lib/selenium_on_rails/acceptance_test_runner.rb)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000020\">check (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000029\">choose_cancel_on_next_confirmation (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/FixtureLoader.html#M000085\">clear_tables (SeleniumOnRails::FixtureLoader)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000011\">click (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000012\">click_at (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000033\">close (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilder.html#M000156\">collection_arg (SeleniumOnRails::TestBuilder)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilder.html#M000151\">command (SeleniumOnRails::TestBuilder)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilder.html#M000153\">command_and_wait (SeleniumOnRails::TestBuilder)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilder.html#M000152\">command_verbatim (SeleniumOnRails::TestBuilder)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000037\">control_key_down (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000038\">control_key_up (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000039\">create_cookie (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000040\">delete_cookie (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000041\">double_click (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000042\">double_click_at (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000043\">drag_and_drop (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000044\">drag_and_drop_to_object (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000045\">echo (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilder.html#M000148\">exactize (SeleniumOnRails::TestBuilder)</a><br />\n    <a href=\"classes/SeleniumOnRails/PartialsSupport.html#M000142\">extract_commands_from_partial (SeleniumOnRails::PartialsSupport)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000013\">fire_event (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/Paths.html#M000076\">fixtures_path (SeleniumOnRails::Paths)</a><br />\n    <a href=\"classes/SeleniumOnRailsConfig.html#M000007\">get (SeleniumOnRailsConfig)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000031\">go_back (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000046\">highlight (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000010\">include_partial (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000015\">key_down (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000014\">key_press (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000016\">key_up (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/Paths.html#M000075\">layout_path (SeleniumOnRails::Paths)</a><br />\n    <a href=\"classes/SeleniumOnRails/SuiteRenderer.html#M000082\">link_to_test_case (SeleniumOnRails::SuiteRenderer)</a><br />\n    <a href=\"classes/SeleniumOnRails/FixtureLoader.html#M000084\">load_fixtures (SeleniumOnRails::FixtureLoader)</a><br />\n    <a href=\"classes/SeleniumOnRails/Paths.html#M000077\">log_path (SeleniumOnRails::Paths)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilder.html#M000154\">make_command_waiting (SeleniumOnRails::TestBuilder)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000047\">meta_key_down (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000048\">meta_key_up (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000018\">mouse_down (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000049\">mouse_down_at (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000050\">mouse_move (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000051\">mouse_move_at (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000052\">mouse_out (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000017\">mouse_over (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000053\">mouse_up (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000054\">mouse_up_at (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilder.html#M000149\">new (SeleniumOnRails::TestBuilder)</a><br />\n    <a href=\"classes/SeleniumOnRails/RSelenese.html#M000145\">new (SeleniumOnRails::RSelenese)</a><br />\n    <a href=\"classes/SeleniumOnRails/Selenese.html#M000143\">new (SeleniumOnRails::Selenese)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000026\">open (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000055\">open_window (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000056\">pause (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumController.html#M000006\">record (SeleniumController)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000032\">refresh (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000057\">remove_all_selections (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000024\">remove_selection (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/RSelenese.html#M000146\">render (SeleniumOnRails::RSelenese)</a><br />\n    <a href=\"classes/SeleniumOnRails/Selenese.html#M000144\">render (SeleniumOnRails::Selenese)</a><br />\n    <a href=\"classes/SeleniumOnRails/PartialsSupport.html#M000141\">render_partial (SeleniumOnRails::PartialsSupport)</a><br />\n    <a href=\"classes/SeleniumOnRails/Renderer.html#M000071\">render_test_case (SeleniumOnRails::Renderer)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000022\">select (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000058\">select_frame (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000027\">select_window (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/Paths.html#M000072\">selenium_path (SeleniumOnRails::Paths)</a><br />\n    <a href=\"classes/SeleniumOnRails/Paths.html#M000073\">selenium_tests_path (SeleniumOnRails::Paths)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilder.html#M000147\">selenize (SeleniumOnRails::TestBuilder)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000067\">set_context (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000059\">set_cursor_position (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000060\">set_mouse_speed (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000069\">set_timeout (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000009\">setup (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumController.html#M000003\">setup (SeleniumController)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000061\">shift_key_down (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000062\">shift_key_up (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/Paths.html#M000078\">skip_file? (SeleniumOnRails::Paths)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000063\">store (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000100\">store_absolute_location (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000097\">store_alert (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000091\">store_alert_present (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000134\">store_all_buttons (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000136\">store_all_fields (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000135\">store_all_links (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000088\">store_all_window_ids (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000089\">store_all_window_names (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000090\">store_all_window_titles (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000122\">store_attribute (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000092\">store_attribute_from_all_windows (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000104\">store_body_text (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000108\">store_checked (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000098\">store_confirmation (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000094\">store_confirmation_present (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000095\">store_cookie (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000096\">store_cursor_position (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000133\">store_editable (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000127\">store_element_height (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000128\">store_element_index (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000130\">store_element_position_left (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000131\">store_element_position_top (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000125\">store_element_present (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000129\">store_element_width (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000086\">store_error_on_next (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000107\">store_eval (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000138\">store_expression (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000087\">store_failure_on_next (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000137\">store_html_source (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000101\">store_location (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000132\">store_log_messages (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000102\">store_mouse_speed (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000123\">store_ordered (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000099\">store_prompt (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000093\">store_prompt_present (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000121\">store_select_options (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000110\">store_selected (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000111\">store_selected_id (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000112\">store_selected_ids (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000113\">store_selected_index (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000114\">store_selected_indexes (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000115\">store_selected_label (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000116\">store_selected_labels (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000120\">store_selected_options (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000117\">store_selected_value (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000118\">store_selected_values (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000119\">store_something_selected (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000109\">store_table (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000106\">store_text (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000124\">store_text_present (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000103\">store_title (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000105\">store_value (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000126\">store_visible (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000139\">store_whether_this_frame_match_frame_expression (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderAccessors.html#M000140\">store_whether_this_window_match_window_expression (SeleniumOnRails::TestBuilderAccessors)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000025\">submit (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumController.html#M000005\">support_file (SeleniumController)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilder.html#M000150\">table (SeleniumOnRails::TestBuilder)</a><br />\n    <a href=\"classes/SeleniumHelper.html#M000008\">test_case_name (SeleniumHelper)</a><br />\n    <a href=\"classes/SeleniumOnRails/SuiteRenderer.html#M000081\">test_cases (SeleniumOnRails::SuiteRenderer)</a><br />\n    <a href=\"classes/SeleniumController.html#M000004\">test_file (SeleniumController)</a><br />\n    <a href=\"classes/SeleniumOnRails/SuiteRenderer.html#M000079\">test_suite_name (SeleniumOnRails::SuiteRenderer)</a><br />\n    <a href=\"classes/SeleniumOnRails/SuiteRenderer.html#M000080\">test_suites (SeleniumOnRails::SuiteRenderer)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000019\">type (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000064\">type_keys (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000021\">uncheck (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilder.html#M000155\">url_arg (SeleniumOnRails::TestBuilder)</a><br />\n    <a href=\"classes/SeleniumOnRails/Paths.html#M000074\">view_path (SeleniumOnRails::Paths)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000068\">wait_for_condition (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000070\">wait_for_page_to_load (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000028\">wait_for_popup (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000065\">window_focus (SeleniumOnRails::TestBuilderActions)</a><br />\n    <a href=\"classes/SeleniumOnRails/TestBuilderActions.html#M000066\">window_maximize (SeleniumOnRails::TestBuilderActions)</a><br />\n  </div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/index.html",
    "content": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<!DOCTYPE html \n     PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\"\n     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">\n\n<!--\n\n    SeleniumOnRails\n\n  -->\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <title>SeleniumOnRails</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n</head>\n<frameset rows=\"20%, 80%\">\n    <frameset cols=\"25%,35%,45%\">\n        <frame src=\"fr_file_index.html\"   title=\"Files\" name=\"Files\" />\n        <frame src=\"fr_class_index.html\"  name=\"Classes\" />\n        <frame src=\"fr_method_index.html\" name=\"Methods\" />\n    </frameset>\n    <frame src=\"files/README.html\" name=\"docwin\" />\n</frameset>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/doc/rdoc-style.css",
    "content": "\nbody {\n    font-family: Verdana,Arial,Helvetica,sans-serif;\n    font-size:   90%;\n    margin: 0;\n    margin-left: 40px;\n    padding: 0;\n    background: white;\n}\n\nh1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }\nh1 { font-size: 150%; }\nh2,h3,h4 { margin-top: 1em; }\n\na { background: #eef; color: #039; text-decoration: none; }\na:hover { background: #039; color: #eef; }\n\n/* Override the base stylesheet's Anchor inside a table cell */\ntd > a {\n  background: transparent;\n  color: #039;\n  text-decoration: none;\n}\n\n/* and inside a section title */\n.section-title > a {\n  background: transparent;\n  color: #eee;\n  text-decoration: none;\n}\n\n/* === Structural elements =================================== */\n\ndiv#index {\n    margin: 0;\n    margin-left: -40px;\n    padding: 0;\n    font-size: 90%;\n}\n\n\ndiv#index a {\n    margin-left: 0.7em;\n}\n\ndiv#index .section-bar {\n   margin-left: 0px;\n   padding-left: 0.7em;\n   background: #ccc;\n   font-size: small;\n}\n\n\ndiv#classHeader, div#fileHeader {\n    width: auto;\n    color: white;\n    padding: 0.5em 1.5em 0.5em 1.5em;\n    margin: 0;\n    margin-left: -40px;\n    border-bottom: 3px solid #006;\n}\n\ndiv#classHeader a, div#fileHeader a {\n    background: inherit;\n    color: white;\n}\n\ndiv#classHeader td, div#fileHeader td {\n    background: inherit;\n    color: white;\n}\n\n\ndiv#fileHeader {\n    background: #057;\n}\n\ndiv#classHeader {\n    background: #048;\n}\n\n\n.class-name-in-header {\n  font-size:  180%;\n  font-weight: bold;\n}\n\n\ndiv#bodyContent {\n    padding: 0 1.5em 0 1.5em;\n}\n\ndiv#description {\n    padding: 0.5em 1.5em;\n    background: #efefef;\n    border: 1px dotted #999;\n}\n\ndiv#description h1,h2,h3,h4,h5,h6 {\n    color: #125;;\n    background: transparent;\n}\n\ndiv#validator-badges {\n    text-align: center;\n}\ndiv#validator-badges img { border: 0; }\n\ndiv#copyright {\n    color: #333;\n    background: #efefef;\n    font: 0.75em sans-serif;\n    margin-top: 5em;\n    margin-bottom: 0;\n    padding: 0.5em 2em;\n}\n\n\n/* === Classes =================================== */\n\ntable.header-table {\n    color: white;\n    font-size: small;\n}\n\n.type-note {\n    font-size: small;\n    color: #DEDEDE;\n}\n\n.xxsection-bar {\n    background: #eee;\n    color: #333;\n    padding: 3px;\n}\n\n.section-bar {\n   color: #333;\n   border-bottom: 1px solid #999;\n    margin-left: -20px;\n}\n\n\n.section-title {\n    background: #79a;\n    color: #eee;\n    padding: 3px;\n    margin-top: 2em;\n    margin-left: -30px;\n    border: 1px solid #999;\n}\n\n.top-aligned-row {  vertical-align: top }\n.bottom-aligned-row { vertical-align: bottom }\n\n/* --- Context section classes ----------------------- */\n\n.context-row { }\n.context-item-name { font-family: monospace; font-weight: bold; color: black; }\n.context-item-value { font-size: small; color: #448; }\n.context-item-desc { color: #333; padding-left: 2em; }\n\n/* --- Method classes -------------------------- */\n.method-detail {\n    background: #efefef;\n    padding: 0;\n    margin-top: 0.5em;\n    margin-bottom: 1em;\n    border: 1px dotted #ccc;\n}\n.method-heading {\n  color: black;\n  background: #ccc;\n  border-bottom: 1px solid #666;\n  padding: 0.2em 0.5em 0 0.5em;\n}\n.method-signature { color: black; background: inherit; }\n.method-name { font-weight: bold; }\n.method-args { font-style: italic; }\n.method-description { padding: 0 0.5em 0 0.5em; }\n\n/* --- Source code sections -------------------- */\n\na.source-toggle { font-size: 90%; }\ndiv.method-source-code {\n    background: #262626;\n    color: #ffdead;\n    margin: 1em;\n    padding: 0.5em;\n    border: 1px dashed #999;\n    overflow: hidden;\n}\n\ndiv.method-source-code pre { color: #ffdead; overflow: hidden; }\n\n/* --- Ruby keyword styles --------------------- */\n\n.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }\n\n.ruby-constant  { color: #7fffd4; background: transparent; }\n.ruby-keyword { color: #00ffff; background: transparent; }\n.ruby-ivar    { color: #eedd82; background: transparent; }\n.ruby-operator  { color: #00ffee; background: transparent; }\n.ruby-identifier { color: #ffdead; background: transparent; }\n.ruby-node    { color: #ffa07a; background: transparent; }\n.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }\n.ruby-regexp  { color: #ffa07a; background: transparent; }\n.ruby-value   { color: #7fffd4; background: transparent; }"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/generators/selenium/USAGE",
    "content": "Description:\n    Generates a stub Selenium test case.\n\nExamples:\n    ./script/generate selenium login\n    will create:\n        /test/selenium/login.sel\n    \n    ./script/generate selenium user/create\n    will create:\n        /test/selenium/user/create.sel\n\n    ./script/generate selenium login.rsel\n    will create:\n        /test/selenium/login.rsel\n        \n    ./script/generate selenium logout.rhtml\n    will create:\n        /test/selenium/logout.rhtml\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/generators/selenium/selenium_generator.rb",
    "content": "class SeleniumGenerator < Rails::Generator::Base\n  def initialize runtime_args, runtime_options = {}\n    super\n    usage if @args.empty?\n  end\n\n  def banner\n    \"Usage: #{$0} #{spec.name} testname [options]\"\n  end\n\n  def manifest\n    record do |m|\n      path = 'test/selenium'\n      path = File.join(path, suite_path) unless suite_path.empty?\n      m.directory path\n\n      template = case File.extname(filename)\n                   when '.rhtml' then 'rhtml.rhtml'\n                   when '.rsel' then 'rselenese.rhtml'\n                   else 'selenese.rhtml'\n                 end\n      m.template template, File.join(path, filename)\n    end\n  end\n\n  def filename\n    name = File.basename args[0]\n    extensions = ['.sel', '.rhtml', '.rsel']\n    name =  \"#{name}.sel\" unless extensions.include? File.extname(name)\n    name\n  end\n\n  def suite_path\n    sp = File.dirname args[0]\n    sp = '' if sp == '.'\n    sp\n  end\n\n  def testcase_link\n    l = \"http://localhost:3000/selenium/tests/\"\n    l = \"#{l}#{suite_path}/\" unless suite_path.empty?\n    l + filename\n  end\n\n  def suite_link\n    l = \"http://localhost:3000/selenium\"\n    l = \"#{l}/TestRunner.html?test=tests/#{suite_path}\" unless suite_path.empty?\n    l\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/generators/selenium/templates/rhtml.html.erb",
    "content": "<p>It's often a good idea to start the test with opening <tt>/selenium/setup</tt> (see <%%= link_to 'here', :controller => 'selenium', :action => 'setup' %> for more info).</p>\n\n<table>\n\t<tr><th colspan=\"3\"><%%= @page_title %></th></tr>\n\t<tr><td>open</td><td>/selenium/setup</td><td>&nbsp;</td></tr>\n<%% for page in ['/', '/home'] -%>\n\t<tr><td>open</td><td><%%= page %></td><td>&nbsp;</td></tr>\n\t<tr><td>assertTitle</td><td>Home</td><td>&nbsp;</td></tr>\n<%% end -%>\n</table>\n\n<p>More information about the commands is available <a href=\"http://release.openqa.org/selenium-core/nightly/reference.html\">here</a>.</p>\n\n<p>You can write comments above and below the commands, but you can only have one set of commands, i.e. one table, per test.</p>\n\n<p>Point the browser to <a href=\"<%= testcase_link %>\"><%= testcase_link %></a> to see how this test is rendered, or to <a href=\"<%= suite_link %>\"><%= suite_link %></a> to run the suite.</p>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/generators/selenium/templates/rselenese.html.erb",
    "content": "# It's often a good idea to start the test with 'setup'.\n# See /selenium/setup for more info.\n\nsetup\nopen '/'\nassert_title 'Home'\n\n# More information about the commands is available at:\n#   http://release.openqa.org/selenium-core/nightly/reference.html\n# See also the RDoc for SeleniumOnRails::TestBuilder.\n#\n# Point the browser to <%= testcase_link %> to see\n# how this test is rendered, or to <%= suite_link %> to\n# run the suite.\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/generators/selenium/templates/selenese.html.erb",
    "content": "It's often a good idea to start the test with opening <tt>/selenium/setup</tt> (see \"here\":/selenium/setup for more info).\n\n|open|/selenium/setup|\n|open|/|\n|assertTitle|Home|\n\nMore information about the commands is available \"here\":http://release.openqa.org/selenium-core/nightly/reference.html.\n\nYou can write comments above and below the commands, but you can only have one set of commands, i.e. one table, per test. \"RedCloth\":http://www.whytheluckystiff.net/ruby/redcloth/ is used for formatting if installed.\n\nPoint the browser to \"<%= testcase_link %>\":<%= testcase_link %> to see how this test is rendered, or to \"<%= suite_link %>\":<%= suite_link %> to run the suite.\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/init.rb",
    "content": "require 'selenium_on_rails_config'\nenvs = SeleniumOnRailsConfig.get :environments\n\nif envs.include? RAILS_ENV\n  #initialize the plugin\n  $LOAD_PATH << File.dirname(__FILE__) + \"/lib/controllers\"\n  require 'selenium_controller'\n  require File.dirname(__FILE__) + '/routes'\n\n  SeleniumController.prepend_view_path File.expand_path(File.dirname(__FILE__) + '/lib/views')\nelse\n  #erase all traces\n  $LOAD_PATH.delete lib_path\nend\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/controllers/selenium_controller.rb",
    "content": "require 'webrick/httputils'\n\nclass SeleniumController < ActionController::Base\n  include SeleniumOnRails::FixtureLoader\n  include SeleniumOnRails::Renderer\n  \n  def initialize\n    @result_dir = SeleniumOnRailsConfig.get(:result_dir)\n  end\n  \n  def setup\n    unless params.has_key? :keep_session\n      reset_session #  IS THIS WORKING!  NO THINK SO\n      @session_wiped = true\n    end\n    @cleared_tables = clear_tables params[:clear_tables].to_s\n    @loaded_fixtures = load_fixtures params[:fixtures].to_s\n    render :file => view_path('setup.rhtml'), :layout => layout_path\\\n  end\n\n  def test_file\n    params[:testname] = '' if params[:testname].to_s == 'TestSuite.html'\n    filename = File.join selenium_tests_path, params[:testname]\n    if File.directory? filename\n      @suite_path = filename\n      render :file => view_path('test_suite.rhtml'), :layout => layout_path\n    elsif File.readable? filename\n      render_test_case filename\n    else\n      if File.directory? selenium_tests_path\n        render :text => 'Not found', :status => 404\n      else\n        render :text => \"Did not find the Selenium tests path (#{selenium_tests_path}). Run script/generate selenium\", :status => 404\n      end\n    end\n  end\n\n  def support_file\n    if params[:filename].empty?\n      redirect_to :filename => 'TestRunner.html', :test => 'tests'\n      return\n    end\n\n    filename = File.join selenium_path, params[:filename]\n    if File.file? filename\n      type = WEBrick::HTTPUtils::DefaultMimeTypes[$1.downcase] if filename =~ /\\.(\\w+)$/\n      type ||= 'text/html'\n      send_file filename, :type => type, :disposition => 'inline', :stream => false\n    else\n      render :text => 'Not found', :status => 404\n    end\n  end\n\n  def record\n    dir = record_table\n\n    @result = {'resultDir' => dir}\n    ['result', 'numTestFailures', 'numTestPasses', 'numCommandFailures', 'numCommandPasses', 'numCommandErrors', 'totalTime'].each do |item|\n      @result[item] = params[item]\n    end\n    \n    File.open(log_path(params[:logFile] || 'default.yml'), 'w') {|f| YAML.dump(@result, f)}\n    \n    render :file => view_path('record.rhtml'), :layout => layout_path\n  end\n\n  def record_table\n    return nil unless @result_dir\n\n    cur_result_dir = File.join(@result_dir, (params[:logFile] || \"default\").sub(/\\.yml$/, ''))\n    FileUtils.mkdir_p(cur_result_dir)\n    File.open(\"#{cur_result_dir}/index.html\", \"wb\") do |f|\n      f.write <<EOS\n<html>\n<head><title>Selenium Test Result</title></head>\n<frameset cols=\"30%,*\">\n<frame name=\"suite\" src=\"suite.html\">\n<frame name=\"testcase\" src=\"blank.html\">\n</frameset>\n</html>\nEOS\n    end\n    html_header = <<EOS\n<html>\n<head>\n<link rel=\"stylesheet\" type=\"text/css\" href=\"selenium-test.css\">\n</head>\n<body>\nEOS\n    html_footer = \"</body></html>\\n\"\n    if selenium_path\n      css_file = File.join selenium_path, \"selenium-test.css\"\n      if File.exist?(css_file)\n        FileUtils.cp css_file, cur_result_dir\n      end\n    end\n    File.open(\"#{cur_result_dir}/blank.html\", \"wb\") do |f|\n      f.write \"<html><body></body></html>\"\n    end\n    File.open(\"#{cur_result_dir}/suite.html\", \"wb\") do |f|\n      suite = params[:suite]\n      suite.sub!(/^.*(<table[\\s>])/im, '\\1')\n      i = 1\n      suite.gsub!(/(\\shref=)\"[^\"]*\"/i) do |m|\n        link = \"#{$1}\\\"test#{i}.html\\\" target=\\\"testcase\\\"\"\n        File.open(\"#{cur_result_dir}/test#{i}.html\", \"wb\") do |testcase|\n          testcase.write html_header\n          testcase.write(params[\"testTable.#{i}\"])\n          testcase.write html_footer\n        end\n        i += 1\n        link\n      end\n      f.write html_header\n      f.write suite\n      f.write html_footer\n    end\n    cur_result_dir\n  end\n  \n  private :record_table\nend"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/controllers/switch_environment_controller.rb",
    "content": "class SwitchEnvironmentController < ActionController::Base\n  def index\n    readme_path = File.expand_path File.join(File.dirname(__FILE__), '..', 'README')\n    render :status => 500, :locals => {:readme_path => readme_path }, :inline => <<END\n<p>\n  Selenium on Rails is only activated for <%= SeleniumOnRailsConfig.get(:environments).join ', ' %>\n  environment<%= SeleniumOnRailsConfig.get(:environments).size > 1 ? 's' : '' %> (you're running\n  <%= RAILS_ENV %>).\n</p>\n<p>\n  Start your server in a different environment or see <tt><%= readme_path %></tt> \n  for information regarding how to change this behavior.\n</p>\nEND\n  end\nend"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_helper.rb",
    "content": "module SeleniumHelper\n  include SeleniumOnRails::SuiteRenderer\n  include SeleniumOnRails::FixtureLoader\n  \n  def test_case_name filename\n    File.basename(filename).sub(/\\..*/,'').humanize\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/acceptance_test_runner.rb",
    "content": "$: << File.expand_path(File.dirname(__FILE__) + \"/\")\n$: << File.expand_path(File.dirname(__FILE__) + \"/../\")\nrequire 'paths'\nrequire 'net/http'\nrequire 'tempfile'\n\n\ndef c(var, default = nil) SeleniumOnRailsConfig.get var, default end\ndef c_b(var, default = nil) SeleniumOnRailsConfig.get(var, default) { yield } end\n\nBROWSERS =              c :browsers, {}\nREUSE_EXISTING_SERVER = c :reuse_existing_server, true\nSTART_SERVER =          c :start_server, false  #TODO can't get it to work reliably on Windows, perhaps it's just on my computer, but I leave it off by default for now\nHOST =                  c :host, 'localhost'\nPORTS =                 c(:port_start, 3000)..c(:port_end, 3005)\nBASE_URL_PATH =         c :base_url_path, '/'\nTEST_RUNNER_URL =       c :test_runner_url, '/selenium/TestRunner.html'\nMAX_BROWSER_DURATION =  c :max_browser_duration, 2*60\nMULTI_WINDOW =          c :multi_window, false\nSERVER_COMMAND =      c_b :server_command do\n  server_path = File.expand_path(File.dirname(__FILE__) + '/../../../../../script/server')\n  if RUBY_PLATFORM =~ /mswin/\n    \"ruby #{server_path} webrick -p %d -e test > NUL 2>&1\"\n  else\n    # don't use redirects to /dev/nul since it makes the fork return wrong pid\n    # see UnixSubProcess\n    \"#{server_path} webrick -p %d -e test\"\n  end\nend\n\nmodule SeleniumOnRails\n  class AcceptanceTestRunner\n    include SeleniumOnRails::Paths\n  \n    def run\n      raise 'no browser specified, edit/create config.yml' if BROWSERS.empty?\n      start_server\n      has_error = false\n      begin\n        BROWSERS.each_pair do |browser, path|\n          log_file = start_browser browser, path\n          wait_for_completion log_file\n          stop_browser\n          result = YAML::load_file log_file\n          print_result result\n          has_error ||= result['numTestFailures'].to_i > 0\n          # File.delete log_file unless has_error\n        end\n      rescue\n        stop_server\n        raise\n      end\n      stop_server\n      raise 'Test failures' if has_error\n    end\n    \n    private\n      def start_server\n        PORTS.each do |p|\n          @port = p\n          case server_check\n            when :success\n              return if REUSE_EXISTING_SERVER\n              next\n            when Fixnum\n              next\n            when :no_response\n              next unless START_SERVER\n              do_start_server\n              return\n          end\n        end\n        raise START_SERVER ? 'failed to start server': 'failed to find existing server, run script/server -e test'\n      end\n      \n      def do_start_server\n        puts 'Starting server'\n        @server = start_subprocess(format(SERVER_COMMAND, @port))\n        while true\n          print '.'\n          r = server_check\n          if r == :success\n            puts\n            return\n          end\n          raise \"server returned error: #{r}\" if r.instance_of? Fixnum\n          sleep 3\n        end\n      end\n    \n      def server_check\n        begin\n          res = Net::HTTP.get_response HOST, TEST_RUNNER_URL, @port\n          return :success if (200..399).include? res.code.to_i\n          return res.code.to_i\n        rescue Errno::ECONNREFUSED\n          return :no_response\n        end\n      end\n    \n      def stop_server\n        return unless defined? @server\n        puts\n        @server.stop 'server'\n      end\n    \n      def start_browser browser, path\n        puts\n        puts \"Starting #{browser}\"\n        base_url = \"http://#{HOST}:#{@port}#{BASE_URL_PATH}\"\n        log = log_file browser\n        command = \"\\\"#{path}\\\" \\\"http://#{HOST}:#{@port}#{TEST_RUNNER_URL}?test=tests&auto=true&baseUrl=#{base_url}&resultsUrl=postResults/#{log}&multiWindow=#{MULTI_WINDOW}\\\"\"\n        @browser = start_subprocess command    \n        log_path log\n      end\n      \n      def stop_browser\n        @browser.stop 'browser'\n      end\n      \n      def start_subprocess command\n        if RUBY_PLATFORM =~ /mswin/\n          SeleniumOnRails::AcceptanceTestRunner::Win32SubProcess.new command\n        elsif RUBY_PLATFORM =~ /darwin/i && command =~ /safari/i\n          SeleniumOnRails::AcceptanceTestRunner::SafariSubProcess.new command\n        else\n          SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess.new command\n        end\n      end\n      \n      def log_file browser\n        FileUtils.mkdir_p(log_path(''))\n        (0..100).each do |i|\n          name = browser + (i==0 ? '' : \"(#{i})\") + '.yml'\n          return name unless File.exist?(log_path(name))\n        end\n        raise 'there are way too many files in the log directory...'\n      end\n    \n      def wait_for_completion log_file\n        duration = 0\n        while true\n          raise 'browser takes too long' if duration > MAX_BROWSER_DURATION\n          print '.'\n          break if File.exist? log_file\n          sleep 5\n          duration += 5\n        end\n        puts\n      end\n    \n      def print_result result\n        puts \"Finished in #{result['totalTime']} seconds.\"\n        puts\n        puts \"#{result['numTestPasses']} tests passed, #{result['numTestFailures']} tests failed\"\n        puts \"(Results stored in '#{result['resultDir']}')\" if result['resultDir']\n      end\n        \n  end\nend\n\nclass SeleniumOnRails::AcceptanceTestRunner::SubProcess\n  def stop what\n    begin\n      puts \"Stopping #{what} (pid=#{@pid}) ...\"\n      Process.kill 9, @pid\n    rescue Errno::EPERM #such as the process is already closed (tabbed browser)\n    end\n  end\nend\n\nclass SeleniumOnRails::AcceptanceTestRunner::Win32SubProcess < SeleniumOnRails::AcceptanceTestRunner::SubProcess\n  def initialize command\n    require 'win32/open3' #win32-open3 http://raa.ruby-lang.org/project/win32-open3/\n\n    puts command\n    input, output, error, @pid = Open4.popen4 command, 't', true\n  end\nend\n\nclass SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess < SeleniumOnRails::AcceptanceTestRunner::SubProcess\n  def initialize command\n    puts command\n    @pid = fork do\n      # Since we can't use shell redirects without screwing \n      # up the pid, we'll reopen stdin and stdout instead\n      # to get the same effect.\n      [STDOUT,STDERR].each {|f| f.reopen '/dev/null', 'w' }\n      exec command\n    end\n  end\nend\n\n# The path to Safari should look like this: /Applications/Safari.app/Contents/MacOS/Safari\nclass SeleniumOnRails::AcceptanceTestRunner::SafariSubProcess < SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess\n  def initialize command\n    f = File.open(Tempfile.new('selenium-on-rails').path, 'w')\n    f.puts <<-HTML\n      <html>\n        <head>\n          <script type=\"text/javascript\" charset=\"utf-8\">\n            window.location.href = #{command.split.last};\n          </script>\n        </head>\n        <body></body>\n      </html>\n    HTML\n    f.close\n    \n    super \"#{command.split.first} #{f.path}\"\n   end\n  \nend\n  \n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/fixture_loader.rb",
    "content": "require 'test/unit'\nrequire 'active_record'\nrequire 'active_record/fixtures'\n\nmodule SeleniumOnRails::FixtureLoader\n  include SeleniumOnRails::Paths\n  \n  def available_fixtures\n    fixtures = {}\n    path = fixtures_path + '/'\n    files = Dir[\"#{path}**/*.{yml,csv}\"]\n    files.each do |file|\n      rel_path = file.sub(path, '')\n      next if skip_file? rel_path\n      fixture_set = File.dirname(rel_path)\n      fixture_set = '' if fixture_set == '.'\n      fixture = rel_path.sub /\\.[^.]*$/, ''\n      fixtures[fixture_set] ||= []\n      fixtures[fixture_set] << fixture\n    end\n    \n    fixtures\n  end\n\n  def load_fixtures fixtures_param\n    available = nil\n    fixtures = fixtures_param.split(/\\s*,\\s*/).collect do |f|\n      fixture_set = File.dirname f\n      fixture_set = '' if fixture_set == '.'\n      fixture = File.basename f\n      if fixture == 'all'\n        available ||= available_fixtures\n        available[fixture_set]\n      else\n        f\n      end\n    end\n    fixtures.flatten!\n    fixtures.reject! {|f| f.blank? }\n\n    if fixtures.any?\n      Fixtures.reset_cache # in case they've already been loaded and things have changed\n      Fixtures.create_fixtures fixtures_path, fixtures\n    end\n    fixtures\n  end\n\n  def clear_tables tables\n    table_names = tables.split /\\s*,\\s*/\n    connection = ActiveRecord::Base.connection \n    table_names.each do |table|\n      connection.execute \"DELETE FROM #{table}\" \n    end\n    table_names\n  end\n  \nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/partials_support.rb",
    "content": "require 'selenium_on_rails/paths'\n\nmodule SeleniumOnRails::PartialsSupport\n  include SeleniumOnRails::Paths\n\n  # Overrides where the partial is searched for, and returns only the command table rows.\n  def render_partial(options)\n    pattern = partial_pattern options[:partial]\n    filename = Dir[pattern].first\n    raise \"Partial '#{partial_path}' cannot be found! (Looking for file: '#{pattern}')\" unless filename\n    partial = render :file => filename, :use_full_path => false, :locals => options[:locals]\n    extract_commands_from_partial partial\n  end\n\n  # Extracts the commands from a partial. The partial must contain a html table\n  # and the first row is ignored since it cannot contain a command.\n  def extract_commands_from_partial partial\n    partial = partial.match(/.*<table>.*?<tr>.*?<\\/tr>(.*?)<\\/table>/im)[1]\n    raise \"Partial '#{name}' doesn't contain any table\" unless partial\n    partial\n  end\n\n  private\n    # Generates the file pattern from the provided partial path.\n    # The starting _ and file extension don't have too be provided.\n    def partial_pattern partial_path\n      path = partial_path.split '/'\n      filename = path.delete_at(-1)\n      filename = '_' + filename unless filename.starts_with? '_'\n      filename << '.*' unless filename.include? '.'\n      pattern = selenium_tests_path + '/'\n      pattern << path.join('/') + '/' if path\n      pattern << filename\n    end\n\nend"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/paths.rb",
    "content": "require 'selenium_on_rails_config'\n\nmodule SeleniumOnRails\n  module Paths\n    \n    def selenium_path\n      @@selenium_path ||= find_selenium_path\n      @@selenium_path\n    end\n    \n    def selenium_tests_path\n      return SeleniumOnRailsConfig.get(\"selenium_tests_path\") if SeleniumOnRailsConfig.get(\"selenium_tests_path\")\n      File.expand_path(File.join(RAILS_ROOT, 'test/selenium'))\n    end\n    \n    def view_path view\n      File.expand_path(File.dirname(__FILE__) + '/../views/' + view)\n    end\n  \n    # Returns the path to the layout template. The path is relative in relation\n    # to the app/views/ directory since Rails doesn't support absolute paths\n    # to layout templates.\n    def layout_path\n      'layout.rhtml'\n    end\n    \n    def fixtures_path\n      return SeleniumOnRailsConfig.get(\"fixtures_path\") if SeleniumOnRailsConfig.get(\"fixtures_path\")\n      File.expand_path File.join(RAILS_ROOT, 'test/fixtures')\n    end\n    \n    def log_path log_file\n      File.expand_path(File.dirname(__FILE__) + '/../../log/' + File.basename(log_file))\n    end\n\n    def skip_file? file\n      file.split('/').each do |f|\n        return true if f.upcase == 'CVS' or f.starts_with?('.') or f.ends_with?('~') or f.starts_with?('_')\n      end\n      false\n    end\n    \n    private ###############################################\n\n    def find_selenium_path\n      sel_dirs = SeleniumOnRailsConfig.get :selenium_path do\n        File.expand_path(File.dirname(__FILE__) + '/../../selenium-core')\n      end\n\n      sel_dirs.to_a.each do |seleniumdir|\n        ['', 'core', 'selenium', 'javascript'].each do |subdir|\n          path = File.join seleniumdir, subdir\n          return path if File.exist?(File.join(path, 'TestRunner.html'))\n        end\n      end\n      \n      raise 'Could not find Selenium Core installation'\n    end\n       \n  end\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/renderer.rb",
    "content": "module SeleniumOnRails::Renderer\n  include SeleniumOnRails::Paths\n  \n  def render_test_case filename\n    @template.extend SeleniumOnRails::PartialsSupport\n    @page_title = test_case_name filename\n    output = render_to_string :file => filename, :locals => {\"page_title\" => @page_title}\n    layout = (output =~ /<html>/i ? false : layout_path)\n    render :text => output, :layout => layout\n\n    headers['Cache-control'] = 'no-cache'\n    headers['Pragma'] = 'no-cache'\n    headers['Expires'] = '-1'\n  end\n  \n  def test_case_name filename\n    File.basename(filename).sub(/\\..*/,'').humanize\n  end\n\nend"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/rselenese.rb",
    "content": "# Renders Selenium test templates in a fashion analogous to +rxml+ and\n# +rjs+ templates.\n#\n#   setup\n#   open :controller => 'customer', :action => 'list'\n#   assert_title 'Customers'\n#\n# See SeleniumOnRails::TestBuilder for a list of available commands.\nclass SeleniumOnRails::RSelenese < SeleniumOnRails::TestBuilder\nend\nActionView::Template.register_template_handler 'rsel', SeleniumOnRails::RSelenese\n\nclass SeleniumOnRails::RSelenese\n  attr_accessor :view\n\n  def initialize view\n    super view\n    @view = view\n  end\n\n  def render template, local_assigns = {}\n    title = (@view.assigns['page_title'] or local_assigns['page_title'])\n\n    evaluator = Evaluator.new(@view)\n    evaluator.run_script title, assign_locals_code_from(local_assigns) + \"\\n\" + template.source, local_assigns\n  end\n  \n  def assign_locals_code_from(local_assigns)\n    return local_assigns.keys.collect {|key| \"#{key} = local_assigns[#{key.inspect}];\"}.join\n  end\n  \n  def self.call(template)\n    \"#{name}.new(self).render(template, local_assigns)\"\n  end\n\n  class Evaluator < SeleniumOnRails::TestBuilder\n    def run_script(title, script, local_assigns)\n      table(title) do\n        test = self #to enable test.command\n        eval script\n      end \n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/selenese.rb",
    "content": "require 'selenium_on_rails/partials_support'\n\nclass SeleniumOnRails::Selenese\nend\nActionView::Template.register_template_handler 'sel', SeleniumOnRails::Selenese\n\n\nclass SeleniumOnRails::Selenese  \n  def initialize view\n    @view = view\n  end\n\n  def render template, local_assigns = {}\n    name = (@view.assigns['page_title'] or local_assigns['page_title'])\n    lines = template.source.strip.split \"\\n\"\n    html = ''\n    html << extract_comments(lines)\n    html << extract_commands(lines, name)\n    html << extract_comments(lines)\n    raise 'You cannot have comments in the middle of commands!' if next_line lines, :any\n    html\n  end\n  \n  private\n    def next_line lines, expects\n      while lines.any?\n        l = lines.shift.strip\n        next if (l.empty? and expects != :comment)\n        comment = (l =~ /^\\|.*\\|$/).nil?\n        if (comment and expects == :command) or (!comment and expects == :comment)\n          lines.unshift l\n          return nil\n        end\n        return l\n      end\n    end\n    \n    def self.call(template)\n      \"#{name}.new(self).render(template, local_assigns)\"\n    end\n\n    def extract_comments lines\n      comments = ''\n      while (line = next_line lines, :comment)\n        comments << line + \"\\n\"\n      end\n      if defined? RedCloth\n        comments = RedCloth.new(comments).to_html\n      end\n      comments += \"\\n\" unless comments.empty?\n      comments\n    end\n\n    def extract_commands lines, name\n      html = \"<table>\\n<tr><th colspan=\\\"3\\\">#{name}</th></tr>\\n\"\n      while (line = next_line lines, :command)\n        line = line[1..-2] #remove starting and ending |\n        cells = line.split '|'\n        if cells.first == 'includePartial'\n          html << include_partial(cells[1..-1])\n          next\n        end\n        raise 'There might only be a maximum of three cells!' if cells.length > 3\n        html << '<tr>'\n        (1..3).each do\n          cell = cells.shift\n          cell = (cell ? CGI.escapeHTML(cell.strip) : '&nbsp;')\n          html << \"<td>#{cell}</td>\"\n        end\n        html << \"</tr>\\n\"\n      end\n      html << \"</table>\\n\"\n    end\n\n    def include_partial params\n      partial = params.shift\n      locals = {}\n      params.each do |assignment|\n        next if assignment.empty?\n        _, var, value = assignment.split(/^([a-z_][a-zA-Z0-9_]*)\\s*=\\s*(.*)$/)\n        raise \"Invalid format '#{assignment}'. Should be '|includePartial|partial|var1=value|var2=value|.\" unless var\n        locals[var.to_sym] = value or ''\n      end\n      @view.render :partial => partial, :locals => locals\n    end\n\nend"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/suite_renderer.rb",
    "content": "require 'selenium_on_rails'\n\nmodule SeleniumOnRails\n  module SuiteRenderer\n    def test_suite_name path\n      return 'All test cases' if [nil, '/'].include? path_to_relative_url(path)\n      File.split(path)[-1].humanize\n    end\n  \n    def test_suites path\n      suites = []\n\n      parent_path = File.join(File.split(path).slice(0..-2)) #all but last\n      parent_path = path_to_relative_url parent_path\n      suites << ['..', parent_path] unless parent_path.nil?\n\n      visit_all_tests path, '', Proc.new {|n, p| suites << [n,path_to_relative_url(p)]}, nil\n      suites\n    end\n\n    def test_cases path\n      tests = []\n      visit_all_tests path, '', nil, Proc.new {|n, p| tests << [n,p]}\n      tests\n    end\n  \n    def link_to_test_case suite_name, filename\n      name = suite_name + test_case_name(filename)\n      link_to name, :action => :test_file, :testname => path_to_relative_url(filename).sub(/^\\//,'')\n    end\n  \n    private ###############################################\n    \n    def path_to_relative_url path\n      slt = @controller.selenium_tests_path\n      return nil unless path.index slt\n      path.sub slt, ''\n    end\n            \n    def visit_all_tests path, suite_name, suite_consumer, test_consumer\n      dirs = [] #add dirs to an array in order for files to be processed before dirs\n      Dir.entries(path).sort.each do |e|\n        next if skip_file?(e) or ['.','..'].include?(e)\n        filename = File.join path, e\n        if File.directory? filename\n          dirs << [filename, \"#{suite_name}#{e.humanize}.\"]\n          suite_consumer.call(\"#{suite_name}#{e.humanize}\", filename) if suite_consumer\n        else\n          test_consumer.call(suite_name, filename) if test_consumer\n        end\n      end\n      #recurse through dirs\n      dirs.each {|p, n| visit_all_tests p, n, suite_consumer, test_consumer }\n    end      \n  end\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/tasks/test_acceptance.rake",
    "content": "task :test_acceptance => 'test:acceptance'\nnamespace :test do\n  desc 'Run Selenium tests in all browsers'\n  task :acceptance do\n    require File.dirname(__FILE__) + '/../lib/selenium_on_rails/acceptance_test_runner'\n    SeleniumOnRails::AcceptanceTestRunner.new.run\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder.rb",
    "content": "require 'selenium_on_rails/test_builder_actions'\nrequire 'selenium_on_rails/test_builder_accessors'\n\n# Create test_builder_user_actions.rb to support actions included\n# in selenium-core's user-extensions.js\n#\n# See test_builder_user_actions.rb.example for examples matching\n# selenium-core's user-extensions.js.sample\nmodule SeleniumOnRails::TestBuilderUserActions\nend\nrequire 'selenium_on_rails/test_builder_user_actions' if File.exist?(File.expand_path(File.join(File.dirname(__FILE__), 'test_builder_user_actions.rb')))\n\n\n# Create test_builder_user_accessors.rb to support accessors\n# included in selenium-core's user-extensions.js\n#\n# See test_builder_user_accessors.rb.example for examples matching\n# selenium-core's user-extensions.js.sample\nmodule SeleniumOnRails::TestBuilderUserAccessors\nend\nrequire 'selenium_on_rails/test_builder_user_accessors' if File.exist?(File.expand_path(File.join(File.dirname(__FILE__), 'test_builder_user_accessors.rb')))\n\n# Builds Selenium test table using a high-level Ruby interface. Normally\n# invoked through SeleniumOnRails::RSelenese.\n#\n# See SeleniumOnRails::TestBuilderActions for the available actions and\n# SeleniumOnRails::TestBuilderAccessors for the available checks.\n#\n# For more information on the commands supported by TestBuilder, see the\n# Selenium Commands Documentation at\n# http://release.openqa.org/selenium-core/nightly/reference.html.\nclass SeleniumOnRails::TestBuilder\n  include SeleniumOnRails::TestBuilderActions\n  include SeleniumOnRails::TestBuilderAccessors\n  include SeleniumOnRails::TestBuilderUserActions\n  include SeleniumOnRails::TestBuilderUserAccessors\n\n  # Convert _str_ to a Selenium command name.\n  def self.selenize str\n    str.camelize.gsub(/^[A-Z]/) {|s| s.downcase }\n  end\n\n  # Prepends _pattern_ with 'exact:' if it would be considered containing \n  # string-match pattern otherwise.\n  def exactize pattern\n    pattern.include?(':') ? \"exact:#{pattern}\" : pattern\n  end\n\n  # Create a new TestBuilder for _view_.\n  def initialize view\n    @view = view\n    @output = ''\n    @xml = Builder::XmlMarkup.new :indent => 2, :target => @output\n  end\n\n  # Add a new table of tests, and return the HTML.\n  def table title\n    @xml.table do\n      @xml.tr do @xml.th(title, :colspan => 3) end\n      yield self\n    end\n  end\n\n  # Add a new test command using _cmd_, _target_ and _value_.\n  def command cmd, target=nil, value=nil\n    @xml.tr do\n      _tdata cmd\n      _tdata target\n      _tdata value\n    end\n  end\n  # :nodoc\n  alias_method :command_verbatim, :command \n\n  # Same as _command_ but add _AndWait_ to the name of _cmd_.\n  def command_and_wait cmd, target=nil, value=nil\n    command_verbatim cmd.to_s + 'AndWait', target, value\n  end\n\n  # Re routes commands in the provided block to #command_and_wait instead of\n  # #command.\n  def make_command_waiting\n    self.class.send :alias_method, :command, :command_and_wait\n    yield\n    self.class.send :alias_method, :command, :command_verbatim \n  end\n\nprotected\n\n  # If _url_ is a string, return unchanged.  Otherwise, pass it to\n  # ActionView#UrlHelper#url_for.\n  def url_arg url\n    if url.instance_of?(String) then url else exactize(@view.url_for(url)) end\n  end\n\n  # If _arg_ is an array formats _arg_ to a textual representation.\n  # Otherwise return unchanged.\n  def collection_arg arg\n    if arg.is_a? Array\n      arg.collect {|e| e.gsub(/[\\\\,]/) {|s| \"\\\\#{s}\" } }.join(',')\n    else\n      arg\n    end\n  end\n\nprivate\n\n  # Output a single TD element.\n  def _tdata value\n    if value\n      @xml.td(value.to_s)\n    else\n      @xml.td do @xml.target! << '&nbsp;' end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_accessors.rb",
    "content": "# The accessors available for SeleniumOnRails::TestBuilder tests.\n#\n# For each +store_foo+ there's +assert_foo+, +assert_not_foo+, +verify_foo+,\n# +verify_not_foo+, +wait_for_foo+, +wait_for_not_foo+.\nmodule SeleniumOnRails::TestBuilderAccessors\n  \n  # Tell Selenium to expect an error on the next command execution.\n  #\n  # NOTE: <tt>store_error_on_next</tt> is currently not supported by \n  # Selenium Core and is only added to here as a shortcut for \n  # generating the related assertions.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_error_on_next(message)</tt>\n  # * <tt>assert_not_error_on_next(message)</tt>\n  # * <tt>verify_error_on_next(message)</tt>\n  # * <tt>verify_not_error_on_next(message)</tt>\n  # * <tt>wait_for_error_on_next(message)</tt>\n  # * <tt>wait_for_not_error_on_next(message)</tt>\n  def store_error_on_next message\n    raise 'Not supported in Selenium Core at the moment'\n  end\n  \n  # Tell Selenium to expect a failure on the next command execution.\n  #\n  # NOTE: <tt>store_failure_on_next</tt> is currently not supported by \n  # Selenium Core and is only added to here as a shortcut for \n  # generating the related assertions.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_failure_on_next(message)</tt>\n  # * <tt>assert_not_failure_on_next(message)</tt>\n  # * <tt>verify_failure_on_next(message)</tt>\n  # * <tt>verify_not_failure_on_next(message)</tt>\n  # * <tt>wait_for_failure_on_next(message)</tt>\n  # * <tt>wait_for_not_failure_on_next(message)</tt>\n  def store_failure_on_next message\n    raise 'Not supported in Selenium Core at the moment'\n  end\n  \n  # Returns the IDs of all windows that the browser knows about.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assertAllWindowIds(pattern)</tt>\n  # * <tt>assertNotAllWindowIds(pattern)</tt>\n  # * <tt>verifyAllWindowIds(pattern)</tt>\n  # * <tt>verifyNotAllWindowIds(pattern)</tt>\n  # * <tt>waitForAllWindowIds(pattern)</tt>\n  # * <tt>waitForNotAllWindowIds(pattern)</tt>\n  def store_all_window_ids variable_name\n    command 'storeAllWindowIds', variable_name\n  end\n  \n  # Returns the names of all windows that the browser knows about.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assertAllWindowNames(pattern)</tt>\n  # * <tt>assertNotAllWindowNames(pattern)</tt>\n  # * <tt>verifyAllWindowNames(pattern)</tt>\n  # * <tt>verifyNotAllWindowNames(pattern)</tt>\n  # * <tt>waitForAllWindowNames(pattern)</tt>\n  # * <tt>waitForNotAllWindowNames(pattern)</tt>\n  def store_all_window_names variable_name\n    command 'storeAllWindowNames', variable_name\n  end\n  \n  # Returns the titles of all windows that the browser knows about.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assertAllWindowTitles(pattern)</tt>\n  # * <tt>assertNotAllWindowTitles(pattern)</tt>\n  # * <tt>verifyAllWindowTitles(pattern)</tt>\n  # * <tt>verifyNotAllWindowTitles(pattern)</tt>\n  # * <tt>waitForAllWindowTitles(pattern)</tt>\n  # * <tt>waitForNotAllWindowTitles(pattern)</tt>\n  def store_all_window_titles variable_name\n    command 'storeAllWindowTitles', variable_name\n  end\n  \n  # Has an alert occurred? \n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_alert_present</tt>\n  # * <tt>assert_alert_not_present</tt>\n  # * <tt>verify_alert_present</tt>\n  # * <tt>verify_alert_not_present</tt>\n  # * <tt>wait_for_alert_present</tt>\n  # * <tt>wait_for_alert_not_present</tt>\n  def store_alert_present variable_name\n    command 'storeAlertPresent', variable_name\n  end\n  \n  # Returns every instance of some attribute from all known windows.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_attribute_from_all_windows(attribute_name, pattern)</tt>\n  # * <tt>assert_not_attribute_from_all_windows(attribute_name, pattern)</tt>\n  # * <tt>verify_attribute_from_all_windows(attribute_name, pattern)</tt>\n  # * <tt>verify_not_attribute_from_all_windows(attribute_name, pattern)</tt>\n  # * <tt>wait_for_attribute_from_all_windows(attribute_name, pattern)</tt>\n  # * <tt>wait_for_not_attribute_from_all_windows(attribute_name, pattern)</tt>\n  def store_attribute_from_all_windows attribute_name, variable_name\n    command 'storeAttributeFromAllWindows', attribute_name, variable_name\n  end\n\n  # Has a prompt occurred? \n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_prompt_present</tt>\n  # * <tt>assert_prompt_not_present</tt>\n  # * <tt>verify_prompt_present</tt>\n  # * <tt>verify_prompt_not_present</tt>\n  # * <tt>wait_for_prompt_present</tt>\n  # * <tt>wait_for_prompt_not_present</tt>\n  def store_prompt_present variable_name\n    command 'storePromptPresent', variable_name\n  end\n\n  # Has <tt>confirm()</tt> been called? \n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_confirmation_present</tt>\n  # * <tt>assert_confirmation_not_present</tt>\n  # * <tt>verify_confirmation_present</tt>\n  # * <tt>verify_confirmation_not_present</tt>\n  # * <tt>wait_for_confirmation_present</tt>\n  # * <tt>wait_for_confirmation_not_present</tt>\n  def store_confirmation_present variable_name\n    command 'storeConfirmationPresent', variable_name\n  end\n  \n  # Return all cookies of the current page under test.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_cookie(pattern)</tt>\n  # * <tt>assert_not_cookie(pattern)</tt>\n  # * <tt>verify_cookie(pattern)</tt>\n  # * <tt>verify_not_cookie(pattern)</tt>\n  # * <tt>wait_for_cookie(pattern)</tt>\n  # * <tt>wait_for_not_cookie(pattern)</tt>\n  def store_cookie variable_name\n    command 'storeCookie', variable_name\n  end\n  \n  # Retrieves the text cursor position in the given input element or \n  # textarea; beware, this may not work perfectly on all browsers.\n  #\n  # This method will fail if the specified element isn't an input element \n  # or textarea, or there is no cursor in the element.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_cursor_position(locator, pattern)</tt>\n  # * <tt>assert_not_cursor_position(locator, pattern)</tt>\n  # * <tt>verify_cursor_position(locator, pattern)</tt>\n  # * <tt>verify_not_cursor_position(locator, pattern)</tt>\n  # * <tt>wait_for_cursor_position(locator, pattern)</tt>\n  # * <tt>wait_for_not_cursor_position(locator, pattern)</tt>\n  def store_cursor_position locator, variable_name\n    command 'storeCursorPosition', locator, variable_name\n  end\n\n  # Retrieves the message of a JavaScript alert generated during the previous\n  # action, or fail if there were no alerts.\n  #\n  # Getting an alert has the same effect as manually clicking OK. If an alert\n  # is generated but you do not get/verify it, the next Selenium action will\n  # fail.\n  #\n  # NOTE: under Selenium, JavaScript alerts will NOT pop up a visible alert\n  # dialog.\n  #\n  # NOTE: Selenium does NOT support JavaScript alerts that are generated in a\n  # page's <tt>onload()</tt> event handler. In this case a visible dialog WILL be\n  # generated and Selenium will hang until someone manually clicks OK.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_alert(pattern)</tt>\n  # * <tt>assert_not_alert(pattern)</tt>\n  # * <tt>verify_alert_present(pattern)</tt>\n  # * <tt>verify_not_alert(pattern)</tt>\n  # * <tt>wait_for_alert(pattern)</tt>\n  # * <tt>wait_for_not_alert(pattern)</tt>\n  def store_alert variable_name\n    command 'storeAlert', variable_name\n  end\n\n  # Retrieves the message of a JavaScript confirmation dialog generated during\n  # the previous action.\n  #\n  # By default, the confirm function will return +true+, having the same effect\n  # as manually clicking OK. This can be changed by prior execution of the\n  # +choose_cancel_on_next_confirmation+ command. If a confirmation is\n  # generated but you do not get/verify it, the next Selenium action will fail.\n  #\n  # NOTE: under Selenium, JavaScript confirmations will NOT pop up a visible\n  # dialog.\n  #\n  # NOTE: Selenium does NOT support JavaScript confirmations that are generated\n  # in a page's <tt>onload()</tt> event handler. In this case a visible dialog WILL be\n  # generated and Selenium will hang until you manually click OK.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_confirmation(pattern)</tt>\n  # * <tt>assert_not_confirmation(pattern)</tt>\n  # * <tt>verify_confirmation_present(pattern)</tt>\n  # * <tt>verify_not_confirmation(pattern)</tt>\n  # * <tt>wait_for_confirmation(pattern)</tt>\n  # * <tt>wait_for_not_confirmation(pattern)</tt>\n  def store_confirmation variable_name\n    command 'storeConfirmation', variable_name\n  end\n\n  # Retrieves the message of a JavaScript question prompt dialog generated \n  # during the previous action. \n  #\n  # Successful handling of the prompt requires prior execution of the \n  # +answer_on_next_prompt+ command. If a prompt is generated but you do not \n  # get/verify it, the next Selenium action will fail.\n  #\n  # NOTE: under Selenium, JavaScript prompts will NOT pop up a visible dialog.\n  #\n  # NOTE: Selenium does NOT support JavaScript prompts that are generated in a \n  # page's <tt>onload()</tt> event handler. In this case a visible dialog WILL be\n  # generated and Selenium will hang until someone manually clicks OK.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_prompt(pattern)</tt>\n  # * <tt>assert_not_prompt(pattern)</tt>\n  # * <tt>verify_prompt_present(pattern)</tt>\n  # * <tt>verify_not_prompt(pattern)</tt>\n  # * <tt>wait_for_prompt(pattern)</tt>\n  # * <tt>wait_for_not_prompt(pattern)</tt>\n  def store_prompt variable_name\n    command 'storePrompt', variable_name\n  end\n\n  # Gets the absolute URL of the current page. \n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_absolute_location(pattern)</tt>\n  # * <tt>assert_not_absolute_location(pattern)</tt>\n  # * <tt>verify_absolute_location_present(pattern)</tt>\n  # * <tt>verify_not_absolute_location(pattern)</tt>\n  # * <tt>wait_for_absolute_location(pattern)</tt>\n  # * <tt>wait_for_not_absolute_location(pattern)</tt>\n  def store_absolute_location variable_name\n    command 'storeAbsoluteLocation', variable_name\n  end\n\n  # Verify the location of the current page ends with the expected location. \n  # If an URL querystring is provided, this is checked as well. \n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_location(pattern)</tt>\n  # * <tt>assert_not_location(pattern)</tt>\n  # * <tt>verify_location_present(pattern)</tt>\n  # * <tt>verify_not_location(pattern)</tt>\n  # * <tt>wait_for_location(pattern)</tt>\n  # * <tt>wait_for_not_location(pattern)</tt>\n  def store_location expected_location, variable_name\n    command 'storeLocation', expected_location, variable_name\n  end\n  \n  # Returns the number of pixels between \"mousemove\" events during \n  # drag_and_drop commands (default=10).\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_mouse_speed(pattern)</tt>\n  # * <tt>assert_not_mouse_speed(pattern)</tt>\n  # * <tt>verify_mouse_speed(pattern)</tt>\n  # * <tt>verify_not_mouse_speed(pattern)</tt>\n  # * <tt>wait_for_mouse_speed(pattern)</tt>\n  # * <tt>wait_for_not_mouse_speed(pattern)</tt>\n  def store_mouse_speed variable_name\n    command 'storeMouseSpeed', variable_name\n  end\n  \n  # Gets the title of the current page.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_title(pattern)</tt>\n  # * <tt>assert_not_title(pattern)</tt>\n  # * <tt>verify_title_present(pattern)</tt>\n  # * <tt>verify_not_title(pattern)</tt>\n  # * <tt>wait_for_title(pattern)</tt>\n  # * <tt>wait_for_not_title(pattern)</tt>\n  def store_title variable_name\n    command 'storeTitle', variable_name\n  end\n\n  # Gets the entire text of the page.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_body_text(pattern)</tt>\n  # * <tt>assert_not_body_text(pattern)</tt>\n  # * <tt>verify_body_text_present(pattern)</tt>\n  # * <tt>verify_not_body_text(pattern)</tt>\n  # * <tt>wait_for_body_text(pattern)</tt>\n  # * <tt>wait_for_not_body_text(pattern)</tt>\n  def store_body_text variable_name\n    command 'storeBodyText', variable_name\n  end\n\n  # Gets the (whitespace-trimmed) value of an input field (or anything else\n  # with a value parameter). For checkbox/radio elements, the value will be\n  # \"on\" or \"off\" depending on whether the element is checked or not. \n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_value(locator, pattern)</tt>\n  # * <tt>assert_not_value(locator, pattern)</tt>\n  # * <tt>verify_value_present(locator, pattern)</tt>\n  # * <tt>verify_not_value(locator, pattern)</tt>\n  # * <tt>wait_for_value(locator, pattern)</tt>\n  # * <tt>wait_for_not_value(locator, pattern)</tt>\n  def store_value locator, variable_name\n    command 'storeValue', locator, variable_name\n  end\n\n  # Gets the text of an element. This works for any element that contains text.\n  # This command uses either the +textContent+ (Mozilla-like browsers) or the\n  # +innerText+ (IE-like browsers) of the element, which is the rendered text\n  # shown to the user.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_text(locator, pattern)</tt>\n  # * <tt>assert_not_text(locator, pattern)</tt>\n  # * <tt>verify_text_present(locator, pattern)</tt>\n  # * <tt>verify_not_text(locator, pattern)</tt>\n  # * <tt>wait_for_text(locator, pattern)</tt>\n  # * <tt>wait_for_not_text(locator, pattern)</tt>\n  def store_text locator, variable_name\n    command 'storeText', locator, variable_name\n  end\n\n  # Gets the result of evaluating the specified JavaScript snippet. The snippet\n  # may have multiple lines, but only the result of the last line will be\n  # returned.\n  #\n  # Note that, by default, the snippet will run in the context of the\n  # \"selenium\" object itself, so +this+ will refer to the Selenium object, and\n  # +window+ will refer to the top-level runner test window, not the window of\n  # your application.\n  #\n  # If you need a reference to the window of your application, you can refer to\n  # <tt>this.browserbot.getCurrentWindow()</tt> and if you need to use a locator to\n  # refer to a single element in your application page, you can use\n  # <tt>this.page().findElement(\"foo\")</tt> where <tt>\"foo\"</tt> is your locator.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_eval(script, pattern)</tt>\n  # * <tt>assert_not_eval(script, pattern)</tt>\n  # * <tt>verify_eval_present(script, pattern)</tt>\n  # * <tt>verify_not_eval(script, pattern)</tt>\n  # * <tt>wait_for_eval(script, pattern)</tt>\n  # * <tt>wait_for_not_eval(script, pattern)</tt>\n  def store_eval script, variable_name\n    command 'storeEval', script, variable_name\n  end\n\n  # Gets whether a toggle-button (checkbox/radio) is checked. Fails if the\n  # specified element doesn't exist or isn't a toggle-button.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_checked(locator)</tt>\n  # * <tt>assert_not_checked(locator)</tt>\n  # * <tt>verify_checked_present(locator)</tt>\n  # * <tt>verify_not_checked(locator)</tt>\n  # * <tt>wait_for_checked(locator)</tt>\n  # * <tt>wait_for_not_checked(locator)</tt>\n  def store_checked locator, variable_name\n    command 'storeChecked', locator, variable_name\n  end\n\n  # Gets the text from a cell of a table.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_table(locator, row, column, pattern)</tt>\n  # * <tt>assert_not_table(locator, row, column, pattern)</tt>\n  # * <tt>verify_table_present(locator, row, column, pattern)</tt>\n  # * <tt>verify_not_table(locator, row, column, pattern)</tt>\n  # * <tt>wait_for_table(locator, row, column, pattern)</tt>\n  # * <tt>wait_for_not_table(locator, row, column, pattern)</tt>\n  def store_table locator, row, column, variable_name\n    command 'storeTable', \"#{locator}.#{row}.#{column}\", variable_name\n  end\n\n  # Verifies that the selected option of a drop-down satisfies the\n  # <tt>option_locator</tt>.\n  #\n  # <tt>option_locator</tt> is typically just an option label (e.g. \"John Smith\").\n  #\n  # See the <tt>select</tt> command for more information about option locators.\n  #\n  # NOTE: <tt>store_selected</tt> is currently not supported by Selenium Core.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_selected(locator, option_locator)</tt>\n  # * <tt>assert_not_selected(locator, option_locator)</tt>\n  # * <tt>verify_selected_present(locator, option_locator)</tt>\n  # * <tt>verify_not_selected(locator, option_locator)</tt>\n  # * <tt>wait_for_selected(locator, option_locator)</tt>\n  # * <tt>wait_for_not_selected(locator, option_locator)</tt>\n  def store_selected locator, option_locator, variable_name\n    raise 'Not supported in Selenium Core at the moment'\n  end\n  \n  # Gets option element ID for selected option in the specified select element.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_selected_id(select_locator, pattern)</tt>\n  # * <tt>assert_not_selected_id(select_locator, pattern)</tt>\n  # * <tt>verify_selected_id(select_locator, pattern)</tt>\n  # * <tt>verify_not_selected_id(select_locator, pattern)</tt>\n  # * <tt>wait_for_selected_id(select_locator, pattern)</tt>\n  # * <tt>wait_for_not_selected_id(select_locator, pattern)</tt>\n  def store_selected_id select_locator, variable_name\n    command 'storeSelectedId', select_locator, variable_name\n  end\n\n  # Gets all option element IDs for selected options in the specified select \n  # or multi-select element.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_selected_ids(select_locator, pattern)</tt>\n  # * <tt>assert_not_selected_ids(select_locator, pattern)</tt>\n  # * <tt>verify_selected_ids(select_locator, pattern)</tt>\n  # * <tt>verify_not_selected_ids(select_locator, pattern)</tt>\n  # * <tt>wait_for_selected_ids(select_locator, pattern)</tt>\n  # * <tt>wait_for_not_selected_ids(select_locator, pattern)</tt>\n  def store_selected_ids select_locator, variable_name\n    command 'storeSelectedIds', select_locator, variable_name\n  end\n  \n  # Gets option index (option number, starting at 0) for selected option in the \n  # specified select element.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_selected_index(select_locator, pattern)</tt>\n  # * <tt>assert_not_selected_index(select_locator, pattern)</tt>\n  # * <tt>verify_selected_index(select_locator, pattern)</tt>\n  # * <tt>verify_not_selected_index(select_locator, pattern)</tt>\n  # * <tt>wait_for_selected_index(select_locator, pattern)</tt>\n  # * <tt>wait_for_not_selected_index(select_locator, pattern)</tt>\n  def store_selected_index select_locator, variable_name\n    command 'storeSelectedIndex', select_locator, variable_name\n  end\n\n  # Gets all option indexes (option number, starting at 0) for selected options \n  # in the specified select or multi-select element.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_selected_indexes(select_locator, pattern)</tt>\n  # * <tt>assert_not_selected_indexes(select_locator, pattern)</tt>\n  # * <tt>verify_selected_indexes(select_locator, pattern)</tt>\n  # * <tt>verify_not_selected_indexes(select_locator, pattern)</tt>\n  # * <tt>wait_for_selected_indexes(select_locator, pattern)</tt>\n  # * <tt>wait_for_not_selected_indexes(select_locator, pattern)</tt>\n  def store_selected_indexes select_locator, variable_name\n    command 'storeSelectedIndexes', select_locator, variable_name\n  end\n  \n  # Gets option label (visible text) for selected option in the specified select \n  # element.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_selected_label(select_locator, pattern)</tt>\n  # * <tt>assert_not_selected_label(select_locator, pattern)</tt>\n  # * <tt>verify_selected_label(select_locator, pattern)</tt>\n  # * <tt>verify_not_selected_label(select_locator, pattern)</tt>\n  # * <tt>wait_for_selected_label(select_locator, pattern)</tt>\n  # * <tt>wait_for_not_selected_label(select_locator, pattern)</tt>\n  def store_selected_label select_locator, variable_name\n    command 'storeSelectedLabel', select_locator, variable_name\n  end\n\n  # Gets all option labels (visible text) for selected options in the specified \n  # select or multi-select element.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_selected_labels(select_locator, pattern)</tt>\n  # * <tt>assert_not_selected_labels(select_locator, pattern)</tt>\n  # * <tt>verify_selected_labels(select_locator, pattern)</tt>\n  # * <tt>verify_not_selected_labels(select_locator, pattern)</tt>\n  # * <tt>wait_for_selected_labels(select_locator, pattern)</tt>\n  # * <tt>wait_for_not_selected_labels(select_locator, pattern)</tt>\n  def store_selected_labels select_locator, variable_name\n    command 'storeSelectedLabels', select_locator, variable_name\n  end\n  \n  # Gets option value (value attribute) for selected option in the specified \n  # select element.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_selected_value(select_locator, pattern)</tt>\n  # * <tt>assert_not_selected_value(select_locator, pattern)</tt>\n  # * <tt>verify_selected_value(select_locator, pattern)</tt>\n  # * <tt>verify_not_selected_value(select_locator, pattern)</tt>\n  # * <tt>wait_for_selected_value(select_locator, pattern)</tt>\n  # * <tt>wait_for_not_selected_value(select_locator, pattern)</tt>\n  def store_selected_value select_locator, variable_name\n    command 'storeSelectedValue', select_locator, variable_name\n  end\n\n  # Gets all option values (value attribute) for selected options in the specified \n  # select or multi-select element.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_selected_values(select_locator, pattern)</tt>\n  # * <tt>assert_not_selected_values(select_locator, pattern)</tt>\n  # * <tt>verify_selected_values(select_locator, pattern)</tt>\n  # * <tt>verify_not_selected_values(select_locator, pattern)</tt>\n  # * <tt>wait_for_selected_values(select_locator, pattern)</tt>\n  # * <tt>wait_for_not_selected_values(select_locator, pattern)</tt>\n  def store_selected_values select_locator, variable_name\n    command 'storeSelectedValues', select_locator, variable_name\n  end\n  \n  # Determines whether some option in a drop-down menu is selected.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_something_selected(select_locator)</tt>\n  # * <tt>assert_not_something_selected(select_locator)</tt>\n  # * <tt>verify_something_selected(select_locator)</tt>\n  # * <tt>verify_not_something_selected(select_locator)</tt>\n  # * <tt>wait_for_something_selected(select_locator)</tt>\n  # * <tt>wait_for_not_something_selected(select_locator)</tt>\n  def store_something_selected select_locator, variable_name\n    command 'storeSomethingSelected', select_locator, variable_name\n  end\n\n  # Gets all option labels for selected options in the specified select or\n  # multi-select element.\n  #\n  # The +pattern+ for the automatically generated assertions can either take an\n  # array or a pattern.\n  #  assert_selected_options 'fruits', ['apple', 'pear']\n  #  assert_selected_options 'fruits', 'a*,p*'\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_selected_options(locator, pattern)</tt>\n  # * <tt>assert_not_selected_options(locator, pattern)</tt>\n  # * <tt>verify_selected_options_present(locator, pattern)</tt>\n  # * <tt>verify_not_selected_options(locator, pattern)</tt>\n  # * <tt>wait_for_selected_options(locator, pattern)</tt>\n  # * <tt>wait_for_not_selected_options(locator, pattern)</tt>\n  def store_selected_options locator, variable_name\n    command 'storeSelectedOptions', locator, variable_name\n  end\n\n  # Gets all option labels in the specified select drop-down.\n  #\n  # The +pattern+ for the automatically generated assertions can either take an\n  # array or a pattern.\n  #  assert_select_options 'fruits', ['apple', 'pear']\n  #  assert_select_options 'fruits', 'a*,p*'\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_select_options(locator, pattern)</tt>\n  # * <tt>assert_not_select_options(locator, pattern)</tt>\n  # * <tt>verify_select_options_present(locator, pattern)</tt>\n  # * <tt>verify_not_select_options(locator, pattern)</tt>\n  # * <tt>wait_for_select_options(locator, pattern)</tt>\n  # * <tt>wait_for_not_select_options(locator, pattern)</tt>\n  def store_select_options locator, variable_name\n    command 'storeSelectOptions', locator, variable_name\n  end\n\n  # Gets the value of an element attribute.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_attribute(locator, attribute_name, pattern)</tt>\n  # * <tt>assert_not_attribute(locator, attribute_name, pattern)</tt>\n  # * <tt>verify_attribute_present(locator, attribute_name, pattern)</tt>\n  # * <tt>verify_not_attribute(locator, attribute_name, pattern)</tt>\n  # * <tt>wait_for_attribute(locator, attribute_name, pattern)</tt>\n  # * <tt>wait_for_not_attribute(locator, attribute_name, pattern)</tt>\n  def store_attribute locator, attribute_name, variable_name\n    command 'storeAttribute', \"#{locator}@#{attribute_name}\", variable_name\n  end\n  \n  # Check if these two elements have same parent and are ordered. Two \n  # same elements will not be considered ordered.\n  #\n  # NOTE: <tt>store_ordered</tt> is currently not supported by Selenium Core.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_ordered(locator_1, locator_2)</tt>\n  # * <tt>assert_not_ordered(locator_1, locator_2)</tt>\n  # * <tt>verify_ordered(locator_1, locator_2)</tt>\n  # * <tt>verify_not_ordered(locator_1, locator_2)</tt>\n  # * <tt>wait_for_ordered(locator_1, locator_2)</tt>\n  # * <tt>wait_for_not_ordered(locator_1, locator_2)</tt>\n  def store_ordered locator_1, locator_2, variable_name\n    raise 'Not supported in Selenium Core at the moment'\n  end\n\n  # Verifies that the specified text pattern appears somewhere on the rendered\n  # page shown to the user.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_text_present(pattern)</tt>\n  # * <tt>assert_text_not_present(pattern)</tt>\n  # * <tt>verify_text_present(pattern)</tt>\n  # * <tt>verify_text_not_present(pattern)</tt>\n  # * <tt>wait_for_text_present(pattern)</tt>\n  # * <tt>wait_for_text_not_present(pattern)</tt>\n  def store_text_present pattern, variable_name\n    command 'storeTextPresent', pattern, variable_name\n  end\n\n  # Verifies that the specified element is somewhere on the page.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_element_present(locator)</tt>\n  # * <tt>assert_element_not_present(locator)</tt>\n  # * <tt>verify_element_present(locator)</tt>\n  # * <tt>verify_element_not_present(locator)</tt>\n  # * <tt>wait_for_element_present(locator)</tt>\n  # * <tt>wait_for_element_not_present(locator)</tt>\n  def store_element_present locator, variable_name\n    command 'storeElementPresent', locator, variable_name\n  end\n\n  # Determines if the specified element is visible. An element can be rendered\n  # invisible by setting the CSS \"visibility\" property to \"hidden\", or the\n  # \"display\" property to \"none\", either for the element itself or one if its\n  # ancestors. This method will fail if the element is not present.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_visible(locator)</tt>\n  # * <tt>assert_not_visible(locator)</tt>\n  # * <tt>verify_visible(locator)</tt>\n  # * <tt>verify_not_visible(locator)</tt>\n  # * <tt>wait_for_visible(locator)</tt>\n  # * <tt>wait_for_not_visible(locator)</tt>\n  def store_visible locator, variable_name\n    command 'storeVisible', locator, variable_name\n  end\n  \n  # Retrieves the height of an element. This method will fail if the element \n  # is not present.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_element_height(locator, pattern)</tt>\n  # * <tt>assert_not_element_height(locator, pattern)</tt>\n  # * <tt>verify_element_height(locator, pattern)</tt>\n  # * <tt>verify_not_element_height(locator, pattern)</tt>\n  # * <tt>wait_for_element_height(locator, pattern)</tt>\n  # * <tt>wait_for_not_element_height(locator, pattern)</tt>\n  def store_element_height locator, variable_name\n    command 'storeElementHeight', locator, variable_name\n  end\n  \n  # Get the relative index of an element to its parent (starting from 0). \n  # The comment node and empty text node will be ignored.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_element_index(locator, pattern)</tt>\n  # * <tt>assert_not_element_index(locator, pattern)</tt>\n  # * <tt>verify_element_index(locator, pattern)</tt>\n  # * <tt>verify_not_element_index(locator, pattern)</tt>\n  # * <tt>wait_for_element_index(locator, pattern)</tt>\n  # * <tt>wait_for_not_element_index(locator, pattern)</tt>\n  def store_element_index locator, variable_name\n    command 'storeElementIndex', locator, variable_name\n  end\n  \n  # Retrieves the width of an element. This method will fail if the element \n  # is not present.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_element_width(locator, pattern)</tt>\n  # * <tt>assert_not_element_width(locator, pattern)</tt>\n  # * <tt>verify_element_width(locator, pattern)</tt>\n  # * <tt>verify_not_element_width(locator, pattern)</tt>\n  # * <tt>wait_for_element_width(locator, pattern)</tt>\n  # * <tt>wait_for_not_element_width(locator, pattern)</tt>\n  def store_element_width locator, variable_name\n    command 'storeElementWidth', locator, variable_name\n  end\n  \n  # Retrieves the horizontal position of an element. This method will fail \n  # if the element is not present.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_element_position_left(locator, pattern)</tt>\n  # * <tt>assert_not_element_position_left(locator, pattern)</tt>\n  # * <tt>verify_element_position_left(locator, pattern)</tt>\n  # * <tt>verify_not_element_position_left(locator, pattern)</tt>\n  # * <tt>wait_for_element_position_left(locator, pattern)</tt>\n  # * <tt>wait_for_not_element_position_left(locator, pattern)</tt>\n  def store_element_position_left locator, variable_name\n    command 'storeElementPositionLeft', locator, variable_name\n  end\n  \n  # Retrieves the vertical position of an element. This method will fail \n  # if the element is not present.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_element_position_top(locator, pattern)</tt>\n  # * <tt>assert_not_element_position_top(locator, pattern)</tt>\n  # * <tt>verify_element_position_top(locator, pattern)</tt>\n  # * <tt>verify_not_element_position_top(locator, pattern)</tt>\n  # * <tt>wait_for_element_position_top(locator, pattern)</tt>\n  # * <tt>wait_for_not_element_position_top(locator, pattern)</tt>\n  def store_element_position_top locator, variable_name\n    command 'storeElementPositionTop', locator, variable_name\n  end\n  \n  # Return the contents of the log.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_log_messages(pattern)</tt>\n  # * <tt>assert_not_log_messages(pattern)</tt>\n  # * <tt>verify_log_messages(pattern)</tt>\n  # * <tt>verify_not_log_messages(pattern)</tt>\n  # * <tt>wait_for_log_messages(pattern)</tt>\n  # * <tt>wait_for_not_log_messages(pattern)</tt>\n  def store_log_messages variable_name\n    command 'storeLogMessages', variable_name\n  end\n\n  # Determines whether the specified input element is editable, i.e. hasn't\n  # been disabled. This method will fail if the specified element isn't an\n  # input element.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_editable(locator)</tt>\n  # * <tt>assert_not_editable(locator)</tt>\n  # * <tt>verify_editable(locator)</tt>\n  # * <tt>verify_not_editable(locator)</tt>\n  # * <tt>wait_for_editable(locator)</tt>\n  # * <tt>wait_for_not_editable(locator)</tt>\n  def store_editable locator, variable_name\n    command 'storeEditable', locator, variable_name\n  end\n\n  # Returns the IDs of all buttons on the page.\n  #\n  # If a given button has no ID, it will appear as \"\" in this array.\n  #\n  # The +pattern+ for the automatically generated assertions can either take an\n  # array or a pattern.\n  #  assert_all_buttons ['but1', 'but2']\n  #  assert_all_buttons 'but?,but?*'\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_all_buttons(pattern)</tt>\n  # * <tt>assert_not_all_buttons(pattern)</tt>\n  # * <tt>verify_all_buttons(pattern)</tt>\n  # * <tt>verify_not_all_buttons(pattern)</tt>\n  # * <tt>wait_for_all_buttons(pattern)</tt>\n  # * <tt>wait_for_not_all_buttons(pattern)</tt>\n  def store_all_buttons variable_name\n    command 'storeAllButtons', variable_name\n  end\n\n  # Returns the IDs of all links on the page.\n  #\n  # If a given link has no ID, it will appear as \"\" in this array.\n  #\n  # The +pattern+ for the automatically generated assertions can either take an\n  # array or a pattern.\n  #  assert_all_links ['link1', 'link2']\n  #  assert_all_links 'link?,link?*'\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_all_links(pattern)</tt>\n  # * <tt>assert_not_all_links(pattern)</tt>\n  # * <tt>verify_all_links(pattern)</tt>\n  # * <tt>verify_not_all_links(pattern)</tt>\n  # * <tt>wait_for_all_links(pattern)</tt>\n  # * <tt>wait_for_not_all_links(pattern)</tt>\n  def store_all_links variable_name\n    command 'storeAllLinks', variable_name\n  end\n\n  # Returns the IDs of all input fields on the page.\n  #\n  # If a given field has no ID, it will appear as \"\" in this array.\n  #\n  # The +pattern+ for the automatically generated assertions can either take an\n  # array or a pattern.\n  #  assert_all_fields ['field1', 'field2']\n  #  assert_all_fields 'field?,field?*'\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_all_fields(pattern)</tt>\n  # * <tt>assert_not_all_fields(pattern)</tt>\n  # * <tt>verify_all_fields(pattern)</tt>\n  # * <tt>verify_not_all_fields(pattern)</tt>\n  # * <tt>wait_for_all_fields(pattern)</tt>\n  # * <tt>wait_for_not_all_fields(pattern)</tt>\n  def store_all_fields variable_name\n    command 'storeAllFields', variable_name\n  end\n\n  # Returns the entire HTML source between the opening and closing \"html\" tags.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_html_source(pattern)</tt>\n  # * <tt>assert_not_html_source(pattern)</tt>\n  # * <tt>verify_html_source(pattern)</tt>\n  # * <tt>verify_not_html_source(pattern)</tt>\n  # * <tt>wait_for_html_source(pattern)</tt>\n  # * <tt>wait_for_not_html_source(pattern)</tt>\n  def store_html_source variable_name\n    command 'storeHtmlSource', variable_name\n  end\n\n  # Returns the specified expression.\n  #\n  # This is useful because of JavaScript preprocessing.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_expression(expression, pattern)</tt>\n  # * <tt>assert_not_expression(expression, pattern)</tt>\n  # * <tt>verify_expression(expression, pattern)</tt>\n  # * <tt>verify_not_expression(expression, pattern)</tt>\n  # * <tt>wait_for_expression(expression, pattern)</tt>\n  # * <tt>wait_for_not_expression(expression, pattern)</tt>\n  def store_expression expression, variable_name\n    command 'storeExpression', expression, variable_name\n  end\n  \n  # Determine whether current/locator identify the frame containing this \n  # running code.\n  #\n  # This is useful in proxy injection mode, where this code runs in every \n  # browser frame and window, and sometimes the selenium server needs to \n  # identify the \"current\" frame. In this case, when the test calls select_frame, \n  # this routine is called for each frame to figure out which one has been \n  # selected. The selected frame will return true, while all others will return \n  # false.\n  #\n  # NOTE: <tt>store_whether_this_frame_match_frame_expression</tt> is currently \n  # not supported by Selenium Core.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_whether_this_frame_match_frame_expression(current_frame_string, target)</tt>\n  # * <tt>assert_not_whether_this_frame_match_frame_expression(current_frame_string, target)</tt>\n  # * <tt>verify_whether_this_frame_match_frame_expression(current_frame_string, target)</tt>\n  # * <tt>verify_not_whether_this_frame_match_frame_expression(current_frame_string, target)</tt>\n  # * <tt>wait_for_whether_this_frame_match_frame_expression(current_frame_string, target)</tt>\n  # * <tt>wait_for_not_whether_this_frame_match_frame_expression(current_frame_string, target)</tt>\n  def store_whether_this_frame_match_frame_expression current_frame_string, target, variable_name\n    raise 'Not supported in Selenium Core at the moment'\n  end\n  \n  # Determine whether current_window_string plus target identify the window \n  # containing this running code.\n  #\n  # This is useful in proxy injection mode, where this code runs in every browser \n  # frame and window, and sometimes the selenium server needs to identify the \n  # \"current\" window. In this case, when the test calls select_window, this routine \n  # is called for each window to figure out which one has been selected. The selected \n  # window will return true, while all others will return false.\n  #\n  # NOTE: <tt>store_whether_this_window_match_window_expression</tt> is currently \n  # not supported by Selenium Core.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_whether_this_window_match_window_expression(current_window_string, target)</tt>\n  # * <tt>assert_not_whether_this_window_match_window_expression(current_window_string, target)</tt>\n  # * <tt>verify_whether_this_window_match_window_expression(current_window_string, target)</tt>\n  # * <tt>verify_not_whether_this_window_match_window_expression(current_window_string, target)</tt>\n  # * <tt>wait_for_whether_this_window_match_window_expression(current_window_string, target)</tt>\n  # * <tt>wait_for_not_whether_this_window_match_window_expression(current_window_string, target)</tt>\n  def store_whether_this_window_match_window_expression current_window_string, target, variable_name\n    raise 'Not supported in Selenium Core at the moment'\n  end\n\nprivate\n  # Generates all assertions for the accessors.\n  def self.generate_methods\n    public_instance_methods.each do |method|\n      case method\n      when 'store_alert_present',\n           'store_prompt_present',\n           'store_confirmation_present'\n        each_assertion method do |assertion_method, command_name|\n          define_method assertion_method do\n             command command_name\n          end\n        end\n      when 'store_error_on_next',\n           'store_failure_on_next',\n           'store_alert',\n           'store_all_window_ids',\n           'store_all_window_names',\n           'store_all_window_titles',\n           'store_confirmation',\n           'store_cookie',\n           'store_log_messages',\n           'store_mouse_speed',\n           'store_prompt',\n           'store_title',\n           'store_body_text',\n           'store_text_present',\n           'store_element_present',\n           'store_visible',\n           'store_editable',\n           'store_html_source',\n           'store_checked',\n           'store_something_selected'\n        each_assertion method do |assertion_method, command_name|\n          define_method assertion_method do |pattern|\n             command command_name, pattern\n          end\n        end\n      when 'store_attribute_from_all_windows',\n           'store_value',\n           'store_text',\n           'store_eval',\n           'store_cursor_position',\n           'store_selected',\n           'store_selected_id',\n           'store_selected_ids',\n           'store_selected_index',\n           'store_selected_indexes',\n           'store_selected_label',\n           'store_selected_labels',\n           'store_selected_value',\n           'store_selected_values',\n           'store_element_height',\n           'store_element_index',\n           'store_element_width',\n           'store_element_position_left',\n           'store_element_position_top',\n           'store_expression',\n           'store_ordered',\n           'store_whether_this_frame_match_frame_expression',\n           'store_whether_this_window_match_window_expression'\n        each_assertion method do |assertion_method, command_name|\n          define_method assertion_method do |arg1, arg2|\n             command command_name, arg1, arg2\n          end\n        end\n      when 'store_all_buttons',\n           'store_all_links',\n           'store_all_fields'\n        each_assertion method do |assertion_method, command_name|\n          define_method assertion_method do |pattern|\n             command command_name, collection_arg(pattern)\n          end\n        end\n      when 'store_select_options',\n           'store_selected_options'\n        each_assertion method do |assertion_method, command_name|\n          define_method assertion_method do |locator, pattern|\n             command command_name, locator, collection_arg(pattern)\n          end\n        end\n      when 'store_attribute'\n        each_assertion method do |assertion_method, command_name|\n          define_method assertion_method do |locator, attribute_name, pattern|\n             command command_name, \"#{locator}@#{attribute_name}\", pattern\n          end\n        end\n      when 'store_table'\n        each_assertion method do |assertion_method, command_name|\n          define_method assertion_method do |locator, row, column, pattern|\n             command command_name, \"#{locator}.#{row}.#{column}\", pattern\n          end\n        end\n      when 'store_absolute_location',\n           'store_location'\n        each_assertion method do |assertion_method, command_name|\n          define_method assertion_method do |pattern|\n            if method == 'store_absolute_location' and pattern.is_a? Hash\n              pattern[:only_path] = false\n            end\n\n            command command_name, url_arg(pattern)\n          end\n        end\n      when /^store_/\n         raise 'internal error'\n      end\n    end\n  end\n\n  # Generates all the assertions needed given a +store_method+.\n  def self.each_assertion store_method\n    before_negation = nil\n    after_negation = store_method.split('_')[1..-1] #throw away 'store'\n    if after_negation.last == 'present'\n      before_negation, after_negation = after_negation, after_negation.pop\n    end\n\n    ['assert', 'verify', ['wait','for']].each do |action|\n      [nil, 'not'].each do |negation|\n        name = [action, before_negation, negation, after_negation].flatten.reject{|a|a.nil?}\n        method_name = name.join '_'\n        command = name.inject(name.shift.clone) {|n, p| n << p.capitalize}\n        yield method_name, command\n      end\n    end\n  end\n\n  generate_methods\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_actions.rb",
    "content": "# The actions available for SeleniumOnRails::TestBuilder tests.\n#\n# For each action +foo+ there's also an action +foo_and_wait+.\nmodule SeleniumOnRails::TestBuilderActions\n  # Tell Selenium on Rails to clear the session and load any fixtures.  DO\n  # NOT CALL THIS AGAINST NON-TEST DATABASES.\n  # The supported +options+ are <code>:keep_session</code>, \n  # <code>:fixtures</code> and <code>:clear_tables</code>\n  #   setup\n  #   setup :keep_session\n  #   setup :fixtures => :all\n  #   setup :keep_session, :fixtures => [:foo, :bar]\n  #   setup :clear_tables => [:foo, :bar]\n  def setup options = {}\n    options = {options => nil} unless options.is_a? Hash\n\n    opts = {:controller => 'selenium', :action => 'setup'}\n    opts[:keep_session] = true if options.has_key? :keep_session\n\n    [:fixtures, :clear_tables].each do |key|\n      if (f = options[key])\n        f = [f] unless f.is_a? Array\n        opts[key] = f.join ','\n      end\n    end\n\n    open opts\n  end\n\n  # Includes a partial.\n  # The path is relative to the Selenium tests root. The starting _ and the file\n  # extension don't have to be specified.\n  #   #include test/selenium/_partial.*\n  #   include_partial 'partial'\n  #   #include test/selenium/suite/_partial.*\n  #   include_partial 'suite/partial'\n  #   #include test/selenium/suite/_partial.* and provide local assigns\n  #   include_partial 'suite/partial', :foo => bar\n  def include_partial path, local_assigns = {}\n    partial = @view.render :partial => path, :locals => local_assigns\n    @output << partial\n  end\n\n  # Clicks on a link, button, checkbox or radio button. If the click action\n  # causes a new page to load (like a link usually does), call \n  # +wait_for_page_to_load+.\n  def click locator\n    command 'click', locator\n  end\n  \n  # Clicks on a link, button, checkbox or radio button. If the click action causes \n  # a new page to load (like a link usually does), call wait_for_page_to_load.\n  def click_at locator, coord_string\n    command 'clickAt', locator, coord_string\n  end\n\n  # Explicitly simulate an event (e.g. <tt>\"focus\"</tt>, <tt>\"blur\"</tt>), to\n  # trigger the corresponding <tt>\"on_event_\"</tt> handler.\n  def fire_event locator, event_name\n    command 'fireEvent', locator, event_name\n  end\n\n  # Simulates a user pressing and releasing a key.\n  #\n  # +keycode+ is the numeric keycode of the key to be pressed, normally the\n  # ASCII value of that key.\n  def key_press locator, keycode\n    command 'keyPress', locator, keycode\n  end\n  \n  # Simulates a user pressing a key (without releasing it yet).\n  #\n  # +keycode+ is the numeric keycode of the key to be pressed, normally the\n  # ASCII value of that key.\n  def key_down locator, keycode\n    command 'keyDown', locator, keycode\n  end\n  \n  # Simulates a user releasing a key.\n  #\n  # +keycode+ is the numeric keycode of the key to be released, normally the\n  # ASCII value of that key.\n  def key_up locator, keycode\n    command 'keyUp', locator, keycode\n  end\n\n  # Simulates a user hovering a mouse over the specified element.\n  def mouse_over locator\n    command 'mouseOver', locator\n  end\n  \n  # Simulates a user pressing the mouse button (without releasing it yet) on the\n  # specified element.\n  def mouse_down locator\n    command 'mouseDown', locator\n  end\n\n  # Sets the value of an input field, as though you typed it in. \n  #\n  # Can also be used to set the value of combo boxes, check boxes, etc. In these\n  # cases, +value+ should be the value of the option selected, not the visible\n  # text.\n  def type locator, value\n    command 'type', locator, value\n  end\n\n  # Check a toggle-button (checkbox/radio).\n  def check locator\n    command 'check', locator\n  end\n\n  # Uncheck a toggle-button (checkbox/radio).\n  def uncheck locator\n    command 'uncheck', locator\n  end\n\n  # Select an option from a drop-down using an option locator.\n  #\n  # Option locators provide different ways of specifying options of an HTML\n  # Select element (e.g. for selecting a specific option, or for asserting that\n  # the selected option satisfies a specification). There are several forms of\n  # Select Option Locator.\n  #\n  # * label=labelPattern \n  #   matches options based on their labels, i.e. the visible text. (This is the\n  #   default.)\n  #     label=regexp:^[Oo]ther\n  # * value=valuePattern\n  #   matches options based on their values.\n  #     value=other\n  # * id=id\n  #   matches options based on their ids.\n  #     id=option1\n  # * index=index\n  #   matches an option based on its index (offset from zero). \n  #     index=2 \n  #\n  # If no option locator prefix is provided, the default behaviour is to match\n  # on label. \n  def select locator, option_locator\n    command 'select', locator, option_locator\n  end\n\n  # Add a selection to the set of selected options in a multi-select element\n  # using an option locator.\n  #\n  # See the <tt>#select</tt> command for more information about option locators.\n  def add_selection locator, option_locator\n    command 'addSelection', locator, option_locator\n  end\n\n  # Remove a selection from the set of selected options in a multi-select\n  # element using an option locator.\n  #\n  # See the +select+ command for more information about option locators.\n  def remove_selection locator, option_locator\n    command 'removeSelection', locator, option_locator\n  end\n\n  # Submit the specified form. This is particularly useful for forms without\n  # submit buttons, e.g. single-input \"Search\" forms.\n  def submit locator\n    command 'submit', locator\n  end\n\n  # Opens an URL in the test frame. This accepts both relative and absolute\n  # URLs. The <tt>open</tt> command waits for the page to load before\n  # proceeding, i.e. you don't have to call +wait_for_page_to_load+.\n  #\n  # Note: The URL must be on the same domain as the runner HTML due to security\n  # restrictions in the browser (Same Origin Policy).\n  def open url\n    command 'open', url_arg(url)\n  end\n\n  # Selects a popup window; once a popup window has been selected, all commands\n  # go to that window. To select the main window again, use +nil+ as the target.\n  def select_window window_id\n    command 'selectWindow', window_id||'null'\n  end\n\n  # Waits for a popup window to appear and load up.\n  #\n  # The +timeout+ is specified in milliseconds.\n  def wait_for_popup window_id, timeout\n    command 'waitForPopUp', window_id||'null', timeout\n  end\n\n  # By default, Selenium's overridden <tt>window.confirm()</tt> function will return\n  # +true+, as if the user had manually clicked OK. After running this command,\n  # the next call to <tt>confirm()</tt> will return +false+, as if the user had clicked\n  # Cancel. \n  def choose_cancel_on_next_confirmation\n    command 'chooseCancelOnNextConfirmation'\n  end\n\n  # Instructs Selenium to return the specified answer string in response to the\n  # next JavaScript prompt (<tt>window.prompt()</tt>). \n  def answer_on_next_prompt answer\n    command 'answerOnNextPrompt', answer\n  end\n\n  # Simulates the user clicking the \"back\" button on their browser. \n  def go_back\n    command 'goBack'\n  end\n\n  # Simulates the user clicking the \"Refresh\" button on their browser. \n  def refresh\n    command 'refresh'\n  end\n\n  # Simulates the user clicking the \"close\" button in the titlebar of a popup\n  # window or tab.\n  def close\n    command 'close'\n  end\n  \n  # Simulates the user pressing the alt key and hold it down until do_alt_up()\n  # is called or a new page is loaded.\n  def alt_key_down\n    command 'altKeyDown'\n  end\n  \n  # Simulates the user releasing the alt key.\n  def alt_key_up\n    command 'altKeyUp'\n  end\n  \n  # Halt the currently running test, and wait for the user to press the Continue \n  # button. This command is useful for debugging, but be careful when using it, \n  # because it will force automated tests to hang until a user intervenes manually.\n  #\n  # NOTE: <tt>break</tt> is a reserved word in Ruby, so we have to simulate\n  # Selenium core's <tt>break()</tt> with <tt>brake()</tt>\n  def brake\n    command 'break'\n  end\n  \n  # Simulates the user pressing the alt key and hold it down until do_control_up()\n  # is called or a new page is loaded.\n  def control_key_down\n    command 'controlKeyDown'\n  end\n  \n  # Simulates the user releasing the control key.\n  def control_key_up\n    command 'controlKeyUp'\n  end\n  \n  # Create a new cookie whose path and domain are same with those of current page \n  # under test, unless you specified a path for this cookie explicitly.\n  #\n  # Arguments:\n  # * <tt>name_value_pair</tt> - name and value of the cookie in a format \"name=value\"\n  # * <tt>options_string</tt> - options for the cookie. Currently supported options \n  #   include 'path' and 'max_age'. The options_string's format is \n  #   <tt>\"path=/path/, max_age=60\"</tt>. The order of options are irrelevant, the \n  #   unit of the value of 'max_age' is second.\n  def create_cookie name_value_pair, options_string\n    command 'createCookie', name_value_pair, options_string\n  end\n  \n  # Delete a named cookie with specified path.\n  def delete_cookie name, path\n    command 'deleteCookie', name, path\n  end\n  \n  # Double clicks on a link, button, checkbox or radio button. If the double click action \n  # causes a new page to load (like a link usually does), call <tt>wait_for_page_to_load</tt>.\n  def double_click locator\n    command 'doubleClick', locator\n  end\n  \n  # Doubleclicks on a link, button, checkbox or radio button. If the action causes a new page \n  # to load (like a link usually does), call <tt>wait_for_page_to_load</tt>.\n  def double_click_at locator, coord_string\n    command 'doubleClickAt', locator, coord_string\n  end\n  \n  # Drags an element a certain distance and then drops it.\n  def drag_and_drop locator, movements_string\n    command 'dragAndDrop', locator, movements_string\n  end\n  \n  # Drags an element and drops it on another element.\n  def drag_and_drop_to_object locator_of_object_to_be_dragged, locator_of_drag_destination_object\n    command 'dragAndDropToObject', locator_of_object_to_be_dragged, locator_of_drag_destination_object\n  end\n  \n  # Prints the specified message into the third table cell in your Selenese\n  # tables. \n  # Useful for debugging.\n  def echo message\n    command 'echo', message\n  end\n    \n  # Briefly changes the backgroundColor of the specified element yellow.\n  # Useful for debugging.\n  def highlight locator\n    command 'highlight', locator\n  end\n  \n  # Press the meta key and hold it down until <tt>doMetaUp()</tt> is called or\n  # a new page is loaded.\n  def meta_key_down\n    command 'metaKeyDown'\n  end\n  \n  # Release the meta key.\n  def meta_key_up\n    command 'metaKeyUp'\n  end\n  \n  # Simulates a user pressing the mouse button (without releasing it yet) on the specified\n  # element.\n  def mouse_down_at locator, coord_string\n    command 'mouseDownAt', locator, coord_string\n  end\n  \n  # Simulates a user moving the mouse.\n  def mouse_move locator\n    command 'mouseMove', locator\n  end\n  \n  # Simulates a user moving the mouse relative to the specified element.\n  def mouse_move_at locator, coord_string\n    command 'mouseMoveAt', locator, coord_string\n  end\n  \n  # Simulates the user moving the mouse off the specified element.\n  def mouse_out locator\n    command 'mouseOut', locator\n  end\n  \n  # Simulates the user releasing the mouse button on the specified element.\n  def mouse_up locator\n    command 'mouseUp', locator\n  end\n  \n  # Simulates a user pressing the mouse button (without releasing it yet) on the\n  # specified element.\n  def mouse_up_at locator, coord_string\n    command 'mouseUpAt', locator, coord_string\n  end\n  \n  # Opens a popup window (if a window with that ID isn't already open). After opening the\n  # window, you'll need to select it using the <tt>select_window</tt> command.\n  #\n  # This command can also be a useful workaround for bug SEL-339. In some cases, Selenium\n  # will be unable to intercept a call to window.open (if the call occurs during or before\n  # the \"onLoad\" event, for example). In those cases, you can force Selenium to notice the\n  # open window's name by using the Selenium openWindow command, using an empty (blank) url,\n  # like this: <tt>open_window(\"\", \"myFunnyWindow\")</tt>.\n  def open_window url, window_id\n    command 'openWindow', url, window_id\n  end\n  \n  # Wait for the specified amount of time (in milliseconds).\n  def pause wait_time\n    command 'pause', wait_time\n  end\n  \n  # Unselects all of the selected options in a multi-select element.\n  def remove_all_selections locator\n    command 'removeAllSelections', locator\n  end\n  \n  # Selects a frame within the current window. (You may invoke this command multiple times\n  # to select nested frames.) To select the parent frame, use \"relative=parent\" as a\n  # locator; to select the top frame, use \"relative=top\".\n  #\n  # You may also use a DOM expression to identify the frame you want directly, like this:\n  # <tt>dom=frames[\"main\"].frames[\"subframe\"]</tt>\n  def select_frame locator\n    command 'selectFrame', locator\n  end\n  \n  # Moves the text cursor to the specified position in the given input element or textarea.\n  # This method will fail if the specified element isn't an input element or textarea.\n  def set_cursor_position locator, position\n    command 'setCursorPosition', locator, position\n  end\n  \n  # Configure the number of pixels between \"mousemove\" events during dragAndDrop commands\n  # (default=10).\n  # Setting this value to 0 means that we'll send a \"mousemove\" event to every single pixel\n  # in between the start location and the end location; that can be very slow, and may\n  # cause some browsers to force the JavaScript to timeout.\n  #\n  # If the mouse speed is greater than the distance between the two dragged objects, we'll \n  # just send one \"mousemove\" at the start location and then one final one at the end location.\n  def set_mouse_speed pixels\n    command 'setMouseSpeed', pixels\n  end\n  \n  # Press the shift key and hold it down until <tt>doShiftUp()</tt> is called or a new page\n  # is loaded.\n  def shift_key_down\n    command 'shiftKeyDown'\n  end\n  \n  # Release the shift key.\n  def shift_key_up\n    command 'shiftKeyUp'\n  end\n  \n  # This command is a synonym for <tt>store_expression</tt>.\n  def store expression, variable_name\n    command 'store', expression, variable_name\n  end\n  \n  # Simulates keystroke events on the specified element, as though you typed the value \n  # key-by-key.\n  #\n  # This is a convenience method for calling <tt>key_down</tt>, <tt>key_up</tt>, \n  # <tt>key_press</tt> for every character in the specified string; this is useful for\n  # dynamic UI widgets (like auto-completing combo boxes) that require explicit key events.\n  #\n  # Unlike the simple \"type\" command, which forces the specified value into the page directly,\n  # this command may or may not have any visible effect, even in cases where typing keys would\n  # normally have a visible effect. For example, if you use \"<tt>type_keys</tt>\" on a form\n  # element, you may or may not see the results of what you typed in the field.\n  #\n  # In some cases, you may need to use the simple \"type\" command to set the value of the field\n  # and then the \"<tt>type_keys</tt>\" command to send the keystroke events corresponding to\n  # what you just typed.\n  def type_keys locator, value\n    command 'typeKeys', locator, value\n  end\n  \n  # Gives focus to a window.\n  def window_focus window_name\n    command 'windowFocus', window_name\n  end\n  \n  # Resize window to take up the entire screen.\n  def window_maximize window_name\n    command 'windowMaximize', window_name\n  end\n  \n  # Writes a message to the status bar and adds a note to the browser-side log. \n  #\n  # +context+ is the message sent to the browser.\n  #\n  # +log_level_threshold+ can be +nil+, <tt>:debug</tt>, <tt>:info</tt>, \n  # <tt>:warn</tt> or <tt>:error</tt>.\n  def set_context context, log_level_threshold = nil\n    if log_level_threshold\n      command 'setContext', context, log_level_threshold.to_s\n    else\n      command 'setContext', context\n    end\n  end\n\n  # Runs the specified JavaScript snippet repeatedly until it evaluates to\n  # +true+. The snippet may have multiple lines, but only the result of the last\n  # line will be considered. \n  # \n  # Note that, by default, the snippet will be run in the runner's test window,\n  # not in the window of your application. To get the window of your\n  # application, you can use the JavaScript snippet\n  # <tt>selenium.browserbot.getCurrentWindow()</tt>, and then run your \n  # JavaScript in there.\n  #\n  # +timeout+ is specified in milliseconds.\n  def wait_for_condition script, timeout\n    command 'waitForCondition', script, timeout\n  end\n\n  # Specifies the amount of time that Selenium will wait for actions to\n  # complete. \n  #\n  # Actions that require waiting include +open+ and the <tt>wait_for*</tt>\n  # actions.\n  #\n  # The default timeout is 30 seconds. \n  #\n  # +timeout+ is specified in milliseconds.\n  def set_timeout timeout\n    command 'setTimeout', timeout\n  end\n\n  # Waits for a new page to load. \n  #\n  # You can use this command instead of the +and_wait+ suffixes,\n  # +click_and_wait+, +select_and_wait+, +type_and_wait+ etc. (which are only\n  # available in the JS API).\n  #\n  # Selenium constantly keeps track of new pages loading, and sets a\n  # +newPageLoaded+ flag when it first notices a page load. Running any other\n  # Selenium command after turns the flag to +false+. Hence, if you want to wait\n  # for a page to load, you must wait immediately after a Selenium command that\n  # caused a page-load.\n  #\n  # +timeout+ is specified in milliseconds.\n  def wait_for_page_to_load timeout\n    command 'waitForPageToLoad', timeout\n  end\n\nprivate\n  # Generates the corresponding +_and_wait+ for each action.\n  def self.generate_and_wait_actions\n    public_instance_methods.each do |method|\n      define_method method + '_and_wait' do |*args|\n        methods_array = method.split(\"_\")\n        send 'command_and_wait', methods_array.first.downcase + methods_array[1..-1].collect{|part| part.camelize}.join, *args\n      end\n    end\n  end\n\n  generate_and_wait_actions\nend\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_user_accessors.rb.example",
    "content": "# Mirrors the accessors specified in user-extensions.js from the selenium-core\nmodule SeleniumOnRails::TestBuilderUserAccessors\n  \n  # Return the length of text of a specified element.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_text_length(locator, variable)</tt>\n  # * <tt>assert_not_text_length(locator, length)</tt>\n  # * <tt>verify_text_length(locator, length)</tt>\n  # * <tt>verify_not_text_length(locator, length)</tt>\n  # * <tt>wait_for_text_length(locator, length)</tt>\n  # * <tt>wait_for_not_text_length(locator, length)</tt>\n  def store_text_length locator, variable_name\n    command 'storeTextLength', locator, variable_name\n  end\n  \n  # Checks if value entered more than once in textbox.\n  #\n  # Related Assertions, automatically generated:\n  # * <tt>assert_not_text_length(locator, text)</tt>\n  # * <tt>verify_text_length(locator, text)</tt>\n  # * <tt>verify_not_text_length(locator, text)</tt>\n  # * <tt>wait_for_text_length(locator, text)</tt>\n  # * <tt>wait_for_not_text_length(locator, text)</tt>\n  def assert_value_repeated locator, text\n    command 'assertValueRepeated', locator, text\n  end\n  \n  private\n  \n  def self.generate_methods\n    public_instance_methods.each do |method|\n      case method\n      when 'store_text_length'\n        each_assertion method do |assertion_method, command_name|\n          define_method assertion_method do |arg1, arg2|\n            command command_name, arg1, arg2\n          end\n        end\n      when 'assert_value_repeated'\n        each_check method do |check_method, command_name|\n          define_method check_method do |arg1, arg2|\n             command command_name, arg1, arg2\n          end\n        end\n      else\n        raise \"Internal error: Don't know how to process user accessor: #{method}\"\n      end\n    end\n  end\n  \n  # Generates all the assertions needed given a +store_method+.\n  def self.each_assertion store_method\n    before_negation = nil\n    after_negation = store_method.split('_')[1..-1] #throw away 'store'\n    if after_negation.last == 'present'\n      before_negation, after_negation = after_negation, after_negation.pop\n    end\n\n    ['assert', 'verify', ['wait','for']].each do |action|\n      [nil, 'not'].each do |negation|\n        name = [action, before_negation, negation, after_negation].flatten.reject{|a|a.nil?}\n        method_name = name.join '_'\n        command = name.inject(name.shift.clone) {|n, p| n << p.capitalize}\n        yield method_name, command\n      end\n    end\n  end\n  \n  def self.each_check assert_method\n    before_negation = nil\n    after_negation = assert_method.split('_')[1..-1] #throw away 'assert'\n    if after_negation.last == 'present'\n      before_negation, after_negation = after_negation, after_negation.pop\n    end\n    \n    ['assert', 'verify', ['wait', 'for']].each do |action|\n      [nil, 'not'].each do |negation|\n        unless (action == 'assert' && negation.nil?)\n          name = [action, before_negation, negation, after_negation].flatten.reject{|a|a.nil?}\n          method_name = name.join '_'\n          command = name.inject(name.shift.clone) {|n, p| n << p.capitalize}\n          yield method_name, command\n        end\n      end\n    end\n  end\n  \n  generate_methods\n  \nend"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_user_actions.rb.example",
    "content": "# Mirrors the actions specified in user-extensions.js from the selenium-core\nmodule SeleniumOnRails::TestBuilderUserActions\n \n # Types the text twice into a text box.\n def type_repeated locator, text\n   command 'typeRepeated', locator, text\n end\n \n private\n   \n # Generates the corresponding +_and_wait+ for each action.\n def self.generate_and_wait_actions\n   public_instance_methods.each do |method|\n     define_method method + '_and_wait' do |*args|\n       make_command_waiting do\n         send method, *args\n       end\n     end\n   end\n end\n\n generate_and_wait_actions\n \nend"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails.rb",
    "content": "module SeleniumOnRails # :nodoc\nend\n\nrequire 'selenium_on_rails/selenese'\nrequire 'selenium_on_rails/test_builder'\nrequire 'selenium_on_rails/rselenese'\nrequire 'selenium_on_rails/suite_renderer'\nrequire 'selenium_on_rails/paths'\nrequire 'selenium_on_rails/fixture_loader'\nrequire 'selenium_on_rails/partials_support'\nrequire 'selenium_on_rails/renderer'\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/selenium_on_rails_config.rb",
    "content": "require 'yaml'\nrequire 'erb'\n\nclass SeleniumOnRailsConfig\n  @@defaults = {:environments => ['test']}\n  def self.get var, default = nil\n    value = configs[var.to_s]\n    value ||= @@defaults[var]\n    value ||= default\n    value ||= yield if block_given?\n    value\n  end\n\n  private\n    def self.configs\n      @@configs ||= nil\n      unless @@configs\n        files = [File.join(RAILS_ROOT, 'config', 'selenium.yml'), File.expand_path(File.dirname(__FILE__) + '/../config.yml')]\n        files.each do |file|\n          if File.exist?(file)\n            @@configs = YAML.load(ERB.new(IO.read(file)).result)\n            break\n          end\n        end\n        @@configs ||= {}\n      end\n      @@configs\n    end\n\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/views/layouts/layout.html.erb",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html>\n<head>\n\t<title>Selenium on Rails<%= defined?(@page_title) ? \": #{@page_title}\" : '' %></title>\n</head>\n<style type=\"text/css\">\nbody, html { font-family: Verdana, Arial, sans-serif; }\ntable { border-collapse: collapse; margin: 10px 0px; }\ntd, th { border: 2px solid black; }\n#notice { text-align: center; color: darkgreen; background-color: lightgreen; padding: 5px 15px; width: 400px; margin-left: auto; margin-right: auto; }\n#notice * { text-align: left; }\n#usagedescription { margin: 15px 30px; }\n</style>\n<body>\n<%= @content_for_layout %>\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/views/record.html.erb",
    "content": "<table>\n<% @result.each_pair do |key, value| -%>\n<tr><td><%=  key %></td><td><%= value %></td></tr>\n<% end -%>\n</table>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/views/selenium_helper.rb",
    "content": "module SeleniumHelper\n  include SeleniumOnRails::SuiteRenderer\n  include SeleniumOnRails::FixtureLoader\n\n  def test_case_name filename\n    File.basename(filename).sub(/\\..*/,'').humanize\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/views/setup.html.erb",
    "content": "<% @page_title = 'Setup' -%>\n<% if defined?(@session_wiped) or @cleared_tables.any? or @loaded_fixtures.any? -%>\n\t<div id=\"notice\">\n\t\t<% if defined?(@session_wiped) -%>\n\t\t<p>The session is wiped clean.</p>\n    <% end-%>\n\t\t<% if @cleared_tables.any? -%>\n\t\t<p>The following database tables are cleared:</p>\n\t\t\t<ul>\n\t\t\t\t<% for table in @cleared_tables -%>\n\t\t\t\t<li><%= table %></li>\n\t\t\t\t<% end-%>\n\t\t\t</ul>\n\t\t<% end -%>\n\t\t<% if @loaded_fixtures.any? -%>\n\t\t<p>The following fixtures are loaded:</p>\n\t\t\t<ul>\n\t\t\t\t<% for fixture in @loaded_fixtures -%>\n\t\t\t\t<li><%= fixture %></li>\n\t\t\t\t<% end-%>\n\t\t\t</ul>\n\t\t<% end -%>\n\t</div>\n<% end -%>\n\n<div id=\"usagedescription\">\n<p>This page can be used to setup your Selenium tests. The following options can be used:</p>\n<dl>\n\t<dt><tt>keep_session</tt></dt>\n\t<dd>\n\t\tPer default the session is reset, so add <tt>keep_session</tt> in order to keep the current session.\n\t\t<table>\n\t\t\t<tr><td>open</td><td><%= url_for %>?keep_session</td><td>&nbsp;</td></tr>\n\t\t</table>\n\t</dd>\n\t<dt><tt>fixtures</tt></dt>\n\t<dd>\n    Loads one or many fixtures into the database. <strong>This will destroy the current data you have in your database!</strong> Use <tt>all</tt> as name in order to load all fixtures, or specify which fixtures that should be loaded (delimited by commas).<br />\n    If a test needs different data than you have in your fixtures, you can add another <em>fixture set</em>. A fixture set is just a sub directory in <tt>/test/fixtures/</tt> where you can add alternate fixtures (e.g. <tt>/test/fixtures/blank/users.yml</tt>).\n\t\t<table>\n\t\t\t<tr><td>open</td><td><%= url_for :fixtures => 'all' %></td><td>&nbsp;</td></tr>\n\t\t\t<tr><td>open</td><td><%= url_for :fixtures => 'fixture' %></td><td>&nbsp;</td></tr>\n\t\t\t<tr><td>open</td><td><%= url_for :fixtures => 'fixture_one' %>,fixture_two</td><td>&nbsp;</td></tr>\n\t\t</table>\n    <b>Available fixtures</b><br />\n    <% fixtures = available_fixtures -%>\n    <% for fixture_set in fixtures.keys.sort -%>\n      In the <%= fixture_set.blank? ? 'default' : \"<tt>#{fixture_set}</tt>\" %> fixture set:\n\t  \t<ul>\n        <% fixtures[fixture_set].unshift fixture_set.blank? ? 'all' : \"#{fixture_set}/all\" -%>\n\t\t    <% for fixture in fixtures[fixture_set] -%>\n          <li><tt><%= fixture %></tt></li>\n\t\t    <% end -%>\n\t\t  </ul>\n    <% end -%>\n\t</dd>\n\t<dt><tt>clear_tables</tt></dt>\n\t<dd>\n    Clears one or many database tables. Another way to do the same thing is to create an empty fixture in a new fixture set (see <tt>fixtures</tt> above).\n\t\t<table>\n\t\t\t<tr><td>open</td><td><%= url_for :clear_tables => 'sessions' %></td><td>&nbsp;</td></tr>\n\t\t\t<tr><td>open</td><td><%= url_for :clear_tables => 'sessions' %>,outgoing_messages</td><td>&nbsp;</td></tr>\n\t\t</table>\n\t</dd>\n</dl>\n\n</div>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/lib/views/test_suite.html.erb",
    "content": "<% @page_title = test_suite_name @suite_path -%>\n<script type=\"text/javascript\">\n<!--\nfunction openSuite(selector) {\n\tvar suite = selector.options[selector.selectedIndex].value;\n\tif(suite == \"header\") return;\n\tif(top.location.href != location.href) //inside a frame\n\t\ttop.location =  \"<%= url_for :action => :support_file %>/TestRunner.html?test=tests\" + suite\n\telse\n\t\twindow.location = \"<%= url_for :action => :test_file, :testname => '' %>\" + suite\n}\n//-->\n</script>\n<select onchange=\"openSuite(this)\">\n\t<option value=\"header\">Suites:</option>\n<% for name, path in test_suites @suite_path -%>\n\t<option value=\"<%= path %>\"><%= name%></option>\n<% end -%>\n</select>\n\n<table>\n\t<tr><th><%=  @page_title %></th></tr>\n<% for name, path in test_cases @suite_path -%>\n\t<tr><td><%= link_to_test_case name, path %></td></tr>\n<% end -%>\n</table>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/log/default.yml",
    "content": "--- \nresult: Failed\nnumTestPasses: \"1079\"\nnumTestFailures: \"906\"\nnumCommandFailures: \"1027\"\nnumCommandPasses: \"3\"\nnumCommandErrors: \"57\"\nresultDir: \ntotalTime: A long time\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/routes.rb",
    "content": "module ActionController\n  module Routing #:nodoc:\n    class RouteSet #:nodoc:\n      alias_method :draw_without_selenium_routes, :draw\n      def draw\n        draw_without_selenium_routes do |map|\n          map.connect 'selenium/setup',\n            :controller => 'selenium', :action => 'setup'\n          map.connect 'selenium/tests/*testname',\n            :controller => 'selenium', :action => 'test_file'\n          map.connect 'selenium/postResults',\n            :controller => 'selenium', :action => 'record'\n          map.connect 'selenium/postResults/:logFile',\n            :controller => 'selenium', :action => 'record', :requirements => { :logFile => /.*/ }\n          map.connect 'selenium/*filename',\n            :controller => 'selenium', :action => 'support_file'\n          map.connect 'switch_environment',\n            :controller => 'switch_environment', :action => 'index'  \n          yield map if block_given?\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/Blank.html",
    "content": "<html>\n    <head>\n        <meta content=\"text/html; charset=ISO-8859-1\" http-equiv=\"content-type\">\n    </head>\n<body>\n</body>\n</html>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/InjectedRemoteRunner.html",
    "content": "<html>\n    <head>\n        <meta content=\"text/html; charset=ISO-8859-1\" http-equiv=\"content-type\">\n    </head>\n<body>\n    <h3>selenium-rc initial page</h3>\n</body>\n</html>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/RemoteRunner.html",
    "content": "<html>\n\n<!--\nCopyright 2004 ThoughtWorks, Inc\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n-->\n<HTA:APPLICATION ID=\"SeleniumHTARunner\" APPLICATIONNAME=\"Selenium\" >\n<head>\n<meta content=\"text/html; charset=ISO-8859-1\"\nhttp-equiv=\"content-type\">\n<title>Selenium Remote Control</title>\n<link rel=\"stylesheet\" type=\"text/css\" href=\"selenium.css\" />\n<script type=\"text/javascript\" src=\"scripts/xmlextras.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"lib/prototype.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"lib/cssQuery/cssQuery-p.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"lib/snapsie.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/htmlutils.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/ui-element.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-browserdetect.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-browserbot.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/find_matching_child.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-api.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-commandhandlers.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-executionloop.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-remoterunner.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-logging.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-version.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/util.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/xmltoken.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/dom.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/xpath.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/user-extensions.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\">\n    function openDomViewer() {\n        var autFrame = document.getElementById('selenium_myiframe');\n        var autFrameDocument = getIframeDocument(autFrame);\n        var domViewer = window.open(getDocumentBase(document) + 'domviewer/domviewer.html');\n        domViewer.rootDocument = autFrameDocument;\n        return false;\n    }\n\n    function cleanUp() {\n    \tif (LOG != null) {\n\t\tLOG.close();\n\t}\n    }\n\n</script>\n</head>\n\n<body onLoad=\"setTimeout(function(){runSeleniumTest();},1000)\" onUnload=\"cleanUp()\">\n\n<table border=\"1\" style=\"height: 100%; width: 100%;\">               \n  <tr>\n    <td width=\"50%\">\n      <table>\n      <tr>\n        <td class=\"remoterunner\">\n          <h4><a href=\"http://selenium.openqa.org\">Selenium</a> Functional Testing for Web Apps</h4>\n          Open Source From <a href=\"http://selenium.openqa.org/thoughtworks-and-friends.html\">ThoughtWorks and Friends</a>\n          <form action=\"\">\n          <br/>\n          <iframe id=\"seleniumLoggingFrame\" name=\"seleniumLoggingFrame\" src=\"Blank.html\" style=\"border: 0; height: 0; width: 0; \"></iframe>\n          <fieldset>\n            <button type=\"button\" id=\"domViewer1\" onclick=\"openDomViewer();\">\n              View DOM\n            </button>\n            <button type=\"button\" onclick=\"LOG.show();\">\n              Show Log\n            </button>\n            <label><INPUT TYPE=\"CHECKBOX\" NAME=\"FASTMODE\" VALUE=\"YES\" onmouseup=\"slowClicked()\"> Slow Mode</label>\t\t\t\n          </fieldset>\n\n          </form>\n\n        </td>\n      </tr>\n      </table>\n      <form action=\"\">\n        <label id=\"context\" name=\"context\"></label>\n      </form>\n    </td>\n    <td width=\"50%\" class=\"remoterunner\">\n      <h4>Command History:</h4>\n      <form name=\"commands\">\n        <textarea style=\"overflow:auto; height:8em; width:100%\" wrap=\"off\" id=\"commandList\"></textarea>\n      </form>\n    </td>\n  </tr>\n    <tr>\n    <td colspan=\"2\" height=\"100%\">\n      <iframe name=\"selenium_myiframe\" id=\"selenium_myiframe\" src=\"Blank.html\" height=\"100%\" width=\"100%\"></iframe>\n    </td>\n  </tr>\n</table>\n\n</body>\n</html>\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/SeleniumLog.html",
    "content": "<html>\n\n<head>\n<title>Selenium Log Console</title>\n<link id=\"cssLink\" rel=\"stylesheet\" href=\"selenium.css\" />\n<script src=\"scripts/htmlutils.js\"></script>\n<script language=\"JavaScript\">\n\nvar disabled = true;\n\nfunction logOnLoad() {\n    var urlConfig = new URLConfiguration();\n    urlConfig.queryString = window.location.search.substr(1);\n    var startingThreshold = urlConfig._getQueryParameter(\"startingThreshold\");\n    setThresholdLevel(startingThreshold);\n    var buttons = document.getElementsByTagName(\"input\");\n    for (var i = 0; i < buttons.length; i++) {\n        addChangeListener(buttons[i]);\n    }\n}\n\nfunction enableButtons() {\n    var buttons = document.getElementsByTagName(\"input\");\n    for (var i = 0; i < buttons.length; i++) {\n        buttons[i].disabled = false;\n        disabled = false;\n    }\n}\n\nfunction callBack() {}\n\nfunction changeHandler() {\n    callBack(getThresholdLevel());\n}\n\nfunction addChangeListener(element) {\n    if (window.addEventListener && !window.opera)\n        element.addEventListener(\"click\", changeHandler, true);\n    else if (window.attachEvent)\n        element.attachEvent(\"onclick\", changeHandler);\n}\n\nvar logLevels = {\n    debug: 0,\n    info: 1,\n    warn: 2,\n    error: 3\n};\n\nfunction getThresholdLevel() {\n    var buttons = document.getElementById('logLevelChooser').level;\n    for (var i = 0; i < buttons.length; i++) {\n        if (buttons[i].checked) {\n            return buttons[i].value;\n        }\n    }\n}\n\nfunction setThresholdLevel(logLevel) {\n    var buttons = document.getElementById('logLevelChooser').level;\n    for (var i = 0; i < buttons.length; i++) {\n        if (buttons[i].value==logLevel) {\n            buttons[i].checked = true;\n        }\n        else {\n            buttons[i].checked = false;\n        }\n    }\n}\n\nfunction append(message, logLevel) {\n    var logLevelThreshold = getThresholdLevel();\n    if (logLevels[logLevel] < logLevels[logLevelThreshold]) {\n        return;\n    }\n    var log = document.getElementById('log');\n    var newEntry = document.createElement('li');\n    newEntry.className = logLevel;\n    newEntry.appendChild(document.createTextNode(message));\n    log.appendChild(newEntry);\n    if (newEntry.scrollIntoView) {\n        newEntry.scrollIntoView();\n    }\n}\n\n</script>\n</head>\n<body id=\"logging-console\" onload=\"logOnLoad();\">\n\n\n\n<div id=\"banner\">\n  <form id=\"logLevelChooser\">\n      <input id=\"level-error\" type=\"radio\" name=\"level\" disabled='true'\n             value=\"error\" /><label for=\"level-error\">Error</label>\n      <input id=\"level-warn\" type=\"radio\" name=\"level\" disabled='true'\n             value=\"warn\" /><label for=\"level-warn\">Warn</label>\n      <input id=\"level-info\" type=\"radio\" name=\"level\" disabled='true'\n             value=\"info\" /><label for=\"level-info\">Info</label>\n      <input id=\"level-debug\" type=\"radio\" name=\"level\" checked=\"yes\" disabled='true'\n             value=\"debug\" /><label for=\"level-debug\">Debug</label>\n  </form>\n  <h1>Selenium Log Console</h1>\n</div>\n\n<ul id=\"log\"></ul>\n\n</body>\n</html>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/TestPrompt.html",
    "content": "<html>\n<!--\nCopyright 2004 ThoughtWorks, Inc\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n-->\n\n<head>\n    <meta content=\"text/html; charset=ISO-8859-1\"\n          http-equiv=\"content-type\">\n    <title>Select a Test Suite</title>\n    <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-browserdetect.js\"></script>\n    <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/xmlextras.js\"></script>\n    <script>\n\n        function load() {\n            if (browserVersion.isHTA) {\n                document.getElementById(\"save-div\").style.display = \"inline\";\n            }\n            if (/thisIsSeleniumServer/.test(window.location.search)) {\n                document.getElementById(\"slowResources-div\").style.display = \"inline\";\n                if (browserVersion.isHTA || browserVersion.isChrome) {\n                    document.getElementById(\"test\").value = \"http://localhost:4444/selenium-server/tests/TestSuite.html\";\n                }\n            }\n        }\n\n        function autoCheck() {\n            var auto = document.getElementById(\"auto\");\n            var autoDiv = document.getElementById(\"auto-div\");\n            if (auto.checked) {\n                autoDiv.style.display = \"inline\";\n            } else {\n                autoDiv.style.display = \"none\";\n            }\n        }\n\n        function slowCheck() {\n            var slowResourcesCheckbox = document.getElementById(\"slowResources\");\n            var slowResources = slowResourcesCheckbox.checked ? true : false;\n            var xhr = XmlHttp.create();\n            var driverUrl = \"http://localhost:4444/selenium-server/driver/?cmd=slowResources&1=\" + slowResources;\n            xhr.open(\"GET\", driverUrl, true);\n            xhr.send(null);\n        }\n\n        function saveCheck() {\n            var results = document.getElementById(\"results\");\n            var check = document.getElementById(\"save\").checked;\n            if (check) {\n                results.firstChild.nodeValue = \"Results file \";\n                document.getElementById(\"resultsUrl\").value = \"results.html\";\n            } else {\n                results.firstChild.nodeValue = \"Results URL \";\n                document.getElementById(\"resultsUrl\").value = \"../postResults\";\n            }\n        }\n\n        function go() {\n            if (!browserVersion.isHTA && !browserVersion.isChrome) return true;\n            var inputs = document.getElementsByTagName(\"input\");\n            var queryString = \"\";\n            for (var i = 0; i < inputs.length; i++) {\n                var elem = inputs[i];\n                var name = elem.name;\n                var value = elem.value;\n                if (elem.type == \"checkbox\") {\n                    value = elem.checked;\n                }\n                queryString += escape(name) + \"=\" + escape(value);\n                if (i < (inputs.length - 1)) {\n                    queryString += \"&\";\n                }\n            }\n\n            window.parent.selenium = null;\n            window.parent.htmlTestRunner.controlPanel.queryString = queryString;\n            window.parent.htmlTestRunner.loadSuiteFrame();\n            return false;\n        }\n    </script>\n</head>\n\n<body onload=\"load()\" style=\"font-size: x-small\">\n<form id=\"prompt\" target=\"_top\" method=\"GET\" onsubmit=\"return go();\" action=\"TestRunner.html\">\n\n    <p>\n        Test Suite:\n        <input id=\"test\" name=\"test\" size=\"30\" value=\"../tests/TestSuite.html\"/>\n    </p>\n\n    <p align=\"center\"><input type=\"submit\" value=\"Go\"/></p>\n\n    <fieldset>\n        <legend>Options</legend>\n\n        <p>\n            <input id=\"multiWindow\" type=\"checkbox\" name=\"multiWindow\" onclick=\"autoCheck();\"/> <label\n                for=\"multiWindow\">AUT in separate window</label>\n\n        <p>\n\n        <div id=\"slowResources-div\" style=\"display: none\">\n            <p>\n                <input id=\"slowResources\" type=\"checkbox\" name=\"slowResources\" onclick=\"slowCheck();\" /> <label for=\"slowResources\">Slow down web server</label>\n            </p>\n        </div>\n\n        <p>\n            <input id=\"auto\" type=\"checkbox\" name=\"auto\" onclick=\"autoCheck();\"/> <label for=\"auto\">Run\n            automatically</label>\n        </p>\n\n        <div id=\"auto-div\" style=\"display: none\">\n            <p>\n                <input id=\"close\" type=\"checkbox\" name=\"close\"/> <label for=\"close\">Close afterwards </label>\n            </p>\n\n            <div id=\"save-div\" style=\"display: none\">\n                <br/><label for=\"save\">Save to file </label><input id=\"save\" type=\"checkbox\" name=\"save\"\n                                                                   onclick=\"saveCheck();\"/>\n            </div>\n\n            <p id=\"results\">\n                Results URL:\n                <input id=\"resultsUrl\" name=\"resultsUrl\" value=\"../postResults\"/>\n            </p>\n\n        </div>\n    </fieldset>\n\n\n</form>\n</body>\n</html>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/TestRunner-splash.html",
    "content": "<!--\nCopyright 2005 ThoughtWorks, Inc\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n-->\n\n<html>\n<link rel=\"stylesheet\" type=\"text/css\" href=\"selenium.css\" />\n<body>\n<table width=\"100%\">\n\n<tr>\n  <th>&uarr;</th>\n  <th>&uarr;</th>\n  <th>&uarr;</th>\n</tr>\n<tr>\n  <th width=\"25%\">Test Suite</th>\n  <th width=\"50%\">Current Test</th>\n  <th width=\"25%\">Control Panel</th>\n</tr>\n<tr><td>&nbsp;</td></tr>\n\n<tr>\n<td></td>\n<td class=\"selenium splash\">\n\n<img src=\"selenium-logo.png\" align=\"right\">\n\n<h1>Selenium</h1>\n<h2>by <a href=\"http://www.thoughtworks.com\">ThoughtWorks</a> and friends</h2>\n\n<p>\nFor more information on Selenium, visit\n\n<pre>\n    <a href=\"http://selenium.openqa.org\" target=\"_blank\">http://selenium.openqa.org</a>\n</pre>\n\n</td>\n<tr>\n\n</table>\n</body>\n</html>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/TestRunner.hta",
    "content": "<html>\n\n<head>\n    <HTA:APPLICATION ID=\"SeleniumHTARunner\" APPLICATIONNAME=\"Selenium\">\n        <!-- the previous line is only relevant if you rename this\n     file to \"TestRunner.hta\" -->\n\n        <!-- The copyright notice and other comments have been moved to after the HTA declaration,\nto work-around a bug in IE on Win2K whereby the HTA application doesn't function correctly -->\n        <!--\n        Copyright 2004 ThoughtWorks, Inc\n\n         Licensed under the Apache License, Version 2.0 (the \"License\");\n         you may not use this file except in compliance with the License.\n         You may obtain a copy of the License at\n\n             http://www.apache.org/licenses/LICENSE-2.0\n\n         Unless required by applicable law or agreed to in writing, software\n         distributed under the License is distributed on an \"AS IS\" BASIS,\n         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n         See the License for the specific language governing permissions and\n         limitations under the License.\n        -->\n        <meta content=\"text/html; charset=ISO-8859-1\" http-equiv=\"content-type\"/>\n\n        <title>Selenium Functional Test Runner</title>\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"selenium.css\"/>\n        <script type=\"text/javascript\" src=\"scripts/xmlextras.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"lib/prototype.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"lib/cssQuery/cssQuery-p.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"lib/snapsie.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/htmlutils.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/ui-element.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"lib/scriptaculous/scriptaculous.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-browserdetect.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-browserbot.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/find_matching_child.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-api.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-commandhandlers.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-executionloop.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-testrunner.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-logging.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-version.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/util.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/xmltoken.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/dom.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/xpath.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/javascript-xpath-0.1.11.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/user-extensions.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\">\n            function openDomViewer() {\n                var autFrame = document.getElementById('selenium_myiframe');\n                var autFrameDocument = new SeleniumFrame(autFrame).getDocument();\n                this.rootDocument = autFrameDocument;\n                var domViewer = window.open(getDocumentBase(document) + 'domviewer/domviewer.html');\n                return false;\n            }\n        </script>\n</head>\n\n<body onLoad=\"onSeleniumLoad();\">\n<table class=\"layout\">\n<form action=\"\" name=\"controlPanel\">\n\n<!-- Suite, Test, Control Panel -->\n\n<tr class=\"selenium\">\n<td width=\"25%\" height=\"30%\">\n    <iframe name=\"testSuiteFrame\" id=\"testSuiteFrame\" src=\"./TestPrompt.html\" application=\"yes\"></iframe>\n</td>\n<td width=\"50%\" height=\"30%\">\n    <iframe name=\"testFrame\" id=\"testFrame\" application=\"yes\" src=\"Blank.html\"></iframe>\n</td>\n\n<td width=\"25%\">\n    <table class=\"layout\">\n        <tr class=\"selenium\">\n            <th width=\"25%\" height=\"1\" class=\"header\">\n                <h1><a href=\"http://selenium.openqa.org\" title=\"The Selenium Project\">Selenium</a> TestRunner\n                </h1>\n            </th>\n        </tr>\n        <tr>\n            <td width=\"25%\" height=\"30%\" id=\"controlPanel\">\n                <fieldset>\n                    <legend>Execute Tests</legend>\n\n                    <div id=\"imageButtonPanel\">\n                        <button type=\"button\" id=\"runSuite\" onClick=\"htmlTestRunner.startTestSuite();\"\n                                title=\"Run All tests\" accesskey=\"a\">\n                        </button>\n                        <button type=\"button\" id=\"runSeleniumTest\" onClick=\"htmlTestRunner.runSingleTest();\"\n                                title=\"Run the Selected test\" accesskey=\"r\">\n                        </button>\n                        <button type=\"button\" id=\"pauseTest\" disabled=\"disabled\"\n                                title=\"Pause/Continue\" accesskey=\"p\" class=\"cssPauseTest\">\n                        </button>\n                        <button type=\"button\" id=\"stepTest\" disabled=\"disabled\"\n                                title=\"Step\" accesskey=\"s\">\n                        </button>\n                    </div>\n\n                    <div style=\"float:left\">Fast</div>\n                    <div style=\"float:right\">Slow</div>\n                    <br/>\n                    <div id=\"speedSlider\">\n                        <div id=\"speedTrack\">&nbsp;</div>\n                        <div id=\"speedHandle\">&nbsp;</div>\n                    </div>\n\n                    <div class=\"executionOptions\">\n                        <input id=\"highlightOption\" type=\"checkbox\" name=\"highlightOption\" value=\"0\"/>\n                        <label for=\"highlightOption\">Highlight elements</label>\n                    </div>\n\n                </fieldset>\n\n                <table id=\"stats\" align=\"center\">\n                    <tr>\n                        <td colspan=\"2\" align=\"right\">Elapsed:</td>\n                        <td id=\"elapsedTime\" colspan=\"2\">00.00</td>\n                    </tr>\n                    <tr>\n                        <th colspan=\"2\">Tests</th>\n                        <th colspan=\"2\">Commands</th>\n                    </tr>\n                    <tr>\n                        <td class=\"count\" id=\"testRuns\">0</td>\n                        <td>run</td>\n                        <td class=\"count\" id=\"commandPasses\">0</td>\n                        <td>passed</td>\n                    </tr>\n                    <tr>\n                        <td class=\"count\" id=\"testFailures\">0</td>\n                        <td>failed</td>\n                        <td class=\"count\" id=\"commandFailures\">0</td>\n                        <td>failed</td>\n                    </tr>\n                    <tr>\n                        <td colspan=\"2\"></td>\n                        <td class=\"count\" id=\"commandErrors\">0</td>\n                        <td>incomplete</td>\n                    </tr>\n                </table>\n\n                <fieldset>\n                    <legend>Tools</legend>\n\n                    <button type=\"button\" id=\"domViewer1\" onClick=\"openDomViewer();\">\n                        View DOM\n                    </button>\n                    <button type=\"button\" onClick=\"LOG.show();\">\n                        Show Log\n                    </button>\n\n                </fieldset>\n\n            </td>\n        </tr>\n    </table>\n</td>\n</tr>\n\n<!-- AUT -->\n\n<tr>\n    <td colspan=\"3\" height=\"70%\">\n        <iframe name=\"selenium_myiframe\" id=\"selenium_myiframe\" src=\"TestRunner-splash.html\"></iframe>\n    </td>\n</tr>\n\n    </form>\n    </table>\n\n</body>\n</html>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/TestRunner.html",
    "content": "<html>\n\n<head>\n    <HTA:APPLICATION ID=\"SeleniumHTARunner\" APPLICATIONNAME=\"Selenium\">\n        <!-- the previous line is only relevant if you rename this\n     file to \"TestRunner.hta\" -->\n\n        <!-- The copyright notice and other comments have been moved to after the HTA declaration,\nto work-around a bug in IE on Win2K whereby the HTA application doesn't function correctly -->\n        <!--\n        Copyright 2004 ThoughtWorks, Inc\n\n         Licensed under the Apache License, Version 2.0 (the \"License\");\n         you may not use this file except in compliance with the License.\n         You may obtain a copy of the License at\n\n             http://www.apache.org/licenses/LICENSE-2.0\n\n         Unless required by applicable law or agreed to in writing, software\n         distributed under the License is distributed on an \"AS IS\" BASIS,\n         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n         See the License for the specific language governing permissions and\n         limitations under the License.\n        -->\n        <meta content=\"text/html; charset=ISO-8859-1\" http-equiv=\"content-type\"/>\n\n        <title>Selenium Functional Test Runner</title>\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"selenium.css\"/>\n        <script type=\"text/javascript\" src=\"scripts/xmlextras.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"lib/prototype.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"lib/cssQuery/cssQuery-p.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"lib/snapsie.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/htmlutils.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/ui-element.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"lib/scriptaculous/scriptaculous.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-browserdetect.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-browserbot.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/find_matching_child.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-api.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-commandhandlers.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-executionloop.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-testrunner.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-logging.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/selenium-version.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/util.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/xmltoken.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/dom.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/xpath.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"xpath/javascript-xpath-0.1.11.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\" src=\"scripts/user-extensions.js\"></script>\n        <script language=\"JavaScript\" type=\"text/javascript\">\n            function openDomViewer() {\n                var autFrame = document.getElementById('selenium_myiframe');\n                var autFrameDocument = new SeleniumFrame(autFrame).getDocument();\n                this.rootDocument = autFrameDocument;\n                var domViewer = window.open(getDocumentBase(document) + 'domviewer/domviewer.html');\n                return false;\n            }\n        </script>\n</head>\n\n<body onLoad=\"onSeleniumLoad();\">\n<table class=\"layout\">\n<form action=\"\" name=\"controlPanel\">\n\n<!-- Suite, Test, Control Panel -->\n\n<tr class=\"selenium\">\n<td width=\"25%\" height=\"30%\">\n    <iframe name=\"testSuiteFrame\" id=\"testSuiteFrame\" src=\"./TestPrompt.html\" application=\"yes\"></iframe>\n</td>\n<td width=\"50%\" height=\"30%\">\n    <iframe name=\"testFrame\" id=\"testFrame\" application=\"yes\" src=\"Blank.html\"></iframe>\n</td>\n\n<td width=\"25%\">\n    <table class=\"layout\">\n        <tr class=\"selenium\">\n            <th width=\"25%\" height=\"1\" class=\"header\">\n                <h1><a href=\"http://selenium.openqa.org\" title=\"The Selenium Project\">Selenium</a> TestRunner\n                </h1>\n            </th>\n        </tr>\n        <tr>\n            <td width=\"25%\" height=\"30%\" id=\"controlPanel\">\n                <fieldset>\n                    <legend>Execute Tests</legend>\n\n                    <div id=\"imageButtonPanel\">\n                        <button type=\"button\" id=\"runSuite\" onClick=\"htmlTestRunner.startTestSuite();\"\n                                title=\"Run All tests\" accesskey=\"a\">\n                        </button>\n                        <button type=\"button\" id=\"runSeleniumTest\" onClick=\"htmlTestRunner.runSingleTest();\"\n                                title=\"Run the Selected test\" accesskey=\"r\">\n                        </button>\n                        <button type=\"button\" id=\"pauseTest\" disabled=\"disabled\"\n                                title=\"Pause/Continue\" accesskey=\"p\" class=\"cssPauseTest\">\n                        </button>\n                        <button type=\"button\" id=\"stepTest\" disabled=\"disabled\"\n                                title=\"Step\" accesskey=\"s\">\n                        </button>\n                    </div>\n\n                    <div style=\"float:left\">Fast</div>\n                    <div style=\"float:right\">Slow</div>\n                    <br/>\n                    <div id=\"speedSlider\">\n                        <div id=\"speedTrack\">&nbsp;</div>\n                        <div id=\"speedHandle\">&nbsp;</div>\n                    </div>\n\n                    <div class=\"executionOptions\">\n                        <input id=\"highlightOption\" type=\"checkbox\" name=\"highlightOption\" value=\"0\"/>\n                        <label for=\"highlightOption\">Highlight elements</label>\n                    </div>\n\n                </fieldset>\n\n                <table id=\"stats\" align=\"center\">\n                    <tr>\n                        <td colspan=\"2\" align=\"right\">Elapsed:</td>\n                        <td id=\"elapsedTime\" colspan=\"2\">00.00</td>\n                    </tr>\n                    <tr>\n                        <th colspan=\"2\">Tests</th>\n                        <th colspan=\"2\">Commands</th>\n                    </tr>\n                    <tr>\n                        <td class=\"count\" id=\"testRuns\">0</td>\n                        <td>run</td>\n                        <td class=\"count\" id=\"commandPasses\">0</td>\n                        <td>passed</td>\n                    </tr>\n                    <tr>\n                        <td class=\"count\" id=\"testFailures\">0</td>\n                        <td>failed</td>\n                        <td class=\"count\" id=\"commandFailures\">0</td>\n                        <td>failed</td>\n                    </tr>\n                    <tr>\n                        <td colspan=\"2\"></td>\n                        <td class=\"count\" id=\"commandErrors\">0</td>\n                        <td>incomplete</td>\n                    </tr>\n                </table>\n\n                <fieldset>\n                    <legend>Tools</legend>\n\n                    <button type=\"button\" id=\"domViewer1\" onClick=\"openDomViewer();\">\n                        View DOM\n                    </button>\n                    <button type=\"button\" onClick=\"LOG.show();\">\n                        Show Log\n                    </button>\n\n                </fieldset>\n\n            </td>\n        </tr>\n    </table>\n</td>\n</tr>\n\n<!-- AUT -->\n\n<tr>\n    <td colspan=\"3\" height=\"70%\">\n        <iframe name=\"selenium_myiframe\" id=\"selenium_myiframe\" src=\"TestRunner-splash.html\"></iframe>\n    </td>\n</tr>\n\n    </form>\n    </table>\n\n</body>\n</html>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/domviewer/domviewer.css",
    "content": "/******************************************************************************\n* Defines default styles for site pages.                                      *\n******************************************************************************/\n.hidden {\n\tdisplay: none;\n}\n\nimg{\n    display: inline;\n\tborder: none;\n}\n\n.box{\n\tbackground: #fcfcfc;\n    border: 1px solid #000;\n\tborder-color: blue;\n    color: #000000;\n\tmargin: 10px auto;\n    padding: 3px;\n\tvertical-align: bottom;\n}\na {\n  text-decoration: none;\n}\n\nbody {\n  background-color: #ffffff;\n  color: #000000;\n  font-family: Arial, Helvetica, sans-serif;\n  font-size: 10pt;\n}\n\nh2 {\n  font-size: 140%;\n}\n\nh3 {\n  font-size: 120%;\n}\n\nh4 {\n  font-size: 100%;\n}\n\npre {\n  font-family: Courier New, Courier, monospace;\n  font-size: 80%;\n}\n\ntd, th {\n  font-family: Arial, Helvetica, sans-serif;\n  font-size: 10pt;\n  text-align: left;\n  vertical-align: top;\n}\n\nth {\n  font-weight: bold;\n  vertical-align: bottom;\n}\n\nul {\n  list-style-type: square;\n}\n\n#demoBox {\n  border-color: #000000;\n  border-style: solid;\n  border-width: 1px;\n  padding: 8px;\n  width: 24em;\n}\n\n.footer {\n  margin-bottom: 0px;\n  text-align: center;\n}\n\n/* Boxed table styles */\n\ntable.boxed {\n  border-spacing: 2px;\n  empty-cells: hide;\n}\n\ntd.boxed, th.boxed, th.boxedHeader {\n  background-color: #ffffff;\n  border-color: #000000;\n  border-style: solid;\n  border-width: 1px;\n  color: #000000;\n  padding: 2px;\n  padding-left: 8px;\n  padding-right: 8px;\n}\n\nth.boxed {\n  background-color: #c0c0c0;\n}\n\nth.boxedHeader {\n  background-color: #808080;\n  color: #ffffff;\n}\n\na.object {\n  color: #0000ff;\n}\n\nli {\n  white-space: nowrap;\n}\n\nul {\n  list-style-type: square;\n  margin-left: 0px;\n  padding-left: 1em;\n}\n\n.boxlevel1{\n\tbackground: #FFD700;\n}\n\n.boxlevel2{\n\tbackground: #D2691E;\n}\n\n.boxlevel3{\n\tbackground: #DCDCDC;\n}\n\n.boxlevel4{\n\tbackground: #F5F5F5;\n}\n\n.boxlevel5{\n\tbackground: #BEBEBE;\n}\n\n.boxlevel6{\n\tbackground: #D3D3D3;\n}\n\n.boxlevel7{\n\tbackground: #A9A9A9;\n}\n\n.boxlevel8{\n\tbackground: #191970;\n}\n\n.boxlevel9{\n\tbackground: #000080;\n}\n\n.boxlevel10{\n\tbackground: #6495ED;\n}\n\n.boxlevel11{\n\tbackground: #483D8B;\n}\n\n.boxlevel12{\n\tbackground: #6A5ACD;\n}\n\n.boxlevel13{\n\tbackground: #7B68EE;\n}\n\n.boxlevel14{\n\tbackground: #8470FF;\n}\n\n.boxlevel15{\n\tbackground: #0000CD;\n}\n\n.boxlevel16{\n\tbackground: #4169E1;\n}\n\n.boxlevel17{\n\tbackground: #0000FF;\n}\n\n.boxlevel18{\n\tbackground: #1E90FF;\n}\n\n.boxlevel19{\n\tbackground: #00BFFF;\n}\n\n.boxlevel20{\n\tbackground: #87CEEB;\n}\n\n.boxlevel21{\n\tbackground: #B0C4DE;\n}\n\n.boxlevel22{\n\tbackground: #ADD8E6;\n}\n\n.boxlevel23{\n\tbackground: #00CED1;\n}\n\n.boxlevel24{\n\tbackground: #48D1CC;\n}\n\n.boxlevel25{\n\tbackground: #40E0D0;\n}\n\n.boxlevel26{\n\tbackground: #008B8B;\n}\n\n.boxlevel27{\n\tbackground: #00FFFF;\n}\n\n.boxlevel28{\n\tbackground: #E0FFFF;\n}\n\n.boxlevel29{\n\tbackground: #5F9EA0;\n}\n\n.boxlevel30{\n\tbackground: #66CDAA;\n}\n\n.boxlevel31{\n\tbackground: #7FFFD4;\n}\n\n.boxlevel32{\n\tbackground: #006400;\n}\n\n.boxlevel33{\n\tbackground: #556B2F;\n}\n\n.boxlevel34{\n\tbackground: #8FBC8F;\n}\n\n.boxlevel35{\n\tbackground: #2E8B57;\n}\n\n.boxlevel36{\n\tbackground: #3CB371;\n}\n\n.boxlevel37{\n\tbackground: #20B2AA;\n}\n\n.boxlevel38{\n\tbackground: #00FF7F;\n}\n\n.boxlevel39{\n\tbackground: #7CFC00;\n}\n\n.boxlevel40{\n\tbackground: #90EE90;\n}\n\n.boxlevel41{\n\tbackground: #00FF00;\n}\n\n.boxlevel41{\n\tbackground: #7FFF00;\n}\n\n.boxlevel42{\n\tbackground: #00FA9A;\n}\n\n.boxlevel43{\n\tbackground: #ADFF2F;\n}\n\n.boxlevel44{\n\tbackground: #32CD32;\n}"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/domviewer/domviewer.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n    <head>\n        <title>DOM Viewer</title>\n        <meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"domviewer.css\"/>\n        <script type=\"text/javascript\" src=\"selenium-domviewer.js\"></script>\n    </head>\n\t<body onload=\"loadDomViewer();\">\n\t\t<h3>DOM Viewer</h3>\n\t\t<p> This page is generated using JavaScript. If you see this text, your \n\t\t\tbrowser doesn't support JavaScript.</p>\n\t</body>\n\t\n</html>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/domviewer/selenium-domviewer.js",
    "content": "var HIDDEN=\"hidden\";\nvar LEVEL = \"level\";\nvar PLUS_SRC=\"butplus.gif\";\nvar MIN_SRC=\"butmin.gif\";\nvar newRoot;\nvar maxColumns=1;\n\nfunction loadDomViewer() {\n    // See if the rootDocument variable has been set on this window.\n    var rootDocument = window.rootDocument;\n\n    // If not look to the opener for an explicity rootDocument variable, otherwise, use the opener document\n    if (!rootDocument && window.opener) {\n        rootDocument = window.opener.rootDocument || window.opener.document;\n    }\n\n    if (rootDocument) {\n        document.body.innerHTML = displayDOM(rootDocument);\n    }\n    else {\n        document.body.innerHTML = \"<b>Must specify rootDocument for window. This can be done by setting the rootDocument variable on this window, or on the opener window for a popup window.</b>\";\n    }\n}\n\n\nfunction displayDOM(root){\n    var str = \"\";\n    str+=\"<table>\";\n    str += treeTraversal(root,0);\n    // to make table columns work well.\n    str += \"<tr>\";\n    for (var i=0; i < maxColumns; i++) {\n        str+= \"<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>\";\n    }\n    str += \"</tr>\";\n    str += \"</table>\";\n    return str;\n}\n\nfunction checkForChildren(element){\n    if(!element.hasChildNodes())\n        return false;\n    \n    var nodes = element.childNodes;\n    var size = nodes.length;\n    var count=0;\n    \n    for(var i=0; i< size; i++){\n        var node = nodes.item(i);\n        //if(node.toString()==\"[object Text]\"){\n        //this is equalent to the above\n        //but will work with more browsers\n        if(node.nodeType!=1){\n            count++;\n        }\n    }\n    \n    if(count == size)\n        return false;\n    else\n        return true;\n}\n\nfunction treeTraversal(root, level){\n    var str = \"\";\n    var nodes= null;\n    var size = null;\n    //it is supposed to show the last node, \n    //but the last node is always nodeText type\n    //and we don't show it\n    if(!root.hasChildNodes())\n        return \"\";//displayNode(root,level,false);\n    \n    nodes = root.childNodes;\n    size = nodes.length;\n\n    for(var i=0; i< size; i++){\n        var element = nodes.item(i);\n        //if the node is textNode, don't display\n        if(element.nodeType==1){\n            str+= displayNode(element,level,checkForChildren(element));\n            str+=treeTraversal(element, level+1);\t\n        }\n    }\n    return str;\n}\n\nfunction displayNode(element, level, isLink){\n    nodeContent = getNodeContent(element);\n    columns = Math.round((nodeContent.length / 12) + 0.5);\n    if (columns + level > maxColumns) {\n        maxColumns = columns + level;\n    }\n    var str =\"<tr class='\"+LEVEL+level+\"'>\";\n    for (var i=0; i < level; i++)\n        str+= \"<td> </td>\";\n    str+=\"<td colspan='\"+ columns +\"' class='box\"+\" boxlevel\"+level+\"' >\";\n    if(isLink){\n        str+='<a onclick=\"hide(this);return false;\" href=\"javascript:void();\">';\n        str+='<img src=\"'+MIN_SRC+'\" />';\n    }\n    str += nodeContent;\n    if(isLink)\n        str+=\"</a></td></tr>\";\n    return str;\n}\n\nfunction getNodeContent(element) {\n\n    str = \"\";\n    id =\"\";\n    if (element.id != null && element.id != \"\") {\n        id = \" ID(\" + element.id +\")\";\n    }\n    name =\"\";\n    if (element.name != null && element.name != \"\") {\n        name = \" NAME(\" + element.name + \")\";\n    }\n    value =\"\";\n    if (element.value != null && element.value != \"\") {\n        value = \" VALUE(\" + element.value + \")\";\n    }\n    href =\"\";\n    if (element.href != null && element.href != \"\") {\n        href = \" HREF(\" + element.href + \")\";\n    }\n    clazz = \"\";\n    if (element.className != null && element.className != \"\") {\n        clazz = \" CLASS(\" + element.className + \")\";\n    }\n    src = \"\";\n    if (element.src != null && element.src != \"\") {\n        src = \" SRC(\" + element.src + \")\";\n    }\n    alt = \"\";\n    if (element.alt != null && element.alt != \"\") {\n        alt = \" ALT(\" + element.alt + \")\";\n    }\n    type = \"\";\n    if (element.type != null && element.type != \"\") {\n        type = \" TYPE(\" + element.type + \")\";\n    }\n    text =\"\";\n    if (element.text != null && element.text != \"\" && element.text != \"undefined\") {\n        text = \" #TEXT(\" + trim(element.text) +\")\";\n    }\n    str+=\" <b>\"+ element.nodeName + id + alt + type + clazz + name + value + href + src + text + \"</b>\";\n    return str;\n\n}\n\nfunction trim(val) {\n    val2 = val.substring(0,40) + \"                   \";\n    var spaceChr = String.fromCharCode(32);\n    var length = val2.length;\n    var retVal = \"\";\n    var ix = length -1;\n\n    while(ix > -1){\n        if(val2.charAt(ix) == spaceChr) {\n        } else {\n            retVal = val2.substring(0, ix +1);\n            break;\n        }\n        ix = ix-1;\n    }\n    if (val.length > 40) {\n        retVal += \"...\";\n    }\n    return retVal;\n}\n\nfunction hide(hlink){\n    var isHidden = false;\n    var image = hlink.firstChild;\n    if(image.src.toString().indexOf(MIN_SRC)!=-1){\n        image.src=PLUS_SRC;\n        isHidden=true;\n    }else{\n        image.src=MIN_SRC;\n    }\n    var rowObj= hlink.parentNode.parentNode;\n    var rowLevel = parseInt(rowObj.className.substring(LEVEL.length));\n\t\n    var sibling = rowObj.nextSibling;\n    var siblingLevel = sibling.className.substring(LEVEL.length);\n    if(siblingLevel.indexOf(HIDDEN)!=-1){\n        siblingLevel = siblingLevel.substring(0,siblingLevel.length - HIDDEN.length-1);\n    }\n    siblingLevel=parseInt(siblingLevel);\n    while(sibling!=null && rowLevel<siblingLevel){\n        if(isHidden){\n            sibling.className += \" \"+ HIDDEN;\n        }else if(!isHidden && sibling.className.indexOf(HIDDEN)!=-1){\n            var str = sibling.className;\n            sibling.className=str.substring(0, str.length - HIDDEN.length-1);\n        }\n        sibling = sibling.nextSibling;\n        siblingLevel = parseInt(sibling.className.substring(LEVEL.length));\n    }\n}\n\nfunction LOG(message) {\n    window.opener.LOG.warn(message);\n}\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/iedoc-core.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<apidoc>\n\n<top>Defines an object that runs Selenium commands.\n\n<h3><a name=\"locators\"></a>Element Locators</h3>\n<p>\nElement Locators tell Selenium which HTML element a command refers to.\nThe format of a locator is:</p>\n<blockquote>\n<em>locatorType</em><strong>=</strong><em>argument</em>\n</blockquote>\n\n<p>\nWe support the following strategies for locating elements:\n</p>\n\n<ul>\n<li><strong>identifier</strong>=<em>id</em>: \nSelect the element with the specified &#064;id attribute. If no match is\nfound, select the first element whose &#064;name attribute is <em>id</em>.\n(This is normally the default; see below.)</li>\n<li><strong>id</strong>=<em>id</em>:\nSelect the element with the specified &#064;id attribute.</li>\n\n<li><strong>name</strong>=<em>name</em>:\nSelect the first element with the specified &#064;name attribute.\n<ul class=\"first last simple\">\n<li>username</li>\n<li>name=username</li>\n</ul>\n\n<p>The name may optionally be followed by one or more <em>element-filters</em>, separated from the name by whitespace.  If the <em>filterType</em> is not specified, <strong>value</strong> is assumed.</p>\n\n<ul class=\"first last simple\">\n<li>name=flavour value=chocolate</li>\n</ul>\n</li>\n<li><strong>dom</strong>=<em>javascriptExpression</em>: \n\nFind an element by evaluating the specified string.  This allows you to traverse the HTML Document Object\nModel using JavaScript.  Note that you must not return a value in this string; simply make it the last expression in the block.\n<ul class=\"first last simple\">\n<li>dom=document.forms['myForm'].myDropdown</li>\n<li>dom=document.images[56]</li>\n<li>dom=function foo() { return document.links[1]; }; foo();</li>\n</ul>\n\n</li>\n\n<li><strong>xpath</strong>=<em>xpathExpression</em>: \nLocate an element using an XPath expression.\n<ul class=\"first last simple\">\n<li>xpath=//img[&#064;alt='The image alt text']</li>\n<li>xpath=//table[&#064;id='table1']//tr[4]/td[2]</li>\n<li>xpath=//a[contains(&#064;href,'#id1')]</li>\n<li>xpath=//a[contains(&#064;href,'#id1')]/&#064;class</li>\n<li>xpath=(//table[&#064;class='stylee'])//th[text()='theHeaderText']/../td</li>\n<li>xpath=//input[&#064;name='name2' and &#064;value='yes']</li>\n<li>xpath=//*[text()=\"right\"]</li>\n\n</ul>\n</li>\n<li><strong>link</strong>=<em>textPattern</em>:\nSelect the link (anchor) element which contains text matching the\nspecified <em>pattern</em>.\n<ul class=\"first last simple\">\n<li>link=The link text</li>\n</ul>\n\n</li>\n\n<li><strong>css</strong>=<em>cssSelectorSyntax</em>:\nSelect the element using css selectors. Please refer to <a href=\"http://www.w3.org/TR/REC-CSS2/selector.html\">CSS2 selectors</a>, <a href=\"http://www.w3.org/TR/2001/CR-css3-selectors-20011113/\">CSS3 selectors</a> for more information. You can also check the TestCssLocators test in the selenium test suite for an example of usage, which is included in the downloaded selenium core package.\n<ul class=\"first last simple\">\n<li>css=a[href=\"#id3\"]</li>\n<li>css=span#firstChild + span</li>\n</ul>\n<p>Currently the css selector locator supports all css1, css2 and css3 selectors except namespace in css3, some pseudo classes(:nth-of-type, :nth-last-of-type, :first-of-type, :last-of-type, :only-of-type, :visited, :hover, :active, :focus, :indeterminate) and pseudo elements(::first-line, ::first-letter, ::selection, ::before, ::after). </p>\n</li>\n\n<li><strong>ui</strong>=<em>uiSpecifierString</em>:\nLocate an element by resolving the UI specifier string to another locator, and evaluating it. See the <a href=\"http://svn.openqa.org/fisheye/browse/~raw,r=trunk/selenium/trunk/src/main/resources/core/scripts/ui-doc.html\">Selenium UI-Element Reference</a> for more details.\n<ul class=\"first last simple\">\n<li>ui=loginPages::loginButton()</li>\n<li>ui=settingsPages::toggle(label=Hide Email)</li>\n<li>ui=forumPages::postBody(index=2)//a[2]</li>\n</ul>\n</li>\n\n</ul>\n\n<p>\nWithout an explicit locator prefix, Selenium uses the following default\nstrategies:\n</p>\n\n<ul class=\"simple\">\n<li><strong>dom</strong>, for locators starting with &quot;document.&quot;</li>\n<li><strong>xpath</strong>, for locators starting with &quot;//&quot;</li>\n<li><strong>identifier</strong>, otherwise</li>\n</ul>\n\n<h3><a name=\"element-filters\">Element Filters</a></h3>\n<blockquote>\n<p>Element filters can be used with a locator to refine a list of candidate elements.  They are currently used only in the 'name' element-locator.</p>\n<p>Filters look much like locators, ie.</p>\n<blockquote>\n<em>filterType</em><strong>=</strong><em>argument</em></blockquote>\n\n<p>Supported element-filters are:</p>\n<p><strong>value=</strong><em>valuePattern</em></p>\n<blockquote>\nMatches elements based on their values.  This is particularly useful for refining a list of similarly-named toggle-buttons.</blockquote>\n<p><strong>index=</strong><em>index</em></p>\n<blockquote>\nSelects a single element based on its position in the list (offset from zero).</blockquote>\n</blockquote>\n\n<h3><a name=\"patterns\"></a>String-match Patterns</h3>\n\n<p>\nVarious Pattern syntaxes are available for matching string values:\n</p>\n<ul>\n<li><strong>glob:</strong><em>pattern</em>:\nMatch a string against a \"glob\" (aka \"wildmat\") pattern. \"Glob\" is a\nkind of limited regular-expression syntax typically used in command-line\nshells. In a glob pattern, \"*\" represents any sequence of characters, and \"?\"\nrepresents any single character. Glob patterns match against the entire\nstring.</li>\n<li><strong>regexp:</strong><em>regexp</em>:\nMatch a string using a regular-expression. The full power of JavaScript\nregular-expressions is available.</li>\n<li><strong>regexpi:</strong><em>regexpi</em>:\nMatch a string using a case-insensitive regular-expression.</li>\n<li><strong>exact:</strong><em>string</em>:\n\nMatch a string exactly, verbatim, without any of that fancy wildcard\nstuff.</li>\n</ul>\n<p>\nIf no pattern prefix is specified, Selenium assumes that it's a \"glob\"\npattern.\n</p>\n<p>\nFor commands that return multiple values (such as verifySelectOptions),\nthe string being matched is a comma-separated list of the return values,\nwhere both commas and backslashes in the values are backslash-escaped.\nWhen providing a pattern, the optional matching syntax (i.e. glob,\nregexp, etc.) is specified once, as usual, at the beginning of the\npattern.\n</p></top>\n\n<function name=\"click\">\n\n<param name=\"locator\">an element locator</param>\n\n<comment>Clicks on a link, button, checkbox or radio button. If the click action\ncauses a new page to load (like a link usually does), call\nwaitForPageToLoad.</comment>\n\n</function>\n\n<function name=\"doubleClick\">\n\n<param name=\"locator\">an element locator</param>\n\n<comment>Double clicks on a link, button, checkbox or radio button. If the double click action\ncauses a new page to load (like a link usually does), call\nwaitForPageToLoad.</comment>\n\n</function>\n\n<function name=\"contextMenu\">\n\n<param name=\"locator\">an element locator</param>\n\n<comment>Simulates opening the context menu for the specified element (as might happen if the user \"right-clicked\" on the element).</comment>\n\n</function>\n\n<function name=\"clickAt\">\n\n<param name=\"locator\">an element locator</param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Clicks on a link, button, checkbox or radio button. If the click action\ncauses a new page to load (like a link usually does), call\nwaitForPageToLoad.</comment>\n\n</function>\n\n<function name=\"doubleClickAt\">\n\n<param name=\"locator\">an element locator</param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Doubleclicks on a link, button, checkbox or radio button. If the action\ncauses a new page to load (like a link usually does), call\nwaitForPageToLoad.</comment>\n\n</function>\n\n<function name=\"contextMenuAt\">\n\n<param name=\"locator\">an element locator</param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates opening the context menu for the specified element (as might happen if the user \"right-clicked\" on the element).</comment>\n\n</function>\n\n<function name=\"fireEvent\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"eventName\">the event name, e.g. \"focus\" or \"blur\"</param>\n\n<comment>Explicitly simulate an event, to trigger the corresponding &quot;on<em>event</em>&quot;\nhandler.</comment>\n\n</function>\n\n<function name=\"focus\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Move the focus to the specified element; for example, if the element is an input field, move the cursor to that field.</comment>\n\n</function>\n\n<function name=\"keyPress\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"keySequence\">Either be a string(\"\\\" followed by the numeric keycode  of the key to be pressed, normally the ASCII value of that key), or a single  character. For example: \"w\", \"\\119\".</param>\n\n<comment>Simulates a user pressing and releasing a key.</comment>\n\n</function>\n\n<function name=\"shiftKeyDown\">\n\n<comment>Press the shift key and hold it down until doShiftUp() is called or a new page is loaded.</comment>\n\n</function>\n\n<function name=\"shiftKeyUp\">\n\n<comment>Release the shift key.</comment>\n\n</function>\n\n<function name=\"metaKeyDown\">\n\n<comment>Press the meta key and hold it down until doMetaUp() is called or a new page is loaded.</comment>\n\n</function>\n\n<function name=\"metaKeyUp\">\n\n<comment>Release the meta key.</comment>\n\n</function>\n\n<function name=\"altKeyDown\">\n\n<comment>Press the alt key and hold it down until doAltUp() is called or a new page is loaded.</comment>\n\n</function>\n\n<function name=\"altKeyUp\">\n\n<comment>Release the alt key.</comment>\n\n</function>\n\n<function name=\"controlKeyDown\">\n\n<comment>Press the control key and hold it down until doControlUp() is called or a new page is loaded.</comment>\n\n</function>\n\n<function name=\"controlKeyUp\">\n\n<comment>Release the control key.</comment>\n\n</function>\n\n<function name=\"keyDown\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"keySequence\">Either be a string(\"\\\" followed by the numeric keycode  of the key to be pressed, normally the ASCII value of that key), or a single  character. For example: \"w\", \"\\119\".</param>\n\n<comment>Simulates a user pressing a key (without releasing it yet).</comment>\n\n</function>\n\n<function name=\"keyUp\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"keySequence\">Either be a string(\"\\\" followed by the numeric keycode  of the key to be pressed, normally the ASCII value of that key), or a single  character. For example: \"w\", \"\\119\".</param>\n\n<comment>Simulates a user releasing a key.</comment>\n\n</function>\n\n<function name=\"mouseOver\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates a user hovering a mouse over the specified element.</comment>\n\n</function>\n\n<function name=\"mouseOut\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates a user moving the mouse pointer away from the specified element.</comment>\n\n</function>\n\n<function name=\"mouseDown\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates a user pressing the left mouse button (without releasing it yet) on\nthe specified element.</comment>\n\n</function>\n\n<function name=\"mouseDownRight\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates a user pressing the right mouse button (without releasing it yet) on\nthe specified element.</comment>\n\n</function>\n\n<function name=\"mouseDownAt\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates a user pressing the left mouse button (without releasing it yet) at\nthe specified location.</comment>\n\n</function>\n\n<function name=\"mouseDownRightAt\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates a user pressing the right mouse button (without releasing it yet) at\nthe specified location.</comment>\n\n</function>\n\n<function name=\"mouseUp\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates the event that occurs when the user releases the mouse button (i.e., stops\nholding the button down) on the specified element.</comment>\n\n</function>\n\n<function name=\"mouseUpRight\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates the event that occurs when the user releases the right mouse button (i.e., stops\nholding the button down) on the specified element.</comment>\n\n</function>\n\n<function name=\"mouseUpAt\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates the event that occurs when the user releases the mouse button (i.e., stops\nholding the button down) at the specified location.</comment>\n\n</function>\n\n<function name=\"mouseUpRightAt\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates the event that occurs when the user releases the right mouse button (i.e., stops\nholding the button down) at the specified location.</comment>\n\n</function>\n\n<function name=\"mouseMove\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates a user pressing the mouse button (without releasing it yet) on\nthe specified element.</comment>\n\n</function>\n\n<function name=\"mouseMoveAt\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates a user pressing the mouse button (without releasing it yet) on\nthe specified element.</comment>\n\n</function>\n\n<function name=\"type\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"value\">the value to type</param>\n\n<comment>Sets the value of an input field, as though you typed it in.\n\n<p>Can also be used to set the value of combo boxes, check boxes, etc. In these cases,\nvalue should be the value of the option selected, not the visible text.</p></comment>\n\n</function>\n\n<function name=\"typeKeys\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"value\">the value to type</param>\n\n<comment>Simulates keystroke events on the specified element, as though you typed the value key-by-key.\n\n<p>This is a convenience method for calling keyDown, keyUp, keyPress for every character in the specified string;\nthis is useful for dynamic UI widgets (like auto-completing combo boxes) that require explicit key events.</p>\n\n<p>Unlike the simple \"type\" command, which forces the specified value into the page directly, this command\nmay or may not have any visible effect, even in cases where typing keys would normally have a visible effect.\nFor example, if you use \"typeKeys\" on a form element, you may or may not see the results of what you typed in\nthe field.</p>\n<p>In some cases, you may need to use the simple \"type\" command to set the value of the field and then the \"typeKeys\" command to\nsend the keystroke events corresponding to what you just typed.</p></comment>\n\n</function>\n\n<function name=\"setSpeed\">\n\n<param name=\"value\">the number of milliseconds to pause after operation</param>\n\n<comment>Set execution speed (i.e., set the millisecond length of a delay which will follow each selenium operation).  By default, there is no such delay, i.e.,\nthe delay is 0 milliseconds.</comment>\n\n</function>\n\n<function name=\"getSpeed\">\n\n<return type=\"string\">the execution speed in milliseconds.</return>\n\n<comment>Get execution speed (i.e., get the millisecond length of the delay following each selenium operation).  By default, there is no such delay, i.e.,\nthe delay is 0 milliseconds.\n\nSee also setSpeed.</comment>\n\n</function>\n\n<function name=\"check\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Check a toggle-button (checkbox/radio)</comment>\n\n</function>\n\n<function name=\"uncheck\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Uncheck a toggle-button (checkbox/radio)</comment>\n\n</function>\n\n<function name=\"select\">\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<param name=\"optionLocator\">an option locator (a label by default)</param>\n\n<comment>Select an option from a drop-down using an option locator.\n\n<p>\nOption locators provide different ways of specifying options of an HTML\nSelect element (e.g. for selecting a specific option, or for asserting\nthat the selected option satisfies a specification). There are several\nforms of Select Option Locator.\n</p>\n<ul>\n<li><strong>label</strong>=<em>labelPattern</em>:\nmatches options based on their labels, i.e. the visible text. (This\nis the default.)\n<ul class=\"first last simple\">\n<li>label=regexp:^[Oo]ther</li>\n</ul>\n</li>\n<li><strong>value</strong>=<em>valuePattern</em>:\nmatches options based on their values.\n<ul class=\"first last simple\">\n<li>value=other</li>\n</ul>\n\n\n</li>\n<li><strong>id</strong>=<em>id</em>:\n\nmatches options based on their ids.\n<ul class=\"first last simple\">\n<li>id=option1</li>\n</ul>\n</li>\n<li><strong>index</strong>=<em>index</em>:\nmatches an option based on its index (offset from zero).\n<ul class=\"first last simple\">\n\n<li>index=2</li>\n</ul>\n</li>\n</ul>\n<p>\nIf no option locator prefix is provided, the default behaviour is to match on <strong>label</strong>.\n</p></comment>\n\n</function>\n\n<function name=\"addSelection\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> identifying a multi-select box</param>\n\n<param name=\"optionLocator\">an option locator (a label by default)</param>\n\n<comment>Add a selection to the set of selected options in a multi-select element using an option locator.\n\n@see #doSelect for details of option locators</comment>\n\n</function>\n\n<function name=\"removeSelection\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> identifying a multi-select box</param>\n\n<param name=\"optionLocator\">an option locator (a label by default)</param>\n\n<comment>Remove a selection from the set of selected options in a multi-select element using an option locator.\n\n@see #doSelect for details of option locators</comment>\n\n</function>\n\n<function name=\"removeAllSelections\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> identifying a multi-select box</param>\n\n<comment>Unselects all of the selected options in a multi-select element.</comment>\n\n</function>\n\n<function name=\"submit\">\n\n<param name=\"formLocator\">an <a href=\"#locators\">element locator</a> for the form you want to submit</param>\n\n<comment>Submit the specified form. This is particularly useful for forms without\nsubmit buttons, e.g. single-input \"Search\" forms.</comment>\n\n</function>\n\n<function name=\"open\">\n\n<param name=\"url\">the URL to open; may be relative or absolute</param>\n\n<comment>Opens an URL in the test frame. This accepts both relative and absolute\nURLs.\n\nThe &quot;open&quot; command waits for the page to load before proceeding,\nie. the &quot;AndWait&quot; suffix is implicit.\n\n<em>Note</em>: The URL must be on the same domain as the runner HTML\ndue to security restrictions in the browser (Same Origin Policy). If you\nneed to open an URL on another domain, use the Selenium Server to start a\nnew browser session on that domain.</comment>\n\n</function>\n\n<function name=\"openWindow\">\n\n<param name=\"url\">the URL to open, which can be blank</param>\n\n<param name=\"windowID\">the JavaScript window ID of the window to select</param>\n\n<comment>Opens a popup window (if a window with that ID isn't already open).\nAfter opening the window, you'll need to select it using the selectWindow\ncommand.\n\n<p>This command can also be a useful workaround for bug SEL-339.  In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the \"onLoad\" event, for example).\nIn those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using\nan empty (blank) url, like this: openWindow(\"\", \"myFunnyWindow\").</p></comment>\n\n</function>\n\n<function name=\"selectWindow\">\n\n<param name=\"windowID\">the JavaScript window ID of the window to select</param>\n\n<comment>Selects a popup window using a window locator; once a popup window has been selected, all\ncommands go to that window. To select the main window again, use null\nas the target.\n\n<p>\n\nWindow locators provide different ways of specifying the window object:\nby title, by internal JavaScript \"name,\" or by JavaScript variable.\n</p>\n<ul>\n<li><strong>title</strong>=<em>My Special Window</em>:\nFinds the window using the text that appears in the title bar.  Be careful;\ntwo windows can share the same title.  If that happens, this locator will\njust pick one.\n</li>\n<li><strong>name</strong>=<em>myWindow</em>:\nFinds the window using its internal JavaScript \"name\" property.  This is the second \nparameter \"windowName\" passed to the JavaScript method window.open(url, windowName, windowFeatures, replaceFlag)\n(which Selenium intercepts).\n</li>\n<li><strong>var</strong>=<em>variableName</em>:\nSome pop-up windows are unnamed (anonymous), but are associated with a JavaScript variable name in the current\napplication window, e.g. \"window.foo = window.open(url);\".  In those cases, you can open the window using\n\"var=foo\".\n</li>\n</ul>\n<p>\nIf no window locator prefix is provided, we'll try to guess what you mean like this:</p>\n<p>1.) if windowID is null, (or the string \"null\") then it is assumed the user is referring to the original window instantiated by the browser).</p>\n<p>2.) if the value of the \"windowID\" parameter is a JavaScript variable name in the current application window, then it is assumed\nthat this variable contains the return value from a call to the JavaScript window.open() method.</p>\n<p>3.) Otherwise, selenium looks in a hash it maintains that maps string names to window \"names\".</p>\n<p>4.) If <em>that</em> fails, we'll try looping over all of the known windows to try to find the appropriate \"title\".\nSince \"title\" is not necessarily unique, this may have unexpected behavior.</p>\n\n<p>If you're having trouble figuring out the name of a window that you want to manipulate, look at the Selenium log messages\nwhich identify the names of windows created via window.open (and therefore intercepted by Selenium).  You will see messages\nlike the following for each window as it is opened:</p>\n\n<p><code>debug: window.open call intercepted; window ID (which you can use with selectWindow()) is \"myNewWindow\"</code></p>\n\n<p>In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the \"onLoad\" event, for example).\n(This is bug SEL-339.)  In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using\nan empty (blank) url, like this: openWindow(\"\", \"myFunnyWindow\").</p></comment>\n\n</function>\n\n<function name=\"selectFrame\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> identifying a frame or iframe</param>\n\n<comment>Selects a frame within the current window.  (You may invoke this command\nmultiple times to select nested frames.)  To select the parent frame, use\n\"relative=parent\" as a locator; to select the top frame, use \"relative=top\".\nYou can also select a frame by its 0-based index number; select the first frame with\n\"index=0\", or the third frame with \"index=2\".\n\n<p>You may also use a DOM expression to identify the frame you want directly,\nlike this: <code>dom=frames[\"main\"].frames[\"subframe\"]</code></p></comment>\n\n</function>\n\n<function name=\"getWhetherThisFrameMatchFrameExpression\">\n\n<return type=\"boolean\">true if the new frame is this code's window</return>\n\n<param name=\"currentFrameString\">starting frame</param>\n\n<param name=\"target\">new frame (which might be relative to the current one)</param>\n\n<comment>Determine whether current/locator identify the frame containing this running code.\n\n<p>This is useful in proxy injection mode, where this code runs in every\nbrowser frame and window, and sometimes the selenium server needs to identify\nthe \"current\" frame.  In this case, when the test calls selectFrame, this\nroutine is called for each frame to figure out which one has been selected.\nThe selected frame will return true, while all others will return false.</p></comment>\n\n</function>\n\n<function name=\"getWhetherThisWindowMatchWindowExpression\">\n\n<return type=\"boolean\">true if the new window is this code's window</return>\n\n<param name=\"currentWindowString\">starting window</param>\n\n<param name=\"target\">new window (which might be relative to the current one, e.g., \"_parent\")</param>\n\n<comment>Determine whether currentWindowString plus target identify the window containing this running code.\n\n<p>This is useful in proxy injection mode, where this code runs in every\nbrowser frame and window, and sometimes the selenium server needs to identify\nthe \"current\" window.  In this case, when the test calls selectWindow, this\nroutine is called for each window to figure out which one has been selected.\nThe selected window will return true, while all others will return false.</p></comment>\n\n</function>\n\n<function name=\"waitForPopUp\">\n\n<param name=\"windowID\">the JavaScript window \"name\" of the window that will appear (not the text of the title bar)</param>\n\n<param name=\"timeout\">a timeout in milliseconds, after which the action will return with an error</param>\n\n<comment>Waits for a popup window to appear and load up.</comment>\n\n</function>\n\n<function name=\"chooseCancelOnNextConfirmation\">\n\n<comment><p>\nBy default, Selenium's overridden window.confirm() function will\nreturn true, as if the user had manually clicked OK; after running\nthis command, the next call to confirm() will return false, as if\nthe user had clicked Cancel.  Selenium will then resume using the\ndefault behavior for future confirmations, automatically returning \ntrue (OK) unless/until you explicitly call this command for each\nconfirmation.\n</p>\n<p>\nTake note - every time a confirmation comes up, you must\nconsume it with a corresponding getConfirmation, or else\nthe next selenium operation will fail.\n</p></comment>\n\n</function>\n\n<function name=\"chooseOkOnNextConfirmation\">\n\n<comment><p>\nUndo the effect of calling chooseCancelOnNextConfirmation.  Note\nthat Selenium's overridden window.confirm() function will normally automatically\nreturn true, as if the user had manually clicked OK, so you shouldn't\nneed to use this command unless for some reason you need to change\nyour mind prior to the next confirmation.  After any confirmation, Selenium will resume using the\ndefault behavior for future confirmations, automatically returning \ntrue (OK) unless/until you explicitly call chooseCancelOnNextConfirmation for each\nconfirmation.\n</p>\n<p>\nTake note - every time a confirmation comes up, you must\nconsume it with a corresponding getConfirmation, or else\nthe next selenium operation will fail.\n</p></comment>\n\n</function>\n\n<function name=\"answerOnNextPrompt\">\n\n<param name=\"answer\">the answer to give in response to the prompt pop-up</param>\n\n<comment>Instructs Selenium to return the specified answer string in response to\nthe next JavaScript prompt [window.prompt()].</comment>\n\n</function>\n\n<function name=\"goBack\">\n\n<comment>Simulates the user clicking the \"back\" button on their browser.</comment>\n\n</function>\n\n<function name=\"refresh\">\n\n<comment>Simulates the user clicking the \"Refresh\" button on their browser.</comment>\n\n</function>\n\n<function name=\"close\">\n\n<comment>Simulates the user clicking the \"close\" button in the titlebar of a popup\nwindow or tab.</comment>\n\n</function>\n\n<function name=\"isAlertPresent\">\n\n<return type=\"boolean\">true if there is an alert</return>\n\n<comment>Has an alert occurred?\n\n<p>\nThis function never throws an exception\n</p></comment>\n\n</function>\n\n<function name=\"isPromptPresent\">\n\n<return type=\"boolean\">true if there is a pending prompt</return>\n\n<comment>Has a prompt occurred?\n\n<p>\nThis function never throws an exception\n</p></comment>\n\n</function>\n\n<function name=\"isConfirmationPresent\">\n\n<return type=\"boolean\">true if there is a pending confirmation</return>\n\n<comment>Has confirm() been called?\n\n<p>\nThis function never throws an exception\n</p></comment>\n\n</function>\n\n<function name=\"getAlert\">\n\n<return type=\"string\">The message of the most recent JavaScript alert</return>\n\n<comment>Retrieves the message of a JavaScript alert generated during the previous action, or fail if there were no alerts.\n\n<p>Getting an alert has the same effect as manually clicking OK. If an\nalert is generated but you do not consume it with getAlert, the next Selenium action\nwill fail.</p>\n\n<p>Under Selenium, JavaScript alerts will NOT pop up a visible alert\ndialog.</p>\n\n<p>Selenium does NOT support JavaScript alerts that are generated in a\npage's onload() event handler. In this case a visible dialog WILL be\ngenerated and Selenium will hang until someone manually clicks OK.</p></comment>\n\n</function>\n\n<function name=\"getConfirmation\">\n\n<return type=\"string\">the message of the most recent JavaScript confirmation dialog</return>\n\n<comment>Retrieves the message of a JavaScript confirmation dialog generated during\nthe previous action.\n\n<p>\nBy default, the confirm function will return true, having the same effect\nas manually clicking OK. This can be changed by prior execution of the\nchooseCancelOnNextConfirmation command. \n</p>\n<p>\nIf an confirmation is generated but you do not consume it with getConfirmation,\nthe next Selenium action will fail.\n</p>\n\n<p>\nNOTE: under Selenium, JavaScript confirmations will NOT pop up a visible\ndialog.\n</p>\n\n<p>\nNOTE: Selenium does NOT support JavaScript confirmations that are\ngenerated in a page's onload() event handler. In this case a visible\ndialog WILL be generated and Selenium will hang until you manually click\nOK.\n</p></comment>\n\n</function>\n\n<function name=\"getPrompt\">\n\n<return type=\"string\">the message of the most recent JavaScript question prompt</return>\n\n<comment>Retrieves the message of a JavaScript question prompt dialog generated during\nthe previous action.\n\n<p>Successful handling of the prompt requires prior execution of the\nanswerOnNextPrompt command. If a prompt is generated but you\ndo not get/verify it, the next Selenium action will fail.</p>\n\n<p>NOTE: under Selenium, JavaScript prompts will NOT pop up a visible\ndialog.</p>\n\n<p>NOTE: Selenium does NOT support JavaScript prompts that are generated in a\npage's onload() event handler. In this case a visible dialog WILL be\ngenerated and Selenium will hang until someone manually clicks OK.</p></comment>\n\n</function>\n\n<function name=\"getLocation\">\n\n<return type=\"string\">the absolute URL of the current page</return>\n\n<comment>Gets the absolute URL of the current page.</comment>\n\n</function>\n\n<function name=\"getTitle\">\n\n<return type=\"string\">the title of the current page</return>\n\n<comment>Gets the title of the current page.</comment>\n\n</function>\n\n<function name=\"getBodyText\">\n\n<return type=\"string\">the entire text of the page</return>\n\n<comment>Gets the entire text of the page.</comment>\n\n</function>\n\n<function name=\"getValue\">\n\n<return type=\"string\">the element value, or \"on/off\" for checkbox/radio elements</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Gets the (whitespace-trimmed) value of an input field (or anything else with a value parameter).\nFor checkbox/radio elements, the value will be \"on\" or \"off\" depending on\nwhether the element is checked or not.</comment>\n\n</function>\n\n<function name=\"getText\">\n\n<return type=\"string\">the text of the element</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Gets the text of an element. This works for any element that contains\ntext. This command uses either the textContent (Mozilla-like browsers) or\nthe innerText (IE-like browsers) of the element, which is the rendered\ntext shown to the user.</comment>\n\n</function>\n\n<function name=\"highlight\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Briefly changes the backgroundColor of the specified element yellow.  Useful for debugging.</comment>\n\n</function>\n\n<function name=\"getEval\">\n\n<return type=\"string\">the results of evaluating the snippet</return>\n\n<param name=\"script\">the JavaScript snippet to run</param>\n\n<comment>Gets the result of evaluating the specified JavaScript snippet.  The snippet may\nhave multiple lines, but only the result of the last line will be returned.\n\n<p>Note that, by default, the snippet will run in the context of the \"selenium\"\nobject itself, so <code>this</code> will refer to the Selenium object.  Use <code>window</code> to\nrefer to the window of your application, e.g. <code>window.document.getElementById('foo')</code></p>\n\n<p>If you need to use\na locator to refer to a single element in your application page, you can\nuse <code>this.browserbot.findElement(\"id=foo\")</code> where \"id=foo\" is your locator.</p></comment>\n\n</function>\n\n<function name=\"isChecked\">\n\n<return type=\"boolean\">true if the checkbox is checked, false otherwise</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to a checkbox or radio button</param>\n\n<comment>Gets whether a toggle-button (checkbox/radio) is checked.  Fails if the specified element doesn't exist or isn't a toggle-button.</comment>\n\n</function>\n\n<function name=\"getTable\">\n\n<return type=\"string\">the text from the specified cell</return>\n\n<param name=\"tableCellAddress\">a cell address, e.g. \"foo.1.4\"</param>\n\n<comment>Gets the text from a cell of a table. The cellAddress syntax\ntableLocator.row.column, where row and column start at 0.</comment>\n\n</function>\n\n<function name=\"getSelectedLabels\">\n\n<return type=\"string[]\">an array of all selected option labels in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets all option labels (visible text) for selected options in the specified select or multi-select element.</comment>\n\n</function>\n\n<function name=\"getSelectedLabel\">\n\n<return type=\"string\">the selected option label in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets option label (visible text) for selected option in the specified select element.</comment>\n\n</function>\n\n<function name=\"getSelectedValues\">\n\n<return type=\"string[]\">an array of all selected option values in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets all option values (value attributes) for selected options in the specified select or multi-select element.</comment>\n\n</function>\n\n<function name=\"getSelectedValue\">\n\n<return type=\"string\">the selected option value in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets option value (value attribute) for selected option in the specified select element.</comment>\n\n</function>\n\n<function name=\"getSelectedIndexes\">\n\n<return type=\"string[]\">an array of all selected option indexes in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets all option indexes (option number, starting at 0) for selected options in the specified select or multi-select element.</comment>\n\n</function>\n\n<function name=\"getSelectedIndex\">\n\n<return type=\"string\">the selected option index in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets option index (option number, starting at 0) for selected option in the specified select element.</comment>\n\n</function>\n\n<function name=\"getSelectedIds\">\n\n<return type=\"string[]\">an array of all selected option IDs in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets all option element IDs for selected options in the specified select or multi-select element.</comment>\n\n</function>\n\n<function name=\"getSelectedId\">\n\n<return type=\"string\">the selected option ID in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets option element ID for selected option in the specified select element.</comment>\n\n</function>\n\n<function name=\"isSomethingSelected\">\n\n<return type=\"boolean\">true if some option has been selected, false otherwise</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Determines whether some option in a drop-down menu is selected.</comment>\n\n</function>\n\n<function name=\"getSelectOptions\">\n\n<return type=\"string[]\">an array of all option labels in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets all option labels in the specified select drop-down.</comment>\n\n</function>\n\n<function name=\"getAttribute\">\n\n<return type=\"string\">the value of the specified attribute</return>\n\n<param name=\"attributeLocator\">an element locator followed by an &#064; sign and then the name of the attribute, e.g. \"foo&#064;bar\"</param>\n\n<comment>Gets the value of an element attribute. The value of the attribute may\ndiffer across browsers (this is the case for the \"style\" attribute, for\nexample).</comment>\n\n</function>\n\n<function name=\"isTextPresent\">\n\n<return type=\"boolean\">true if the pattern matches the text, false otherwise</return>\n\n<param name=\"pattern\">a <a href=\"#patterns\">pattern</a> to match with the text of the page</param>\n\n<comment>Verifies that the specified text pattern appears somewhere on the rendered page shown to the user.</comment>\n\n</function>\n\n<function name=\"isElementPresent\">\n\n<return type=\"boolean\">true if the element is present, false otherwise</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Verifies that the specified element is somewhere on the page.</comment>\n\n</function>\n\n<function name=\"isVisible\">\n\n<return type=\"boolean\">true if the specified element is visible, false otherwise</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Determines if the specified element is visible. An\nelement can be rendered invisible by setting the CSS \"visibility\"\nproperty to \"hidden\", or the \"display\" property to \"none\", either for the\nelement itself or one if its ancestors.  This method will fail if\nthe element is not present.</comment>\n\n</function>\n\n<function name=\"isEditable\">\n\n<return type=\"boolean\">true if the input element is editable, false otherwise</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Determines whether the specified input element is editable, ie hasn't been disabled.\nThis method will fail if the specified element isn't an input element.</comment>\n\n</function>\n\n<function name=\"getAllButtons\">\n\n<return type=\"string[]\">the IDs of all buttons on the page</return>\n\n<comment>Returns the IDs of all buttons on the page.\n\n<p>If a given button has no ID, it will appear as \"\" in this array.</p></comment>\n\n</function>\n\n<function name=\"getAllLinks\">\n\n<return type=\"string[]\">the IDs of all links on the page</return>\n\n<comment>Returns the IDs of all links on the page.\n\n<p>If a given link has no ID, it will appear as \"\" in this array.</p></comment>\n\n</function>\n\n<function name=\"getAllFields\">\n\n<return type=\"string[]\">the IDs of all field on the page</return>\n\n<comment>Returns the IDs of all input fields on the page.\n\n<p>If a given field has no ID, it will appear as \"\" in this array.</p></comment>\n\n</function>\n\n<function name=\"getAttributeFromAllWindows\">\n\n<return type=\"string[]\">the set of values of this attribute from all known windows.</return>\n\n<param name=\"attributeName\">name of an attribute on the windows</param>\n\n<comment>Returns every instance of some attribute from all known windows.</comment>\n\n</function>\n\n<function name=\"dragdrop\">\n\n<param name=\"locator\">an element locator</param>\n\n<param name=\"movementsString\">offset in pixels from the current location to which the element should be moved, e.g., \"+70,-300\"</param>\n\n<comment>deprecated - use dragAndDrop instead</comment>\n\n</function>\n\n<function name=\"setMouseSpeed\">\n\n<param name=\"pixels\">the number of pixels between \"mousemove\" events</param>\n\n<comment>Configure the number of pixels between \"mousemove\" events during dragAndDrop commands (default=10).\n<p>Setting this value to 0 means that we'll send a \"mousemove\" event to every single pixel\nin between the start location and the end location; that can be very slow, and may\ncause some browsers to force the JavaScript to timeout.</p>\n\n<p>If the mouse speed is greater than the distance between the two dragged objects, we'll\njust send one \"mousemove\" at the start location and then one final one at the end location.</p></comment>\n\n</function>\n\n<function name=\"getMouseSpeed\">\n\n<return type=\"number\">the number of pixels between \"mousemove\" events during dragAndDrop commands (default=10)</return>\n\n<comment>Returns the number of pixels between \"mousemove\" events during dragAndDrop commands (default=10).</comment>\n\n</function>\n\n<function name=\"dragAndDrop\">\n\n<param name=\"locator\">an element locator</param>\n\n<param name=\"movementsString\">offset in pixels from the current location to which the element should be moved, e.g., \"+70,-300\"</param>\n\n<comment>Drags an element a certain distance and then drops it</comment>\n\n</function>\n\n<function name=\"dragAndDropToObject\">\n\n<param name=\"locatorOfObjectToBeDragged\">an element to be dragged</param>\n\n<param name=\"locatorOfDragDestinationObject\">an element whose location (i.e., whose center-most pixel) will be the point where locatorOfObjectToBeDragged  is dropped</param>\n\n<comment>Drags an element and drops it on another element</comment>\n\n</function>\n\n<function name=\"windowFocus\">\n\n<comment>Gives focus to the currently selected window</comment>\n\n</function>\n\n<function name=\"windowMaximize\">\n\n<comment>Resize currently selected window to take up the entire screen</comment>\n\n</function>\n\n<function name=\"getAllWindowIds\">\n\n<return type=\"string[]\">the IDs of all windows that the browser knows about.</return>\n\n<comment>Returns the IDs of all windows that the browser knows about.</comment>\n\n</function>\n\n<function name=\"getAllWindowNames\">\n\n<return type=\"string[]\">the names of all windows that the browser knows about.</return>\n\n<comment>Returns the names of all windows that the browser knows about.</comment>\n\n</function>\n\n<function name=\"getAllWindowTitles\">\n\n<return type=\"string[]\">the titles of all windows that the browser knows about.</return>\n\n<comment>Returns the titles of all windows that the browser knows about.</comment>\n\n</function>\n\n<function name=\"getHtmlSource\">\n\n<return type=\"string\">the entire HTML source</return>\n\n<comment>Returns the entire HTML source between the opening and\nclosing \"html\" tags.</comment>\n\n</function>\n\n<function name=\"setCursorPosition\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an input element or textarea</param>\n\n<param name=\"position\">the numerical position of the cursor in the field; position should be 0 to move the position to the beginning of the field.  You can also set the cursor to -1 to move it to the end of the field.</param>\n\n<comment>Moves the text cursor to the specified position in the given input element or textarea.\nThis method will fail if the specified element isn't an input element or textarea.</comment>\n\n</function>\n\n<function name=\"getElementIndex\">\n\n<return type=\"number\">of relative index of the element to its parent (starting from 0)</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element</param>\n\n<comment>Get the relative index of an element to its parent (starting from 0). The comment node and empty text node\nwill be ignored.</comment>\n\n</function>\n\n<function name=\"isOrdered\">\n\n<return type=\"boolean\">true if element1 is the previous sibling of element2, false otherwise</return>\n\n<param name=\"locator1\">an <a href=\"#locators\">element locator</a> pointing to the first element</param>\n\n<param name=\"locator2\">an <a href=\"#locators\">element locator</a> pointing to the second element</param>\n\n<comment>Check if these two elements have same parent and are ordered siblings in the DOM. Two same elements will\nnot be considered ordered.</comment>\n\n</function>\n\n<function name=\"getElementPositionLeft\">\n\n<return type=\"number\">of pixels from the edge of the frame.</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element OR an element itself</param>\n\n<comment>Retrieves the horizontal position of an element</comment>\n\n</function>\n\n<function name=\"getElementPositionTop\">\n\n<return type=\"number\">of pixels from the edge of the frame.</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element OR an element itself</param>\n\n<comment>Retrieves the vertical position of an element</comment>\n\n</function>\n\n<function name=\"getElementWidth\">\n\n<return type=\"number\">width of an element in pixels</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element</param>\n\n<comment>Retrieves the width of an element</comment>\n\n</function>\n\n<function name=\"getElementHeight\">\n\n<return type=\"number\">height of an element in pixels</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element</param>\n\n<comment>Retrieves the height of an element</comment>\n\n</function>\n\n<function name=\"getCursorPosition\">\n\n<return type=\"number\">the numerical position of the cursor in the field</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an input element or textarea</param>\n\n<comment>Retrieves the text cursor position in the given input element or textarea; beware, this may not work perfectly on all browsers.\n\n<p>Specifically, if the cursor/selection has been cleared by JavaScript, this command will tend to\nreturn the position of the last location of the cursor, even though the cursor is now gone from the page.  This is filed as <a href=\"http://jira.openqa.org/browse/SEL-243\">SEL-243</a>.</p>\nThis method will fail if the specified element isn't an input element or textarea, or there is no cursor in the element.</comment>\n\n</function>\n\n<function name=\"getExpression\">\n\n<return type=\"string\">the value passed in</return>\n\n<param name=\"expression\">the value to return</param>\n\n<comment>Returns the specified expression.\n\n<p>This is useful because of JavaScript preprocessing.\nIt is used to generate commands like assertExpression and waitForExpression.</p></comment>\n\n</function>\n\n<function name=\"getXpathCount\">\n\n<return type=\"number\">the number of nodes that match the specified xpath</return>\n\n<param name=\"xpath\">the xpath expression to evaluate. do NOT wrap this expression in a 'count()' function; we will do that for you.</param>\n\n<comment>Returns the number of nodes that match the specified xpath, eg. \"//table\" would give\nthe number of tables.</comment>\n\n</function>\n\n<function name=\"assignId\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element</param>\n\n<param name=\"identifier\">a string to be used as the ID of the specified element</param>\n\n<comment>Temporarily sets the \"id\" attribute of the specified element, so you can locate it in the future\nusing its ID rather than a slow/complicated XPath.  This ID will disappear once the page is\nreloaded.</comment>\n\n</function>\n\n<function name=\"allowNativeXpath\">\n\n<param name=\"allow\">boolean, true means we'll prefer to use native XPath; false means we'll only use JS XPath</param>\n\n<comment>Specifies whether Selenium should use the native in-browser implementation\nof XPath (if any native version is available); if you pass \"false\" to\nthis function, we will always use our pure-JavaScript xpath library.\nUsing the pure-JS xpath library can improve the consistency of xpath\nelement locators between different browser vendors, but the pure-JS\nversion is much slower than the native implementations.</comment>\n\n</function>\n\n<function name=\"ignoreAttributesWithoutValue\">\n\n<param name=\"ignore\">boolean, true means we'll ignore attributes without value                        at the expense of xpath \"correctness\"; false means                        we'll sacrifice speed for correctness.</param>\n\n<comment>Specifies whether Selenium will ignore xpath attributes that have no\nvalue, i.e. are the empty string, when using the non-native xpath\nevaluation engine. You'd want to do this for performance reasons in IE.\nHowever, this could break certain xpaths, for example an xpath that looks\nfor an attribute whose value is NOT the empty string.\n\nThe hope is that such xpaths are relatively rare, but the user should\nhave the option of using them. Note that this only influences xpath\nevaluation when using the ajaxslt engine (i.e. not \"javascript-xpath\").</comment>\n\n</function>\n\n<function name=\"waitForCondition\">\n\n<param name=\"script\">the JavaScript snippet to run</param>\n\n<param name=\"timeout\">a timeout in milliseconds, after which this command will return with an error</param>\n\n<comment>Runs the specified JavaScript snippet repeatedly until it evaluates to \"true\".\nThe snippet may have multiple lines, but only the result of the last line\nwill be considered.\n\n<p>Note that, by default, the snippet will be run in the runner's test window, not in the window\nof your application.  To get the window of your application, you can use\nthe JavaScript snippet <code>selenium.browserbot.getCurrentWindow()</code>, and then\nrun your JavaScript in there</p></comment>\n\n</function>\n\n<function name=\"setTimeout\">\n\n<param name=\"timeout\">a timeout in milliseconds, after which the action will return with an error</param>\n\n<comment>Specifies the amount of time that Selenium will wait for actions to complete.\n\n<p>Actions that require waiting include \"open\" and the \"waitFor*\" actions.</p>\nThe default timeout is 30 seconds.</comment>\n\n</function>\n\n<function name=\"waitForPageToLoad\">\n\n<param name=\"timeout\">a timeout in milliseconds, after which this command will return with an error</param>\n\n<comment>Waits for a new page to load.\n\n<p>You can use this command instead of the \"AndWait\" suffixes, \"clickAndWait\", \"selectAndWait\", \"typeAndWait\" etc.\n(which are only available in the JS API).</p>\n\n<p>Selenium constantly keeps track of new pages loading, and sets a \"newPageLoaded\"\nflag when it first notices a page load.  Running any other Selenium command after\nturns the flag to false.  Hence, if you want to wait for a page to load, you must\nwait immediately after a Selenium command that caused a page-load.</p></comment>\n\n</function>\n\n<function name=\"waitForFrameToLoad\">\n\n<param name=\"frameAddress\">FrameAddress from the server side</param>\n\n<param name=\"timeout\">a timeout in milliseconds, after which this command will return with an error</param>\n\n<comment>Waits for a new frame to load.\n\n<p>Selenium constantly keeps track of new pages and frames loading, \nand sets a \"newPageLoaded\" flag when it first notices a page load.</p>\n\nSee waitForPageToLoad for more information.</comment>\n\n</function>\n\n<function name=\"getCookie\">\n\n<return type=\"string\">all cookies of the current page under test</return>\n\n<comment>Return all cookies of the current page under test.</comment>\n\n</function>\n\n<function name=\"getCookieByName\">\n\n<return type=\"string\">the value of the cookie</return>\n\n<param name=\"name\">the name of the cookie</param>\n\n<comment>Returns the value of the cookie with the specified name, or throws an error if the cookie is not present.</comment>\n\n</function>\n\n<function name=\"isCookiePresent\">\n\n<return type=\"boolean\">true if a cookie with the specified name is present, or false otherwise.</return>\n\n<param name=\"name\">the name of the cookie</param>\n\n<comment>Returns true if a cookie with the specified name is present, or false otherwise.</comment>\n\n</function>\n\n<function name=\"createCookie\">\n\n<param name=\"nameValuePair\">name and value of the cookie in a format \"name=value\"</param>\n\n<param name=\"optionsString\">options for the cookie. Currently supported options include 'path', 'max_age' and 'domain'.      the optionsString's format is \"path=/path/, max_age=60, domain=.foo.com\". The order of options are irrelevant, the unit      of the value of 'max_age' is second.  Note that specifying a domain that isn't a subset of the current domain will      usually fail.</param>\n\n<comment>Create a new cookie whose path and domain are same with those of current page\nunder test, unless you specified a path for this cookie explicitly.</comment>\n\n</function>\n\n<function name=\"deleteCookie\">\n\n<param name=\"name\">the name of the cookie to be deleted</param>\n\n<param name=\"optionsString\">options for the cookie. Currently supported options include 'path', 'domain'      and 'recurse.' The optionsString's format is \"path=/path/, domain=.foo.com, recurse=true\".      The order of options are irrelevant. Note that specifying a domain that isn't a subset of      the current domain will usually fail.</param>\n\n<comment>Delete a named cookie with specified path and domain.  Be careful; to delete a cookie, you\nneed to delete it using the exact same path and domain that were used to create the cookie.\nIf the path is wrong, or the domain is wrong, the cookie simply won't be deleted.  Also\nnote that specifying a domain that isn't a subset of the current domain will usually fail.\n\nSince there's no way to discover at runtime the original path and domain of a given cookie,\nwe've added an option called 'recurse' to try all sub-domains of the current domain with\nall paths that are a subset of the current path.  Beware; this option can be slow.  In\nbig-O notation, it operates in O(n*m) time, where n is the number of dots in the domain\nname and m is the number of slashes in the path.</comment>\n\n</function>\n\n<function name=\"deleteAllVisibleCookies\">\n\n<comment>Calls deleteCookie with recurse=true on all cookies visible to the current page.\nAs noted on the documentation for deleteCookie, recurse=true can be much slower\nthan simply deleting the cookies using a known domain/path.</comment>\n\n</function>\n\n<function name=\"setBrowserLogLevel\">\n\n<param name=\"logLevel\">one of the following: \"debug\", \"info\", \"warn\", \"error\" or \"off\"</param>\n\n<comment>Sets the threshold for browser-side logging messages; log messages beneath this threshold will be discarded.\nValid logLevel strings are: \"debug\", \"info\", \"warn\", \"error\" or \"off\".\nTo see the browser logs, you need to\neither show the log window in GUI mode, or enable browser-side logging in Selenium RC.</comment>\n\n</function>\n\n<function name=\"runScript\">\n\n<param name=\"script\">the JavaScript snippet to run</param>\n\n<comment>Creates a new \"script\" tag in the body of the current test window, and \nadds the specified text into the body of the command.  Scripts run in\nthis way can often be debugged more easily than scripts executed using\nSelenium's \"getEval\" command.  Beware that JS exceptions thrown in these script\ntags aren't managed by Selenium, so you should probably wrap your script\nin try/catch blocks if there is any chance that the script will throw\nan exception.</comment>\n\n</function>\n\n<function name=\"addLocationStrategy\">\n\n<param name=\"strategyName\">the name of the strategy to define; this should use only   letters [a-zA-Z] with no spaces or other punctuation.</param>\n\n<param name=\"functionDefinition\">a string defining the body of a function in JavaScript.   For example: <code>return inDocument.getElementById(locator);</code></param>\n\n<comment>Defines a new function for Selenium to locate elements on the page.\nFor example,\nif you define the strategy \"foo\", and someone runs click(\"foo=blah\"), we'll\nrun your function, passing you the string \"blah\", and click on the element \nthat your function\nreturns, or throw an \"Element not found\" error if your function returns null.\n\nWe'll pass three arguments to your function:\n<ul>\n<li>locator: the string the user passed in</li>\n<li>inWindow: the currently selected window</li>\n<li>inDocument: the currently selected document</li>\n</ul>\nThe function must return null if the element can't be found.</comment>\n\n</function>\n\n<function name=\"captureEntirePageScreenshot\">\n\n<param name=\"filename\">the path to the file to persist the screenshot as. No                  filename extension will be appended by default.                  Directories will not be created if they do not exist,                    and an exception will be thrown, possibly by native                  code.</param>\n\n<param name=\"kwargs\">a kwargs string that modifies the way the screenshot                  is captured. Example: \"background=#CCFFDD\" .                  Currently valid options:                  <dl>                   <dt>background</dt>                     <dd>the background CSS for the HTML document. This                     may be useful to set for capturing screenshots of                     less-than-ideal layouts, for example where absolute                     positioning causes the calculation of the canvas                     dimension to fail and a black background is exposed                     (possibly obscuring black text).</dd>                  </dl></param>\n\n<comment>Saves the entire contents of the current window canvas to a PNG file.\nContrast this with the captureScreenshot command, which captures the\ncontents of the OS viewport (i.e. whatever is currently being displayed\non the monitor), and is implemented in the RC only. Currently this only\nworks in Firefox when running in chrome mode, and in IE non-HTA using\nthe EXPERIMENTAL \"Snapsie\" utility. The Firefox implementation is mostly\nborrowed from the Screengrab! Firefox extension. Please see\nhttp://www.screengrab.org and http://snapsie.sourceforge.net/ for\ndetails.</comment>\n\n</function>\n\n<function name=\"rollup\">\n\n<param name=\"rollupName\">the name of the rollup command</param>\n\n<param name=\"kwargs\">keyword arguments string that influences how the                    rollup expands into commands</param>\n\n<comment>Executes a command rollup, which is a series of commands with a unique\nname, and optionally arguments that control the generation of the set of\ncommands. If any one of the rolled-up commands fails, the rollup is\nconsidered to have failed. Rollups may also contain nested rollups.</comment>\n\n</function>\n\n<function name=\"addScript\">\n\n<param name=\"scriptContent\">the Javascript content of the script to add</param>\n\n<param name=\"scriptTagId\">(optional) the id of the new script tag. If                       specified, and an element with this id already                       exists, this operation will fail.</param>\n\n<comment>Loads script content into a new script tag in the Selenium document. This\ndiffers from the runScript command in that runScript adds the script tag\nto the document of the AUT, not the Selenium document. The following\nentities in the script content are replaced by the characters they\nrepresent:\n\n    &lt;\n    &gt;\n    &amp;\n\nThe corresponding remove command is removeScript.</comment>\n\n</function>\n\n<function name=\"removeScript\">\n\n<param name=\"scriptTagId\">the id of the script element to remove.</param>\n\n<comment>Removes a script tag from the Selenium document identified by the given\nid. Does nothing if the referenced tag doesn't exist.</comment>\n\n</function>\n\n<function name=\"useXpathLibrary\">\n\n<param name=\"libraryName\">name of the desired library Only the following three can be chosen:   ajaxslt - Google's library   javascript - Cybozu Labs' faster library   default - The default library.  Currently the default library is ajaxslt. If libraryName isn't one of these three, then  no change will be made.</param>\n\n<comment>Allows choice of one of the available libraries.</comment>\n\n</function>\n\n<function name=\"pause\">\n\n<param name=\"waitTime\">the amount of time to sleep (in milliseconds)</param>\n\n<comment>Wait for the specified amount of time (in milliseconds)</comment>\n\n</function>\n\n<function name=\"break\">\n\n<comment>Halt the currently running test, and wait for the user to press the Continue button.\nThis command is useful for debugging, but be careful when using it, because it will\nforce automated tests to hang until a user intervenes manually.</comment>\n\n</function>\n\n<function name=\"store\">\n\n<param name=\"expression\">the value to store</param>\n\n<param name=\"variableName\">the name of a <a href=\"#storedVars\">variable</a> in which the result is to be stored.</param>\n\n<comment>This command is a synonym for storeExpression.</comment>\n\n</function>\n\n<function name=\"echo\">\n\n<param name=\"message\">the message to print</param>\n\n<comment>Prints the specified message into the third table cell in your Selenese tables.\nUseful for debugging.</comment>\n\n</function>\n\n<function name=\"assertSelected\">\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<param name=\"optionLocator\">an option locator, typically just an option label (e.g. \"John Smith\")</param>\n\n<comment>Verifies that the selected option of a drop-down satisfies the optionSpecifier.  <i>Note that this command is deprecated; you should use assertSelectedLabel, assertSelectedValue, assertSelectedIndex, or assertSelectedId instead.</i>\n\n<p>See the select command for more information about option locators.</p></comment>\n\n</function>\n\n<function name=\"assertFailureOnNext\">\n\n<param name=\"message\">The failure message we should expect.  This command will fail if the wrong failure message appears.</param>\n\n<comment>Tell Selenium to expect a failure on the next command execution.</comment>\n\n</function>\n\n<function name=\"assertErrorOnNext\">\n\n<param name=\"message\">The error message we should expect.  This command will fail if the wrong error message appears.</param>\n\n<comment>Tell Selenium to expect an error on the next command execution.</comment>\n\n</function>\n\n</apidoc>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/iedoc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<apidoc>\n\n<top>Defines an object that runs Selenium commands.\n\n<h3><a name=\"locators\"></a>Element Locators</h3>\n<p>\nElement Locators tell Selenium which HTML element a command refers to.\nThe format of a locator is:</p>\n<blockquote>\n<em>locatorType</em><strong>=</strong><em>argument</em>\n</blockquote>\n\n<p>\nWe support the following strategies for locating elements:\n</p>\n\n<ul>\n<li><strong>identifier</strong>=<em>id</em>: \nSelect the element with the specified &#064;id attribute. If no match is\nfound, select the first element whose &#064;name attribute is <em>id</em>.\n(This is normally the default; see below.)</li>\n<li><strong>id</strong>=<em>id</em>:\nSelect the element with the specified &#064;id attribute.</li>\n\n<li><strong>name</strong>=<em>name</em>:\nSelect the first element with the specified &#064;name attribute.\n<ul class=\"first last simple\">\n<li>username</li>\n<li>name=username</li>\n</ul>\n\n<p>The name may optionally be followed by one or more <em>element-filters</em>, separated from the name by whitespace.  If the <em>filterType</em> is not specified, <strong>value</strong> is assumed.</p>\n\n<ul class=\"first last simple\">\n<li>name=flavour value=chocolate</li>\n</ul>\n</li>\n<li><strong>dom</strong>=<em>javascriptExpression</em>: \n\nFind an element by evaluating the specified string.  This allows you to traverse the HTML Document Object\nModel using JavaScript.  Note that you must not return a value in this string; simply make it the last expression in the block.\n<ul class=\"first last simple\">\n<li>dom=document.forms['myForm'].myDropdown</li>\n<li>dom=document.images[56]</li>\n<li>dom=function foo() { return document.links[1]; }; foo();</li>\n</ul>\n\n</li>\n\n<li><strong>xpath</strong>=<em>xpathExpression</em>: \nLocate an element using an XPath expression.\n<ul class=\"first last simple\">\n<li>xpath=//img[&#064;alt='The image alt text']</li>\n<li>xpath=//table[&#064;id='table1']//tr[4]/td[2]</li>\n<li>xpath=//a[contains(&#064;href,'#id1')]</li>\n<li>xpath=//a[contains(&#064;href,'#id1')]/&#064;class</li>\n<li>xpath=(//table[&#064;class='stylee'])//th[text()='theHeaderText']/../td</li>\n<li>xpath=//input[&#064;name='name2' and &#064;value='yes']</li>\n<li>xpath=//*[text()=\"right\"]</li>\n\n</ul>\n</li>\n<li><strong>link</strong>=<em>textPattern</em>:\nSelect the link (anchor) element which contains text matching the\nspecified <em>pattern</em>.\n<ul class=\"first last simple\">\n<li>link=The link text</li>\n</ul>\n\n</li>\n\n<li><strong>css</strong>=<em>cssSelectorSyntax</em>:\nSelect the element using css selectors. Please refer to <a href=\"http://www.w3.org/TR/REC-CSS2/selector.html\">CSS2 selectors</a>, <a href=\"http://www.w3.org/TR/2001/CR-css3-selectors-20011113/\">CSS3 selectors</a> for more information. You can also check the TestCssLocators test in the selenium test suite for an example of usage, which is included in the downloaded selenium core package.\n<ul class=\"first last simple\">\n<li>css=a[href=\"#id3\"]</li>\n<li>css=span#firstChild + span</li>\n</ul>\n<p>Currently the css selector locator supports all css1, css2 and css3 selectors except namespace in css3, some pseudo classes(:nth-of-type, :nth-last-of-type, :first-of-type, :last-of-type, :only-of-type, :visited, :hover, :active, :focus, :indeterminate) and pseudo elements(::first-line, ::first-letter, ::selection, ::before, ::after). </p>\n</li>\n\n<li><strong>ui</strong>=<em>uiSpecifierString</em>:\nLocate an element by resolving the UI specifier string to another locator, and evaluating it. See the <a href=\"http://svn.openqa.org/fisheye/browse/~raw,r=trunk/selenium/trunk/src/main/resources/core/scripts/ui-doc.html\">Selenium UI-Element Reference</a> for more details.\n<ul class=\"first last simple\">\n<li>ui=loginPages::loginButton()</li>\n<li>ui=settingsPages::toggle(label=Hide Email)</li>\n<li>ui=forumPages::postBody(index=2)//a[2]</li>\n</ul>\n</li>\n\n</ul>\n\n<p>\nWithout an explicit locator prefix, Selenium uses the following default\nstrategies:\n</p>\n\n<ul class=\"simple\">\n<li><strong>dom</strong>, for locators starting with &quot;document.&quot;</li>\n<li><strong>xpath</strong>, for locators starting with &quot;//&quot;</li>\n<li><strong>identifier</strong>, otherwise</li>\n</ul>\n\n<h3><a name=\"element-filters\">Element Filters</a></h3>\n<blockquote>\n<p>Element filters can be used with a locator to refine a list of candidate elements.  They are currently used only in the 'name' element-locator.</p>\n<p>Filters look much like locators, ie.</p>\n<blockquote>\n<em>filterType</em><strong>=</strong><em>argument</em></blockquote>\n\n<p>Supported element-filters are:</p>\n<p><strong>value=</strong><em>valuePattern</em></p>\n<blockquote>\nMatches elements based on their values.  This is particularly useful for refining a list of similarly-named toggle-buttons.</blockquote>\n<p><strong>index=</strong><em>index</em></p>\n<blockquote>\nSelects a single element based on its position in the list (offset from zero).</blockquote>\n</blockquote>\n\n<h3><a name=\"patterns\"></a>String-match Patterns</h3>\n\n<p>\nVarious Pattern syntaxes are available for matching string values:\n</p>\n<ul>\n<li><strong>glob:</strong><em>pattern</em>:\nMatch a string against a \"glob\" (aka \"wildmat\") pattern. \"Glob\" is a\nkind of limited regular-expression syntax typically used in command-line\nshells. In a glob pattern, \"*\" represents any sequence of characters, and \"?\"\nrepresents any single character. Glob patterns match against the entire\nstring.</li>\n<li><strong>regexp:</strong><em>regexp</em>:\nMatch a string using a regular-expression. The full power of JavaScript\nregular-expressions is available.</li>\n<li><strong>regexpi:</strong><em>regexpi</em>:\nMatch a string using a case-insensitive regular-expression.</li>\n<li><strong>exact:</strong><em>string</em>:\n\nMatch a string exactly, verbatim, without any of that fancy wildcard\nstuff.</li>\n</ul>\n<p>\nIf no pattern prefix is specified, Selenium assumes that it's a \"glob\"\npattern.\n</p>\n<p>\nFor commands that return multiple values (such as verifySelectOptions),\nthe string being matched is a comma-separated list of the return values,\nwhere both commas and backslashes in the values are backslash-escaped.\nWhen providing a pattern, the optional matching syntax (i.e. glob,\nregexp, etc.) is specified once, as usual, at the beginning of the\npattern.\n</p></top>\n\n<function name=\"click\">\n\n<param name=\"locator\">an element locator</param>\n\n<comment>Clicks on a link, button, checkbox or radio button. If the click action\ncauses a new page to load (like a link usually does), call\nwaitForPageToLoad.</comment>\n\n</function>\n\n<function name=\"doubleClick\">\n\n<param name=\"locator\">an element locator</param>\n\n<comment>Double clicks on a link, button, checkbox or radio button. If the double click action\ncauses a new page to load (like a link usually does), call\nwaitForPageToLoad.</comment>\n\n</function>\n\n<function name=\"contextMenu\">\n\n<param name=\"locator\">an element locator</param>\n\n<comment>Simulates opening the context menu for the specified element (as might happen if the user \"right-clicked\" on the element).</comment>\n\n</function>\n\n<function name=\"clickAt\">\n\n<param name=\"locator\">an element locator</param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Clicks on a link, button, checkbox or radio button. If the click action\ncauses a new page to load (like a link usually does), call\nwaitForPageToLoad.</comment>\n\n</function>\n\n<function name=\"doubleClickAt\">\n\n<param name=\"locator\">an element locator</param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Doubleclicks on a link, button, checkbox or radio button. If the action\ncauses a new page to load (like a link usually does), call\nwaitForPageToLoad.</comment>\n\n</function>\n\n<function name=\"contextMenuAt\">\n\n<param name=\"locator\">an element locator</param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates opening the context menu for the specified element (as might happen if the user \"right-clicked\" on the element).</comment>\n\n</function>\n\n<function name=\"fireEvent\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"eventName\">the event name, e.g. \"focus\" or \"blur\"</param>\n\n<comment>Explicitly simulate an event, to trigger the corresponding &quot;on<em>event</em>&quot;\nhandler.</comment>\n\n</function>\n\n<function name=\"focus\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Move the focus to the specified element; for example, if the element is an input field, move the cursor to that field.</comment>\n\n</function>\n\n<function name=\"keyPress\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"keySequence\">Either be a string(\"\\\" followed by the numeric keycode  of the key to be pressed, normally the ASCII value of that key), or a single  character. For example: \"w\", \"\\119\".</param>\n\n<comment>Simulates a user pressing and releasing a key.</comment>\n\n</function>\n\n<function name=\"shiftKeyDown\">\n\n<comment>Press the shift key and hold it down until doShiftUp() is called or a new page is loaded.</comment>\n\n</function>\n\n<function name=\"shiftKeyUp\">\n\n<comment>Release the shift key.</comment>\n\n</function>\n\n<function name=\"metaKeyDown\">\n\n<comment>Press the meta key and hold it down until doMetaUp() is called or a new page is loaded.</comment>\n\n</function>\n\n<function name=\"metaKeyUp\">\n\n<comment>Release the meta key.</comment>\n\n</function>\n\n<function name=\"altKeyDown\">\n\n<comment>Press the alt key and hold it down until doAltUp() is called or a new page is loaded.</comment>\n\n</function>\n\n<function name=\"altKeyUp\">\n\n<comment>Release the alt key.</comment>\n\n</function>\n\n<function name=\"controlKeyDown\">\n\n<comment>Press the control key and hold it down until doControlUp() is called or a new page is loaded.</comment>\n\n</function>\n\n<function name=\"controlKeyUp\">\n\n<comment>Release the control key.</comment>\n\n</function>\n\n<function name=\"keyDown\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"keySequence\">Either be a string(\"\\\" followed by the numeric keycode  of the key to be pressed, normally the ASCII value of that key), or a single  character. For example: \"w\", \"\\119\".</param>\n\n<comment>Simulates a user pressing a key (without releasing it yet).</comment>\n\n</function>\n\n<function name=\"keyUp\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"keySequence\">Either be a string(\"\\\" followed by the numeric keycode  of the key to be pressed, normally the ASCII value of that key), or a single  character. For example: \"w\", \"\\119\".</param>\n\n<comment>Simulates a user releasing a key.</comment>\n\n</function>\n\n<function name=\"mouseOver\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates a user hovering a mouse over the specified element.</comment>\n\n</function>\n\n<function name=\"mouseOut\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates a user moving the mouse pointer away from the specified element.</comment>\n\n</function>\n\n<function name=\"mouseDown\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates a user pressing the left mouse button (without releasing it yet) on\nthe specified element.</comment>\n\n</function>\n\n<function name=\"mouseDownRight\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates a user pressing the right mouse button (without releasing it yet) on\nthe specified element.</comment>\n\n</function>\n\n<function name=\"mouseDownAt\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates a user pressing the left mouse button (without releasing it yet) at\nthe specified location.</comment>\n\n</function>\n\n<function name=\"mouseDownRightAt\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates a user pressing the right mouse button (without releasing it yet) at\nthe specified location.</comment>\n\n</function>\n\n<function name=\"mouseUp\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates the event that occurs when the user releases the mouse button (i.e., stops\nholding the button down) on the specified element.</comment>\n\n</function>\n\n<function name=\"mouseUpRight\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates the event that occurs when the user releases the right mouse button (i.e., stops\nholding the button down) on the specified element.</comment>\n\n</function>\n\n<function name=\"mouseUpAt\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates the event that occurs when the user releases the mouse button (i.e., stops\nholding the button down) at the specified location.</comment>\n\n</function>\n\n<function name=\"mouseUpRightAt\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates the event that occurs when the user releases the right mouse button (i.e., stops\nholding the button down) at the specified location.</comment>\n\n</function>\n\n<function name=\"mouseMove\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Simulates a user pressing the mouse button (without releasing it yet) on\nthe specified element.</comment>\n\n</function>\n\n<function name=\"mouseMoveAt\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"coordString\">specifies the x,y position (i.e. - 10,20) of the mouse      event relative to the element returned by the locator.</param>\n\n<comment>Simulates a user pressing the mouse button (without releasing it yet) on\nthe specified element.</comment>\n\n</function>\n\n<function name=\"type\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"value\">the value to type</param>\n\n<comment>Sets the value of an input field, as though you typed it in.\n\n<p>Can also be used to set the value of combo boxes, check boxes, etc. In these cases,\nvalue should be the value of the option selected, not the visible text.</p></comment>\n\n</function>\n\n<function name=\"typeKeys\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"value\">the value to type</param>\n\n<comment>Simulates keystroke events on the specified element, as though you typed the value key-by-key.\n\n<p>This is a convenience method for calling keyDown, keyUp, keyPress for every character in the specified string;\nthis is useful for dynamic UI widgets (like auto-completing combo boxes) that require explicit key events.</p>\n\n<p>Unlike the simple \"type\" command, which forces the specified value into the page directly, this command\nmay or may not have any visible effect, even in cases where typing keys would normally have a visible effect.\nFor example, if you use \"typeKeys\" on a form element, you may or may not see the results of what you typed in\nthe field.</p>\n<p>In some cases, you may need to use the simple \"type\" command to set the value of the field and then the \"typeKeys\" command to\nsend the keystroke events corresponding to what you just typed.</p></comment>\n\n</function>\n\n<function name=\"setSpeed\">\n\n<param name=\"value\">the number of milliseconds to pause after operation</param>\n\n<comment>Set execution speed (i.e., set the millisecond length of a delay which will follow each selenium operation).  By default, there is no such delay, i.e.,\nthe delay is 0 milliseconds.</comment>\n\n</function>\n\n<function name=\"getSpeed\">\n\n<return type=\"string\">the execution speed in milliseconds.</return>\n\n<comment>Get execution speed (i.e., get the millisecond length of the delay following each selenium operation).  By default, there is no such delay, i.e.,\nthe delay is 0 milliseconds.\n\nSee also setSpeed.</comment>\n\n</function>\n\n<function name=\"check\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Check a toggle-button (checkbox/radio)</comment>\n\n</function>\n\n<function name=\"uncheck\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Uncheck a toggle-button (checkbox/radio)</comment>\n\n</function>\n\n<function name=\"select\">\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<param name=\"optionLocator\">an option locator (a label by default)</param>\n\n<comment>Select an option from a drop-down using an option locator.\n\n<p>\nOption locators provide different ways of specifying options of an HTML\nSelect element (e.g. for selecting a specific option, or for asserting\nthat the selected option satisfies a specification). There are several\nforms of Select Option Locator.\n</p>\n<ul>\n<li><strong>label</strong>=<em>labelPattern</em>:\nmatches options based on their labels, i.e. the visible text. (This\nis the default.)\n<ul class=\"first last simple\">\n<li>label=regexp:^[Oo]ther</li>\n</ul>\n</li>\n<li><strong>value</strong>=<em>valuePattern</em>:\nmatches options based on their values.\n<ul class=\"first last simple\">\n<li>value=other</li>\n</ul>\n\n\n</li>\n<li><strong>id</strong>=<em>id</em>:\n\nmatches options based on their ids.\n<ul class=\"first last simple\">\n<li>id=option1</li>\n</ul>\n</li>\n<li><strong>index</strong>=<em>index</em>:\nmatches an option based on its index (offset from zero).\n<ul class=\"first last simple\">\n\n<li>index=2</li>\n</ul>\n</li>\n</ul>\n<p>\nIf no option locator prefix is provided, the default behaviour is to match on <strong>label</strong>.\n</p></comment>\n\n</function>\n\n<function name=\"addSelection\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> identifying a multi-select box</param>\n\n<param name=\"optionLocator\">an option locator (a label by default)</param>\n\n<comment>Add a selection to the set of selected options in a multi-select element using an option locator.\n\n@see #doSelect for details of option locators</comment>\n\n</function>\n\n<function name=\"removeSelection\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> identifying a multi-select box</param>\n\n<param name=\"optionLocator\">an option locator (a label by default)</param>\n\n<comment>Remove a selection from the set of selected options in a multi-select element using an option locator.\n\n@see #doSelect for details of option locators</comment>\n\n</function>\n\n<function name=\"removeAllSelections\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> identifying a multi-select box</param>\n\n<comment>Unselects all of the selected options in a multi-select element.</comment>\n\n</function>\n\n<function name=\"submit\">\n\n<param name=\"formLocator\">an <a href=\"#locators\">element locator</a> for the form you want to submit</param>\n\n<comment>Submit the specified form. This is particularly useful for forms without\nsubmit buttons, e.g. single-input \"Search\" forms.</comment>\n\n</function>\n\n<function name=\"open\">\n\n<param name=\"url\">the URL to open; may be relative or absolute</param>\n\n<comment>Opens an URL in the test frame. This accepts both relative and absolute\nURLs.\n\nThe &quot;open&quot; command waits for the page to load before proceeding,\nie. the &quot;AndWait&quot; suffix is implicit.\n\n<em>Note</em>: The URL must be on the same domain as the runner HTML\ndue to security restrictions in the browser (Same Origin Policy). If you\nneed to open an URL on another domain, use the Selenium Server to start a\nnew browser session on that domain.</comment>\n\n</function>\n\n<function name=\"openWindow\">\n\n<param name=\"url\">the URL to open, which can be blank</param>\n\n<param name=\"windowID\">the JavaScript window ID of the window to select</param>\n\n<comment>Opens a popup window (if a window with that ID isn't already open).\nAfter opening the window, you'll need to select it using the selectWindow\ncommand.\n\n<p>This command can also be a useful workaround for bug SEL-339.  In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the \"onLoad\" event, for example).\nIn those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using\nan empty (blank) url, like this: openWindow(\"\", \"myFunnyWindow\").</p></comment>\n\n</function>\n\n<function name=\"selectWindow\">\n\n<param name=\"windowID\">the JavaScript window ID of the window to select</param>\n\n<comment>Selects a popup window using a window locator; once a popup window has been selected, all\ncommands go to that window. To select the main window again, use null\nas the target.\n\n<p>\n\nWindow locators provide different ways of specifying the window object:\nby title, by internal JavaScript \"name,\" or by JavaScript variable.\n</p>\n<ul>\n<li><strong>title</strong>=<em>My Special Window</em>:\nFinds the window using the text that appears in the title bar.  Be careful;\ntwo windows can share the same title.  If that happens, this locator will\njust pick one.\n</li>\n<li><strong>name</strong>=<em>myWindow</em>:\nFinds the window using its internal JavaScript \"name\" property.  This is the second \nparameter \"windowName\" passed to the JavaScript method window.open(url, windowName, windowFeatures, replaceFlag)\n(which Selenium intercepts).\n</li>\n<li><strong>var</strong>=<em>variableName</em>:\nSome pop-up windows are unnamed (anonymous), but are associated with a JavaScript variable name in the current\napplication window, e.g. \"window.foo = window.open(url);\".  In those cases, you can open the window using\n\"var=foo\".\n</li>\n</ul>\n<p>\nIf no window locator prefix is provided, we'll try to guess what you mean like this:</p>\n<p>1.) if windowID is null, (or the string \"null\") then it is assumed the user is referring to the original window instantiated by the browser).</p>\n<p>2.) if the value of the \"windowID\" parameter is a JavaScript variable name in the current application window, then it is assumed\nthat this variable contains the return value from a call to the JavaScript window.open() method.</p>\n<p>3.) Otherwise, selenium looks in a hash it maintains that maps string names to window \"names\".</p>\n<p>4.) If <em>that</em> fails, we'll try looping over all of the known windows to try to find the appropriate \"title\".\nSince \"title\" is not necessarily unique, this may have unexpected behavior.</p>\n\n<p>If you're having trouble figuring out the name of a window that you want to manipulate, look at the Selenium log messages\nwhich identify the names of windows created via window.open (and therefore intercepted by Selenium).  You will see messages\nlike the following for each window as it is opened:</p>\n\n<p><code>debug: window.open call intercepted; window ID (which you can use with selectWindow()) is \"myNewWindow\"</code></p>\n\n<p>In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the \"onLoad\" event, for example).\n(This is bug SEL-339.)  In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using\nan empty (blank) url, like this: openWindow(\"\", \"myFunnyWindow\").</p></comment>\n\n</function>\n\n<function name=\"selectFrame\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> identifying a frame or iframe</param>\n\n<comment>Selects a frame within the current window.  (You may invoke this command\nmultiple times to select nested frames.)  To select the parent frame, use\n\"relative=parent\" as a locator; to select the top frame, use \"relative=top\".\nYou can also select a frame by its 0-based index number; select the first frame with\n\"index=0\", or the third frame with \"index=2\".\n\n<p>You may also use a DOM expression to identify the frame you want directly,\nlike this: <code>dom=frames[\"main\"].frames[\"subframe\"]</code></p></comment>\n\n</function>\n\n<function name=\"getWhetherThisFrameMatchFrameExpression\">\n\n<return type=\"boolean\">true if the new frame is this code's window</return>\n\n<param name=\"currentFrameString\">starting frame</param>\n\n<param name=\"target\">new frame (which might be relative to the current one)</param>\n\n<comment>Determine whether current/locator identify the frame containing this running code.\n\n<p>This is useful in proxy injection mode, where this code runs in every\nbrowser frame and window, and sometimes the selenium server needs to identify\nthe \"current\" frame.  In this case, when the test calls selectFrame, this\nroutine is called for each frame to figure out which one has been selected.\nThe selected frame will return true, while all others will return false.</p></comment>\n\n</function>\n\n<function name=\"getWhetherThisWindowMatchWindowExpression\">\n\n<return type=\"boolean\">true if the new window is this code's window</return>\n\n<param name=\"currentWindowString\">starting window</param>\n\n<param name=\"target\">new window (which might be relative to the current one, e.g., \"_parent\")</param>\n\n<comment>Determine whether currentWindowString plus target identify the window containing this running code.\n\n<p>This is useful in proxy injection mode, where this code runs in every\nbrowser frame and window, and sometimes the selenium server needs to identify\nthe \"current\" window.  In this case, when the test calls selectWindow, this\nroutine is called for each window to figure out which one has been selected.\nThe selected window will return true, while all others will return false.</p></comment>\n\n</function>\n\n<function name=\"waitForPopUp\">\n\n<param name=\"windowID\">the JavaScript window \"name\" of the window that will appear (not the text of the title bar)</param>\n\n<param name=\"timeout\">a timeout in milliseconds, after which the action will return with an error</param>\n\n<comment>Waits for a popup window to appear and load up.</comment>\n\n</function>\n\n<function name=\"chooseCancelOnNextConfirmation\">\n\n<comment><p>\nBy default, Selenium's overridden window.confirm() function will\nreturn true, as if the user had manually clicked OK; after running\nthis command, the next call to confirm() will return false, as if\nthe user had clicked Cancel.  Selenium will then resume using the\ndefault behavior for future confirmations, automatically returning \ntrue (OK) unless/until you explicitly call this command for each\nconfirmation.\n</p>\n<p>\nTake note - every time a confirmation comes up, you must\nconsume it with a corresponding getConfirmation, or else\nthe next selenium operation will fail.\n</p></comment>\n\n</function>\n\n<function name=\"chooseOkOnNextConfirmation\">\n\n<comment><p>\nUndo the effect of calling chooseCancelOnNextConfirmation.  Note\nthat Selenium's overridden window.confirm() function will normally automatically\nreturn true, as if the user had manually clicked OK, so you shouldn't\nneed to use this command unless for some reason you need to change\nyour mind prior to the next confirmation.  After any confirmation, Selenium will resume using the\ndefault behavior for future confirmations, automatically returning \ntrue (OK) unless/until you explicitly call chooseCancelOnNextConfirmation for each\nconfirmation.\n</p>\n<p>\nTake note - every time a confirmation comes up, you must\nconsume it with a corresponding getConfirmation, or else\nthe next selenium operation will fail.\n</p></comment>\n\n</function>\n\n<function name=\"answerOnNextPrompt\">\n\n<param name=\"answer\">the answer to give in response to the prompt pop-up</param>\n\n<comment>Instructs Selenium to return the specified answer string in response to\nthe next JavaScript prompt [window.prompt()].</comment>\n\n</function>\n\n<function name=\"goBack\">\n\n<comment>Simulates the user clicking the \"back\" button on their browser.</comment>\n\n</function>\n\n<function name=\"refresh\">\n\n<comment>Simulates the user clicking the \"Refresh\" button on their browser.</comment>\n\n</function>\n\n<function name=\"close\">\n\n<comment>Simulates the user clicking the \"close\" button in the titlebar of a popup\nwindow or tab.</comment>\n\n</function>\n\n<function name=\"isAlertPresent\">\n\n<return type=\"boolean\">true if there is an alert</return>\n\n<comment>Has an alert occurred?\n\n<p>\nThis function never throws an exception\n</p></comment>\n\n</function>\n\n<function name=\"isPromptPresent\">\n\n<return type=\"boolean\">true if there is a pending prompt</return>\n\n<comment>Has a prompt occurred?\n\n<p>\nThis function never throws an exception\n</p></comment>\n\n</function>\n\n<function name=\"isConfirmationPresent\">\n\n<return type=\"boolean\">true if there is a pending confirmation</return>\n\n<comment>Has confirm() been called?\n\n<p>\nThis function never throws an exception\n</p></comment>\n\n</function>\n\n<function name=\"getAlert\">\n\n<return type=\"string\">The message of the most recent JavaScript alert</return>\n\n<comment>Retrieves the message of a JavaScript alert generated during the previous action, or fail if there were no alerts.\n\n<p>Getting an alert has the same effect as manually clicking OK. If an\nalert is generated but you do not consume it with getAlert, the next Selenium action\nwill fail.</p>\n\n<p>Under Selenium, JavaScript alerts will NOT pop up a visible alert\ndialog.</p>\n\n<p>Selenium does NOT support JavaScript alerts that are generated in a\npage's onload() event handler. In this case a visible dialog WILL be\ngenerated and Selenium will hang until someone manually clicks OK.</p></comment>\n\n</function>\n\n<function name=\"getConfirmation\">\n\n<return type=\"string\">the message of the most recent JavaScript confirmation dialog</return>\n\n<comment>Retrieves the message of a JavaScript confirmation dialog generated during\nthe previous action.\n\n<p>\nBy default, the confirm function will return true, having the same effect\nas manually clicking OK. This can be changed by prior execution of the\nchooseCancelOnNextConfirmation command. \n</p>\n<p>\nIf an confirmation is generated but you do not consume it with getConfirmation,\nthe next Selenium action will fail.\n</p>\n\n<p>\nNOTE: under Selenium, JavaScript confirmations will NOT pop up a visible\ndialog.\n</p>\n\n<p>\nNOTE: Selenium does NOT support JavaScript confirmations that are\ngenerated in a page's onload() event handler. In this case a visible\ndialog WILL be generated and Selenium will hang until you manually click\nOK.\n</p></comment>\n\n</function>\n\n<function name=\"getPrompt\">\n\n<return type=\"string\">the message of the most recent JavaScript question prompt</return>\n\n<comment>Retrieves the message of a JavaScript question prompt dialog generated during\nthe previous action.\n\n<p>Successful handling of the prompt requires prior execution of the\nanswerOnNextPrompt command. If a prompt is generated but you\ndo not get/verify it, the next Selenium action will fail.</p>\n\n<p>NOTE: under Selenium, JavaScript prompts will NOT pop up a visible\ndialog.</p>\n\n<p>NOTE: Selenium does NOT support JavaScript prompts that are generated in a\npage's onload() event handler. In this case a visible dialog WILL be\ngenerated and Selenium will hang until someone manually clicks OK.</p></comment>\n\n</function>\n\n<function name=\"getLocation\">\n\n<return type=\"string\">the absolute URL of the current page</return>\n\n<comment>Gets the absolute URL of the current page.</comment>\n\n</function>\n\n<function name=\"getTitle\">\n\n<return type=\"string\">the title of the current page</return>\n\n<comment>Gets the title of the current page.</comment>\n\n</function>\n\n<function name=\"getBodyText\">\n\n<return type=\"string\">the entire text of the page</return>\n\n<comment>Gets the entire text of the page.</comment>\n\n</function>\n\n<function name=\"getValue\">\n\n<return type=\"string\">the element value, or \"on/off\" for checkbox/radio elements</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Gets the (whitespace-trimmed) value of an input field (or anything else with a value parameter).\nFor checkbox/radio elements, the value will be \"on\" or \"off\" depending on\nwhether the element is checked or not.</comment>\n\n</function>\n\n<function name=\"getText\">\n\n<return type=\"string\">the text of the element</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Gets the text of an element. This works for any element that contains\ntext. This command uses either the textContent (Mozilla-like browsers) or\nthe innerText (IE-like browsers) of the element, which is the rendered\ntext shown to the user.</comment>\n\n</function>\n\n<function name=\"highlight\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Briefly changes the backgroundColor of the specified element yellow.  Useful for debugging.</comment>\n\n</function>\n\n<function name=\"getEval\">\n\n<return type=\"string\">the results of evaluating the snippet</return>\n\n<param name=\"script\">the JavaScript snippet to run</param>\n\n<comment>Gets the result of evaluating the specified JavaScript snippet.  The snippet may\nhave multiple lines, but only the result of the last line will be returned.\n\n<p>Note that, by default, the snippet will run in the context of the \"selenium\"\nobject itself, so <code>this</code> will refer to the Selenium object.  Use <code>window</code> to\nrefer to the window of your application, e.g. <code>window.document.getElementById('foo')</code></p>\n\n<p>If you need to use\na locator to refer to a single element in your application page, you can\nuse <code>this.browserbot.findElement(\"id=foo\")</code> where \"id=foo\" is your locator.</p></comment>\n\n</function>\n\n<function name=\"isChecked\">\n\n<return type=\"boolean\">true if the checkbox is checked, false otherwise</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to a checkbox or radio button</param>\n\n<comment>Gets whether a toggle-button (checkbox/radio) is checked.  Fails if the specified element doesn't exist or isn't a toggle-button.</comment>\n\n</function>\n\n<function name=\"getTable\">\n\n<return type=\"string\">the text from the specified cell</return>\n\n<param name=\"tableCellAddress\">a cell address, e.g. \"foo.1.4\"</param>\n\n<comment>Gets the text from a cell of a table. The cellAddress syntax\ntableLocator.row.column, where row and column start at 0.</comment>\n\n</function>\n\n<function name=\"getSelectedLabels\">\n\n<return type=\"string[]\">an array of all selected option labels in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets all option labels (visible text) for selected options in the specified select or multi-select element.</comment>\n\n</function>\n\n<function name=\"getSelectedLabel\">\n\n<return type=\"string\">the selected option label in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets option label (visible text) for selected option in the specified select element.</comment>\n\n</function>\n\n<function name=\"getSelectedValues\">\n\n<return type=\"string[]\">an array of all selected option values in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets all option values (value attributes) for selected options in the specified select or multi-select element.</comment>\n\n</function>\n\n<function name=\"getSelectedValue\">\n\n<return type=\"string\">the selected option value in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets option value (value attribute) for selected option in the specified select element.</comment>\n\n</function>\n\n<function name=\"getSelectedIndexes\">\n\n<return type=\"string[]\">an array of all selected option indexes in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets all option indexes (option number, starting at 0) for selected options in the specified select or multi-select element.</comment>\n\n</function>\n\n<function name=\"getSelectedIndex\">\n\n<return type=\"string\">the selected option index in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets option index (option number, starting at 0) for selected option in the specified select element.</comment>\n\n</function>\n\n<function name=\"getSelectedIds\">\n\n<return type=\"string[]\">an array of all selected option IDs in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets all option element IDs for selected options in the specified select or multi-select element.</comment>\n\n</function>\n\n<function name=\"getSelectedId\">\n\n<return type=\"string\">the selected option ID in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets option element ID for selected option in the specified select element.</comment>\n\n</function>\n\n<function name=\"isSomethingSelected\">\n\n<return type=\"boolean\">true if some option has been selected, false otherwise</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Determines whether some option in a drop-down menu is selected.</comment>\n\n</function>\n\n<function name=\"getSelectOptions\">\n\n<return type=\"string[]\">an array of all option labels in the specified select drop-down</return>\n\n<param name=\"selectLocator\">an <a href=\"#locators\">element locator</a> identifying a drop-down menu</param>\n\n<comment>Gets all option labels in the specified select drop-down.</comment>\n\n</function>\n\n<function name=\"getAttribute\">\n\n<return type=\"string\">the value of the specified attribute</return>\n\n<param name=\"attributeLocator\">an element locator followed by an &#064; sign and then the name of the attribute, e.g. \"foo&#064;bar\"</param>\n\n<comment>Gets the value of an element attribute. The value of the attribute may\ndiffer across browsers (this is the case for the \"style\" attribute, for\nexample).</comment>\n\n</function>\n\n<function name=\"isTextPresent\">\n\n<return type=\"boolean\">true if the pattern matches the text, false otherwise</return>\n\n<param name=\"pattern\">a <a href=\"#patterns\">pattern</a> to match with the text of the page</param>\n\n<comment>Verifies that the specified text pattern appears somewhere on the rendered page shown to the user.</comment>\n\n</function>\n\n<function name=\"isElementPresent\">\n\n<return type=\"boolean\">true if the element is present, false otherwise</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Verifies that the specified element is somewhere on the page.</comment>\n\n</function>\n\n<function name=\"isVisible\">\n\n<return type=\"boolean\">true if the specified element is visible, false otherwise</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Determines if the specified element is visible. An\nelement can be rendered invisible by setting the CSS \"visibility\"\nproperty to \"hidden\", or the \"display\" property to \"none\", either for the\nelement itself or one if its ancestors.  This method will fail if\nthe element is not present.</comment>\n\n</function>\n\n<function name=\"isEditable\">\n\n<return type=\"boolean\">true if the input element is editable, false otherwise</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a></param>\n\n<comment>Determines whether the specified input element is editable, ie hasn't been disabled.\nThis method will fail if the specified element isn't an input element.</comment>\n\n</function>\n\n<function name=\"getAllButtons\">\n\n<return type=\"string[]\">the IDs of all buttons on the page</return>\n\n<comment>Returns the IDs of all buttons on the page.\n\n<p>If a given button has no ID, it will appear as \"\" in this array.</p></comment>\n\n</function>\n\n<function name=\"getAllLinks\">\n\n<return type=\"string[]\">the IDs of all links on the page</return>\n\n<comment>Returns the IDs of all links on the page.\n\n<p>If a given link has no ID, it will appear as \"\" in this array.</p></comment>\n\n</function>\n\n<function name=\"getAllFields\">\n\n<return type=\"string[]\">the IDs of all field on the page</return>\n\n<comment>Returns the IDs of all input fields on the page.\n\n<p>If a given field has no ID, it will appear as \"\" in this array.</p></comment>\n\n</function>\n\n<function name=\"getAttributeFromAllWindows\">\n\n<return type=\"string[]\">the set of values of this attribute from all known windows.</return>\n\n<param name=\"attributeName\">name of an attribute on the windows</param>\n\n<comment>Returns every instance of some attribute from all known windows.</comment>\n\n</function>\n\n<function name=\"dragdrop\">\n\n<param name=\"locator\">an element locator</param>\n\n<param name=\"movementsString\">offset in pixels from the current location to which the element should be moved, e.g., \"+70,-300\"</param>\n\n<comment>deprecated - use dragAndDrop instead</comment>\n\n</function>\n\n<function name=\"setMouseSpeed\">\n\n<param name=\"pixels\">the number of pixels between \"mousemove\" events</param>\n\n<comment>Configure the number of pixels between \"mousemove\" events during dragAndDrop commands (default=10).\n<p>Setting this value to 0 means that we'll send a \"mousemove\" event to every single pixel\nin between the start location and the end location; that can be very slow, and may\ncause some browsers to force the JavaScript to timeout.</p>\n\n<p>If the mouse speed is greater than the distance between the two dragged objects, we'll\njust send one \"mousemove\" at the start location and then one final one at the end location.</p></comment>\n\n</function>\n\n<function name=\"getMouseSpeed\">\n\n<return type=\"number\">the number of pixels between \"mousemove\" events during dragAndDrop commands (default=10)</return>\n\n<comment>Returns the number of pixels between \"mousemove\" events during dragAndDrop commands (default=10).</comment>\n\n</function>\n\n<function name=\"dragAndDrop\">\n\n<param name=\"locator\">an element locator</param>\n\n<param name=\"movementsString\">offset in pixels from the current location to which the element should be moved, e.g., \"+70,-300\"</param>\n\n<comment>Drags an element a certain distance and then drops it</comment>\n\n</function>\n\n<function name=\"dragAndDropToObject\">\n\n<param name=\"locatorOfObjectToBeDragged\">an element to be dragged</param>\n\n<param name=\"locatorOfDragDestinationObject\">an element whose location (i.e., whose center-most pixel) will be the point where locatorOfObjectToBeDragged  is dropped</param>\n\n<comment>Drags an element and drops it on another element</comment>\n\n</function>\n\n<function name=\"windowFocus\">\n\n<comment>Gives focus to the currently selected window</comment>\n\n</function>\n\n<function name=\"windowMaximize\">\n\n<comment>Resize currently selected window to take up the entire screen</comment>\n\n</function>\n\n<function name=\"getAllWindowIds\">\n\n<return type=\"string[]\">the IDs of all windows that the browser knows about.</return>\n\n<comment>Returns the IDs of all windows that the browser knows about.</comment>\n\n</function>\n\n<function name=\"getAllWindowNames\">\n\n<return type=\"string[]\">the names of all windows that the browser knows about.</return>\n\n<comment>Returns the names of all windows that the browser knows about.</comment>\n\n</function>\n\n<function name=\"getAllWindowTitles\">\n\n<return type=\"string[]\">the titles of all windows that the browser knows about.</return>\n\n<comment>Returns the titles of all windows that the browser knows about.</comment>\n\n</function>\n\n<function name=\"getHtmlSource\">\n\n<return type=\"string\">the entire HTML source</return>\n\n<comment>Returns the entire HTML source between the opening and\nclosing \"html\" tags.</comment>\n\n</function>\n\n<function name=\"setCursorPosition\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an input element or textarea</param>\n\n<param name=\"position\">the numerical position of the cursor in the field; position should be 0 to move the position to the beginning of the field.  You can also set the cursor to -1 to move it to the end of the field.</param>\n\n<comment>Moves the text cursor to the specified position in the given input element or textarea.\nThis method will fail if the specified element isn't an input element or textarea.</comment>\n\n</function>\n\n<function name=\"getElementIndex\">\n\n<return type=\"number\">of relative index of the element to its parent (starting from 0)</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element</param>\n\n<comment>Get the relative index of an element to its parent (starting from 0). The comment node and empty text node\nwill be ignored.</comment>\n\n</function>\n\n<function name=\"isOrdered\">\n\n<return type=\"boolean\">true if element1 is the previous sibling of element2, false otherwise</return>\n\n<param name=\"locator1\">an <a href=\"#locators\">element locator</a> pointing to the first element</param>\n\n<param name=\"locator2\">an <a href=\"#locators\">element locator</a> pointing to the second element</param>\n\n<comment>Check if these two elements have same parent and are ordered siblings in the DOM. Two same elements will\nnot be considered ordered.</comment>\n\n</function>\n\n<function name=\"getElementPositionLeft\">\n\n<return type=\"number\">of pixels from the edge of the frame.</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element OR an element itself</param>\n\n<comment>Retrieves the horizontal position of an element</comment>\n\n</function>\n\n<function name=\"getElementPositionTop\">\n\n<return type=\"number\">of pixels from the edge of the frame.</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element OR an element itself</param>\n\n<comment>Retrieves the vertical position of an element</comment>\n\n</function>\n\n<function name=\"getElementWidth\">\n\n<return type=\"number\">width of an element in pixels</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element</param>\n\n<comment>Retrieves the width of an element</comment>\n\n</function>\n\n<function name=\"getElementHeight\">\n\n<return type=\"number\">height of an element in pixels</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element</param>\n\n<comment>Retrieves the height of an element</comment>\n\n</function>\n\n<function name=\"getCursorPosition\">\n\n<return type=\"number\">the numerical position of the cursor in the field</return>\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an input element or textarea</param>\n\n<comment>Retrieves the text cursor position in the given input element or textarea; beware, this may not work perfectly on all browsers.\n\n<p>Specifically, if the cursor/selection has been cleared by JavaScript, this command will tend to\nreturn the position of the last location of the cursor, even though the cursor is now gone from the page.  This is filed as <a href=\"http://jira.openqa.org/browse/SEL-243\">SEL-243</a>.</p>\nThis method will fail if the specified element isn't an input element or textarea, or there is no cursor in the element.</comment>\n\n</function>\n\n<function name=\"getExpression\">\n\n<return type=\"string\">the value passed in</return>\n\n<param name=\"expression\">the value to return</param>\n\n<comment>Returns the specified expression.\n\n<p>This is useful because of JavaScript preprocessing.\nIt is used to generate commands like assertExpression and waitForExpression.</p></comment>\n\n</function>\n\n<function name=\"getXpathCount\">\n\n<return type=\"number\">the number of nodes that match the specified xpath</return>\n\n<param name=\"xpath\">the xpath expression to evaluate. do NOT wrap this expression in a 'count()' function; we will do that for you.</param>\n\n<comment>Returns the number of nodes that match the specified xpath, eg. \"//table\" would give\nthe number of tables.</comment>\n\n</function>\n\n<function name=\"assignId\">\n\n<param name=\"locator\">an <a href=\"#locators\">element locator</a> pointing to an element</param>\n\n<param name=\"identifier\">a string to be used as the ID of the specified element</param>\n\n<comment>Temporarily sets the \"id\" attribute of the specified element, so you can locate it in the future\nusing its ID rather than a slow/complicated XPath.  This ID will disappear once the page is\nreloaded.</comment>\n\n</function>\n\n<function name=\"allowNativeXpath\">\n\n<param name=\"allow\">boolean, true means we'll prefer to use native XPath; false means we'll only use JS XPath</param>\n\n<comment>Specifies whether Selenium should use the native in-browser implementation\nof XPath (if any native version is available); if you pass \"false\" to\nthis function, we will always use our pure-JavaScript xpath library.\nUsing the pure-JS xpath library can improve the consistency of xpath\nelement locators between different browser vendors, but the pure-JS\nversion is much slower than the native implementations.</comment>\n\n</function>\n\n<function name=\"ignoreAttributesWithoutValue\">\n\n<param name=\"ignore\">boolean, true means we'll ignore attributes without value                        at the expense of xpath \"correctness\"; false means                        we'll sacrifice speed for correctness.</param>\n\n<comment>Specifies whether Selenium will ignore xpath attributes that have no\nvalue, i.e. are the empty string, when using the non-native xpath\nevaluation engine. You'd want to do this for performance reasons in IE.\nHowever, this could break certain xpaths, for example an xpath that looks\nfor an attribute whose value is NOT the empty string.\n\nThe hope is that such xpaths are relatively rare, but the user should\nhave the option of using them. Note that this only influences xpath\nevaluation when using the ajaxslt engine (i.e. not \"javascript-xpath\").</comment>\n\n</function>\n\n<function name=\"waitForCondition\">\n\n<param name=\"script\">the JavaScript snippet to run</param>\n\n<param name=\"timeout\">a timeout in milliseconds, after which this command will return with an error</param>\n\n<comment>Runs the specified JavaScript snippet repeatedly until it evaluates to \"true\".\nThe snippet may have multiple lines, but only the result of the last line\nwill be considered.\n\n<p>Note that, by default, the snippet will be run in the runner's test window, not in the window\nof your application.  To get the window of your application, you can use\nthe JavaScript snippet <code>selenium.browserbot.getCurrentWindow()</code>, and then\nrun your JavaScript in there</p></comment>\n\n</function>\n\n<function name=\"setTimeout\">\n\n<param name=\"timeout\">a timeout in milliseconds, after which the action will return with an error</param>\n\n<comment>Specifies the amount of time that Selenium will wait for actions to complete.\n\n<p>Actions that require waiting include \"open\" and the \"waitFor*\" actions.</p>\nThe default timeout is 30 seconds.</comment>\n\n</function>\n\n<function name=\"waitForPageToLoad\">\n\n<param name=\"timeout\">a timeout in milliseconds, after which this command will return with an error</param>\n\n<comment>Waits for a new page to load.\n\n<p>You can use this command instead of the \"AndWait\" suffixes, \"clickAndWait\", \"selectAndWait\", \"typeAndWait\" etc.\n(which are only available in the JS API).</p>\n\n<p>Selenium constantly keeps track of new pages loading, and sets a \"newPageLoaded\"\nflag when it first notices a page load.  Running any other Selenium command after\nturns the flag to false.  Hence, if you want to wait for a page to load, you must\nwait immediately after a Selenium command that caused a page-load.</p></comment>\n\n</function>\n\n<function name=\"waitForFrameToLoad\">\n\n<param name=\"frameAddress\">FrameAddress from the server side</param>\n\n<param name=\"timeout\">a timeout in milliseconds, after which this command will return with an error</param>\n\n<comment>Waits for a new frame to load.\n\n<p>Selenium constantly keeps track of new pages and frames loading, \nand sets a \"newPageLoaded\" flag when it first notices a page load.</p>\n\nSee waitForPageToLoad for more information.</comment>\n\n</function>\n\n<function name=\"getCookie\">\n\n<return type=\"string\">all cookies of the current page under test</return>\n\n<comment>Return all cookies of the current page under test.</comment>\n\n</function>\n\n<function name=\"getCookieByName\">\n\n<return type=\"string\">the value of the cookie</return>\n\n<param name=\"name\">the name of the cookie</param>\n\n<comment>Returns the value of the cookie with the specified name, or throws an error if the cookie is not present.</comment>\n\n</function>\n\n<function name=\"isCookiePresent\">\n\n<return type=\"boolean\">true if a cookie with the specified name is present, or false otherwise.</return>\n\n<param name=\"name\">the name of the cookie</param>\n\n<comment>Returns true if a cookie with the specified name is present, or false otherwise.</comment>\n\n</function>\n\n<function name=\"createCookie\">\n\n<param name=\"nameValuePair\">name and value of the cookie in a format \"name=value\"</param>\n\n<param name=\"optionsString\">options for the cookie. Currently supported options include 'path', 'max_age' and 'domain'.      the optionsString's format is \"path=/path/, max_age=60, domain=.foo.com\". The order of options are irrelevant, the unit      of the value of 'max_age' is second.  Note that specifying a domain that isn't a subset of the current domain will      usually fail.</param>\n\n<comment>Create a new cookie whose path and domain are same with those of current page\nunder test, unless you specified a path for this cookie explicitly.</comment>\n\n</function>\n\n<function name=\"deleteCookie\">\n\n<param name=\"name\">the name of the cookie to be deleted</param>\n\n<param name=\"optionsString\">options for the cookie. Currently supported options include 'path', 'domain'      and 'recurse.' The optionsString's format is \"path=/path/, domain=.foo.com, recurse=true\".      The order of options are irrelevant. Note that specifying a domain that isn't a subset of      the current domain will usually fail.</param>\n\n<comment>Delete a named cookie with specified path and domain.  Be careful; to delete a cookie, you\nneed to delete it using the exact same path and domain that were used to create the cookie.\nIf the path is wrong, or the domain is wrong, the cookie simply won't be deleted.  Also\nnote that specifying a domain that isn't a subset of the current domain will usually fail.\n\nSince there's no way to discover at runtime the original path and domain of a given cookie,\nwe've added an option called 'recurse' to try all sub-domains of the current domain with\nall paths that are a subset of the current path.  Beware; this option can be slow.  In\nbig-O notation, it operates in O(n*m) time, where n is the number of dots in the domain\nname and m is the number of slashes in the path.</comment>\n\n</function>\n\n<function name=\"deleteAllVisibleCookies\">\n\n<comment>Calls deleteCookie with recurse=true on all cookies visible to the current page.\nAs noted on the documentation for deleteCookie, recurse=true can be much slower\nthan simply deleting the cookies using a known domain/path.</comment>\n\n</function>\n\n<function name=\"setBrowserLogLevel\">\n\n<param name=\"logLevel\">one of the following: \"debug\", \"info\", \"warn\", \"error\" or \"off\"</param>\n\n<comment>Sets the threshold for browser-side logging messages; log messages beneath this threshold will be discarded.\nValid logLevel strings are: \"debug\", \"info\", \"warn\", \"error\" or \"off\".\nTo see the browser logs, you need to\neither show the log window in GUI mode, or enable browser-side logging in Selenium RC.</comment>\n\n</function>\n\n<function name=\"runScript\">\n\n<param name=\"script\">the JavaScript snippet to run</param>\n\n<comment>Creates a new \"script\" tag in the body of the current test window, and \nadds the specified text into the body of the command.  Scripts run in\nthis way can often be debugged more easily than scripts executed using\nSelenium's \"getEval\" command.  Beware that JS exceptions thrown in these script\ntags aren't managed by Selenium, so you should probably wrap your script\nin try/catch blocks if there is any chance that the script will throw\nan exception.</comment>\n\n</function>\n\n<function name=\"addLocationStrategy\">\n\n<param name=\"strategyName\">the name of the strategy to define; this should use only   letters [a-zA-Z] with no spaces or other punctuation.</param>\n\n<param name=\"functionDefinition\">a string defining the body of a function in JavaScript.   For example: <code>return inDocument.getElementById(locator);</code></param>\n\n<comment>Defines a new function for Selenium to locate elements on the page.\nFor example,\nif you define the strategy \"foo\", and someone runs click(\"foo=blah\"), we'll\nrun your function, passing you the string \"blah\", and click on the element \nthat your function\nreturns, or throw an \"Element not found\" error if your function returns null.\n\nWe'll pass three arguments to your function:\n<ul>\n<li>locator: the string the user passed in</li>\n<li>inWindow: the currently selected window</li>\n<li>inDocument: the currently selected document</li>\n</ul>\nThe function must return null if the element can't be found.</comment>\n\n</function>\n\n<function name=\"captureEntirePageScreenshot\">\n\n<param name=\"filename\">the path to the file to persist the screenshot as. No                  filename extension will be appended by default.                  Directories will not be created if they do not exist,                    and an exception will be thrown, possibly by native                  code.</param>\n\n<param name=\"kwargs\">a kwargs string that modifies the way the screenshot                  is captured. Example: \"background=#CCFFDD\" .                  Currently valid options:                  <dl>                   <dt>background</dt>                     <dd>the background CSS for the HTML document. This                     may be useful to set for capturing screenshots of                     less-than-ideal layouts, for example where absolute                     positioning causes the calculation of the canvas                     dimension to fail and a black background is exposed                     (possibly obscuring black text).</dd>                  </dl></param>\n\n<comment>Saves the entire contents of the current window canvas to a PNG file.\nContrast this with the captureScreenshot command, which captures the\ncontents of the OS viewport (i.e. whatever is currently being displayed\non the monitor), and is implemented in the RC only. Currently this only\nworks in Firefox when running in chrome mode, and in IE non-HTA using\nthe EXPERIMENTAL \"Snapsie\" utility. The Firefox implementation is mostly\nborrowed from the Screengrab! Firefox extension. Please see\nhttp://www.screengrab.org and http://snapsie.sourceforge.net/ for\ndetails.</comment>\n\n</function>\n\n<function name=\"rollup\">\n\n<param name=\"rollupName\">the name of the rollup command</param>\n\n<param name=\"kwargs\">keyword arguments string that influences how the                    rollup expands into commands</param>\n\n<comment>Executes a command rollup, which is a series of commands with a unique\nname, and optionally arguments that control the generation of the set of\ncommands. If any one of the rolled-up commands fails, the rollup is\nconsidered to have failed. Rollups may also contain nested rollups.</comment>\n\n</function>\n\n<function name=\"addScript\">\n\n<param name=\"scriptContent\">the Javascript content of the script to add</param>\n\n<param name=\"scriptTagId\">(optional) the id of the new script tag. If                       specified, and an element with this id already                       exists, this operation will fail.</param>\n\n<comment>Loads script content into a new script tag in the Selenium document. This\ndiffers from the runScript command in that runScript adds the script tag\nto the document of the AUT, not the Selenium document. The following\nentities in the script content are replaced by the characters they\nrepresent:\n\n    &lt;\n    &gt;\n    &amp;\n\nThe corresponding remove command is removeScript.</comment>\n\n</function>\n\n<function name=\"removeScript\">\n\n<param name=\"scriptTagId\">the id of the script element to remove.</param>\n\n<comment>Removes a script tag from the Selenium document identified by the given\nid. Does nothing if the referenced tag doesn't exist.</comment>\n\n</function>\n\n<function name=\"useXpathLibrary\">\n\n<param name=\"libraryName\">name of the desired library Only the following three can be chosen:   ajaxslt - Google's library   javascript - Cybozu Labs' faster library   default - The default library.  Currently the default library is ajaxslt. If libraryName isn't one of these three, then  no change will be made.</param>\n\n<comment>Allows choice of one of the available libraries.</comment>\n\n</function>\n\n<function name=\"setContext\">\n\n<param name=\"context\">the message to be sent to the browser</param>\n\n<comment>Writes a message to the status bar and adds a note to the browser-side\nlog.</comment>\n\n</function>\n\n<function name=\"attachFile\">\n\n<param name=\"fieldLocator\">an <a href=\"#locators\">element locator</a></param>\n\n<param name=\"fileLocator\">a URL pointing to the specified file. Before the file  can be set in the input field (fieldLocator), Selenium RC may need to transfer the file    to the local machine before attaching the file in a web page form. This is common in selenium  grid configurations where the RC server driving the browser is not the same  machine that started the test.   Supported Browsers: Firefox (\"*chrome\") only.</param>\n\n<comment>Sets a file input (upload) field to the file listed in fileLocator</comment>\n\n</function>\n\n<function name=\"captureScreenshot\">\n\n<param name=\"filename\">the absolute path to the file to be written, e.g. \"c:\\blah\\screenshot.png\"</param>\n\n<comment>Captures a PNG screenshot to the specified file.</comment>\n\n</function>\n\n<function name=\"captureScreenshotToString\">\n\n<return type=\"string\">The base 64 encoded string of the screen shot (PNG file)</return>\n\n<comment>Capture a PNG screenshot.  It then returns the file as a base 64 encoded string.</comment>\n\n</function>\n\n<function name=\"captureEntirePageScreenshotToString\">\n\n<return type=\"string\">The base 64 encoded string of the page screenshot (PNG file)</return>\n\n<param name=\"kwargs\">A kwargs string that modifies the way the screenshot is captured. Example: \"background=#CCFFDD\". This may be useful to set for capturing screenshots of less-than-ideal layouts, for example where absolute positioning causes the calculation of the canvas dimension to fail and a black background is exposed  (possibly obscuring black text).</param>\n\n<comment>Downloads a screenshot of the browser current window canvas to a \nbased 64 encoded PNG file. The <em>entire</em> windows canvas is captured,\nincluding parts rendered outside of the current view port.\n\nCurrently this only works in Mozilla and when running in chrome mode.</comment>\n\n</function>\n\n<function name=\"shutDownSeleniumServer\">\n\n<comment>Kills the running Selenium Server and all browser sessions.  After you run this command, you will no longer be able to send\ncommands to the server; you can't remotely start the server once it has been stopped.  Normally\nyou should prefer to run the \"stop\" command, which terminates the current browser session, rather than \nshutting down the entire server.</comment>\n\n</function>\n\n<function name=\"retrieveLastRemoteControlLogs\">\n\n<return type=\"string\">The last N log messages as a multi-line string.</return>\n\n<comment>Retrieve the last messages logged on a specific remote control. Useful for error reports, especially\nwhen running multiple remote controls in a distributed environment. The maximum number of log messages\nthat can be retrieve is configured on remote control startup.</comment>\n\n</function>\n\n<function name=\"keyDownNative\">\n\n<param name=\"keycode\">an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes!</param>\n\n<comment>Simulates a user pressing a key (without releasing it yet) by sending a native operating system keystroke.\nThis function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing\na key on the keyboard.  It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and\nmetaKeyDown commands, and does not target any particular HTML element.  To send a keystroke to a particular\nelement, focus on the element first before running this command.</comment>\n\n</function>\n\n<function name=\"keyUpNative\">\n\n<param name=\"keycode\">an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes!</param>\n\n<comment>Simulates a user releasing a key by sending a native operating system keystroke.\nThis function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing\na key on the keyboard.  It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and\nmetaKeyDown commands, and does not target any particular HTML element.  To send a keystroke to a particular\nelement, focus on the element first before running this command.</comment>\n\n</function>\n\n<function name=\"keyPressNative\">\n\n<param name=\"keycode\">an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes!</param>\n\n<comment>Simulates a user pressing and releasing a key by sending a native operating system keystroke.\nThis function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing\na key on the keyboard.  It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and\nmetaKeyDown commands, and does not target any particular HTML element.  To send a keystroke to a particular\nelement, focus on the element first before running this command.</comment>\n\n</function>\n\n</apidoc>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/cssQuery-p.js",
    "content": "/*\n\tcssQuery, version 2.0.2 (2005-08-19)\n\tCopyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)\n\tLicense: http://creativecommons.org/licenses/LGPL/2.1/\n*/\neval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('7 x=6(){7 1D=\"2.0.2\";7 C=/\\\\s*,\\\\s*/;7 x=6(s,A){33{7 m=[];7 u=1z.32.2c&&!A;7 b=(A)?(A.31==22)?A:[A]:[1g];7 1E=18(s).1l(C),i;9(i=0;i<1E.y;i++){s=1y(1E[i]);8(U&&s.Z(0,3).2b(\"\")==\" *#\"){s=s.Z(2);A=24([],b,s[1])}1A A=b;7 j=0,t,f,a,c=\"\";H(j<s.y){t=s[j++];f=s[j++];c+=t+f;a=\"\";8(s[j]==\"(\"){H(s[j++]!=\")\")a+=s[j];a=a.Z(0,-1);c+=\"(\"+a+\")\"}A=(u&&V[c])?V[c]:21(A,t,f,a);8(u)V[c]=A}m=m.30(A)}2a x.2d;5 m}2Z(e){x.2d=e;5[]}};x.1Z=6(){5\"6 x() {\\\\n  [1D \"+1D+\"]\\\\n}\"};7 V={};x.2c=L;x.2Y=6(s){8(s){s=1y(s).2b(\"\");2a V[s]}1A V={}};7 29={};7 19=L;x.15=6(n,s){8(19)1i(\"s=\"+1U(s));29[n]=12 s()};x.2X=6(c){5 c?1i(c):o};7 D={};7 h={};7 q={P:/\\\\[([\\\\w-]+(\\\\|[\\\\w-]+)?)\\\\s*(\\\\W?=)?\\\\s*([^\\\\]]*)\\\\]/};7 T=[];D[\" \"]=6(r,f,t,n){7 e,i,j;9(i=0;i<f.y;i++){7 s=X(f[i],t,n);9(j=0;(e=s[j]);j++){8(M(e)&&14(e,n))r.z(e)}}};D[\"#\"]=6(r,f,i){7 e,j;9(j=0;(e=f[j]);j++)8(e.B==i)r.z(e)};D[\".\"]=6(r,f,c){c=12 1t(\"(^|\\\\\\\\s)\"+c+\"(\\\\\\\\s|$)\");7 e,i;9(i=0;(e=f[i]);i++)8(c.l(e.1V))r.z(e)};D[\":\"]=6(r,f,p,a){7 t=h[p],e,i;8(t)9(i=0;(e=f[i]);i++)8(t(e,a))r.z(e)};h[\"2W\"]=6(e){7 d=Q(e);8(d.1C)9(7 i=0;i<d.1C.y;i++){8(d.1C[i]==e)5 K}};h[\"2V\"]=6(e){};7 M=6(e){5(e&&e.1c==1&&e.1f!=\"!\")?e:23};7 16=6(e){H(e&&(e=e.2U)&&!M(e))28;5 e};7 G=6(e){H(e&&(e=e.2T)&&!M(e))28;5 e};7 1r=6(e){5 M(e.27)||G(e.27)};7 1P=6(e){5 M(e.26)||16(e.26)};7 1o=6(e){7 c=[];e=1r(e);H(e){c.z(e);e=G(e)}5 c};7 U=K;7 1h=6(e){7 d=Q(e);5(2S d.25==\"2R\")?/\\\\.1J$/i.l(d.2Q):2P(d.25==\"2O 2N\")};7 Q=6(e){5 e.2M||e.1g};7 X=6(e,t){5(t==\"*\"&&e.1B)?e.1B:e.X(t)};7 17=6(e,t,n){8(t==\"*\")5 M(e);8(!14(e,n))5 L;8(!1h(e))t=t.2L();5 e.1f==t};7 14=6(e,n){5!n||(n==\"*\")||(e.2K==n)};7 1e=6(e){5 e.1G};6 24(r,f,B){7 m,i,j;9(i=0;i<f.y;i++){8(m=f[i].1B.2J(B)){8(m.B==B)r.z(m);1A 8(m.y!=23){9(j=0;j<m.y;j++){8(m[j].B==B)r.z(m[j])}}}}5 r};8(![].z)22.2I.z=6(){9(7 i=0;i<1z.y;i++){o[o.y]=1z[i]}5 o.y};7 N=/\\\\|/;6 21(A,t,f,a){8(N.l(f)){f=f.1l(N);a=f[0];f=f[1]}7 r=[];8(D[t]){D[t](r,A,f,a)}5 r};7 S=/^[^\\\\s>+~]/;7 20=/[\\\\s#.:>+~()@]|[^\\\\s#.:>+~()@]+/g;6 1y(s){8(S.l(s))s=\" \"+s;5 s.P(20)||[]};7 W=/\\\\s*([\\\\s>+~(),]|^|$)\\\\s*/g;7 I=/([\\\\s>+~,]|[^(]\\\\+|^)([#.:@])/g;7 18=6(s){5 s.O(W,\"$1\").O(I,\"$1*$2\")};7 1u={1Z:6(){5\"\\'\"},P:/^(\\'[^\\']*\\')|(\"[^\"]*\")$/,l:6(s){5 o.P.l(s)},1S:6(s){5 o.l(s)?s:o+s+o},1Y:6(s){5 o.l(s)?s.Z(1,-1):s}};7 1s=6(t){5 1u.1Y(t)};7 E=/([\\\\/()[\\\\]?{}|*+-])/g;6 R(s){5 s.O(E,\"\\\\\\\\$1\")};x.15(\"1j-2H\",6(){D[\">\"]=6(r,f,t,n){7 e,i,j;9(i=0;i<f.y;i++){7 s=1o(f[i]);9(j=0;(e=s[j]);j++)8(17(e,t,n))r.z(e)}};D[\"+\"]=6(r,f,t,n){9(7 i=0;i<f.y;i++){7 e=G(f[i]);8(e&&17(e,t,n))r.z(e)}};D[\"@\"]=6(r,f,a){7 t=T[a].l;7 e,i;9(i=0;(e=f[i]);i++)8(t(e))r.z(e)};h[\"2G-10\"]=6(e){5!16(e)};h[\"1x\"]=6(e,c){c=12 1t(\"^\"+c,\"i\");H(e&&!e.13(\"1x\"))e=e.1n;5 e&&c.l(e.13(\"1x\"))};q.1X=/\\\\\\\\:/g;q.1w=\"@\";q.J={};q.O=6(m,a,n,c,v){7 k=o.1w+m;8(!T[k]){a=o.1W(a,c||\"\",v||\"\");T[k]=a;T.z(a)}5 T[k].B};q.1Q=6(s){s=s.O(o.1X,\"|\");7 m;H(m=s.P(o.P)){7 r=o.O(m[0],m[1],m[2],m[3],m[4]);s=s.O(o.P,r)}5 s};q.1W=6(p,t,v){7 a={};a.B=o.1w+T.y;a.2F=p;t=o.J[t];t=t?t(o.13(p),1s(v)):L;a.l=12 2E(\"e\",\"5 \"+t);5 a};q.13=6(n){1d(n.2D()){F\"B\":5\"e.B\";F\"2C\":5\"e.1V\";F\"9\":5\"e.2B\";F\"1T\":8(U){5\"1U((e.2A.P(/1T=\\\\\\\\1v?([^\\\\\\\\s\\\\\\\\1v]*)\\\\\\\\1v?/)||[])[1]||\\'\\')\"}}5\"e.13(\\'\"+n.O(N,\":\")+\"\\')\"};q.J[\"\"]=6(a){5 a};q.J[\"=\"]=6(a,v){5 a+\"==\"+1u.1S(v)};q.J[\"~=\"]=6(a,v){5\"/(^| )\"+R(v)+\"( |$)/.l(\"+a+\")\"};q.J[\"|=\"]=6(a,v){5\"/^\"+R(v)+\"(-|$)/.l(\"+a+\")\"};7 1R=18;18=6(s){5 1R(q.1Q(s))}});x.15(\"1j-2z\",6(){D[\"~\"]=6(r,f,t,n){7 e,i;9(i=0;(e=f[i]);i++){H(e=G(e)){8(17(e,t,n))r.z(e)}}};h[\"2y\"]=6(e,t){t=12 1t(R(1s(t)));5 t.l(1e(e))};h[\"2x\"]=6(e){5 e==Q(e).1H};h[\"2w\"]=6(e){7 n,i;9(i=0;(n=e.1F[i]);i++){8(M(n)||n.1c==3)5 L}5 K};h[\"1N-10\"]=6(e){5!G(e)};h[\"2v-10\"]=6(e){e=e.1n;5 1r(e)==1P(e)};h[\"2u\"]=6(e,s){7 n=x(s,Q(e));9(7 i=0;i<n.y;i++){8(n[i]==e)5 L}5 K};h[\"1O-10\"]=6(e,a){5 1p(e,a,16)};h[\"1O-1N-10\"]=6(e,a){5 1p(e,a,G)};h[\"2t\"]=6(e){5 e.B==2s.2r.Z(1)};h[\"1M\"]=6(e){5 e.1M};h[\"2q\"]=6(e){5 e.1q===L};h[\"1q\"]=6(e){5 e.1q};h[\"1L\"]=6(e){5 e.1L};q.J[\"^=\"]=6(a,v){5\"/^\"+R(v)+\"/.l(\"+a+\")\"};q.J[\"$=\"]=6(a,v){5\"/\"+R(v)+\"$/.l(\"+a+\")\"};q.J[\"*=\"]=6(a,v){5\"/\"+R(v)+\"/.l(\"+a+\")\"};6 1p(e,a,t){1d(a){F\"n\":5 K;F\"2p\":a=\"2n\";1a;F\"2o\":a=\"2n+1\"}7 1m=1o(e.1n);6 1k(i){7 i=(t==G)?1m.y-i:i-1;5 1m[i]==e};8(!Y(a))5 1k(a);a=a.1l(\"n\");7 m=1K(a[0]);7 s=1K(a[1]);8((Y(m)||m==1)&&s==0)5 K;8(m==0&&!Y(s))5 1k(s);8(Y(s))s=0;7 c=1;H(e=t(e))c++;8(Y(m)||m==1)5(t==G)?(c<=s):(s>=c);5(c%m)==s}});x.15(\"1j-2m\",6(){U=1i(\"L;/*@2l@8(@\\\\2k)U=K@2j@*/\");8(!U){X=6(e,t,n){5 n?e.2i(\"*\",t):e.X(t)};14=6(e,n){5!n||(n==\"*\")||(e.2h==n)};1h=1g.1I?6(e){5/1J/i.l(Q(e).1I)}:6(e){5 Q(e).1H.1f!=\"2g\"};1e=6(e){5 e.2f||e.1G||1b(e)};6 1b(e){7 t=\"\",n,i;9(i=0;(n=e.1F[i]);i++){1d(n.1c){F 11:F 1:t+=1b(n);1a;F 3:t+=n.2e;1a}}5 t}}});19=K;5 x}();',62,190,'|||||return|function|var|if|for||||||||pseudoClasses||||test|||this||AttributeSelector|||||||cssQuery|length|push|fr|id||selectors||case|nextElementSibling|while||tests|true|false|thisElement||replace|match|getDocument|regEscape||attributeSelectors|isMSIE|cache||getElementsByTagName|isNaN|slice|child||new|getAttribute|compareNamespace|addModule|previousElementSibling|compareTagName|parseSelector|loaded|break|_0|nodeType|switch|getTextContent|tagName|document|isXML|eval|css|_1|split|ch|parentNode|childElements|nthChild|disabled|firstElementChild|getText|RegExp|Quote|x22|PREFIX|lang|_2|arguments|else|all|links|version|se|childNodes|innerText|documentElement|contentType|xml|parseInt|indeterminate|checked|last|nth|lastElementChild|parse|_3|add|href|String|className|create|NS_IE|remove|toString|ST|select|Array|null|_4|mimeType|lastChild|firstChild|continue|modules|delete|join|caching|error|nodeValue|textContent|HTML|prefix|getElementsByTagNameNS|end|x5fwin32|cc_on|standard||odd|even|enabled|hash|location|target|not|only|empty|root|contains|level3|outerHTML|htmlFor|class|toLowerCase|Function|name|first|level2|prototype|item|scopeName|toUpperCase|ownerDocument|Document|XML|Boolean|URL|unknown|typeof|nextSibling|previousSibling|visited|link|valueOf|clearCache|catch|concat|constructor|callee|try'.split('|'),0,{}))\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery-level2.js",
    "content": "/*\n\tcssQuery, version 2.0.2 (2005-08-19)\n\tCopyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)\n\tLicense: http://creativecommons.org/licenses/LGPL/2.1/\n*/\n\ncssQuery.addModule(\"css-level2\", function() {\n\n// -----------------------------------------------------------------------\n// selectors\n// -----------------------------------------------------------------------\n\n// child selector\nselectors[\">\"] = function($results, $from, $tagName, $namespace) {\n\tvar $element, i, j;\n\tfor (i = 0; i < $from.length; i++) {\n\t\tvar $subset = childElements($from[i]);\n\t\tfor (j = 0; ($element = $subset[j]); j++)\n\t\t\tif (compareTagName($element, $tagName, $namespace))\n\t\t\t\t$results.push($element);\n\t}\n};\n\n// sibling selector\nselectors[\"+\"] = function($results, $from, $tagName, $namespace) {\n\tfor (var i = 0; i < $from.length; i++) {\n\t\tvar $element = nextElementSibling($from[i]);\n\t\tif ($element && compareTagName($element, $tagName, $namespace))\n\t\t\t$results.push($element);\n\t}\n};\n\n// attribute selector\nselectors[\"@\"] = function($results, $from, $attributeSelectorID) {\n\tvar $test = attributeSelectors[$attributeSelectorID].test;\n\tvar $element, i;\n\tfor (i = 0; ($element = $from[i]); i++)\n\t\tif ($test($element)) $results.push($element);\n};\n\n// -----------------------------------------------------------------------\n// pseudo-classes\n// -----------------------------------------------------------------------\n\npseudoClasses[\"first-child\"] = function($element) {\n\treturn !previousElementSibling($element);\n};\n\npseudoClasses[\"lang\"] = function($element, $code) {\n\t$code = new RegExp(\"^\" + $code, \"i\");\n\twhile ($element && !$element.getAttribute(\"lang\")) $element = $element.parentNode;\n\treturn $element && $code.test($element.getAttribute(\"lang\"));\n};\n\n// -----------------------------------------------------------------------\n//  attribute selectors\n// -----------------------------------------------------------------------\n\n// constants\nAttributeSelector.NS_IE = /\\\\:/g;\nAttributeSelector.PREFIX = \"@\";\n// properties\nAttributeSelector.tests = {};\n// methods\nAttributeSelector.replace = function($match, $attribute, $namespace, $compare, $value) {\n\tvar $key = this.PREFIX + $match;\n\tif (!attributeSelectors[$key]) {\n\t\t$attribute = this.create($attribute, $compare || \"\", $value || \"\");\n\t\t// store the selector\n\t\tattributeSelectors[$key] = $attribute;\n\t\tattributeSelectors.push($attribute);\n\t}\n\treturn attributeSelectors[$key].id;\n};\nAttributeSelector.parse = function($selector) {\n\t$selector = $selector.replace(this.NS_IE, \"|\");\n\tvar $match;\n\twhile ($match = $selector.match(this.match)) {\n\t\tvar $replace = this.replace($match[0], $match[1], $match[2], $match[3], $match[4]);\n\t\t$selector = $selector.replace(this.match, $replace);\n\t}\n\treturn $selector;\n};\nAttributeSelector.create = function($propertyName, $test, $value) {\n\tvar $attributeSelector = {};\n\t$attributeSelector.id = this.PREFIX + attributeSelectors.length;\n\t$attributeSelector.name = $propertyName;\n\t$test = this.tests[$test];\n\t$test = $test ? $test(this.getAttribute($propertyName), getText($value)) : false;\n\t$attributeSelector.test = new Function(\"e\", \"return \" + $test);\n\treturn $attributeSelector;\n};\nAttributeSelector.getAttribute = function($name) {\n\tswitch ($name.toLowerCase()) {\n\t\tcase \"id\":\n\t\t\treturn \"e.id\";\n\t\tcase \"class\":\n\t\t\treturn \"e.className\";\n\t\tcase \"for\":\n\t\t\treturn \"e.htmlFor\";\n\t\tcase \"href\":\n\t\t\tif (isMSIE) {\n\t\t\t\t// IE always returns the full path not the fragment in the href attribute\n\t\t\t\t//  so we RegExp it out of outerHTML. Opera does the same thing but there\n\t\t\t\t//  is no way to get the original attribute.\n\t\t\t\treturn \"String((e.outerHTML.match(/href=\\\\x22?([^\\\\s\\\\x22]*)\\\\x22?/)||[])[1]||'')\";\n\t\t\t}\n\t}\n\treturn \"e.getAttribute('\" + $name.replace($NAMESPACE, \":\") + \"')\";\n};\n\n// -----------------------------------------------------------------------\n//  attribute selector tests\n// -----------------------------------------------------------------------\n\nAttributeSelector.tests[\"\"] = function($attribute) {\n\treturn $attribute;\n};\n\nAttributeSelector.tests[\"=\"] = function($attribute, $value) {\n\treturn $attribute + \"==\" + Quote.add($value);\n};\n\nAttributeSelector.tests[\"~=\"] = function($attribute, $value) {\n\treturn \"/(^| )\" + regEscape($value) + \"( |$)/.test(\" + $attribute + \")\";\n};\n\nAttributeSelector.tests[\"|=\"] = function($attribute, $value) {\n\treturn \"/^\" + regEscape($value) + \"(-|$)/.test(\" + $attribute + \")\";\n};\n\n// -----------------------------------------------------------------------\n//  parsing\n// -----------------------------------------------------------------------\n\n// override parseSelector to parse out attribute selectors\nvar _parseSelector = parseSelector;\nparseSelector = function($selector) {\n\treturn _parseSelector(AttributeSelector.parse($selector));\n};\n\n}); // addModule\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery-level3.js",
    "content": "/*\n\tcssQuery, version 2.0.2 (2005-08-19)\n\tCopyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)\n\tLicense: http://creativecommons.org/licenses/LGPL/2.1/\n*/\n\n/* Thanks to Bill Edney */\n\ncssQuery.addModule(\"css-level3\", function() {\n\n// -----------------------------------------------------------------------\n// selectors\n// -----------------------------------------------------------------------\n\n// indirect sibling selector\nselectors[\"~\"] = function($results, $from, $tagName, $namespace) {\n\tvar $element, i;\n\tfor (i = 0; ($element = $from[i]); i++) {\n\t\twhile ($element = nextElementSibling($element)) {\n\t\t\tif (compareTagName($element, $tagName, $namespace))\n\t\t\t\t$results.push($element);\n\t\t}\n\t}\n};\n\n// -----------------------------------------------------------------------\n// pseudo-classes\n// -----------------------------------------------------------------------\n\n// I'm hoping these pseudo-classes are pretty readable. Let me know if\n//  any need explanation.\n\npseudoClasses[\"contains\"] = function($element, $text) {\n\t$text = new RegExp(regEscape(getText($text)));\n\treturn $text.test(getTextContent($element));\n};\n\npseudoClasses[\"root\"] = function($element) {\n\treturn $element == getDocument($element).documentElement;\n};\n\npseudoClasses[\"empty\"] = function($element) {\n\tvar $node, i;\n\tfor (i = 0; ($node = $element.childNodes[i]); i++) {\n\t\tif (thisElement($node) || $node.nodeType == 3) return false;\n\t}\n\treturn true;\n};\n\npseudoClasses[\"last-child\"] = function($element) {\n\treturn !nextElementSibling($element);\n};\n\npseudoClasses[\"only-child\"] = function($element) {\n\t$element = $element.parentNode;\n\treturn firstElementChild($element) == lastElementChild($element);\n};\n\npseudoClasses[\"not\"] = function($element, $selector) {\n\tvar $negated = cssQuery($selector, getDocument($element));\n\tfor (var i = 0; i < $negated.length; i++) {\n\t\tif ($negated[i] == $element) return false;\n\t}\n\treturn true;\n};\n\npseudoClasses[\"nth-child\"] = function($element, $arguments) {\n\treturn nthChild($element, $arguments, previousElementSibling);\n};\n\npseudoClasses[\"nth-last-child\"] = function($element, $arguments) {\n\treturn nthChild($element, $arguments, nextElementSibling);\n};\n\npseudoClasses[\"target\"] = function($element) {\n\treturn $element.id == location.hash.slice(1);\n};\n\n// UI element states\n\npseudoClasses[\"checked\"] = function($element) {\n\treturn $element.checked;\n};\n\npseudoClasses[\"enabled\"] = function($element) {\n\treturn $element.disabled === false;\n};\n\npseudoClasses[\"disabled\"] = function($element) {\n\treturn $element.disabled;\n};\n\npseudoClasses[\"indeterminate\"] = function($element) {\n\treturn $element.indeterminate;\n};\n\n// -----------------------------------------------------------------------\n//  attribute selector tests\n// -----------------------------------------------------------------------\n\nAttributeSelector.tests[\"^=\"] = function($attribute, $value) {\n\treturn \"/^\" + regEscape($value) + \"/.test(\" + $attribute + \")\";\n};\n\nAttributeSelector.tests[\"$=\"] = function($attribute, $value) {\n\treturn \"/\" + regEscape($value) + \"$/.test(\" + $attribute + \")\";\n};\n\nAttributeSelector.tests[\"*=\"] = function($attribute, $value) {\n\treturn \"/\" + regEscape($value) + \"/.test(\" + $attribute + \")\";\n};\n\n// -----------------------------------------------------------------------\n//  nth child support (Bill Edney)\n// -----------------------------------------------------------------------\n\nfunction nthChild($element, $arguments, $traverse) {\n\tswitch ($arguments) {\n\t\tcase \"n\": return true;\n\t\tcase \"even\": $arguments = \"2n\"; break;\n\t\tcase \"odd\": $arguments = \"2n+1\";\n\t}\n\n\tvar $$children = childElements($element.parentNode);\n\tfunction _checkIndex($index) {\n\t\tvar $index = ($traverse == nextElementSibling) ? $$children.length - $index : $index - 1;\n\t\treturn $$children[$index] == $element;\n\t};\n\n\t//\tit was just a number (no \"n\")\n\tif (!isNaN($arguments)) return _checkIndex($arguments);\n\n\t$arguments = $arguments.split(\"n\");\n\tvar $multiplier = parseInt($arguments[0]);\n\tvar $step = parseInt($arguments[1]);\n\n\tif ((isNaN($multiplier) || $multiplier == 1) && $step == 0) return true;\n\tif ($multiplier == 0 && !isNaN($step)) return _checkIndex($step);\n\tif (isNaN($step)) $step = 0;\n\n\tvar $count = 1;\n\twhile ($element = $traverse($element)) $count++;\n\n\tif (isNaN($multiplier) || $multiplier == 1)\n\t\treturn ($traverse == nextElementSibling) ? ($count <= $step) : ($step >= $count);\n\n\treturn ($count % $multiplier) == $step;\n};\n\n}); // addModule\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery-standard.js",
    "content": "/*\n\tcssQuery, version 2.0.2 (2005-08-19)\n\tCopyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)\n\tLicense: http://creativecommons.org/licenses/LGPL/2.1/\n*/\n\ncssQuery.addModule(\"css-standard\", function() { // override IE optimisation\n\n// cssQuery was originally written as the CSS engine for IE7. It is\n//  optimised (in terms of size not speed) for IE so this module is\n//  provided separately to provide cross-browser support.\n\n// -----------------------------------------------------------------------\n// browser compatibility\n// -----------------------------------------------------------------------\n\n// sniff for Win32 Explorer\nisMSIE = eval(\"false;/*@cc_on@if(@\\x5fwin32)isMSIE=true@end@*/\");\n\nif (!isMSIE) {\n\tgetElementsByTagName = function($element, $tagName, $namespace) {\n\t\treturn $namespace ? $element.getElementsByTagNameNS(\"*\", $tagName) :\n\t\t\t$element.getElementsByTagName($tagName);\n\t};\n\n\tcompareNamespace = function($element, $namespace) {\n\t\treturn !$namespace || ($namespace == \"*\") || ($element.prefix == $namespace);\n\t};\n\n\tisXML = document.contentType ? function($element) {\n\t\treturn /xml/i.test(getDocument($element).contentType);\n\t} : function($element) {\n\t\treturn getDocument($element).documentElement.tagName != \"HTML\";\n\t};\n\n\tgetTextContent = function($element) {\n\t\t// mozilla || opera || other\n\t\treturn $element.textContent || $element.innerText || _getTextContent($element);\n\t};\n\n\tfunction _getTextContent($element) {\n\t\tvar $textContent = \"\", $node, i;\n\t\tfor (i = 0; ($node = $element.childNodes[i]); i++) {\n\t\t\tswitch ($node.nodeType) {\n\t\t\t\tcase 11: // document fragment\n\t\t\t\tcase 1: $textContent += _getTextContent($node); break;\n\t\t\t\tcase 3: $textContent += $node.nodeValue; break;\n\t\t\t}\n\t\t}\n\t\treturn $textContent;\n\t};\n}\n}); // addModule\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery.js",
    "content": "/*\n\tcssQuery, version 2.0.2 (2005-08-19)\n\tCopyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)\n\tLicense: http://creativecommons.org/licenses/LGPL/2.1/\n*/\n\n// the following functions allow querying of the DOM using CSS selectors\nvar cssQuery = function() {\nvar version = \"2.0.2\";\n\n// -----------------------------------------------------------------------\n// main query function\n// -----------------------------------------------------------------------\n\nvar $COMMA = /\\s*,\\s*/;\nvar cssQuery = function($selector, $$from) {\ntry {\n\tvar $match = [];\n\tvar $useCache = arguments.callee.caching && !$$from;\n\tvar $base = ($$from) ? ($$from.constructor == Array) ? $$from : [$$from] : [document];\n\t// process comma separated selectors\n\tvar $$selectors = parseSelector($selector).split($COMMA), i;\n\tfor (i = 0; i < $$selectors.length; i++) {\n\t\t// convert the selector to a stream\n\t\t$selector = _toStream($$selectors[i]);\n\t\t// faster chop if it starts with id (MSIE only)\n\t\tif (isMSIE && $selector.slice(0, 3).join(\"\") == \" *#\") {\n\t\t\t$selector = $selector.slice(2);\n\t\t\t$$from = _msie_selectById([], $base, $selector[1]);\n\t\t} else $$from = $base;\n\t\t// process the stream\n\t\tvar j = 0, $token, $filter, $arguments, $cacheSelector = \"\";\n\t\twhile (j < $selector.length) {\n\t\t\t$token = $selector[j++];\n\t\t\t$filter = $selector[j++];\n\t\t\t$cacheSelector += $token + $filter;\n\t\t\t// some pseudo-classes allow arguments to be passed\n\t\t\t//  e.g. nth-child(even)\n\t\t\t$arguments = \"\";\n\t\t\tif ($selector[j] == \"(\") {\n\t\t\t\twhile ($selector[j++] != \")\" && j < $selector.length) {\n\t\t\t\t\t$arguments += $selector[j];\n\t\t\t\t}\n\t\t\t\t$arguments = $arguments.slice(0, -1);\n\t\t\t\t$cacheSelector += \"(\" + $arguments + \")\";\n\t\t\t}\n\t\t\t// process a token/filter pair use cached results if possible\n\t\t\t$$from = ($useCache && cache[$cacheSelector]) ?\n\t\t\t\tcache[$cacheSelector] : select($$from, $token, $filter, $arguments);\n\t\t\tif ($useCache) cache[$cacheSelector] = $$from;\n\t\t}\n\t\t$match = $match.concat($$from);\n\t}\n\tdelete cssQuery.error;\n\treturn $match;\n} catch ($error) {\n\tcssQuery.error = $error;\n\treturn [];\n}};\n\n// -----------------------------------------------------------------------\n// public interface\n// -----------------------------------------------------------------------\n\ncssQuery.toString = function() {\n\treturn \"function cssQuery() {\\n  [version \" + version + \"]\\n}\";\n};\n\n// caching\nvar cache = {};\ncssQuery.caching = false;\ncssQuery.clearCache = function($selector) {\n\tif ($selector) {\n\t\t$selector = _toStream($selector).join(\"\");\n\t\tdelete cache[$selector];\n\t} else cache = {};\n};\n\n// allow extensions\nvar modules = {};\nvar loaded = false;\ncssQuery.addModule = function($name, $script) {\n\tif (loaded) eval(\"$script=\" + String($script));\n\tmodules[$name] = new $script();;\n};\n\n// hackery\ncssQuery.valueOf = function($code) {\n\treturn $code ? eval($code) : this;\n};\n\n// -----------------------------------------------------------------------\n// declarations\n// -----------------------------------------------------------------------\n\nvar selectors = {};\nvar pseudoClasses = {};\n// a safari bug means that these have to be declared here\nvar AttributeSelector = {match: /\\[([\\w-]+(\\|[\\w-]+)?)\\s*(\\W?=)?\\s*([^\\]]*)\\]/};\nvar attributeSelectors = [];\n\n// -----------------------------------------------------------------------\n// selectors\n// -----------------------------------------------------------------------\n\n// descendant selector\nselectors[\" \"] = function($results, $from, $tagName, $namespace) {\n\t// loop through current selection\n\tvar $element, i, j;\n\tfor (i = 0; i < $from.length; i++) {\n\t\t// get descendants\n\t\tvar $subset = getElementsByTagName($from[i], $tagName, $namespace);\n\t\t// loop through descendants and add to results selection\n\t\tfor (j = 0; ($element = $subset[j]); j++) {\n\t\t\tif (thisElement($element) && compareNamespace($element, $namespace))\n\t\t\t\t$results.push($element);\n\t\t}\n\t}\n};\n\n// ID selector\nselectors[\"#\"] = function($results, $from, $id) {\n\t// loop through current selection and check ID\n\tvar $element, j;\n\tfor (j = 0; ($element = $from[j]); j++) if ($element.id == $id) $results.push($element);\n};\n\n// class selector\nselectors[\".\"] = function($results, $from, $className) {\n\t// create a RegExp version of the class\n\t$className = new RegExp(\"(^|\\\\s)\" + $className + \"(\\\\s|$)\");\n\t// loop through current selection and check class\n\tvar $element, i;\n\tfor (i = 0; ($element = $from[i]); i++)\n\t\tif ($className.test($element.className)) $results.push($element);\n};\n\n// pseudo-class selector\nselectors[\":\"] = function($results, $from, $pseudoClass, $arguments) {\n\t// retrieve the cssQuery pseudo-class function\n\tvar $test = pseudoClasses[$pseudoClass], $element, i;\n\t// loop through current selection and apply pseudo-class filter\n\tif ($test) for (i = 0; ($element = $from[i]); i++)\n\t\t// if the cssQuery pseudo-class function returns \"true\" add the element\n\t\tif ($test($element, $arguments)) $results.push($element);\n};\n\n// -----------------------------------------------------------------------\n// pseudo-classes\n// -----------------------------------------------------------------------\n\npseudoClasses[\"link\"] = function($element) {\n\tvar $document = getDocument($element);\n\tif ($document.links) for (var i = 0; i < $document.links.length; i++) {\n\t\tif ($document.links[i] == $element) return true;\n\t}\n};\n\npseudoClasses[\"visited\"] = function($element) {\n\t// can't do this without jiggery-pokery\n};\n\n// -----------------------------------------------------------------------\n// DOM traversal\n// -----------------------------------------------------------------------\n\n// IE5/6 includes comments (LOL) in it's elements collections.\n// so we have to check for this. the test is tagName != \"!\". LOL (again).\nvar thisElement = function($element) {\n\treturn ($element && $element.nodeType == 1 && $element.tagName != \"!\") ? $element : null;\n};\n\n// return the previous element to the supplied element\n//  previousSibling is not good enough as it might return a text or comment node\nvar previousElementSibling = function($element) {\n\twhile ($element && ($element = $element.previousSibling) && !thisElement($element)) continue;\n\treturn $element;\n};\n\n// return the next element to the supplied element\nvar nextElementSibling = function($element) {\n\twhile ($element && ($element = $element.nextSibling) && !thisElement($element)) continue;\n\treturn $element;\n};\n\n// return the first child ELEMENT of an element\n//  NOT the first child node (though they may be the same thing)\nvar firstElementChild = function($element) {\n\treturn thisElement($element.firstChild) || nextElementSibling($element.firstChild);\n};\n\nvar lastElementChild = function($element) {\n\treturn thisElement($element.lastChild) || previousElementSibling($element.lastChild);\n};\n\n// return child elements of an element (not child nodes)\nvar childElements = function($element) {\n\tvar $childElements = [];\n\t$element = firstElementChild($element);\n\twhile ($element) {\n\t\t$childElements.push($element);\n\t\t$element = nextElementSibling($element);\n\t}\n\treturn $childElements;\n};\n\n// -----------------------------------------------------------------------\n// browser compatibility\n// -----------------------------------------------------------------------\n\n// all of the functions in this section can be overwritten. the default\n//  configuration is for IE. The functions below reflect this. standard\n//  methods are included in a separate module. It would probably be better\n//  the other way round of course but this makes it easier to keep IE7 trim.\n\nvar isMSIE = true;\n\nvar isXML = function($element) {\n\tvar $document = getDocument($element);\n\treturn (typeof $document.mimeType == \"unknown\") ?\n\t\t/\\.xml$/i.test($document.URL) :\n\t\tBoolean($document.mimeType == \"XML Document\");\n};\n\n// return the element's containing document\nvar getDocument = function($element) {\n\treturn $element.ownerDocument || $element.document;\n};\n\nvar getElementsByTagName = function($element, $tagName) {\n\treturn ($tagName == \"*\" && $element.all) ? $element.all : $element.getElementsByTagName($tagName);\n};\n\nvar compareTagName = function($element, $tagName, $namespace) {\n\tif ($tagName == \"*\") return thisElement($element);\n\tif (!compareNamespace($element, $namespace)) return false;\n\tif (!isXML($element)) $tagName = $tagName.toUpperCase();\n\treturn $element.tagName == $tagName;\n};\n\nvar compareNamespace = function($element, $namespace) {\n\treturn !$namespace || ($namespace == \"*\") || ($element.scopeName == $namespace);\n};\n\nvar getTextContent = function($element) {\n\treturn $element.innerText;\n};\n\nfunction _msie_selectById($results, $from, id) {\n\tvar $match, i, j;\n\tfor (i = 0; i < $from.length; i++) {\n\t\tif ($match = $from[i].all.item(id)) {\n\t\t\tif ($match.id == id) $results.push($match);\n\t\t\telse if ($match.length != null) {\n\t\t\t\tfor (j = 0; j < $match.length; j++) {\n\t\t\t\t\tif ($match[j].id == id) $results.push($match[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn $results;\n};\n\n// for IE5.0\nif (![].push) Array.prototype.push = function() {\n\tfor (var i = 0; i < arguments.length; i++) {\n\t\tthis[this.length] = arguments[i];\n\t}\n\treturn this.length;\n};\n\n// -----------------------------------------------------------------------\n// query support\n// -----------------------------------------------------------------------\n\n// select a set of matching elements.\n// \"from\" is an array of elements.\n// \"token\" is a character representing the type of filter\n//  e.g. \">\" means child selector\n// \"filter\" represents the tag name, id or class name that is being selected\n// the function returns an array of matching elements\nvar $NAMESPACE = /\\|/;\nfunction select($$from, $token, $filter, $arguments) {\n\tif ($NAMESPACE.test($filter)) {\n\t\t$filter = $filter.split($NAMESPACE);\n\t\t$arguments = $filter[0];\n\t\t$filter = $filter[1];\n\t}\n\tvar $results = [];\n\tif (selectors[$token]) {\n\t\tselectors[$token]($results, $$from, $filter, $arguments);\n\t}\n\treturn $results;\n};\n\n// -----------------------------------------------------------------------\n// parsing\n// -----------------------------------------------------------------------\n\n// convert css selectors to a stream of tokens and filters\n//  it's not a real stream. it's just an array of strings.\nvar $STANDARD_SELECT = /^[^\\s>+~]/;\nvar $$STREAM = /[\\s#.:>+~()@]|[^\\s#.:>+~()@]+/g;\nfunction _toStream($selector) {\n\tif ($STANDARD_SELECT.test($selector)) $selector = \" \" + $selector;\n\treturn $selector.match($$STREAM) || [];\n};\n\nvar $WHITESPACE = /\\s*([\\s>+~(),]|^|$)\\s*/g;\nvar $IMPLIED_ALL = /([\\s>+~,]|[^(]\\+|^)([#.:@])/g;\nvar parseSelector = function($selector) {\n\treturn $selector\n\t// trim whitespace\n\t.replace($WHITESPACE, \"$1\")\n\t// e.g. \".class1\" --> \"*.class1\"\n\t.replace($IMPLIED_ALL, \"$1*$2\");\n};\n\nvar Quote = {\n\ttoString: function() {return \"'\"},\n\tmatch: /^('[^']*')|(\"[^\"]*\")$/,\n\ttest: function($string) {\n\t\treturn this.match.test($string);\n\t},\n\tadd: function($string) {\n\t\treturn this.test($string) ? $string : this + $string + this;\n\t},\n\tremove: function($string) {\n\t\treturn this.test($string) ? $string.slice(1, -1) : $string;\n\t}\n};\n\nvar getText = function($text) {\n\treturn Quote.remove($text);\n};\n\nvar $ESCAPE = /([\\/()[\\]?{}|*+-])/g;\nfunction regEscape($string) {\n\treturn $string.replace($ESCAPE, \"\\\\$1\");\n};\n\n// -----------------------------------------------------------------------\n// modules\n// -----------------------------------------------------------------------\n\n// -------- >>      insert modules here for packaging       << -------- \\\\\n\nloaded = true;\n\n// -----------------------------------------------------------------------\n// return the query function\n// -----------------------------------------------------------------------\n\nreturn cssQuery;\n\n}(); // cssQuery\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/prototype.js",
    "content": "/*  Prototype JavaScript framework, version 1.5.0_rc0\n *  (c) 2005 Sam Stephenson <sam@conio.net>\n *\n *  Prototype is freely distributable under the terms of an MIT-style license.\n *  For details, see the Prototype web site: http://prototype.conio.net/\n *\n/*--------------------------------------------------------------------------*/\n\nvar Prototype = {\n  Version: '1.5.0_rc0',\n  ScriptFragment: '(?:<script.*?>)((\\n|\\r|.)*?)(?:<\\/script>)',\n\n  emptyFunction: function() {},\n  K: function(x) {return x}\n}\n\nvar Class = {\n  create: function() {\n    return function() {\n      this.initialize.apply(this, arguments);\n    }\n  }\n}\n\nvar Abstract = new Object();\n\nObject.extend = function(destination, source) {\n  for (var property in source) {\n    destination[property] = source[property];\n  }\n  return destination;\n}\n\nObject.inspect = function(object) {\n  try {\n    if (object == undefined) return 'undefined';\n    if (object == null) return 'null';\n    return object.inspect ? object.inspect() : object.toString();\n  } catch (e) {\n    if (e instanceof RangeError) return '...';\n    throw e;\n  }\n}\n\nFunction.prototype.bind = function() {\n  var __method = this, args = $A(arguments), object = args.shift();\n  return function() {\n    return __method.apply(object, args.concat($A(arguments)));\n  }\n}\n\nFunction.prototype.bindAsEventListener = function(object) {\n  var __method = this;\n  return function(event) {\n    return __method.call(object, event || window.event);\n  }\n}\n\nObject.extend(Number.prototype, {\n  toColorPart: function() {\n    var digits = this.toString(16);\n    if (this < 16) return '0' + digits;\n    return digits;\n  },\n\n  succ: function() {\n    return this + 1;\n  },\n\n  times: function(iterator) {\n    $R(0, this, true).each(iterator);\n    return this;\n  }\n});\n\nvar Try = {\n  these: function() {\n    var returnValue;\n\n    for (var i = 0; i < arguments.length; i++) {\n      var lambda = arguments[i];\n      try {\n        returnValue = lambda();\n        break;\n      } catch (e) {}\n    }\n\n    return returnValue;\n  }\n}\n\n/*--------------------------------------------------------------------------*/\n\nvar PeriodicalExecuter = Class.create();\nPeriodicalExecuter.prototype = {\n  initialize: function(callback, frequency) {\n    this.callback = callback;\n    this.frequency = frequency;\n    this.currentlyExecuting = false;\n\n    this.registerCallback();\n  },\n\n  registerCallback: function() {\n    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);\n  },\n\n  onTimerEvent: function() {\n    if (!this.currentlyExecuting) {\n      try {\n        this.currentlyExecuting = true;\n        this.callback();\n      } finally {\n        this.currentlyExecuting = false;\n      }\n    }\n  }\n}\nObject.extend(String.prototype, {\n  gsub: function(pattern, replacement) {\n    var result = '', source = this, match;\n    replacement = arguments.callee.prepareReplacement(replacement);\n\n    while (source.length > 0) {\n      if (match = source.match(pattern)) {\n        result += source.slice(0, match.index);\n        result += (replacement(match) || '').toString();\n        source  = source.slice(match.index + match[0].length);\n      } else {\n        result += source, source = '';\n      }\n    }\n    return result;\n  },\n\n  sub: function(pattern, replacement, count) {\n    replacement = this.gsub.prepareReplacement(replacement);\n    count = count === undefined ? 1 : count;\n\n    return this.gsub(pattern, function(match) {\n      if (--count < 0) return match[0];\n      return replacement(match);\n    });\n  },\n\n  scan: function(pattern, iterator) {\n    this.gsub(pattern, iterator);\n    return this;\n  },\n\n  truncate: function(length, truncation) {\n    length = length || 30;\n    truncation = truncation === undefined ? '...' : truncation;\n    return this.length > length ?\n      this.slice(0, length - truncation.length) + truncation : this;\n  },\n\n  strip: function() {\n    return this.replace(/^\\s+/, '').replace(/\\s+$/, '');\n  },\n\n  stripTags: function() {\n    return this.replace(/<\\/?[^>]+>/gi, '');\n  },\n\n  stripScripts: function() {\n    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');\n  },\n\n  extractScripts: function() {\n    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');\n    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');\n    return (this.match(matchAll) || []).map(function(scriptTag) {\n      return (scriptTag.match(matchOne) || ['', ''])[1];\n    });\n  },\n\n  evalScripts: function() {\n    return this.extractScripts().map(function(script) { return eval(script) });\n  },\n\n  escapeHTML: function() {\n    var div = document.createElement('div');\n    var text = document.createTextNode(this);\n    div.appendChild(text);\n    return div.innerHTML;\n  },\n\n  unescapeHTML: function() {\n    var div = document.createElement('div');\n    div.innerHTML = this.stripTags();\n    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';\n  },\n\n  toQueryParams: function() {\n    var pairs = this.match(/^\\??(.*)$/)[1].split('&');\n    return pairs.inject({}, function(params, pairString) {\n      var pair = pairString.split('=');\n      params[pair[0]] = pair[1];\n      return params;\n    });\n  },\n\n  toArray: function() {\n    return this.split('');\n  },\n\n  camelize: function() {\n    var oStringList = this.split('-');\n    if (oStringList.length == 1) return oStringList[0];\n\n    var camelizedString = this.indexOf('-') == 0\n      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)\n      : oStringList[0];\n\n    for (var i = 1, len = oStringList.length; i < len; i++) {\n      var s = oStringList[i];\n      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);\n    }\n\n    return camelizedString;\n  },\n\n  inspect: function() {\n    return \"'\" + this.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, '\\\\\\'') + \"'\";\n  }\n});\n\nString.prototype.gsub.prepareReplacement = function(replacement) {\n  if (typeof replacement == 'function') return replacement;\n  var template = new Template(replacement);\n  return function(match) { return template.evaluate(match) };\n}\n\nString.prototype.parseQuery = String.prototype.toQueryParams;\n\nvar Template = Class.create();\nTemplate.Pattern = /(^|.|\\r|\\n)(#\\{(.*?)\\})/;\nTemplate.prototype = {\n  initialize: function(template, pattern) {\n    this.template = template.toString();\n    this.pattern  = pattern || Template.Pattern;\n  },\n\n  evaluate: function(object) {\n    return this.template.gsub(this.pattern, function(match) {\n      var before = match[1];\n      if (before == '\\\\') return match[2];\n      return before + (object[match[3]] || '').toString();\n    });\n  }\n}\n\nvar $break    = new Object();\nvar $continue = new Object();\n\nvar Enumerable = {\n  each: function(iterator) {\n    var index = 0;\n    try {\n      this._each(function(value) {\n        try {\n          iterator(value, index++);\n        } catch (e) {\n          if (e != $continue) throw e;\n        }\n      });\n    } catch (e) {\n      if (e != $break) throw e;\n    }\n  },\n\n  all: function(iterator) {\n    var result = true;\n    this.each(function(value, index) {\n      result = result && !!(iterator || Prototype.K)(value, index);\n      if (!result) throw $break;\n    });\n    return result;\n  },\n\n  any: function(iterator) {\n    var result = true;\n    this.each(function(value, index) {\n      if (result = !!(iterator || Prototype.K)(value, index))\n        throw $break;\n    });\n    return result;\n  },\n\n  collect: function(iterator) {\n    var results = [];\n    this.each(function(value, index) {\n      results.push(iterator(value, index));\n    });\n    return results;\n  },\n\n  detect: function (iterator) {\n    var result;\n    this.each(function(value, index) {\n      if (iterator(value, index)) {\n        result = value;\n        throw $break;\n      }\n    });\n    return result;\n  },\n\n  findAll: function(iterator) {\n    var results = [];\n    this.each(function(value, index) {\n      if (iterator(value, index))\n        results.push(value);\n    });\n    return results;\n  },\n\n  grep: function(pattern, iterator) {\n    var results = [];\n    this.each(function(value, index) {\n      var stringValue = value.toString();\n      if (stringValue.match(pattern))\n        results.push((iterator || Prototype.K)(value, index));\n    })\n    return results;\n  },\n\n  include: function(object) {\n    var found = false;\n    this.each(function(value) {\n      if (value == object) {\n        found = true;\n        throw $break;\n      }\n    });\n    return found;\n  },\n\n  inject: function(memo, iterator) {\n    this.each(function(value, index) {\n      memo = iterator(memo, value, index);\n    });\n    return memo;\n  },\n\n  invoke: function(method) {\n    var args = $A(arguments).slice(1);\n    return this.collect(function(value) {\n      return value[method].apply(value, args);\n    });\n  },\n\n  max: function(iterator) {\n    var result;\n    this.each(function(value, index) {\n      value = (iterator || Prototype.K)(value, index);\n      if (result == undefined || value >= result)\n        result = value;\n    });\n    return result;\n  },\n\n  min: function(iterator) {\n    var result;\n    this.each(function(value, index) {\n      value = (iterator || Prototype.K)(value, index);\n      if (result == undefined || value < result)\n        result = value;\n    });\n    return result;\n  },\n\n  partition: function(iterator) {\n    var trues = [], falses = [];\n    this.each(function(value, index) {\n      ((iterator || Prototype.K)(value, index) ?\n        trues : falses).push(value);\n    });\n    return [trues, falses];\n  },\n\n  pluck: function(property) {\n    var results = [];\n    this.each(function(value, index) {\n      results.push(value[property]);\n    });\n    return results;\n  },\n\n  reject: function(iterator) {\n    var results = [];\n    this.each(function(value, index) {\n      if (!iterator(value, index))\n        results.push(value);\n    });\n    return results;\n  },\n\n  sortBy: function(iterator) {\n    return this.collect(function(value, index) {\n      return {value: value, criteria: iterator(value, index)};\n    }).sort(function(left, right) {\n      var a = left.criteria, b = right.criteria;\n      return a < b ? -1 : a > b ? 1 : 0;\n    }).pluck('value');\n  },\n\n  toArray: function() {\n    return this.collect(Prototype.K);\n  },\n\n  zip: function() {\n    var iterator = Prototype.K, args = $A(arguments);\n    if (typeof args.last() == 'function')\n      iterator = args.pop();\n\n    var collections = [this].concat(args).map($A);\n    return this.map(function(value, index) {\n      return iterator(collections.pluck(index));\n    });\n  },\n\n  inspect: function() {\n    return '#<Enumerable:' + this.toArray().inspect() + '>';\n  }\n}\n\nObject.extend(Enumerable, {\n  map:     Enumerable.collect,\n  find:    Enumerable.detect,\n  select:  Enumerable.findAll,\n  member:  Enumerable.include,\n  entries: Enumerable.toArray\n});\nvar $A = Array.from = function(iterable) {\n  if (!iterable) return [];\n  if (iterable.toArray) {\n    return iterable.toArray();\n  } else {\n    var results = [];\n    for (var i = 0; i < iterable.length; i++)\n      results.push(iterable[i]);\n    return results;\n  }\n}\n\nObject.extend(Array.prototype, Enumerable);\n\nif (!Array.prototype._reverse)\n  Array.prototype._reverse = Array.prototype.reverse;\n\nObject.extend(Array.prototype, {\n  _each: function(iterator) {\n    for (var i = 0; i < this.length; i++)\n      iterator(this[i]);\n  },\n\n  clear: function() {\n    this.length = 0;\n    return this;\n  },\n\n  first: function() {\n    return this[0];\n  },\n\n  last: function() {\n    return this[this.length - 1];\n  },\n\n  compact: function() {\n    return this.select(function(value) {\n      return value != undefined || value != null;\n    });\n  },\n\n  flatten: function() {\n    return this.inject([], function(array, value) {\n      return array.concat(value && value.constructor == Array ?\n        value.flatten() : [value]);\n    });\n  },\n\n  without: function() {\n    var values = $A(arguments);\n    return this.select(function(value) {\n      return !values.include(value);\n    });\n  },\n\n  indexOf: function(object) {\n    for (var i = 0; i < this.length; i++)\n      if (this[i] == object) return i;\n    return -1;\n  },\n\n  reverse: function(inline) {\n    return (inline !== false ? this : this.toArray())._reverse();\n  },\n\n  inspect: function() {\n    return '[' + this.map(Object.inspect).join(', ') + ']';\n  }\n});\nvar Hash = {\n  _each: function(iterator) {\n    for (var key in this) {\n      var value = this[key];\n      if (typeof value == 'function') continue;\n\n      var pair = [key, value];\n      pair.key = key;\n      pair.value = value;\n      iterator(pair);\n    }\n  },\n\n  keys: function() {\n    return this.pluck('key');\n  },\n\n  values: function() {\n    return this.pluck('value');\n  },\n\n  merge: function(hash) {\n    return $H(hash).inject($H(this), function(mergedHash, pair) {\n      mergedHash[pair.key] = pair.value;\n      return mergedHash;\n    });\n  },\n\n  toQueryString: function() {\n    return this.map(function(pair) {\n      return pair.map(encodeURIComponent).join('=');\n    }).join('&');\n  },\n\n  inspect: function() {\n    return '#<Hash:{' + this.map(function(pair) {\n      return pair.map(Object.inspect).join(': ');\n    }).join(', ') + '}>';\n  }\n}\n\nfunction $H(object) {\n  var hash = Object.extend({}, object || {});\n  Object.extend(hash, Enumerable);\n  Object.extend(hash, Hash);\n  return hash;\n}\nObjectRange = Class.create();\nObject.extend(ObjectRange.prototype, Enumerable);\nObject.extend(ObjectRange.prototype, {\n  initialize: function(start, end, exclusive) {\n    this.start = start;\n    this.end = end;\n    this.exclusive = exclusive;\n  },\n\n  _each: function(iterator) {\n    var value = this.start;\n    do {\n      iterator(value);\n      value = value.succ();\n    } while (this.include(value));\n  },\n\n  include: function(value) {\n    if (value < this.start)\n      return false;\n    if (this.exclusive)\n      return value < this.end;\n    return value <= this.end;\n  }\n});\n\nvar $R = function(start, end, exclusive) {\n  return new ObjectRange(start, end, exclusive);\n}\n\nvar Ajax = {\n  getTransport: function() {\n    return Try.these(\n      function() {return new XMLHttpRequest()},\n      function() {return new ActiveXObject('Msxml2.XMLHTTP')},\n      function() {return new ActiveXObject('Microsoft.XMLHTTP')}\n    ) || false;\n  },\n\n  activeRequestCount: 0\n}\n\nAjax.Responders = {\n  responders: [],\n\n  _each: function(iterator) {\n    this.responders._each(iterator);\n  },\n\n  register: function(responderToAdd) {\n    if (!this.include(responderToAdd))\n      this.responders.push(responderToAdd);\n  },\n\n  unregister: function(responderToRemove) {\n    this.responders = this.responders.without(responderToRemove);\n  },\n\n  dispatch: function(callback, request, transport, json) {\n    this.each(function(responder) {\n      if (responder[callback] && typeof responder[callback] == 'function') {\n        try {\n          responder[callback].apply(responder, [request, transport, json]);\n        } catch (e) {}\n      }\n    });\n  }\n};\n\nObject.extend(Ajax.Responders, Enumerable);\n\nAjax.Responders.register({\n  onCreate: function() {\n    Ajax.activeRequestCount++;\n  },\n\n  onComplete: function() {\n    Ajax.activeRequestCount--;\n  }\n});\n\nAjax.Base = function() {};\nAjax.Base.prototype = {\n  setOptions: function(options) {\n    this.options = {\n      method:       'post',\n      asynchronous: true,\n      contentType:  'application/x-www-form-urlencoded',\n      parameters:   ''\n    }\n    Object.extend(this.options, options || {});\n  },\n\n  responseIsSuccess: function() {\n    return this.transport.status == undefined\n        || this.transport.status == 0\n        || (this.transport.status >= 200 && this.transport.status < 300);\n  },\n\n  responseIsFailure: function() {\n    return !this.responseIsSuccess();\n  }\n}\n\nAjax.Request = Class.create();\nAjax.Request.Events =\n  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];\n\nAjax.Request.prototype = Object.extend(new Ajax.Base(), {\n  initialize: function(url, options) {\n    this.transport = Ajax.getTransport();\n    this.setOptions(options);\n    this.request(url);\n  },\n\n  request: function(url) {\n    var parameters = this.options.parameters || '';\n    if (parameters.length > 0) parameters += '&_=';\n\n    try {\n      this.url = url;\n      if (this.options.method == 'get' && parameters.length > 0)\n        this.url += (this.url.match(/\\?/) ? '&' : '?') + parameters;\n\n      Ajax.Responders.dispatch('onCreate', this, this.transport);\n\n      this.transport.open(this.options.method, this.url,\n        this.options.asynchronous);\n\n      if (this.options.asynchronous) {\n        this.transport.onreadystatechange = this.onStateChange.bind(this);\n        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);\n      }\n\n      this.setRequestHeaders();\n\n      var body = this.options.postBody ? this.options.postBody : parameters;\n      this.transport.send(this.options.method == 'post' ? body : null);\n\n    } catch (e) {\n      this.dispatchException(e);\n    }\n  },\n\n  setRequestHeaders: function() {\n    var requestHeaders =\n      ['X-Requested-With', 'XMLHttpRequest',\n       'X-Prototype-Version', Prototype.Version,\n       'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];\n\n    if (this.options.method == 'post') {\n      requestHeaders.push('Content-type', this.options.contentType);\n\n      /* Force \"Connection: close\" for Mozilla browsers to work around\n       * a bug where XMLHttpReqeuest sends an incorrect Content-length\n       * header. See Mozilla Bugzilla #246651.\n       */\n      if (this.transport.overrideMimeType)\n        requestHeaders.push('Connection', 'close');\n    }\n\n    if (this.options.requestHeaders)\n      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);\n\n    for (var i = 0; i < requestHeaders.length; i += 2)\n      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);\n  },\n\n  onStateChange: function() {\n    var readyState = this.transport.readyState;\n    if (readyState != 1)\n      this.respondToReadyState(this.transport.readyState);\n  },\n\n  header: function(name) {\n    try {\n      return this.transport.getResponseHeader(name);\n    } catch (e) {}\n  },\n\n  evalJSON: function() {\n    try {\n      return eval('(' + this.header('X-JSON') + ')');\n    } catch (e) {}\n  },\n\n  evalResponse: function() {\n    try {\n      return eval(this.transport.responseText);\n    } catch (e) {\n      this.dispatchException(e);\n    }\n  },\n\n  respondToReadyState: function(readyState) {\n    var event = Ajax.Request.Events[readyState];\n    var transport = this.transport, json = this.evalJSON();\n\n    if (event == 'Complete') {\n      try {\n        (this.options['on' + this.transport.status]\n         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]\n         || Prototype.emptyFunction)(transport, json);\n      } catch (e) {\n        this.dispatchException(e);\n      }\n\n      if ((this.header('Content-type') || '').match(/^text\\/javascript/i))\n        this.evalResponse();\n    }\n\n    try {\n      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);\n      Ajax.Responders.dispatch('on' + event, this, transport, json);\n    } catch (e) {\n      this.dispatchException(e);\n    }\n\n    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */\n    if (event == 'Complete')\n      this.transport.onreadystatechange = Prototype.emptyFunction;\n  },\n\n  dispatchException: function(exception) {\n    (this.options.onException || Prototype.emptyFunction)(this, exception);\n    Ajax.Responders.dispatch('onException', this, exception);\n  }\n});\n\nAjax.Updater = Class.create();\n\nObject.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {\n  initialize: function(container, url, options) {\n    this.containers = {\n      success: container.success ? $(container.success) : $(container),\n      failure: container.failure ? $(container.failure) :\n        (container.success ? null : $(container))\n    }\n\n    this.transport = Ajax.getTransport();\n    this.setOptions(options);\n\n    var onComplete = this.options.onComplete || Prototype.emptyFunction;\n    this.options.onComplete = (function(transport, object) {\n      this.updateContent();\n      onComplete(transport, object);\n    }).bind(this);\n\n    this.request(url);\n  },\n\n  updateContent: function() {\n    var receiver = this.responseIsSuccess() ?\n      this.containers.success : this.containers.failure;\n    var response = this.transport.responseText;\n\n    if (!this.options.evalScripts)\n      response = response.stripScripts();\n\n    if (receiver) {\n      if (this.options.insertion) {\n        new this.options.insertion(receiver, response);\n      } else {\n        Element.update(receiver, response);\n      }\n    }\n\n    if (this.responseIsSuccess()) {\n      if (this.onComplete)\n        setTimeout(this.onComplete.bind(this), 10);\n    }\n  }\n});\n\nAjax.PeriodicalUpdater = Class.create();\nAjax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {\n  initialize: function(container, url, options) {\n    this.setOptions(options);\n    this.onComplete = this.options.onComplete;\n\n    this.frequency = (this.options.frequency || 2);\n    this.decay = (this.options.decay || 1);\n\n    this.updater = {};\n    this.container = container;\n    this.url = url;\n\n    this.start();\n  },\n\n  start: function() {\n    this.options.onComplete = this.updateComplete.bind(this);\n    this.onTimerEvent();\n  },\n\n  stop: function() {\n    this.updater.onComplete = undefined;\n    clearTimeout(this.timer);\n    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);\n  },\n\n  updateComplete: function(request) {\n    if (this.options.decay) {\n      this.decay = (request.responseText == this.lastText ?\n        this.decay * this.options.decay : 1);\n\n      this.lastText = request.responseText;\n    }\n    this.timer = setTimeout(this.onTimerEvent.bind(this),\n      this.decay * this.frequency * 1000);\n  },\n\n  onTimerEvent: function() {\n    this.updater = new Ajax.Updater(this.container, this.url, this.options);\n  }\n});\nfunction $() {\n  var results = [], element;\n  for (var i = 0; i < arguments.length; i++) {\n    element = arguments[i];\n    if (typeof element == 'string')\n      element = document.getElementById(element);\n    results.push(Element.extend(element));\n  }\n  return results.length < 2 ? results[0] : results;\n}\n\ndocument.getElementsByClassName = function(className, parentElement) {\n  var children = ($(parentElement) || document.body).getElementsByTagName('*');\n  return $A(children).inject([], function(elements, child) {\n    if (child.className.match(new RegExp(\"(^|\\\\s)\" + className + \"(\\\\s|$)\")))\n      elements.push(Element.extend(child));\n    return elements;\n  });\n}\n\n/*--------------------------------------------------------------------------*/\n\nif (!window.Element)\n  var Element = new Object();\n\nElement.extend = function(element) {\n  if (!element) return;\n  if (_nativeExtensions) return element;\n\n  if (!element._extended && element.tagName && element != window) {\n    var methods = Element.Methods, cache = Element.extend.cache;\n    for (property in methods) {\n      var value = methods[property];\n      if (typeof value == 'function')\n        element[property] = cache.findOrStore(value);\n    }\n  }\n\n  element._extended = true;\n  return element;\n}\n\nElement.extend.cache = {\n  findOrStore: function(value) {\n    return this[value] = this[value] || function() {\n      return value.apply(null, [this].concat($A(arguments)));\n    }\n  }\n}\n\nElement.Methods = {\n  visible: function(element) {\n    return $(element).style.display != 'none';\n  },\n\n  toggle: function() {\n    for (var i = 0; i < arguments.length; i++) {\n      var element = $(arguments[i]);\n      Element[Element.visible(element) ? 'hide' : 'show'](element);\n    }\n  },\n\n  hide: function() {\n    for (var i = 0; i < arguments.length; i++) {\n      var element = $(arguments[i]);\n      element.style.display = 'none';\n    }\n  },\n\n  show: function() {\n    for (var i = 0; i < arguments.length; i++) {\n      var element = $(arguments[i]);\n      element.style.display = '';\n    }\n  },\n\n  remove: function(element) {\n    element = $(element);\n    element.parentNode.removeChild(element);\n  },\n\n  update: function(element, html) {\n    $(element).innerHTML = html.stripScripts();\n    setTimeout(function() {html.evalScripts()}, 10);\n  },\n\n  replace: function(element, html) {\n    element = $(element);\n    if (element.outerHTML) {\n      element.outerHTML = html.stripScripts();\n    } else {\n      var range = element.ownerDocument.createRange();\n      range.selectNodeContents(element);\n      element.parentNode.replaceChild(\n        range.createContextualFragment(html.stripScripts()), element);\n    }\n    setTimeout(function() {html.evalScripts()}, 10);\n  },\n\n  getHeight: function(element) {\n    element = $(element);\n    return element.offsetHeight;\n  },\n\n  classNames: function(element) {\n    return new Element.ClassNames(element);\n  },\n\n  hasClassName: function(element, className) {\n    if (!(element = $(element))) return;\n    return Element.classNames(element).include(className);\n  },\n\n  addClassName: function(element, className) {\n    if (!(element = $(element))) return;\n    return Element.classNames(element).add(className);\n  },\n\n  removeClassName: function(element, className) {\n    if (!(element = $(element))) return;\n    return Element.classNames(element).remove(className);\n  },\n\n  // removes whitespace-only text node children\n  cleanWhitespace: function(element) {\n    element = $(element);\n    for (var i = 0; i < element.childNodes.length; i++) {\n      var node = element.childNodes[i];\n      if (node.nodeType == 3 && !/\\S/.test(node.nodeValue))\n        Element.remove(node);\n    }\n  },\n\n  empty: function(element) {\n    return $(element).innerHTML.match(/^\\s*$/);\n  },\n\n  childOf: function(element, ancestor) {\n    element = $(element), ancestor = $(ancestor);\n    while (element = element.parentNode)\n      if (element == ancestor) return true;\n    return false;\n  },\n\n  scrollTo: function(element) {\n    element = $(element);\n    var x = element.x ? element.x : element.offsetLeft,\n        y = element.y ? element.y : element.offsetTop;\n    window.scrollTo(x, y);\n  },\n\n  getStyle: function(element, style) {\n    element = $(element);\n    var value = element.style[style.camelize()];\n    if (!value) {\n      if (document.defaultView && document.defaultView.getComputedStyle) {\n        var css = document.defaultView.getComputedStyle(element, null);\n        value = css ? css.getPropertyValue(style) : null;\n      } else if (element.currentStyle) {\n        value = element.currentStyle[style.camelize()];\n      }\n    }\n\n    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))\n      if (Element.getStyle(element, 'position') == 'static') value = 'auto';\n\n    return value == 'auto' ? null : value;\n  },\n\n  setStyle: function(element, style) {\n    element = $(element);\n    for (var name in style)\n      element.style[name.camelize()] = style[name];\n  },\n\n  getDimensions: function(element) {\n    element = $(element);\n    if (Element.getStyle(element, 'display') != 'none')\n      return {width: element.offsetWidth, height: element.offsetHeight};\n\n    // All *Width and *Height properties give 0 on elements with display none,\n    // so enable the element temporarily\n    var els = element.style;\n    var originalVisibility = els.visibility;\n    var originalPosition = els.position;\n    els.visibility = 'hidden';\n    els.position = 'absolute';\n    els.display = '';\n    var originalWidth = element.clientWidth;\n    var originalHeight = element.clientHeight;\n    els.display = 'none';\n    els.position = originalPosition;\n    els.visibility = originalVisibility;\n    return {width: originalWidth, height: originalHeight};\n  },\n\n  makePositioned: function(element) {\n    element = $(element);\n    var pos = Element.getStyle(element, 'position');\n    if (pos == 'static' || !pos) {\n      element._madePositioned = true;\n      element.style.position = 'relative';\n      // Opera returns the offset relative to the positioning context, when an\n      // element is position relative but top and left have not been defined\n      if (window.opera) {\n        element.style.top = 0;\n        element.style.left = 0;\n      }\n    }\n  },\n\n  undoPositioned: function(element) {\n    element = $(element);\n    if (element._madePositioned) {\n      element._madePositioned = undefined;\n      element.style.position =\n        element.style.top =\n        element.style.left =\n        element.style.bottom =\n        element.style.right = '';\n    }\n  },\n\n  makeClipping: function(element) {\n    element = $(element);\n    if (element._overflow) return;\n    element._overflow = element.style.overflow;\n    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')\n      element.style.overflow = 'hidden';\n  },\n\n  undoClipping: function(element) {\n    element = $(element);\n    if (element._overflow) return;\n    element.style.overflow = element._overflow;\n    element._overflow = undefined;\n  }\n}\n\nObject.extend(Element, Element.Methods);\n\nvar _nativeExtensions = false;\n\nif(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {\n  var HTMLElement = {}\n  HTMLElement.prototype = document.createElement('div').__proto__;\n}\n\nElement.addMethods = function(methods) {\n  Object.extend(Element.Methods, methods || {});\n\n  if(typeof HTMLElement != 'undefined') {\n    var methods = Element.Methods, cache = Element.extend.cache;\n    for (property in methods) {\n      var value = methods[property];\n      if (typeof value == 'function')\n        HTMLElement.prototype[property] = cache.findOrStore(value);\n    }\n    _nativeExtensions = true;\n  }\n}\n\nElement.addMethods();\n\nvar Toggle = new Object();\nToggle.display = Element.toggle;\n\n/*--------------------------------------------------------------------------*/\n\nAbstract.Insertion = function(adjacency) {\n  this.adjacency = adjacency;\n}\n\nAbstract.Insertion.prototype = {\n  initialize: function(element, content) {\n    this.element = $(element);\n    this.content = content.stripScripts();\n\n    if (this.adjacency && this.element.insertAdjacentHTML) {\n      try {\n        this.element.insertAdjacentHTML(this.adjacency, this.content);\n      } catch (e) {\n        var tagName = this.element.tagName.toLowerCase();\n        if (tagName == 'tbody' || tagName == 'tr') {\n          this.insertContent(this.contentFromAnonymousTable());\n        } else {\n          throw e;\n        }\n      }\n    } else {\n      this.range = this.element.ownerDocument.createRange();\n      if (this.initializeRange) this.initializeRange();\n      this.insertContent([this.range.createContextualFragment(this.content)]);\n    }\n\n    setTimeout(function() {content.evalScripts()}, 10);\n  },\n\n  contentFromAnonymousTable: function() {\n    var div = document.createElement('div');\n    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';\n    return $A(div.childNodes[0].childNodes[0].childNodes);\n  }\n}\n\nvar Insertion = new Object();\n\nInsertion.Before = Class.create();\nInsertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {\n  initializeRange: function() {\n    this.range.setStartBefore(this.element);\n  },\n\n  insertContent: function(fragments) {\n    fragments.each((function(fragment) {\n      this.element.parentNode.insertBefore(fragment, this.element);\n    }).bind(this));\n  }\n});\n\nInsertion.Top = Class.create();\nInsertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {\n  initializeRange: function() {\n    this.range.selectNodeContents(this.element);\n    this.range.collapse(true);\n  },\n\n  insertContent: function(fragments) {\n    fragments.reverse(false).each((function(fragment) {\n      this.element.insertBefore(fragment, this.element.firstChild);\n    }).bind(this));\n  }\n});\n\nInsertion.Bottom = Class.create();\nInsertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {\n  initializeRange: function() {\n    this.range.selectNodeContents(this.element);\n    this.range.collapse(this.element);\n  },\n\n  insertContent: function(fragments) {\n    fragments.each((function(fragment) {\n      this.element.appendChild(fragment);\n    }).bind(this));\n  }\n});\n\nInsertion.After = Class.create();\nInsertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {\n  initializeRange: function() {\n    this.range.setStartAfter(this.element);\n  },\n\n  insertContent: function(fragments) {\n    fragments.each((function(fragment) {\n      this.element.parentNode.insertBefore(fragment,\n        this.element.nextSibling);\n    }).bind(this));\n  }\n});\n\n/*--------------------------------------------------------------------------*/\n\nElement.ClassNames = Class.create();\nElement.ClassNames.prototype = {\n  initialize: function(element) {\n    this.element = $(element);\n  },\n\n  _each: function(iterator) {\n    this.element.className.split(/\\s+/).select(function(name) {\n      return name.length > 0;\n    })._each(iterator);\n  },\n\n  set: function(className) {\n    this.element.className = className;\n  },\n\n  add: function(classNameToAdd) {\n    if (this.include(classNameToAdd)) return;\n    this.set(this.toArray().concat(classNameToAdd).join(' '));\n  },\n\n  remove: function(classNameToRemove) {\n    if (!this.include(classNameToRemove)) return;\n    this.set(this.select(function(className) {\n      return className != classNameToRemove;\n    }).join(' '));\n  },\n\n  toString: function() {\n    return this.toArray().join(' ');\n  }\n}\n\nObject.extend(Element.ClassNames.prototype, Enumerable);\nvar Selector = Class.create();\nSelector.prototype = {\n  initialize: function(expression) {\n    this.params = {classNames: []};\n    this.expression = expression.toString().strip();\n    this.parseExpression();\n    this.compileMatcher();\n  },\n\n  parseExpression: function() {\n    function abort(message) { throw 'Parse error in selector: ' + message; }\n\n    if (this.expression == '')  abort('empty expression');\n\n    var params = this.params, expr = this.expression, match, modifier, clause, rest;\n    while (match = expr.match(/^(.*)\\[([a-z0-9_:-]+?)(?:([~\\|!]?=)(?:\"([^\"]*)\"|([^\\]\\s]*)))?\\]$/i)) {\n      params.attributes = params.attributes || [];\n      params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});\n      expr = match[1];\n    }\n\n    if (expr == '*') return this.params.wildcard = true;\n\n    while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {\n      modifier = match[1], clause = match[2], rest = match[3];\n      switch (modifier) {\n        case '#':       params.id = clause; break;\n        case '.':       params.classNames.push(clause); break;\n        case '':\n        case undefined: params.tagName = clause.toUpperCase(); break;\n        default:        abort(expr.inspect());\n      }\n      expr = rest;\n    }\n\n    if (expr.length > 0) abort(expr.inspect());\n  },\n\n  buildMatchExpression: function() {\n    var params = this.params, conditions = [], clause;\n\n    if (params.wildcard)\n      conditions.push('true');\n    if (clause = params.id)\n      conditions.push('element.id == ' + clause.inspect());\n    if (clause = params.tagName)\n      conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());\n    if ((clause = params.classNames).length > 0)\n      for (var i = 0; i < clause.length; i++)\n        conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');\n    if (clause = params.attributes) {\n      clause.each(function(attribute) {\n        var value = 'element.getAttribute(' + attribute.name.inspect() + ')';\n        var splitValueBy = function(delimiter) {\n          return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';\n        }\n\n        switch (attribute.operator) {\n          case '=':       conditions.push(value + ' == ' + attribute.value.inspect()); break;\n          case '~=':      conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;\n          case '|=':      conditions.push(\n                            splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()\n                          ); break;\n          case '!=':      conditions.push(value + ' != ' + attribute.value.inspect()); break;\n          case '':\n          case undefined: conditions.push(value + ' != null'); break;\n          default:        throw 'Unknown operator ' + attribute.operator + ' in selector';\n        }\n      });\n    }\n\n    return conditions.join(' && ');\n  },\n\n  compileMatcher: function() {\n    this.match = new Function('element', 'if (!element.tagName) return false; \\n' +\n    'return ' + this.buildMatchExpression());\n  },\n\n  findElements: function(scope) {\n    var element;\n\n    if (element = $(this.params.id))\n      if (this.match(element))\n        if (!scope || Element.childOf(element, scope))\n          return [element];\n\n    scope = (scope || document).getElementsByTagName(this.params.tagName || '*');\n\n    var results = [];\n    for (var i = 0; i < scope.length; i++)\n      if (this.match(element = scope[i]))\n        results.push(Element.extend(element));\n\n    return results;\n  },\n\n  toString: function() {\n    return this.expression;\n  }\n}\n\nfunction $$() {\n  return $A(arguments).map(function(expression) {\n    return expression.strip().split(/\\s+/).inject([null], function(results, expr) {\n      var selector = new Selector(expr);\n      return results.map(selector.findElements.bind(selector)).flatten();\n    });\n  }).flatten();\n}\nvar Field = {\n  clear: function() {\n    for (var i = 0; i < arguments.length; i++)\n      $(arguments[i]).value = '';\n  },\n\n  focus: function(element) {\n    $(element).focus();\n  },\n\n  present: function() {\n    for (var i = 0; i < arguments.length; i++)\n      if ($(arguments[i]).value == '') return false;\n    return true;\n  },\n\n  select: function(element) {\n    $(element).select();\n  },\n\n  activate: function(element) {\n    element = $(element);\n    element.focus();\n    if (element.select)\n      element.select();\n  }\n}\n\n/*--------------------------------------------------------------------------*/\n\nvar Form = {\n  serialize: function(form) {\n    var elements = Form.getElements($(form));\n    var queryComponents = new Array();\n\n    for (var i = 0; i < elements.length; i++) {\n      var queryComponent = Form.Element.serialize(elements[i]);\n      if (queryComponent)\n        queryComponents.push(queryComponent);\n    }\n\n    return queryComponents.join('&');\n  },\n\n  getElements: function(form) {\n    form = $(form);\n    var elements = new Array();\n\n    for (var tagName in Form.Element.Serializers) {\n      var tagElements = form.getElementsByTagName(tagName);\n      for (var j = 0; j < tagElements.length; j++)\n        elements.push(tagElements[j]);\n    }\n    return elements;\n  },\n\n  getInputs: function(form, typeName, name) {\n    form = $(form);\n    var inputs = form.getElementsByTagName('input');\n\n    if (!typeName && !name)\n      return inputs;\n\n    var matchingInputs = new Array();\n    for (var i = 0; i < inputs.length; i++) {\n      var input = inputs[i];\n      if ((typeName && input.type != typeName) ||\n          (name && input.name != name))\n        continue;\n      matchingInputs.push(input);\n    }\n\n    return matchingInputs;\n  },\n\n  disable: function(form) {\n    var elements = Form.getElements(form);\n    for (var i = 0; i < elements.length; i++) {\n      var element = elements[i];\n      element.blur();\n      element.disabled = 'true';\n    }\n  },\n\n  enable: function(form) {\n    var elements = Form.getElements(form);\n    for (var i = 0; i < elements.length; i++) {\n      var element = elements[i];\n      element.disabled = '';\n    }\n  },\n\n  findFirstElement: function(form) {\n    return Form.getElements(form).find(function(element) {\n      return element.type != 'hidden' && !element.disabled &&\n        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());\n    });\n  },\n\n  focusFirstElement: function(form) {\n    Field.activate(Form.findFirstElement(form));\n  },\n\n  reset: function(form) {\n    $(form).reset();\n  }\n}\n\nForm.Element = {\n  serialize: function(element) {\n    element = $(element);\n    var method = element.tagName.toLowerCase();\n    var parameter = Form.Element.Serializers[method](element);\n\n    if (parameter) {\n      var key = encodeURIComponent(parameter[0]);\n      if (key.length == 0) return;\n\n      if (parameter[1].constructor != Array)\n        parameter[1] = [parameter[1]];\n\n      return parameter[1].map(function(value) {\n        return key + '=' + encodeURIComponent(value);\n      }).join('&');\n    }\n  },\n\n  getValue: function(element) {\n    element = $(element);\n    var method = element.tagName.toLowerCase();\n    var parameter = Form.Element.Serializers[method](element);\n\n    if (parameter)\n      return parameter[1];\n  }\n}\n\nForm.Element.Serializers = {\n  input: function(element) {\n    switch (element.type.toLowerCase()) {\n      case 'submit':\n      case 'hidden':\n      case 'password':\n      case 'text':\n        return Form.Element.Serializers.textarea(element);\n      case 'checkbox':\n      case 'radio':\n        return Form.Element.Serializers.inputSelector(element);\n    }\n    return false;\n  },\n\n  inputSelector: function(element) {\n    if (element.checked)\n      return [element.name, element.value];\n  },\n\n  textarea: function(element) {\n    return [element.name, element.value];\n  },\n\n  select: function(element) {\n    return Form.Element.Serializers[element.type == 'select-one' ?\n      'selectOne' : 'selectMany'](element);\n  },\n\n  selectOne: function(element) {\n    var value = '', opt, index = element.selectedIndex;\n    if (index >= 0) {\n      opt = element.options[index];\n      value = opt.value || opt.text;\n    }\n    return [element.name, value];\n  },\n\n  selectMany: function(element) {\n    var value = [];\n    for (var i = 0; i < element.length; i++) {\n      var opt = element.options[i];\n      if (opt.selected)\n        value.push(opt.value || opt.text);\n    }\n    return [element.name, value];\n  }\n}\n\n/*--------------------------------------------------------------------------*/\n\nvar $F = Form.Element.getValue;\n\n/*--------------------------------------------------------------------------*/\n\nAbstract.TimedObserver = function() {}\nAbstract.TimedObserver.prototype = {\n  initialize: function(element, frequency, callback) {\n    this.frequency = frequency;\n    this.element   = $(element);\n    this.callback  = callback;\n\n    this.lastValue = this.getValue();\n    this.registerCallback();\n  },\n\n  registerCallback: function() {\n    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);\n  },\n\n  onTimerEvent: function() {\n    var value = this.getValue();\n    if (this.lastValue != value) {\n      this.callback(this.element, value);\n      this.lastValue = value;\n    }\n  }\n}\n\nForm.Element.Observer = Class.create();\nForm.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {\n  getValue: function() {\n    return Form.Element.getValue(this.element);\n  }\n});\n\nForm.Observer = Class.create();\nForm.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {\n  getValue: function() {\n    return Form.serialize(this.element);\n  }\n});\n\n/*--------------------------------------------------------------------------*/\n\nAbstract.EventObserver = function() {}\nAbstract.EventObserver.prototype = {\n  initialize: function(element, callback) {\n    this.element  = $(element);\n    this.callback = callback;\n\n    this.lastValue = this.getValue();\n    if (this.element.tagName.toLowerCase() == 'form')\n      this.registerFormCallbacks();\n    else\n      this.registerCallback(this.element);\n  },\n\n  onElementEvent: function() {\n    var value = this.getValue();\n    if (this.lastValue != value) {\n      this.callback(this.element, value);\n      this.lastValue = value;\n    }\n  },\n\n  registerFormCallbacks: function() {\n    var elements = Form.getElements(this.element);\n    for (var i = 0; i < elements.length; i++)\n      this.registerCallback(elements[i]);\n  },\n\n  registerCallback: function(element) {\n    if (element.type) {\n      switch (element.type.toLowerCase()) {\n        case 'checkbox':\n        case 'radio':\n          Event.observe(element, 'click', this.onElementEvent.bind(this));\n          break;\n        case 'password':\n        case 'text':\n        case 'textarea':\n        case 'select-one':\n        case 'select-multiple':\n          Event.observe(element, 'change', this.onElementEvent.bind(this));\n          break;\n      }\n    }\n  }\n}\n\nForm.Element.EventObserver = Class.create();\nForm.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {\n  getValue: function() {\n    return Form.Element.getValue(this.element);\n  }\n});\n\nForm.EventObserver = Class.create();\nForm.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {\n  getValue: function() {\n    return Form.serialize(this.element);\n  }\n});\nif (!window.Event) {\n  var Event = new Object();\n}\n\nObject.extend(Event, {\n  KEY_BACKSPACE: 8,\n  KEY_TAB:       9,\n  KEY_RETURN:   13,\n  KEY_ESC:      27,\n  KEY_LEFT:     37,\n  KEY_UP:       38,\n  KEY_RIGHT:    39,\n  KEY_DOWN:     40,\n  KEY_DELETE:   46,\n\n  element: function(event) {\n    return event.target || event.srcElement;\n  },\n\n  isLeftClick: function(event) {\n    return (((event.which) && (event.which == 1)) ||\n            ((event.button) && (event.button == 1)));\n  },\n\n  pointerX: function(event) {\n    return event.pageX || (event.clientX +\n      (document.documentElement.scrollLeft || document.body.scrollLeft));\n  },\n\n  pointerY: function(event) {\n    return event.pageY || (event.clientY +\n      (document.documentElement.scrollTop || document.body.scrollTop));\n  },\n\n  stop: function(event) {\n    if (event.preventDefault) {\n      event.preventDefault();\n      event.stopPropagation();\n    } else {\n      event.returnValue = false;\n      event.cancelBubble = true;\n    }\n  },\n\n  // find the first node with the given tagName, starting from the\n  // node the event was triggered on; traverses the DOM upwards\n  findElement: function(event, tagName) {\n    var element = Event.element(event);\n    while (element.parentNode && (!element.tagName ||\n        (element.tagName.toUpperCase() != tagName.toUpperCase())))\n      element = element.parentNode;\n    return element;\n  },\n\n  observers: false,\n\n  _observeAndCache: function(element, name, observer, useCapture) {\n    if (!this.observers) this.observers = [];\n    if (element.addEventListener) {\n      this.observers.push([element, name, observer, useCapture]);\n      element.addEventListener(name, observer, useCapture);\n    } else if (element.attachEvent) {\n      this.observers.push([element, name, observer, useCapture]);\n      element.attachEvent('on' + name, observer);\n    }\n  },\n\n  unloadCache: function() {\n    if (!Event.observers) return;\n    for (var i = 0; i < Event.observers.length; i++) {\n      Event.stopObserving.apply(this, Event.observers[i]);\n      Event.observers[i][0] = null;\n    }\n    Event.observers = false;\n  },\n\n  observe: function(element, name, observer, useCapture) {\n    var element = $(element);\n    useCapture = useCapture || false;\n\n    if (name == 'keypress' &&\n        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)\n        || element.attachEvent))\n      name = 'keydown';\n\n    this._observeAndCache(element, name, observer, useCapture);\n  },\n\n  stopObserving: function(element, name, observer, useCapture) {\n    var element = $(element);\n    useCapture = useCapture || false;\n\n    if (name == 'keypress' &&\n        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)\n        || element.detachEvent))\n      name = 'keydown';\n\n    if (element.removeEventListener) {\n      element.removeEventListener(name, observer, useCapture);\n    } else if (element.detachEvent) {\n      element.detachEvent('on' + name, observer);\n    }\n  }\n});\n\n/* prevent memory leaks in IE */\nif (navigator.appVersion.match(/\\bMSIE\\b/))\n  Event.observe(window, 'unload', Event.unloadCache, false);\nvar Position = {\n  // set to true if needed, warning: firefox performance problems\n  // NOT neeeded for page scrolling, only if draggable contained in\n  // scrollable elements\n  includeScrollOffsets: false,\n\n  // must be called before calling withinIncludingScrolloffset, every time the\n  // page is scrolled\n  prepare: function() {\n    this.deltaX =  window.pageXOffset\n                || document.documentElement.scrollLeft\n                || document.body.scrollLeft\n                || 0;\n    this.deltaY =  window.pageYOffset\n                || document.documentElement.scrollTop\n                || document.body.scrollTop\n                || 0;\n  },\n\n  realOffset: function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.scrollTop  || 0;\n      valueL += element.scrollLeft || 0;\n      element = element.parentNode;\n    } while (element);\n    return [valueL, valueT];\n  },\n\n  cumulativeOffset: function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n      element = element.offsetParent;\n    } while (element);\n    return [valueL, valueT];\n  },\n\n  positionedOffset: function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n      element = element.offsetParent;\n      if (element) {\n        p = Element.getStyle(element, 'position');\n        if (p == 'relative' || p == 'absolute') break;\n      }\n    } while (element);\n    return [valueL, valueT];\n  },\n\n  offsetParent: function(element) {\n    if (element.offsetParent) return element.offsetParent;\n    if (element == document.body) return element;\n\n    while ((element = element.parentNode) && element != document.body)\n      if (Element.getStyle(element, 'position') != 'static')\n        return element;\n\n    return document.body;\n  },\n\n  // caches x/y coordinate pair to use with overlap\n  within: function(element, x, y) {\n    if (this.includeScrollOffsets)\n      return this.withinIncludingScrolloffsets(element, x, y);\n    this.xcomp = x;\n    this.ycomp = y;\n    this.offset = this.cumulativeOffset(element);\n\n    return (y >= this.offset[1] &&\n            y <  this.offset[1] + element.offsetHeight &&\n            x >= this.offset[0] &&\n            x <  this.offset[0] + element.offsetWidth);\n  },\n\n  withinIncludingScrolloffsets: function(element, x, y) {\n    var offsetcache = this.realOffset(element);\n\n    this.xcomp = x + offsetcache[0] - this.deltaX;\n    this.ycomp = y + offsetcache[1] - this.deltaY;\n    this.offset = this.cumulativeOffset(element);\n\n    return (this.ycomp >= this.offset[1] &&\n            this.ycomp <  this.offset[1] + element.offsetHeight &&\n            this.xcomp >= this.offset[0] &&\n            this.xcomp <  this.offset[0] + element.offsetWidth);\n  },\n\n  // within must be called directly before\n  overlap: function(mode, element) {\n    if (!mode) return 0;\n    if (mode == 'vertical')\n      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /\n        element.offsetHeight;\n    if (mode == 'horizontal')\n      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /\n        element.offsetWidth;\n  },\n\n  clone: function(source, target) {\n    source = $(source);\n    target = $(target);\n    target.style.position = 'absolute';\n    var offsets = this.cumulativeOffset(source);\n    target.style.top    = offsets[1] + 'px';\n    target.style.left   = offsets[0] + 'px';\n    target.style.width  = source.offsetWidth + 'px';\n    target.style.height = source.offsetHeight + 'px';\n  },\n\n  page: function(forElement) {\n    var valueT = 0, valueL = 0;\n\n    var element = forElement;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n\n      // Safari fix\n      if (element.offsetParent==document.body)\n        if (Element.getStyle(element,'position')=='absolute') break;\n\n    } while (element = element.offsetParent);\n\n    element = forElement;\n    do {\n      valueT -= element.scrollTop  || 0;\n      valueL -= element.scrollLeft || 0;\n    } while (element = element.parentNode);\n\n    return [valueL, valueT];\n  },\n\n  clone: function(source, target) {\n    var options = Object.extend({\n      setLeft:    true,\n      setTop:     true,\n      setWidth:   true,\n      setHeight:  true,\n      offsetTop:  0,\n      offsetLeft: 0\n    }, arguments[2] || {})\n\n    // find page position of source\n    source = $(source);\n    var p = Position.page(source);\n\n    // find coordinate system to use\n    target = $(target);\n    var delta = [0, 0];\n    var parent = null;\n    // delta [0,0] will do fine with position: fixed elements,\n    // position:absolute needs offsetParent deltas\n    if (Element.getStyle(target,'position') == 'absolute') {\n      parent = Position.offsetParent(target);\n      delta = Position.page(parent);\n    }\n\n    // correct by body offsets (fixes Safari)\n    if (parent == document.body) {\n      delta[0] -= document.body.offsetLeft;\n      delta[1] -= document.body.offsetTop;\n    }\n\n    // set position\n    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';\n    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';\n    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';\n    if(options.setHeight) target.style.height = source.offsetHeight + 'px';\n  },\n\n  absolutize: function(element) {\n    element = $(element);\n    if (element.style.position == 'absolute') return;\n    Position.prepare();\n\n    var offsets = Position.positionedOffset(element);\n    var top     = offsets[1];\n    var left    = offsets[0];\n    var width   = element.clientWidth;\n    var height  = element.clientHeight;\n\n    element._originalLeft   = left - parseFloat(element.style.left  || 0);\n    element._originalTop    = top  - parseFloat(element.style.top || 0);\n    element._originalWidth  = element.style.width;\n    element._originalHeight = element.style.height;\n\n    element.style.position = 'absolute';\n    element.style.top    = top + 'px';;\n    element.style.left   = left + 'px';;\n    element.style.width  = width + 'px';;\n    element.style.height = height + 'px';;\n  },\n\n  relativize: function(element) {\n    element = $(element);\n    if (element.style.position == 'relative') return;\n    Position.prepare();\n\n    element.style.position = 'relative';\n    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);\n    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);\n\n    element.style.top    = top + 'px';\n    element.style.left   = left + 'px';\n    element.style.height = element._originalHeight;\n    element.style.width  = element._originalWidth;\n  }\n}\n\n// Safari returns margins on body which is incorrect if the child is absolutely\n// positioned.  For performance reasons, redefine Position.cumulativeOffset for\n// KHTML/WebKit only.\nif (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {\n  Position.cumulativeOffset = function(element) {\n    var valueT = 0, valueL = 0;\n    do {\n      valueT += element.offsetTop  || 0;\n      valueL += element.offsetLeft || 0;\n      if (element.offsetParent == document.body)\n        if (Element.getStyle(element, 'position') == 'absolute') break;\n\n      element = element.offsetParent;\n    } while (element);\n\n    return [valueL, valueT];\n  }\n}"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/builder.js",
    "content": "// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)\n//\n// See scriptaculous.js for full license.\n\nvar Builder = {\n  NODEMAP: {\n    AREA: 'map',\n    CAPTION: 'table',\n    COL: 'table',\n    COLGROUP: 'table',\n    LEGEND: 'fieldset',\n    OPTGROUP: 'select',\n    OPTION: 'select',\n    PARAM: 'object',\n    TBODY: 'table',\n    TD: 'table',\n    TFOOT: 'table',\n    TH: 'table',\n    THEAD: 'table',\n    TR: 'table'\n  },\n  // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,\n  //       due to a Firefox bug\n  node: function(elementName) {\n    elementName = elementName.toUpperCase();\n    \n    // try innerHTML approach\n    var parentTag = this.NODEMAP[elementName] || 'div';\n    var parentElement = document.createElement(parentTag);\n    try { // prevent IE \"feature\": http://dev.rubyonrails.org/ticket/2707\n      parentElement.innerHTML = \"<\" + elementName + \"></\" + elementName + \">\";\n    } catch(e) {}\n    var element = parentElement.firstChild || null;\n      \n    // see if browser added wrapping tags\n    if(element && (element.tagName != elementName))\n      element = element.getElementsByTagName(elementName)[0];\n    \n    // fallback to createElement approach\n    if(!element) element = document.createElement(elementName);\n    \n    // abort if nothing could be created\n    if(!element) return;\n\n    // attributes (or text)\n    if(arguments[1])\n      if(this._isStringOrNumber(arguments[1]) ||\n        (arguments[1] instanceof Array)) {\n          this._children(element, arguments[1]);\n        } else {\n          var attrs = this._attributes(arguments[1]);\n          if(attrs.length) {\n            try { // prevent IE \"feature\": http://dev.rubyonrails.org/ticket/2707\n              parentElement.innerHTML = \"<\" +elementName + \" \" +\n                attrs + \"></\" + elementName + \">\";\n            } catch(e) {}\n            element = parentElement.firstChild || null;\n            // workaround firefox 1.0.X bug\n            if(!element) {\n              element = document.createElement(elementName);\n              for(attr in arguments[1]) \n                element[attr == 'class' ? 'className' : attr] = arguments[1][attr];\n            }\n            if(element.tagName != elementName)\n              element = parentElement.getElementsByTagName(elementName)[0];\n            }\n        } \n\n    // text, or array of children\n    if(arguments[2])\n      this._children(element, arguments[2]);\n\n     return element;\n  },\n  _text: function(text) {\n     return document.createTextNode(text);\n  },\n  _attributes: function(attributes) {\n    var attrs = [];\n    for(attribute in attributes)\n      attrs.push((attribute=='className' ? 'class' : attribute) +\n          '=\"' + attributes[attribute].toString().escapeHTML() + '\"');\n    return attrs.join(\" \");\n  },\n  _children: function(element, children) {\n    if(typeof children=='object') { // array can hold nodes and text\n      children.flatten().each( function(e) {\n        if(typeof e=='object')\n          element.appendChild(e)\n        else\n          if(Builder._isStringOrNumber(e))\n            element.appendChild(Builder._text(e));\n      });\n    } else\n      if(Builder._isStringOrNumber(children)) \n         element.appendChild(Builder._text(children));\n  },\n  _isStringOrNumber: function(param) {\n    return(typeof param=='string' || typeof param=='number');\n  }\n}"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/controls.js",
    "content": "// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)\n//           (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)\n//           (c) 2005 Jon Tirsen (http://www.tirsen.com)\n// Contributors:\n//  Richard Livsey\n//  Rahul Bhargava\n//  Rob Wills\n// \n// See scriptaculous.js for full license.\n\n// Autocompleter.Base handles all the autocompletion functionality \n// that's independent of the data source for autocompletion. This\n// includes drawing the autocompletion menu, observing keyboard\n// and mouse events, and similar.\n//\n// Specific autocompleters need to provide, at the very least, \n// a getUpdatedChoices function that will be invoked every time\n// the text inside the monitored textbox changes. This method \n// should get the text for which to provide autocompletion by\n// invoking this.getToken(), NOT by directly accessing\n// this.element.value. This is to allow incremental tokenized\n// autocompletion. Specific auto-completion logic (AJAX, etc)\n// belongs in getUpdatedChoices.\n//\n// Tokenized incremental autocompletion is enabled automatically\n// when an autocompleter is instantiated with the 'tokens' option\n// in the options parameter, e.g.:\n// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });\n// will incrementally autocomplete with a comma as the token.\n// Additionally, ',' in the above example can be replaced with\n// a token array, e.g. { tokens: [',', '\\n'] } which\n// enables autocompletion on multiple tokens. This is most \n// useful when one of the tokens is \\n (a newline), as it \n// allows smart autocompletion after linebreaks.\n\nvar Autocompleter = {}\nAutocompleter.Base = function() {};\nAutocompleter.Base.prototype = {\n  baseInitialize: function(element, update, options) {\n    this.element     = $(element); \n    this.update      = $(update);  \n    this.hasFocus    = false; \n    this.changed     = false; \n    this.active      = false; \n    this.index       = 0;     \n    this.entryCount  = 0;\n\n    if (this.setOptions)\n      this.setOptions(options);\n    else\n      this.options = options || {};\n\n    this.options.paramName    = this.options.paramName || this.element.name;\n    this.options.tokens       = this.options.tokens || [];\n    this.options.frequency    = this.options.frequency || 0.4;\n    this.options.minChars     = this.options.minChars || 1;\n    this.options.onShow       = this.options.onShow || \n    function(element, update){ \n      if(!update.style.position || update.style.position=='absolute') {\n        update.style.position = 'absolute';\n        Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight});\n      }\n      Effect.Appear(update,{duration:0.15});\n    };\n    this.options.onHide = this.options.onHide || \n    function(element, update){ new Effect.Fade(update,{duration:0.15}) };\n\n    if (typeof(this.options.tokens) == 'string') \n      this.options.tokens = new Array(this.options.tokens);\n\n    this.observer = null;\n    \n    this.element.setAttribute('autocomplete','off');\n\n    Element.hide(this.update);\n\n    Event.observe(this.element, \"blur\", this.onBlur.bindAsEventListener(this));\n    Event.observe(this.element, \"keypress\", this.onKeyPress.bindAsEventListener(this));\n  },\n\n  show: function() {\n    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);\n    if(!this.iefix && \n      (navigator.appVersion.indexOf('MSIE')>0) &&\n      (navigator.userAgent.indexOf('Opera')<0) &&\n      (Element.getStyle(this.update, 'position')=='absolute')) {\n      new Insertion.After(this.update, \n       '<iframe id=\"' + this.update.id + '_iefix\" '+\n       'style=\"display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);\" ' +\n       'src=\"javascript:false;\" frameborder=\"0\" scrolling=\"no\"></iframe>');\n      this.iefix = $(this.update.id+'_iefix');\n    }\n    if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);\n  },\n  \n  fixIEOverlapping: function() {\n    Position.clone(this.update, this.iefix);\n    this.iefix.style.zIndex = 1;\n    this.update.style.zIndex = 2;\n    Element.show(this.iefix);\n  },\n\n  hide: function() {\n    this.stopIndicator();\n    if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);\n    if(this.iefix) Element.hide(this.iefix);\n  },\n\n  startIndicator: function() {\n    if(this.options.indicator) Element.show(this.options.indicator);\n  },\n\n  stopIndicator: function() {\n    if(this.options.indicator) Element.hide(this.options.indicator);\n  },\n\n  onKeyPress: function(event) {\n    if(this.active)\n      switch(event.keyCode) {\n       case Event.KEY_TAB:\n       case Event.KEY_RETURN:\n         this.selectEntry();\n         Event.stop(event);\n       case Event.KEY_ESC:\n         this.hide();\n         this.active = false;\n         Event.stop(event);\n         return;\n       case Event.KEY_LEFT:\n       case Event.KEY_RIGHT:\n         return;\n       case Event.KEY_UP:\n         this.markPrevious();\n         this.render();\n         if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);\n         return;\n       case Event.KEY_DOWN:\n         this.markNext();\n         this.render();\n         if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);\n         return;\n      }\n     else \n       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || \n         (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;\n\n    this.changed = true;\n    this.hasFocus = true;\n\n    if(this.observer) clearTimeout(this.observer);\n      this.observer = \n        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);\n  },\n\n  activate: function() {\n    this.changed = false;\n    this.hasFocus = true;\n    this.getUpdatedChoices();\n  },\n\n  onHover: function(event) {\n    var element = Event.findElement(event, 'LI');\n    if(this.index != element.autocompleteIndex) \n    {\n        this.index = element.autocompleteIndex;\n        this.render();\n    }\n    Event.stop(event);\n  },\n  \n  onClick: function(event) {\n    var element = Event.findElement(event, 'LI');\n    this.index = element.autocompleteIndex;\n    this.selectEntry();\n    this.hide();\n  },\n  \n  onBlur: function(event) {\n    // needed to make click events working\n    setTimeout(this.hide.bind(this), 250);\n    this.hasFocus = false;\n    this.active = false;     \n  }, \n  \n  render: function() {\n    if(this.entryCount > 0) {\n      for (var i = 0; i < this.entryCount; i++)\n        this.index==i ? \n          Element.addClassName(this.getEntry(i),\"selected\") : \n          Element.removeClassName(this.getEntry(i),\"selected\");\n        \n      if(this.hasFocus) { \n        this.show();\n        this.active = true;\n      }\n    } else {\n      this.active = false;\n      this.hide();\n    }\n  },\n  \n  markPrevious: function() {\n    if(this.index > 0) this.index--\n      else this.index = this.entryCount-1;\n  },\n  \n  markNext: function() {\n    if(this.index < this.entryCount-1) this.index++\n      else this.index = 0;\n  },\n  \n  getEntry: function(index) {\n    return this.update.firstChild.childNodes[index];\n  },\n  \n  getCurrentEntry: function() {\n    return this.getEntry(this.index);\n  },\n  \n  selectEntry: function() {\n    this.active = false;\n    this.updateElement(this.getCurrentEntry());\n  },\n\n  updateElement: function(selectedElement) {\n    if (this.options.updateElement) {\n      this.options.updateElement(selectedElement);\n      return;\n    }\n    var value = '';\n    if (this.options.select) {\n      var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];\n      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);\n    } else\n      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');\n    \n    var lastTokenPos = this.findLastToken();\n    if (lastTokenPos != -1) {\n      var newValue = this.element.value.substr(0, lastTokenPos + 1);\n      var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\\s+/);\n      if (whitespace)\n        newValue += whitespace[0];\n      this.element.value = newValue + value;\n    } else {\n      this.element.value = value;\n    }\n    this.element.focus();\n    \n    if (this.options.afterUpdateElement)\n      this.options.afterUpdateElement(this.element, selectedElement);\n  },\n\n  updateChoices: function(choices) {\n    if(!this.changed && this.hasFocus) {\n      this.update.innerHTML = choices;\n      Element.cleanWhitespace(this.update);\n      Element.cleanWhitespace(this.update.firstChild);\n\n      if(this.update.firstChild && this.update.firstChild.childNodes) {\n        this.entryCount = \n          this.update.firstChild.childNodes.length;\n        for (var i = 0; i < this.entryCount; i++) {\n          var entry = this.getEntry(i);\n          entry.autocompleteIndex = i;\n          this.addObservers(entry);\n        }\n      } else { \n        this.entryCount = 0;\n      }\n\n      this.stopIndicator();\n\n      this.index = 0;\n      this.render();\n    }\n  },\n\n  addObservers: function(element) {\n    Event.observe(element, \"mouseover\", this.onHover.bindAsEventListener(this));\n    Event.observe(element, \"click\", this.onClick.bindAsEventListener(this));\n  },\n\n  onObserverEvent: function() {\n    this.changed = false;   \n    if(this.getToken().length>=this.options.minChars) {\n      this.startIndicator();\n      this.getUpdatedChoices();\n    } else {\n      this.active = false;\n      this.hide();\n    }\n  },\n\n  getToken: function() {\n    var tokenPos = this.findLastToken();\n    if (tokenPos != -1)\n      var ret = this.element.value.substr(tokenPos + 1).replace(/^\\s+/,'').replace(/\\s+$/,'');\n    else\n      var ret = this.element.value;\n\n    return /\\n/.test(ret) ? '' : ret;\n  },\n\n  findLastToken: function() {\n    var lastTokenPos = -1;\n\n    for (var i=0; i<this.options.tokens.length; i++) {\n      var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);\n      if (thisTokenPos > lastTokenPos)\n        lastTokenPos = thisTokenPos;\n    }\n    return lastTokenPos;\n  }\n}\n\nAjax.Autocompleter = Class.create();\nObject.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {\n  initialize: function(element, update, url, options) {\n    this.baseInitialize(element, update, options);\n    this.options.asynchronous  = true;\n    this.options.onComplete    = this.onComplete.bind(this);\n    this.options.defaultParams = this.options.parameters || null;\n    this.url                   = url;\n  },\n\n  getUpdatedChoices: function() {\n    entry = encodeURIComponent(this.options.paramName) + '=' + \n      encodeURIComponent(this.getToken());\n\n    this.options.parameters = this.options.callback ?\n      this.options.callback(this.element, entry) : entry;\n\n    if(this.options.defaultParams) \n      this.options.parameters += '&' + this.options.defaultParams;\n\n    new Ajax.Request(this.url, this.options);\n  },\n\n  onComplete: function(request) {\n    this.updateChoices(request.responseText);\n  }\n\n});\n\n// The local array autocompleter. Used when you'd prefer to\n// inject an array of autocompletion options into the page, rather\n// than sending out Ajax queries, which can be quite slow sometimes.\n//\n// The constructor takes four parameters. The first two are, as usual,\n// the id of the monitored textbox, and id of the autocompletion menu.\n// The third is the array you want to autocomplete from, and the fourth\n// is the options block.\n//\n// Extra local autocompletion options:\n// - choices - How many autocompletion choices to offer\n//\n// - partialSearch - If false, the autocompleter will match entered\n//                    text only at the beginning of strings in the \n//                    autocomplete array. Defaults to true, which will\n//                    match text at the beginning of any *word* in the\n//                    strings in the autocomplete array. If you want to\n//                    search anywhere in the string, additionally set\n//                    the option fullSearch to true (default: off).\n//\n// - fullSsearch - Search anywhere in autocomplete array strings.\n//\n// - partialChars - How many characters to enter before triggering\n//                   a partial match (unlike minChars, which defines\n//                   how many characters are required to do any match\n//                   at all). Defaults to 2.\n//\n// - ignoreCase - Whether to ignore case when autocompleting.\n//                 Defaults to true.\n//\n// It's possible to pass in a custom function as the 'selector' \n// option, if you prefer to write your own autocompletion logic.\n// In that case, the other options above will not apply unless\n// you support them.\n\nAutocompleter.Local = Class.create();\nAutocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {\n  initialize: function(element, update, array, options) {\n    this.baseInitialize(element, update, options);\n    this.options.array = array;\n  },\n\n  getUpdatedChoices: function() {\n    this.updateChoices(this.options.selector(this));\n  },\n\n  setOptions: function(options) {\n    this.options = Object.extend({\n      choices: 10,\n      partialSearch: true,\n      partialChars: 2,\n      ignoreCase: true,\n      fullSearch: false,\n      selector: function(instance) {\n        var ret       = []; // Beginning matches\n        var partial   = []; // Inside matches\n        var entry     = instance.getToken();\n        var count     = 0;\n\n        for (var i = 0; i < instance.options.array.length &&  \n          ret.length < instance.options.choices ; i++) { \n\n          var elem = instance.options.array[i];\n          var foundPos = instance.options.ignoreCase ? \n            elem.toLowerCase().indexOf(entry.toLowerCase()) : \n            elem.indexOf(entry);\n\n          while (foundPos != -1) {\n            if (foundPos == 0 && elem.length != entry.length) { \n              ret.push(\"<li><strong>\" + elem.substr(0, entry.length) + \"</strong>\" + \n                elem.substr(entry.length) + \"</li>\");\n              break;\n            } else if (entry.length >= instance.options.partialChars && \n              instance.options.partialSearch && foundPos != -1) {\n              if (instance.options.fullSearch || /\\s/.test(elem.substr(foundPos-1,1))) {\n                partial.push(\"<li>\" + elem.substr(0, foundPos) + \"<strong>\" +\n                  elem.substr(foundPos, entry.length) + \"</strong>\" + elem.substr(\n                  foundPos + entry.length) + \"</li>\");\n                break;\n              }\n            }\n\n            foundPos = instance.options.ignoreCase ? \n              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : \n              elem.indexOf(entry, foundPos + 1);\n\n          }\n        }\n        if (partial.length)\n          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))\n        return \"<ul>\" + ret.join('') + \"</ul>\";\n      }\n    }, options || {});\n  }\n});\n\n// AJAX in-place editor\n//\n// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor\n\n// Use this if you notice weird scrolling problems on some browsers,\n// the DOM might be a bit confused when this gets called so do this\n// waits 1 ms (with setTimeout) until it does the activation\nField.scrollFreeActivate = function(field) {\n  setTimeout(function() {\n    Field.activate(field);\n  }, 1);\n}\n\nAjax.InPlaceEditor = Class.create();\nAjax.InPlaceEditor.defaultHighlightColor = \"#FFFF99\";\nAjax.InPlaceEditor.prototype = {\n  initialize: function(element, url, options) {\n    this.url = url;\n    this.element = $(element);\n\n    this.options = Object.extend({\n      okButton: true,\n      okText: \"ok\",\n      cancelLink: true,\n      cancelText: \"cancel\",\n      savingText: \"Saving...\",\n      clickToEditText: \"Click to edit\",\n      okText: \"ok\",\n      rows: 1,\n      onComplete: function(transport, element) {\n        new Effect.Highlight(element, {startcolor: this.options.highlightcolor});\n      },\n      onFailure: function(transport) {\n        alert(\"Error communicating with the server: \" + transport.responseText.stripTags());\n      },\n      callback: function(form) {\n        return Form.serialize(form);\n      },\n      handleLineBreaks: true,\n      loadingText: 'Loading...',\n      savingClassName: 'inplaceeditor-saving',\n      loadingClassName: 'inplaceeditor-loading',\n      formClassName: 'inplaceeditor-form',\n      highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,\n      highlightendcolor: \"#FFFFFF\",\n      externalControl: null,\n      submitOnBlur: false,\n      ajaxOptions: {},\n      evalScripts: false\n    }, options || {});\n\n    if(!this.options.formId && this.element.id) {\n      this.options.formId = this.element.id + \"-inplaceeditor\";\n      if ($(this.options.formId)) {\n        // there's already a form with that name, don't specify an id\n        this.options.formId = null;\n      }\n    }\n    \n    if (this.options.externalControl) {\n      this.options.externalControl = $(this.options.externalControl);\n    }\n    \n    this.originalBackground = Element.getStyle(this.element, 'background-color');\n    if (!this.originalBackground) {\n      this.originalBackground = \"transparent\";\n    }\n    \n    this.element.title = this.options.clickToEditText;\n    \n    this.onclickListener = this.enterEditMode.bindAsEventListener(this);\n    this.mouseoverListener = this.enterHover.bindAsEventListener(this);\n    this.mouseoutListener = this.leaveHover.bindAsEventListener(this);\n    Event.observe(this.element, 'click', this.onclickListener);\n    Event.observe(this.element, 'mouseover', this.mouseoverListener);\n    Event.observe(this.element, 'mouseout', this.mouseoutListener);\n    if (this.options.externalControl) {\n      Event.observe(this.options.externalControl, 'click', this.onclickListener);\n      Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);\n      Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);\n    }\n  },\n  enterEditMode: function(evt) {\n    if (this.saving) return;\n    if (this.editing) return;\n    this.editing = true;\n    this.onEnterEditMode();\n    if (this.options.externalControl) {\n      Element.hide(this.options.externalControl);\n    }\n    Element.hide(this.element);\n    this.createForm();\n    this.element.parentNode.insertBefore(this.form, this.element);\n    Field.scrollFreeActivate(this.editField);\n    // stop the event to avoid a page refresh in Safari\n    if (evt) {\n      Event.stop(evt);\n    }\n    return false;\n  },\n  createForm: function() {\n    this.form = document.createElement(\"form\");\n    this.form.id = this.options.formId;\n    Element.addClassName(this.form, this.options.formClassName)\n    this.form.onsubmit = this.onSubmit.bind(this);\n\n    this.createEditField();\n\n    if (this.options.textarea) {\n      var br = document.createElement(\"br\");\n      this.form.appendChild(br);\n    }\n\n    if (this.options.okButton) {\n      okButton = document.createElement(\"input\");\n      okButton.type = \"submit\";\n      okButton.value = this.options.okText;\n      okButton.className = 'editor_ok_button';\n      this.form.appendChild(okButton);\n    }\n\n    if (this.options.cancelLink) {\n      cancelLink = document.createElement(\"a\");\n      cancelLink.href = \"#\";\n      cancelLink.appendChild(document.createTextNode(this.options.cancelText));\n      cancelLink.onclick = this.onclickCancel.bind(this);\n      cancelLink.className = 'editor_cancel';      \n      this.form.appendChild(cancelLink);\n    }\n  },\n  hasHTMLLineBreaks: function(string) {\n    if (!this.options.handleLineBreaks) return false;\n    return string.match(/<br/i) || string.match(/<p>/i);\n  },\n  convertHTMLLineBreaks: function(string) {\n    return string.replace(/<br>/gi, \"\\n\").replace(/<br\\/>/gi, \"\\n\").replace(/<\\/p>/gi, \"\\n\").replace(/<p>/gi, \"\");\n  },\n  createEditField: function() {\n    var text;\n    if(this.options.loadTextURL) {\n      text = this.options.loadingText;\n    } else {\n      text = this.getText();\n    }\n\n    var obj = this;\n    \n    if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {\n      this.options.textarea = false;\n      var textField = document.createElement(\"input\");\n      textField.obj = this;\n      textField.type = \"text\";\n      textField.name = \"value\";\n      textField.value = text;\n      textField.style.backgroundColor = this.options.highlightcolor;\n      textField.className = 'editor_field';\n      var size = this.options.size || this.options.cols || 0;\n      if (size != 0) textField.size = size;\n      if (this.options.submitOnBlur)\n        textField.onblur = this.onSubmit.bind(this);\n      this.editField = textField;\n    } else {\n      this.options.textarea = true;\n      var textArea = document.createElement(\"textarea\");\n      textArea.obj = this;\n      textArea.name = \"value\";\n      textArea.value = this.convertHTMLLineBreaks(text);\n      textArea.rows = this.options.rows;\n      textArea.cols = this.options.cols || 40;\n      textArea.className = 'editor_field';      \n      if (this.options.submitOnBlur)\n        textArea.onblur = this.onSubmit.bind(this);\n      this.editField = textArea;\n    }\n    \n    if(this.options.loadTextURL) {\n      this.loadExternalText();\n    }\n    this.form.appendChild(this.editField);\n  },\n  getText: function() {\n    return this.element.innerHTML;\n  },\n  loadExternalText: function() {\n    Element.addClassName(this.form, this.options.loadingClassName);\n    this.editField.disabled = true;\n    new Ajax.Request(\n      this.options.loadTextURL,\n      Object.extend({\n        asynchronous: true,\n        onComplete: this.onLoadedExternalText.bind(this)\n      }, this.options.ajaxOptions)\n    );\n  },\n  onLoadedExternalText: function(transport) {\n    Element.removeClassName(this.form, this.options.loadingClassName);\n    this.editField.disabled = false;\n    this.editField.value = transport.responseText.stripTags();\n  },\n  onclickCancel: function() {\n    this.onComplete();\n    this.leaveEditMode();\n    return false;\n  },\n  onFailure: function(transport) {\n    this.options.onFailure(transport);\n    if (this.oldInnerHTML) {\n      this.element.innerHTML = this.oldInnerHTML;\n      this.oldInnerHTML = null;\n    }\n    return false;\n  },\n  onSubmit: function() {\n    // onLoading resets these so we need to save them away for the Ajax call\n    var form = this.form;\n    var value = this.editField.value;\n    \n    // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...\n    // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...\n    // to be displayed indefinitely\n    this.onLoading();\n    \n    if (this.options.evalScripts) {\n      new Ajax.Request(\n        this.url, Object.extend({\n          parameters: this.options.callback(form, value),\n          onComplete: this.onComplete.bind(this),\n          onFailure: this.onFailure.bind(this),\n          asynchronous:true, \n          evalScripts:true\n        }, this.options.ajaxOptions));\n    } else  {\n      new Ajax.Updater(\n        { success: this.element,\n          // don't update on failure (this could be an option)\n          failure: null }, \n        this.url, Object.extend({\n          parameters: this.options.callback(form, value),\n          onComplete: this.onComplete.bind(this),\n          onFailure: this.onFailure.bind(this)\n        }, this.options.ajaxOptions));\n    }\n    // stop the event to avoid a page refresh in Safari\n    if (arguments.length > 1) {\n      Event.stop(arguments[0]);\n    }\n    return false;\n  },\n  onLoading: function() {\n    this.saving = true;\n    this.removeForm();\n    this.leaveHover();\n    this.showSaving();\n  },\n  showSaving: function() {\n    this.oldInnerHTML = this.element.innerHTML;\n    this.element.innerHTML = this.options.savingText;\n    Element.addClassName(this.element, this.options.savingClassName);\n    this.element.style.backgroundColor = this.originalBackground;\n    Element.show(this.element);\n  },\n  removeForm: function() {\n    if(this.form) {\n      if (this.form.parentNode) Element.remove(this.form);\n      this.form = null;\n    }\n  },\n  enterHover: function() {\n    if (this.saving) return;\n    this.element.style.backgroundColor = this.options.highlightcolor;\n    if (this.effect) {\n      this.effect.cancel();\n    }\n    Element.addClassName(this.element, this.options.hoverClassName)\n  },\n  leaveHover: function() {\n    if (this.options.backgroundColor) {\n      this.element.style.backgroundColor = this.oldBackground;\n    }\n    Element.removeClassName(this.element, this.options.hoverClassName)\n    if (this.saving) return;\n    this.effect = new Effect.Highlight(this.element, {\n      startcolor: this.options.highlightcolor,\n      endcolor: this.options.highlightendcolor,\n      restorecolor: this.originalBackground\n    });\n  },\n  leaveEditMode: function() {\n    Element.removeClassName(this.element, this.options.savingClassName);\n    this.removeForm();\n    this.leaveHover();\n    this.element.style.backgroundColor = this.originalBackground;\n    Element.show(this.element);\n    if (this.options.externalControl) {\n      Element.show(this.options.externalControl);\n    }\n    this.editing = false;\n    this.saving = false;\n    this.oldInnerHTML = null;\n    this.onLeaveEditMode();\n  },\n  onComplete: function(transport) {\n    this.leaveEditMode();\n    this.options.onComplete.bind(this)(transport, this.element);\n  },\n  onEnterEditMode: function() {},\n  onLeaveEditMode: function() {},\n  dispose: function() {\n    if (this.oldInnerHTML) {\n      this.element.innerHTML = this.oldInnerHTML;\n    }\n    this.leaveEditMode();\n    Event.stopObserving(this.element, 'click', this.onclickListener);\n    Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);\n    Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);\n    if (this.options.externalControl) {\n      Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);\n      Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);\n      Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);\n    }\n  }\n};\n\nAjax.InPlaceCollectionEditor = Class.create();\nObject.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);\nObject.extend(Ajax.InPlaceCollectionEditor.prototype, {\n  createEditField: function() {\n    if (!this.cached_selectTag) {\n      var selectTag = document.createElement(\"select\");\n      var collection = this.options.collection || [];\n      var optionTag;\n      collection.each(function(e,i) {\n        optionTag = document.createElement(\"option\");\n        optionTag.value = (e instanceof Array) ? e[0] : e;\n        if(this.options.value==optionTag.value) optionTag.selected = true;\n        optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));\n        selectTag.appendChild(optionTag);\n      }.bind(this));\n      this.cached_selectTag = selectTag;\n    }\n\n    this.editField = this.cached_selectTag;\n    if(this.options.loadTextURL) this.loadExternalText();\n    this.form.appendChild(this.editField);\n    this.options.callback = function(form, value) {\n      return \"value=\" + encodeURIComponent(value);\n    }\n  }\n});\n\n// Delayed observer, like Form.Element.Observer, \n// but waits for delay after last key input\n// Ideal for live-search fields\n\nForm.Element.DelayedObserver = Class.create();\nForm.Element.DelayedObserver.prototype = {\n  initialize: function(element, delay, callback) {\n    this.delay     = delay || 0.5;\n    this.element   = $(element);\n    this.callback  = callback;\n    this.timer     = null;\n    this.lastValue = $F(this.element); \n    Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));\n  },\n  delayedListener: function(event) {\n    if(this.lastValue == $F(this.element)) return;\n    if(this.timer) clearTimeout(this.timer);\n    this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);\n    this.lastValue = $F(this.element);\n  },\n  onTimerEvent: function() {\n    this.timer = null;\n    this.callback(this.element, $F(this.element));\n  }\n};\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/dragdrop.js",
    "content": "// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)\n//           (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)\n// \n// See scriptaculous.js for full license.\n\n/*--------------------------------------------------------------------------*/\n\nvar Droppables = {\n  drops: [],\n\n  remove: function(element) {\n    this.drops = this.drops.reject(function(d) { return d.element==$(element) });\n  },\n\n  add: function(element) {\n    element = $(element);\n    var options = Object.extend({\n      greedy:     true,\n      hoverclass: null,\n      tree:       false\n    }, arguments[1] || {});\n\n    // cache containers\n    if(options.containment) {\n      options._containers = [];\n      var containment = options.containment;\n      if((typeof containment == 'object') && \n        (containment.constructor == Array)) {\n        containment.each( function(c) { options._containers.push($(c)) });\n      } else {\n        options._containers.push($(containment));\n      }\n    }\n    \n    if(options.accept) options.accept = [options.accept].flatten();\n\n    Element.makePositioned(element); // fix IE\n    options.element = element;\n\n    this.drops.push(options);\n  },\n  \n  findDeepestChild: function(drops) {\n    deepest = drops[0];\n      \n    for (i = 1; i < drops.length; ++i)\n      if (Element.isParent(drops[i].element, deepest.element))\n        deepest = drops[i];\n    \n    return deepest;\n  },\n\n  isContained: function(element, drop) {\n    var containmentNode;\n    if(drop.tree) {\n      containmentNode = element.treeNode; \n    } else {\n      containmentNode = element.parentNode;\n    }\n    return drop._containers.detect(function(c) { return containmentNode == c });\n  },\n  \n  isAffected: function(point, element, drop) {\n    return (\n      (drop.element!=element) &&\n      ((!drop._containers) ||\n        this.isContained(element, drop)) &&\n      ((!drop.accept) ||\n        (Element.classNames(element).detect( \n          function(v) { return drop.accept.include(v) } ) )) &&\n      Position.within(drop.element, point[0], point[1]) );\n  },\n\n  deactivate: function(drop) {\n    if(drop.hoverclass)\n      Element.removeClassName(drop.element, drop.hoverclass);\n    this.last_active = null;\n  },\n\n  activate: function(drop) {\n    if(drop.hoverclass)\n      Element.addClassName(drop.element, drop.hoverclass);\n    this.last_active = drop;\n  },\n\n  show: function(point, element) {\n    if(!this.drops.length) return;\n    var affected = [];\n    \n    if(this.last_active) this.deactivate(this.last_active);\n    this.drops.each( function(drop) {\n      if(Droppables.isAffected(point, element, drop))\n        affected.push(drop);\n    });\n        \n    if(affected.length>0) {\n      drop = Droppables.findDeepestChild(affected);\n      Position.within(drop.element, point[0], point[1]);\n      if(drop.onHover)\n        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));\n      \n      Droppables.activate(drop);\n    }\n  },\n\n  fire: function(event, element) {\n    if(!this.last_active) return;\n    Position.prepare();\n\n    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))\n      if (this.last_active.onDrop) \n        this.last_active.onDrop(element, this.last_active.element, event);\n  },\n\n  reset: function() {\n    if(this.last_active)\n      this.deactivate(this.last_active);\n  }\n}\n\nvar Draggables = {\n  drags: [],\n  observers: [],\n  \n  register: function(draggable) {\n    if(this.drags.length == 0) {\n      this.eventMouseUp   = this.endDrag.bindAsEventListener(this);\n      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);\n      this.eventKeypress  = this.keyPress.bindAsEventListener(this);\n      \n      Event.observe(document, \"mouseup\", this.eventMouseUp);\n      Event.observe(document, \"mousemove\", this.eventMouseMove);\n      Event.observe(document, \"keypress\", this.eventKeypress);\n    }\n    this.drags.push(draggable);\n  },\n  \n  unregister: function(draggable) {\n    this.drags = this.drags.reject(function(d) { return d==draggable });\n    if(this.drags.length == 0) {\n      Event.stopObserving(document, \"mouseup\", this.eventMouseUp);\n      Event.stopObserving(document, \"mousemove\", this.eventMouseMove);\n      Event.stopObserving(document, \"keypress\", this.eventKeypress);\n    }\n  },\n  \n  activate: function(draggable) {\n    window.focus(); // allows keypress events if window isn't currently focused, fails for Safari\n    this.activeDraggable = draggable;\n  },\n  \n  deactivate: function() {\n    this.activeDraggable = null;\n  },\n  \n  updateDrag: function(event) {\n    if(!this.activeDraggable) return;\n    var pointer = [Event.pointerX(event), Event.pointerY(event)];\n    // Mozilla-based browsers fire successive mousemove events with\n    // the same coordinates, prevent needless redrawing (moz bug?)\n    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;\n    this._lastPointer = pointer;\n    this.activeDraggable.updateDrag(event, pointer);\n  },\n  \n  endDrag: function(event) {\n    if(!this.activeDraggable) return;\n    this._lastPointer = null;\n    this.activeDraggable.endDrag(event);\n    this.activeDraggable = null;\n  },\n  \n  keyPress: function(event) {\n    if(this.activeDraggable)\n      this.activeDraggable.keyPress(event);\n  },\n  \n  addObserver: function(observer) {\n    this.observers.push(observer);\n    this._cacheObserverCallbacks();\n  },\n  \n  removeObserver: function(element) {  // element instead of observer fixes mem leaks\n    this.observers = this.observers.reject( function(o) { return o.element==element });\n    this._cacheObserverCallbacks();\n  },\n  \n  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'\n    if(this[eventName+'Count'] > 0)\n      this.observers.each( function(o) {\n        if(o[eventName]) o[eventName](eventName, draggable, event);\n      });\n  },\n  \n  _cacheObserverCallbacks: function() {\n    ['onStart','onEnd','onDrag'].each( function(eventName) {\n      Draggables[eventName+'Count'] = Draggables.observers.select(\n        function(o) { return o[eventName]; }\n      ).length;\n    });\n  }\n}\n\n/*--------------------------------------------------------------------------*/\n\nvar Draggable = Class.create();\nDraggable.prototype = {\n  initialize: function(element) {\n    var options = Object.extend({\n      handle: false,\n      starteffect: function(element) {\n        element._opacity = Element.getOpacity(element); \n        new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); \n      },\n      reverteffect: function(element, top_offset, left_offset) {\n        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;\n        element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur});\n      },\n      endeffect: function(element) {\n        var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0\n        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity}); \n      },\n      zindex: 1000,\n      revert: false,\n      scroll: false,\n      scrollSensitivity: 20,\n      scrollSpeed: 15,\n      snap: false   // false, or xy or [x,y] or function(x,y){ return [x,y] }\n    }, arguments[1] || {});\n\n    this.element = $(element);\n    \n    if(options.handle && (typeof options.handle == 'string')) {\n      var h = Element.childrenWithClassName(this.element, options.handle, true);\n      if(h.length>0) this.handle = h[0];\n    }\n    if(!this.handle) this.handle = $(options.handle);\n    if(!this.handle) this.handle = this.element;\n    \n    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML)\n      options.scroll = $(options.scroll);\n\n    Element.makePositioned(this.element); // fix IE    \n\n    this.delta    = this.currentDelta();\n    this.options  = options;\n    this.dragging = false;   \n\n    this.eventMouseDown = this.initDrag.bindAsEventListener(this);\n    Event.observe(this.handle, \"mousedown\", this.eventMouseDown);\n    \n    Draggables.register(this);\n  },\n  \n  destroy: function() {\n    Event.stopObserving(this.handle, \"mousedown\", this.eventMouseDown);\n    Draggables.unregister(this);\n  },\n  \n  currentDelta: function() {\n    return([\n      parseInt(Element.getStyle(this.element,'left') || '0'),\n      parseInt(Element.getStyle(this.element,'top') || '0')]);\n  },\n  \n  initDrag: function(event) {\n    if(Event.isLeftClick(event)) {    \n      // abort on form elements, fixes a Firefox issue\n      var src = Event.element(event);\n      if(src.tagName && (\n        src.tagName=='INPUT' ||\n        src.tagName=='SELECT' ||\n        src.tagName=='OPTION' ||\n        src.tagName=='BUTTON' ||\n        src.tagName=='TEXTAREA')) return;\n        \n      if(this.element._revert) {\n        this.element._revert.cancel();\n        this.element._revert = null;\n      }\n      \n      var pointer = [Event.pointerX(event), Event.pointerY(event)];\n      var pos     = Position.cumulativeOffset(this.element);\n      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });\n      \n      Draggables.activate(this);\n      Event.stop(event);\n    }\n  },\n  \n  startDrag: function(event) {\n    this.dragging = true;\n    \n    if(this.options.zindex) {\n      this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);\n      this.element.style.zIndex = this.options.zindex;\n    }\n    \n    if(this.options.ghosting) {\n      this._clone = this.element.cloneNode(true);\n      Position.absolutize(this.element);\n      this.element.parentNode.insertBefore(this._clone, this.element);\n    }\n    \n    if(this.options.scroll) {\n      if (this.options.scroll == window) {\n        var where = this._getWindowScroll(this.options.scroll);\n        this.originalScrollLeft = where.left;\n        this.originalScrollTop = where.top;\n      } else {\n        this.originalScrollLeft = this.options.scroll.scrollLeft;\n        this.originalScrollTop = this.options.scroll.scrollTop;\n      }\n    }\n    \n    Draggables.notify('onStart', this, event);\n    if(this.options.starteffect) this.options.starteffect(this.element);\n  },\n  \n  updateDrag: function(event, pointer) {\n    if(!this.dragging) this.startDrag(event);\n    Position.prepare();\n    Droppables.show(pointer, this.element);\n    Draggables.notify('onDrag', this, event);\n    this.draw(pointer);\n    if(this.options.change) this.options.change(this);\n    \n    if(this.options.scroll) {\n      this.stopScrolling();\n      \n      var p;\n      if (this.options.scroll == window) {\n        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }\n      } else {\n        p = Position.page(this.options.scroll);\n        p[0] += this.options.scroll.scrollLeft;\n        p[1] += this.options.scroll.scrollTop;\n        p.push(p[0]+this.options.scroll.offsetWidth);\n        p.push(p[1]+this.options.scroll.offsetHeight);\n      }\n      var speed = [0,0];\n      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);\n      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);\n      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);\n      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);\n      this.startScrolling(speed);\n    }\n    \n    // fix AppleWebKit rendering\n    if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);\n    \n    Event.stop(event);\n  },\n  \n  finishDrag: function(event, success) {\n    this.dragging = false;\n\n    if(this.options.ghosting) {\n      Position.relativize(this.element);\n      Element.remove(this._clone);\n      this._clone = null;\n    }\n\n    if(success) Droppables.fire(event, this.element);\n    Draggables.notify('onEnd', this, event);\n\n    var revert = this.options.revert;\n    if(revert && typeof revert == 'function') revert = revert(this.element);\n    \n    var d = this.currentDelta();\n    if(revert && this.options.reverteffect) {\n      this.options.reverteffect(this.element, \n        d[1]-this.delta[1], d[0]-this.delta[0]);\n    } else {\n      this.delta = d;\n    }\n\n    if(this.options.zindex)\n      this.element.style.zIndex = this.originalZ;\n\n    if(this.options.endeffect) \n      this.options.endeffect(this.element);\n\n    Draggables.deactivate(this);\n    Droppables.reset();\n  },\n  \n  keyPress: function(event) {\n    if(event.keyCode!=Event.KEY_ESC) return;\n    this.finishDrag(event, false);\n    Event.stop(event);\n  },\n  \n  endDrag: function(event) {\n    if(!this.dragging) return;\n    this.stopScrolling();\n    this.finishDrag(event, true);\n    Event.stop(event);\n  },\n  \n  draw: function(point) {\n    var pos = Position.cumulativeOffset(this.element);\n    var d = this.currentDelta();\n    pos[0] -= d[0]; pos[1] -= d[1];\n    \n    if(this.options.scroll && (this.options.scroll != window)) {\n      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;\n      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;\n    }\n    \n    var p = [0,1].map(function(i){ \n      return (point[i]-pos[i]-this.offset[i]) \n    }.bind(this));\n    \n    if(this.options.snap) {\n      if(typeof this.options.snap == 'function') {\n        p = this.options.snap(p[0],p[1],this);\n      } else {\n      if(this.options.snap instanceof Array) {\n        p = p.map( function(v, i) {\n          return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))\n      } else {\n        p = p.map( function(v) {\n          return Math.round(v/this.options.snap)*this.options.snap }.bind(this))\n      }\n    }}\n    \n    var style = this.element.style;\n    if((!this.options.constraint) || (this.options.constraint=='horizontal'))\n      style.left = p[0] + \"px\";\n    if((!this.options.constraint) || (this.options.constraint=='vertical'))\n      style.top  = p[1] + \"px\";\n    if(style.visibility==\"hidden\") style.visibility = \"\"; // fix gecko rendering\n  },\n  \n  stopScrolling: function() {\n    if(this.scrollInterval) {\n      clearInterval(this.scrollInterval);\n      this.scrollInterval = null;\n      Draggables._lastScrollPointer = null;\n    }\n  },\n  \n  startScrolling: function(speed) {\n    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];\n    this.lastScrolled = new Date();\n    this.scrollInterval = setInterval(this.scroll.bind(this), 10);\n  },\n  \n  scroll: function() {\n    var current = new Date();\n    var delta = current - this.lastScrolled;\n    this.lastScrolled = current;\n    if(this.options.scroll == window) {\n      with (this._getWindowScroll(this.options.scroll)) {\n        if (this.scrollSpeed[0] || this.scrollSpeed[1]) {\n          var d = delta / 1000;\n          this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );\n        }\n      }\n    } else {\n      this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;\n      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;\n    }\n    \n    Position.prepare();\n    Droppables.show(Draggables._lastPointer, this.element);\n    Draggables.notify('onDrag', this);\n    Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);\n    Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;\n    Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;\n    if (Draggables._lastScrollPointer[0] < 0)\n      Draggables._lastScrollPointer[0] = 0;\n    if (Draggables._lastScrollPointer[1] < 0)\n      Draggables._lastScrollPointer[1] = 0;\n    this.draw(Draggables._lastScrollPointer);\n    \n    if(this.options.change) this.options.change(this);\n  },\n  \n  _getWindowScroll: function(w) {\n    var T, L, W, H;\n    with (w.document) {\n      if (w.document.documentElement && documentElement.scrollTop) {\n        T = documentElement.scrollTop;\n        L = documentElement.scrollLeft;\n      } else if (w.document.body) {\n        T = body.scrollTop;\n        L = body.scrollLeft;\n      }\n      if (w.innerWidth) {\n        W = w.innerWidth;\n        H = w.innerHeight;\n      } else if (w.document.documentElement && documentElement.clientWidth) {\n        W = documentElement.clientWidth;\n        H = documentElement.clientHeight;\n      } else {\n        W = body.offsetWidth;\n        H = body.offsetHeight\n      }\n    }\n    return { top: T, left: L, width: W, height: H };\n  }\n}\n\n/*--------------------------------------------------------------------------*/\n\nvar SortableObserver = Class.create();\nSortableObserver.prototype = {\n  initialize: function(element, observer) {\n    this.element   = $(element);\n    this.observer  = observer;\n    this.lastValue = Sortable.serialize(this.element);\n  },\n  \n  onStart: function() {\n    this.lastValue = Sortable.serialize(this.element);\n  },\n  \n  onEnd: function() {\n    Sortable.unmark();\n    if(this.lastValue != Sortable.serialize(this.element))\n      this.observer(this.element)\n  }\n}\n\nvar Sortable = {\n  sortables: {},\n  \n  _findRootElement: function(element) {\n    while (element.tagName != \"BODY\") {  \n      if(element.id && Sortable.sortables[element.id]) return element;\n      element = element.parentNode;\n    }\n  },\n\n  options: function(element) {\n    element = Sortable._findRootElement($(element));\n    if(!element) return;\n    return Sortable.sortables[element.id];\n  },\n  \n  destroy: function(element){\n    var s = Sortable.options(element);\n    \n    if(s) {\n      Draggables.removeObserver(s.element);\n      s.droppables.each(function(d){ Droppables.remove(d) });\n      s.draggables.invoke('destroy');\n      \n      delete Sortable.sortables[s.element.id];\n    }\n  },\n\n  create: function(element) {\n    element = $(element);\n    var options = Object.extend({ \n      element:     element,\n      tag:         'li',       // assumes li children, override with tag: 'tagname'\n      dropOnEmpty: false,\n      tree:        false,\n      treeTag:     'ul',\n      overlap:     'vertical', // one of 'vertical', 'horizontal'\n      constraint:  'vertical', // one of 'vertical', 'horizontal', false\n      containment: element,    // also takes array of elements (or id's); or false\n      handle:      false,      // or a CSS class\n      only:        false,\n      hoverclass:  null,\n      ghosting:    false,\n      scroll:      false,\n      scrollSensitivity: 20,\n      scrollSpeed: 15,\n      format:      /^[^_]*_(.*)$/,\n      onChange:    Prototype.emptyFunction,\n      onUpdate:    Prototype.emptyFunction\n    }, arguments[1] || {});\n\n    // clear any old sortable with same element\n    this.destroy(element);\n\n    // build options for the draggables\n    var options_for_draggable = {\n      revert:      true,\n      scroll:      options.scroll,\n      scrollSpeed: options.scrollSpeed,\n      scrollSensitivity: options.scrollSensitivity,\n      ghosting:    options.ghosting,\n      constraint:  options.constraint,\n      handle:      options.handle };\n\n    if(options.starteffect)\n      options_for_draggable.starteffect = options.starteffect;\n\n    if(options.reverteffect)\n      options_for_draggable.reverteffect = options.reverteffect;\n    else\n      if(options.ghosting) options_for_draggable.reverteffect = function(element) {\n        element.style.top  = 0;\n        element.style.left = 0;\n      };\n\n    if(options.endeffect)\n      options_for_draggable.endeffect = options.endeffect;\n\n    if(options.zindex)\n      options_for_draggable.zindex = options.zindex;\n\n    // build options for the droppables  \n    var options_for_droppable = {\n      overlap:     options.overlap,\n      containment: options.containment,\n      tree:        options.tree,\n      hoverclass:  options.hoverclass,\n      onHover:     Sortable.onHover\n      //greedy:      !options.dropOnEmpty\n    }\n    \n    var options_for_tree = {\n      onHover:      Sortable.onEmptyHover,\n      overlap:      options.overlap,\n      containment:  options.containment,\n      hoverclass:   options.hoverclass\n    }\n\n    // fix for gecko engine\n    Element.cleanWhitespace(element); \n\n    options.draggables = [];\n    options.droppables = [];\n\n    // drop on empty handling\n    if(options.dropOnEmpty || options.tree) {\n      Droppables.add(element, options_for_tree);\n      options.droppables.push(element);\n    }\n\n    (this.findElements(element, options) || []).each( function(e) {\n      // handles are per-draggable\n      var handle = options.handle ? \n        Element.childrenWithClassName(e, options.handle)[0] : e;    \n      options.draggables.push(\n        new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));\n      Droppables.add(e, options_for_droppable);\n      if(options.tree) e.treeNode = element;\n      options.droppables.push(e);      \n    });\n    \n    if(options.tree) {\n      (Sortable.findTreeElements(element, options) || []).each( function(e) {\n        Droppables.add(e, options_for_tree);\n        e.treeNode = element;\n        options.droppables.push(e);\n      });\n    }\n\n    // keep reference\n    this.sortables[element.id] = options;\n\n    // for onupdate\n    Draggables.addObserver(new SortableObserver(element, options.onUpdate));\n\n  },\n\n  // return all suitable-for-sortable elements in a guaranteed order\n  findElements: function(element, options) {\n    return Element.findChildren(\n      element, options.only, options.tree ? true : false, options.tag);\n  },\n  \n  findTreeElements: function(element, options) {\n    return Element.findChildren(\n      element, options.only, options.tree ? true : false, options.treeTag);\n  },\n\n  onHover: function(element, dropon, overlap) {\n    if(Element.isParent(dropon, element)) return;\n\n    if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {\n      return;\n    } else if(overlap>0.5) {\n      Sortable.mark(dropon, 'before');\n      if(dropon.previousSibling != element) {\n        var oldParentNode = element.parentNode;\n        element.style.visibility = \"hidden\"; // fix gecko rendering\n        dropon.parentNode.insertBefore(element, dropon);\n        if(dropon.parentNode!=oldParentNode) \n          Sortable.options(oldParentNode).onChange(element);\n        Sortable.options(dropon.parentNode).onChange(element);\n      }\n    } else {\n      Sortable.mark(dropon, 'after');\n      var nextElement = dropon.nextSibling || null;\n      if(nextElement != element) {\n        var oldParentNode = element.parentNode;\n        element.style.visibility = \"hidden\"; // fix gecko rendering\n        dropon.parentNode.insertBefore(element, nextElement);\n        if(dropon.parentNode!=oldParentNode) \n          Sortable.options(oldParentNode).onChange(element);\n        Sortable.options(dropon.parentNode).onChange(element);\n      }\n    }\n  },\n  \n  onEmptyHover: function(element, dropon, overlap) {\n    var oldParentNode = element.parentNode;\n    var droponOptions = Sortable.options(dropon);\n        \n    if(!Element.isParent(dropon, element)) {\n      var index;\n      \n      var children = Sortable.findElements(dropon, {tag: droponOptions.tag});\n      var child = null;\n            \n      if(children) {\n        var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);\n        \n        for (index = 0; index < children.length; index += 1) {\n          if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {\n            offset -= Element.offsetSize (children[index], droponOptions.overlap);\n          } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {\n            child = index + 1 < children.length ? children[index + 1] : null;\n            break;\n          } else {\n            child = children[index];\n            break;\n          }\n        }\n      }\n      \n      dropon.insertBefore(element, child);\n      \n      Sortable.options(oldParentNode).onChange(element);\n      droponOptions.onChange(element);\n    }\n  },\n\n  unmark: function() {\n    if(Sortable._marker) Element.hide(Sortable._marker);\n  },\n\n  mark: function(dropon, position) {\n    // mark on ghosting only\n    var sortable = Sortable.options(dropon.parentNode);\n    if(sortable && !sortable.ghosting) return; \n\n    if(!Sortable._marker) {\n      Sortable._marker = $('dropmarker') || document.createElement('DIV');\n      Element.hide(Sortable._marker);\n      Element.addClassName(Sortable._marker, 'dropmarker');\n      Sortable._marker.style.position = 'absolute';\n      document.getElementsByTagName(\"body\").item(0).appendChild(Sortable._marker);\n    }    \n    var offsets = Position.cumulativeOffset(dropon);\n    Sortable._marker.style.left = offsets[0] + 'px';\n    Sortable._marker.style.top = offsets[1] + 'px';\n    \n    if(position=='after')\n      if(sortable.overlap == 'horizontal') \n        Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px';\n      else\n        Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';\n    \n    Element.show(Sortable._marker);\n  },\n  \n  _tree: function(element, options, parent) {\n    var children = Sortable.findElements(element, options) || [];\n  \n    for (var i = 0; i < children.length; ++i) {\n      var match = children[i].id.match(options.format);\n\n      if (!match) continue;\n      \n      var child = {\n        id: encodeURIComponent(match ? match[1] : null),\n        element: element,\n        parent: parent,\n        children: new Array,\n        position: parent.children.length,\n        container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase())\n      }\n      \n      /* Get the element containing the children and recurse over it */\n      if (child.container)\n        this._tree(child.container, options, child)\n      \n      parent.children.push (child);\n    }\n\n    return parent; \n  },\n\n  /* Finds the first element of the given tag type within a parent element.\n    Used for finding the first LI[ST] within a L[IST]I[TEM].*/\n  _findChildrenElement: function (element, containerTag) {\n    if (element && element.hasChildNodes)\n      for (var i = 0; i < element.childNodes.length; ++i)\n        if (element.childNodes[i].tagName == containerTag)\n          return element.childNodes[i];\n  \n    return null;\n  },\n\n  tree: function(element) {\n    element = $(element);\n    var sortableOptions = this.options(element);\n    var options = Object.extend({\n      tag: sortableOptions.tag,\n      treeTag: sortableOptions.treeTag,\n      only: sortableOptions.only,\n      name: element.id,\n      format: sortableOptions.format\n    }, arguments[1] || {});\n    \n    var root = {\n      id: null,\n      parent: null,\n      children: new Array,\n      container: element,\n      position: 0\n    }\n    \n    return Sortable._tree (element, options, root);\n  },\n\n  /* Construct a [i] index for a particular node */\n  _constructIndex: function(node) {\n    var index = '';\n    do {\n      if (node.id) index = '[' + node.position + ']' + index;\n    } while ((node = node.parent) != null);\n    return index;\n  },\n\n  sequence: function(element) {\n    element = $(element);\n    var options = Object.extend(this.options(element), arguments[1] || {});\n    \n    return $(this.findElements(element, options) || []).map( function(item) {\n      return item.id.match(options.format) ? item.id.match(options.format)[1] : '';\n    });\n  },\n\n  setSequence: function(element, new_sequence) {\n    element = $(element);\n    var options = Object.extend(this.options(element), arguments[2] || {});\n    \n    var nodeMap = {};\n    this.findElements(element, options).each( function(n) {\n        if (n.id.match(options.format))\n            nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];\n        n.parentNode.removeChild(n);\n    });\n   \n    new_sequence.each(function(ident) {\n      var n = nodeMap[ident];\n      if (n) {\n        n[1].appendChild(n[0]);\n        delete nodeMap[ident];\n      }\n    });\n  },\n  \n  serialize: function(element) {\n    element = $(element);\n    var options = Object.extend(Sortable.options(element), arguments[1] || {});\n    var name = encodeURIComponent(\n      (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);\n    \n    if (options.tree) {\n      return Sortable.tree(element, arguments[1]).children.map( function (item) {\n        return [name + Sortable._constructIndex(item) + \"=\" + \n                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));\n      }).flatten().join('&');\n    } else {\n      return Sortable.sequence(element, arguments[1]).map( function(item) {\n        return name + \"[]=\" + encodeURIComponent(item);\n      }).join('&');\n    }\n  }\n}\n\n/* Returns true if child is contained within element */\nElement.isParent = function(child, element) {\n  if (!child.parentNode || child == element) return false;\n\n  if (child.parentNode == element) return true;\n\n  return Element.isParent(child.parentNode, element);\n}\n\nElement.findChildren = function(element, only, recursive, tagName) {    \n  if(!element.hasChildNodes()) return null;\n  tagName = tagName.toUpperCase();\n  if(only) only = [only].flatten();\n  var elements = [];\n  $A(element.childNodes).each( function(e) {\n    if(e.tagName && e.tagName.toUpperCase()==tagName &&\n      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))\n        elements.push(e);\n    if(recursive) {\n      var grandchildren = Element.findChildren(e, only, recursive, tagName);\n      if(grandchildren) elements.push(grandchildren);\n    }\n  });\n\n  return (elements.length>0 ? elements.flatten() : []);\n}\n\nElement.offsetSize = function (element, type) {\n  if (type == 'vertical' || type == 'height')\n    return element.offsetHeight;\n  else\n    return element.offsetWidth;\n}"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/effects.js",
    "content": "// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)\n// Contributors:\n//  Justin Palmer (http://encytemedia.com/)\n//  Mark Pilgrim (http://diveintomark.org/)\n//  Martin Bialasinki\n// \n// See scriptaculous.js for full license.  \n\n// converts rgb() and #xxx to #xxxxxx format,  \n// returns self (or first argument) if not convertable  \nString.prototype.parseColor = function() {  \n  var color = '#';  \n  if(this.slice(0,4) == 'rgb(') {  \n    var cols = this.slice(4,this.length-1).split(',');  \n    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  \n  } else {  \n    if(this.slice(0,1) == '#') {  \n      if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  \n      if(this.length==7) color = this.toLowerCase();  \n    }  \n  }  \n  return(color.length==7 ? color : (arguments[0] || this));  \n}\n\n/*--------------------------------------------------------------------------*/\n\nElement.collectTextNodes = function(element) {  \n  return $A($(element).childNodes).collect( function(node) {\n    return (node.nodeType==3 ? node.nodeValue : \n      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));\n  }).flatten().join('');\n}\n\nElement.collectTextNodesIgnoreClass = function(element, className) {  \n  return $A($(element).childNodes).collect( function(node) {\n    return (node.nodeType==3 ? node.nodeValue : \n      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? \n        Element.collectTextNodesIgnoreClass(node, className) : ''));\n  }).flatten().join('');\n}\n\nElement.setContentZoom = function(element, percent) {\n  element = $(element);  \n  Element.setStyle(element, {fontSize: (percent/100) + 'em'});   \n  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);\n}\n\nElement.getOpacity = function(element){  \n  var opacity;\n  if (opacity = Element.getStyle(element, 'opacity'))  \n    return parseFloat(opacity);  \n  if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\\(opacity=(.*)\\)/))  \n    if(opacity[1]) return parseFloat(opacity[1]) / 100;  \n  return 1.0;  \n}\n\nElement.setOpacity = function(element, value){  \n  element= $(element);  \n  if (value == 1){\n    Element.setStyle(element, { opacity: \n      (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? \n      0.999999 : null });\n    if(/MSIE/.test(navigator.userAgent))  \n      Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\\([^\\)]*\\)/gi,'')});  \n  } else {  \n    if(value < 0.00001) value = 0;  \n    Element.setStyle(element, {opacity: value});\n    if(/MSIE/.test(navigator.userAgent))  \n     Element.setStyle(element, \n       { filter: Element.getStyle(element,'filter').replace(/alpha\\([^\\)]*\\)/gi,'') +\n                 'alpha(opacity='+value*100+')' });  \n  }\n}  \n \nElement.getInlineOpacity = function(element){  \n  return $(element).style.opacity || '';\n}  \n\nElement.childrenWithClassName = function(element, className, findFirst) {\n  var classNameRegExp = new RegExp(\"(^|\\\\s)\" + className + \"(\\\\s|$)\");\n  var results = $A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) { \n    return (c.className && c.className.match(classNameRegExp));\n  });\n  if(!results) results = [];\n  return results;\n}\n\nElement.forceRerendering = function(element) {\n  try {\n    element = $(element);\n    var n = document.createTextNode(' ');\n    element.appendChild(n);\n    element.removeChild(n);\n  } catch(e) { }\n};\n\n/*--------------------------------------------------------------------------*/\n\nArray.prototype.call = function() {\n  var args = arguments;\n  this.each(function(f){ f.apply(this, args) });\n}\n\n/*--------------------------------------------------------------------------*/\n\nvar Effect = {\n  tagifyText: function(element) {\n    var tagifyStyle = 'position:relative';\n    if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1';\n    element = $(element);\n    $A(element.childNodes).each( function(child) {\n      if(child.nodeType==3) {\n        child.nodeValue.toArray().each( function(character) {\n          element.insertBefore(\n            Builder.node('span',{style: tagifyStyle},\n              character == ' ' ? String.fromCharCode(160) : character), \n              child);\n        });\n        Element.remove(child);\n      }\n    });\n  },\n  multiple: function(element, effect) {\n    var elements;\n    if(((typeof element == 'object') || \n        (typeof element == 'function')) && \n       (element.length))\n      elements = element;\n    else\n      elements = $(element).childNodes;\n      \n    var options = Object.extend({\n      speed: 0.1,\n      delay: 0.0\n    }, arguments[2] || {});\n    var masterDelay = options.delay;\n\n    $A(elements).each( function(element, index) {\n      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));\n    });\n  },\n  PAIRS: {\n    'slide':  ['SlideDown','SlideUp'],\n    'blind':  ['BlindDown','BlindUp'],\n    'appear': ['Appear','Fade']\n  },\n  toggle: function(element, effect) {\n    element = $(element);\n    effect = (effect || 'appear').toLowerCase();\n    var options = Object.extend({\n      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }\n    }, arguments[2] || {});\n    Effect[element.visible() ? \n      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);\n  }\n};\n\nvar Effect2 = Effect; // deprecated\n\n/* ------------- transitions ------------- */\n\nEffect.Transitions = {}\n\nEffect.Transitions.linear = function(pos) {\n  return pos;\n}\nEffect.Transitions.sinoidal = function(pos) {\n  return (-Math.cos(pos*Math.PI)/2) + 0.5;\n}\nEffect.Transitions.reverse  = function(pos) {\n  return 1-pos;\n}\nEffect.Transitions.flicker = function(pos) {\n  return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;\n}\nEffect.Transitions.wobble = function(pos) {\n  return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;\n}\nEffect.Transitions.pulse = function(pos) {\n  return (Math.floor(pos*10) % 2 == 0 ? \n    (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10)));\n}\nEffect.Transitions.none = function(pos) {\n  return 0;\n}\nEffect.Transitions.full = function(pos) {\n  return 1;\n}\n\n/* ------------- core effects ------------- */\n\nEffect.ScopedQueue = Class.create();\nObject.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {\n  initialize: function() {\n    this.effects  = [];\n    this.interval = null;\n  },\n  _each: function(iterator) {\n    this.effects._each(iterator);\n  },\n  add: function(effect) {\n    var timestamp = new Date().getTime();\n    \n    var position = (typeof effect.options.queue == 'string') ? \n      effect.options.queue : effect.options.queue.position;\n    \n    switch(position) {\n      case 'front':\n        // move unstarted effects after this effect  \n        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {\n            e.startOn  += effect.finishOn;\n            e.finishOn += effect.finishOn;\n          });\n        break;\n      case 'end':\n        // start effect after last queued effect has finished\n        timestamp = this.effects.pluck('finishOn').max() || timestamp;\n        break;\n    }\n    \n    effect.startOn  += timestamp;\n    effect.finishOn += timestamp;\n\n    if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))\n      this.effects.push(effect);\n    \n    if(!this.interval) \n      this.interval = setInterval(this.loop.bind(this), 40);\n  },\n  remove: function(effect) {\n    this.effects = this.effects.reject(function(e) { return e==effect });\n    if(this.effects.length == 0) {\n      clearInterval(this.interval);\n      this.interval = null;\n    }\n  },\n  loop: function() {\n    var timePos = new Date().getTime();\n    this.effects.invoke('loop', timePos);\n  }\n});\n\nEffect.Queues = {\n  instances: $H(),\n  get: function(queueName) {\n    if(typeof queueName != 'string') return queueName;\n    \n    if(!this.instances[queueName])\n      this.instances[queueName] = new Effect.ScopedQueue();\n      \n    return this.instances[queueName];\n  }\n}\nEffect.Queue = Effect.Queues.get('global');\n\nEffect.DefaultOptions = {\n  transition: Effect.Transitions.sinoidal,\n  duration:   1.0,   // seconds\n  fps:        25.0,  // max. 25fps due to Effect.Queue implementation\n  sync:       false, // true for combining\n  from:       0.0,\n  to:         1.0,\n  delay:      0.0,\n  queue:      'parallel'\n}\n\nEffect.Base = function() {};\nEffect.Base.prototype = {\n  position: null,\n  start: function(options) {\n    this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});\n    this.currentFrame = 0;\n    this.state        = 'idle';\n    this.startOn      = this.options.delay*1000;\n    this.finishOn     = this.startOn + (this.options.duration*1000);\n    this.event('beforeStart');\n    if(!this.options.sync)\n      Effect.Queues.get(typeof this.options.queue == 'string' ? \n        'global' : this.options.queue.scope).add(this);\n  },\n  loop: function(timePos) {\n    if(timePos >= this.startOn) {\n      if(timePos >= this.finishOn) {\n        this.render(1.0);\n        this.cancel();\n        this.event('beforeFinish');\n        if(this.finish) this.finish(); \n        this.event('afterFinish');\n        return;  \n      }\n      var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);\n      var frame = Math.round(pos * this.options.fps * this.options.duration);\n      if(frame > this.currentFrame) {\n        this.render(pos);\n        this.currentFrame = frame;\n      }\n    }\n  },\n  render: function(pos) {\n    if(this.state == 'idle') {\n      this.state = 'running';\n      this.event('beforeSetup');\n      if(this.setup) this.setup();\n      this.event('afterSetup');\n    }\n    if(this.state == 'running') {\n      if(this.options.transition) pos = this.options.transition(pos);\n      pos *= (this.options.to-this.options.from);\n      pos += this.options.from;\n      this.position = pos;\n      this.event('beforeUpdate');\n      if(this.update) this.update(pos);\n      this.event('afterUpdate');\n    }\n  },\n  cancel: function() {\n    if(!this.options.sync)\n      Effect.Queues.get(typeof this.options.queue == 'string' ? \n        'global' : this.options.queue.scope).remove(this);\n    this.state = 'finished';\n  },\n  event: function(eventName) {\n    if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);\n    if(this.options[eventName]) this.options[eventName](this);\n  },\n  inspect: function() {\n    return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';\n  }\n}\n\nEffect.Parallel = Class.create();\nObject.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {\n  initialize: function(effects) {\n    this.effects = effects || [];\n    this.start(arguments[1]);\n  },\n  update: function(position) {\n    this.effects.invoke('render', position);\n  },\n  finish: function(position) {\n    this.effects.each( function(effect) {\n      effect.render(1.0);\n      effect.cancel();\n      effect.event('beforeFinish');\n      if(effect.finish) effect.finish(position);\n      effect.event('afterFinish');\n    });\n  }\n});\n\nEffect.Opacity = Class.create();\nObject.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {\n  initialize: function(element) {\n    this.element = $(element);\n    // make this work on IE on elements without 'layout'\n    if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))\n      this.element.setStyle({zoom: 1});\n    var options = Object.extend({\n      from: this.element.getOpacity() || 0.0,\n      to:   1.0\n    }, arguments[1] || {});\n    this.start(options);\n  },\n  update: function(position) {\n    this.element.setOpacity(position);\n  }\n});\n\nEffect.Move = Class.create();\nObject.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {\n  initialize: function(element) {\n    this.element = $(element);\n    var options = Object.extend({\n      x:    0,\n      y:    0,\n      mode: 'relative'\n    }, arguments[1] || {});\n    this.start(options);\n  },\n  setup: function() {\n    // Bug in Opera: Opera returns the \"real\" position of a static element or\n    // relative element that does not have top/left explicitly set.\n    // ==> Always set top and left for position relative elements in your stylesheets \n    // (to 0 if you do not need them) \n    this.element.makePositioned();\n    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');\n    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');\n    if(this.options.mode == 'absolute') {\n      // absolute movement, so we need to calc deltaX and deltaY\n      this.options.x = this.options.x - this.originalLeft;\n      this.options.y = this.options.y - this.originalTop;\n    }\n  },\n  update: function(position) {\n    this.element.setStyle({\n      left: this.options.x  * position + this.originalLeft + 'px',\n      top:  this.options.y  * position + this.originalTop  + 'px'\n    });\n  }\n});\n\n// for backwards compatibility\nEffect.MoveBy = function(element, toTop, toLeft) {\n  return new Effect.Move(element, \n    Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));\n};\n\nEffect.Scale = Class.create();\nObject.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {\n  initialize: function(element, percent) {\n    this.element = $(element)\n    var options = Object.extend({\n      scaleX: true,\n      scaleY: true,\n      scaleContent: true,\n      scaleFromCenter: false,\n      scaleMode: 'box',        // 'box' or 'contents' or {} with provided values\n      scaleFrom: 100.0,\n      scaleTo:   percent\n    }, arguments[2] || {});\n    this.start(options);\n  },\n  setup: function() {\n    this.restoreAfterFinish = this.options.restoreAfterFinish || false;\n    this.elementPositioning = this.element.getStyle('position');\n    \n    this.originalStyle = {};\n    ['top','left','width','height','fontSize'].each( function(k) {\n      this.originalStyle[k] = this.element.style[k];\n    }.bind(this));\n      \n    this.originalTop  = this.element.offsetTop;\n    this.originalLeft = this.element.offsetLeft;\n    \n    var fontSize = this.element.getStyle('font-size') || '100%';\n    ['em','px','%'].each( function(fontSizeType) {\n      if(fontSize.indexOf(fontSizeType)>0) {\n        this.fontSize     = parseFloat(fontSize);\n        this.fontSizeType = fontSizeType;\n      }\n    }.bind(this));\n    \n    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;\n    \n    this.dims = null;\n    if(this.options.scaleMode=='box')\n      this.dims = [this.element.offsetHeight, this.element.offsetWidth];\n    if(/^content/.test(this.options.scaleMode))\n      this.dims = [this.element.scrollHeight, this.element.scrollWidth];\n    if(!this.dims)\n      this.dims = [this.options.scaleMode.originalHeight,\n                   this.options.scaleMode.originalWidth];\n  },\n  update: function(position) {\n    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);\n    if(this.options.scaleContent && this.fontSize)\n      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });\n    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);\n  },\n  finish: function(position) {\n    if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);\n  },\n  setDimensions: function(height, width) {\n    var d = {};\n    if(this.options.scaleX) d.width = width + 'px';\n    if(this.options.scaleY) d.height = height + 'px';\n    if(this.options.scaleFromCenter) {\n      var topd  = (height - this.dims[0])/2;\n      var leftd = (width  - this.dims[1])/2;\n      if(this.elementPositioning == 'absolute') {\n        if(this.options.scaleY) d.top = this.originalTop-topd + 'px';\n        if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';\n      } else {\n        if(this.options.scaleY) d.top = -topd + 'px';\n        if(this.options.scaleX) d.left = -leftd + 'px';\n      }\n    }\n    this.element.setStyle(d);\n  }\n});\n\nEffect.Highlight = Class.create();\nObject.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {\n  initialize: function(element) {\n    this.element = $(element);\n    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});\n    this.start(options);\n  },\n  setup: function() {\n    // Prevent executing on elements not in the layout flow\n    if(this.element.getStyle('display')=='none') { this.cancel(); return; }\n    // Disable background image during the effect\n    this.oldStyle = {\n      backgroundImage: this.element.getStyle('background-image') };\n    this.element.setStyle({backgroundImage: 'none'});\n    if(!this.options.endcolor)\n      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');\n    if(!this.options.restorecolor)\n      this.options.restorecolor = this.element.getStyle('background-color');\n    // init color calculations\n    this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));\n    this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));\n  },\n  update: function(position) {\n    this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){\n      return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });\n  },\n  finish: function() {\n    this.element.setStyle(Object.extend(this.oldStyle, {\n      backgroundColor: this.options.restorecolor\n    }));\n  }\n});\n\nEffect.ScrollTo = Class.create();\nObject.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {\n  initialize: function(element) {\n    this.element = $(element);\n    this.start(arguments[1] || {});\n  },\n  setup: function() {\n    Position.prepare();\n    var offsets = Position.cumulativeOffset(this.element);\n    if(this.options.offset) offsets[1] += this.options.offset;\n    var max = window.innerHeight ? \n      window.height - window.innerHeight :\n      document.body.scrollHeight - \n        (document.documentElement.clientHeight ? \n          document.documentElement.clientHeight : document.body.clientHeight);\n    this.scrollStart = Position.deltaY;\n    this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;\n  },\n  update: function(position) {\n    Position.prepare();\n    window.scrollTo(Position.deltaX, \n      this.scrollStart + (position*this.delta));\n  }\n});\n\n/* ------------- combination effects ------------- */\n\nEffect.Fade = function(element) {\n  element = $(element);\n  var oldOpacity = element.getInlineOpacity();\n  var options = Object.extend({\n  from: element.getOpacity() || 1.0,\n  to:   0.0,\n  afterFinishInternal: function(effect) { \n    if(effect.options.to!=0) return;\n    effect.element.hide();\n    effect.element.setStyle({opacity: oldOpacity}); \n  }}, arguments[1] || {});\n  return new Effect.Opacity(element,options);\n}\n\nEffect.Appear = function(element) {\n  element = $(element);\n  var options = Object.extend({\n  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),\n  to:   1.0,\n  // force Safari to render floated elements properly\n  afterFinishInternal: function(effect) {\n    effect.element.forceRerendering();\n  },\n  beforeSetup: function(effect) {\n    effect.element.setOpacity(effect.options.from);\n    effect.element.show(); \n  }}, arguments[1] || {});\n  return new Effect.Opacity(element,options);\n}\n\nEffect.Puff = function(element) {\n  element = $(element);\n  var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position') };\n  return new Effect.Parallel(\n   [ new Effect.Scale(element, 200, \n      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), \n     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], \n     Object.extend({ duration: 1.0, \n      beforeSetupInternal: function(effect) {\n        effect.effects[0].element.setStyle({position: 'absolute'}); },\n      afterFinishInternal: function(effect) {\n         effect.effects[0].element.hide();\n         effect.effects[0].element.setStyle(oldStyle); }\n     }, arguments[1] || {})\n   );\n}\n\nEffect.BlindUp = function(element) {\n  element = $(element);\n  element.makeClipping();\n  return new Effect.Scale(element, 0, \n    Object.extend({ scaleContent: false, \n      scaleX: false, \n      restoreAfterFinish: true,\n      afterFinishInternal: function(effect) {\n        effect.element.hide();\n        effect.element.undoClipping();\n      } \n    }, arguments[1] || {})\n  );\n}\n\nEffect.BlindDown = function(element) {\n  element = $(element);\n  var elementDimensions = element.getDimensions();\n  return new Effect.Scale(element, 100, \n    Object.extend({ scaleContent: false, \n      scaleX: false,\n      scaleFrom: 0,\n      scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},\n      restoreAfterFinish: true,\n      afterSetup: function(effect) {\n        effect.element.makeClipping();\n        effect.element.setStyle({height: '0px'});\n        effect.element.show(); \n      },  \n      afterFinishInternal: function(effect) {\n        effect.element.undoClipping();\n      }\n    }, arguments[1] || {})\n  );\n}\n\nEffect.SwitchOff = function(element) {\n  element = $(element);\n  var oldOpacity = element.getInlineOpacity();\n  return new Effect.Appear(element, { \n    duration: 0.4,\n    from: 0,\n    transition: Effect.Transitions.flicker,\n    afterFinishInternal: function(effect) {\n      new Effect.Scale(effect.element, 1, { \n        duration: 0.3, scaleFromCenter: true,\n        scaleX: false, scaleContent: false, restoreAfterFinish: true,\n        beforeSetup: function(effect) { \n          effect.element.makePositioned();\n          effect.element.makeClipping();\n        },\n        afterFinishInternal: function(effect) {\n          effect.element.hide();\n          effect.element.undoClipping();\n          effect.element.undoPositioned();\n          effect.element.setStyle({opacity: oldOpacity});\n        }\n      })\n    }\n  });\n}\n\nEffect.DropOut = function(element) {\n  element = $(element);\n  var oldStyle = {\n    top: element.getStyle('top'),\n    left: element.getStyle('left'),\n    opacity: element.getInlineOpacity() };\n  return new Effect.Parallel(\n    [ new Effect.Move(element, {x: 0, y: 100, sync: true }), \n      new Effect.Opacity(element, { sync: true, to: 0.0 }) ],\n    Object.extend(\n      { duration: 0.5,\n        beforeSetup: function(effect) {\n          effect.effects[0].element.makePositioned(); \n        },\n        afterFinishInternal: function(effect) {\n          effect.effects[0].element.hide();\n          effect.effects[0].element.undoPositioned();\n          effect.effects[0].element.setStyle(oldStyle);\n        } \n      }, arguments[1] || {}));\n}\n\nEffect.Shake = function(element) {\n  element = $(element);\n  var oldStyle = {\n    top: element.getStyle('top'),\n    left: element.getStyle('left') };\n    return new Effect.Move(element, \n      { x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {\n    new Effect.Move(effect.element,\n      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {\n    new Effect.Move(effect.element,\n      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {\n    new Effect.Move(effect.element,\n      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {\n    new Effect.Move(effect.element,\n      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {\n    new Effect.Move(effect.element,\n      { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {\n        effect.element.undoPositioned();\n        effect.element.setStyle(oldStyle);\n  }}) }}) }}) }}) }}) }});\n}\n\nEffect.SlideDown = function(element) {\n  element = $(element);\n  element.cleanWhitespace();\n  // SlideDown need to have the content of the element wrapped in a container element with fixed height!\n  var oldInnerBottom = $(element.firstChild).getStyle('bottom');\n  var elementDimensions = element.getDimensions();\n  return new Effect.Scale(element, 100, Object.extend({ \n    scaleContent: false, \n    scaleX: false, \n    scaleFrom: window.opera ? 0 : 1,\n    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},\n    restoreAfterFinish: true,\n    afterSetup: function(effect) {\n      effect.element.makePositioned();\n      effect.element.firstChild.makePositioned();\n      if(window.opera) effect.element.setStyle({top: ''});\n      effect.element.makeClipping();\n      effect.element.setStyle({height: '0px'});\n      effect.element.show(); },\n    afterUpdateInternal: function(effect) {\n      effect.element.firstChild.setStyle({bottom:\n        (effect.dims[0] - effect.element.clientHeight) + 'px' }); \n    },\n    afterFinishInternal: function(effect) {\n      effect.element.undoClipping(); \n      // IE will crash if child is undoPositioned first\n      if(/MSIE/.test(navigator.userAgent)){\n        effect.element.undoPositioned();\n        effect.element.firstChild.undoPositioned();\n      }else{\n        effect.element.firstChild.undoPositioned();\n        effect.element.undoPositioned();\n      }\n      effect.element.firstChild.setStyle({bottom: oldInnerBottom}); }\n    }, arguments[1] || {})\n  );\n}\n  \nEffect.SlideUp = function(element) {\n  element = $(element);\n  element.cleanWhitespace();\n  var oldInnerBottom = $(element.firstChild).getStyle('bottom');\n  return new Effect.Scale(element, window.opera ? 0 : 1,\n   Object.extend({ scaleContent: false, \n    scaleX: false, \n    scaleMode: 'box',\n    scaleFrom: 100,\n    restoreAfterFinish: true,\n    beforeStartInternal: function(effect) {\n      effect.element.makePositioned();\n      effect.element.firstChild.makePositioned();\n      if(window.opera) effect.element.setStyle({top: ''});\n      effect.element.makeClipping();\n      effect.element.show(); },  \n    afterUpdateInternal: function(effect) {\n      effect.element.firstChild.setStyle({bottom:\n        (effect.dims[0] - effect.element.clientHeight) + 'px' }); },\n    afterFinishInternal: function(effect) {\n      effect.element.hide();\n      effect.element.undoClipping();\n      effect.element.firstChild.undoPositioned();\n      effect.element.undoPositioned();\n      effect.element.setStyle({bottom: oldInnerBottom}); }\n   }, arguments[1] || {})\n  );\n}\n\n// Bug in opera makes the TD containing this element expand for a instance after finish \nEffect.Squish = function(element) {\n  return new Effect.Scale(element, window.opera ? 1 : 0, \n    { restoreAfterFinish: true,\n      beforeSetup: function(effect) {\n        effect.element.makeClipping(effect.element); },  \n      afterFinishInternal: function(effect) {\n        effect.element.hide(effect.element); \n        effect.element.undoClipping(effect.element); }\n  });\n}\n\nEffect.Grow = function(element) {\n  element = $(element);\n  var options = Object.extend({\n    direction: 'center',\n    moveTransition: Effect.Transitions.sinoidal,\n    scaleTransition: Effect.Transitions.sinoidal,\n    opacityTransition: Effect.Transitions.full\n  }, arguments[1] || {});\n  var oldStyle = {\n    top: element.style.top,\n    left: element.style.left,\n    height: element.style.height,\n    width: element.style.width,\n    opacity: element.getInlineOpacity() };\n\n  var dims = element.getDimensions();    \n  var initialMoveX, initialMoveY;\n  var moveX, moveY;\n  \n  switch (options.direction) {\n    case 'top-left':\n      initialMoveX = initialMoveY = moveX = moveY = 0; \n      break;\n    case 'top-right':\n      initialMoveX = dims.width;\n      initialMoveY = moveY = 0;\n      moveX = -dims.width;\n      break;\n    case 'bottom-left':\n      initialMoveX = moveX = 0;\n      initialMoveY = dims.height;\n      moveY = -dims.height;\n      break;\n    case 'bottom-right':\n      initialMoveX = dims.width;\n      initialMoveY = dims.height;\n      moveX = -dims.width;\n      moveY = -dims.height;\n      break;\n    case 'center':\n      initialMoveX = dims.width / 2;\n      initialMoveY = dims.height / 2;\n      moveX = -dims.width / 2;\n      moveY = -dims.height / 2;\n      break;\n  }\n  \n  return new Effect.Move(element, {\n    x: initialMoveX,\n    y: initialMoveY,\n    duration: 0.01, \n    beforeSetup: function(effect) {\n      effect.element.hide();\n      effect.element.makeClipping();\n      effect.element.makePositioned();\n    },\n    afterFinishInternal: function(effect) {\n      new Effect.Parallel(\n        [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),\n          new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),\n          new Effect.Scale(effect.element, 100, {\n            scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, \n            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})\n        ], Object.extend({\n             beforeSetup: function(effect) {\n               effect.effects[0].element.setStyle({height: '0px'});\n               effect.effects[0].element.show(); \n             },\n             afterFinishInternal: function(effect) {\n               effect.effects[0].element.undoClipping();\n               effect.effects[0].element.undoPositioned();\n               effect.effects[0].element.setStyle(oldStyle); \n             }\n           }, options)\n      )\n    }\n  });\n}\n\nEffect.Shrink = function(element) {\n  element = $(element);\n  var options = Object.extend({\n    direction: 'center',\n    moveTransition: Effect.Transitions.sinoidal,\n    scaleTransition: Effect.Transitions.sinoidal,\n    opacityTransition: Effect.Transitions.none\n  }, arguments[1] || {});\n  var oldStyle = {\n    top: element.style.top,\n    left: element.style.left,\n    height: element.style.height,\n    width: element.style.width,\n    opacity: element.getInlineOpacity() };\n\n  var dims = element.getDimensions();\n  var moveX, moveY;\n  \n  switch (options.direction) {\n    case 'top-left':\n      moveX = moveY = 0;\n      break;\n    case 'top-right':\n      moveX = dims.width;\n      moveY = 0;\n      break;\n    case 'bottom-left':\n      moveX = 0;\n      moveY = dims.height;\n      break;\n    case 'bottom-right':\n      moveX = dims.width;\n      moveY = dims.height;\n      break;\n    case 'center':  \n      moveX = dims.width / 2;\n      moveY = dims.height / 2;\n      break;\n  }\n  \n  return new Effect.Parallel(\n    [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),\n      new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),\n      new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })\n    ], Object.extend({            \n         beforeStartInternal: function(effect) {\n           effect.effects[0].element.makePositioned();\n           effect.effects[0].element.makeClipping(); },\n         afterFinishInternal: function(effect) {\n           effect.effects[0].element.hide();\n           effect.effects[0].element.undoClipping();\n           effect.effects[0].element.undoPositioned();\n           effect.effects[0].element.setStyle(oldStyle); }\n       }, options)\n  );\n}\n\nEffect.Pulsate = function(element) {\n  element = $(element);\n  var options    = arguments[1] || {};\n  var oldOpacity = element.getInlineOpacity();\n  var transition = options.transition || Effect.Transitions.sinoidal;\n  var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };\n  reverser.bind(transition);\n  return new Effect.Opacity(element, \n    Object.extend(Object.extend({  duration: 3.0, from: 0,\n      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }\n    }, options), {transition: reverser}));\n}\n\nEffect.Fold = function(element) {\n  element = $(element);\n  var oldStyle = {\n    top: element.style.top,\n    left: element.style.left,\n    width: element.style.width,\n    height: element.style.height };\n  Element.makeClipping(element);\n  return new Effect.Scale(element, 5, Object.extend({   \n    scaleContent: false,\n    scaleX: false,\n    afterFinishInternal: function(effect) {\n    new Effect.Scale(element, 1, { \n      scaleContent: false, \n      scaleY: false,\n      afterFinishInternal: function(effect) {\n        effect.element.hide();\n        effect.element.undoClipping(); \n        effect.element.setStyle(oldStyle);\n      } });\n  }}, arguments[1] || {}));\n};\n\n['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',\n 'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each( \n  function(f) { Element.Methods[f] = Element[f]; }\n);\n\nElement.Methods.visualEffect = function(element, effect, options) {\n  s = effect.gsub(/_/, '-').camelize();\n  effect_class = s.charAt(0).toUpperCase() + s.substring(1);\n  new Effect[effect_class](element, options);\n  return $(element);\n};\n\nElement.addMethods();"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/scriptaculous.js",
    "content": "// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)\n// \n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so, subject to\n// the following conditions:\n// \n// The above copyright notice and this permission notice shall be\n// included in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nvar Scriptaculous = {\n  Version: '1.6.1',\n  require: function(libraryName) {\n    // inserting via DOM fails in Safari 2.0, so brute force approach\n    document.write('<script type=\"text/javascript\" src=\"'+libraryName+'\"></script>');\n  },\n  load: function() {\n    if((typeof Prototype=='undefined') || \n       (typeof Element == 'undefined') || \n       (typeof Element.Methods=='undefined') ||\n       parseFloat(Prototype.Version.split(\".\")[0] + \".\" +\n                  Prototype.Version.split(\".\")[1]) < 1.5)\n       throw(\"script.aculo.us requires the Prototype JavaScript framework >= 1.5.0\");\n    \n    $A(document.getElementsByTagName(\"script\")).findAll( function(s) {\n      return (s.src && s.src.match(/scriptaculous\\.js(\\?.*)?$/))\n    }).each( function(s) {\n      var path = s.src.replace(/scriptaculous\\.js(\\?.*)?$/,'');\n      var includes = s.src.match(/\\?.*load=([a-z,]*)/);\n      (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each(\n       function(include) { Scriptaculous.require(path+include+'.js') });\n    });\n  }\n}\n\nScriptaculous.load();"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/slider.js",
    "content": "// Copyright (c) 2005 Marty Haught, Thomas Fuchs \n//\n// See http://script.aculo.us for more info\n// \n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so, subject to\n// the following conditions:\n// \n// The above copyright notice and this permission notice shall be\n// included in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nif(!Control) var Control = {};\nControl.Slider = Class.create();\n\n// options:\n//  axis: 'vertical', or 'horizontal' (default)\n//\n// callbacks:\n//  onChange(value)\n//  onSlide(value)\nControl.Slider.prototype = {\n  initialize: function(handle, track, options) {\n    var slider = this;\n    \n    if(handle instanceof Array) {\n      this.handles = handle.collect( function(e) { return $(e) });\n    } else {\n      this.handles = [$(handle)];\n    }\n    \n    this.track   = $(track);\n    this.options = options || {};\n\n    this.axis      = this.options.axis || 'horizontal';\n    this.increment = this.options.increment || 1;\n    this.step      = parseInt(this.options.step || '1');\n    this.range     = this.options.range || $R(0,1);\n    \n    this.value     = 0; // assure backwards compat\n    this.values    = this.handles.map( function() { return 0 });\n    this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;\n    this.options.startSpan = $(this.options.startSpan || null);\n    this.options.endSpan   = $(this.options.endSpan || null);\n\n    this.restricted = this.options.restricted || false;\n\n    this.maximum   = this.options.maximum || this.range.end;\n    this.minimum   = this.options.minimum || this.range.start;\n\n    // Will be used to align the handle onto the track, if necessary\n    this.alignX = parseInt(this.options.alignX || '0');\n    this.alignY = parseInt(this.options.alignY || '0');\n    \n    this.trackLength = this.maximumOffset() - this.minimumOffset();\n    this.handleLength = this.isVertical() ? this.handles[0].offsetHeight : this.handles[0].offsetWidth;\n\n    this.active   = false;\n    this.dragging = false;\n    this.disabled = false;\n\n    if(this.options.disabled) this.setDisabled();\n\n    // Allowed values array\n    this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;\n    if(this.allowedValues) {\n      this.minimum = this.allowedValues.min();\n      this.maximum = this.allowedValues.max();\n    }\n\n    this.eventMouseDown = this.startDrag.bindAsEventListener(this);\n    this.eventMouseUp   = this.endDrag.bindAsEventListener(this);\n    this.eventMouseMove = this.update.bindAsEventListener(this);\n\n    // Initialize handles in reverse (make sure first handle is active)\n    this.handles.each( function(h,i) {\n      i = slider.handles.length-1-i;\n      slider.setValue(parseFloat(\n        (slider.options.sliderValue instanceof Array ? \n          slider.options.sliderValue[i] : slider.options.sliderValue) || \n         slider.range.start), i);\n      Element.makePositioned(h); // fix IE\n      Event.observe(h, \"mousedown\", slider.eventMouseDown);\n    });\n    \n    Event.observe(this.track, \"mousedown\", this.eventMouseDown);\n    Event.observe(document, \"mouseup\", this.eventMouseUp);\n    Event.observe(document, \"mousemove\", this.eventMouseMove);\n    \n    this.initialized = true;\n  },\n  dispose: function() {\n    var slider = this;    \n    Event.stopObserving(this.track, \"mousedown\", this.eventMouseDown);\n    Event.stopObserving(document, \"mouseup\", this.eventMouseUp);\n    Event.stopObserving(document, \"mousemove\", this.eventMouseMove);\n    this.handles.each( function(h) {\n      Event.stopObserving(h, \"mousedown\", slider.eventMouseDown);\n    });\n  },\n  setDisabled: function(){\n    this.disabled = true;\n  },\n  setEnabled: function(){\n    this.disabled = false;\n  },  \n  getNearestValue: function(value){\n    if(this.allowedValues){\n      if(value >= this.allowedValues.max()) return(this.allowedValues.max());\n      if(value <= this.allowedValues.min()) return(this.allowedValues.min());\n      \n      var offset = Math.abs(this.allowedValues[0] - value);\n      var newValue = this.allowedValues[0];\n      this.allowedValues.each( function(v) {\n        var currentOffset = Math.abs(v - value);\n        if(currentOffset <= offset){\n          newValue = v;\n          offset = currentOffset;\n        } \n      });\n      return newValue;\n    }\n    if(value > this.range.end) return this.range.end;\n    if(value < this.range.start) return this.range.start;\n    return value;\n  },\n  setValue: function(sliderValue, handleIdx){\n    if(!this.active) {\n      this.activeHandle    = this.handles[handleIdx];\n      this.activeHandleIdx = handleIdx;\n      this.updateStyles();\n    }\n    handleIdx = handleIdx || this.activeHandleIdx || 0;\n    if(this.initialized && this.restricted) {\n      if((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))\n        sliderValue = this.values[handleIdx-1];\n      if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))\n        sliderValue = this.values[handleIdx+1];\n    }\n    sliderValue = this.getNearestValue(sliderValue);\n    this.values[handleIdx] = sliderValue;\n    this.value = this.values[0]; // assure backwards compat\n    \n    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = \n      this.translateToPx(sliderValue);\n    \n    this.drawSpans();\n    if(!this.dragging || !this.event) this.updateFinished();\n  },\n  setValueBy: function(delta, handleIdx) {\n    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, \n      handleIdx || this.activeHandleIdx || 0);\n  },\n  translateToPx: function(value) {\n    return Math.round(\n      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * \n      (value - this.range.start)) + \"px\";\n  },\n  translateToValue: function(offset) {\n    return ((offset/(this.trackLength-this.handleLength) * \n      (this.range.end-this.range.start)) + this.range.start);\n  },\n  getRange: function(range) {\n    var v = this.values.sortBy(Prototype.K); \n    range = range || 0;\n    return $R(v[range],v[range+1]);\n  },\n  minimumOffset: function(){\n    return(this.isVertical() ? this.alignY : this.alignX);\n  },\n  maximumOffset: function(){\n    return(this.isVertical() ?\n      this.track.offsetHeight - this.alignY : this.track.offsetWidth - this.alignX);\n  },  \n  isVertical:  function(){\n    return (this.axis == 'vertical');\n  },\n  drawSpans: function() {\n    var slider = this;\n    if(this.spans)\n      $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });\n    if(this.options.startSpan)\n      this.setSpan(this.options.startSpan,\n        $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));\n    if(this.options.endSpan)\n      this.setSpan(this.options.endSpan, \n        $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));\n  },\n  setSpan: function(span, range) {\n    if(this.isVertical()) {\n      span.style.top = this.translateToPx(range.start);\n      span.style.height = this.translateToPx(range.end - range.start + this.range.start);\n    } else {\n      span.style.left = this.translateToPx(range.start);\n      span.style.width = this.translateToPx(range.end - range.start + this.range.start);\n    }\n  },\n  updateStyles: function() {\n    this.handles.each( function(h){ Element.removeClassName(h, 'selected') });\n    Element.addClassName(this.activeHandle, 'selected');\n  },\n  startDrag: function(event) {\n    if(Event.isLeftClick(event)) {\n      if(!this.disabled){\n        this.active = true;\n        \n        var handle = Event.element(event);\n        var pointer  = [Event.pointerX(event), Event.pointerY(event)];\n        if(handle==this.track) {\n          var offsets  = Position.cumulativeOffset(this.track); \n          this.event = event;\n          this.setValue(this.translateToValue( \n           (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)\n          ));\n          var offsets  = Position.cumulativeOffset(this.activeHandle);\n          this.offsetX = (pointer[0] - offsets[0]);\n          this.offsetY = (pointer[1] - offsets[1]);\n        } else {\n          // find the handle (prevents issues with Safari)\n          while((this.handles.indexOf(handle) == -1) && handle.parentNode) \n            handle = handle.parentNode;\n        \n          this.activeHandle    = handle;\n          this.activeHandleIdx = this.handles.indexOf(this.activeHandle);\n          this.updateStyles();\n        \n          var offsets  = Position.cumulativeOffset(this.activeHandle);\n          this.offsetX = (pointer[0] - offsets[0]);\n          this.offsetY = (pointer[1] - offsets[1]);\n        }\n      }\n      Event.stop(event);\n    }\n  },\n  update: function(event) {\n   if(this.active) {\n      if(!this.dragging) this.dragging = true;\n      this.draw(event);\n      // fix AppleWebKit rendering\n      if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);\n      Event.stop(event);\n   }\n  },\n  draw: function(event) {\n    var pointer = [Event.pointerX(event), Event.pointerY(event)];\n    var offsets = Position.cumulativeOffset(this.track);\n    pointer[0] -= this.offsetX + offsets[0];\n    pointer[1] -= this.offsetY + offsets[1];\n    this.event = event;\n    this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));\n    if(this.initialized && this.options.onSlide)\n      this.options.onSlide(this.values.length>1 ? this.values : this.value, this);\n  },\n  endDrag: function(event) {\n    if(this.active && this.dragging) {\n      this.finishDrag(event, true);\n      Event.stop(event);\n    }\n    this.active = false;\n    this.dragging = false;\n  },  \n  finishDrag: function(event, success) {\n    this.active = false;\n    this.dragging = false;\n    this.updateFinished();\n  },\n  updateFinished: function() {\n    if(this.initialized && this.options.onChange) \n      this.options.onChange(this.values.length>1 ? this.values : this.value, this);\n    this.event = null;\n  }\n}"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/unittest.js",
    "content": "// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)\n//           (c) 2005 Jon Tirsen (http://www.tirsen.com)\n//           (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/)\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so, subject to\n// the following conditions:\n// \n// The above copyright notice and this permission notice shall be\n// included in all copies or substantial portions of the Software.\n// \n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n// experimental, Firefox-only\nEvent.simulateMouse = function(element, eventName) {\n  var options = Object.extend({\n    pointerX: 0,\n    pointerY: 0,\n    buttons: 0\n  }, arguments[2] || {});\n  var oEvent = document.createEvent(\"MouseEvents\");\n  oEvent.initMouseEvent(eventName, true, true, document.defaultView, \n    options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, \n    false, false, false, false, 0, $(element));\n  \n  if(this.mark) Element.remove(this.mark);\n  this.mark = document.createElement('div');\n  this.mark.appendChild(document.createTextNode(\" \"));\n  document.body.appendChild(this.mark);\n  this.mark.style.position = 'absolute';\n  this.mark.style.top = options.pointerY + \"px\";\n  this.mark.style.left = options.pointerX + \"px\";\n  this.mark.style.width = \"5px\";\n  this.mark.style.height = \"5px;\";\n  this.mark.style.borderTop = \"1px solid red;\"\n  this.mark.style.borderLeft = \"1px solid red;\"\n  \n  if(this.step)\n    alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options));\n  \n  $(element).dispatchEvent(oEvent);\n};\n\n// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed \"too much\", this doesn't work in 1.0.6 or DP2.\n// You need to downgrade to 1.0.4 for now to get this working\n// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much\nEvent.simulateKey = function(element, eventName) {\n  var options = Object.extend({\n    ctrlKey: false,\n    altKey: false,\n    shiftKey: false,\n    metaKey: false,\n    keyCode: 0,\n    charCode: 0\n  }, arguments[2] || {});\n\n  var oEvent = document.createEvent(\"KeyEvents\");\n  oEvent.initKeyEvent(eventName, true, true, window, \n    options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,\n    options.keyCode, options.charCode );\n  $(element).dispatchEvent(oEvent);\n};\n\nEvent.simulateKeys = function(element, command) {\n  for(var i=0; i<command.length; i++) {\n    Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)});\n  }\n};\n\nvar Test = {}\nTest.Unit = {};\n\n// security exception workaround\nTest.Unit.inspect = Object.inspect;\n\nTest.Unit.Logger = Class.create();\nTest.Unit.Logger.prototype = {\n  initialize: function(log) {\n    this.log = $(log);\n    if (this.log) {\n      this._createLogTable();\n    }\n  },\n  start: function(testName) {\n    if (!this.log) return;\n    this.testName = testName;\n    this.lastLogLine = document.createElement('tr');\n    this.statusCell = document.createElement('td');\n    this.nameCell = document.createElement('td');\n    this.nameCell.appendChild(document.createTextNode(testName));\n    this.messageCell = document.createElement('td');\n    this.lastLogLine.appendChild(this.statusCell);\n    this.lastLogLine.appendChild(this.nameCell);\n    this.lastLogLine.appendChild(this.messageCell);\n    this.loglines.appendChild(this.lastLogLine);\n  },\n  finish: function(status, summary) {\n    if (!this.log) return;\n    this.lastLogLine.className = status;\n    this.statusCell.innerHTML = status;\n    this.messageCell.innerHTML = this._toHTML(summary);\n  },\n  message: function(message) {\n    if (!this.log) return;\n    this.messageCell.innerHTML = this._toHTML(message);\n  },\n  summary: function(summary) {\n    if (!this.log) return;\n    this.logsummary.innerHTML = this._toHTML(summary);\n  },\n  _createLogTable: function() {\n    this.log.innerHTML =\n    '<div id=\"logsummary\"></div>' +\n    '<table id=\"logtable\">' +\n    '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +\n    '<tbody id=\"loglines\"></tbody>' +\n    '</table>';\n    this.logsummary = $('logsummary')\n    this.loglines = $('loglines');\n  },\n  _toHTML: function(txt) {\n    return txt.escapeHTML().replace(/\\n/g,\"<br/>\");\n  }\n}\n\nTest.Unit.Runner = Class.create();\nTest.Unit.Runner.prototype = {\n  initialize: function(testcases) {\n    this.options = Object.extend({\n      testLog: 'testlog'\n    }, arguments[1] || {});\n    this.options.resultsURL = this.parseResultsURLQueryParameter();\n    if (this.options.testLog) {\n      this.options.testLog = $(this.options.testLog) || null;\n    }\n    if(this.options.tests) {\n      this.tests = [];\n      for(var i = 0; i < this.options.tests.length; i++) {\n        if(/^test/.test(this.options.tests[i])) {\n          this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases[\"setup\"], testcases[\"teardown\"]));\n        }\n      }\n    } else {\n      if (this.options.test) {\n        this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases[\"setup\"], testcases[\"teardown\"])];\n      } else {\n        this.tests = [];\n        for(var testcase in testcases) {\n          if(/^test/.test(testcase)) {\n            this.tests.push(new Test.Unit.Testcase(testcase, testcases[testcase], testcases[\"setup\"], testcases[\"teardown\"]));\n          }\n        }\n      }\n    }\n    this.currentTest = 0;\n    this.logger = new Test.Unit.Logger(this.options.testLog);\n    setTimeout(this.runTests.bind(this), 1000);\n  },\n  parseResultsURLQueryParameter: function() {\n    return window.location.search.parseQuery()[\"resultsURL\"];\n  },\n  // Returns:\n  //  \"ERROR\" if there was an error,\n  //  \"FAILURE\" if there was a failure, or\n  //  \"SUCCESS\" if there was neither\n  getResult: function() {\n    var hasFailure = false;\n    for(var i=0;i<this.tests.length;i++) {\n      if (this.tests[i].errors > 0) {\n        return \"ERROR\";\n      }\n      if (this.tests[i].failures > 0) {\n        hasFailure = true;\n      }\n    }\n    if (hasFailure) {\n      return \"FAILURE\";\n    } else {\n      return \"SUCCESS\";\n    }\n  },\n  postResults: function() {\n    if (this.options.resultsURL) {\n      new Ajax.Request(this.options.resultsURL, \n        { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false });\n    }\n  },\n  runTests: function() {\n    var test = this.tests[this.currentTest];\n    if (!test) {\n      // finished!\n      this.postResults();\n      this.logger.summary(this.summary());\n      return;\n    }\n    if(!test.isWaiting) {\n      this.logger.start(test.name);\n    }\n    test.run();\n    if(test.isWaiting) {\n      this.logger.message(\"Waiting for \" + test.timeToWait + \"ms\");\n      setTimeout(this.runTests.bind(this), test.timeToWait || 1000);\n    } else {\n      this.logger.finish(test.status(), test.summary());\n      this.currentTest++;\n      // tail recursive, hopefully the browser will skip the stackframe\n      this.runTests();\n    }\n  },\n  summary: function() {\n    var assertions = 0;\n    var failures = 0;\n    var errors = 0;\n    var messages = [];\n    for(var i=0;i<this.tests.length;i++) {\n      assertions +=   this.tests[i].assertions;\n      failures   +=   this.tests[i].failures;\n      errors     +=   this.tests[i].errors;\n    }\n    return (\n      this.tests.length + \" tests, \" + \n      assertions + \" assertions, \" + \n      failures   + \" failures, \" +\n      errors     + \" errors\");\n  }\n}\n\nTest.Unit.Assertions = Class.create();\nTest.Unit.Assertions.prototype = {\n  initialize: function() {\n    this.assertions = 0;\n    this.failures   = 0;\n    this.errors     = 0;\n    this.messages   = [];\n  },\n  summary: function() {\n    return (\n      this.assertions + \" assertions, \" + \n      this.failures   + \" failures, \" +\n      this.errors     + \" errors\" + \"\\n\" +\n      this.messages.join(\"\\n\"));\n  },\n  pass: function() {\n    this.assertions++;\n  },\n  fail: function(message) {\n    this.failures++;\n    this.messages.push(\"Failure: \" + message);\n  },\n  info: function(message) {\n    this.messages.push(\"Info: \" + message);\n  },\n  error: function(error) {\n    this.errors++;\n    this.messages.push(error.name + \": \"+ error.message + \"(\" + Test.Unit.inspect(error) +\")\");\n  },\n  status: function() {\n    if (this.failures > 0) return 'failed';\n    if (this.errors > 0) return 'error';\n    return 'passed';\n  },\n  assert: function(expression) {\n    var message = arguments[1] || 'assert: got \"' + Test.Unit.inspect(expression) + '\"';\n    try { expression ? this.pass() : \n      this.fail(message); }\n    catch(e) { this.error(e); }\n  },\n  assertEqual: function(expected, actual) {\n    var message = arguments[2] || \"assertEqual\";\n    try { (expected == actual) ? this.pass() :\n      this.fail(message + ': expected \"' + Test.Unit.inspect(expected) + \n        '\", actual \"' + Test.Unit.inspect(actual) + '\"'); }\n    catch(e) { this.error(e); }\n  },\n  assertEnumEqual: function(expected, actual) {\n    var message = arguments[2] || \"assertEnumEqual\";\n    try { $A(expected).length == $A(actual).length && \n      expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ?\n        this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) + \n          ', actual ' + Test.Unit.inspect(actual)); }\n    catch(e) { this.error(e); }\n  },\n  assertNotEqual: function(expected, actual) {\n    var message = arguments[2] || \"assertNotEqual\";\n    try { (expected != actual) ? this.pass() : \n      this.fail(message + ': got \"' + Test.Unit.inspect(actual) + '\"'); }\n    catch(e) { this.error(e); }\n  },\n  assertNull: function(obj) {\n    var message = arguments[1] || 'assertNull'\n    try { (obj==null) ? this.pass() : \n      this.fail(message + ': got \"' + Test.Unit.inspect(obj) + '\"'); }\n    catch(e) { this.error(e); }\n  },\n  assertHidden: function(element) {\n    var message = arguments[1] || 'assertHidden';\n    this.assertEqual(\"none\", element.style.display, message);\n  },\n  assertNotNull: function(object) {\n    var message = arguments[1] || 'assertNotNull';\n    this.assert(object != null, message);\n  },\n  assertInstanceOf: function(expected, actual) {\n    var message = arguments[2] || 'assertInstanceOf';\n    try { \n      (actual instanceof expected) ? this.pass() : \n      this.fail(message + \": object was not an instance of the expected type\"); }\n    catch(e) { this.error(e); } \n  },\n  assertNotInstanceOf: function(expected, actual) {\n    var message = arguments[2] || 'assertNotInstanceOf';\n    try { \n      !(actual instanceof expected) ? this.pass() : \n      this.fail(message + \": object was an instance of the not expected type\"); }\n    catch(e) { this.error(e); } \n  },\n  _isVisible: function(element) {\n    element = $(element);\n    if(!element.parentNode) return true;\n    this.assertNotNull(element);\n    if(element.style && Element.getStyle(element, 'display') == 'none')\n      return false;\n    \n    return this._isVisible(element.parentNode);\n  },\n  assertNotVisible: function(element) {\n    this.assert(!this._isVisible(element), Test.Unit.inspect(element) + \" was not hidden and didn't have a hidden parent either. \" + (\"\" || arguments[1]));\n  },\n  assertVisible: function(element) {\n    this.assert(this._isVisible(element), Test.Unit.inspect(element) + \" was not visible. \" + (\"\" || arguments[1]));\n  },\n  benchmark: function(operation, iterations) {\n    var startAt = new Date();\n    (iterations || 1).times(operation);\n    var timeTaken = ((new Date())-startAt);\n    this.info((arguments[2] || 'Operation') + ' finished ' + \n       iterations + ' iterations in ' + (timeTaken/1000)+'s' );\n    return timeTaken;\n  }\n}\n\nTest.Unit.Testcase = Class.create();\nObject.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {\n  initialize: function(name, test, setup, teardown) {\n    Test.Unit.Assertions.prototype.initialize.bind(this)();\n    this.name           = name;\n    this.test           = test || function() {};\n    this.setup          = setup || function() {};\n    this.teardown       = teardown || function() {};\n    this.isWaiting      = false;\n    this.timeToWait     = 1000;\n  },\n  wait: function(time, nextPart) {\n    this.isWaiting = true;\n    this.test = nextPart;\n    this.timeToWait = time;\n  },\n  run: function() {\n    try {\n      try {\n        if (!this.isWaiting) this.setup.bind(this)();\n        this.isWaiting = false;\n        this.test.bind(this)();\n      } finally {\n        if(!this.isWaiting) {\n          this.teardown.bind(this)();\n        }\n      }\n    }\n    catch(e) { this.error(e); }\n  }\n});\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/lib/snapsie.js",
    "content": "/**\n * This file wraps the Snapsie ActiveX object, exposing a single saveSnapshot()\n * method on a the object.\n *\n * See http://snapsie.sourceforge.net/\n */\n\nfunction Snapsie() {\n    // private methods\n    \n    function isQuirksMode(inDocument) {\n        return (inDocument.compatMode == 'BackCompat');\n    }\n    \n    function getDrawableElement(inDocument) {\n        if (isQuirksMode(inDocument)) {\n            var body = inDocument.getElementsByTagName('body')[0];\n            return body;\n        }\n        else {\n            // standards mode\n            return inDocument.documentElement;\n        }\n    }\n    \n    /**\n     * Returns the canonical Windows path for a given path. This means\n     * basically replacing any forwards slashes with backslashes.\n     *\n     * @param path  the path whose canonical form to return\n     */\n    function getCanonicalPath(path) {\n        path = path.replace(/\\//g, '\\\\');\n        path = path.replace(/\\\\\\\\/g, '\\\\');\n        return path;\n    }\n\n    // public methods\n    \n    /**\n     * Saves a screenshot of the current document to a file. If frameId is\n     * specified, a screenshot of just the frame is captured instead.\n     *\n     * @param outputFile  the file to which to save the screenshot\n     * @param frameId     the frame to capture; omit to capture entire document\n     */\n    this.saveSnapshot = function(outputFile, frameId) {\n        var drawableElement = getDrawableElement(document);\n        var drawableInfo = {\n              overflow  : drawableElement.style.overflow\n            , scrollLeft: drawableElement.scrollLeft\n            , scrollTop : drawableElement.scrollTop\n        };\n        drawableElement.style.overflow = 'hidden';\n        \n        var capturableDocument;\n        var frameBCR = { left: 0, top: 0 };\n        if (!frameId) {\n            capturableDocument = document;\n        }\n        else {\n            var frame = document.getElementById(frameId);\n            capturableDocument = frame.document;\n            \n            // scroll as much of the frame into view as possible\n            frameBCR = frame.getBoundingClientRect();\n            window.scroll(frameBCR.left, frameBCR.top);\n            frameBCR = frame.getBoundingClientRect();\n        }\n        \n        var nativeObj = new ActiveXObject('Snapsie.CoSnapsie');\n        nativeObj.saveSnapshot(\n            getCanonicalPath(outputFile),\n            frameId,\n            drawableElement.scrollWidth,\n            drawableElement.scrollHeight,\n            drawableElement.clientWidth,\n            drawableElement.clientHeight,\n            drawableElement.clientLeft,\n            drawableElement.clientTop,\n            frameBCR.left,\n            frameBCR.top\n        );\n        \n        // revert\n        \n        drawableElement.style.overflow = drawableInfo.overflow;\n        drawableElement.scrollLeft = drawableInfo.scrollLeft;\n        drawableElement.scrollTop = drawableInfo.scrollTop;\n    }\n};\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/find_matching_child.js",
    "content": "/*\n * Copyright 2004 ThoughtWorks, Inc\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\nelementFindMatchingChildren = function(element, selector) {\n  var matches = [];\n\n  var childCount = element.childNodes.length;\n  for (var i=0; i<childCount; i++) {\n    var child = element.childNodes[i];\n    if (selector(child)) {\n      matches.push(child);\n    } else {\n      childMatches = elementFindMatchingChildren(child, selector);\n      matches.push(childMatches);\n    }\n  }\n\n  return matches.flatten();\n}\n\nELEMENT_NODE_TYPE = 1;\n\nelementFindFirstMatchingChild = function(element, selector) {\n\n  var childCount = element.childNodes.length;\n  for (var i=0; i<childCount; i++) {\n    var child = element.childNodes[i];\n    if (child.nodeType == ELEMENT_NODE_TYPE) {\n      if (selector(child)) {\n        return child;\n      }\n      result = elementFindFirstMatchingChild(child, selector);\n      if (result) {\n        return result;\n      }\n    }\n  }\n  return null;\n}\n\nelementFindFirstMatchingParent = function(element, selector) {\n  var current = element.parentNode;\n  while (current != null) {\n    if (selector(current)) {\n      break;\n    }\n    current = current.parentNode;\n  }\n  return current;\n}\n\nelementFindMatchingChildById = function(element, id) {\n  return elementFindFirstMatchingChild(element, function(element){return element.id==id} );\n}\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/htmlutils.js",
    "content": "/*\n * Copyright 2004 ThoughtWorks, Inc\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\n// This script contains a badly-organised collection of miscellaneous\n// functions that really better homes.\n\nfunction classCreate() {\n    return function() {\n      this.initialize.apply(this, arguments);\n    }\n}\n\nfunction objectExtend(destination, source) {\n  for (var property in source) {\n    destination[property] = source[property];\n  }\n  return destination;\n}\n\nfunction sel$() {\n  var results = [], element;\n  for (var i = 0; i < arguments.length; i++) {\n    element = arguments[i];\n    if (typeof element == 'string')\n      element = document.getElementById(element);\n    results[results.length] = element;\n  }\n  return results.length < 2 ? results[0] : results;\n}\n\nfunction sel$A(iterable) {\n  if (!iterable) return [];\n  if (iterable.toArray) {\n    return iterable.toArray();\n  } else {\n    var results = [];\n    for (var i = 0; i < iterable.length; i++)\n      results.push(iterable[i]);\n    return results;\n  }\n}\n\nfunction fnBind() {\n  var args = sel$A(arguments), __method = args.shift(), object = args.shift();\n  var retval = function() {\n    return __method.apply(object, args.concat(sel$A(arguments)));\n  }\n  retval.__method = __method;\n  return retval;\n}\n\nfunction fnBindAsEventListener(fn, object) {\n  var __method = fn;\n  return function(event) {\n    return __method.call(object, event || window.event);\n  }\n}\n\nfunction removeClassName(element, name) {\n    var re = new RegExp(\"\\\\b\" + name + \"\\\\b\", \"g\");\n    element.className = element.className.replace(re, \"\");\n}\n\nfunction addClassName(element, name) {\n    element.className = element.className + ' ' + name;\n}\n\nfunction elementSetStyle(element, style) {\n    for (var name in style) {\n      var value = style[name];\n      if (value == null) value = \"\";\n      element.style[name] = value;\n    }\n}\n\nfunction elementGetStyle(element, style) {\n    var value = element.style[style];\n    if (!value) {\n      if (document.defaultView && document.defaultView.getComputedStyle) {\n        var css = document.defaultView.getComputedStyle(element, null);\n        value = css ? css.getPropertyValue(style) : null;\n      } else if (element.currentStyle) {\n        value = element.currentStyle[style];\n      }\n    }\n\n    /** DGF necessary? \n    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))\n      if (Element.getStyle(element, 'position') == 'static') value = 'auto'; */\n\n    return value == 'auto' ? null : value;\n  }\n\nString.prototype.trim = function() {\n    var result = this.replace(/^\\s+/g, \"\");\n    // strip leading\n    return result.replace(/\\s+$/g, \"\");\n    // strip trailing\n};\nString.prototype.lcfirst = function() {\n    return this.charAt(0).toLowerCase() + this.substr(1);\n};\nString.prototype.ucfirst = function() {\n    return this.charAt(0).toUpperCase() + this.substr(1);\n};\nString.prototype.startsWith = function(str) {\n    return this.indexOf(str) == 0;\n};\n\n/**\n * Given a string literal that would appear in an XPath, puts it in quotes and\n * returns it. Special consideration is given to literals who themselves\n * contain quotes. It's possible for a concat() expression to be returned.\n */\nString.prototype.quoteForXPath = function()\n{\n    if (/\\'/.test(this)) {\n        if (/\\\"/.test(this)) {\n            // concat scenario\n            var pieces = [];\n            var a = \"'\", b = '\"', c;\n            for (var i = 0, j = 0; i < this.length;) {\n                if (this.charAt(i) == a) {\n                    // encountered a quote that cannot be contained in current\n                    // quote, so need to flip-flop quoting scheme\n                    if (j < i) {\n                        pieces.push(a + this.substring(j, i) + a);\n                        j = i;\n                    }\n                    c = a;\n                    a = b;\n                    b = c;\n                }\n                else {\n                    ++i;\n                }\n            }\n            pieces.push(a + this.substring(j) + a);\n            return 'concat(' + pieces.join(', ') + ')';\n        }\n        else {\n            // quote with doubles\n            return '\"' + this + '\"';\n        }\n    }\n    // quote with singles\n    return \"'\" + this + \"'\";\n};\n\n// Returns the text in this element\nfunction getText(element) {\n    var text = \"\";\n\n    var isRecentFirefox = (browserVersion.isFirefox && browserVersion.firefoxVersion >= \"1.5\");\n    if (isRecentFirefox || browserVersion.isKonqueror || browserVersion.isSafari || browserVersion.isOpera) {\n        text = getTextContent(element);\n    } else if (element.textContent) {\n        text = element.textContent;\n    } else if (element.innerText) {\n        text = element.innerText;\n    }\n\n    text = normalizeNewlines(text);\n    text = normalizeSpaces(text);\n\n    return text.trim();\n}\n\nfunction getTextContent(element, preformatted) {\n    if (element.nodeType == 3 /*Node.TEXT_NODE*/) {\n        var text = element.data;\n        if (!preformatted) {\n            text = text.replace(/\\n|\\r|\\t/g, \" \");\n        }\n        return text;\n    }\n    if (element.nodeType == 1 /*Node.ELEMENT_NODE*/) {\n        var childrenPreformatted = preformatted || (element.tagName == \"PRE\");\n        var text = \"\";\n        for (var i = 0; i < element.childNodes.length; i++) {\n            var child = element.childNodes.item(i);\n            text += getTextContent(child, childrenPreformatted);\n        }\n        // Handle block elements that introduce newlines\n        // -- From HTML spec:\n        //<!ENTITY % block\n        //     \"P | %heading; | %list; | %preformatted; | DL | DIV | NOSCRIPT |\n        //      BLOCKQUOTE | F:wORM | HR | TABLE | FIELDSET | ADDRESS\">\n        //\n        // TODO: should potentially introduce multiple newlines to separate blocks\n        if (element.tagName == \"P\" || element.tagName == \"BR\" || element.tagName == \"HR\" || element.tagName == \"DIV\") {\n            text += \"\\n\";\n        }\n        return text;\n    }\n    return '';\n}\n\n/**\n * Convert all newlines to \\n\n */\nfunction normalizeNewlines(text)\n{\n    return text.replace(/\\r\\n|\\r/g, \"\\n\");\n}\n\n/**\n * Replace multiple sequential spaces with a single space, and then convert &nbsp; to space.\n */\nfunction normalizeSpaces(text)\n{\n    // IE has already done this conversion, so doing it again will remove multiple nbsp\n    if (browserVersion.isIE)\n    {\n        return text;\n    }\n\n    // Replace multiple spaces with a single space\n    // TODO - this shouldn't occur inside PRE elements\n    text = text.replace(/\\ +/g, \" \");\n\n    // Replace &nbsp; with a space\n    var nbspPattern = new RegExp(String.fromCharCode(160), \"g\");\n    if (browserVersion.isSafari) {\n\treturn replaceAll(text, String.fromCharCode(160), \" \");\n    } else {\n\treturn text.replace(nbspPattern, \" \");\n    }\n}\n\nfunction replaceAll(text, oldText, newText) {\n    while (text.indexOf(oldText) != -1) {\n\ttext = text.replace(oldText, newText);\n    }\n    return text;\n}\n\n\nfunction xmlDecode(text) {\n    text = text.replace(/&quot;/g, '\"');\n    text = text.replace(/&apos;/g, \"'\");\n    text = text.replace(/&lt;/g, \"<\");\n    text = text.replace(/&gt;/g, \">\");\n    text = text.replace(/&amp;/g, \"&\");\n    return text;\n}\n\n// Sets the text in this element\nfunction setText(element, text) {\n    if (element.textContent != null) {\n        element.textContent = text;\n    } else if (element.innerText != null) {\n        element.innerText = text;\n    }\n}\n\n// Get the value of an <input> element\nfunction getInputValue(inputElement) {\n    if (inputElement.type) {\n        if (inputElement.type.toUpperCase() == 'CHECKBOX' ||\n            inputElement.type.toUpperCase() == 'RADIO')\n        {\n            return (inputElement.checked ? 'on' : 'off');\n        }\n    }\n    if (inputElement.value == null) {\n        throw new SeleniumError(\"This element has no value; is it really a form field?\");\n    }\n    return inputElement.value;\n}\n\n/* Fire an event in a browser-compatible manner */\nfunction triggerEvent(element, eventType, canBubble, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown) {\n    canBubble = (typeof(canBubble) == undefined) ? true : canBubble;\n    if (element.fireEvent && element.ownerDocument && element.ownerDocument.createEventObject) { // IE\n        var evt = createEventObject(element, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown);        \n        element.fireEvent('on' + eventType, evt);\n    }\n    else {\n        var evt = document.createEvent('HTMLEvents');\n        \n        try {\n            evt.shiftKey = shiftKeyDown;\n            evt.metaKey = metaKeyDown;\n            evt.altKey = altKeyDown;\n            evt.ctrlKey = controlKeyDown;\n        } catch (e) {\n            // On Firefox 1.0, you can only set these during initMouseEvent or initKeyEvent\n            // we'll have to ignore them here\n            LOG.exception(e);\n        }\n        \n        evt.initEvent(eventType, canBubble, true);\n        element.dispatchEvent(evt);\n    }\n}\n\nfunction getKeyCodeFromKeySequence(keySequence) {\n    var match = /^\\\\(\\d{1,3})$/.exec(keySequence);\n    if (match != null) {\n        return match[1];\n    }\n    match = /^.$/.exec(keySequence);\n    if (match != null) {\n        return match[0].charCodeAt(0);\n    }\n    // this is for backward compatibility with existing tests\n    // 1 digit ascii codes will break however because they are used for the digit chars\n    match = /^\\d{2,3}$/.exec(keySequence);\n    if (match != null) {\n        return match[0];\n    }\n    throw new SeleniumError(\"invalid keySequence\");\n}\n\nfunction createEventObject(element, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown) {\n     var evt = element.ownerDocument.createEventObject();\n     evt.shiftKey = shiftKeyDown;\n     evt.metaKey = metaKeyDown;\n     evt.altKey = altKeyDown;\n     evt.ctrlKey = controlKeyDown;\n     return evt;\n}\n\nfunction triggerKeyEvent(element, eventType, keySequence, canBubble, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown) {\n    var keycode = getKeyCodeFromKeySequence(keySequence);\n    canBubble = (typeof(canBubble) == undefined) ? true : canBubble;\n    if (element.fireEvent && element.ownerDocument && element.ownerDocument.createEventObject) { // IE\n        var keyEvent = createEventObject(element, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown);\n        keyEvent.keyCode = keycode;\n        element.fireEvent('on' + eventType, keyEvent);\n    }\n    else {\n        var evt;\n        if (window.KeyEvent) {\n            evt = document.createEvent('KeyEvents');\n            evt.initKeyEvent(eventType, true, true, window, controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown, keycode, keycode);\n        } else {\n            evt = document.createEvent('UIEvents');\n            \n            evt.shiftKey = shiftKeyDown;\n            evt.metaKey = metaKeyDown;\n            evt.altKey = altKeyDown;\n            evt.ctrlKey = controlKeyDown;\n\n            evt.initUIEvent(eventType, true, true, window, 1);\n            evt.keyCode = keycode;\n            evt.which = keycode;\n        }\n\n        element.dispatchEvent(evt);\n    }\n}\n\nfunction removeLoadListener(element, command) {\n    LOG.debug('Removing loadListenter for ' + element + ', ' + command);\n    if (window.removeEventListener)\n        element.removeEventListener(\"load\", command, true);\n    else if (window.detachEvent)\n        element.detachEvent(\"onload\", command);\n}\n\nfunction addLoadListener(element, command) {\n    LOG.debug('Adding loadListenter for ' + element + ', ' + command);\n    var augmentedCommand = function() {\n        command.call(this, element);\n    }\n    if (window.addEventListener && !browserVersion.isOpera)\n        element.addEventListener(\"load\", augmentedCommand, true);\n    else if (window.attachEvent)\n        element.attachEvent(\"onload\", augmentedCommand);\n}\n\n/**\n * Override the broken getFunctionName() method from JsUnit\n * This file must be loaded _after_ the jsunitCore.js\n */\nfunction getFunctionName(aFunction) {\n    var regexpResult = aFunction.toString().match(/function (\\w*)/);\n    if (regexpResult && regexpResult[1]) {\n        return regexpResult[1];\n    }\n    return 'anonymous';\n}\n\nfunction getDocumentBase(doc) {\n    var bases = document.getElementsByTagName(\"base\");\n    if (bases && bases.length && bases[0].href) {\n        return bases[0].href;\n    }\n    return \"\";\n}\n\nfunction getTagName(element) {\n    var tagName;\n    if (element && element.tagName && element.tagName.toLowerCase) {\n        tagName = element.tagName.toLowerCase();\n    }\n    return tagName;\n}\n\nfunction selArrayToString(a) {\n    if (isArray(a)) {\n        // DGF copying the array, because the array-like object may be a non-modifiable nodelist\n        var retval = [];\n        for (var i = 0; i < a.length; i++) {\n            var item = a[i];\n            var replaced = new String(item).replace(/([,\\\\])/g, '\\\\$1');\n            retval[i] = replaced;\n        }\n        return retval;\n    }\n    return new String(a);\n}\n\n\nfunction isArray(x) {\n    return ((typeof x) == \"object\") && (x[\"length\"] != null);\n}\n\nfunction absolutify(url, baseUrl) {\n    /** returns a relative url in its absolute form, given by baseUrl.\n    * \n    * This function is a little odd, because it can take baseUrls that\n    * aren't necessarily directories.  It uses the same rules as the HTML \n    * &lt;base&gt; tag; if the baseUrl doesn't end with \"/\", we'll assume\n    * that it points to a file, and strip the filename off to find its\n    * base directory.\n    *\n    * So absolutify(\"foo\", \"http://x/bar\") will return \"http://x/foo\" (stripping off bar),\n    * whereas absolutify(\"foo\", \"http://x/bar/\") will return \"http://x/bar/foo\" (preserving bar).\n    * Naturally absolutify(\"foo\", \"http://x\") will return \"http://x/foo\", appropriately.\n    * \n    * @param url the url to make absolute; if this url is already absolute, we'll just return that, unchanged\n    * @param baseUrl the baseUrl from which we'll absolutify, following the rules above.\n    * @return 'url' if it was already absolute, or the absolutized version of url if it was not absolute.\n    */\n    \n    // DGF isn't there some library we could use for this?\n        \n    if (/^\\w+:/.test(url)) {\n        // it's already absolute\n        return url;\n    }\n    \n    var loc;\n    try {\n        loc = parseUrl(baseUrl);\n    } catch (e) {\n        // is it an absolute windows file path? let's play the hero in that case\n        if (/^\\w:\\\\/.test(baseUrl)) {\n            baseUrl = \"file:///\" + baseUrl.replace(/\\\\/g, \"/\");\n            loc = parseUrl(baseUrl);\n        } else {\n            throw new SeleniumError(\"baseUrl wasn't absolute: \" + baseUrl);\n        }\n    }\n    loc.search = null;\n    loc.hash = null;\n    \n    // if url begins with /, then that's the whole pathname\n    if (/^\\//.test(url)) {\n        loc.pathname = url;\n        var result = reassembleLocation(loc);\n        return result;\n    }\n    \n    // if pathname is null, then we'll just append \"/\" + the url\n    if (!loc.pathname) {\n        loc.pathname = \"/\" + url;\n        var result = reassembleLocation(loc);\n        return result;\n    }\n    \n    // if pathname ends with /, just append url\n    if (/\\/$/.test(loc.pathname)) {\n        loc.pathname += url;\n        var result = reassembleLocation(loc);\n        return result;\n    }\n    \n    // if we're here, then the baseUrl has a pathname, but it doesn't end with /\n    // in that case, we replace everything after the final / with the relative url\n    loc.pathname = loc.pathname.replace(/[^\\/\\\\]+$/, url);\n    var result = reassembleLocation(loc);\n    return result;\n    \n}\n\nvar URL_REGEX = /^((\\w+):\\/\\/)(([^:]+):?([^@]+)?@)?([^\\/\\?:]*):?(\\d+)?(\\/?[^\\?#]+)?\\??([^#]+)?#?(.+)?/;\n\nfunction parseUrl(url) {\n    var fields = ['url', null, 'protocol', null, 'username', 'password', 'host', 'port', 'pathname', 'search', 'hash'];\n    var result = URL_REGEX.exec(url);\n    if (!result) {\n        throw new SeleniumError(\"Invalid URL: \" + url);\n    }\n    var loc = new Object();\n    for (var i = 0; i < fields.length; i++) {\n        var field = fields[i];\n        if (field == null) {\n            continue;\n        }\n        loc[field] = result[i];\n    }\n    return loc;\n}\n\nfunction reassembleLocation(loc) {\n    if (!loc.protocol) {\n        throw new Error(\"Not a valid location object: \" + o2s(loc));\n    }\n    var protocol = loc.protocol;\n    protocol = protocol.replace(/:$/, \"\");\n    var url = protocol + \"://\";\n    if (loc.username) {\n        url += loc.username;\n        if (loc.password) {\n            url += \":\" + loc.password;\n        }\n        url += \"@\";\n    }\n    if (loc.host) {\n        url += loc.host;\n    }\n    \n    if (loc.port) {\n        url += \":\" + loc.port;\n    }\n    \n    if (loc.pathname) {\n        url += loc.pathname;\n    }\n    \n    if (loc.search) {\n        url += \"?\" + loc.search;\n    }\n    if (loc.hash) {\n        var hash = loc.hash;\n        hash = loc.hash.replace(/^#/, \"\");\n        url += \"#\" + hash;\n    }\n    return url;\n}\n\nfunction canonicalize(url) {\n    if(url == \"about:blank\")\n    {\n\treturn url;\n    }\n    var tempLink = window.document.createElement(\"link\");\n    tempLink.href = url; // this will canonicalize the href on most browsers\n    var loc = parseUrl(tempLink.href)\n    if (!/\\/\\.\\.\\//.test(loc.pathname)) {\n    \treturn tempLink.href;\n    }\n  \t// didn't work... let's try it the hard way\n  \tvar originalParts = loc.pathname.split(\"/\");\n  \tvar newParts = [];\n  \tnewParts.push(originalParts.shift());\n  \tfor (var i = 0; i < originalParts.length; i++) {\n  \t\tvar part = originalParts[i];\n  \t\tif (\"..\" == part) {\n  \t\t\tnewParts.pop();\n  \t\t\tcontinue;\n  \t\t}\n  \t\tnewParts.push(part);\n  \t}\n  \tloc.pathname = newParts.join(\"/\");\n    return reassembleLocation(loc);\n}\n\nfunction extractExceptionMessage(ex) {\n    if (ex == null) return \"null exception\";\n    if (ex.message != null) return ex.message;\n    if (ex.toString && ex.toString() != null) return ex.toString();\n}\n    \n\nfunction describe(object, delimiter) {\n    var props = new Array();\n    for (var prop in object) {\n        try {\n            props.push(prop + \" -> \" + object[prop]);\n        } catch (e) {\n            props.push(prop + \" -> [htmlutils: ack! couldn't read this property! (Permission Denied?)]\");\n        }\n    }\n    return props.join(delimiter || '\\n');\n}\n\nvar PatternMatcher = function(pattern) {\n    this.selectStrategy(pattern);\n};\nPatternMatcher.prototype = {\n\n    selectStrategy: function(pattern) {\n        this.pattern = pattern;\n        var strategyName = 'glob';\n        // by default\n        if (/^([a-z-]+):(.*)/.test(pattern)) {\n            var possibleNewStrategyName = RegExp.$1;\n            var possibleNewPattern = RegExp.$2;\n            if (PatternMatcher.strategies[possibleNewStrategyName]) {\n                strategyName = possibleNewStrategyName;\n                pattern = possibleNewPattern;\n            }\n        }\n        var matchStrategy = PatternMatcher.strategies[strategyName];\n        if (!matchStrategy) {\n            throw new SeleniumError(\"cannot find PatternMatcher.strategies.\" + strategyName);\n        }\n        this.strategy = matchStrategy;\n        this.matcher = new matchStrategy(pattern);\n    },\n\n    matches: function(actual) {\n        return this.matcher.matches(actual + '');\n        // Note: appending an empty string avoids a Konqueror bug\n    }\n\n};\n\n/**\n * A \"static\" convenience method for easy matching\n */\nPatternMatcher.matches = function(pattern, actual) {\n    return new PatternMatcher(pattern).matches(actual);\n};\n\nPatternMatcher.strategies = {\n\n/**\n * Exact matching, e.g. \"exact:***\"\n */\n    exact: function(expected) {\n        this.expected = expected;\n        this.matches = function(actual) {\n            return actual == this.expected;\n        };\n    },\n\n/**\n * Match by regular expression, e.g. \"regexp:^[0-9]+$\"\n */\n    regexp: function(regexpString) {\n        this.regexp = new RegExp(regexpString);\n        this.matches = function(actual) {\n            return this.regexp.test(actual);\n        };\n    },\n\n    regex: function(regexpString) {\n        this.regexp = new RegExp(regexpString);\n        this.matches = function(actual) {\n            return this.regexp.test(actual);\n        };\n    },\n    \n    regexpi: function(regexpString) {\n        this.regexp = new RegExp(regexpString, \"i\");\n        this.matches = function(actual) {\n            return this.regexp.test(actual);\n        };\n    },\n\n    regexi: function(regexpString) {\n        this.regexp = new RegExp(regexpString, \"i\");\n        this.matches = function(actual) {\n            return this.regexp.test(actual);\n        };\n    },\n\n/**\n * \"globContains\" (aka \"wildmat\") patterns, e.g. \"glob:one,two,*\",\n * but don't require a perfect match; instead succeed if actual\n * contains something that matches globString.\n * Making this distinction is motivated by a bug in IE6 which\n * leads to the browser hanging if we implement *TextPresent tests\n * by just matching against a regular expression beginning and\n * ending with \".*\".  The globcontains strategy allows us to satisfy\n * the functional needs of the *TextPresent ops more efficiently\n * and so avoid running into this IE6 freeze.\n */\n    globContains: function(globString) {\n        this.regexp = new RegExp(PatternMatcher.regexpFromGlobContains(globString));\n        this.matches = function(actual) {\n            return this.regexp.test(actual);\n        };\n    },\n\n\n/**\n * \"glob\" (aka \"wildmat\") patterns, e.g. \"glob:one,two,*\"\n */\n    glob: function(globString) {\n        this.regexp = new RegExp(PatternMatcher.regexpFromGlob(globString));\n        this.matches = function(actual) {\n            return this.regexp.test(actual);\n        };\n    }\n\n};\n\nPatternMatcher.convertGlobMetaCharsToRegexpMetaChars = function(glob) {\n    var re = glob;\n    re = re.replace(/([.^$+(){}\\[\\]\\\\|])/g, \"\\\\$1\");\n    re = re.replace(/\\?/g, \"(.|[\\r\\n])\");\n    re = re.replace(/\\*/g, \"(.|[\\r\\n])*\");\n    return re;\n};\n\nPatternMatcher.regexpFromGlobContains = function(globContains) {\n    return PatternMatcher.convertGlobMetaCharsToRegexpMetaChars(globContains);\n};\n\nPatternMatcher.regexpFromGlob = function(glob) {\n    return \"^\" + PatternMatcher.convertGlobMetaCharsToRegexpMetaChars(glob) + \"$\";\n};\n\nif (!this[\"Assert\"]) Assert = {};\n\n\nAssert.fail = function(message) {\n    throw new AssertionFailedError(message);\n};\n\n/*\n* Assert.equals(comment?, expected, actual)\n*/\nAssert.equals = function() {\n    var args = new AssertionArguments(arguments);\n    if (args.expected === args.actual) {\n        return;\n    }\n    Assert.fail(args.comment +\n                \"Expected '\" + args.expected +\n                \"' but was '\" + args.actual + \"'\");\n};\n\nAssert.assertEquals = Assert.equals;\n\n/*\n* Assert.matches(comment?, pattern, actual)\n*/\nAssert.matches = function() {\n    var args = new AssertionArguments(arguments);\n    if (PatternMatcher.matches(args.expected, args.actual)) {\n        return;\n    }\n    Assert.fail(args.comment +\n                \"Actual value '\" + args.actual +\n                \"' did not match '\" + args.expected + \"'\");\n}\n\n/*\n* Assert.notMtches(comment?, pattern, actual)\n*/\nAssert.notMatches = function() {\n    var args = new AssertionArguments(arguments);\n    if (!PatternMatcher.matches(args.expected, args.actual)) {\n        return;\n    }\n    Assert.fail(args.comment +\n                \"Actual value '\" + args.actual +\n                \"' did match '\" + args.expected + \"'\");\n}\n\n\n// Preprocess the arguments to allow for an optional comment.\nfunction AssertionArguments(args) {\n    if (args.length == 2) {\n        this.comment = \"\";\n        this.expected = args[0];\n        this.actual = args[1];\n    } else {\n        this.comment = args[0] + \"; \";\n        this.expected = args[1];\n        this.actual = args[2];\n    }\n}\n\nfunction AssertionFailedError(message) {\n    this.isAssertionFailedError = true;\n    this.isSeleniumError = true;\n    this.message = message;\n    this.failureMessage = message;\n}\n\nfunction SeleniumError(message) {\n    var error = new Error(message);\n    if (typeof(arguments.caller) != 'undefined') { // IE, not ECMA\n        var result = '';\n        for (var a = arguments.caller; a != null; a = a.caller) {\n            result += '> ' + a.callee.toString() + '\\n';\n            if (a.caller == a) {\n                result += '*';\n                break;\n            }\n        }\n        error.stack = result;\n    }\n    error.isSeleniumError = true;\n    return error;\n}\n\nfunction highlight(element) {\n    var highLightColor = \"yellow\";\n    if (element.originalColor == undefined) { // avoid picking up highlight\n        element.originalColor = elementGetStyle(element, \"background-color\");\n    }\n    elementSetStyle(element, {\"backgroundColor\" : highLightColor});\n    window.setTimeout(function() {\n        try {\n            //if element is orphan, probably page of it has already gone, so ignore\n            if (!element.parentNode) {\n                return;\n            }\n            elementSetStyle(element, {\"backgroundColor\" : element.originalColor});\n        } catch (e) {} // DGF unhighlighting is very dangerous and low priority\n    }, 200);\n}\n\n\n\n// for use from vs.2003 debugger\nfunction o2s(obj) {\n    var s = \"\";\n    for (key in obj) {\n        var line = key + \"->\" + obj[key];\n        line.replace(\"\\n\", \" \");\n        s += line + \"\\n\";\n    }\n    return s;\n}\n\nvar seenReadyStateWarning = false;\n\nfunction openSeparateApplicationWindow(url, suppressMozillaWarning) {\n    // resize the Selenium window itself\n    window.resizeTo(1200, 500);\n    window.moveTo(window.screenX, 0);\n\n    var appWindow = window.open(url + '?start=true', 'main');\n    if (appWindow == null) {\n        var errorMessage = \"Couldn't open app window; is the pop-up blocker enabled?\"\n        LOG.error(errorMessage);\n        throw new Error(\"Couldn't open app window; is the pop-up blocker enabled?\");\n    }\n    try {\n        var windowHeight = 500;\n        if (window.outerHeight) {\n            windowHeight = window.outerHeight;\n        } else if (document.documentElement && document.documentElement.offsetHeight) {\n            windowHeight = document.documentElement.offsetHeight;\n        }\n\n        if (window.screenLeft && !window.screenX) window.screenX = window.screenLeft;\n        if (window.screenTop && !window.screenY) window.screenY = window.screenTop;\n\n        appWindow.resizeTo(1200, screen.availHeight - windowHeight - 60);\n        appWindow.moveTo(window.screenX, window.screenY + windowHeight + 25);\n    } catch (e) {\n        LOG.error(\"Couldn't resize app window\");\n        LOG.exception(e);\n    }\n\n\n    if (!suppressMozillaWarning && window.document.readyState == null && !seenReadyStateWarning) {\n        alert(\"Beware!  Mozilla bug 300992 means that we can't always reliably detect when a new page has loaded.  Install the Selenium IDE extension or the readyState extension available from selenium.openqa.org to make page load detection more reliable.\");\n        seenReadyStateWarning = true;\n    }\n\n    return appWindow;\n}\n\nvar URLConfiguration = classCreate();\nobjectExtend(URLConfiguration.prototype, {\n    initialize: function() {\n    },\n    _isQueryParameterTrue: function (name) {\n        var parameterValue = this._getQueryParameter(name);\n        if (parameterValue == null) return false;\n        if (parameterValue.toLowerCase() == \"true\") return true;\n        if (parameterValue.toLowerCase() == \"on\") return true;\n        return false;\n    },\n\n    _getQueryParameter: function(searchKey) {\n        var str = this.queryString\n        if (str == null) return null;\n        var clauses = str.split('&');\n        for (var i = 0; i < clauses.length; i++) {\n            var keyValuePair = clauses[i].split('=', 2);\n            var key = unescape(keyValuePair[0]);\n            if (key == searchKey) {\n                return unescape(keyValuePair[1]);\n            }\n        }\n        return null;\n    },\n\n    _extractArgs: function() {\n        var str = SeleniumHTARunner.commandLine;\n        if (str == null || str == \"\") return new Array();\n        var matches = str.match(/(?:\\\"([^\\\"]+)\\\"|(?!\\\"([^\\\"]+)\\\")(\\S+))/g);\n        // We either want non quote stuff ([^\"]+) surrounded by quotes\n        // or we want to look-ahead, see that the next character isn't\n        // a quoted argument, and then grab all the non-space stuff\n        // this will return for the line: \"foo\" bar\n        // the results \"\\\"foo\\\"\" and \"bar\"\n\n        // So, let's unquote the quoted arguments:\n        var args = new Array;\n        for (var i = 0; i < matches.length; i++) {\n            args[i] = matches[i];\n            args[i] = args[i].replace(/^\"(.*)\"$/, \"$1\");\n        }\n        return args;\n    },\n\n    isMultiWindowMode:function() {\n        return this._isQueryParameterTrue('multiWindow');\n    },\n    \n    getBaseUrl:function() {\n        return this._getQueryParameter('baseUrl');\n            \n    }\n});\n\n\nfunction safeScrollIntoView(element) {\n    if (element.scrollIntoView) {\n        element.scrollIntoView(false);\n        return;\n    }\n    // TODO: work out how to scroll browsers that don't support\n    // scrollIntoView (like Konqueror)\n}\n\n/**\n * Returns the absolute time represented as an offset of the current time.\n * Throws a SeleniumException if timeout is invalid.\n *\n * @param timeout  the number of milliseconds from \"now\" whose absolute time\n *                 to return\n */\nfunction getTimeoutTime(timeout) {\n    var now = new Date().getTime();\n    var timeoutLength = parseInt(timeout);\n    \n    if (isNaN(timeoutLength)) {\n        throw new SeleniumError(\"Timeout is not a number: '\" + timeout + \"'\");\n    }\n    \n    return now + timeoutLength;\n}\n\n/**\n * Returns true iff the current environment is the IDE.\n */\nfunction is_IDE()\n{\n    return (typeof(SeleniumIDE) != 'undefined');\n}\n\n/**\n * Logs a message if the Logger exists, and does nothing if it doesn't exist.\n *\n * @param level  the level to log at\n * @param msg    the message to log\n */\nfunction safe_log(level, msg)\n{\n    try {\n        LOG[level](msg);\n    }\n    catch (e) {\n        // couldn't log!\n    }\n}\n\n/**\n * Displays a warning message to the user appropriate to the context under\n * which the issue is encountered. This is primarily used to avoid popping up\n * alert dialogs that might pause an automated test suite.\n *\n * @param msg  the warning message to display\n */\nfunction safe_alert(msg)\n{\n    if (is_IDE()) {\n        alert(msg);\n    }\n}\n\n/**\n * Returns true iff the given element represents a link with a javascript\n * href attribute, and does not have an onclick attribute defined.\n *\n * @param element  the element to test\n */\nfunction hasJavascriptHref(element) {\n    if (getTagName(element) != 'a') {\n        return false;\n    }\n    if (element.onclick) {\n        return false;\n    }\n    if (! element.href) {\n        return false;\n    }\n    if (! /\\s*javascript:/i.test(element.href)) {\n        return false;\n    }\n    return true;\n}\n\n/**\n * Returns the given element, or its nearest ancestor, that satisfies\n * hasJavascriptHref(). Returns null if none is found.\n *\n * @param element  the element whose ancestors to test\n */\nfunction getAncestorOrSelfWithJavascriptHref(element) {\n    if (hasJavascriptHref(element)) {\n        return element;\n    }\n    if (element.parentNode == null) {\n        return null;\n    }\n    return getAncestorOrSelfWithJavascriptHref(element.parentNode);\n}\n\n//******************************************************************************\n// Locator evaluation support\n\n/**\n * Parses a Selenium locator, returning its type and the unprefixed locator\n * string as an object.\n *\n * @param locator  the locator to parse\n */\nfunction parse_locator(locator)\n{\n    var result = locator.match(/^([A-Za-z]+)=(.+)/);\n    if (result) {\n        return { type: result[1].toLowerCase(), string: result[2] };\n    }\n    return { type: 'implicit', string: locator };\n}\n\n/**\n * Evaluates an xpath on a document, and returns a list containing nodes in the\n * resulting nodeset. The browserbot xpath methods are now backed by this\n * function. A context node may optionally be provided, and the xpath will be\n * evaluated from that context.\n *\n * @param xpath       the xpath to evaluate\n * @param inDocument  the document in which to evaluate the xpath.\n * @param opts        (optional) An object containing various flags that can\n *                    modify how the xpath is evaluated. Here's a listing of\n *                    the meaningful keys:\n *\n *                     contextNode: \n *                       the context node from which to evaluate the xpath. If\n *                       unspecified, the context will be the root document\n *                       element.\n *\n *                     namespaceResolver:\n *                       the namespace resolver function. Defaults to null.\n *\n *                     xpathLibrary:\n *                       the javascript library to use for XPath. \"ajaxslt\" is\n *                       the default. \"javascript-xpath\" is newer and faster,\n *                       but needs more testing.\n *\n *                     allowNativeXpath:\n *                       whether to allow native evaluate(). Defaults to true.\n *\n *                     ignoreAttributesWithoutValue:\n *                       whether it's ok to ignore attributes without value\n *                       when evaluating the xpath. This can greatly improve\n *                       performance in IE; however, if your xpaths depend on\n *                       such attributes, you can't ignore them! Defaults to\n *                       true.\n *\n *                     returnOnFirstMatch:\n *                       whether to optimize the XPath evaluation to only\n *                       return the first match. The match, if any, will still\n *                       be returned in a list. Defaults to false.\n */\nfunction eval_xpath(xpath, inDocument, opts)\n{\n    if (!opts) {\n        var opts = {};\n    }\n    var contextNode = opts.contextNode\n        ? opts.contextNode : inDocument;\n    var namespaceResolver = opts.namespaceResolver\n        ? opts.namespaceResolver : null;\n    var xpathLibrary = opts.xpathLibrary\n        ? opts.xpathLibrary : null;\n    var allowNativeXpath = (opts.allowNativeXpath != undefined)\n        ? opts.allowNativeXpath : true;\n    var ignoreAttributesWithoutValue = (opts.ignoreAttributesWithoutValue != undefined)\n        ? opts.ignoreAttributesWithoutValue : true;\n    var returnOnFirstMatch = (opts.returnOnFirstMatch != undefined)\n        ? opts.returnOnFirstMatch : false;\n\n    // Trim any trailing \"/\": not valid xpath, and remains from attribute\n    // locator.\n    if (xpath.charAt(xpath.length - 1) == '/') {\n        xpath = xpath.slice(0, -1);\n    }\n    // HUGE hack - remove namespace from xpath for IE\n    if (browserVersion && browserVersion.isIE) {\n        xpath = xpath.replace(/x:/g, '')\n    }\n    \n    var nativeXpathAvailable = inDocument.evaluate;\n    var useNativeXpath = allowNativeXpath && nativeXpathAvailable;\n    var useDocumentEvaluate = useNativeXpath;\n\n    // When using the new and faster javascript-xpath library,\n    // we'll use the TestRunner's document object, not the App-Under-Test's document.\n    // The new library only modifies the TestRunner document with the new \n    // functionality.\n    if (xpathLibrary == 'javascript-xpath' && !useNativeXpath) {\n        documentForXpath = document;\n        useDocumentEvaluate = true;\n    } else {\n        documentForXpath = inDocument;\n    }\n    var results = [];\n    \n    // this is either native xpath or javascript-xpath via TestRunner.evaluate \n    if (useDocumentEvaluate) {\n        try {\n            // Regarding use of the second argument to document.evaluate():\n            // http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/a59ce20639c74ba1/a9d9f53e88e5ebb5\n            var xpathResult = documentForXpath\n                .evaluate((contextNode == inDocument ? xpath : '.' + xpath),\n                    contextNode, namespaceResolver, 0, null);\n        }\n        catch (e) {\n            throw new SeleniumError(\"Invalid xpath: \" + extractExceptionMessage(e));\n        }\n        finally{\n            if (xpathResult == null) {\n                // If the result is null, we should still throw an Error.\n                throw new SeleniumError(\"Invalid xpath: \" + xpath); \n            }\n        }\n        var result = xpathResult.iterateNext();\n        while (result) {\n            results.push(result);\n            result = xpathResult.iterateNext();\n        }\n        return results;\n    }\n\n    // If not, fall back to slower JavaScript implementation\n    // DGF set xpathdebug = true (using getEval, if you like) to turn on JS XPath debugging\n    //xpathdebug = true;\n    var context;\n    if (contextNode == inDocument) {\n        context = new ExprContext(inDocument);\n    }\n    else {\n        // provide false values to get the default constructor values\n        context = new ExprContext(contextNode, false, false,\n            contextNode.parentNode);\n    }\n    context.setCaseInsensitive(true);\n    context.setIgnoreAttributesWithoutValue(ignoreAttributesWithoutValue);\n    context.setReturnOnFirstMatch(returnOnFirstMatch);\n    var xpathObj;\n    try {\n        xpathObj = xpathParse(xpath);\n    }\n    catch (e) {\n        throw new SeleniumError(\"Invalid xpath: \" + extractExceptionMessage(e));\n    }\n    var xpathResult = xpathObj.evaluate(context);\n    if (xpathResult && xpathResult.value) {\n        for (var i = 0; i < xpathResult.value.length; ++i) {\n            results.push(xpathResult.value[i]);\n        }\n    }\n    return results;\n}\n\n/**\n * Returns the full resultset of a CSS selector evaluation.\n */\nfunction eval_css(locator, inDocument)\n{\n    return cssQuery(locator, inDocument);\n}\n\n/**\n * This function duplicates part of BrowserBot.findElement() to open up locator\n * evaluation on arbitrary documents. It returns a plain old array of located\n * elements found by using a Selenium locator.\n * \n * Multiple results may be generated for xpath and CSS locators. Even though a\n * list could potentially be generated for other locator types, such as link,\n * we don't try for them, because they aren't very expressive location\n * strategies; if you want a list, use xpath or CSS. Furthermore, strategies\n * for these locators have been optimized to only return the first result. For\n * these types of locators, performance is more important than ideal behavior.\n * \n * @param locator          a locator string\n * @param inDocument       the document in which to apply the locator\n * @param opt_contextNode  the context within which to evaluate the locator\n *\n * @return  a list of result elements\n */\nfunction eval_locator(locator, inDocument, opt_contextNode)\n{\n    locator = parse_locator(locator);\n    \n    var pageBot;\n    if (typeof(selenium) != 'undefined' && selenium != undefined) {\n        if (typeof(editor) == 'undefined' || editor.state == 'playing') {\n            safe_log('info', 'Trying [' + locator.type + ']: '\n                + locator.string);\n        }\n        pageBot = selenium.browserbot;\n    }\n    else {\n        if (!UI_GLOBAL.mozillaBrowserBot) {\n            // create a browser bot to evaluate the locator. Hand it the IDE\n            // window as a dummy window, and cache it for future use.\n            UI_GLOBAL.mozillaBrowserBot = new MozillaBrowserBot(window)\n        }\n        pageBot = UI_GLOBAL.mozillaBrowserBot;\n    }\n    \n    var results = [];\n    \n    if (locator.type == 'xpath' || (locator.string.charAt(0) == '/' &&\n        locator.type == 'implicit')) {\n        results = eval_xpath(locator.string, inDocument,\n            { contextNode: opt_contextNode });\n    }\n    else if (locator.type == 'css') {\n        results = eval_css(locator.string, inDocument);\n    }\n    else {\n        var element = pageBot\n            .findElementBy(locator.type, locator.string, inDocument);\n        if (element != null) {\n            results.push(element);\n        }\n    }\n    \n    return results;\n}\n\n//******************************************************************************\n// UI-Element\n\n/**\n * Escapes the special regular expression characters in a string intended to be\n * used as a regular expression.\n *\n * Based on: http://simonwillison.net/2006/Jan/20/escape/\n */\nRegExp.escape = (function() {\n    var specials = [\n        '/', '.', '*', '+', '?', '|', '^', '$',\n        '(', ')', '[', ']', '{', '}', '\\\\'\n    ];\n    \n    var sRE = new RegExp(\n        '(\\\\' + specials.join('|\\\\') + ')', 'g'\n    );\n  \n    return function(text) {\n        return text.replace(sRE, '\\\\$1');\n    }\n})();\n\n/**\n * Returns true if two arrays are identical, and false otherwise.\n *\n * @param a1  the first array, may only contain simple values (strings or\n *            numbers)\n * @param a2  the second array, same restricts on data as for a1\n * @return    true if the arrays are equivalent, false otherwise.\n */\nfunction are_equal(a1, a2)\n{\n    if (typeof(a1) != typeof(a2))\n        return false;\n    \n    switch(typeof(a1)) {\n        case 'object':\n            // arrays\n            if (a1.length) {\n                if (a1.length != a2.length)\n                    return false;\n                for (var i = 0; i < a1.length; ++i) {\n                    if (!are_equal(a1[i], a2[i]))\n                        return false\n                }\n            }\n            // associative arrays\n            else {\n                var keys = {};\n                for (var key in a1) {\n                    keys[key] = true;\n                }\n                for (var key in a2) {\n                    keys[key] = true;\n                }\n                for (var key in keys) {\n                    if (!are_equal(a1[key], a2[key]))\n                        return false;\n                }\n            }\n            return true;\n            \n        default:\n            return a1 == a2;\n    }\n}\n\n\n/**\n * Create a clone of an object and return it. This is a deep copy of everything\n * but functions, whose references are copied. You shouldn't expect a deep copy\n * of functions anyway.\n *\n * @param orig  the original object to copy\n * @return      a deep copy of the original object. Any functions attached,\n *              however, will have their references copied only.\n */\nfunction clone(orig) {\n    var copy;\n    switch(typeof(orig)) {\n        case 'object':\n            copy = (orig.length) ? [] : {};\n            for (var attr in orig) {\n                copy[attr] = clone(orig[attr]);\n            }\n            break;\n        default:\n            copy = orig;\n            break;\n    }\n    return copy;\n}\n\n/**\n * Emulates php's print_r() functionality. Returns a nicely formatted string\n * representation of an object. Very useful for debugging.\n *\n * @param object    the object to dump\n * @param maxDepth  the maximum depth to recurse into the object. Ellipses will\n *                  be shown for objects whose depth exceeds the maximum.\n * @param indent    the string to use for indenting progressively deeper levels\n *                  of the dump.\n * @return          a string representing a dump of the object\n */\nfunction print_r(object, maxDepth, indent)\n{\n    var parentIndent, attr, str = \"\";\n    if (arguments.length == 1) {\n        var maxDepth = Number.MAX_VALUE;\n    } else {\n        maxDepth--;\n    }\n    if (arguments.length < 3) {\n        parentIndent = ''\n        var indent = '    ';\n    } else {\n        parentIndent = indent;\n        indent += '    ';\n    }\n\n    switch(typeof(object)) {\n    case 'object':\n        if (object.length != undefined) {\n            if (object.length == 0) {\n                str += \"Array ()\\r\\n\";\n            }\n            else {\n                str += \"Array (\\r\\n\";\n                for (var i = 0; i < object.length; ++i) {\n                    str += indent + '[' + i + '] => ';\n                    if (maxDepth == 0)\n                        str += \"...\\r\\n\";\n                    else\n                        str += print_r(object[i], maxDepth, indent);\n                }\n                str += parentIndent + \")\\r\\n\";\n            }\n        }\n        else {\n            str += \"Object (\\r\\n\";\n            for (attr in object) {\n                str += indent + \"[\" + attr + \"] => \";\n                if (maxDepth == 0)\n                    str += \"...\\r\\n\";\n                else\n                    str += print_r(object[attr], maxDepth, indent);\n            }\n            str += parentIndent + \")\\r\\n\";\n        }\n        break;\n    case 'boolean':\n        str += (object ? 'true' : 'false') + \"\\r\\n\";\n        break;\n    case 'function':\n        str += \"Function\\r\\n\";\n        break;\n    default:\n        str += object + \"\\r\\n\";\n        break;\n\n    }\n    return str;\n}\n\n/**\n * Return an array containing all properties of an object. Perl-style.\n *\n * @param object  the object whose keys to return\n * @return        array of object keys, as strings\n */\nfunction keys(object)\n{\n    var keys = [];\n    for (var k in object) {\n        keys.push(k);\n    }\n    return keys;\n}\n\n/**\n * Emulates python's range() built-in. Returns an array of integers, counting\n * up (or down) from start to end. Note that the range returned is up to, but\n * NOT INCLUDING, end.\n *.\n * @param start  integer from which to start counting. If the end parameter is\n *               not provided, this value is considered the end and start will\n *               be zero.\n * @param end    integer to which to count. If omitted, the function will count\n *               up from zero to the value of the start parameter. Note that\n *               the array returned will count up to but will not include this\n *               value.\n * @return       an array of consecutive integers. \n */\nfunction range(start, end)\n{\n    if (arguments.length == 1) {\n        var end = start;\n        start = 0;\n    }\n    \n    var r = [];\n    if (start < end) {\n        while (start != end)\n            r.push(start++);\n    }\n    else {\n        while (start != end)\n            r.push(start--);\n    }\n    return r;\n}\n\n/**\n * Parses a python-style keyword arguments string and returns the pairs in a\n * new object.\n *\n * @param  kwargs  a string representing a set of keyword arguments. It should\n *                 look like <tt>keyword1=value1, keyword2=value2, ...</tt>\n * @return         an object mapping strings to strings\n */\nfunction parse_kwargs(kwargs)\n{\n    var args = new Object();\n    var pairs = kwargs.split(/,/);\n    for (var i = 0; i < pairs.length;) {\n        if (i > 0 && pairs[i].indexOf('=') == -1) {\n            // the value string contained a comma. Glue the parts back together.\n            pairs[i-1] += ',' + pairs.splice(i, 1)[0];\n        }\n        else {\n            ++i;\n        }\n    }\n    for (var i = 0; i < pairs.length; ++i) {\n        var splits = pairs[i].split(/=/);\n        if (splits.length == 1) {\n            continue;\n        }\n        var key = splits.shift();\n        var value = splits.join('=');\n        args[key.trim()] = value.trim();\n    }\n    return args;\n}\n\n/**\n * Creates a python-style keyword arguments string from an object.\n *\n * @param args        an associative array mapping strings to strings\n * @param sortedKeys  (optional) a list of keys of the args parameter that\n *                    specifies the order in which the arguments will appear in\n *                    the returned kwargs string\n *\n * @return            a kwarg string representation of args\n */\nfunction to_kwargs(args, sortedKeys)\n{\n    var s = '';\n    if (!sortedKeys) {\n        var sortedKeys = keys(args).sort();\n    }\n    for (var i = 0; i < sortedKeys.length; ++i) {\n        var k = sortedKeys[i];\n        if (args[k] != undefined) {\n            if (s) {\n                s += ', ';\n            }\n            s += k + '=' + args[k];\n        }\n    }\n    return s;\n}\n\n/**\n * Returns true if a node is an ancestor node of a target node, and false\n * otherwise.\n *\n * @param node    the node being compared to the target node\n * @param target  the target node\n * @return        true if node is an ancestor node of target, false otherwise.\n */\nfunction is_ancestor(node, target)\n{\n    while (target.parentNode) {\n        target = target.parentNode;\n        if (node == target)\n            return true;\n    }\n    return false;\n}\n\n//******************************************************************************\n// parseUri 1.2.1\n// MIT License\n\n/*\nCopyright (c) 2007 Steven Levithan <stevenlevithan.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n*/\n\nfunction parseUri (str) {\n    var o   = parseUri.options,\n        m   = o.parser[o.strictMode ? \"strict\" : \"loose\"].exec(str),\n        uri = {},\n        i   = 14;\n\n    while (i--) uri[o.key[i]] = m[i] || \"\";\n\n    uri[o.q.name] = {};\n    uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {\n        if ($1) uri[o.q.name][$1] = $2;\n    });\n\n    return uri;\n};\n\nparseUri.options = {\n    strictMode: false,\n    key: [\"source\",\"protocol\",\"authority\",\"userInfo\",\"user\",\"password\",\"host\",\"port\",\"relative\",\"path\",\"directory\",\"file\",\"query\",\"anchor\"],\n    q:   {\n        name:   \"queryKey\",\n        parser: /(?:^|&)([^&=]*)=?([^&]*)/g\n    },\n    parser: {\n        strict: /^(?:([^:\\/?#]+):)?(?:\\/\\/((?:(([^:@]*):?([^:@]*))?@)?([^:\\/?#]*)(?::(\\d*))?))?((((?:[^?#\\/]*\\/)*)([^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/,\n        loose:  /^(?:(?![^:@]+:[^:@\\/]*@)([^:\\/?#.]+):)?(?:\\/\\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/\n    }\n};\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/injection.html",
    "content": "<script language=\"JavaScript\">\n    if (window[\"selenium_has_been_loaded_into_this_window\"]==null)\n    {\n\n        __SELENIUM_JS__\n// Some background on the code below: broadly speaking, where we are relative to other windows\n// when running in proxy injection mode depends on whether we are in a frame set file or not.\n//\n// In regular HTML files, the selenium JavaScript is injected into an iframe called \"selenium\"\n// in order to reduce its impact on the JavaScript environment (through namespace pollution,\n// etc.).  So in regular HTML files, we need to look at the parent of the current window when we want\n// a handle to, e.g., the application window.\n//\n// In frame set files, we can't use an iframe, so we put the JavaScript in the head element and share\n// the window with the frame set.  So in this case, we need to look at the current window, not the\n// parent when looking for, e.g., the application window.  (TODO: Perhaps I should have just\n// assigned a regular frame for selenium?)\n//\nBrowserBot.prototype.getContentWindow = function() {\n    return window;\n};\n\nBrowserBot.prototype.getTargetWindow = function(windowName) {\n    return window;\n};\n\nBrowserBot.prototype.getCurrentWindow = function() {\n    return window;\n};\n\nLOG.openLogWindow = function(message, className) {\n\t// disable for now\n};\n\nBrowserBot.prototype.relayToRC = function(name) {\n\tvar object = eval(name);\n        var s = 'state:' + serializeObject(name, object) + \"\\n\";\n        sendToRC(s,\"state=true\");\n}\n\nfunction selenium_frameRunTest(oldOnLoadRoutine) {\n\tif (oldOnLoadRoutine) {\n\t\teval(oldOnLoadRoutine);\n\t}\n        runSeleniumTest();\n}\n\nfunction seleniumOnLoad() {\n    injectedSessionId = \"@SESSION_ID@\";\n    window[\"selenium_has_been_loaded_into_this_window\"] = true;\n    runSeleniumTest();\n}\n\nfunction seleniumOnUnload() {\n\tsendToRC(\"Current window or frame is closed!\", \"closing=true\");\n}\n\nif (window.addEventListener) {\n        window.addEventListener(\"load\", seleniumOnLoad, false);\t// firefox\n        window.addEventListener(\"unload\", seleniumOnUnload, false);\t// firefox\n} else if (window.attachEvent){\n    \twindow.attachEvent(\"onload\", seleniumOnLoad);\t// IE\n        window.attachEvent(\"onunload\", seleniumOnUnload);\t// IE\n}\nelse {\n    \tthrow \"causing a JavaScript error to tell the world that I did not arrange to be run on load\";\n}\n\ninjectedSessionId = \"@SESSION_ID@\";\nproxyInjectionMode = true;\n}\n</script>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-api.js",
    "content": "/*\n * Copyright 2004 ThoughtWorks, Inc\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\n// TODO: stop navigating this.browserbot.document() ... it breaks encapsulation\n\nvar storedVars = new Object();\n\nfunction Selenium(browserbot) {\n    /**\n     * Defines an object that runs Selenium commands.\n     *\n     * <h3><a name=\"locators\"></a>Element Locators</h3>\n     * <p>\n     * Element Locators tell Selenium which HTML element a command refers to.\n     * The format of a locator is:</p>\n     * <blockquote>\n     * <em>locatorType</em><strong>=</strong><em>argument</em>\n     * </blockquote>\n     *\n     * <p>\n     * We support the following strategies for locating elements:\n     * </p>\n     * \n     * <ul>\n     * <li><strong>identifier</strong>=<em>id</em>: \n     * Select the element with the specified &#064;id attribute. If no match is\n     * found, select the first element whose &#064;name attribute is <em>id</em>.\n     * (This is normally the default; see below.)</li>\n     * <li><strong>id</strong>=<em>id</em>:\n     * Select the element with the specified &#064;id attribute.</li>\n     *\n     * <li><strong>name</strong>=<em>name</em>:\n     * Select the first element with the specified &#064;name attribute.\n     * <ul class=\"first last simple\">\n     * <li>username</li>\n     * <li>name=username</li>\n     * </ul>\n     * \n     * <p>The name may optionally be followed by one or more <em>element-filters</em>, separated from the name by whitespace.  If the <em>filterType</em> is not specified, <strong>value</strong> is assumed.</p>\n     *\n     * <ul class=\"first last simple\">\n     * <li>name=flavour value=chocolate</li>\n     * </ul>\n     * </li>\n     * <li><strong>dom</strong>=<em>javascriptExpression</em>: \n     *\n     * Find an element by evaluating the specified string.  This allows you to traverse the HTML Document Object\n     * Model using JavaScript.  Note that you must not return a value in this string; simply make it the last expression in the block.\n     * <ul class=\"first last simple\">\n     * <li>dom=document.forms['myForm'].myDropdown</li>\n     * <li>dom=document.images[56]</li>\n     * <li>dom=function foo() { return document.links[1]; }; foo();</li>\n     * </ul>\n     *\n     * </li>\n     *\n     * <li><strong>xpath</strong>=<em>xpathExpression</em>: \n     * Locate an element using an XPath expression.\n     * <ul class=\"first last simple\">\n     * <li>xpath=//img[&#064;alt='The image alt text']</li>\n     * <li>xpath=//table[&#064;id='table1']//tr[4]/td[2]</li>\n     * <li>xpath=//a[contains(&#064;href,'#id1')]</li>\n     * <li>xpath=//a[contains(&#064;href,'#id1')]/&#064;class</li>\n     * <li>xpath=(//table[&#064;class='stylee'])//th[text()='theHeaderText']/../td</li>\n     * <li>xpath=//input[&#064;name='name2' and &#064;value='yes']</li>\n     * <li>xpath=//*[text()=\"right\"]</li>\n     *\n     * </ul>\n     * </li>\n     * <li><strong>link</strong>=<em>textPattern</em>:\n     * Select the link (anchor) element which contains text matching the\n     * specified <em>pattern</em>.\n     * <ul class=\"first last simple\">\n     * <li>link=The link text</li>\n     * </ul>\n     *\n     * </li>\n     *\n     * <li><strong>css</strong>=<em>cssSelectorSyntax</em>:\n     * Select the element using css selectors. Please refer to <a href=\"http://www.w3.org/TR/REC-CSS2/selector.html\">CSS2 selectors</a>, <a href=\"http://www.w3.org/TR/2001/CR-css3-selectors-20011113/\">CSS3 selectors</a> for more information. You can also check the TestCssLocators test in the selenium test suite for an example of usage, which is included in the downloaded selenium core package.\n     * <ul class=\"first last simple\">\n     * <li>css=a[href=\"#id3\"]</li>\n     * <li>css=span#firstChild + span</li>\n     * </ul>\n     * <p>Currently the css selector locator supports all css1, css2 and css3 selectors except namespace in css3, some pseudo classes(:nth-of-type, :nth-last-of-type, :first-of-type, :last-of-type, :only-of-type, :visited, :hover, :active, :focus, :indeterminate) and pseudo elements(::first-line, ::first-letter, ::selection, ::before, ::after). </p>\n     * </li>\n     * \n     * <li><strong>ui</strong>=<em>uiSpecifierString</em>:\n     * Locate an element by resolving the UI specifier string to another locator, and evaluating it. See the <a href=\"http://svn.openqa.org/fisheye/browse/~raw,r=trunk/selenium/trunk/src/main/resources/core/scripts/ui-doc.html\">Selenium UI-Element Reference</a> for more details.\n     * <ul class=\"first last simple\">\n     * <li>ui=loginPages::loginButton()</li>\n     * <li>ui=settingsPages::toggle(label=Hide Email)</li>\n     * <li>ui=forumPages::postBody(index=2)//a[2]</li>\n     * </ul>\n     * </li>\n     *\n     * </ul>\n     *\n     * <p>\n     * Without an explicit locator prefix, Selenium uses the following default\n     * strategies:\n     * </p>\n     *\n     * <ul class=\"simple\">\n     * <li><strong>dom</strong>, for locators starting with &quot;document.&quot;</li>\n     * <li><strong>xpath</strong>, for locators starting with &quot;//&quot;</li>\n     * <li><strong>identifier</strong>, otherwise</li>\n     * </ul>\n     *\n     * <h3><a name=\"element-filters\">Element Filters</a></h3>\n     * <blockquote>\n     * <p>Element filters can be used with a locator to refine a list of candidate elements.  They are currently used only in the 'name' element-locator.</p>\n     * <p>Filters look much like locators, ie.</p>\n     * <blockquote>\n     * <em>filterType</em><strong>=</strong><em>argument</em></blockquote>\n     *\n     * <p>Supported element-filters are:</p>\n     * <p><strong>value=</strong><em>valuePattern</em></p>\n     * <blockquote>\n     * Matches elements based on their values.  This is particularly useful for refining a list of similarly-named toggle-buttons.</blockquote>\n     * <p><strong>index=</strong><em>index</em></p>\n     * <blockquote>\n     * Selects a single element based on its position in the list (offset from zero).</blockquote>\n     * </blockquote>\n     *\n     * <h3><a name=\"patterns\"></a>String-match Patterns</h3>\n     *\n     * <p>\n     * Various Pattern syntaxes are available for matching string values:\n     * </p>\n     * <ul>\n     * <li><strong>glob:</strong><em>pattern</em>:\n     * Match a string against a \"glob\" (aka \"wildmat\") pattern. \"Glob\" is a\n     * kind of limited regular-expression syntax typically used in command-line\n     * shells. In a glob pattern, \"*\" represents any sequence of characters, and \"?\"\n     * represents any single character. Glob patterns match against the entire\n     * string.</li>\n     * <li><strong>regexp:</strong><em>regexp</em>:\n     * Match a string using a regular-expression. The full power of JavaScript\n     * regular-expressions is available.</li>\n     * <li><strong>regexpi:</strong><em>regexpi</em>:\n     * Match a string using a case-insensitive regular-expression.</li>\n     * <li><strong>exact:</strong><em>string</em>:\n     *\n     * Match a string exactly, verbatim, without any of that fancy wildcard\n     * stuff.</li>\n     * </ul>\n     * <p>\n     * If no pattern prefix is specified, Selenium assumes that it's a \"glob\"\n     * pattern.\n     * </p>\n     * <p>\n     * For commands that return multiple values (such as verifySelectOptions),\n     * the string being matched is a comma-separated list of the return values,\n     * where both commas and backslashes in the values are backslash-escaped.\n     * When providing a pattern, the optional matching syntax (i.e. glob,\n     * regexp, etc.) is specified once, as usual, at the beginning of the\n     * pattern.\n     * </p>\n     */\n    this.browserbot = browserbot;\n    this.optionLocatorFactory = new OptionLocatorFactory();\n    // DGF for backwards compatibility\n    this.page = function() {\n        return browserbot;\n    };\n    this.defaultTimeout = Selenium.DEFAULT_TIMEOUT;\n    this.mouseSpeed = 10;\n}\n\nSelenium.DEFAULT_TIMEOUT = 30 * 1000;\nSelenium.DEFAULT_MOUSE_SPEED = 10;\nSelenium.RIGHT_MOUSE_CLICK = 2;\n\nSelenium.decorateFunctionWithTimeout = function(f, timeout) {\n    if (f == null) {\n        return null;\n    }\n    \n    var timeoutTime = getTimeoutTime(timeout);\n    \n    return function() {\n        if (new Date().getTime() > timeoutTime) {\n            throw new SeleniumError(\"Timed out after \" + timeout + \"ms\");\n        }\n        return f();\n    };\n}\n\nSelenium.createForWindow = function(window, proxyInjectionMode) {\n    if (!window.location) {\n        throw \"error: not a window!\";\n    }\n    return new Selenium(BrowserBot.createForWindow(window, proxyInjectionMode));\n};\n\nSelenium.prototype.reset = function() {\n    this.defaultTimeout = Selenium.DEFAULT_TIMEOUT;\n    // todo: this.browserbot.reset()\n    this.browserbot.selectWindow(\"null\");\n    this.browserbot.resetPopups();\n};\n\nSelenium.prototype.doClick = function(locator) {\n    /**\n   * Clicks on a link, button, checkbox or radio button. If the click action\n   * causes a new page to load (like a link usually does), call\n   * waitForPageToLoad.\n   *\n   * @param locator an element locator\n   *\n   */\n    var element = this.browserbot.findElement(locator);\n    var elementWithHref = getAncestorOrSelfWithJavascriptHref(element);\n   \n    if (browserVersion.isChrome && elementWithHref != null) {\n        // SEL-621: Firefox chrome: Race condition bug in alert-handling code\n        //\n        // This appears to be because javascript href's are being executed in a\n        // separate thread from the main thread when running in chrome mode.\n        //\n        // This workaround injects a callback into the executing href that\n        // lowers a flag, which is initially raised. Execution of this click\n        // command will wait for the flag to be lowered.\n        \n        var win = elementWithHref.ownerDocument.defaultView;\n        var originalLocation = win.location.href;\n        var originalHref = elementWithHref.href;\n        \n        elementWithHref.href = 'javascript:try { '\n            + originalHref.replace(/^\\s*javascript:/i, \"\")\n            + '} finally { window._executingJavascriptHref = undefined; }' ;\n        \n        win._executingJavascriptHref = true;\n        \n        this.browserbot.clickElement(element);\n        \n        return Selenium.decorateFunctionWithTimeout(function() {\n            if (win.closed) {\n                return true;\n            }\n            if (win.location.href != originalLocation) {\n                // navigated to some other page ... javascript from previous\n                // page can't still be executing!\n                return true;\n            }\n            if (! win._executingJavascriptHref) {\n                try {\n                    elementWithHref.href = originalHref;\n                }\n                catch (e) {\n                    // maybe the javascript removed the element ... should be\n                    // no danger in not reverting its href attribute\n                }\n                return true;\n            }\n            \n            return false;\n        }, Selenium.DEFAULT_TIMEOUT);\n    }\n    \n    this.browserbot.clickElement(element);\n};\n\nSelenium.prototype.doDoubleClick = function(locator) {\n    /**\n   * Double clicks on a link, button, checkbox or radio button. If the double click action\n   * causes a new page to load (like a link usually does), call\n   * waitForPageToLoad.\n   *\n   * @param locator an element locator\n   *\n   */\n   var element = this.browserbot.findElement(locator);\n   this.browserbot.doubleClickElement(element);\n};\n\nSelenium.prototype.doContextMenu = function(locator) {\n    /**\n   * Simulates opening the context menu for the specified element (as might happen if the user \"right-clicked\" on the element).\n   *\n   * @param locator an element locator\n   *\n   */\n   var element = this.browserbot.findElement(locator);\n   this.browserbot.contextMenuOnElement(element);\n};\n\nSelenium.prototype.doClickAt = function(locator, coordString) {\n    /**\n   * Clicks on a link, button, checkbox or radio button. If the click action\n   * causes a new page to load (like a link usually does), call\n   * waitForPageToLoad.\n   *\n   * @param locator an element locator\n   * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse\n   *      event relative to the element returned by the locator.\n   *\n   */\n    var element = this.browserbot.findElement(locator);\n    var clientXY = getClientXY(element, coordString)\n    this.doMouseMove(locator);\n    this.doMouseDown(locator);\n    this.browserbot.clickElement(element, clientXY[0], clientXY[1]);\n    this.doMouseUp(locator);\n};\n\nSelenium.prototype.doDoubleClickAt = function(locator, coordString) {\n    /**\n   * Doubleclicks on a link, button, checkbox or radio button. If the action\n   * causes a new page to load (like a link usually does), call\n   * waitForPageToLoad.\n   *\n   * @param locator an element locator\n   * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse\n   *      event relative to the element returned by the locator.\n   *\n   */\n    var element = this.browserbot.findElement(locator);\n    var clientXY = getClientXY(element, coordString)\n    this.doMouseMove(locator);\n    this.doMouseDown(locator);\n    this.browserbot.doubleClickElement(element, clientXY[0], clientXY[1]);\n    this.doMouseUp(locator);\n};\n\nSelenium.prototype.doContextMenuAt = function(locator, coordString) {\n    /**\n   * Simulates opening the context menu for the specified element (as might happen if the user \"right-clicked\" on the element).\n   *\n   * @param locator an element locator\n   * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse\n   *      event relative to the element returned by the locator.\n   *\n   */\n    var element = this.browserbot.findElement(locator);\n    var clientXY = getClientXY(element, coordString)\n    this.browserbot.contextMenuOnElement(element, clientXY[0], clientXY[1]);\n};\n\nSelenium.prototype.doFireEvent = function(locator, eventName) {\n    /**\n   * Explicitly simulate an event, to trigger the corresponding &quot;on<em>event</em>&quot;\n   * handler.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @param eventName the event name, e.g. \"focus\" or \"blur\"\n   */\n    var element = this.browserbot.findElement(locator);\n    triggerEvent(element, eventName, false);\n};\n\nSelenium.prototype.doFocus = function(locator) {\n    /** Move the focus to the specified element; for example, if the element is an input field, move the cursor to that field.\n    *\n    * @param locator an <a href=\"#locators\">element locator</a>\n    */\n    var element = this.browserbot.findElement(locator);\n    if (element.focus) {\n        element.focus();\n    } else {\n         triggerEvent(element, \"focus\", false);\n    }\n}\n\nSelenium.prototype.doKeyPress = function(locator, keySequence) {\n    /**\n   * Simulates a user pressing and releasing a key.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @param keySequence Either be a string(\"\\\" followed by the numeric keycode\n   *  of the key to be pressed, normally the ASCII value of that key), or a single\n   *  character. For example: \"w\", \"\\119\".\n   */\n    var element = this.browserbot.findElement(locator);\n    triggerKeyEvent(element, 'keypress', keySequence, true, \n        this.browserbot.controlKeyDown, \n        this.browserbot.altKeyDown, \n            this.browserbot.shiftKeyDown,\n            this.browserbot.metaKeyDown);\n};\n\nSelenium.prototype.doShiftKeyDown = function() {\n    /**\n   * Press the shift key and hold it down until doShiftUp() is called or a new page is loaded.\n   *\n   */\n   this.browserbot.shiftKeyDown = true;\n};\n\nSelenium.prototype.doShiftKeyUp = function() {\n    /**\n   * Release the shift key.\n   *\n   */\n   this.browserbot.shiftKeyDown = false;\n};\n\nSelenium.prototype.doMetaKeyDown = function() {\n    /**\n   * Press the meta key and hold it down until doMetaUp() is called or a new page is loaded.\n   *\n   */\n   this.browserbot.metaKeyDown = true;\n};\n\nSelenium.prototype.doMetaKeyUp = function() {\n    /**\n   * Release the meta key.\n   *\n   */\n   this.browserbot.metaKeyDown = false;\n};\n\nSelenium.prototype.doAltKeyDown = function() {\n    /**\n   * Press the alt key and hold it down until doAltUp() is called or a new page is loaded.\n   *\n   */\n   this.browserbot.altKeyDown = true;\n};\n\nSelenium.prototype.doAltKeyUp = function() {\n    /**\n   * Release the alt key.\n   *\n   */\n   this.browserbot.altKeyDown = false;\n};\n\nSelenium.prototype.doControlKeyDown = function() {\n    /**\n   * Press the control key and hold it down until doControlUp() is called or a new page is loaded.\n   *\n   */\n   this.browserbot.controlKeyDown = true;\n};\n\nSelenium.prototype.doControlKeyUp = function() {\n    /**\n   * Release the control key.\n   *\n   */\n   this.browserbot.controlKeyDown = false;\n};\n\nSelenium.prototype.doKeyDown = function(locator, keySequence) {\n    /**\n   * Simulates a user pressing a key (without releasing it yet).\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @param keySequence Either be a string(\"\\\" followed by the numeric keycode\n   *  of the key to be pressed, normally the ASCII value of that key), or a single\n   *  character. For example: \"w\", \"\\119\".\n   */\n    var element = this.browserbot.findElement(locator);\n    triggerKeyEvent(element, 'keydown', keySequence, true,\n        this.browserbot.controlKeyDown, \n            this.browserbot.altKeyDown, \n            this.browserbot.shiftKeyDown, \n            this.browserbot.metaKeyDown);\n};\n\nSelenium.prototype.doKeyUp = function(locator, keySequence) {\n    /**\n   * Simulates a user releasing a key.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @param keySequence Either be a string(\"\\\" followed by the numeric keycode\n   *  of the key to be pressed, normally the ASCII value of that key), or a single\n   *  character. For example: \"w\", \"\\119\".\n   */\n    var element = this.browserbot.findElement(locator);\n    triggerKeyEvent(element, 'keyup', keySequence, true,\n        this.browserbot.controlKeyDown, \n            this.browserbot.altKeyDown, \n        this.browserbot.shiftKeyDown,\n        this.browserbot.metaKeyDown);\n};\n\nfunction getClientXY(element, coordString) {\n   // Parse coordString\n   var coords = null;\n   var x;\n   var y;\n   if (coordString) {\n      coords = coordString.split(/,/);\n      x = Number(coords[0]);\n      y = Number(coords[1]);\n   }\n   else {\n      x = y = 0;\n   }\n\n   // Get position of element,\n   // Return 2 item array with clientX and clientY\n   return [Selenium.prototype.getElementPositionLeft(element) + x, Selenium.prototype.getElementPositionTop(element) + y];\n}\n\nSelenium.prototype.doMouseOver = function(locator) {\n    /**\n   * Simulates a user hovering a mouse over the specified element.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   */\n    var element = this.browserbot.findElement(locator);\n    this.browserbot.triggerMouseEvent(element, 'mouseover', true);\n};\n\nSelenium.prototype.doMouseOut = function(locator) {\n   /**\n   * Simulates a user moving the mouse pointer away from the specified element.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   */\n    var element = this.browserbot.findElement(locator);\n    this.browserbot.triggerMouseEvent(element, 'mouseout', true);\n};\n\nSelenium.prototype.doMouseDown = function(locator) {\n    /**\n   * Simulates a user pressing the left mouse button (without releasing it yet) on\n   * the specified element.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   */\n   var element = this.browserbot.findElement(locator);\n   this.browserbot.triggerMouseEvent(element, 'mousedown', true);\n};\n\nSelenium.prototype.doMouseDownRight = function(locator) {\n    /**\n   * Simulates a user pressing the right mouse button (without releasing it yet) on\n   * the specified element.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   */\n   var element = this.browserbot.findElement(locator);\n   this.browserbot.triggerMouseEvent(element, 'mousedown', true, undefined, undefined, Selenium.RIGHT_MOUSE_CLICK);\n};\n\nSelenium.prototype.doMouseDownAt = function(locator, coordString) {\n    /**\n   * Simulates a user pressing the left mouse button (without releasing it yet) at\n   * the specified location.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse\n   *      event relative to the element returned by the locator.\n   */\n    var element = this.browserbot.findElement(locator);\n    var clientXY = getClientXY(element, coordString)\n\n    this.browserbot.triggerMouseEvent(element, 'mousedown', true, clientXY[0], clientXY[1]);\n};\n\nSelenium.prototype.doMouseDownRightAt = function(locator, coordString) {\n    /**\n   * Simulates a user pressing the right mouse button (without releasing it yet) at\n   * the specified location.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse\n   *      event relative to the element returned by the locator.\n   */\n    var element = this.browserbot.findElement(locator);\n    var clientXY = getClientXY(element, coordString)\n\n    this.browserbot.triggerMouseEvent(element, 'mousedown', true, clientXY[0], clientXY[1], Selenium.RIGHT_MOUSE_CLICK);\n};\n\nSelenium.prototype.doMouseUp = function(locator) {\n    /**\n   * Simulates the event that occurs when the user releases the mouse button (i.e., stops\n   * holding the button down) on the specified element.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   */\n   var element = this.browserbot.findElement(locator);\n   this.browserbot.triggerMouseEvent(element, 'mouseup', true);\n};\n\nSelenium.prototype.doMouseUpRight = function(locator) {\n    /**\n   * Simulates the event that occurs when the user releases the right mouse button (i.e., stops\n   * holding the button down) on the specified element.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   */\n   var element = this.browserbot.findElement(locator);\n   this.browserbot.triggerMouseEvent(element, 'mouseup', true, undefined, undefined, Selenium.RIGHT_MOUSE_CLICK);\n};\n\nSelenium.prototype.doMouseUpAt = function(locator, coordString) {\n    /**\n   * Simulates the event that occurs when the user releases the mouse button (i.e., stops\n   * holding the button down) at the specified location.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse\n   *      event relative to the element returned by the locator.\n   */\n    var element = this.browserbot.findElement(locator);\n    var clientXY = getClientXY(element, coordString)\n\n    this.browserbot.triggerMouseEvent(element, 'mouseup', true, clientXY[0], clientXY[1]);\n};\n\nSelenium.prototype.doMouseUpRightAt = function(locator, coordString) {\n    /**\n   * Simulates the event that occurs when the user releases the right mouse button (i.e., stops\n   * holding the button down) at the specified location.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse\n   *      event relative to the element returned by the locator.\n   */\n    var element = this.browserbot.findElement(locator);\n    var clientXY = getClientXY(element, coordString)\n\n    this.browserbot.triggerMouseEvent(element, 'mouseup', true, clientXY[0], clientXY[1], Selenium.RIGHT_MOUSE_CLICK);\n};\n\nSelenium.prototype.doMouseMove = function(locator) {\n    /**\n   * Simulates a user pressing the mouse button (without releasing it yet) on\n   * the specified element.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   */\n   var element = this.browserbot.findElement(locator);\n   this.browserbot.triggerMouseEvent(element, 'mousemove', true);\n};\n\nSelenium.prototype.doMouseMoveAt = function(locator, coordString) {\n    /**\n   * Simulates a user pressing the mouse button (without releasing it yet) on\n   * the specified element.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @param coordString specifies the x,y position (i.e. - 10,20) of the mouse\n   *      event relative to the element returned by the locator.\n   */\n\n    var element = this.browserbot.findElement(locator);\n    var clientXY = getClientXY(element, coordString)\n\n    this.browserbot.triggerMouseEvent(element, 'mousemove', true, clientXY[0], clientXY[1]);\n};\n\nSelenium.prototype.doType = function(locator, value) {\n    /**\n   * Sets the value of an input field, as though you typed it in.\n   *\n   * <p>Can also be used to set the value of combo boxes, check boxes, etc. In these cases,\n   * value should be the value of the option selected, not the visible text.</p>\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @param value the value to type\n   */\n   if (this.browserbot.controlKeyDown || this.browserbot.altKeyDown || this.browserbot.metaKeyDown) {\n        throw new SeleniumError(\"type not supported immediately after call to controlKeyDown() or altKeyDown() or metaKeyDown()\");\n    }\n        // TODO fail if it can't be typed into.\n    var element = this.browserbot.findElement(locator);\n    if (this.browserbot.shiftKeyDown) {\n        value = new String(value).toUpperCase();\n    }\n    this.browserbot.replaceText(element, value);\n};\n\nSelenium.prototype.doTypeKeys = function(locator, value) {\n    /**\n    * Simulates keystroke events on the specified element, as though you typed the value key-by-key.\n    *\n    * <p>This is a convenience method for calling keyDown, keyUp, keyPress for every character in the specified string;\n    * this is useful for dynamic UI widgets (like auto-completing combo boxes) that require explicit key events.</p>\n    * \n    * <p>Unlike the simple \"type\" command, which forces the specified value into the page directly, this command\n    * may or may not have any visible effect, even in cases where typing keys would normally have a visible effect.\n    * For example, if you use \"typeKeys\" on a form element, you may or may not see the results of what you typed in\n    * the field.</p>\n    * <p>In some cases, you may need to use the simple \"type\" command to set the value of the field and then the \"typeKeys\" command to\n    * send the keystroke events corresponding to what you just typed.</p>\n    *\n    * @param locator an <a href=\"#locators\">element locator</a>\n    * @param value the value to type\n    */\n    var keys = new String(value).split(\"\");\n    for (var i = 0; i < keys.length; i++) {\n        var c = keys[i];\n        this.doKeyDown(locator, c);\n        this.doKeyUp(locator, c);\n        this.doKeyPress(locator, c);\n    }\n};\n\nSelenium.prototype.doSetSpeed = function(value) {\n /**\n * Set execution speed (i.e., set the millisecond length of a delay which will follow each selenium operation).  By default, there is no such delay, i.e.,\n * the delay is 0 milliseconds.\n   *\n   * @param value the number of milliseconds to pause after operation\n   */\n   throw new SeleniumError(\"this operation is only implemented in selenium-rc, and should never result in a request making it across the wire\");\n};\n\nSelenium.prototype.getSpeed = function() {\n /**\n * Get execution speed (i.e., get the millisecond length of the delay following each selenium operation).  By default, there is no such delay, i.e.,\n * the delay is 0 milliseconds.\n   *\n   * See also setSpeed.\n   *\n   * @return string the execution speed in milliseconds.\n   */\n   throw new SeleniumError(\"this operation is only implemented in selenium-rc, and should never result in a request making it across the wire\");\n};\n\nSelenium.prototype.findToggleButton = function(locator) {\n    var element = this.browserbot.findElement(locator);\n    if (element.checked == null) {\n        Assert.fail(\"Element \" + locator + \" is not a toggle-button.\");\n    }\n    return element;\n}\n\nSelenium.prototype.doCheck = function(locator) {\n    /**\n   * Check a toggle-button (checkbox/radio)\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   */\n    this.findToggleButton(locator).checked = true;\n};\n\nSelenium.prototype.doUncheck = function(locator) {\n    /**\n   * Uncheck a toggle-button (checkbox/radio)\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   */\n    this.findToggleButton(locator).checked = false;\n};\n\nSelenium.prototype.doSelect = function(selectLocator, optionLocator) {\n    /**\n   * Select an option from a drop-down using an option locator.\n   *\n   * <p>\n   * Option locators provide different ways of specifying options of an HTML\n   * Select element (e.g. for selecting a specific option, or for asserting\n   * that the selected option satisfies a specification). There are several\n   * forms of Select Option Locator.\n   * </p>\n   * <ul>\n   * <li><strong>label</strong>=<em>labelPattern</em>:\n   * matches options based on their labels, i.e. the visible text. (This\n   * is the default.)\n   * <ul class=\"first last simple\">\n   * <li>label=regexp:^[Oo]ther</li>\n   * </ul>\n   * </li>\n   * <li><strong>value</strong>=<em>valuePattern</em>:\n   * matches options based on their values.\n   * <ul class=\"first last simple\">\n   * <li>value=other</li>\n   * </ul>\n   *\n   *\n   * </li>\n   * <li><strong>id</strong>=<em>id</em>:\n   *\n   * matches options based on their ids.\n   * <ul class=\"first last simple\">\n   * <li>id=option1</li>\n   * </ul>\n   * </li>\n   * <li><strong>index</strong>=<em>index</em>:\n   * matches an option based on its index (offset from zero).\n   * <ul class=\"first last simple\">\n   *\n   * <li>index=2</li>\n   * </ul>\n   * </li>\n   * </ul>\n   * <p>\n   * If no option locator prefix is provided, the default behaviour is to match on <strong>label</strong>.\n   * </p>\n   *\n   *\n   * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n   * @param optionLocator an option locator (a label by default)\n   */\n    var element = this.browserbot.findElement(selectLocator);\n    if (!(\"options\" in element)) {\n        throw new SeleniumError(\"Specified element is not a Select (has no options)\");\n    }\n    var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);\n    var option = locator.findOption(element);\n    this.browserbot.selectOption(element, option);\n};\n\n\n\nSelenium.prototype.doAddSelection = function(locator, optionLocator) {\n    /**\n   * Add a selection to the set of selected options in a multi-select element using an option locator.\n   *\n   * @see #doSelect for details of option locators\n   *\n   * @param locator an <a href=\"#locators\">element locator</a> identifying a multi-select box\n   * @param optionLocator an option locator (a label by default)\n   */\n    var element = this.browserbot.findElement(locator);\n    if (!(\"options\" in element)) {\n        throw new SeleniumError(\"Specified element is not a Select (has no options)\");\n    }\n    var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);\n    var option = locator.findOption(element);\n    this.browserbot.addSelection(element, option);\n};\n\nSelenium.prototype.doRemoveSelection = function(locator, optionLocator) {\n    /**\n   * Remove a selection from the set of selected options in a multi-select element using an option locator.\n   *\n   * @see #doSelect for details of option locators\n   *\n   * @param locator an <a href=\"#locators\">element locator</a> identifying a multi-select box\n   * @param optionLocator an option locator (a label by default)\n   */\n\n    var element = this.browserbot.findElement(locator);\n    if (!(\"options\" in element)) {\n        throw new SeleniumError(\"Specified element is not a Select (has no options)\");\n    }\n    var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);\n    var option = locator.findOption(element);\n    this.browserbot.removeSelection(element, option);\n};\n\nSelenium.prototype.doRemoveAllSelections = function(locator) {\n    /**\n    * Unselects all of the selected options in a multi-select element.\n    *\n    * @param locator an <a href=\"#locators\">element locator</a> identifying a multi-select box\n    */\n    var element = this.browserbot.findElement(locator);\n    if (!(\"options\" in element)) {\n        throw new SeleniumError(\"Specified element is not a Select (has no options)\");\n    }\n    for (var i = 0; i < element.options.length; i++) {\n        this.browserbot.removeSelection(element, element.options[i]);\n    }\n}\n\nSelenium.prototype.doSubmit = function(formLocator) {\n    /**\n   * Submit the specified form. This is particularly useful for forms without\n   * submit buttons, e.g. single-input \"Search\" forms.\n   *\n   * @param formLocator an <a href=\"#locators\">element locator</a> for the form you want to submit\n   */\n    var form = this.browserbot.findElement(formLocator);\n    return this.browserbot.submit(form);\n\n};\n\nSelenium.prototype.makePageLoadCondition = function(timeout) {\n    if (timeout == null) {\n        timeout = this.defaultTimeout;\n    }\n    // if the timeout is zero, we won't wait for the page to load before returning\n    if (timeout == 0) {\n    \t  return;\n    }\n    return Selenium.decorateFunctionWithTimeout(fnBind(this._isNewPageLoaded, this), timeout);\n};\n\nSelenium.prototype.doOpen = function(url) {\n    /**\n   * Opens an URL in the test frame. This accepts both relative and absolute\n   * URLs.\n   *\n   * The &quot;open&quot; command waits for the page to load before proceeding,\n   * ie. the &quot;AndWait&quot; suffix is implicit.\n   *\n   * <em>Note</em>: The URL must be on the same domain as the runner HTML\n   * due to security restrictions in the browser (Same Origin Policy). If you\n   * need to open an URL on another domain, use the Selenium Server to start a\n   * new browser session on that domain.\n   *\n   * @param url the URL to open; may be relative or absolute\n   */\n    this.browserbot.openLocation(url);\n    if (window[\"proxyInjectionMode\"] == null || !window[\"proxyInjectionMode\"]) {\n        return this.makePageLoadCondition();\n    } // in PI mode, just return \"OK\"; the server will waitForLoad\n};\n\nSelenium.prototype.doOpenWindow = function(url, windowID) {\n    /**\n   * Opens a popup window (if a window with that ID isn't already open).\n   * After opening the window, you'll need to select it using the selectWindow\n   * command.\n   * \n   * <p>This command can also be a useful workaround for bug SEL-339.  In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the \"onLoad\" event, for example).\n   * In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using\n   * an empty (blank) url, like this: openWindow(\"\", \"myFunnyWindow\").</p>\n   *\n   * @param url the URL to open, which can be blank \n   * @param windowID the JavaScript window ID of the window to select\n   */\n   this.browserbot.openWindow(url, windowID);\n};\n\nSelenium.prototype.doSelectWindow = function(windowID) {\n    /**\n   * Selects a popup window using a window locator; once a popup window has been selected, all\n   * commands go to that window. To select the main window again, use null\n   * as the target.\n   *\n   * <p>\n   * \n   * Window locators provide different ways of specifying the window object:\n   * by title, by internal JavaScript \"name,\" or by JavaScript variable.\n   * </p>\n   * <ul>\n   * <li><strong>title</strong>=<em>My Special Window</em>:\n   * Finds the window using the text that appears in the title bar.  Be careful;\n   * two windows can share the same title.  If that happens, this locator will\n   * just pick one.\n   * </li>\n   * <li><strong>name</strong>=<em>myWindow</em>:\n   * Finds the window using its internal JavaScript \"name\" property.  This is the second \n   * parameter \"windowName\" passed to the JavaScript method window.open(url, windowName, windowFeatures, replaceFlag)\n   * (which Selenium intercepts).\n   * </li>\n   * <li><strong>var</strong>=<em>variableName</em>:\n   * Some pop-up windows are unnamed (anonymous), but are associated with a JavaScript variable name in the current\n   * application window, e.g. \"window.foo = window.open(url);\".  In those cases, you can open the window using\n   * \"var=foo\".\n   * </li>\n   * </ul>\n   * <p>\n   * If no window locator prefix is provided, we'll try to guess what you mean like this:</p>\n   * <p>1.) if windowID is null, (or the string \"null\") then it is assumed the user is referring to the original window instantiated by the browser).</p>\n   * <p>2.) if the value of the \"windowID\" parameter is a JavaScript variable name in the current application window, then it is assumed\n   * that this variable contains the return value from a call to the JavaScript window.open() method.</p>\n   * <p>3.) Otherwise, selenium looks in a hash it maintains that maps string names to window \"names\".</p>\n   * <p>4.) If <em>that</em> fails, we'll try looping over all of the known windows to try to find the appropriate \"title\".\n   * Since \"title\" is not necessarily unique, this may have unexpected behavior.</p>\n   * \n   * <p>If you're having trouble figuring out the name of a window that you want to manipulate, look at the Selenium log messages\n   * which identify the names of windows created via window.open (and therefore intercepted by Selenium).  You will see messages\n   * like the following for each window as it is opened:</p>\n   * \n   * <p><code>debug: window.open call intercepted; window ID (which you can use with selectWindow()) is \"myNewWindow\"</code></p>\n   *\n   * <p>In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the \"onLoad\" event, for example).\n   * (This is bug SEL-339.)  In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using\n   * an empty (blank) url, like this: openWindow(\"\", \"myFunnyWindow\").</p>\n   * \n   * @param windowID the JavaScript window ID of the window to select\n   */\n    this.browserbot.selectWindow(windowID);\n};\n\nSelenium.prototype.doSelectFrame = function(locator) {\n    /**\n    * Selects a frame within the current window.  (You may invoke this command\n    * multiple times to select nested frames.)  To select the parent frame, use\n    * \"relative=parent\" as a locator; to select the top frame, use \"relative=top\".\n    * You can also select a frame by its 0-based index number; select the first frame with\n    * \"index=0\", or the third frame with \"index=2\".\n    *\n    * <p>You may also use a DOM expression to identify the frame you want directly,\n    * like this: <code>dom=frames[\"main\"].frames[\"subframe\"]</code></p>\n    *\n    * @param locator an <a href=\"#locators\">element locator</a> identifying a frame or iframe\n    */\n        this.browserbot.selectFrame(locator);\n};\n\nSelenium.prototype.getWhetherThisFrameMatchFrameExpression = function(currentFrameString, target) {\n    /**\n     * Determine whether current/locator identify the frame containing this running code.\n     *\n     * <p>This is useful in proxy injection mode, where this code runs in every\n     * browser frame and window, and sometimes the selenium server needs to identify\n     * the \"current\" frame.  In this case, when the test calls selectFrame, this\n     * routine is called for each frame to figure out which one has been selected.\n     * The selected frame will return true, while all others will return false.</p>\n     *\n     * @param currentFrameString starting frame\n     * @param target new frame (which might be relative to the current one)\n     * @return boolean true if the new frame is this code's window\n     */\n    return this.browserbot.doesThisFrameMatchFrameExpression(currentFrameString, target);\n};\n\nSelenium.prototype.getWhetherThisWindowMatchWindowExpression = function(currentWindowString, target) {\n    /**\n    * Determine whether currentWindowString plus target identify the window containing this running code.\n     *\n     * <p>This is useful in proxy injection mode, where this code runs in every\n     * browser frame and window, and sometimes the selenium server needs to identify\n     * the \"current\" window.  In this case, when the test calls selectWindow, this\n     * routine is called for each window to figure out which one has been selected.\n     * The selected window will return true, while all others will return false.</p>\n     *\n     * @param currentWindowString starting window\n     * @param target new window (which might be relative to the current one, e.g., \"_parent\")\n     * @return boolean true if the new window is this code's window\n     */\n     if (window.opener!=null && window.opener[target]!=null && window.opener[target]==window) {\n         return true;\n     }\n     return false;\n};\n\nSelenium.prototype.doWaitForPopUp = function(windowID, timeout) {\n    /**\n    * Waits for a popup window to appear and load up.\n    *\n    * @param windowID the JavaScript window \"name\" of the window that will appear (not the text of the title bar)\n    * @param timeout a timeout in milliseconds, after which the action will return with an error\n    */\n    var timeoutTime = getTimeoutTime(timeout);\n    \n    var popupLoadedPredicate = function () {\n        var targetWindow;\n        try {\n            targetWindow = selenium.browserbot.getWindowByName(windowID, true);\n        }\n        catch (e) {\n            if (new Date().getTime() > timeoutTime) {\n                throw e;\n            }\n        }\n        \n        if (!targetWindow) return false;\n        if (!targetWindow.location) return false;\n        if (\"about:blank\" == targetWindow.location) return false;\n        if (browserVersion.isKonqueror) {\n            if (\"/\" == targetWindow.location.href) {\n                // apparently Konqueror uses this as the temporary location, instead of about:blank\n                return false;\n            }\n        }\n        if (browserVersion.isSafari) {\n            if(targetWindow.location.href == selenium.browserbot.buttonWindow.location.href) {\n                // Apparently Safari uses this as the temporary location, instead of about:blank\n                // what a world!\n                LOG.debug(\"DGF what a world!\");\n                return false;\n            }\n        }\n        if (!targetWindow.document) return false;\n        if (!selenium.browserbot.getCurrentWindow().document.readyState) {\n            // This is Firefox, with no readyState extension\n            return true;\n        }\n        if ('complete' != targetWindow.document.readyState) return false;\n        return true;\n    };\n\n    return Selenium.decorateFunctionWithTimeout(popupLoadedPredicate, timeout);\n}\n\nSelenium.prototype.doWaitForPopUp.dontCheckAlertsAndConfirms = true;\n\nSelenium.prototype.doChooseCancelOnNextConfirmation = function() {\n    /**\n   * <p>\n   * By default, Selenium's overridden window.confirm() function will\n   * return true, as if the user had manually clicked OK; after running\n   * this command, the next call to confirm() will return false, as if\n   * the user had clicked Cancel.  Selenium will then resume using the\n   * default behavior for future confirmations, automatically returning \n   * true (OK) unless/until you explicitly call this command for each\n   * confirmation.\n   * </p>\n   * <p>\n   * Take note - every time a confirmation comes up, you must\n   * consume it with a corresponding getConfirmation, or else\n   * the next selenium operation will fail.\n   * </p>\n   */\n    this.browserbot.cancelNextConfirmation(false);\n};\n\nSelenium.prototype.doChooseOkOnNextConfirmation = function() {\n    /**\n   * <p>\n   * Undo the effect of calling chooseCancelOnNextConfirmation.  Note\n   * that Selenium's overridden window.confirm() function will normally automatically\n   * return true, as if the user had manually clicked OK, so you shouldn't\n   * need to use this command unless for some reason you need to change\n   * your mind prior to the next confirmation.  After any confirmation, Selenium will resume using the\n   * default behavior for future confirmations, automatically returning \n   * true (OK) unless/until you explicitly call chooseCancelOnNextConfirmation for each\n   * confirmation.\n   * </p>\n   * <p>\n   * Take note - every time a confirmation comes up, you must\n   * consume it with a corresponding getConfirmation, or else\n   * the next selenium operation will fail.\n   * </p>\n   *\n   */\n    this.browserbot.cancelNextConfirmation(true);\n};\n\nSelenium.prototype.doAnswerOnNextPrompt = function(answer) {\n    /**\n   * Instructs Selenium to return the specified answer string in response to\n   * the next JavaScript prompt [window.prompt()].\n   *\n   *\n   * @param answer the answer to give in response to the prompt pop-up\n   */\n    this.browserbot.setNextPromptResult(answer);\n};\n\nSelenium.prototype.doGoBack = function() {\n    /**\n     * Simulates the user clicking the \"back\" button on their browser.\n     *\n     */\n    this.browserbot.goBack();\n};\n\nSelenium.prototype.doRefresh = function() {\n    /**\n     * Simulates the user clicking the \"Refresh\" button on their browser.\n     *\n     */\n    this.browserbot.refresh();\n};\n\nSelenium.prototype.doClose = function() {\n    /**\n     * Simulates the user clicking the \"close\" button in the titlebar of a popup\n     * window or tab.\n     */\n    this.browserbot.close();\n};\n\nSelenium.prototype.ensureNoUnhandledPopups = function() {\n    if (this.browserbot.hasAlerts()) {\n        throw new SeleniumError(\"There was an unexpected Alert! [\" + this.browserbot.getNextAlert() + \"]\");\n    }\n    if ( this.browserbot.hasConfirmations() ) {\n        throw new SeleniumError(\"There was an unexpected Confirmation! [\" + this.browserbot.getNextConfirmation() + \"]\");\n    }\n};\n\nSelenium.prototype.isAlertPresent = function() {\n   /**\n   * Has an alert occurred?\n   *\n   * <p>\n   * This function never throws an exception\n   * </p>\n   * @return boolean true if there is an alert\n   */\n    return this.browserbot.hasAlerts();\n};\n\nSelenium.prototype.isPromptPresent = function() {\n   /**\n   * Has a prompt occurred?\n   *\n   * <p>\n   * This function never throws an exception\n   * </p>\n   * @return boolean true if there is a pending prompt\n   */\n    return this.browserbot.hasPrompts();\n};\n\nSelenium.prototype.isConfirmationPresent = function() {\n   /**\n   * Has confirm() been called?\n   *\n   * <p>\n   * This function never throws an exception\n   * </p>\n   * @return boolean true if there is a pending confirmation\n   */\n    return this.browserbot.hasConfirmations();\n};\nSelenium.prototype.getAlert = function() {\n    /**\n   * Retrieves the message of a JavaScript alert generated during the previous action, or fail if there were no alerts.\n   *\n   * <p>Getting an alert has the same effect as manually clicking OK. If an\n   * alert is generated but you do not consume it with getAlert, the next Selenium action\n   * will fail.</p>\n   *\n   * <p>Under Selenium, JavaScript alerts will NOT pop up a visible alert\n   * dialog.</p>\n   *\n   * <p>Selenium does NOT support JavaScript alerts that are generated in a\n   * page's onload() event handler. In this case a visible dialog WILL be\n   * generated and Selenium will hang until someone manually clicks OK.</p>\n   * @return string The message of the most recent JavaScript alert\n\n   */\n    if (!this.browserbot.hasAlerts()) {\n        Assert.fail(\"There were no alerts\");\n    }\n    return this.browserbot.getNextAlert();\n};\nSelenium.prototype.getAlert.dontCheckAlertsAndConfirms = true;\n\nSelenium.prototype.getConfirmation = function() {\n    /**\n   * Retrieves the message of a JavaScript confirmation dialog generated during\n   * the previous action.\n   *\n   * <p>\n   * By default, the confirm function will return true, having the same effect\n   * as manually clicking OK. This can be changed by prior execution of the\n   * chooseCancelOnNextConfirmation command. \n   * </p>\n   * <p>\n   * If an confirmation is generated but you do not consume it with getConfirmation,\n   * the next Selenium action will fail.\n   * </p>\n   *\n   * <p>\n   * NOTE: under Selenium, JavaScript confirmations will NOT pop up a visible\n   * dialog.\n   * </p>\n   *\n   * <p>\n   * NOTE: Selenium does NOT support JavaScript confirmations that are\n   * generated in a page's onload() event handler. In this case a visible\n   * dialog WILL be generated and Selenium will hang until you manually click\n   * OK.\n   * </p>\n   *\n   * @return string the message of the most recent JavaScript confirmation dialog\n   */\n    if (!this.browserbot.hasConfirmations()) {\n        Assert.fail(\"There were no confirmations\");\n    }\n    return this.browserbot.getNextConfirmation();\n};\nSelenium.prototype.getConfirmation.dontCheckAlertsAndConfirms = true;\n\nSelenium.prototype.getPrompt = function() {\n    /**\n   * Retrieves the message of a JavaScript question prompt dialog generated during\n   * the previous action.\n   *\n   * <p>Successful handling of the prompt requires prior execution of the\n   * answerOnNextPrompt command. If a prompt is generated but you\n   * do not get/verify it, the next Selenium action will fail.</p>\n   *\n   * <p>NOTE: under Selenium, JavaScript prompts will NOT pop up a visible\n   * dialog.</p>\n   *\n   * <p>NOTE: Selenium does NOT support JavaScript prompts that are generated in a\n   * page's onload() event handler. In this case a visible dialog WILL be\n   * generated and Selenium will hang until someone manually clicks OK.</p>\n   * @return string the message of the most recent JavaScript question prompt\n   */\n    if (! this.browserbot.hasPrompts()) {\n        Assert.fail(\"There were no prompts\");\n    }\n    return this.browserbot.getNextPrompt();\n};\n\nSelenium.prototype.getLocation = function() {\n    /** Gets the absolute URL of the current page.\n   *\n   * @return string the absolute URL of the current page\n   */\n    return this.browserbot.getCurrentWindow().location.href;\n};\n\nSelenium.prototype.getTitle = function() {\n    /** Gets the title of the current page.\n   *\n   * @return string the title of the current page\n   */\n    return this.browserbot.getTitle();\n};\n\n\nSelenium.prototype.getBodyText = function() {\n    /**\n     * Gets the entire text of the page.\n     * @return string the entire text of the page\n     */\n    return this.browserbot.bodyText();\n};\n\n\nSelenium.prototype.getValue = function(locator) {\n  /**\n   * Gets the (whitespace-trimmed) value of an input field (or anything else with a value parameter).\n   * For checkbox/radio elements, the value will be \"on\" or \"off\" depending on\n   * whether the element is checked or not.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @return string the element value, or \"on/off\" for checkbox/radio elements\n   */\n    var element = this.browserbot.findElement(locator)\n    return getInputValue(element).trim();\n}\n\nSelenium.prototype.getText = function(locator) {\n    /**\n   * Gets the text of an element. This works for any element that contains\n   * text. This command uses either the textContent (Mozilla-like browsers) or\n   * the innerText (IE-like browsers) of the element, which is the rendered\n   * text shown to the user.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @return string the text of the element\n   */\n    var element = this.browserbot.findElement(locator);\n    return getText(element).trim();\n};\n\nSelenium.prototype.doHighlight = function(locator) {\n    /**\n    * Briefly changes the backgroundColor of the specified element yellow.  Useful for debugging.\n    * \n    * @param locator an <a href=\"#locators\">element locator</a>\n    */\n    var element = this.browserbot.findElement(locator);\n    this.browserbot.highlight(element, true);\n};\n\nSelenium.prototype.getEval = function(script) {\n    /** Gets the result of evaluating the specified JavaScript snippet.  The snippet may\n   * have multiple lines, but only the result of the last line will be returned.\n   *\n   * <p>Note that, by default, the snippet will run in the context of the \"selenium\"\n   * object itself, so <code>this</code> will refer to the Selenium object.  Use <code>window</code> to\n   * refer to the window of your application, e.g. <code>window.document.getElementById('foo')</code></p>\n   *\n   * <p>If you need to use\n   * a locator to refer to a single element in your application page, you can\n   * use <code>this.browserbot.findElement(\"id=foo\")</code> where \"id=foo\" is your locator.</p>\n   *\n   * @param script the JavaScript snippet to run\n   * @return string the results of evaluating the snippet\n   */\n    try {\n        var window = this.browserbot.getCurrentWindow();\n        var result = eval(script);\n        // Selenium RC doesn't allow returning null\n        if (null == result) return \"null\";\n        return result;\n    } catch (e) {\n        throw new SeleniumError(\"Threw an exception: \" + extractExceptionMessage(e));\n    }\n};\n\nSelenium.prototype.isChecked = function(locator) {\n    /**\n   * Gets whether a toggle-button (checkbox/radio) is checked.  Fails if the specified element doesn't exist or isn't a toggle-button.\n   * @param locator an <a href=\"#locators\">element locator</a> pointing to a checkbox or radio button\n   * @return boolean true if the checkbox is checked, false otherwise\n   */\n    var element = this.browserbot.findElement(locator);\n    if (element.checked == null) {\n        throw new SeleniumError(\"Element \" + locator + \" is not a toggle-button.\");\n    }\n    return element.checked;\n};\n\nSelenium.prototype.getTable = function(tableCellAddress) {\n    /**\n   * Gets the text from a cell of a table. The cellAddress syntax\n   * tableLocator.row.column, where row and column start at 0.\n   *\n   * @param tableCellAddress a cell address, e.g. \"foo.1.4\"\n   * @return string the text from the specified cell\n   */\n    // This regular expression matches \"tableName.row.column\"\n    // For example, \"mytable.3.4\"\n    pattern = /(.*)\\.(\\d+)\\.(\\d+)/;\n\n    if(!pattern.test(tableCellAddress)) {\n        throw new SeleniumError(\"Invalid target format. Correct format is tableName.rowNum.columnNum\");\n    }\n\n    pieces = tableCellAddress.match(pattern);\n\n    tableName = pieces[1];\n    row = pieces[2];\n    col = pieces[3];\n\n    var table = this.browserbot.findElement(tableName);\n    if (row > table.rows.length) {\n        Assert.fail(\"Cannot access row \" + row + \" - table has \" + table.rows.length + \" rows\");\n    }\n    else if (col > table.rows[row].cells.length) {\n        Assert.fail(\"Cannot access column \" + col + \" - table row has \" + table.rows[row].cells.length + \" columns\");\n    }\n    else {\n        actualContent = getText(table.rows[row].cells[col]);\n        return actualContent.trim();\n    }\n    return null;\n};\n\nSelenium.prototype.getSelectedLabels = function(selectLocator) {\n    /** Gets all option labels (visible text) for selected options in the specified select or multi-select element.\n   *\n   * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n   * @return string[] an array of all selected option labels in the specified select drop-down\n   */\n    return this.findSelectedOptionProperties(selectLocator, \"text\");\n}\n\nSelenium.prototype.getSelectedLabel = function(selectLocator) {\n    /** Gets option label (visible text) for selected option in the specified select element.\n   *\n   * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n   * @return string the selected option label in the specified select drop-down\n   */\n    return this.findSelectedOptionProperty(selectLocator, \"text\");\n}\n\nSelenium.prototype.getSelectedValues = function(selectLocator) {\n    /** Gets all option values (value attributes) for selected options in the specified select or multi-select element.\n   *\n   * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n   * @return string[] an array of all selected option values in the specified select drop-down\n   */\n    return this.findSelectedOptionProperties(selectLocator, \"value\");\n}\n\nSelenium.prototype.getSelectedValue = function(selectLocator) {\n    /** Gets option value (value attribute) for selected option in the specified select element.\n   *\n   * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n   * @return string the selected option value in the specified select drop-down\n   */\n    return this.findSelectedOptionProperty(selectLocator, \"value\");\n}\n\nSelenium.prototype.getSelectedIndexes = function(selectLocator) {\n    /** Gets all option indexes (option number, starting at 0) for selected options in the specified select or multi-select element.\n   *\n   * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n   * @return string[] an array of all selected option indexes in the specified select drop-down\n   */\n    return this.findSelectedOptionProperties(selectLocator, \"index\");\n}\n\nSelenium.prototype.getSelectedIndex = function(selectLocator) {\n    /** Gets option index (option number, starting at 0) for selected option in the specified select element.\n   *\n   * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n   * @return string the selected option index in the specified select drop-down\n   */\n    return this.findSelectedOptionProperty(selectLocator, \"index\");\n}\n\nSelenium.prototype.getSelectedIds = function(selectLocator) {\n    /** Gets all option element IDs for selected options in the specified select or multi-select element.\n   *\n   * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n   * @return string[] an array of all selected option IDs in the specified select drop-down\n   */\n    return this.findSelectedOptionProperties(selectLocator, \"id\");\n}\n\nSelenium.prototype.getSelectedId = function(selectLocator) {\n    /** Gets option element ID for selected option in the specified select element.\n   *\n   * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n   * @return string the selected option ID in the specified select drop-down\n   */\n    return this.findSelectedOptionProperty(selectLocator, \"id\");\n}\n\nSelenium.prototype.isSomethingSelected = function(selectLocator) {\n    /** Determines whether some option in a drop-down menu is selected.\n   *\n   * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n   * @return boolean true if some option has been selected, false otherwise\n   */\n    var element = this.browserbot.findElement(selectLocator);\n    if (!(\"options\" in element)) {\n        throw new SeleniumError(\"Specified element is not a Select (has no options)\");\n    }\n\n    var selectedOptions = [];\n\n    for (var i = 0; i < element.options.length; i++) {\n        if (element.options[i].selected)\n        {\n            return true;\n        }\n    }\n    return false;\n}\n\nSelenium.prototype.findSelectedOptionProperties = function(locator, property) {\n   var element = this.browserbot.findElement(locator);\n   if (!(\"options\" in element)) {\n        throw new SeleniumError(\"Specified element is not a Select (has no options)\");\n    }\n\n    var selectedOptions = [];\n\n    for (var i = 0; i < element.options.length; i++) {\n        if (element.options[i].selected)\n        {\n            var propVal = element.options[i][property];\n            selectedOptions.push(propVal);\n        }\n    }\n    if (selectedOptions.length == 0) Assert.fail(\"No option selected\");\n    return selectedOptions;\n}\n\nSelenium.prototype.findSelectedOptionProperty = function(locator, property) {\n    var selectedOptions = this.findSelectedOptionProperties(locator, property);\n    if (selectedOptions.length > 1) {\n        Assert.fail(\"More than one selected option!\");\n    }\n    return selectedOptions[0];\n}\n\nSelenium.prototype.getSelectOptions = function(selectLocator) {\n    /** Gets all option labels in the specified select drop-down.\n   *\n   * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n   * @return string[] an array of all option labels in the specified select drop-down\n   */\n    var element = this.browserbot.findElement(selectLocator);\n\n    var selectOptions = [];\n\n    for (var i = 0; i < element.options.length; i++) {\n        var option = element.options[i].text;\n        selectOptions.push(option);\n    }\n\n    return selectOptions;\n};\n\n\nSelenium.prototype.getAttribute = function(attributeLocator) {\n    /**\n   * Gets the value of an element attribute. The value of the attribute may\n   * differ across browsers (this is the case for the \"style\" attribute, for\n   * example).\n   *\n   * @param attributeLocator an element locator followed by an &#064; sign and then the name of the attribute, e.g. \"foo&#064;bar\"\n   * @return string the value of the specified attribute\n   */\n   var result = this.browserbot.findAttribute(attributeLocator);\n   if (result == null) {\n           throw new SeleniumError(\"Could not find element attribute: \" + attributeLocator);\n    }\n    return result;\n};\n\nSelenium.prototype.isTextPresent = function(pattern) {\n    /**\n   * Verifies that the specified text pattern appears somewhere on the rendered page shown to the user.\n   * @param pattern a <a href=\"#patterns\">pattern</a> to match with the text of the page\n   * @return boolean true if the pattern matches the text, false otherwise\n   */\n    var allText = this.browserbot.bodyText();\n\n    var patternMatcher = new PatternMatcher(pattern);\n    if (patternMatcher.strategy == PatternMatcher.strategies.glob) {\n            if (pattern.indexOf(\"glob:\")==0) {\n                    pattern = pattern.substring(\"glob:\".length); // strip off \"glob:\"\n                }\n        patternMatcher.matcher = new PatternMatcher.strategies.globContains(pattern);\n    }\n    else if (patternMatcher.strategy == PatternMatcher.strategies.exact) {\n                pattern = pattern.substring(\"exact:\".length); // strip off \"exact:\"\n        return allText.indexOf(pattern) != -1;\n    }\n    return patternMatcher.matches(allText);\n};\n\nSelenium.prototype.isElementPresent = function(locator) {\n    /**\n    * Verifies that the specified element is somewhere on the page.\n    * @param locator an <a href=\"#locators\">element locator</a>\n    * @return boolean true if the element is present, false otherwise\n    */\n    var element = this.browserbot.findElementOrNull(locator);\n    if (element == null) {\n        return false;\n    }\n    return true;\n};\n\nSelenium.prototype.isVisible = function(locator) {\n    /**\n   * Determines if the specified element is visible. An\n   * element can be rendered invisible by setting the CSS \"visibility\"\n   * property to \"hidden\", or the \"display\" property to \"none\", either for the\n   * element itself or one if its ancestors.  This method will fail if\n   * the element is not present.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @return boolean true if the specified element is visible, false otherwise\n   */\n    var element;\n    element = this.browserbot.findElement(locator);\n    // DGF if it's an input tag of type \"hidden\" then it's not visible\n    if (element.tagName) {\n        var tagName = new String(element.tagName).toLowerCase();\n        if (tagName == \"input\") {\n            if (element.type) {\n                var elementType = new String(element.type).toLowerCase();\n                if (elementType == \"hidden\") {\n                    return false;\n                }\n            }\n        }\n    }\n    var visibility = this.findEffectiveStyleProperty(element, \"visibility\");\n    var _isDisplayed = this._isDisplayed(element);\n    return (visibility != \"hidden\" && _isDisplayed);\n};\n\nSelenium.prototype.findEffectiveStyleProperty = function(element, property) {\n    var effectiveStyle = this.findEffectiveStyle(element);\n    var propertyValue = effectiveStyle[property];\n    if (propertyValue == 'inherit' && element.parentNode.style) {\n        return this.findEffectiveStyleProperty(element.parentNode, property);\n    }\n    return propertyValue;\n};\n\nSelenium.prototype._isDisplayed = function(element) {\n    var display = this.findEffectiveStyleProperty(element, \"display\");\n    if (display == \"none\") return false;\n    if (element.parentNode.style) {\n        return this._isDisplayed(element.parentNode);\n    }\n    return true;\n};\n\nSelenium.prototype.findEffectiveStyle = function(element) {\n    if (element.style == undefined) {\n        return undefined; // not a styled element\n    }\n    var window = this.browserbot.getCurrentWindow();\n    if (window.getComputedStyle) {\n        // DOM-Level-2-CSS\n        return window.getComputedStyle(element, null);\n    }\n    if (element.currentStyle) {\n        // non-standard IE alternative\n        return element.currentStyle;\n        // TODO: this won't really work in a general sense, as\n        //   currentStyle is not identical to getComputedStyle()\n        //   ... but it's good enough for \"visibility\"\n    }\n\n    if (window.document.defaultView && window.document.defaultView.getComputedStyle) {\n        return window.document.defaultView.getComputedStyle(element, null);\n    }\n\n\n    throw new SeleniumError(\"cannot determine effective stylesheet in this browser\");\n};\n\nSelenium.prototype.isEditable = function(locator) {\n    /**\n   * Determines whether the specified input element is editable, ie hasn't been disabled.\n   * This method will fail if the specified element isn't an input element.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a>\n   * @return boolean true if the input element is editable, false otherwise\n   */\n    var element = this.browserbot.findElement(locator);\n    if (element.value == undefined) {\n        Assert.fail(\"Element \" + locator + \" is not an input.\");\n    }\n    if (element.disabled) {\n        return false;\n    }\n    // DGF \"readonly\" is a bit goofy... it doesn't necessarily have a value\n    // You can write <input readonly value=\"black\">\n    var readOnlyNode = element.getAttributeNode('readonly');\n    if (readOnlyNode) {\n        // DGF on IE, every input element has a readOnly node, but it may be false\n        if (typeof(readOnlyNode.nodeValue) == \"boolean\") {\n            var readOnly = readOnlyNode.nodeValue;\n            if (readOnly) {\n                return false;\n            }\n        } else {\n            return false;\n        }\n    }\n    return true;\n};\n\nSelenium.prototype.getAllButtons = function() {\n    /** Returns the IDs of all buttons on the page.\n   *\n   * <p>If a given button has no ID, it will appear as \"\" in this array.</p>\n   *\n   * @return string[] the IDs of all buttons on the page\n   */\n   return this.browserbot.getAllButtons();\n};\n\nSelenium.prototype.getAllLinks = function() {\n    /** Returns the IDs of all links on the page.\n   *\n   * <p>If a given link has no ID, it will appear as \"\" in this array.</p>\n   *\n   * @return string[] the IDs of all links on the page\n   */\n   return this.browserbot.getAllLinks();\n};\n\nSelenium.prototype.getAllFields = function() {\n    /** Returns the IDs of all input fields on the page.\n   *\n   * <p>If a given field has no ID, it will appear as \"\" in this array.</p>\n   *\n   * @return string[] the IDs of all field on the page\n   */\n   return this.browserbot.getAllFields();\n};\n\nSelenium.prototype.getAttributeFromAllWindows = function(attributeName) {\n    /** Returns every instance of some attribute from all known windows.\n    *\n    * @param attributeName name of an attribute on the windows\n    * @return string[] the set of values of this attribute from all known windows.\n    */\n    var attributes = new Array();\n    \n    var win = selenium.browserbot.topWindow;\n    \n    // DGF normally you should use []s instead of eval \"win.\"+attributeName\n    // but in this case, attributeName may contain dots (e.g. document.title)\n    // in that case, we have no choice but to use eval...\n    attributes.push(eval(\"win.\"+attributeName));\n    for (var windowName in this.browserbot.openedWindows)\n    {\n        try {\n            win = selenium.browserbot.openedWindows[windowName];\n            attributes.push(eval(\"win.\"+attributeName));\n        } catch (e) {} // DGF If we miss one... meh. It's probably closed or inaccessible anyway.\n    }\n    return attributes;\n};\n\nSelenium.prototype.findWindow = function(soughtAfterWindowPropertyValue) {\n   var targetPropertyName = \"name\";\n   if (soughtAfterWindowPropertyValue.match(\"^title=\")) {\n       targetPropertyName = \"document.title\";\n        soughtAfterWindowPropertyValue = soughtAfterWindowPropertyValue.replace(/^title=/, \"\");\n   }\n   else {\n       // matching \"name\":\n       // If we are not in proxy injection mode, then the top-level test window will be named selenium_myiframe.\n        // But as far as the interface goes, we are expected to match a blank string to this window, if\n        // we are searching with respect to the widow name.\n        // So make a special case so that this logic will work:\n        if (PatternMatcher.matches(soughtAfterWindowPropertyValue, \"\")) {\n           return this.browserbot.getCurrentWindow();\n        }\n   }\n\n   // DGF normally you should use []s instead of eval \"win.\"+attributeName\n   // but in this case, attributeName may contain dots (e.g. document.title)\n   // in that case, we have no choice but to use eval...\n   if (PatternMatcher.matches(soughtAfterWindowPropertyValue, eval(\"this.browserbot.topWindow.\" + targetPropertyName))) {\n       return this.browserbot.topWindow;\n   }\n   for (windowName in selenium.browserbot.openedWindows) {\n       var openedWindow = selenium.browserbot.openedWindows[windowName];\n       if (PatternMatcher.matches(soughtAfterWindowPropertyValue, eval(\"openedWindow.\" + targetPropertyName))) {\n            return openedWindow;\n        }\n   }\n   throw new SeleniumError(\"could not find window with property \" + targetPropertyName + \" matching \" + soughtAfterWindowPropertyValue);\n};\n\nSelenium.prototype.doDragdrop = function(locator, movementsString) {\n/** deprecated - use dragAndDrop instead\n   *\n   * @param locator an element locator\n   * @param movementsString offset in pixels from the current location to which the element should be moved, e.g., \"+70,-300\"\n   */\n   this.doDragAndDrop(locator, movementsString);\n};\n\nSelenium.prototype.doSetMouseSpeed = function(pixels) {\n    /** Configure the number of pixels between \"mousemove\" events during dragAndDrop commands (default=10).\n    * <p>Setting this value to 0 means that we'll send a \"mousemove\" event to every single pixel\n    * in between the start location and the end location; that can be very slow, and may\n    * cause some browsers to force the JavaScript to timeout.</p>\n    * \n    * <p>If the mouse speed is greater than the distance between the two dragged objects, we'll\n    * just send one \"mousemove\" at the start location and then one final one at the end location.</p>\n    * @param pixels the number of pixels between \"mousemove\" events\n    */\n    this.mouseSpeed = pixels;\n}\n \nSelenium.prototype.getMouseSpeed = function() {\n    /** Returns the number of pixels between \"mousemove\" events during dragAndDrop commands (default=10).\n    * \n    * @return number the number of pixels between \"mousemove\" events during dragAndDrop commands (default=10)\n    */\n    this.mouseSpeed = pixels;\n}\n\n\nSelenium.prototype.doDragAndDrop = function(locator, movementsString) {\n    /** Drags an element a certain distance and then drops it\n    * @param locator an element locator\n    * @param movementsString offset in pixels from the current location to which the element should be moved, e.g., \"+70,-300\"\n    */\n    var element = this.browserbot.findElement(locator);\n    var clientStartXY = getClientXY(element)\n    var clientStartX = clientStartXY[0];\n    var clientStartY = clientStartXY[1];\n    \n    var movements = movementsString.split(/,/);\n    var movementX = Number(movements[0]);\n    var movementY = Number(movements[1]);\n    \n    var clientFinishX = ((clientStartX + movementX) < 0) ? 0 : (clientStartX + movementX);\n    var clientFinishY = ((clientStartY + movementY) < 0) ? 0 : (clientStartY + movementY);\n    \n    var mouseSpeed = this.mouseSpeed;\n    var move = function(current, dest) {\n        if (current == dest) return current;\n        if (Math.abs(current - dest) < mouseSpeed) return dest;\n        return (current < dest) ? current + mouseSpeed : current - mouseSpeed;\n    }\n    \n    this.browserbot.triggerMouseEvent(element, 'mousedown', true, clientStartX, clientStartY);\n    this.browserbot.triggerMouseEvent(element, 'mousemove',   true, clientStartX, clientStartY);\n    var clientX = clientStartX;\n    var clientY = clientStartY;\n    \n    while ((clientX != clientFinishX) || (clientY != clientFinishY)) {\n        clientX = move(clientX, clientFinishX);\n        clientY = move(clientY, clientFinishY);\n        this.browserbot.triggerMouseEvent(element, 'mousemove', true, clientX, clientY);\n    }\n    \n    this.browserbot.triggerMouseEvent(element, 'mousemove',   true, clientFinishX, clientFinishY);\n    this.browserbot.triggerMouseEvent(element, 'mouseup',   true, clientFinishX, clientFinishY);\n};\n\nSelenium.prototype.doDragAndDropToObject = function(locatorOfObjectToBeDragged, locatorOfDragDestinationObject) {\n/** Drags an element and drops it on another element\n   *\n   * @param locatorOfObjectToBeDragged an element to be dragged\n   * @param locatorOfDragDestinationObject an element whose location (i.e., whose center-most pixel) will be the point where locatorOfObjectToBeDragged  is dropped\n   */\n   var startX = this.getElementPositionLeft(locatorOfObjectToBeDragged);\n   var startY = this.getElementPositionTop(locatorOfObjectToBeDragged);\n   \n   var destinationLeftX = this.getElementPositionLeft(locatorOfDragDestinationObject);\n   var destinationTopY = this.getElementPositionTop(locatorOfDragDestinationObject);\n   var destinationWidth = this.getElementWidth(locatorOfDragDestinationObject);\n   var destinationHeight = this.getElementHeight(locatorOfDragDestinationObject);\n\n   var endX = Math.round(destinationLeftX + (destinationWidth / 2));\n   var endY = Math.round(destinationTopY + (destinationHeight / 2));\n   \n   var deltaX = endX - startX;\n   var deltaY = endY - startY;\n   \n   var movementsString = \"\" + deltaX + \",\" + deltaY;\n   \n   this.doDragAndDrop(locatorOfObjectToBeDragged, movementsString);\n};\n\nSelenium.prototype.doWindowFocus = function() {\n/** Gives focus to the currently selected window\n   *\n   */\n   this.browserbot.getCurrentWindow().focus();\n};\n\n\nSelenium.prototype.doWindowMaximize = function() {\n/** Resize currently selected window to take up the entire screen\n   *\n   */\n   var window = this.browserbot.getCurrentWindow();\n   if (window!=null && window.screen) {\n       window.moveTo(0,0);\n       window.resizeTo(screen.availWidth, screen.availHeight);\n   }\n};\n\nSelenium.prototype.getAllWindowIds = function() {\n  /** Returns the IDs of all windows that the browser knows about.\n   *\n   * @return string[] the IDs of all windows that the browser knows about.\n   */\n   return this.getAttributeFromAllWindows(\"id\");\n};\n\nSelenium.prototype.getAllWindowNames = function() {\n  /** Returns the names of all windows that the browser knows about.\n   *\n   * @return string[] the names of all windows that the browser knows about.\n   */\n   return this.getAttributeFromAllWindows(\"name\");\n};\n\nSelenium.prototype.getAllWindowTitles = function() {\n  /** Returns the titles of all windows that the browser knows about.\n   *\n   * @return string[] the titles of all windows that the browser knows about.\n   */\n   return this.getAttributeFromAllWindows(\"document.title\");\n};\n\nSelenium.prototype.getHtmlSource = function() {\n    /** Returns the entire HTML source between the opening and\n   * closing \"html\" tags.\n   *\n   * @return string the entire HTML source\n   */\n    return this.browserbot.getDocument().getElementsByTagName(\"html\")[0].innerHTML;\n};\n\nSelenium.prototype.doSetCursorPosition = function(locator, position) {\n    /**\n   * Moves the text cursor to the specified position in the given input element or textarea.\n   * This method will fail if the specified element isn't an input element or textarea.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a> pointing to an input element or textarea\n   * @param position the numerical position of the cursor in the field; position should be 0 to move the position to the beginning of the field.  You can also set the cursor to -1 to move it to the end of the field.\n   */\n   var element = this.browserbot.findElement(locator);\n    if (element.value == undefined) {\n        Assert.fail(\"Element \" + locator + \" is not an input.\");\n    }\n    if (position == -1) {\n        position = element.value.length;\n    }\n\n   if( element.setSelectionRange && !browserVersion.isOpera) {\n       element.focus();\n        element.setSelectionRange(/*start*/position,/*end*/position);\n   }\n   else if( element.createTextRange ) {\n      triggerEvent(element, 'focus', false);\n      var range = element.createTextRange();\n      range.collapse(true);\n      range.moveEnd('character',position);\n      range.moveStart('character',position);\n      range.select();\n   }\n}\n\nSelenium.prototype.getElementIndex = function(locator) {\n    /**\n     * Get the relative index of an element to its parent (starting from 0). The comment node and empty text node\n     * will be ignored.\n     *\n     * @param locator an <a href=\"#locators\">element locator</a> pointing to an element\n     * @return number of relative index of the element to its parent (starting from 0)\n     */\n    var element = this.browserbot.findElement(locator);\n    var previousSibling;\n    var index = 0;\n    while ((previousSibling = element.previousSibling) != null) {\n        if (!this._isCommentOrEmptyTextNode(previousSibling)) {\n            index++;\n        }\n        element = previousSibling;\n    }\n    return index;\n}\n\nSelenium.prototype.isOrdered = function(locator1, locator2) {\n    /**\n     * Check if these two elements have same parent and are ordered siblings in the DOM. Two same elements will\n     * not be considered ordered.\n     *\n     * @param locator1 an <a href=\"#locators\">element locator</a> pointing to the first element\n     * @param locator2 an <a href=\"#locators\">element locator</a> pointing to the second element\n     * @return boolean true if element1 is the previous sibling of element2, false otherwise\n     */\n    var element1 = this.browserbot.findElement(locator1);\n    var element2 = this.browserbot.findElement(locator2);\n    if (element1 === element2) return false;\n\n    var previousSibling;\n    while ((previousSibling = element2.previousSibling) != null) {\n        if (previousSibling === element1) {\n            return true;\n        }\n        element2 = previousSibling;\n    }\n    return false;\n}\n\nSelenium.prototype._isCommentOrEmptyTextNode = function(node) {\n    return node.nodeType == 8 || ((node.nodeType == 3) && !(/[^\\t\\n\\r ]/.test(node.data)));\n}\n\nSelenium.prototype.getElementPositionLeft = function(locator) {\n   /**\n   * Retrieves the horizontal position of an element\n   *\n   * @param locator an <a href=\"#locators\">element locator</a> pointing to an element OR an element itself\n   * @return number of pixels from the edge of the frame.\n   */\n       var element;\n        if (\"string\"==typeof locator) {\n            element = this.browserbot.findElement(locator);\n        }\n        else {\n            element = locator;\n        }\n    var x = element.offsetLeft;\n    var elementParent = element.offsetParent;\n\n    while (elementParent != null)\n    {\n        if(document.all)\n        {\n            if( (elementParent.tagName != \"TABLE\") && (elementParent.tagName != \"BODY\") )\n            {\n                x += elementParent.clientLeft;\n            }\n        }\n        else // Netscape/DOM\n        {\n            if(elementParent.tagName == \"TABLE\")\n            {\n                var parentBorder = parseInt(elementParent.border);\n                if(isNaN(parentBorder))\n                {\n                    var parentFrame = elementParent.getAttribute('frame');\n                    if(parentFrame != null)\n                    {\n                        x += 1;\n                    }\n                }\n                else if(parentBorder > 0)\n                {\n                    x += parentBorder;\n                }\n            }\n        }\n        x += elementParent.offsetLeft;\n        elementParent = elementParent.offsetParent;\n    }\n    return x;\n};\n\nSelenium.prototype.getElementPositionTop = function(locator) {\n   /**\n   * Retrieves the vertical position of an element\n   *\n   * @param locator an <a href=\"#locators\">element locator</a> pointing to an element OR an element itself\n   * @return number of pixels from the edge of the frame.\n   */\n       var element;\n        if (\"string\"==typeof locator) {\n            element = this.browserbot.findElement(locator);\n        }\n        else {\n            element = locator;\n        }\n\n       var y = 0;\n\n       while (element != null)\n    {\n        if(document.all)\n        {\n            if( (element.tagName != \"TABLE\") && (element.tagName != \"BODY\") )\n            {\n            y += element.clientTop;\n            }\n        }\n        else // Netscape/DOM\n        {\n            if(element.tagName == \"TABLE\")\n            {\n            var parentBorder = parseInt(element.border);\n            if(isNaN(parentBorder))\n            {\n                var parentFrame = element.getAttribute('frame');\n                if(parentFrame != null)\n                {\n                    y += 1;\n                }\n            }\n            else if(parentBorder > 0)\n            {\n                y += parentBorder;\n            }\n            }\n        }\n        y += element.offsetTop;\n\n            // Netscape can get confused in some cases, such that the height of the parent is smaller\n            // than that of the element (which it shouldn't really be). If this is the case, we need to\n            // exclude this element, since it will result in too large a 'top' return value.\n            if (element.offsetParent && element.offsetParent.offsetHeight && element.offsetParent.offsetHeight < element.offsetHeight)\n            {\n                // skip the parent that's too small\n                element = element.offsetParent.offsetParent;\n            }\n            else\n            {\n            // Next up...\n            element = element.offsetParent;\n        }\n       }\n    return y;\n};\n\nSelenium.prototype.getElementWidth = function(locator) {\n   /**\n   * Retrieves the width of an element\n   *\n   * @param locator an <a href=\"#locators\">element locator</a> pointing to an element\n   * @return number width of an element in pixels\n   */\n   var element = this.browserbot.findElement(locator);\n   return element.offsetWidth;\n};\n\nSelenium.prototype.getElementHeight = function(locator) {\n   /**\n   * Retrieves the height of an element\n   *\n   * @param locator an <a href=\"#locators\">element locator</a> pointing to an element\n   * @return number height of an element in pixels\n   */\n   var element = this.browserbot.findElement(locator);\n   return element.offsetHeight;\n};\n\nSelenium.prototype.getCursorPosition = function(locator) {\n    /**\n   * Retrieves the text cursor position in the given input element or textarea; beware, this may not work perfectly on all browsers.\n   *\n   * <p>Specifically, if the cursor/selection has been cleared by JavaScript, this command will tend to\n   * return the position of the last location of the cursor, even though the cursor is now gone from the page.  This is filed as <a href=\"http://jira.openqa.org/browse/SEL-243\">SEL-243</a>.</p>\n   * This method will fail if the specified element isn't an input element or textarea, or there is no cursor in the element.\n   *\n   * @param locator an <a href=\"#locators\">element locator</a> pointing to an input element or textarea\n   * @return number the numerical position of the cursor in the field\n   */\n    var element = this.browserbot.findElement(locator);\n    var doc = this.browserbot.getDocument();\n    var win = this.browserbot.getCurrentWindow();\n    if( doc.selection && !browserVersion.isOpera){\n        try {\n            var selectRange = doc.selection.createRange().duplicate();\n            var elementRange = element.createTextRange();\n            selectRange.move(\"character\",0);\n            elementRange.move(\"character\",0);\n            var inRange1 = selectRange.inRange(elementRange);\n            var inRange2 = elementRange.inRange(selectRange);\n            elementRange.setEndPoint(\"EndToEnd\", selectRange);\n        } catch (e) {\n            Assert.fail(\"There is no cursor on this page!\");\n        }\n        var answer = String(elementRange.text).replace(/\\r/g,\"\").length;\n        return answer;\n    } else {\n        if (typeof(element.selectionStart) != \"undefined\") {\n            if (win.getSelection && typeof(win.getSelection().rangeCount) != undefined && win.getSelection().rangeCount == 0) {\n                Assert.fail(\"There is no cursor on this page!\");\n            }\n            return element.selectionStart;\n        }\n    }\n    throw new Error(\"Couldn't detect cursor position on this browser!\");\n}\n\n\nSelenium.prototype.getExpression = function(expression) {\n    /**\n     * Returns the specified expression.\n     *\n     * <p>This is useful because of JavaScript preprocessing.\n     * It is used to generate commands like assertExpression and waitForExpression.</p>\n     *\n     * @param expression the value to return\n     * @return string the value passed in\n     */\n    return expression;\n}\n\nSelenium.prototype.getXpathCount = function(xpath) {\n    /**\n    * Returns the number of nodes that match the specified xpath, eg. \"//table\" would give\n    * the number of tables.\n    * \n    * @param xpath the xpath expression to evaluate. do NOT wrap this expression in a 'count()' function; we will do that for you.\n    * @return number the number of nodes that match the specified xpath\n    */\n    var result = this.browserbot.evaluateXPathCount(xpath, this.browserbot.getDocument());\n    return result;\n}\n\nSelenium.prototype.doAssignId = function(locator, identifier) {\n    /**\n    * Temporarily sets the \"id\" attribute of the specified element, so you can locate it in the future\n    * using its ID rather than a slow/complicated XPath.  This ID will disappear once the page is\n    * reloaded.\n    * @param locator an <a href=\"#locators\">element locator</a> pointing to an element\n    * @param identifier a string to be used as the ID of the specified element\n    */\n    var element = this.browserbot.findElement(locator);\n    element.id = identifier;\n}\n\nSelenium.prototype.doAllowNativeXpath = function(allow) {\n    /**\n    * Specifies whether Selenium should use the native in-browser implementation\n    * of XPath (if any native version is available); if you pass \"false\" to\n    * this function, we will always use our pure-JavaScript xpath library.\n    * Using the pure-JS xpath library can improve the consistency of xpath\n    * element locators between different browser vendors, but the pure-JS\n    * version is much slower than the native implementations.\n    * @param allow boolean, true means we'll prefer to use native XPath; false means we'll only use JS XPath\n    */\n    if (\"false\" == allow || \"0\" == allow) { // The strings \"false\" and \"0\" are true values in JS\n        allow = false;\n    }\n    this.browserbot.allowNativeXpath = allow;\n}\n\nSelenium.prototype.doIgnoreAttributesWithoutValue = function(ignore) {\n    /**\n    * Specifies whether Selenium will ignore xpath attributes that have no\n    * value, i.e. are the empty string, when using the non-native xpath\n    * evaluation engine. You'd want to do this for performance reasons in IE.\n    * However, this could break certain xpaths, for example an xpath that looks\n    * for an attribute whose value is NOT the empty string.\n    *\n    * The hope is that such xpaths are relatively rare, but the user should\n    * have the option of using them. Note that this only influences xpath\n    * evaluation when using the ajaxslt engine (i.e. not \"javascript-xpath\").\n    *\n    * @param ignore boolean, true means we'll ignore attributes without value\n    *                        at the expense of xpath \"correctness\"; false means\n    *                        we'll sacrifice speed for correctness.\n    */\n    if ('false' == ignore || '0' == ignore) {\n        ignore = false;\n    }\n    this.browserbot.ignoreAttributesWithoutValue = ignore;\n}\n\nSelenium.prototype.doWaitForCondition = function(script, timeout) {\n    /**\n   * Runs the specified JavaScript snippet repeatedly until it evaluates to \"true\".\n   * The snippet may have multiple lines, but only the result of the last line\n   * will be considered.\n   *\n   * <p>Note that, by default, the snippet will be run in the runner's test window, not in the window\n   * of your application.  To get the window of your application, you can use\n   * the JavaScript snippet <code>selenium.browserbot.getCurrentWindow()</code>, and then\n   * run your JavaScript in there</p>\n   * @param script the JavaScript snippet to run\n   * @param timeout a timeout in milliseconds, after which this command will return with an error\n   */\n   \n    return Selenium.decorateFunctionWithTimeout(function () {\n        var window = selenium.browserbot.getCurrentWindow();\n        return eval(script);\n    }, timeout);\n};\n\nSelenium.prototype.doWaitForCondition.dontCheckAlertsAndConfirms = true;\n\nSelenium.prototype.doSetTimeout = function(timeout) {\n    /**\n     * Specifies the amount of time that Selenium will wait for actions to complete.\n     *\n     * <p>Actions that require waiting include \"open\" and the \"waitFor*\" actions.</p>\n     * The default timeout is 30 seconds.\n     * @param timeout a timeout in milliseconds, after which the action will return with an error\n     */\n    if (!timeout) {\n        timeout = Selenium.DEFAULT_TIMEOUT;\n    }\n    this.defaultTimeout = timeout;\n}\n\nSelenium.prototype.doWaitForPageToLoad = function(timeout) {\n    /**\n     * Waits for a new page to load.\n     *\n     * <p>You can use this command instead of the \"AndWait\" suffixes, \"clickAndWait\", \"selectAndWait\", \"typeAndWait\" etc.\n     * (which are only available in the JS API).</p>\n     *\n     * <p>Selenium constantly keeps track of new pages loading, and sets a \"newPageLoaded\"\n     * flag when it first notices a page load.  Running any other Selenium command after\n     * turns the flag to false.  Hence, if you want to wait for a page to load, you must\n     * wait immediately after a Selenium command that caused a page-load.</p>\n     * @param timeout a timeout in milliseconds, after which this command will return with an error\n     */\n    // in pi-mode, the test and the harness share the window; thus if we are executing this code, then we have loaded\n    if (window[\"proxyInjectionMode\"] == null || !window[\"proxyInjectionMode\"]) {\n        return this.makePageLoadCondition(timeout);\n    }\n};\n\nSelenium.prototype.doWaitForFrameToLoad = function(frameAddress, timeout) {\n    /**\n     * Waits for a new frame to load.\n     *\n     * <p>Selenium constantly keeps track of new pages and frames loading, \n     * and sets a \"newPageLoaded\" flag when it first notices a page load.</p>\n     * \n     * See waitForPageToLoad for more information.\n     * \n     * @param frameAddress FrameAddress from the server side\n     * @param timeout a timeout in milliseconds, after which this command will return with an error\n     */\n    // in pi-mode, the test and the harness share the window; thus if we are executing this code, then we have loaded\n    if (window[\"proxyInjectionMode\"] == null || !window[\"proxyInjectionMode\"]) {\n        return this.makePageLoadCondition(timeout);\n    }\n};\n\nSelenium.prototype._isNewPageLoaded = function() {\n    return this.browserbot.isNewPageLoaded();\n};\n\nSelenium.prototype.doWaitForPageToLoad.dontCheckAlertsAndConfirms = true;\n\n/**\n * Evaluate a parameter, performing JavaScript evaluation and variable substitution.\n * If the string matches the pattern \"javascript{ ... }\", evaluate the string between the braces.\n */\nSelenium.prototype.preprocessParameter = function(value) {\n    var match = value.match(/^javascript\\{((.|\\r?\\n)+)\\}$/);\n    if (match && match[1]) {\n        return eval(match[1]).toString();\n    }\n    return this.replaceVariables(value);\n};\n\n/*\n * Search through str and replace all variable references ${varName} with their\n * value in storedVars.\n */\nSelenium.prototype.replaceVariables = function(str) {\n    var stringResult = str;\n\n    // Find all of the matching variable references\n    var match = stringResult.match(/\\$\\{\\w+\\}/g);\n    if (!match) {\n        return stringResult;\n    }\n\n    // For each match, lookup the variable value, and replace if found\n    for (var i = 0; match && i < match.length; i++) {\n        var variable = match[i]; // The replacement variable, with ${}\n        var name = variable.substring(2, variable.length - 1); // The replacement variable without ${}\n        var replacement = storedVars[name];\n        if (replacement != undefined) {\n            stringResult = stringResult.replace(variable, replacement);\n        }\n    }\n    return stringResult;\n};\n\nSelenium.prototype.getCookie = function() {\n    /**\n     * Return all cookies of the current page under test.\n     *\n     * @return string all cookies of the current page under test\n     */\n    var doc = this.browserbot.getDocument();\n    return doc.cookie;\n};\n\nSelenium.prototype.getCookieByName = function(name) {\n    /**\n     * Returns the value of the cookie with the specified name, or throws an error if the cookie is not present.\n     * @param name the name of the cookie\n     * @return string the value of the cookie\n     */\n    var v = this.browserbot.getCookieByName(name);\n    if (v === null) {\n        throw new SeleniumError(\"Cookie '\"+name+\"' was not found\");\n    }\n    return v;\n};\n\nSelenium.prototype.isCookiePresent = function(name) {\n    /**\n     * Returns true if a cookie with the specified name is present, or false otherwise.\n     * @param name the name of the cookie\n     * @return boolean true if a cookie with the specified name is present, or false otherwise.\n     */\n    var v = this.browserbot.getCookieByName(name);\n    var absent = (v === null);\n    return !absent;\n}   \n\nSelenium.prototype.doCreateCookie = function(nameValuePair, optionsString) {\n    /**\n     * Create a new cookie whose path and domain are same with those of current page\n     * under test, unless you specified a path for this cookie explicitly.\n     *\n     * @param nameValuePair name and value of the cookie in a format \"name=value\"\n     * @param optionsString options for the cookie. Currently supported options include 'path', 'max_age' and 'domain'.\n     *      the optionsString's format is \"path=/path/, max_age=60, domain=.foo.com\". The order of options are irrelevant, the unit\n     *      of the value of 'max_age' is second.  Note that specifying a domain that isn't a subset of the current domain will\n     *      usually fail.\n     */\n    var results = /[^\\s=\\[\\]\\(\\),\"\\/\\?@:;]+=[^\\s=\\[\\]\\(\\),\"\\/\\?@:;]*/.test(nameValuePair);\n    if (!results) {\n        throw new SeleniumError(\"Invalid parameter.\");\n    }\n    var cookie = nameValuePair.trim();\n    results = /max_age=(\\d+)/.exec(optionsString);\n    if (results) {\n        var expireDateInMilliseconds = (new Date()).getTime() + results[1] * 1000;\n        cookie += \"; expires=\" + new Date(expireDateInMilliseconds).toGMTString();\n    }\n    results = /path=([^\\s,]+)[,]?/.exec(optionsString);\n    if (results) {\n        var path = results[1];\n        if (browserVersion.khtml) {\n            // Safari and conquerer don't like paths with / at the end\n            if (\"/\" != path) {\n                path = path.replace(/\\/$/, \"\");\n            }\n        }\n        cookie += \"; path=\" + path;\n    }\n    results = /domain=([^\\s,]+)[,]?/.exec(optionsString);\n    if (results) {\n        var domain = results[1];\n        cookie += \"; domain=\" + domain;\n    }\n    LOG.debug(\"Setting cookie to: \" + cookie);\n    this.browserbot.getDocument().cookie = cookie;\n}\n\nSelenium.prototype.doDeleteCookie = function(name,optionsString) {\n    /**\n     * Delete a named cookie with specified path and domain.  Be careful; to delete a cookie, you\n     * need to delete it using the exact same path and domain that were used to create the cookie.\n     * If the path is wrong, or the domain is wrong, the cookie simply won't be deleted.  Also\n     * note that specifying a domain that isn't a subset of the current domain will usually fail.\n     *\n     * Since there's no way to discover at runtime the original path and domain of a given cookie,\n     * we've added an option called 'recurse' to try all sub-domains of the current domain with\n     * all paths that are a subset of the current path.  Beware; this option can be slow.  In\n     * big-O notation, it operates in O(n*m) time, where n is the number of dots in the domain\n     * name and m is the number of slashes in the path.\n     *\n     * @param name the name of the cookie to be deleted\n     * @param optionsString options for the cookie. Currently supported options include 'path', 'domain'\n     *      and 'recurse.' The optionsString's format is \"path=/path/, domain=.foo.com, recurse=true\".\n     *      The order of options are irrelevant. Note that specifying a domain that isn't a subset of\n     *      the current domain will usually fail.\n     */\n    // set the expire time of the cookie to be deleted to one minute before now.\n    var path = \"\";\n    var domain = \"\";\n    var recurse = false;\n    var matched = false;\n    results = /path=([^\\s,]+)[,]?/.exec(optionsString);\n    if (results) {\n        matched = true;\n        path = results[1];\n    }\n    results = /domain=([^\\s,]+)[,]?/.exec(optionsString);\n    if (results) {\n        matched = true;\n        domain = results[1];\n    }\n    results = /recurse=([^\\s,]+)[,]?/.exec(optionsString);\n    if (results) {\n        matched = true;\n        recurse = results[1];\n        if (\"false\" == recurse) {\n            recurse = false;\n        }\n    }\n    // Treat the entire optionsString as a path (for backwards compatibility)\n    if (optionsString && !matched) {\n        LOG.warn(\"Using entire optionsString as a path; please change the argument to deleteCookie to use path=\"+optionsString);\n        path = optionsString;\n    }\n    if (browserVersion.khtml) {\n        // Safari and conquerer don't like paths with / at the end\n        if (\"/\" != path) {\n            path = path.replace(/\\/$/, \"\");\n        }\n    }    \n    path = path.trim();\n    domain = domain.trim();\n    var cookieName = name.trim();\n    if (recurse) {\n        this.browserbot.recursivelyDeleteCookie(cookieName, domain, path);\n    } else {\n        this.browserbot.deleteCookie(cookieName, domain, path);\n    }\n}\n\nSelenium.prototype.doDeleteAllVisibleCookies = function() {\n    /** Calls deleteCookie with recurse=true on all cookies visible to the current page.\n    * As noted on the documentation for deleteCookie, recurse=true can be much slower\n    * than simply deleting the cookies using a known domain/path.\n    */\n    var win = this.browserbot.getCurrentWindow();\n    var doc = win.document;\n    var cookieNames = this.browserbot.getAllCookieNames(doc);\n    var domain = doc.domain;\n    var path = win.location.pathname;\n    for (var i = 0; i < cookieNames.length; i++) {\n        this.browserbot.recursivelyDeleteCookie(cookieNames[i], domain, path, win);\n    }\n}\n\nSelenium.prototype.doSetBrowserLogLevel = function(logLevel) {\n    /**\n    * Sets the threshold for browser-side logging messages; log messages beneath this threshold will be discarded.\n    * Valid logLevel strings are: \"debug\", \"info\", \"warn\", \"error\" or \"off\".\n    * To see the browser logs, you need to\n    * either show the log window in GUI mode, or enable browser-side logging in Selenium RC.\n    *\n    * @param logLevel one of the following: \"debug\", \"info\", \"warn\", \"error\" or \"off\"\n    */\n    if (logLevel == null || logLevel == \"\") {\n        throw new SeleniumError(\"You must specify a log level\");\n    }\n    logLevel = logLevel.toLowerCase();\n    if (LOG.logLevels[logLevel] == null) {\n        throw new SeleniumError(\"Invalid log level: \" + logLevel);\n    }\n    LOG.setLogLevelThreshold(logLevel);\n}\n\nSelenium.prototype.doRunScript = function(script) {\n    /**\n    * Creates a new \"script\" tag in the body of the current test window, and \n    * adds the specified text into the body of the command.  Scripts run in\n    * this way can often be debugged more easily than scripts executed using\n    * Selenium's \"getEval\" command.  Beware that JS exceptions thrown in these script\n    * tags aren't managed by Selenium, so you should probably wrap your script\n    * in try/catch blocks if there is any chance that the script will throw\n    * an exception.\n    * @param script the JavaScript snippet to run\n    */\n    var win = this.browserbot.getCurrentWindow();\n    var doc = win.document;\n    var scriptTag = doc.createElement(\"script\");\n    scriptTag.type = \"text/javascript\"\n    scriptTag.text = script;\n    doc.body.appendChild(scriptTag);\n}\n\nSelenium.prototype.doAddLocationStrategy = function(strategyName, functionDefinition) {\n    /**\n    * Defines a new function for Selenium to locate elements on the page.\n    * For example,\n    * if you define the strategy \"foo\", and someone runs click(\"foo=blah\"), we'll\n    * run your function, passing you the string \"blah\", and click on the element \n    * that your function\n    * returns, or throw an \"Element not found\" error if your function returns null.\n    *\n    * We'll pass three arguments to your function:\n    * <ul>\n    * <li>locator: the string the user passed in</li>\n    * <li>inWindow: the currently selected window</li>\n    * <li>inDocument: the currently selected document</li>\n    * </ul>\n    * The function must return null if the element can't be found.\n    * \n    * @param strategyName the name of the strategy to define; this should use only\n    *   letters [a-zA-Z] with no spaces or other punctuation.\n    * @param functionDefinition a string defining the body of a function in JavaScript.\n    *   For example: <code>return inDocument.getElementById(locator);</code>\n    */\n    if (!/^[a-zA-Z]+$/.test(strategyName)) {\n        throw new SeleniumError(\"Invalid strategy name: \" + strategyName);\n    }\n    var strategyFunction;\n    try {\n        strategyFunction = new Function(\"locator\", \"inDocument\", \"inWindow\", functionDefinition);\n    } catch (ex) {\n        throw new SeleniumError(\"Error evaluating function definition: \" + extractExceptionMessage(ex));\n    }\n    var safeStrategyFunction = function() {\n        try {\n            return strategyFunction.apply(this, arguments);\n        } catch (ex) {\n            throw new SeleniumError(\"Error executing strategy function \" + strategyName + \": \" + extractExceptionMessage(ex));\n        }\n    }\n    this.browserbot.locationStrategies[strategyName] = safeStrategyFunction;\n}\n\nSelenium.prototype.doCaptureEntirePageScreenshot = function(filename, kwargs) {\n    /**\n     * Saves the entire contents of the current window canvas to a PNG file.\n     * Contrast this with the captureScreenshot command, which captures the\n     * contents of the OS viewport (i.e. whatever is currently being displayed\n     * on the monitor), and is implemented in the RC only. Currently this only\n     * works in Firefox when running in chrome mode, and in IE non-HTA using\n     * the EXPERIMENTAL \"Snapsie\" utility. The Firefox implementation is mostly\n     * borrowed from the Screengrab! Firefox extension. Please see\n     * http://www.screengrab.org and http://snapsie.sourceforge.net/ for\n     * details.\n     *\n     * @param filename  the path to the file to persist the screenshot as. No\n     *                  filename extension will be appended by default.\n     *                  Directories will not be created if they do not exist,  \n     *                  and an exception will be thrown, possibly by native\n     *                  code.\n     * @param kwargs    a kwargs string that modifies the way the screenshot\n     *                  is captured. Example: \"background=#CCFFDD\" .\n     *                  Currently valid options:\n     *                  <dl>\n     *                   <dt>background</dt>\n     *                     <dd>the background CSS for the HTML document. This\n     *                     may be useful to set for capturing screenshots of\n     *                     less-than-ideal layouts, for example where absolute\n     *                     positioning causes the calculation of the canvas\n     *                     dimension to fail and a black background is exposed\n     *                     (possibly obscuring black text).</dd>\n     *                  </dl>\n     */\n    if (! browserVersion.isChrome &&\n        ! (browserVersion.isIE && ! browserVersion.isHTA)) {\n        throw new SeleniumError('captureEntirePageScreenshot is only '\n            + 'implemented for Firefox (\"firefox\" or \"chrome\", NOT '\n            + '\"firefoxproxy\") and IE non-HTA (\"iexploreproxy\", NOT \"iexplore\" '\n            + 'or \"iehta\"). The current browser isn\\'t one of them!');\n    }\n    \n    // do or do not ... there is no try\n    \n    if (browserVersion.isIE) {\n        // targeting snapsIE >= 0.2\n        function getFailureMessage(exceptionMessage) {\n            var msg = 'Snapsie failed: ';\n            if (exceptionMessage) {\n                if (exceptionMessage ==\n                    \"Automation server can't create object\") {\n                    msg += 'Is it installed? Does it have permission to run '\n                        'as an add-on? See http://snapsie.sourceforge.net/';\n                }\n                else {\n                    msg += exceptionMessage;\n                }\n            }\n            else {\n                msg += 'Undocumented error';\n            }\n            return msg;\n        }\n    \n        if (typeof(runOptions) != 'undefined' &&\n            runOptions.isMultiWindowMode() == false) {\n            // framed mode\n            try {\n                new Snapsie().saveSnapshot(filename, 'selenium_myiframe');\n            }\n            catch (e) {\n                throw new SeleniumError(getFailureMessage(e.message));\n            }\n        }\n        else {\n            // multi-window mode\n            if (!this.snapsieSrc) {\n                // XXX - cache snapsie, and capture the screenshot as a\n                // callback. Definitely a hack, because we may be late taking\n                // the first screenshot, but saves us from polluting other code\n                // for now. I wish there were an easier way to get at the\n                // contents of a referenced script!\n                var snapsieUrl = (this.browserbot.buttonWindow.location.href)\n                    .replace(/(Test|Remote)Runner\\.html/, 'lib/snapsie.js');\n                var self = this;\n                new Ajax.Request(snapsieUrl, {\n                    method: 'get'\n                    , onSuccess: function(transport) {\n                        self.snapsieSrc = transport.responseText;\n                        self.doCaptureEntirePageScreenshot(filename, kwargs);\n                    }\n                });\n                return;\n            }\n\n            // it's going into a string, so escape the backslashes\n            filename = filename.replace(/\\\\/g, '\\\\\\\\');\n            \n            // this is sort of hackish. We insert a script into the document,\n            // and remove it before anyone notices.\n            var doc = selenium.browserbot.getDocument();\n            var script = doc.createElement('script'); \n            var scriptContent = this.snapsieSrc \n                + 'try {'\n                + '    new Snapsie().saveSnapshot(\"' + filename + '\");'\n                + '}'\n                + 'catch (e) {'\n                + '    document.getElementById(\"takeScreenshot\").failure ='\n                + '        e.message;'\n                + '}';\n            script.id = 'takeScreenshot';\n            script.language = 'javascript';\n            script.text = scriptContent;\n            doc.body.appendChild(script);\n            script.parentNode.removeChild(script);\n            if (script.failure) {\n                throw new SeleniumError(getFailureMessage(script.failure));\n            }\n        }\n        return;\n    }\n    \n    var grabber = {\n        prepareCanvas: function(width, height) {\n            var styleWidth = width + 'px';\n            var styleHeight = height + 'px';\n            \n            var grabCanvas = document.getElementById('screenshot_canvas');\n            if (!grabCanvas) {\n                // create the canvas\n                var ns = 'http://www.w3.org/1999/xhtml';\n                grabCanvas = document.createElementNS(ns, 'html:canvas');\n                grabCanvas.id = 'screenshot_canvas';\n                grabCanvas.style.display = 'none';\n                document.documentElement.appendChild(grabCanvas);\n            }\n            \n            grabCanvas.width = width;\n            grabCanvas.style.width = styleWidth;\n            grabCanvas.style.maxWidth = styleWidth;\n            grabCanvas.height = height;\n            grabCanvas.style.height = styleHeight;\n            grabCanvas.style.maxHeight = styleHeight;\n        \n            return grabCanvas;\n        },\n        \n        prepareContext: function(canvas, box) {\n            var context = canvas.getContext('2d');\n            context.clearRect(box.x, box.y, box.width, box.height);\n            context.save();\n            return context;\n        }\n    };\n    \n    var SGNsUtils = {\n        dataUrlToBinaryInputStream: function(dataUrl) {\n            var nsIoService = Components.classes[\"@mozilla.org/network/io-service;1\"]\n                .getService(Components.interfaces.nsIIOService);\n            var channel = nsIoService\n                .newChannelFromURI(nsIoService.newURI(dataUrl, null, null));\n            var binaryInputStream = Components.classes[\"@mozilla.org/binaryinputstream;1\"]\n                .createInstance(Components.interfaces.nsIBinaryInputStream);\n            \n            binaryInputStream.setInputStream(channel.open());\n            return binaryInputStream;\n        },\n        \n        newFileOutputStream: function(nsFile) {\n            var writeFlag = 0x02; // write only\n            var createFlag = 0x08; // create\n            var truncateFlag = 0x20; // truncate\n            var fileOutputStream = Components.classes[\"@mozilla.org/network/file-output-stream;1\"]\n                .createInstance(Components.interfaces.nsIFileOutputStream);\n                \n            fileOutputStream.init(nsFile,\n                writeFlag | createFlag | truncateFlag, 0664, null);\n            return fileOutputStream;\n        },\n        \n        writeBinaryInputStreamToFileOutputStream:\n        function(binaryInputStream, fileOutputStream) {\n            var numBytes = binaryInputStream.available();\n            var bytes = binaryInputStream.readBytes(numBytes);\n            fileOutputStream.write(bytes, numBytes);\n        }\n    };\n    \n    // compute dimensions\n    var window = this.browserbot.getCurrentWindow();\n    var doc = window.document.documentElement;\n    var box = {\n        x: 0,\n        y: 0,\n        width: doc.scrollWidth,\n        height: doc.scrollHeight\n    };\n    LOG.debug('computed dimensions');\n    \n    var originalBackground = doc.style.background;\n    \n    if (kwargs) {\n        var args = parse_kwargs(kwargs);\n        if (args.background) {\n            doc.style.background = args.background;\n        }\n    }\n    \n    // grab\n    var format = 'png';\n    var canvas = grabber.prepareCanvas(box.width, box.height);\n    var context = grabber.prepareContext(canvas, box);\n    context.drawWindow(window, box.x, box.y, box.width, box.height,\n        'rgb(0, 0, 0)');\n    context.restore();\n    var dataUrl = canvas.toDataURL(\"image/\" + format);\n    LOG.debug('grabbed to canvas');\n    \n    doc.style.background = originalBackground;\n    \n    // save to file\n    var nsFile = Components.classes[\"@mozilla.org/file/local;1\"]\n        .createInstance(Components.interfaces.nsILocalFile);\n    try {\n        nsFile.initWithPath(filename);\n    }\n    catch (e) {\n        if (/NS_ERROR_FILE_UNRECOGNIZED_PATH/.test(e.message)) {\n            // try using the opposite file separator\n            if (filename.indexOf('/') != -1) {\n                filename = filename.replace(/\\//g, '\\\\');\n            }\n            else {\n                filename = filename.replace(/\\\\/g, '/');\n            }\n            nsFile.initWithPath(filename);\n        }\n        else {\n            throw e;\n        }\n    }\n    var binaryInputStream = SGNsUtils.dataUrlToBinaryInputStream(dataUrl);\n    var fileOutputStream = SGNsUtils.newFileOutputStream(nsFile);\n    SGNsUtils.writeBinaryInputStreamToFileOutputStream(binaryInputStream,\n        fileOutputStream);\n    fileOutputStream.close();\n    LOG.debug('saved to file');\n};\n\nSelenium.prototype.doRollup = function(rollupName, kwargs) {\n    /**\n     * Executes a command rollup, which is a series of commands with a unique\n     * name, and optionally arguments that control the generation of the set of\n     * commands. If any one of the rolled-up commands fails, the rollup is\n     * considered to have failed. Rollups may also contain nested rollups.\n     *\n     * @param rollupName  the name of the rollup command\n     * @param kwargs      keyword arguments string that influences how the\n     *                    rollup expands into commands\n     */\n    // we have to temporarily hijack the commandStarted, nextCommand(),\n    // commandComplete(), and commandError() methods of the TestLoop object.\n    // When the expanded rollup commands are done executing (or an error has\n    // occurred), we'll restore them to their original values.\n    var loop = currentTest || htmlTestRunner.currentTest;\n    var backupManager = {\n        backup: function() {\n            for (var item in this.data) {\n                this.data[item] = loop[item];\n            }\n        }\n        , restore: function() {\n            for (var item in this.data) {\n                loop[item] = this.data[item];\n            }\n        }\n        , data: {\n            requiresCallBack: null\n            , commandStarted: null\n            , nextCommand: null\n            , commandComplete: null\n            , commandError: null\n            , pendingRollupCommands: null\n            , rollupFailed: null\n            , rollupFailedMessage: null\n        }\n    };\n    \n    var rule = RollupManager.getInstance().getRollupRule(rollupName);\n    var expandedCommands = rule.getExpandedCommands(kwargs);\n    \n    // hold your breath ...\n    try {\n        backupManager.backup();\n        loop.requiresCallBack = false;\n        loop.commandStarted = function() {};\n        loop.nextCommand = function() {\n            if (this.pendingRollupCommands.length == 0) {\n                return null;\n            }\n            var command = this.pendingRollupCommands.shift();\n            return command;\n        };\n        loop.commandComplete = function(result) {\n            if (result.failed) {\n                this.rollupFailed = true;\n                this.rollupFailureMessages.push(result.failureMessage);\n            }\n            \n            if (this.pendingRollupCommands.length == 0) {\n                result = {\n                    failed: this.rollupFailed\n                    , failureMessage: this.rollupFailureMessages.join('; ')\n                };\n                LOG.info('Rollup execution complete: ' + (result.failed\n                    ? 'failed! (see error messages below)' : 'ok'));\n                backupManager.restore();\n                this.commandComplete(result);\n            }\n        };\n        loop.commandError = function(errorMessage) {\n            LOG.info('Rollup execution complete: bombed!');\n            backupManager.restore();\n            this.commandError(errorMessage);\n        };\n        \n        loop.pendingRollupCommands = expandedCommands;\n        loop.rollupFailed = false;\n        loop.rollupFailureMessages = [];\n    }\n    catch (e) {\n        LOG.error('Rollup error: ' + e);\n        backupManager.restore();\n    }\n};\n\nSelenium.prototype.doAddScript = function(scriptContent, scriptTagId) {\n    /**\n    * Loads script content into a new script tag in the Selenium document. This\n    * differs from the runScript command in that runScript adds the script tag\n    * to the document of the AUT, not the Selenium document. The following\n    * entities in the script content are replaced by the characters they\n    * represent:\n    *\n    *     &lt;\n    *     &gt;\n    *     &amp;\n    *\n    * The corresponding remove command is removeScript.\n    *\n    * @param scriptContent  the Javascript content of the script to add\n    * @param scriptTagId    (optional) the id of the new script tag. If\n    *                       specified, and an element with this id already\n    *                       exists, this operation will fail.\n    */\n    if (scriptTagId && document.getElementById(scriptTagId)) {\n        var msg = \"Element with id '\" + scriptTagId + \"' already exists!\";\n        throw new SeleniumError(msg);\n    }\n    \n    var head = document.getElementsByTagName('head')[0];\n    var script = document.createElement('script');\n    \n    script.type = 'text/javascript';\n    \n    if (scriptTagId) {\n        script.id = scriptTagId;\n    }\n    \n    // replace some entities\n    scriptContent = scriptContent\n        .replace(/&lt;/g, '<')\n        .replace(/&gt;/g, '>')\n        .replace(/&amp;/g, '&');\n    \n    script.text = scriptContent;\n    head.appendChild(script);\n};\n\nSelenium.prototype.doRemoveScript = function(scriptTagId) {\n    /**\n    * Removes a script tag from the Selenium document identified by the given\n    * id. Does nothing if the referenced tag doesn't exist.\n    *\n    * @param scriptTagId  the id of the script element to remove.\n    */\n    var script = document.getElementById(scriptTagId);\n    \n    if (script && getTagName(script) == 'script') {\n        script.parentNode.removeChild(script);\n    }\n};\n\nSelenium.prototype.doUseXpathLibrary = function(libraryName) {\n    /**\n\t* Allows choice of one of the available libraries.\n    * @param libraryName name of the desired library\n    * Only the following three can be chosen:\n    *   ajaxslt - Google's library\n    *   javascript - Cybozu Labs' faster library\n    *   default - The default library.  Currently the default library is ajaxslt.\n    * If libraryName isn't one of these three, then \n    * no change will be made.\n    *   \n    */\n\n    if (libraryName == \"default\") {\n        this.browserbot.xpathLibrary = this.browserbot.defaultXpathLibrary;\n        return;\n    }\n\n\tif ((libraryName != 'ajaxslt') && (libraryName != 'javascript-xpath')) {\n\t\treturn;\n\t}\n\t\n\tthis.browserbot.xpathLibrary = libraryName;\t\n\t\n};\n\n/**\n *  Factory for creating \"Option Locators\".\n *  An OptionLocator is an object for dealing with Select options (e.g. for\n *  finding a specified option, or asserting that the selected option of \n *  Select element matches some condition.\n *  The type of locator returned by the factory depends on the locator string:\n *     label=<exp>  (OptionLocatorByLabel)\n *     value=<exp>  (OptionLocatorByValue)\n *     index=<exp>  (OptionLocatorByIndex)\n *     id=<exp>     (OptionLocatorById)\n *     <exp> (default is OptionLocatorByLabel).\n */\nfunction OptionLocatorFactory() {\n}\n\nOptionLocatorFactory.prototype.fromLocatorString = function(locatorString) {\n    var locatorType = 'label';\n    var locatorValue = locatorString;\n    // If there is a locator prefix, use the specified strategy\n    var result = locatorString.match(/^([a-zA-Z]+)=(.*)/);\n    if (result) {\n        locatorType = result[1];\n        locatorValue = result[2];\n    }\n    if (this.optionLocators == undefined) {\n        this.registerOptionLocators();\n    }\n    if (this.optionLocators[locatorType]) {\n        return new this.optionLocators[locatorType](locatorValue);\n    }\n    throw new SeleniumError(\"Unknown option locator type: \" + locatorType);\n};\n\n/**\n * To allow for easy extension, all of the option locators are found by\n * searching for all methods of OptionLocatorFactory.prototype that start\n * with \"OptionLocatorBy\".\n * TODO: Consider using the term \"Option Specifier\" instead of \"Option Locator\".\n */\nOptionLocatorFactory.prototype.registerOptionLocators = function() {\n    this.optionLocators={};\n    for (var functionName in this) {\n      var result = /OptionLocatorBy([A-Z].+)$/.exec(functionName);\n      if (result != null) {\n          var locatorName = result[1].lcfirst();\n          this.optionLocators[locatorName] = this[functionName];\n      }\n    }\n};\n\n/**\n *  OptionLocator for options identified by their labels.\n */\nOptionLocatorFactory.prototype.OptionLocatorByLabel = function(label) {\n    this.label = label;\n    this.labelMatcher = new PatternMatcher(this.label);\n    this.findOption = function(element) {\n        for (var i = 0; i < element.options.length; i++) {\n            if (this.labelMatcher.matches(element.options[i].text)) {\n                return element.options[i];\n            }\n        }\n        throw new SeleniumError(\"Option with label '\" + this.label + \"' not found\");\n    };\n\n    this.assertSelected = function(element) {\n        var selectedLabel = element.options[element.selectedIndex].text;\n        Assert.matches(this.label, selectedLabel)\n    };\n};\n\n/**\n *  OptionLocator for options identified by their values.\n */\nOptionLocatorFactory.prototype.OptionLocatorByValue = function(value) {\n    this.value = value;\n    this.valueMatcher = new PatternMatcher(this.value);\n    this.findOption = function(element) {\n        for (var i = 0; i < element.options.length; i++) {\n            if (this.valueMatcher.matches(element.options[i].value)) {\n                return element.options[i];\n            }\n        }\n        throw new SeleniumError(\"Option with value '\" + this.value + \"' not found\");\n    };\n\n    this.assertSelected = function(element) {\n        var selectedValue = element.options[element.selectedIndex].value;\n        Assert.matches(this.value, selectedValue)\n    };\n};\n\n/**\n *  OptionLocator for options identified by their index.\n */\nOptionLocatorFactory.prototype.OptionLocatorByIndex = function(index) {\n    this.index = Number(index);\n    if (isNaN(this.index) || this.index < 0) {\n        throw new SeleniumError(\"Illegal Index: \" + index);\n    }\n\n    this.findOption = function(element) {\n        if (element.options.length <= this.index) {\n            throw new SeleniumError(\"Index out of range.  Only \" + element.options.length + \" options available\");\n        }\n        return element.options[this.index];\n    };\n\n    this.assertSelected = function(element) {\n        Assert.equals(this.index, element.selectedIndex);\n    };\n};\n\n/**\n *  OptionLocator for options identified by their id.\n */\nOptionLocatorFactory.prototype.OptionLocatorById = function(id) {\n    this.id = id;\n    this.idMatcher = new PatternMatcher(this.id);\n    this.findOption = function(element) {\n        for (var i = 0; i < element.options.length; i++) {\n            if (this.idMatcher.matches(element.options[i].id)) {\n                return element.options[i];\n            }\n        }\n        throw new SeleniumError(\"Option with id '\" + this.id + \"' not found\");\n    };\n\n    this.assertSelected = function(element) {\n        var selectedId = element.options[element.selectedIndex].id;\n        Assert.matches(this.id, selectedId)\n    };\n};\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-browserbot.js",
    "content": "/*\n* Copyright 2004 ThoughtWorks, Inc\n*\n*  Licensed under the Apache License, Version 2.0 (the \"License\");\n*  you may not use this file except in compliance with the License.\n*  You may obtain a copy of the License at\n*\n*      http://www.apache.org/licenses/LICENSE-2.0\n*\n*  Unless required by applicable law or agreed to in writing, software\n*  distributed under the License is distributed on an \"AS IS\" BASIS,\n*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*  See the License for the specific language governing permissions and\n*  limitations under the License.\n*\n*/\n\n/*\n* This script provides the Javascript API to drive the test application contained within\n* a Browser Window.\n* TODO:\n*    Add support for more events (keyboard and mouse)\n*    Allow to switch \"user-entry\" mode from mouse-based to keyboard-based, firing different\n*          events in different modes.\n*/\n\n// The window to which the commands will be sent.  For example, to click on a\n// popup window, first select that window, and then do a normal click command.\nvar BrowserBot = function(topLevelApplicationWindow) {\n    this.topWindow = topLevelApplicationWindow;\n    this.topFrame = this.topWindow;\n    this.baseUrl=window.location.href;\n\n    // the buttonWindow is the Selenium window\n    // it contains the Run/Pause buttons... this should *not* be the AUT window\n    this.buttonWindow = window;\n    this.currentWindow = this.topWindow;\n    this.currentWindowName = null;\n    this.allowNativeXpath = true;\n    this.xpathLibrary = this.defaultXpathLibrary = 'ajaxslt' // change to \"javascript-xpath\" for the newer, faster engine\n\n    // We need to know this in advance, in case the frame closes unexpectedly\n    this.isSubFrameSelected = false;\n\n    this.altKeyDown = false;\n    this.controlKeyDown = false;\n    this.shiftKeyDown = false;\n    this.metaKeyDown = false;\n\n    this.modalDialogTest = null;\n    this.recordedAlerts = new Array();\n    this.recordedConfirmations = new Array();\n    this.recordedPrompts = new Array();\n    this.openedWindows = {};\n    this.nextConfirmResult = true;\n    this.nextPromptResult = '';\n    this.newPageLoaded = false;\n    this.pageLoadError = null;\n\n    this.shouldHighlightLocatedElement = false;\n\n    this.uniqueId = \"seleniumMarker\" + new Date().getTime();\n    this.pollingForLoad = new Object();\n    this.permDeniedCount = new Object();\n    this.windowPollers = new Array();\n    // DGF for backwards compatibility\n    this.browserbot = this;\n\n    var self = this;\n\n    objectExtend(this, PageBot.prototype);\n    this._registerAllLocatorFunctions();\n\n    this.recordPageLoad = function(elementOrWindow) {\n        LOG.debug(\"Page load detected\");\n        try {\n            if (elementOrWindow.location && elementOrWindow.location.href) {\n                LOG.debug(\"Page load location=\" + elementOrWindow.location.href);\n            } else if (elementOrWindow.contentWindow && elementOrWindow.contentWindow.location && elementOrWindow.contentWindow.location.href) {\n                LOG.debug(\"Page load location=\" + elementOrWindow.contentWindow.location.href);\n            } else {\n                LOG.debug(\"Page load location unknown, current window location=\" + this.getCurrentWindow(true).location);\n            }\n        } catch (e) {\n            LOG.error(\"Caught an exception attempting to log location; this should get noticed soon!\");\n            LOG.exception(e);\n            self.pageLoadError = e;\n            return;\n        }\n        self.newPageLoaded = true;\n    };\n\n    this.isNewPageLoaded = function() {\n        if (this.pageLoadError) {\n            LOG.error(\"isNewPageLoaded found an old pageLoadError\");\n            var e = this.pageLoadError;\n            this.pageLoadError = null;\n            throw e;\n        }\n        return self.newPageLoaded;\n    };\n\n};\n\n// DGF PageBot exists for backwards compatibility with old user-extensions\nvar PageBot = function(){};\n\nBrowserBot.createForWindow = function(window, proxyInjectionMode) {\n    var browserbot;\n    LOG.debug('createForWindow');\n    LOG.debug(\"browserName: \" + browserVersion.name);\n    LOG.debug(\"userAgent: \" + navigator.userAgent);\n    if (browserVersion.isIE) {\n        browserbot = new IEBrowserBot(window);\n    }\n    else if (browserVersion.isKonqueror) {\n        browserbot = new KonquerorBrowserBot(window);\n    }\n    else if (browserVersion.isOpera) {\n        browserbot = new OperaBrowserBot(window);\n    }\n    else if (browserVersion.isSafari) {\n        browserbot = new SafariBrowserBot(window);\n    }\n    else {\n        // Use mozilla by default\n        browserbot = new MozillaBrowserBot(window);\n    }\n    // getCurrentWindow has the side effect of modifying it to handle page loads etc\n    browserbot.proxyInjectionMode = proxyInjectionMode;\n    browserbot.getCurrentWindow();    // for modifyWindow side effect.  This is not a transparent style\n    return browserbot;\n};\n\n// todo: rename?  This doesn't actually \"do\" anything.\nBrowserBot.prototype.doModalDialogTest = function(test) {\n    this.modalDialogTest = test;\n};\n\nBrowserBot.prototype.cancelNextConfirmation = function(result) {\n    this.nextConfirmResult = result;\n};\n\nBrowserBot.prototype.setNextPromptResult = function(result) {\n    this.nextPromptResult = result;\n};\n\nBrowserBot.prototype.hasAlerts = function() {\n    return (this.recordedAlerts.length > 0);\n};\n\nBrowserBot.prototype.relayBotToRC = function(s) {\n    // DGF need to do this funny trick to see if we're in PI mode, because\n    // \"this\" might be the window, rather than the browserbot (e.g. during window.alert) \n    var piMode = this.proxyInjectionMode;\n    if (!piMode) {\n        if (typeof(selenium) != \"undefined\") {\n            piMode = selenium.browserbot && selenium.browserbot.proxyInjectionMode;\n        }\n    }\n    if (piMode) {\n        this.relayToRC(\"selenium.\" + s);\n    }\n};\n\nBrowserBot.prototype.relayToRC = function(name) {\n        var object = eval(name);\n        var s = 'state:' + serializeObject(name, object) + \"\\n\";\n        sendToRC(s,\"state=true\");\n}\n\nBrowserBot.prototype.resetPopups = function() {\n    this.recordedAlerts = [];\n    this.recordedConfirmations = [];\n    this.recordedPrompts = [];\n}\n\nBrowserBot.prototype.getNextAlert = function() {\n    var t = this.recordedAlerts.shift();\n    if (t) { \n        t = t.replace(/\\n/g, \" \");  // because Selenese loses \\n's when retrieving text from HTML table\n    }\n    this.relayBotToRC(\"browserbot.recordedAlerts\");\n    return t;\n};\n\nBrowserBot.prototype.hasConfirmations = function() {\n    return (this.recordedConfirmations.length > 0);\n};\n\nBrowserBot.prototype.getNextConfirmation = function() {\n    var t = this.recordedConfirmations.shift();\n    this.relayBotToRC(\"browserbot.recordedConfirmations\");\n    return t;\n};\n\nBrowserBot.prototype.hasPrompts = function() {\n    return (this.recordedPrompts.length > 0);\n};\n\nBrowserBot.prototype.getNextPrompt = function() {\n    var t = this.recordedPrompts.shift();\n    this.relayBotToRC(\"browserbot.recordedPrompts\");\n    return t;\n};\n\n/* Fire a mouse event in a browser-compatible manner */\n\nBrowserBot.prototype.triggerMouseEvent = function(element, eventType, canBubble, clientX, clientY, button) {\n    clientX = clientX ? clientX : 0;\n    clientY = clientY ? clientY : 0;\n\n    LOG.debug(\"triggerMouseEvent assumes setting screenX and screenY to 0 is ok\");\n    var screenX = 0;\n    var screenY = 0;\n\n    canBubble = (typeof(canBubble) == undefined) ? true : canBubble;\n    if (element.fireEvent && element.ownerDocument && element.ownerDocument.createEventObject) { //IE\n        var evt = createEventObject(element, this.controlKeyDown, this.altKeyDown, this.shiftKeyDown, this.metaKeyDown);\n        evt.detail = 0;\n        evt.button = button ? button : 1; // default will be the left mouse click ( http://www.javascriptkit.com/jsref/event.shtml )\n        evt.relatedTarget = null;\n        if (!screenX && !screenY && !clientX && !clientY && !this.controlKeyDown && !this.altKeyDown && !this.shiftKeyDown && !this.metaKeyDown) {\n            element.fireEvent('on' + eventType);\n        }\n        else {\n            evt.screenX = screenX;\n            evt.screenY = screenY;\n            evt.clientX = clientX;\n            evt.clientY = clientY;\n\n            // when we go this route, window.event is never set to contain the event we have just created.\n            // ideally we could just slide it in as follows in the try-block below, but this normally\n            // doesn't work.  This is why I try to avoid this code path, which is only required if we need to\n            // set attributes on the event (e.g., clientX).\n            try {\n                window.event = evt;\n            }\n            catch(e) {\n                // getting an \"Object does not support this action or property\" error.  Save the event away\n                // for future reference.\n                // TODO: is there a way to update window.event?\n\n                // work around for http://jira.openqa.org/browse/SEL-280 -- make the event available somewhere:\n                selenium.browserbot.getCurrentWindow().selenium_event = evt;\n            }\n            element.fireEvent('on' + eventType, evt);\n        }\n    }\n    else {\n        var evt = document.createEvent('MouseEvents');\n        if (evt.initMouseEvent)\n        {\n            // see http://developer.mozilla.org/en/docs/DOM:event.button and\n            // http://developer.mozilla.org/en/docs/DOM:event.initMouseEvent for button ternary logic logic\n            //Safari\n            evt.initMouseEvent(eventType, canBubble, true, document.defaultView, 1, screenX, screenY, clientX, clientY,\n                this.controlKeyDown, this.altKeyDown, this.shiftKeyDown, this.metaKeyDown, button ? button : 0, null);\n        }\n        else {\n            LOG.warn(\"element doesn't have initMouseEvent; firing an event which should -- but doesn't -- have other mouse-event related attributes here, as well as controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown\");\n            evt.initEvent(eventType, canBubble, true);\n\n            evt.shiftKey = this.shiftKeyDown;\n            evt.metaKey = this.metaKeyDown;\n            evt.altKey = this.altKeyDown;\n            evt.ctrlKey = this.controlKeyDown;\n            if(button)\n            {\n              evt.button = button;\n            }\n        }\n        element.dispatchEvent(evt);\n    }\n}\n\nBrowserBot.prototype._windowClosed = function(win) {\n    var c = win.closed;\n    if (c == null) return true;\n    return c;\n};\n\nBrowserBot.prototype._modifyWindow = function(win) {\n    // In proxyInjectionMode, have to suppress LOG calls in _modifyWindow to avoid an infinite loop\n    if (this._windowClosed(win)) {\n        if (!this.proxyInjectionMode) {\n            LOG.error(\"modifyWindow: Window was closed!\");\n        }\n        return null;\n    }\n    if (!this.proxyInjectionMode) {\n        LOG.debug('modifyWindow ' + this.uniqueId + \":\" + win[this.uniqueId]);\n    }\n    if (!win[this.uniqueId]) {\n        win[this.uniqueId] = 1;\n        this.modifyWindowToRecordPopUpDialogs(win, this);\n    }\n    // In proxyInjection mode, we have our own mechanism for detecting page loads\n    if (!this.proxyInjectionMode) {\n        this.modifySeparateTestWindowToDetectPageLoads(win);\n    }\n    if (win.frames && win.frames.length && win.frames.length > 0) {\n        for (var i = 0; i < win.frames.length; i++) {\n            try {\n                this._modifyWindow(win.frames[i]);\n            } catch (e) {} // we're just trying to be opportunistic; don't worry if this doesn't work out\n        }\n    }\n    return win;\n};\n\nBrowserBot.prototype.selectWindow = function(target) {\n    if (!target || target == \"null\") {\n        this._selectTopWindow();\n        return;\n    }\n    var result = target.match(/^([a-zA-Z]+)=(.*)/);\n    if (!result) {\n        try {\n            this._selectWindowByName(target);\n        }\n        catch (e) {\n            this._selectWindowByTitle(target);\n        }\n        return;\n    }\n    locatorType = result[1];\n    locatorValue = result[2];\n    if (locatorType == \"title\") {\n        this._selectWindowByTitle(locatorValue);\n    }\n    // TODO separate name and var into separate functions\n    else if (locatorType == \"name\") {\n        this._selectWindowByName(locatorValue);\n    } else if (locatorType == \"var\") {\n        this._selectWindowByName(locatorValue);\n    } else {\n        throw new SeleniumError(\"Window locator not recognized: \" + locatorType);\n    }\n};\n\nBrowserBot.prototype._selectTopWindow = function() {\n    this.currentWindowName = null;\n    this.currentWindow = this.topWindow;\n    this.topFrame = this.topWindow;\n    this.isSubFrameSelected = false;\n}\n\nBrowserBot.prototype._selectWindowByName = function(target) {\n    this.currentWindow = this.getWindowByName(target, false);\n    this.topFrame = this.currentWindow;\n    this.currentWindowName = target;\n    this.isSubFrameSelected = false;\n}\n\nBrowserBot.prototype._selectWindowByTitle = function(target) {\n    var windowName = this.getWindowNameByTitle(target);\n    if (!windowName) {\n        this._selectTopWindow();\n    } else {\n        this._selectWindowByName(windowName);\n    }\n}\n\nBrowserBot.prototype.selectFrame = function(target) {\n    if (target.indexOf(\"index=\") == 0) {\n        target = target.substr(6);\n        var frame = this.getCurrentWindow().frames[target];\n        if (frame == null) {\n            throw new SeleniumError(\"Not found: frames[\"+index+\"]\");\n        }\n        if (!frame.document) {\n            throw new SeleniumError(\"frames[\"+index+\"] is not a frame\");\n        }\n        this.currentWindow = frame;\n        this.isSubFrameSelected = true;\n    }\n    else if (target == \"relative=up\" || target == \"relative=parent\") {\n        this.currentWindow = this.getCurrentWindow().parent;\n        this.isSubFrameSelected = (this._getFrameElement(this.currentWindow) != null);\n    } else if (target == \"relative=top\") {\n        this.currentWindow = this.topFrame;\n        this.isSubFrameSelected = false;\n    } else {\n        var frame = this.findElement(target);\n        if (frame == null) {\n            throw new SeleniumError(\"Not found: \" + target);\n        }\n        // now, did they give us a frame or a frame ELEMENT?\n        var match = false;\n        if (frame.contentWindow) {\n            // this must be a frame element\n            if (browserVersion.isHTA) {\n                // stupid HTA bug; can't get in the front door\n                target = frame.contentWindow.name;\n            } else {\n                this.currentWindow = frame.contentWindow;\n                this.isSubFrameSelected = true;\n                match = true;\n            }\n        } else if (frame.document && frame.location) {\n            // must be an actual window frame\n            this.currentWindow = frame;\n            this.isSubFrameSelected = true;\n            match = true;\n        }\n\n        if (!match) {\n            // neither, let's loop through the frame names\n            var win = this.getCurrentWindow();\n\n            if (win && win.frames && win.frames.length) {\n                for (var i = 0; i < win.frames.length; i++) {\n                    if (win.frames[i].name == target) {\n                        this.currentWindow = win.frames[i];\n                        this.isSubFrameSelected = true;\n                        match = true;\n                        break;\n                    }\n                }\n            }\n            if (!match) {\n                throw new SeleniumError(\"Not a frame: \" + target);\n            }\n        }\n    }\n    // modifies the window\n    this.getCurrentWindow();\n};\n\nBrowserBot.prototype.doesThisFrameMatchFrameExpression = function(currentFrameString, target) {\n    var isDom = false;\n    if (target.indexOf(\"dom=\") == 0) {\n        target = target.substr(4);\n        isDom = true;\n    } else if (target.indexOf(\"index=\") == 0) {\n        target = \"frames[\" + target.substr(6) + \"]\";\n        isDom = true;\n    }\n    var t;\n    try {\n        eval(\"t=\" + currentFrameString + \".\" + target);\n    } catch (e) {\n    }\n    var autWindow = this.browserbot.getCurrentWindow();\n    if (t != null) {\n        try {\n            if (t.window == autWindow) {\n                return true;\n            }\n            if (t.window.uniqueId == autWindow.uniqueId) {\n                return true;\n               }\n            return false;\n        } catch (permDenied) {\n            // DGF if the windows are incomparable, they're probably not the same...\n        }\n    }\n    if (isDom) {\n        return false;\n    }\n    var currentFrame;\n    eval(\"currentFrame=\" + currentFrameString);\n    if (target == \"relative=up\") {\n        if (currentFrame.window.parent == autWindow) {\n            return true;\n        }\n        return false;\n    }\n    if (target == \"relative=top\") {\n        if (currentFrame.window.top == autWindow) {\n            return true;\n        }\n        return false;\n    }\n    if (currentFrame.window == autWindow.parent) {\n        if (autWindow.name == target) {\n            return true;\n        }\n        try {\n            var element = this.findElement(target, currentFrame.window);\n            if (element.contentWindow == autWindow) {\n                return true;\n            }\n        } catch (e) {}\n    }\n    return false;\n};\n\nBrowserBot.prototype.openLocation = function(target) {\n    // We're moving to a new page - clear the current one\n    var win = this.getCurrentWindow();\n    LOG.debug(\"openLocation newPageLoaded = false\");\n    this.newPageLoaded = false;\n\n    this.setOpenLocation(win, target);\n};\n\nBrowserBot.prototype.openWindow = function(url, windowID) {\n    if (url != \"\") {\n        url = absolutify(url, this.baseUrl);\n    }\n    if (browserVersion.isHTA) {\n        // in HTA mode, calling .open on the window interprets the url relative to that window\n        // we need to absolute-ize the URL to make it consistent\n        var child = this.getCurrentWindow().open(url, windowID);\n        selenium.browserbot.openedWindows[windowID] = child;\n    } else {\n        this.getCurrentWindow().open(url, windowID);\n    }\n};\n\nBrowserBot.prototype.setIFrameLocation = function(iframe, location) {\n    iframe.src = location;\n};\n\nBrowserBot.prototype.setOpenLocation = function(win, loc) {\n    loc = absolutify(loc, this.baseUrl);\n    if (browserVersion.isHTA) {\n        var oldHref = win.location.href;\n        win.location.href = loc;\n        var marker = null;\n        try {\n            marker = this.isPollingForLoad(win);\n            if (marker && win.location[marker]) {\n                win.location[marker] = false;\n            }\n        } catch (e) {} // DGF don't know why, but this often fails\n    } else {\n        win.location.href = loc;\n    }\n};\n\nBrowserBot.prototype.getCurrentPage = function() {\n    return this;\n};\n\nBrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {\n    var self = this;\n\n    windowToModify.seleniumAlert = windowToModify.alert;\n\n    windowToModify.alert = function(alert) {\n        browserBot.recordedAlerts.push(alert);\n        self.relayBotToRC.call(self, \"browserbot.recordedAlerts\");\n    };\n\n    windowToModify.confirm = function(message) {\n        browserBot.recordedConfirmations.push(message);\n        var result = browserBot.nextConfirmResult;\n        browserBot.nextConfirmResult = true;\n        self.relayBotToRC.call(self, \"browserbot.recordedConfirmations\");\n        return result;\n    };\n\n    windowToModify.prompt = function(message) {\n        browserBot.recordedPrompts.push(message);\n        var result = !browserBot.nextConfirmResult ? null : browserBot.nextPromptResult;\n        browserBot.nextConfirmResult = true;\n        browserBot.nextPromptResult = '';\n        self.relayBotToRC.call(self, \"browserbot.recordedPrompts\");\n        return result;\n    };\n\n    // Keep a reference to all popup windows by name\n    // note that in IE the \"windowName\" argument must be a valid javascript identifier, it seems.\n    var originalOpen = windowToModify.open;\n    var originalOpenReference;\n    if (browserVersion.isHTA) {\n        originalOpenReference = 'selenium_originalOpen' + new Date().getTime();\n        windowToModify[originalOpenReference] = windowToModify.open;\n    }\n\n    var isHTA = browserVersion.isHTA;\n\n    var newOpen = function(url, windowName, windowFeatures, replaceFlag) {\n        var myOriginalOpen = originalOpen;\n        if (isHTA) {\n            myOriginalOpen = this[originalOpenReference];\n        }\n        if (windowName == \"\" || windowName == \"_blank\") {\n            windowName = \"selenium_blank\" + Math.round(100000 * Math.random());\n            LOG.warn(\"Opening window '_blank', which is not a real window name.  Randomizing target to be: \" + windowName);\n        }\n        var openedWindow = myOriginalOpen(url, windowName, windowFeatures, replaceFlag);\n        LOG.debug(\"window.open call intercepted; window ID (which you can use with selectWindow()) is \\\"\" +  windowName + \"\\\"\");\n        if (windowName!=null) {\n            openedWindow[\"seleniumWindowName\"] = windowName;\n        }\n        selenium.browserbot.openedWindows[windowName] = openedWindow;\n        return openedWindow;\n    };\n\n    if (browserVersion.isHTA) {\n        originalOpenReference = 'selenium_originalOpen' + new Date().getTime();\n        newOpenReference = 'selenium_newOpen' + new Date().getTime();\n        var setOriginalRef = \"this['\" + originalOpenReference + \"'] = this.open;\";\n\n        if (windowToModify.eval) {\n            windowToModify.eval(setOriginalRef);\n            windowToModify.open = newOpen;\n        } else {\n            // DGF why can't I eval here?  Seems like I'm querying the window at a bad time, maybe?\n            setOriginalRef += \"this.open = this['\" + newOpenReference + \"'];\";\n            windowToModify[newOpenReference] = newOpen;\n            windowToModify.setTimeout(setOriginalRef, 0);\n        }\n    } else {\n        windowToModify.open = newOpen;\n    }\n};\n\n/**\n * Call the supplied function when a the current page unloads and a new one loads.\n * This is done by polling continuously until the document changes and is fully loaded.\n */\nBrowserBot.prototype.modifySeparateTestWindowToDetectPageLoads = function(windowObject) {\n    // Since the unload event doesn't fire in Safari 1.3, we start polling immediately\n    if (!windowObject) {\n        LOG.warn(\"modifySeparateTestWindowToDetectPageLoads: no windowObject!\");\n        return;\n    }\n    if (this._windowClosed(windowObject)) {\n        LOG.info(\"modifySeparateTestWindowToDetectPageLoads: windowObject was closed\");\n        return;\n    }\n    var oldMarker = this.isPollingForLoad(windowObject);\n    if (oldMarker) {\n        LOG.debug(\"modifySeparateTestWindowToDetectPageLoads: already polling this window: \" + oldMarker);\n        return;\n    }\n\n    var marker = 'selenium' + new Date().getTime();\n    LOG.debug(\"Starting pollForLoad (\" + marker + \"): \" + windowObject.location);\n    this.pollingForLoad[marker] = true;\n    // if this is a frame, add a load listener, otherwise, attach a poller\n    var frameElement = this._getFrameElement(windowObject);\n    // DGF HTA mode can't attach load listeners to subframes (yuk!)\n    var htaSubFrame = this._isHTASubFrame(windowObject);\n    if (frameElement && !htaSubFrame) {\n        LOG.debug(\"modifySeparateTestWindowToDetectPageLoads: this window is a frame; attaching a load listener\");\n        addLoadListener(frameElement, this.recordPageLoad);\n        frameElement[marker] = true;\n        frameElement[\"frame\"+this.uniqueId] = marker;\n\tLOG.debug(\"dgf this.uniqueId=\"+this.uniqueId);\n\tLOG.debug(\"dgf marker=\"+marker);\n\tLOG.debug(\"dgf frameElement['frame'+this.uniqueId]=\"+frameElement['frame'+this.uniqueId]);\nframeElement[this.uniqueId] = marker;\nLOG.debug(\"dgf frameElement[this.uniqueId]=\"+frameElement[this.uniqueId]);\n    } else {\n        windowObject.location[marker] = true;\n        windowObject[this.uniqueId] = marker;\n        this.pollForLoad(this.recordPageLoad, windowObject, windowObject.document, windowObject.location, windowObject.location.href, marker);\n    }\n};\n\nBrowserBot.prototype._isHTASubFrame = function(win) {\n    if (!browserVersion.isHTA) return false;\n    // DGF this is wrong! what if \"win\" isn't the selected window?\n    return this.isSubFrameSelected;\n}\n\nBrowserBot.prototype._getFrameElement = function(win) {\n    var frameElement = null;\n    var caught;\n    try {\n        frameElement = win.frameElement;\n    } catch (e) {\n        caught = true;\n    }\n    if (caught) {\n        // on IE, checking frameElement in a pop-up results in a \"No such interface supported\" exception\n        // but it might have a frame element anyway!\n        var parentContainsIdenticallyNamedFrame = false;\n        try {\n            parentContainsIdenticallyNamedFrame = win.parent.frames[win.name];\n        } catch (e) {} // this may fail if access is denied to the parent; in that case, assume it's not a pop-up\n\n        if (parentContainsIdenticallyNamedFrame) {\n            // it can't be a coincidence that the parent has a frame with the same name as myself!\n            var result;\n            try {\n                result = parentContainsIdenticallyNamedFrame.frameElement;\n                if (result) {\n                    return result;\n                }\n            } catch (e) {} // it was worth a try! _getFrameElementsByName is often slow\n            result = this._getFrameElementByName(win.name, win.parent.document, win);\n            return result;\n        }\n    }\n    LOG.debug(\"_getFrameElement: frameElement=\"+frameElement); \n    if (frameElement) {\n        LOG.debug(\"frameElement.name=\"+frameElement.name);\n    }\n    return frameElement;\n}\n\nBrowserBot.prototype._getFrameElementByName = function(name, doc, win) {\n    var frames;\n    var frame;\n    var i;\n    frames = doc.getElementsByTagName(\"iframe\");\n    for (i = 0; i < frames.length; i++) {\n        frame = frames[i];        \n        if (frame.name === name) {\n            return frame;\n        }\n    }\n    frames = doc.getElementsByTagName(\"frame\");\n    for (i = 0; i < frames.length; i++) {\n        frame = frames[i];        \n        if (frame.name === name) {\n            return frame;\n        }\n    }\n    // DGF weird; we only call this function when we know the doc contains the frame\n    LOG.warn(\"_getFrameElementByName couldn't find a frame or iframe; checking every element for the name \" + name);\n    return BrowserBot.prototype.locateElementByName(win.name, win.parent.document);\n}\n    \n\n/**\n * Set up a polling timer that will keep checking the readyState of the document until it's complete.\n * Since we might call this before the original page is unloaded, we first check to see that the current location\n * or href is different from the original one.\n */\nBrowserBot.prototype.pollForLoad = function(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker) {\n    LOG.debug(\"pollForLoad original (\" + marker + \"): \" + originalHref);\n    try {\n        if (this._windowClosed(windowObject)) {\n            LOG.debug(\"pollForLoad WINDOW CLOSED (\" + marker + \")\");\n            delete this.pollingForLoad[marker];\n            return;\n        }\n\n        var isSamePage = this._isSamePage(windowObject, originalDocument, originalLocation, originalHref, marker);\n        var rs = this.getReadyState(windowObject, windowObject.document);\n\n        if (!isSamePage && rs == 'complete') {\n            var currentHref = windowObject.location.href;\n            LOG.debug(\"pollForLoad FINISHED (\" + marker + \"): \" + rs + \" (\" + currentHref + \")\");\n            delete this.pollingForLoad[marker];\n            this._modifyWindow(windowObject);\n            var newMarker = this.isPollingForLoad(windowObject);\n            if (!newMarker) {\n                LOG.debug(\"modifyWindow didn't start new poller: \" + newMarker);\n                this.modifySeparateTestWindowToDetectPageLoads(windowObject);\n            }\n            newMarker = this.isPollingForLoad(windowObject);\n            var currentlySelectedWindow;\n            var currentlySelectedWindowMarker;\n            currentlySelectedWindow =this.getCurrentWindow(true);\n            currentlySelectedWindowMarker = currentlySelectedWindow[this.uniqueId];\n\n            LOG.debug(\"pollForLoad (\" + marker + \") restarting \" + newMarker);\n            if (/(TestRunner-splash|Blank)\\.html\\?start=true$/.test(currentHref)) {\n                LOG.debug(\"pollForLoad Oh, it's just the starting page.  Never mind!\");\n            } else if (currentlySelectedWindowMarker == newMarker) {\n                loadFunction(currentlySelectedWindow);\n            } else {\n                LOG.debug(\"pollForLoad page load detected in non-current window; ignoring (currentlySelected=\"+currentlySelectedWindowMarker+\", detection in \"+newMarker+\")\");\n            }\n            return;\n        }\n        LOG.debug(\"pollForLoad continue (\" + marker + \"): \" + currentHref);\n        this.reschedulePoller(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);\n    } catch (e) {\n        LOG.debug(\"Exception during pollForLoad; this should get noticed soon (\" + e.message + \")!\");\n        //DGF this is supposed to get logged later; log it at debug just in case\n        //LOG.exception(e);\n        this.pageLoadError = e;\n    }\n};\n\nBrowserBot.prototype._isSamePage = function(windowObject, originalDocument, originalLocation, originalHref, marker) {\n    var currentDocument = windowObject.document;\n    var currentLocation = windowObject.location;\n    var currentHref = currentLocation.href\n\n    var sameDoc = this._isSameDocument(originalDocument, currentDocument);\n\n    var sameLoc = (originalLocation === currentLocation);\n\n    // hash marks don't meant the page has loaded, so we need to strip them off if they exist...\n    var currentHash = currentHref.indexOf('#');\n    if (currentHash > 0) {\n        currentHref = currentHref.substring(0, currentHash);\n    }\n    var originalHash = originalHref.indexOf('#');\n    if (originalHash > 0) {\n        originalHref = originalHref.substring(0, originalHash);\n    }\n    LOG.debug(\"_isSamePage: currentHref: \" + currentHref);\n    LOG.debug(\"_isSamePage: originalHref: \" + originalHref);\n\n    var sameHref = (originalHref === currentHref);\n    var markedLoc = currentLocation[marker];\n\n    if (browserVersion.isKonqueror || browserVersion.isSafari) {\n        // the mark disappears too early on these browsers\n        markedLoc = true;\n    }\n\n    // since this is some _very_ important logic, especially for PI and multiWindow mode, we should log all these out\n    LOG.debug(\"_isSamePage: sameDoc: \" + sameDoc);\n    LOG.debug(\"_isSamePage: sameLoc: \" + sameLoc);\n    LOG.debug(\"_isSamePage: sameHref: \" + sameHref);\n    LOG.debug(\"_isSamePage: markedLoc: \" + markedLoc);\n\n    return sameDoc && sameLoc && sameHref && markedLoc\n};\n\nBrowserBot.prototype._isSameDocument = function(originalDocument, currentDocument) {\n    return originalDocument === currentDocument;\n};\n\n\nBrowserBot.prototype.getReadyState = function(windowObject, currentDocument) {\n    var rs = currentDocument.readyState;\n    if (rs == null) {\n       if ((this.buttonWindow!=null && this.buttonWindow.document.readyState == null) // not proxy injection mode (and therefore buttonWindow isn't null)\n       || (top.document.readyState == null)) {                                               // proxy injection mode (and therefore everything's in the top window, but buttonWindow doesn't exist)\n            // uh oh!  we're probably on Firefox with no readyState extension installed!\n            // We'll have to just take a guess as to when the document is loaded; this guess\n            // will never be perfect. :-(\n            if (typeof currentDocument.getElementsByTagName != 'undefined'\n                    && typeof currentDocument.getElementById != 'undefined'\n                    && ( currentDocument.getElementsByTagName('body')[0] != null\n                    || currentDocument.body != null )) {\n                if (windowObject.frameElement && windowObject.location.href == \"about:blank\" && windowObject.frameElement.src != \"about:blank\") {\n                    LOG.info(\"getReadyState not loaded, frame location was about:blank, but frame src = \" + windowObject.frameElement.src);\n                    return null;\n                }\n                LOG.debug(\"getReadyState = windowObject.frames.length = \" + windowObject.frames.length);\n                for (var i = 0; i < windowObject.frames.length; i++) {\n                    LOG.debug(\"i = \" + i);\n                    if (this.getReadyState(windowObject.frames[i], windowObject.frames[i].document) != 'complete') {\n                        LOG.debug(\"getReadyState aha! the nested frame \" + windowObject.frames[i].name + \" wasn't ready!\");\n                        return null;\n                    }\n                }\n\n                rs = 'complete';\n            } else {\n                LOG.debug(\"pollForLoad readyState was null and DOM appeared to not be ready yet\");\n            }\n        }\n    }\n    else if (rs == \"loading\" && browserVersion.isIE) {\n        LOG.debug(\"pageUnloading = true!!!!\");\n        this.pageUnloading = true;\n    }\n    LOG.debug(\"getReadyState returning \" + rs);\n    return rs;\n};\n\n/** This function isn't used normally, but was the way we used to schedule pollers:\n asynchronously executed autonomous units.  This is deprecated, but remains here\n for future reference.\n */\nBrowserBot.prototype.XXXreschedulePoller = function(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker) {\n    var self = this;\n    window.setTimeout(function() {\n        self.pollForLoad(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);\n    }, 500);\n};\n\n/** This function isn't used normally, but is useful for debugging asynchronous pollers\n * To enable it, rename it to \"reschedulePoller\", so it will override the\n * existing reschedulePoller function\n */\nBrowserBot.prototype.XXXreschedulePoller = function(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker) {\n    var doc = this.buttonWindow.document;\n    var button = doc.createElement(\"button\");\n    var buttonName = doc.createTextNode(marker + \" - \" + windowObject.name);\n    button.appendChild(buttonName);\n    var tools = doc.getElementById(\"tools\");\n    var self = this;\n    button.onclick = function() {\n        tools.removeChild(button);\n        self.pollForLoad(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);\n    };\n    tools.appendChild(button);\n    window.setTimeout(button.onclick, 500);\n};\n\nBrowserBot.prototype.reschedulePoller = function(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker) {\n    var self = this;\n    var pollerFunction = function() {\n        self.pollForLoad(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);\n    };\n    this.windowPollers.push(pollerFunction);\n};\n\nBrowserBot.prototype.runScheduledPollers = function() {\n    LOG.debug(\"runScheduledPollers\");\n    var oldPollers = this.windowPollers;\n    this.windowPollers = new Array();\n    for (var i = 0; i < oldPollers.length; i++) {\n        oldPollers[i].call();\n    }\n    LOG.debug(\"runScheduledPollers DONE\");\n};\n\nBrowserBot.prototype.isPollingForLoad = function(win) {\n    var marker;\n    var frameElement = this._getFrameElement(win);\n    var htaSubFrame = this._isHTASubFrame(win);\n    if (frameElement && !htaSubFrame) {\n\tmarker = frameElement[\"frame\"+this.uniqueId];\n    } else {\n        marker = win[this.uniqueId];\n    }\n    if (!marker) {\n        LOG.debug(\"isPollingForLoad false, missing uniqueId \" + this.uniqueId + \": \" + marker);\n        return false;\n    }\n    if (!this.pollingForLoad[marker]) {\n        LOG.debug(\"isPollingForLoad false, this.pollingForLoad[\" + marker + \"]: \" + this.pollingForLoad[marker]);\n        return false;\n    }\n    return marker;\n};\n\nBrowserBot.prototype.getWindowByName = function(windowName, doNotModify) {\n    LOG.debug(\"getWindowByName(\" + windowName + \")\");\n    // First look in the map of opened windows\n    var targetWindow = this.openedWindows[windowName];\n    if (!targetWindow) {\n        targetWindow = this.topWindow[windowName];\n    }\n    if (!targetWindow && windowName == \"_blank\") {\n        for (var winName in this.openedWindows) {\n            // _blank can match selenium_blank*, if it looks like it's OK (valid href, not closed)\n            if (/^selenium_blank/.test(winName)) {\n                targetWindow = this.openedWindows[winName];\n                var ok;\n                try {\n                    if (!this._windowClosed(targetWindow)) {\n                        ok = targetWindow.location.href;\n                    }\n                } catch (e) {}\n                if (ok) break;\n            }\n        }\n    }\n    if (!targetWindow) {\n        throw new SeleniumError(\"Window does not exist. If this looks like a Selenium bug, make sure to read http://selenium-core.openqa.org/reference.html#openWindow for potential workarounds.\");\n    }\n    if (browserVersion.isHTA) {\n        try {\n            targetWindow.location.href;\n        } catch (e) {\n            targetWindow = window.open(\"\", targetWindow.name);\n            this.openedWindows[targetWindow.name] = targetWindow;\n        }\n    }\n    if (!doNotModify) {\n        this._modifyWindow(targetWindow);\n    }\n    return targetWindow;\n};\n\n/**\n * Find a window name from the window title.\n */\nBrowserBot.prototype.getWindowNameByTitle = function(windowTitle) {\n    LOG.debug(\"getWindowNameByTitle(\" + windowTitle + \")\");\n\n    // First look in the map of opened windows and iterate them\n    for (var windowName in this.openedWindows) {\n        var targetWindow = this.openedWindows[windowName];\n\n        // If the target window's title is our title\n        try {\n            // TODO implement Pattern Matching here\n            if (!this._windowClosed(targetWindow) &&\n                targetWindow.document.title == windowTitle) {\n                return windowName;\n            }\n        } catch (e) {\n            // You'll often get Permission Denied errors here in IE\n            // eh, if we can't read this window's title,\n            // it's probably not available to us right now anyway\n        }\n    }\n    \n    try {\n        if (this.topWindow.document.title == windowTitle) {\n            return \"\";\n        }\n    } catch (e) {} // IE Perm denied\n\n    throw new SeleniumError(\"Could not find window with title \" + windowTitle);\n};\n\nBrowserBot.prototype.getCurrentWindow = function(doNotModify) {\n    if (this.proxyInjectionMode) {\n        return window;\n    }\n    var testWindow = this.currentWindow;\n    if (!doNotModify) {\n        this._modifyWindow(testWindow);\n        LOG.debug(\"getCurrentWindow newPageLoaded = false\");\n        this.newPageLoaded = false;\n    }\n    testWindow = this._handleClosedSubFrame(testWindow, doNotModify);\n    return testWindow;\n};\n\n/**\n * Offer a method the end-user can reliably use to retrieve the current window.\n * This should work even for windows with an XPCNativeWrapper. Returns the\n * current window object.\n */\nBrowserBot.prototype.getUserWindow = function() {\n    var userWindow = this.getCurrentWindow(true);\n    \n    if (userWindow.wrappedJSObject) {\n        userWindow = userWindow.wrappedJSObject;\n    }\n    \n    return userWindow;\n};\n\nBrowserBot.prototype._handleClosedSubFrame = function(testWindow, doNotModify) {\n    if (this.proxyInjectionMode) {\n        return testWindow;\n    }\n\n    if (this.isSubFrameSelected) {\n        var missing = true;\n        if (testWindow.parent && testWindow.parent.frames && testWindow.parent.frames.length) {\n            for (var i = 0; i < testWindow.parent.frames.length; i++) {\n                if (testWindow.parent.frames[i] == testWindow) {\n                    missing = false;\n                    break;\n                }\n            }\n        }\n        if (missing) {\n            LOG.warn(\"Current subframe appears to have closed; selecting top frame\");\n            this.selectFrame(\"relative=top\");\n            return this.getCurrentWindow(doNotModify);\n        }\n    } else if (this._windowClosed(testWindow)) {\n        var closedError = new SeleniumError(\"Current window or frame is closed!\");\n        closedError.windowClosed = true;\n        throw closedError;\n    }\n    return testWindow;\n};\n\nBrowserBot.prototype.highlight = function (element, force) {\n    if (force || this.shouldHighlightLocatedElement) {\n        try {\n            highlight(element);\n        } catch (e) {} // DGF element highlighting is low-priority and possibly dangerous\n    }\n    return element;\n}\n\nBrowserBot.prototype.setShouldHighlightElement = function (shouldHighlight) {\n    this.shouldHighlightLocatedElement = shouldHighlight;\n}\n\n/*****************************************************************/\n/* BROWSER-SPECIFIC FUNCTIONS ONLY AFTER THIS LINE */\n\n\nBrowserBot.prototype._registerAllLocatorFunctions = function() {\n    // TODO - don't do this in the constructor - only needed once ever\n    this.locationStrategies = {};\n    for (var functionName in this) {\n        var result = /^locateElementBy([A-Z].+)$/.exec(functionName);\n        if (result != null) {\n            var locatorFunction = this[functionName];\n            if (typeof(locatorFunction) != 'function') {\n                continue;\n            }\n            // Use a specified prefix in preference to one generated from\n            // the function name\n            var locatorPrefix = locatorFunction.prefix || result[1].toLowerCase();\n            this.locationStrategies[locatorPrefix] = locatorFunction;\n        }\n    }\n\n    /**\n     * Find a locator based on a prefix.\n     */\n    this.findElementBy = function(locatorType, locator, inDocument, inWindow) {\n        var locatorFunction = this.locationStrategies[locatorType];\n        if (! locatorFunction) {\n            throw new SeleniumError(\"Unrecognised locator type: '\" + locatorType + \"'\");\n        }\n        return locatorFunction.call(this, locator, inDocument, inWindow);\n    };\n\n    /**\n     * The implicit locator, that is used when no prefix is supplied.\n     */\n    this.locationStrategies['implicit'] = function(locator, inDocument, inWindow) {\n        if (locator.startsWith('//')) {\n            return this.locateElementByXPath(locator, inDocument, inWindow);\n        }\n        if (locator.startsWith('document.')) {\n            return this.locateElementByDomTraversal(locator, inDocument, inWindow);\n        }\n        return this.locateElementByIdentifier(locator, inDocument, inWindow);\n    };\n}\n\nBrowserBot.prototype.getDocument = function() {\n    return this.getCurrentWindow().document;\n}\n\nBrowserBot.prototype.getTitle = function() {\n    var t = this.getDocument().title;\n    if (typeof(t) == \"string\") {\n        t = t.trim();\n    }\n    return t;\n}\n\nBrowserBot.prototype.getCookieByName = function(cookieName, doc) {\n    if (!doc) doc = this.getDocument();\n    var ck = doc.cookie;\n    if (!ck) return null;\n    var ckPairs = ck.split(/;/);\n    for (var i = 0; i < ckPairs.length; i++) {\n        var ckPair = ckPairs[i].trim();\n        var ckNameValue = ckPair.split(/=/);\n        var ckName = decodeURIComponent(ckNameValue[0]);\n        if (ckName === cookieName) {\n            return decodeURIComponent(ckNameValue[1]);\n        }\n    }\n    return null;\n}\n\nBrowserBot.prototype.getAllCookieNames = function(doc) {\n    if (!doc) doc = this.getDocument();\n    var ck = doc.cookie;\n    if (!ck) return [];\n    var cookieNames = [];\n    var ckPairs = ck.split(/;/);\n    for (var i = 0; i < ckPairs.length; i++) {\n        var ckPair = ckPairs[i].trim();\n        var ckNameValue = ckPair.split(/=/);\n        var ckName = decodeURIComponent(ckNameValue[0]);\n        cookieNames.push(ckName);\n    }\n    return cookieNames;\n}\n\nBrowserBot.prototype.deleteCookie = function(cookieName, domain, path, doc) {\n    if (!doc) doc = this.getDocument();\n    var expireDateInMilliseconds = (new Date()).getTime() + (-1 * 1000);\n    var cookie = cookieName + \"=deleted; \";\n    if (path) {\n        cookie += \"path=\" + path + \"; \";\n    }\n    if (domain) {\n        cookie += \"domain=\" + domain + \"; \";\n    }\n    cookie += \"expires=\" + new Date(expireDateInMilliseconds).toGMTString();\n    LOG.debug(\"Setting cookie to: \" + cookie);\n    doc.cookie = cookie;\n}\n\n/** Try to delete cookie, return false if it didn't work */\nBrowserBot.prototype._maybeDeleteCookie = function(cookieName, domain, path, doc) {\n    this.deleteCookie(cookieName, domain, path, doc);\n    return (!this.getCookieByName(cookieName, doc));\n}\n    \n\nBrowserBot.prototype._recursivelyDeleteCookieDomains = function(cookieName, domain, path, doc) {\n    var deleted = this._maybeDeleteCookie(cookieName, domain, path, doc);\n    if (deleted) return true;\n    var dotIndex = domain.indexOf(\".\");\n    if (dotIndex == 0) {\n        return this._recursivelyDeleteCookieDomains(cookieName, domain.substring(1), path, doc);\n    } else if (dotIndex != -1) {\n        return this._recursivelyDeleteCookieDomains(cookieName, domain.substring(dotIndex), path, doc);\n    } else {\n        // No more dots; try just not passing in a domain at all\n        return this._maybeDeleteCookie(cookieName, null, path, doc);\n    }\n}\n\nBrowserBot.prototype._recursivelyDeleteCookie = function(cookieName, domain, path, doc) {\n    var slashIndex = path.lastIndexOf(\"/\");\n    var finalIndex = path.length-1;\n    if (slashIndex == finalIndex) {\n        slashIndex--;\n    }\n    if (slashIndex != -1) {\n        deleted = this._recursivelyDeleteCookie(cookieName, domain, path.substring(0, slashIndex+1), doc);\n        if (deleted) return true;\n    }\n    return this._recursivelyDeleteCookieDomains(cookieName, domain, path, doc);\n}\n\nBrowserBot.prototype.recursivelyDeleteCookie = function(cookieName, domain, path, win) {\n    if (!win) win = this.getCurrentWindow();\n    var doc = win.document;\n    if (!domain) {\n        domain = doc.domain;\n    }\n    if (!path) {\n        path = win.location.pathname;\n    }\n    var deleted = this._recursivelyDeleteCookie(cookieName, \".\" + domain, path, doc);\n    if (deleted) return;\n    // Finally try a null path (Try it last because it's uncommon)\n    deleted = this._recursivelyDeleteCookieDomains(cookieName, \".\" + domain, null, doc);\n    if (deleted) return;\n    throw new SeleniumError(\"Couldn't delete cookie \" + cookieName);\n}\n\n/*\n * Finds an element recursively in frames and nested frames\n * in the specified document, using various lookup protocols\n */\nBrowserBot.prototype.findElementRecursive = function(locatorType, locatorString, inDocument, inWindow) {\n\n    var element = this.findElementBy(locatorType, locatorString, inDocument, inWindow);\n    if (element != null) {\n        return element;\n    }\n\n    for (var i = 0; i < inWindow.frames.length; i++) {\n        // On some browsers, the document object is undefined for third-party\n        // frames.  Make sure the document is valid before continuing.\n        if (inWindow.frames[i].document) {\n            element = this.findElementRecursive(locatorType, locatorString, inWindow.frames[i].document, inWindow.frames[i]);\n\n            if (element != null) {\n                return element;\n            }\n        }\n    }\n};\n\n/*\n* Finds an element on the current page, using various lookup protocols\n*/\nBrowserBot.prototype.findElementOrNull = function(locator, win) {\n    locator = parse_locator(locator);\n\n    if (win == null) {\n        win = this.getCurrentWindow();\n    }\n    var element = this.findElementRecursive(locator.type, locator.string, win.document, win);\n\n    if (element != null) {\n        return this.browserbot.highlight(element);\n    }\n\n    // Element was not found by any locator function.\n    return null;\n};\n\nBrowserBot.prototype.findElement = function(locator, win) {\n    var element = this.findElementOrNull(locator, win);\n    if (element == null) throw new SeleniumError(\"Element \" + locator + \" not found\");\n    return element;\n}\n\n/**\n * In non-IE browsers, getElementById() does not search by name.  Instead, we\n * we search separately by id and name.\n */\nBrowserBot.prototype.locateElementByIdentifier = function(identifier, inDocument, inWindow) {\n    return BrowserBot.prototype.locateElementById(identifier, inDocument, inWindow)\n            || BrowserBot.prototype.locateElementByName(identifier, inDocument, inWindow)\n            || null;\n};\n\n/**\n * Find the element with id - can't rely on getElementById, coz it returns by name as well in IE..\n */\nBrowserBot.prototype.locateElementById = function(identifier, inDocument, inWindow) {\n    var element = inDocument.getElementById(identifier);\n    if (element && element.getAttribute('id') === identifier) {\n        return element;\n    }\n    else if (browserVersion.isIE || browserVersion.isOpera) {\n        // SEL-484\n        var xpath = '/descendant::*[@id=' + identifier.quoteForXPath() + ']';\n        return BrowserBot.prototype\n            .locateElementByXPath(xpath, inDocument, inWindow);\n    }\n    else {\n        return null;\n    }\n};\n\n/**\n * Find an element by name, refined by (optional) element-filter\n * expressions.\n */\nBrowserBot.prototype.locateElementByName = function(locator, document, inWindow) {\n    var elements = document.getElementsByTagName(\"*\");\n\n    var filters = locator.split(' ');\n    filters[0] = 'name=' + filters[0];\n\n    while (filters.length) {\n        var filter = filters.shift();\n        elements = this.selectElements(filter, elements, 'value');\n    }\n\n    if (elements.length > 0) {\n        return elements[0];\n    }\n    return null;\n};\n\n/**\n * Finds an element using by evaluating the specfied string.\n */\nBrowserBot.prototype.locateElementByDomTraversal = function(domTraversal, document, window) {\n\n    var browserbot = this.browserbot;\n    var element = null;\n    try {\n        element = eval(domTraversal);\n    } catch (e) {\n        return null;\n    }\n\n    if (!element) {\n        return null;\n    }\n\n    return element;\n};\nBrowserBot.prototype.locateElementByDomTraversal.prefix = \"dom\";\n\n/**\n * Finds an element identified by the xpath expression. Expressions _must_\n * begin with \"//\".\n */\nBrowserBot.prototype.locateElementByXPath = function(xpath, inDocument, inWindow) {\n    var results = eval_xpath(xpath, inDocument, {\n        returnOnFirstMatch          : true,\n        ignoreAttributesWithoutValue: this.ignoreAttributesWithoutValue,\n        allowNativeXpath            : this.allowNativeXpath,\n        xpathLibrary                : this.xpathLibrary,\n        namespaceResolver           : this._namespaceResolver\n    });\n    return (results.length > 0) ? results[0] : null;\n};\n\nBrowserBot.prototype._namespaceResolver = function(prefix) {\n    if (prefix == 'html' || prefix == 'xhtml' || prefix == 'x') {\n        return 'http://www.w3.org/1999/xhtml';\n    } else if (prefix == 'mathml') {\n        return 'http://www.w3.org/1998/Math/MathML';\n    } else {\n        throw new Error(\"Unknown namespace: \" + prefix + \".\");\n    }\n}\n\n/**\n * Returns the number of xpath results.\n */\nBrowserBot.prototype.evaluateXPathCount = function(xpath, inDocument) {\n    var results = eval_xpath(xpath, inDocument, {\n        ignoreAttributesWithoutValue: this.ignoreAttributesWithoutValue,\n        allowNativeXpath            : this.allowNativeXpath,\n        xpathLibrary                : this.xpathLibrary,\n        namespaceResolver           : this._namespaceResolver\n    });\n    return results.length;\n};\n\n/**\n * Finds a link element with text matching the expression supplied. Expressions must\n * begin with \"link:\".\n */\nBrowserBot.prototype.locateElementByLinkText = function(linkText, inDocument, inWindow) {\n    var links = inDocument.getElementsByTagName('a');\n    for (var i = 0; i < links.length; i++) {\n        var element = links[i];\n        if (PatternMatcher.matches(linkText, getText(element))) {\n            return element;\n        }\n    }\n    return null;\n};\nBrowserBot.prototype.locateElementByLinkText.prefix = \"link\";\n\n/**\n * Returns an attribute based on an attribute locator. This is made up of an element locator\n * suffixed with @attribute-name.\n */\nBrowserBot.prototype.findAttribute = function(locator) {\n    // Split into locator + attributeName\n    var attributePos = locator.lastIndexOf(\"@\");\n    var elementLocator = locator.slice(0, attributePos);\n    var attributeName = locator.slice(attributePos + 1);\n\n    // Find the element.\n    var element = this.findElement(elementLocator);\n\n    // Handle missing \"class\" attribute in IE.\n    if (browserVersion.isIE && attributeName == \"class\") {\n        attributeName = \"className\";\n    }\n\n    // Get the attribute value.\n    var attributeValue = element.getAttribute(attributeName);\n    \n    // IE returns an object for the \"style\" attribute\n    if (attributeName == 'style' && typeof(attributeValue) != 'string') {\n        attributeValue = attributeValue.cssText;\n    }\n\n    return attributeValue ? attributeValue.toString() : null;\n};\n\n/*\n* Select the specified option and trigger the relevant events of the element.\n*/\nBrowserBot.prototype.selectOption = function(element, optionToSelect) {\n    triggerEvent(element, 'focus', false);\n    var changed = false;\n    for (var i = 0; i < element.options.length; i++) {\n        var option = element.options[i];\n        if (option.selected && option != optionToSelect) {\n            option.selected = false;\n            changed = true;\n        }\n        else if (!option.selected && option == optionToSelect) {\n            option.selected = true;\n            changed = true;\n        }\n    }\n\n    if (changed) {\n        triggerEvent(element, 'change', true);\n    }\n};\n\n/*\n* Select the specified option and trigger the relevant events of the element.\n*/\nBrowserBot.prototype.addSelection = function(element, option) {\n    this.checkMultiselect(element);\n    triggerEvent(element, 'focus', false);\n    if (!option.selected) {\n        option.selected = true;\n        triggerEvent(element, 'change', true);\n    }\n};\n\n/*\n* Select the specified option and trigger the relevant events of the element.\n*/\nBrowserBot.prototype.removeSelection = function(element, option) {\n    this.checkMultiselect(element);\n    triggerEvent(element, 'focus', false);\n    if (option.selected) {\n        option.selected = false;\n        triggerEvent(element, 'change', true);\n    }\n};\n\nBrowserBot.prototype.checkMultiselect = function(element) {\n    if (!element.multiple)\n    {\n        throw new SeleniumError(\"Not a multi-select\");\n    }\n\n};\n\nBrowserBot.prototype.replaceText = function(element, stringValue) {\n    triggerEvent(element, 'focus', false);\n    triggerEvent(element, 'select', true);\n    var maxLengthAttr = element.getAttribute(\"maxLength\");\n    var actualValue = stringValue;\n    if (maxLengthAttr != null) {\n        var maxLength = parseInt(maxLengthAttr);\n        if (stringValue.length > maxLength) {\n            actualValue = stringValue.substr(0, maxLength);\n        }\n    }\n\n    if (getTagName(element) == \"body\") {\n        if (element.ownerDocument && element.ownerDocument.designMode) {\n            var designMode = new String(element.ownerDocument.designMode).toLowerCase();\n            if (designMode = \"on\") {\n                // this must be a rich text control!\n                element.innerHTML = actualValue;\n            }\n        }\n    } else {\n        element.value = actualValue;\n    }\n    // DGF this used to be skipped in chrome URLs, but no longer.  Is xpcnativewrappers to blame?\n    try {\n        triggerEvent(element, 'change', true);\n    } catch (e) {}\n};\n\nBrowserBot.prototype.submit = function(formElement) {\n    var actuallySubmit = true;\n    this._modifyElementTarget(formElement);\n    if (formElement.onsubmit) {\n        if (browserVersion.isHTA) {\n            // run the code in the correct window so alerts are handled correctly even in HTA mode\n            var win = this.browserbot.getCurrentWindow();\n            var now = new Date().getTime();\n            var marker = 'marker' + now;\n            win[marker] = formElement;\n            win.setTimeout(\"var actuallySubmit = \"+marker+\".onsubmit();\" +\n                \"if (actuallySubmit) { \" +\n                    marker+\".submit(); \" +\n                    \"if (\"+marker+\".target && !/^_/.test(\"+marker+\".target)) {\"+\n                        \"window.open('', \"+marker+\".target);\"+\n                    \"}\"+\n                \"};\"+\n                marker+\"=null\", 0);\n            // pause for up to 2s while this command runs\n            var terminationCondition = function () {\n                return !win[marker];\n            }\n            return Selenium.decorateFunctionWithTimeout(terminationCondition, 2000);\n        } else {\n            actuallySubmit = formElement.onsubmit();\n            if (actuallySubmit) {\n                formElement.submit();\n                if (formElement.target && !/^_/.test(formElement.target)) {\n                    this.browserbot.openWindow('', formElement.target);\n                }\n            }\n        }\n    } else {\n        formElement.submit();\n    }\n}\n\nBrowserBot.prototype.clickElement = function(element, clientX, clientY) {\n       this._fireEventOnElement(\"click\", element, clientX, clientY);\n};\n\nBrowserBot.prototype.doubleClickElement = function(element, clientX, clientY) {\n       this._fireEventOnElement(\"dblclick\", element, clientX, clientY);\n};\n\n// The contextmenu event is fired when the user right-clicks to open the context menu\nBrowserBot.prototype.contextMenuOnElement = function(element, clientX, clientY) {\n       this._fireEventOnElement(\"contextmenu\", element, clientX, clientY);\n};\n\nBrowserBot.prototype._modifyElementTarget = function(element) {\n    if (element.target) {\n        if (element.target == \"_blank\" || /^selenium_blank/.test(element.target) ) {\n            var tagName = getTagName(element);\n            if (tagName == \"a\" || tagName == \"form\") {\n                var newTarget = \"selenium_blank\" + Math.round(100000 * Math.random());\n                LOG.warn(\"Link has target '_blank', which is not supported in Selenium!  Randomizing target to be: \" + newTarget);\n                this.browserbot.openWindow('', newTarget);\n                element.target = newTarget;\n            }\n        }\n    }\n}\n\n\nBrowserBot.prototype._handleClickingImagesInsideLinks = function(targetWindow, element) {\n    var itrElement = element;\n    while (itrElement != null) {\n        if (itrElement.href) {\n            targetWindow.location.href = itrElement.href;\n            break;\n        }\n        itrElement = itrElement.parentNode;\n    }\n}\n\nBrowserBot.prototype._getTargetWindow = function(element) {\n    var targetWindow = element.ownerDocument.defaultView;\n    if (element.target) {\n        targetWindow = this._getFrameFromGlobal(element.target);\n    }\n    return targetWindow;\n}\n\nBrowserBot.prototype._getFrameFromGlobal = function(target) {\n\n    if (target == \"_self\") {\n        return this.getCurrentWindow();\n    }\n    if (target == \"_top\") {\n        return this.topFrame;\n    } else if (target == \"_parent\") {\n        return this.getCurrentWindow().parent;\n    } else if (target == \"_blank\") {\n        // TODO should this set cleverer window defaults?\n        return this.getCurrentWindow().open('', '_blank');\n    }\n    var frameElement = this.findElementBy(\"implicit\", target, this.topFrame.document, this.topFrame);\n    if (frameElement) {\n        return frameElement.contentWindow;\n    }\n    var win = this.getWindowByName(target);\n    if (win) return win;\n    return this.getCurrentWindow().open('', target);\n}\n\n\nBrowserBot.prototype.bodyText = function() {\n    if (!this.getDocument().body) {\n        throw new SeleniumError(\"Couldn't access document.body.  Is this HTML page fully loaded?\");\n    }\n    return getText(this.getDocument().body);\n};\n\nBrowserBot.prototype.getAllButtons = function() {\n    var elements = this.getDocument().getElementsByTagName('input');\n    var result = [];\n\n    for (var i = 0; i < elements.length; i++) {\n        if (elements[i].type == 'button' || elements[i].type == 'submit' || elements[i].type == 'reset') {\n            result.push(elements[i].id);\n        }\n    }\n\n    return result;\n};\n\n\nBrowserBot.prototype.getAllFields = function() {\n    var elements = this.getDocument().getElementsByTagName('input');\n    var result = [];\n\n    for (var i = 0; i < elements.length; i++) {\n        if (elements[i].type == 'text') {\n            result.push(elements[i].id);\n        }\n    }\n\n    return result;\n};\n\nBrowserBot.prototype.getAllLinks = function() {\n    var elements = this.getDocument().getElementsByTagName('a');\n    var result = [];\n\n    for (var i = 0; i < elements.length; i++) {\n        result.push(elements[i].id);\n    }\n\n    return result;\n};\n\nfunction isDefined(value) {\n    return typeof(value) != undefined;\n}\n\nBrowserBot.prototype.goBack = function() {\n    this.getCurrentWindow().history.back();\n};\n\nBrowserBot.prototype.goForward = function() {\n    this.getCurrentWindow().history.forward();\n};\n\nBrowserBot.prototype.close = function() {\n    if (browserVersion.isIE) {\n        // fix \"do you want to close this window\" warning in IE\n        // You can only close windows that you have opened.\n        // So, let's \"open\" it.\n        try {\n            this.topFrame.name=new Date().getTime();\n            window.open(\"\", this.topFrame.name, \"\");\n            this.topFrame.close();\n            return;\n        } catch (e) {}\n    }\n    if (browserVersion.isChrome || browserVersion.isSafari || browserVersion.isOpera) {\n        this.topFrame.close();\n    } else {\n        this.getCurrentWindow().eval(\"window.top.close();\");\n    }\n};\n\nBrowserBot.prototype.refresh = function() {\n    this.getCurrentWindow().location.reload(true);\n};\n\n/**\n * Refine a list of elements using a filter.\n */\nBrowserBot.prototype.selectElementsBy = function(filterType, filter, elements) {\n    var filterFunction = BrowserBot.filterFunctions[filterType];\n    if (! filterFunction) {\n        throw new SeleniumError(\"Unrecognised element-filter type: '\" + filterType + \"'\");\n    }\n\n    return filterFunction(filter, elements);\n};\n\nBrowserBot.filterFunctions = {};\n\nBrowserBot.filterFunctions.name = function(name, elements) {\n    var selectedElements = [];\n    for (var i = 0; i < elements.length; i++) {\n        if (elements[i].name === name) {\n            selectedElements.push(elements[i]);\n        }\n    }\n    return selectedElements;\n};\n\nBrowserBot.filterFunctions.value = function(value, elements) {\n    var selectedElements = [];\n    for (var i = 0; i < elements.length; i++) {\n        if (elements[i].value === value) {\n            selectedElements.push(elements[i]);\n        }\n    }\n    return selectedElements;\n};\n\nBrowserBot.filterFunctions.index = function(index, elements) {\n    index = Number(index);\n    if (isNaN(index) || index < 0) {\n        throw new SeleniumError(\"Illegal Index: \" + index);\n    }\n    if (elements.length <= index) {\n        throw new SeleniumError(\"Index out of range: \" + index);\n    }\n    return [elements[index]];\n};\n\nBrowserBot.prototype.selectElements = function(filterExpr, elements, defaultFilterType) {\n\n    var filterType = (defaultFilterType || 'value');\n\n    // If there is a filter prefix, use the specified strategy\n    var result = filterExpr.match(/^([A-Za-z]+)=(.+)/);\n    if (result) {\n        filterType = result[1].toLowerCase();\n        filterExpr = result[2];\n    }\n\n    return this.selectElementsBy(filterType, filterExpr, elements);\n};\n\n/**\n * Find an element by class\n */\nBrowserBot.prototype.locateElementByClass = function(locator, document) {\n    return elementFindFirstMatchingChild(document,\n            function(element) {\n                return element.className == locator\n            }\n            );\n}\n\n/**\n * Find an element by alt\n */\nBrowserBot.prototype.locateElementByAlt = function(locator, document) {\n    return elementFindFirstMatchingChild(document,\n            function(element) {\n                return element.alt == locator\n            }\n            );\n}\n\n/**\n * Find an element by css selector\n */\nBrowserBot.prototype.locateElementByCss = function(locator, document) {\n    var elements = eval_css(locator, document);\n    if (elements.length != 0)\n        return elements[0];\n    return null;\n}\n\n/**\n * This function is responsible for mapping a UI specifier string to an element\n * on the page, and returning it. If no element is found, null is returned.\n * Returning null on failure to locate the element is part of the undocumented\n * API for locator strategies.\n */\nBrowserBot.prototype.locateElementByUIElement = function(locator, inDocument) {\n    // offset locators are delimited by \"->\", which is much simpler than the\n    // previous scheme involving detecting the close-paren.\n    var locators = locator.split(/->/, 2);\n    \n    var locatedElement = null;\n    var pageElements = UIMap.getInstance()\n        .getPageElements(locators[0], inDocument);\n    \n    if (locators.length > 1) {\n        for (var i = 0; i < pageElements.length; ++i) {\n            var locatedElements = eval_locator(locators[1], inDocument,\n                pageElements[i]);\n            if (locatedElements.length) {\n                locatedElement = locatedElements[0];\n                break;\n            }\n        }\n    }\n    else if (pageElements.length) {\n        locatedElement = pageElements[0];\n    }\n    \n    return locatedElement;\n}\n\nBrowserBot.prototype.locateElementByUIElement.prefix = 'ui';\n\n// define a function used to compare the result of a close UI element\n// match with the actual interacted element. If they are close enough\n// according to the heuristic, consider them a match.\n/**\n * A heuristic function for comparing a node with a target node. Typically the\n * node is specified in a UI element definition, while the target node is\n * returned by the recorder as the leaf element which had some event enacted\n * upon it. This particular heuristic covers the case where the anchor element\n * contains other inline tags, such as \"em\" or \"img\".\n *\n * @param node    the node being compared to the target node\n * @param target  the target node\n * @return        true if node equals target, or if node is a link\n *                element and target is its descendant, or if node has\n *                an onclick attribute and target is its descendant.\n *                False otherwise.\n */\nBrowserBot.prototype.locateElementByUIElement.is_fuzzy_match = function(node, target) {\n    try {\n        var isMatch = (\n            (node == target) ||\n            ((node.nodeName == 'A' || node.onclick) && is_ancestor(node, target))\n        );\n        return isMatch;\n    }\n    catch (e) {\n        return false;\n    }\n};\n\n/*****************************************************************/\n/* BROWSER-SPECIFIC FUNCTIONS ONLY AFTER THIS LINE */\n\nfunction MozillaBrowserBot(frame) {\n    BrowserBot.call(this, frame);\n}\nobjectExtend(MozillaBrowserBot.prototype, BrowserBot.prototype);\n\nfunction KonquerorBrowserBot(frame) {\n    BrowserBot.call(this, frame);\n}\nobjectExtend(KonquerorBrowserBot.prototype, BrowserBot.prototype);\n\nKonquerorBrowserBot.prototype.setIFrameLocation = function(iframe, location) {\n    // Window doesn't fire onload event when setting src to the current value,\n    // so we set it to blank first.\n    iframe.src = \"about:blank\";\n    iframe.src = location;\n};\n\nKonquerorBrowserBot.prototype.setOpenLocation = function(win, loc) {\n    // Window doesn't fire onload event when setting src to the current value,\n    // so we just refresh in that case instead.\n    loc = absolutify(loc, this.baseUrl);\n    loc = canonicalize(loc);\n    var startUrl = win.location.href;\n    if (\"about:blank\" != win.location.href) {\n        var startLoc = parseUrl(win.location.href);\n        startLoc.hash = null;\n        var startUrl = reassembleLocation(startLoc);\n    }\n    LOG.debug(\"startUrl=\"+startUrl);\n    LOG.debug(\"win.location.href=\"+win.location.href);\n    LOG.debug(\"loc=\"+loc);\n    if (startUrl == loc) {\n        LOG.debug(\"opening exact same location\");\n        this.refresh();\n    } else {\n        LOG.debug(\"locations differ\");\n        win.location.href = loc;\n    }\n    // force the current polling thread to detect a page load\n    var marker = this.isPollingForLoad(win);\n    if (marker) {\n        delete win.location[marker];\n    }\n};\n\nKonquerorBrowserBot.prototype._isSameDocument = function(originalDocument, currentDocument) {\n    // under Konqueror, there may be this case:\n    // originalDocument and currentDocument are different objects\n    // while their location are same.\n    if (originalDocument) {\n        return originalDocument.location == currentDocument.location\n    } else {\n        return originalDocument === currentDocument;\n    }\n};\n\nfunction SafariBrowserBot(frame) {\n    BrowserBot.call(this, frame);\n}\nobjectExtend(SafariBrowserBot.prototype, BrowserBot.prototype);\n\nSafariBrowserBot.prototype.setIFrameLocation = KonquerorBrowserBot.prototype.setIFrameLocation;\nSafariBrowserBot.prototype.setOpenLocation = KonquerorBrowserBot.prototype.setOpenLocation;\n\n\nfunction OperaBrowserBot(frame) {\n    BrowserBot.call(this, frame);\n}\nobjectExtend(OperaBrowserBot.prototype, BrowserBot.prototype);\nOperaBrowserBot.prototype.setIFrameLocation = function(iframe, location) {\n    if (iframe.src == location) {\n        iframe.src = location + '?reload';\n    } else {\n        iframe.src = location;\n    }\n}\n\nfunction IEBrowserBot(frame) {\n    BrowserBot.call(this, frame);\n}\nobjectExtend(IEBrowserBot.prototype, BrowserBot.prototype);\n\nIEBrowserBot.prototype._handleClosedSubFrame = function(testWindow, doNotModify) {\n    if (this.proxyInjectionMode) {\n        return testWindow;\n    }\n\n    try {\n        testWindow.location.href;\n        this.permDenied = 0;\n    } catch (e) {\n        this.permDenied++;\n    }\n    if (this._windowClosed(testWindow) || this.permDenied > 4) {\n        if (this.isSubFrameSelected) {\n            LOG.warn(\"Current subframe appears to have closed; selecting top frame\");\n            this.selectFrame(\"relative=top\");\n            return this.getCurrentWindow(doNotModify);\n        } else {\n            var closedError = new SeleniumError(\"Current window or frame is closed!\");\n            closedError.windowClosed = true;\n            throw closedError;\n        }\n    }\n    return testWindow;\n};\n\nIEBrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {\n    BrowserBot.prototype.modifyWindowToRecordPopUpDialogs(windowToModify, browserBot);\n\n    // we will call the previous version of this method from within our own interception\n    oldShowModalDialog = windowToModify.showModalDialog;\n\n    windowToModify.showModalDialog = function(url, args, features) {\n        // Get relative directory to where TestRunner.html lives\n        // A risky assumption is that the user's TestRunner is named TestRunner.html\n        var doc_location = document.location.toString();\n        var end_of_base_ref = doc_location.indexOf('TestRunner.html');\n        var base_ref = doc_location.substring(0, end_of_base_ref);\n        var runInterval = '';\n        \n        // Only set run interval if options is defined\n        if (typeof(window.runOptions) != 'undefined') {\n            runInterval = \"&runInterval=\" + runOptions.runInterval;\n        }\n            \n        var testRunnerURL = \"TestRunner.html?auto=true&singletest=\" \n            + escape(browserBot.modalDialogTest)\n            + \"&autoURL=\" \n            + escape(url) \n            + runInterval;\n        var fullURL = base_ref + testRunnerURL;\n        browserBot.modalDialogTest = null;\n\n        // If using proxy injection mode\n        if (this.proxyInjectionMode) {\n            var sessionId = runOptions.getSessionId();\n            if (sessionId == undefined) {\n                sessionId = injectedSessionId;\n            }\n            if (sessionId != undefined) {\n                LOG.debug(\"Invoking showModalDialog and injecting URL \" + fullURL);\n            }\n            fullURL = url;\n        }\n        var returnValue = oldShowModalDialog(fullURL, args, features);\n        return returnValue;\n    };\n};\n\nIEBrowserBot.prototype.modifySeparateTestWindowToDetectPageLoads = function(windowObject) {\n    this.pageUnloading = false;\n    var self = this;\n    var pageUnloadDetector = function() {\n        self.pageUnloading = true;\n    };\n    windowObject.attachEvent(\"onbeforeunload\", pageUnloadDetector);\n    BrowserBot.prototype.modifySeparateTestWindowToDetectPageLoads.call(this, windowObject);\n};\n\nIEBrowserBot.prototype.pollForLoad = function(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker) {\n    LOG.debug(\"IEBrowserBot.pollForLoad: \" + marker);\n    if (!this.permDeniedCount[marker]) this.permDeniedCount[marker] = 0;\n    BrowserBot.prototype.pollForLoad.call(this, loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);\n    if (this.pageLoadError) {\n        if (this.pageUnloading) {\n            var self = this;\n            LOG.debug(\"pollForLoad UNLOADING (\" + marker + \"): caught exception while firing events on unloading page: \" + this.pageLoadError.message);\n            this.reschedulePoller(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);\n            this.pageLoadError = null;\n            return;\n        } else if (((this.pageLoadError.message == \"Permission denied\") || (/^Access is denied/.test(this.pageLoadError.message)))\n                && this.permDeniedCount[marker]++ < 8) {\n            if (this.permDeniedCount[marker] > 4) {\n                var canAccessThisWindow;\n                var canAccessCurrentlySelectedWindow;\n                try {\n                    windowObject.location.href;\n                    canAccessThisWindow = true;\n                } catch (e) {}\n                try {\n                    this.getCurrentWindow(true).location.href;\n                    canAccessCurrentlySelectedWindow = true;\n                } catch (e) {}\n                if (canAccessCurrentlySelectedWindow & !canAccessThisWindow) {\n                    LOG.debug(\"pollForLoad (\" + marker + \") ABORTING: \" + this.pageLoadError.message + \" (\" + this.permDeniedCount[marker] + \"), but the currently selected window is fine\");\n                    // returning without rescheduling\n                    this.pageLoadError = null;\n                    return;\n                }\n            }\n\n            var self = this;\n            LOG.debug(\"pollForLoad (\" + marker + \"): \" + this.pageLoadError.message + \" (\" + this.permDeniedCount[marker] + \"), waiting to see if it goes away\");\n            this.reschedulePoller(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);\n            this.pageLoadError = null;\n            return;\n        }\n        //handy for debugging!\n        //throw this.pageLoadError;\n    }\n};\n\nIEBrowserBot.prototype._windowClosed = function(win) {\n    try {\n        var c = win.closed;\n        // frame windows claim to be non-closed when their parents are closed\n        // but you can't access their document objects in that case\n        if (!c) {\n            try {\n                win.document;\n            } catch (de) {\n                if (de.message == \"Permission denied\") {\n                    // the window is probably unloading, which means it's probably not closed yet\n                    return false;\n                }\n                else if (/^Access is denied/.test(de.message)) {\n                    // rare variation on \"Permission denied\"?\n                    LOG.debug(\"IEBrowserBot.windowClosed: got \" + de.message + \" (this.pageUnloading=\" + this.pageUnloading + \"); assuming window is unloading, probably not closed yet\");\n                    return false;\n                } else {\n                    // this is probably one of those frame window situations\n                    LOG.debug(\"IEBrowserBot.windowClosed: couldn't read win.document, assume closed: \" + de.message + \" (this.pageUnloading=\" + this.pageUnloading + \")\");\n                    return true;\n                }\n            }\n        }\n        if (c == null) {\n            LOG.debug(\"IEBrowserBot.windowClosed: win.closed was null, assuming closed\");\n            return true;\n        }\n        return c;\n    } catch (e) {\n        LOG.debug(\"IEBrowserBot._windowClosed: Got an exception trying to read win.closed; we'll have to take a guess!\");\n\n        if (browserVersion.isHTA) {\n            if (e.message == \"Permission denied\") {\n                // the window is probably unloading, which means it's not closed yet\n                return false;\n            } else {\n                // there's a good chance that we've lost contact with the window object if it is closed\n                return true;\n            }\n        } else {\n            // the window is probably unloading, which means it's not closed yet\n            return false;\n        }\n    }\n};\n\n/**\n * In IE, getElementById() also searches by name - this is an optimisation for IE.\n */\nIEBrowserBot.prototype.locateElementByIdentifer = function(identifier, inDocument, inWindow) {\n    return inDocument.getElementById(identifier);\n};\n\nSafariBrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {\n    BrowserBot.prototype.modifyWindowToRecordPopUpDialogs(windowToModify, browserBot);\n\n    var originalOpen = windowToModify.open;\n    /*\n     * Safari seems to be broken, so that when we manually trigger the onclick method\n     * of a button/href, any window.open calls aren't resolved relative to the app location.\n     * So here we replace the open() method with one that does resolve the url correctly.\n     */\n    windowToModify.open = function(url, windowName, windowFeatures, replaceFlag) {\n\n        if (url.startsWith(\"http://\") || url.startsWith(\"https://\") || url.startsWith(\"/\")) {\n            return originalOpen(url, windowName, windowFeatures, replaceFlag);\n        }\n\n        // Reduce the current path to the directory\n        var currentPath = windowToModify.location.pathname || \"/\";\n        currentPath = currentPath.replace(/\\/[^\\/]*$/, \"/\");\n\n        // Remove any leading \"./\" from the new url.\n        url = url.replace(/^\\.\\//, \"\");\n\n        newUrl = currentPath + url;\n\n        var openedWindow = originalOpen(newUrl, windowName, windowFeatures, replaceFlag);\n        LOG.debug(\"window.open call intercepted; window ID (which you can use with selectWindow()) is \\\"\" +  windowName + \"\\\"\");\n        if (windowName!=null) {\n            openedWindow[\"seleniumWindowName\"] = windowName;\n        }\n        return openedWindow;\n    };\n};\n\nMozillaBrowserBot.prototype._fireEventOnElement = function(eventType, element, clientX, clientY) {\n    var win = this.getCurrentWindow();\n    triggerEvent(element, 'focus', false);\n\n    // Add an event listener that detects if the default action has been prevented.\n    // (This is caused by a javascript onclick handler returning false)\n    // we capture the whole event, rather than the getPreventDefault() state at the time,\n    // because we need to let the entire event bubbling and capturing to go through\n    // before making a decision on whether we should force the href\n    var savedEvent = null;\n\n    element.addEventListener(eventType, function(evt) {\n        savedEvent = evt;\n    }, false);\n\n    this._modifyElementTarget(element);\n\n    // Trigger the event.\n    this.browserbot.triggerMouseEvent(element, eventType, true, clientX, clientY);\n\n    if (this._windowClosed(win)) {\n        return;\n    }\n\n    // Perform the link action if preventDefault was set.\n    // In chrome URL, the link action is already executed by triggerMouseEvent.\n    if (!browserVersion.isChrome && savedEvent != null && !savedEvent.getPreventDefault()) {\n        var targetWindow = this.browserbot._getTargetWindow(element);\n        if (element.href) {\n            targetWindow.location.href = element.href;\n        } else {\n            this.browserbot._handleClickingImagesInsideLinks(targetWindow, element);\n        }\n    }\n\n};\n\n\nOperaBrowserBot.prototype._fireEventOnElement = function(eventType, element, clientX, clientY) {\n    var win = this.getCurrentWindow();\n    triggerEvent(element, 'focus', false);\n\n    this._modifyElementTarget(element);\n\n    // Trigger the click event.\n    this.browserbot.triggerMouseEvent(element, eventType, true, clientX, clientY);\n\n    if (this._windowClosed(win)) {\n        return;\n    }\n\n};\n\n\nKonquerorBrowserBot.prototype._fireEventOnElement = function(eventType, element, clientX, clientY) {\n    var win = this.getCurrentWindow();\n    triggerEvent(element, 'focus', false);\n\n    this._modifyElementTarget(element);\n\n    if (element[eventType]) {\n        element[eventType]();\n    }\n    else {\n        this.browserbot.triggerMouseEvent(element, eventType, true, clientX, clientY);\n    }\n\n    if (this._windowClosed(win)) {\n        return;\n    }\n\n};\n\nSafariBrowserBot.prototype._fireEventOnElement = function(eventType, element, clientX, clientY) {\n    triggerEvent(element, 'focus', false);\n    var wasChecked = element.checked;\n\n    this._modifyElementTarget(element);\n\n    // For form element it is simple.\n    if (element[eventType]) {\n        element[eventType]();\n    }\n    // For links and other elements, event emulation is required.\n    else {\n        var targetWindow = this.browserbot._getTargetWindow(element);\n        // todo: deal with anchors?\n        this.browserbot.triggerMouseEvent(element, eventType, true, clientX, clientY);\n\n    }\n\n};\n\nSafariBrowserBot.prototype.refresh = function() {\n    var win = this.getCurrentWindow();\n    if (win.location.hash) {\n        // DGF Safari refuses to refresh when there's a hash symbol in the URL\n        win.location.hash = \"\";\n        var actuallyReload = function() {\n            win.location.reload(true);\n        }\n        window.setTimeout(actuallyReload, 1);\n    } else {\n        win.location.reload(true);\n    }\n};\n\nIEBrowserBot.prototype._fireEventOnElement = function(eventType, element, clientX, clientY) {\n    var win = this.getCurrentWindow();\n    triggerEvent(element, 'focus', false);\n\n    var wasChecked = element.checked;\n\n    // Set a flag that records if the page will unload - this isn't always accurate, because\n    // <a href=\"javascript:alert('foo'):\"> triggers the onbeforeunload event, even thought the page won't unload\n    var pageUnloading = false;\n    var pageUnloadDetector = function() {\n        pageUnloading = true;\n    };\n    win.attachEvent(\"onbeforeunload\", pageUnloadDetector);\n    this._modifyElementTarget(element);\n    if (element[eventType]) {\n        element[eventType]();\n    }\n    else {\n        this.browserbot.triggerMouseEvent(element, eventType, true, clientX, clientY);\n    }\n\n\n    // If the page is going to unload - still attempt to fire any subsequent events.\n    // However, we can't guarantee that the page won't unload half way through, so we need to handle exceptions.\n    try {\n        win.detachEvent(\"onbeforeunload\", pageUnloadDetector);\n\n        if (this._windowClosed(win)) {\n            return;\n        }\n\n        // Onchange event is not triggered automatically in IE.\n        if (isDefined(element.checked) && wasChecked != element.checked) {\n            triggerEvent(element, 'change', true);\n        }\n\n    }\n    catch (e) {\n        // If the page is unloading, we may get a \"Permission denied\" or \"Unspecified error\".\n        // Just ignore it, because the document may have unloaded.\n        if (pageUnloading) {\n            LOG.logHook = function() {\n            };\n            LOG.warn(\"Caught exception when firing events on unloading page: \" + e.message);\n            return;\n        }\n        throw e;\n    }\n};\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-browserdetect.js",
    "content": "/*\n * Copyright 2004 ThoughtWorks, Inc\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n */\n\n// Although it's generally better web development practice not to use\n// browser-detection (feature detection is better), the subtle browser\n// differences that Selenium has to work around seem to make it\n// necessary. Maybe as we learn more about what we need, we can do this in\n// a more \"feature-centric\" rather than \"browser-centric\" way.\n\nvar BrowserVersion = function() {\n    this.name = navigator.appName;\n\n    if (navigator.userAgent.indexOf('Mac OS X') != -1) {\n        this.isOSX = true;\n    }\n\n    if (navigator.userAgent.indexOf('Windows NT 6') != -1) {\n        this.isVista = true;\n    }\n\n    if (window.opera != null) {\n        this.browser = BrowserVersion.OPERA;\n        this.isOpera = true;\n        return;\n    }\n    \n    var _getQueryParameter = function(searchKey) {\n        var str = location.search.substr(1);\n        if (str == null) return null;\n        var clauses = str.split('&');\n        for (var i = 0; i < clauses.length; i++) {\n            var keyValuePair = clauses[i].split('=', 2);\n            var key = unescape(keyValuePair[0]);\n            if (key == searchKey) {\n                return unescape(keyValuePair[1]);\n            }\n        }\n        return null;\n    };\n    \n    var self = this;\n    \n    var checkChrome = function() {\n        var loc = window.document.location.href;\n        try {\n            loc = window.top.document.location.href;\n            if (/^chrome:\\/\\//.test(loc)) {\n                self.isChrome = true;\n            } else {\n                self.isChrome = false;\n            }\n        } catch (e) {\n            // can't see the top (that means we might be chrome, but it's impossible to be sure)\n            self.isChromeDetectable = \"no, top location couldn't be read in this window\";\n            if (_getQueryParameter('thisIsChrome')) {\n                self.isChrome = true;\n            } else {\n                self.isChrome = false;\n            }\n        }\n        \n        \n    }\n    \n    \n\n    if (this.name == \"Microsoft Internet Explorer\") {\n        this.browser = BrowserVersion.IE;\n        this.isIE = true;\n        try {\n            if (window.top.SeleniumHTARunner && window.top.document.location.pathname.match(/.hta$/i)) {\n                this.isHTA = true;\n            }\n        } catch (e) {\n            this.isHTADetectable = \"no, top location couldn't be read in this window\";\n            if (_getQueryParameter('thisIsHTA')) {\n                self.isHTA = true;\n            } else {\n                self.isHTA = false;\n            }\n        }\n        if (navigator.appVersion.match(/MSIE 6.0/)) {\n        \tthis.isIE6 = true;\n        }\n        if (\"0\" == navigator.appMinorVersion) {\n            this.preSV1 = true;\n            if (this.isIE6) {\n            \tthis.appearsToBeBrokenInitialIE6 = true;\n            }\n        }\n        return;\n    }\n\n    if (navigator.userAgent.indexOf('Safari') != -1) {\n        this.browser = BrowserVersion.SAFARI;\n        this.isSafari = true;\n        this.khtml = true;\n        return;\n    }\n\n    if (navigator.userAgent.indexOf('Konqueror') != -1) {\n        this.browser = BrowserVersion.KONQUEROR;\n        this.isKonqueror = true;\n        this.khtml = true;\n        return;\n    }\n\n    if (navigator.userAgent.indexOf('Firefox') != -1) {\n        this.browser = BrowserVersion.FIREFOX;\n        this.isFirefox = true;\n        this.isGecko = true;\n        var result = /.*Firefox\\/([\\d\\.]+).*/.exec(navigator.userAgent);\n        if (result) {\n            this.firefoxVersion = result[1];\n        }\n        checkChrome();\n        return;\n    }\n\n    if (navigator.userAgent.indexOf('Gecko') != -1) {\n        this.browser = BrowserVersion.MOZILLA;\n        this.isMozilla = true;\n        this.isGecko = true;\n        checkChrome();\n        return;\n    }\n\n    this.browser = BrowserVersion.UNKNOWN;\n}\n\nBrowserVersion.OPERA = \"Opera\";\nBrowserVersion.IE = \"IE\";\nBrowserVersion.KONQUEROR = \"Konqueror\";\nBrowserVersion.SAFARI = \"Safari\";\nBrowserVersion.FIREFOX = \"Firefox\";\nBrowserVersion.MOZILLA = \"Mozilla\";\nBrowserVersion.UNKNOWN = \"Unknown\";\n\nvar browserVersion = new BrowserVersion();\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-commandhandlers.js",
    "content": "/*\n* Copyright 2004 ThoughtWorks, Inc\n*\n*  Licensed under the Apache License, Version 2.0 (the \"License\");\n*  you may not use this file except in compliance with the License.\n*  You may obtain a copy of the License at\n*\n*      http://www.apache.org/licenses/LICENSE-2.0\n*\n*  Unless required by applicable law or agreed to in writing, software\n*  distributed under the License is distributed on an \"AS IS\" BASIS,\n*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*  See the License for the specific language governing permissions and\n*  limitations under the License.\n*/\n\n// A naming convention used in this file:\n//\n//\n//   - a \"seleniumApi\" is an instance of the Selenium object, defined in selenium-api.js.\n//\n//   - a \"Method\" is an unbound function whose target must be supplied when it's called, ie.\n//     it should be invoked using Function.call() or Function.apply()\n//\n//   - a \"Block\" is a function that has been bound to a target object, so can be called invoked directly\n//     (or with a null target)\n//\n//   - \"CommandHandler\" is effectively an abstract base for\n//     various handlers including ActionHandler, AccessorHandler and AssertHandler.\n//     Subclasses need to implement an execute(seleniumApi, command) function,\n//     where seleniumApi is the Selenium object, and command a SeleniumCommand object.\n//\n//   - Handlers will return a \"result\" object (ActionResult, AccessorResult, AssertResult).\n//     ActionResults may contain a .terminationCondition function which is run by \n//     -executionloop.js after the command is run; we'll run it over and over again\n//     until it returns true or the .terminationCondition throws an exception.\n//     AccessorResults will contain the results of running getter (e.g. getTitle returns\n//     the title as a string).\n\nvar CommandHandlerFactory = classCreate();\nobjectExtend(CommandHandlerFactory.prototype, {\n\n    initialize: function() {\n        this.handlers = {};\n    },\n\n    registerAction: function(name, actionBlock, wait, dontCheckAlertsAndConfirms) {\n        this.handlers[name] = new ActionHandler(actionBlock, wait, dontCheckAlertsAndConfirms);\n    },\n\n    registerAccessor: function(name, accessBlock) {\n        this.handlers[name] = new AccessorHandler(accessBlock);\n    },\n\n    registerAssert: function(name, assertBlock, haltOnFailure) {\n        this.handlers[name] = new AssertHandler(assertBlock, haltOnFailure);\n    },\n\n    getCommandHandler: function(name) {\n        return this.handlers[name];\n    },\n\n    _registerAllAccessors: function(seleniumApi) {\n        // Methods of the form getFoo(target) result in commands:\n        // getFoo, assertFoo, verifyFoo, assertNotFoo, verifyNotFoo\n        // storeFoo, waitForFoo, and waitForNotFoo.\n        for (var functionName in seleniumApi) {\n            var match = /^(get|is)([A-Z].+)$/.exec(functionName);\n            if (match) {\n                var accessMethod = seleniumApi[functionName];\n                var accessBlock = fnBind(accessMethod, seleniumApi);\n                var baseName = match[2];\n                var isBoolean = (match[1] == \"is\");\n                var requiresTarget = (accessMethod.length == 1);\n\n                this.registerAccessor(functionName, accessBlock);\n                this._registerStoreCommandForAccessor(baseName, accessBlock, requiresTarget);\n\n                var predicateBlock = this._predicateForAccessor(accessBlock, requiresTarget, isBoolean);\n                this._registerAssertionsForPredicate(baseName, predicateBlock);\n                this._registerWaitForCommandsForPredicate(seleniumApi, baseName, predicateBlock);\n            }\n        }\n    },\n\n    _registerAllActions: function(seleniumApi) {\n        for (var functionName in seleniumApi) {\n            var match = /^do([A-Z].+)$/.exec(functionName);\n            if (match) {\n                var actionName = match[1].lcfirst();\n                var actionMethod = seleniumApi[functionName];\n                var dontCheckPopups = actionMethod.dontCheckAlertsAndConfirms;\n                var actionBlock = fnBind(actionMethod, seleniumApi);\n                this.registerAction(actionName, actionBlock, false, dontCheckPopups);\n                this.registerAction(actionName + \"AndWait\", actionBlock, true, dontCheckPopups);\n            }\n        }\n    },\n\n    _registerAllAsserts: function(seleniumApi) {\n        for (var functionName in seleniumApi) {\n            var match = /^assert([A-Z].+)$/.exec(functionName);\n            if (match) {\n                var assertBlock = fnBind(seleniumApi[functionName], seleniumApi);\n\n                // Register the assert with the \"assert\" prefix, and halt on failure.\n                var assertName = functionName;\n                this.registerAssert(assertName, assertBlock, true);\n\n                // Register the assert with the \"verify\" prefix, and do not halt on failure.\n                var verifyName = \"verify\" + match[1];\n                this.registerAssert(verifyName, assertBlock, false);\n            }\n        }\n    },\n\n    registerAll: function(seleniumApi) {\n        this._registerAllAccessors(seleniumApi);\n        this._registerAllActions(seleniumApi);\n        this._registerAllAsserts(seleniumApi);\n    },\n\n    _predicateForAccessor: function(accessBlock, requiresTarget, isBoolean) {\n        if (isBoolean) {\n            return this._predicateForBooleanAccessor(accessBlock);\n        }\n        if (requiresTarget) {\n            return this._predicateForSingleArgAccessor(accessBlock);\n        }\n        return this._predicateForNoArgAccessor(accessBlock);\n    },\n\n    _predicateForSingleArgAccessor: function(accessBlock) {\n        // Given an accessor function getBlah(target),\n        // return a \"predicate\" equivalient to isBlah(target, value) that\n        // is true when the value returned by the accessor matches the specified value.\n        return function(target, value) {\n            var accessorResult = accessBlock(target);\n            accessorResult = selArrayToString(accessorResult);\n            if (PatternMatcher.matches(value, accessorResult)) {\n                return new PredicateResult(true, \"Actual value '\" + accessorResult + \"' did match '\" + value + \"'\");\n            } else {\n                return new PredicateResult(false, \"Actual value '\" + accessorResult + \"' did not match '\" + value + \"'\");\n            }\n        };\n    },\n\n    _predicateForNoArgAccessor: function(accessBlock) {\n        // Given a (no-arg) accessor function getBlah(),\n        // return a \"predicate\" equivalient to isBlah(value) that\n        // is true when the value returned by the accessor matches the specified value.\n        return function(value) {\n            var accessorResult = accessBlock();\n            accessorResult = selArrayToString(accessorResult);\n            if (PatternMatcher.matches(value, accessorResult)) {\n                return new PredicateResult(true, \"Actual value '\" + accessorResult + \"' did match '\" + value + \"'\");\n            } else {\n                return new PredicateResult(false, \"Actual value '\" + accessorResult + \"' did not match '\" + value + \"'\");\n            }\n        };\n    },\n\n    _predicateForBooleanAccessor: function(accessBlock) {\n        // Given a boolean accessor function isBlah(),\n        // return a \"predicate\" equivalient to isBlah() that\n        // returns an appropriate PredicateResult value.\n        return function() {\n            var accessorResult;\n            if (arguments.length > 2) throw new SeleniumError(\"Too many arguments! \" + arguments.length);\n            if (arguments.length == 2) {\n                accessorResult = accessBlock(arguments[0], arguments[1]);\n            } else if (arguments.length == 1) {\n                accessorResult = accessBlock(arguments[0]);\n            } else {\n                accessorResult = accessBlock();\n            }\n            if (accessorResult) {\n                return new PredicateResult(true, \"true\");\n            } else {\n                return new PredicateResult(false, \"false\");\n            }\n        };\n    },\n\n    _invertPredicate: function(predicateBlock) {\n        // Given a predicate, return the negation of that predicate.\n        // Leaves the message unchanged.\n        // Used to create assertNot, verifyNot, and waitForNot commands.\n        return function(target, value) {\n            var result = predicateBlock(target, value);\n            result.isTrue = !result.isTrue;\n            return result;\n        };\n    },\n\n    createAssertionFromPredicate: function(predicateBlock) {\n        // Convert an isBlahBlah(target, value) function into an assertBlahBlah(target, value) function.\n        return function(target, value) {\n            var result = predicateBlock(target, value);\n            if (!result.isTrue) {\n                Assert.fail(result.message);\n            }\n        };\n    },\n\n    _invertPredicateName: function(baseName) {\n        var matchResult = /^(.*)Present$/.exec(baseName);\n        if (matchResult != null) {\n            return matchResult[1] + \"NotPresent\";\n        }\n        return \"Not\" + baseName;\n    },\n\n    _registerAssertionsForPredicate: function(baseName, predicateBlock) {\n        // Register an assertion, a verification, a negative assertion,\n        // and a negative verification based on the specified accessor.\n        var assertBlock = this.createAssertionFromPredicate(predicateBlock);\n        this.registerAssert(\"assert\" + baseName, assertBlock, true);\n        this.registerAssert(\"verify\" + baseName, assertBlock, false);\n\n        var invertedPredicateBlock = this._invertPredicate(predicateBlock);\n        var negativeassertBlock = this.createAssertionFromPredicate(invertedPredicateBlock);\n        this.registerAssert(\"assert\" + this._invertPredicateName(baseName), negativeassertBlock, true);\n        this.registerAssert(\"verify\" + this._invertPredicateName(baseName), negativeassertBlock, false);\n    },\n\n    _waitForActionForPredicate: function(predicateBlock) {\n        // Convert an isBlahBlah(target, value) function into a waitForBlahBlah(target, value) function.\n        return function(target, value) {\n            var terminationCondition = function () {\n                try {\n                    return predicateBlock(target, value).isTrue;\n                } catch (e) {\n                    // Treat exceptions as meaning the condition is not yet met.\n                    // Useful, for example, for waitForValue when the element has\n                    // not even been created yet.\n                    // TODO: possibly should rethrow some types of exception.\n                    return false;\n                }\n            };\n            return Selenium.decorateFunctionWithTimeout(terminationCondition, this.defaultTimeout);\n        };\n    },\n\n    _registerWaitForCommandsForPredicate: function(seleniumApi, baseName, predicateBlock) {\n        // Register a waitForBlahBlah and waitForNotBlahBlah based on the specified accessor.\n        var waitForActionMethod = this._waitForActionForPredicate(predicateBlock);\n        var waitForActionBlock = fnBind(waitForActionMethod, seleniumApi);\n        \n        var invertedPredicateBlock = this._invertPredicate(predicateBlock);\n        var waitForNotActionMethod = this._waitForActionForPredicate(invertedPredicateBlock);\n        var waitForNotActionBlock = fnBind(waitForNotActionMethod, seleniumApi);\n        \n        this.registerAction(\"waitFor\" + baseName, waitForActionBlock, false, true);\n        this.registerAction(\"waitFor\" + this._invertPredicateName(baseName), waitForNotActionBlock, false, true);\n        //TODO decide remove \"waitForNot.*Present\" action name or not\n        //for the back compatiblity issues we still make waitForNot.*Present availble\n        this.registerAction(\"waitForNot\" + baseName, waitForNotActionBlock, false, true);\n    },\n\n    _registerStoreCommandForAccessor: function(baseName, accessBlock, requiresTarget) {\n        var action;\n        if (requiresTarget) {\n            action = function(target, varName) {\n                storedVars[varName] = accessBlock(target);\n            };\n        } else {\n            action = function(varName) {\n                storedVars[varName] = accessBlock();\n            };\n        }\n        this.registerAction(\"store\" + baseName, action, false, true);\n    }\n\n});\n\nfunction PredicateResult(isTrue, message) {\n    this.isTrue = isTrue;\n    this.message = message;\n}\n\n// NOTE: The CommandHandler is effectively an abstract base for\n// various handlers including ActionHandler, AccessorHandler and AssertHandler.\n// Subclasses need to implement an execute(seleniumApi, command) function,\n// where seleniumApi is the Selenium object, and command a SeleniumCommand object.\nfunction CommandHandler(type, haltOnFailure) {\n    this.type = type;\n    this.haltOnFailure = haltOnFailure;\n}\n\n// An ActionHandler is a command handler that executes the sepcified action,\n// possibly checking for alerts and confirmations (if checkAlerts is set), and\n// possibly waiting for a page load if wait is set.\nfunction ActionHandler(actionBlock, wait, dontCheckAlerts) {\n    this.actionBlock = actionBlock;\n    CommandHandler.call(this, \"action\", true);\n    if (wait) {\n        this.wait = true;\n    }\n    // note that dontCheckAlerts could be undefined!!!\n    this.checkAlerts = (dontCheckAlerts) ? false : true;\n}\nActionHandler.prototype = new CommandHandler;\nActionHandler.prototype.execute = function(seleniumApi, command) {\n    if (this.checkAlerts && (null == /(Alert|Confirmation)(Not)?Present/.exec(command.command))) {\n        // todo: this conditional logic is ugly\n        seleniumApi.ensureNoUnhandledPopups();\n    }\n    var terminationCondition = this.actionBlock(command.target, command.value);\n    // If the handler didn't return a wait flag, check to see if the\n    // handler was registered with the wait flag.\n    if (terminationCondition == undefined && this.wait) {\n        terminationCondition = seleniumApi.makePageLoadCondition();\n    }\n    return new ActionResult(terminationCondition);\n};\n\nfunction ActionResult(terminationCondition) {\n    this.terminationCondition = terminationCondition;\n}\n\nfunction AccessorHandler(accessBlock) {\n    this.accessBlock = accessBlock;\n    CommandHandler.call(this, \"accessor\", true);\n}\nAccessorHandler.prototype = new CommandHandler;\nAccessorHandler.prototype.execute = function(seleniumApi, command) {\n    var returnValue = this.accessBlock(command.target, command.value);\n    return new AccessorResult(returnValue);\n};\n\nfunction AccessorResult(result) {\n    this.result = result;\n}\n\n/**\n * Handler for assertions and verifications.\n */\nfunction AssertHandler(assertBlock, haltOnFailure) {\n    this.assertBlock = assertBlock;\n    CommandHandler.call(this, \"assert\", haltOnFailure || false);\n}\nAssertHandler.prototype = new CommandHandler;\nAssertHandler.prototype.execute = function(seleniumApi, command) {\n    var result = new AssertResult();\n    try {\n        this.assertBlock(command.target, command.value);\n    } catch (e) {\n        // If this is not a AssertionFailedError, or we should haltOnFailure, rethrow.\n        if (!e.isAssertionFailedError) {\n            throw e;\n        }\n        if (this.haltOnFailure) {\n            var error = new SeleniumError(e.failureMessage);\n            throw error;\n        }\n        result.setFailed(e.failureMessage);\n    }\n    return result;\n};\n\nfunction AssertResult() {\n    this.passed = true;\n}\nAssertResult.prototype.setFailed = function(message) {\n    this.passed = null;\n    this.failed = true;\n    this.failureMessage = message;\n}\n\nfunction SeleniumCommand(command, target, value, isBreakpoint) {\n    this.command = command;\n    this.target = target;\n    this.value = value;\n    this.isBreakpoint = isBreakpoint;\n}\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-executionloop.js",
    "content": "/*\n* Copyright 2004 ThoughtWorks, Inc\n*\n*  Licensed under the Apache License, Version 2.0 (the \"License\");\n*  you may not use this file except in compliance with the License.\n*  You may obtain a copy of the License at\n*\n*      http://www.apache.org/licenses/LICENSE-2.0\n*\n*  Unless required by applicable law or agreed to in writing, software\n*  distributed under the License is distributed on an \"AS IS\" BASIS,\n*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*  See the License for the specific language governing permissions and\n*  limitations under the License.\n*/\n\nfunction TestLoop(commandFactory) {\n    this.commandFactory = commandFactory;\n}\n\nTestLoop.prototype = {\n\n    start : function() {\n        selenium.reset();\n        LOG.debug(\"currentTest.start()\");\n        this.continueTest();\n    },\n\n    continueTest : function() {\n        /**\n         * Select the next command and continue the test.\n         */\n        LOG.debug(\"currentTest.continueTest() - acquire the next command\");\n        if (! this.aborted) {\n            this.currentCommand = this.nextCommand();\n        }\n        if (! this.requiresCallBack) {\n            this.continueTestAtCurrentCommand();\n        } // otherwise, just finish and let the callback invoke continueTestAtCurrentCommand()\n    },\n\n    continueTestAtCurrentCommand : function() {\n        LOG.debug(\"currentTest.continueTestAtCurrentCommand()\");\n        if (this.currentCommand) {\n            // TODO: rename commandStarted to commandSelected, OR roll it into nextCommand\n            this.commandStarted(this.currentCommand);\n            this._resumeAfterDelay();\n        } else {\n            this._testComplete();\n        }\n    },\n\n    _resumeAfterDelay : function() {\n        /**\n         * Pause, then execute the current command.\n         */\n\n        // Get the command delay. If a pauseInterval is set, use it once\n        // and reset it.  Otherwise, use the defined command-interval.\n        var delay = this.pauseInterval || this.getCommandInterval();\n        this.pauseInterval = undefined;\n\n        if (this.currentCommand.isBreakpoint || delay < 0) {\n            // Pause: enable the \"next/continue\" button\n            this.pause();\n        } else {\n            window.setTimeout(fnBind(this.resume, this), delay);\n        }\n    },\n\n    resume: function() {\n        /**\n         * Select the next command and continue the test.\n         */\n        LOG.debug(\"currentTest.resume() - actually execute\");\n        try {\n            selenium.browserbot.runScheduledPollers();\n            this._executeCurrentCommand();\n            this.continueTestWhenConditionIsTrue();\n        } catch (e) {\n            if (!this._handleCommandError(e)) {\n                this.testComplete();\n            } else {\n                this.continueTest();\n            }\n        }\n    },\n\n    _testComplete : function() {\n        selenium.ensureNoUnhandledPopups();\n        this.testComplete();\n    },\n\n    _executeCurrentCommand : function() {\n        /**\n         * Execute the current command.\n         *\n         * @return a function which will be used to determine when\n         * execution can continue, or null if we can continue immediately\n         */\n        var command = this.currentCommand;\n        LOG.info(\"Executing: |\" + command.command + \" | \" + command.target + \" | \" + command.value + \" |\");\n\n        var handler = this.commandFactory.getCommandHandler(command.command);\n        if (handler == null) {\n            throw new SeleniumError(\"Unknown command: '\" + command.command + \"'\");\n        }\n\n        command.target = selenium.preprocessParameter(command.target);\n        command.value = selenium.preprocessParameter(command.value);\n        LOG.debug(\"Command found, going to execute \" + command.command);\n        this.result = handler.execute(selenium, command);\n        \n\n        this.waitForCondition = this.result.terminationCondition;\n\n    },\n\n    _handleCommandError : function(e) {\n        if (!e.isSeleniumError) {\n            LOG.exception(e);\n            var msg = \"Command execution failure. Please search the forum at http://clearspace.openqa.org for error details from the log window.\";\n            msg += \"  The error message is: \" + extractExceptionMessage(e);\n            return this.commandError(msg);\n        } else {\n            LOG.error(e.message);\n            return this.commandError(e.message);\n        }\n    },\n\n    continueTestWhenConditionIsTrue: function () {\n        /**\n         * Busy wait for waitForCondition() to become true, and then carry\n         * on with test.  Fail the current test if there's a timeout or an\n         * exception.\n         */\n        //LOG.debug(\"currentTest.continueTestWhenConditionIsTrue()\");\n        selenium.browserbot.runScheduledPollers();\n        try {\n            if (this.waitForCondition == null) {\n                LOG.debug(\"null condition; let's continueTest()\");\n                LOG.debug(\"Command complete\");\n                this.commandComplete(this.result);\n                this.continueTest();\n            } else if (this.waitForCondition()) {\n                LOG.debug(\"condition satisfied; let's continueTest()\");\n                this.waitForCondition = null;\n                LOG.debug(\"Command complete\");\n                this.commandComplete(this.result);\n                this.continueTest();\n            } else {\n                //LOG.debug(\"waitForCondition was false; keep waiting!\");\n                window.setTimeout(fnBind(this.continueTestWhenConditionIsTrue, this), 10);\n            }\n        } catch (e) {\n            this.result = {};\n            this.result.failed = true;\n            this.result.failureMessage = extractExceptionMessage(e);\n            this.commandComplete(this.result);\n            this.continueTest();\n        }\n    },\n\n    pause : function() {},\n    nextCommand : function() {},\n    commandStarted : function() {},\n    commandComplete : function() {},\n    commandError : function() {},\n    testComplete : function() {},\n\n    getCommandInterval : function() {\n        return 0;\n    }\n\n}\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-logging.js",
    "content": "/*\n * Copyright 2004 ThoughtWorks, Inc\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\nvar Logger = function() {\n    this.logWindow = null;\n}\nLogger.prototype = {\n\n    logLevels: {\n        debug: 0,\n        info: 1,\n        warn: 2,\n        error: 3,\n        off: 999\n    },\n\n    pendingMessages: new Array(),\n    \n    threshold: \"info\",\n\n    setLogLevelThreshold: function(logLevel) {\n        this.threshold = logLevel;\n        var logWindow = this.getLogWindow()\n        if (logWindow && logWindow.setThresholdLevel) {\n            logWindow.setThresholdLevel(logLevel);\n        }\n        // NOTE: log messages will be discarded until the log window is\n        // fully loaded.\n    },\n\n    getLogWindow: function() {\n        if (this.logWindow && this.logWindow.closed) {\n            this.logWindow = null;\n        }\n        return this.logWindow;\n    },\n    \n    openLogWindow: function() {\n        this.logWindow = window.open(\n            getDocumentBase(document) + \"SeleniumLog.html?startingThreshold=\"+this.threshold, \"SeleniumLog\",\n            \"width=600,height=1000,bottom=0,right=0,status,scrollbars,resizable\"\n        );\n        this.logWindow.moveTo(window.screenX + 1210, window.screenY + window.outerHeight - 1400);\n        if (browserVersion.appearsToBeBrokenInitialIE6) {\n\t// I would really prefer for the message to immediately appear in the log window, the instant the user requests that the log window be \n        \t// visible.  But when I initially coded it this way, thou message simply didn't appear unless I stepped through the code with a debugger.  \n        \t// So obviously there is some timing issue here which I don't have the patience to figure out.\n        \tvar pendingMessage = new LogMessage(\"warn\", \"You appear to be running an unpatched IE 6, which is not stable and can crash due to memory problems.  We recommend you run Windows update to install a more stable version of IE.\");\n            this.pendingMessages.push(pendingMessage);\n        }\n        return this.logWindow;\n    },\n    \n    show: function() {\n        if (! this.getLogWindow()) {\n            this.openLogWindow();\n        }\n        setTimeout(function(){LOG.error(\"Log window displayed.  Logging events will now be recorded to this window.\");}, 500);\n    },\n\n    logHook: function(logLevel, message) {\n    },\n\n    log: function(logLevel, message) {\n        if (this.logLevels[logLevel] < this.logLevels[this.threshold]) {\n            return;\n        }\n        this.logHook(logLevel, message);\n        var logWindow = this.getLogWindow();\n        if (logWindow) {\n            if (logWindow.append) {\n                if (logWindow.disabled) {\n                    logWindow.callBack = fnBind(this.setLogLevelThreshold, this);\n                    logWindow.enableButtons();\n                }\n                if (this.pendingMessages.length > 0) {\n                    logWindow.append(\"info(\"+(new Date().getTime())+\"): Appending missed logging messages\", \"info\");\n                    while (this.pendingMessages.length > 0) {\n                        var msg = this.pendingMessages.shift();\n                        logWindow.append(msg.type + \"(\"+msg.timestamp+\"): \" + msg.msg, msg.type);\n                    }\n                    logWindow.append(\"info(\"+(new Date().getTime())+\"): Done appending missed logging messages\", \"info\");\n                }\n                logWindow.append(logLevel + \"(\"+(new Date().getTime())+\"): \" + message, logLevel);\n            }\n        } else {\n            // TODO these logging messages are never flushed, which creates \n            //   an enormous array of strings that never stops growing.\n            //   there should at least be a way to clear the messages!\n            this.pendingMessages.push(new LogMessage(logLevel, message));\n        }\n    },\n\n    close: function(message) {\n        if (this.logWindow != null) {\n            try {\n                this.logWindow.close();\n            } catch (e) {\n                // swallow exception\n                // the window is probably closed if we get an exception here\n            }\n            this.logWindow = null;\n        }\n    },\n\n    debug: function(message) {\n       this.log(\"debug\", message);\n    },\n\n    info: function(message) {\n       this.log(\"info\", message);\n    },\n\n    warn: function(message) {\n       this.log(\"warn\", message);\n    },\n\n    error: function(message) {\n       this.log(\"error\", message);\n    },\n\n    exception: function(exception) {\n        this.error(\"Unexpected Exception: \" + extractExceptionMessage(exception));\n        this.error(\"Exception details: \" + describe(exception, ', '));\n    }\n\n};\n\nvar LOG = new Logger();\n\nvar LogMessage = function(type, msg) {\n    this.type = type;\n    this.msg = msg;\n    this.timestamp = (new Date().getTime());\n}\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-remoterunner.js",
    "content": "/*\n* Copyright 2005 ThoughtWorks, Inc\n*\n*  Licensed under the Apache License, Version 2.0 (the \"License\");\n*  you may not use this file except in compliance with the License.\n*  You may obtain a copy of the License at\n*\n*      http://www.apache.org/licenses/LICENSE-2.0\n*\n*  Unless required by applicable law or agreed to in writing, software\n*  distributed under the License is distributed on an \"AS IS\" BASIS,\n*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*  See the License for the specific language governing permissions and\n*  limitations under the License.\n*\n*/\n\npassColor = \"#cfffcf\";\nfailColor = \"#ffcfcf\";\nerrorColor = \"#ffffff\";\nworkingColor = \"#DEE7EC\";\ndoneColor = \"#FFFFCC\";\n\nvar injectedSessionId;\n\nvar postResult = \"START\";\nvar debugMode = false;\nvar relayToRC = null;\nvar proxyInjectionMode = false;\nvar uniqueId = 'sel_' + Math.round(100000 * Math.random());\nvar seleniumSequenceNumber = 0;\nvar cmd8 = \"\";\nvar cmd7 = \"\";\nvar cmd6 = \"\";\nvar cmd5 = \"\";\nvar cmd4 = \"\";\nvar cmd3 = \"\";\nvar cmd2 = \"\";\nvar cmd1 = \"\";\nvar lastCmd = \"\";\nvar lastCmdTime = new Date();\n\nvar RemoteRunnerOptions = classCreate();\nobjectExtend(RemoteRunnerOptions.prototype, URLConfiguration.prototype);\nobjectExtend(RemoteRunnerOptions.prototype, {\n    initialize: function() {\n        this._acquireQueryString();\n    },\n    isDebugMode: function() {\n        return this._isQueryParameterTrue(\"debugMode\");\n    },\n\n    getContinue: function() {\n        return this._getQueryParameter(\"continue\");\n    },\n\n    getDriverUrl: function() {\n        return this._getQueryParameter(\"driverUrl\");\n    },\n\n    // requires per-session extension Javascript as soon as this Selenium\n    // instance becomes aware of the session identifier\n    getSessionId: function() {\n        var sessionId = this._getQueryParameter(\"sessionId\");\n        requireExtensionJs(sessionId);\n        return sessionId;\n    },\n\n    _acquireQueryString: function () {\n        if (this.queryString) return;\n        if (browserVersion.isHTA) {\n            var args = this._extractArgs();\n            if (args.length < 2) return null;\n            this.queryString = args[1];\n        } else if (proxyInjectionMode) {\n            this.queryString = window.location.search.substr(1);\n        } else {\n            this.queryString = top.location.search.substr(1);\n        }\n    }\n\n});\nvar runOptions;\n\nfunction runSeleniumTest() {\n    runOptions = new RemoteRunnerOptions();\n    var testAppWindow;\n\n    if (runOptions.isMultiWindowMode()) {\n        testAppWindow = openSeparateApplicationWindow('Blank.html', true);\n    } else if (sel$('selenium_myiframe') != null) {\n        var myiframe = sel$('selenium_myiframe');\n        if (myiframe) {\n            testAppWindow = myiframe.contentWindow;\n        }\n    }\n    else {\n        proxyInjectionMode = true;\n        testAppWindow = window;\n    }\n    selenium = Selenium.createForWindow(testAppWindow, proxyInjectionMode);\n    if (runOptions.getBaseUrl()) {\n        selenium.browserbot.baseUrl = runOptions.getBaseUrl();\n    }\n    if (!debugMode) {\n        debugMode = runOptions.isDebugMode();\n    }\n    if (proxyInjectionMode) {\n        LOG.logHook = logToRc;\n        selenium.browserbot._modifyWindow(testAppWindow);\n    }\n    else if (debugMode) {\n        LOG.logHook = logToRc;\n    }\n    window.selenium = selenium;\n\n    commandFactory = new CommandHandlerFactory();\n    commandFactory.registerAll(selenium);\n\n    currentTest = new RemoteRunner(commandFactory);\n\n    var doContinue = runOptions.getContinue();\n    if (doContinue != null) postResult = \"OK\";\n\n    currentTest.start();\n}\n\nfunction buildDriverUrl() {\n    var driverUrl = runOptions.getDriverUrl();\n    if (driverUrl != null) {\n        return driverUrl;\n    }\n    var s = window.location.href\n    var slashPairOffset = s.indexOf(\"//\") + \"//\".length\n    var pathSlashOffset = s.substring(slashPairOffset).indexOf(\"/\")\n    return s.substring(0, slashPairOffset + pathSlashOffset) + \"/selenium-server/driver/\";\n    //return \"http://localhost\" + uniqueId + \"/selenium-server/driver/\";\n}\n\nfunction logToRc(logLevel, message) {\n    if (debugMode) {\n        if (logLevel == null) {\n            logLevel = \"debug\";\n        }\n        sendToRCAndForget(\"logLevel=\" + logLevel + \":\" + message.replace(/[\\n\\r\\015]/g, \" \") + \"\\n\", \"logging=true\");\n    }\n}\n\nfunction serializeString(name, s) {\n    return name + \"=unescape(\\\"\" + escape(s) + \"\\\");\";\n}\n\nfunction serializeObject(name, x)\n{\n    var s = '';\n\n    if (isArray(x))\n    {\n        s = name + \"=new Array(); \";\n        var len = x[\"length\"];\n        for (var j = 0; j < len; j++)\n        {\n            s += serializeString(name + \"[\" + j + \"]\", x[j]);\n        }\n    }\n    else if (typeof x == \"string\")\n    {\n        s = serializeString(name, x);\n    }\n    else\n    {\n        throw \"unrecognized object not encoded: \" + name + \"(\" + x + \")\";\n    }\n    return s;\n}\n\nfunction relayBotToRC(s) {\n}\n\n// seems like no one uses this, but in fact it is called using eval from server-side PI mode code; however,\n// because multiple names can map to the same popup, assigning a single name confuses matters sometimes;\n// thus, I'm disabling this for now.  -Nelson 10/21/06\nfunction setSeleniumWindowName(seleniumWindowName) {\n//selenium.browserbot.getCurrentWindow()['seleniumWindowName'] = seleniumWindowName;\n}\n\nRemoteRunner = classCreate();\nobjectExtend(RemoteRunner.prototype, new TestLoop());\nobjectExtend(RemoteRunner.prototype, {\n    initialize : function(commandFactory) {\n        this.commandFactory = commandFactory;\n        this.requiresCallBack = true;\n        this.commandNode = null;\n        this.xmlHttpForCommandsAndResults = null;\n    },\n\n    nextCommand : function() {\n        var urlParms = \"\";\n        if (postResult == \"START\") {\n            urlParms += \"seleniumStart=true\";\n        }\n        this.xmlHttpForCommandsAndResults = XmlHttp.create();\n        sendToRC(postResult, urlParms, fnBind(this._HandleHttpResponse, this), this.xmlHttpForCommandsAndResults);\n    },\n\n    commandStarted : function(command) {\n        this.commandNode = document.createElement(\"div\");\n        var cmdText = command.command + '(';\n        if (command.target != null && command.target != \"\") {\n            cmdText += command.target;\n            if (command.value != null && command.value != \"\") {\n                cmdText += ', ' + command.value;\n            }\n        }\n        if (cmdText.length > 70) {\n            cmdText = cmdText.substring(0, 70) + \"...\\n\";\n        } else {\n            cmdText += \")\\n\";\n        }\n\n        if (cmdText == lastCmd) {\n\t        var rightNow = new Date();\n\t        var msSinceStart = rightNow.getTime() - lastCmdTime.getTime();\n\t        var sinceStart = msSinceStart + \"ms\";\n\t        if (msSinceStart > 1000) {\n\t\t        sinceStart = Math.round(msSinceStart / 1000) + \"s\";\n\t\t    }\n            cmd1 = \"Same command (\" + sinceStart + \"): \" + lastCmd;\n        } else {\n\t        lastCmdTime = new Date();\n            cmd8 = cmd7;\n            cmd7 = cmd6;\n            cmd6 = cmd5;\n            cmd5 = cmd4;\n            cmd4 = cmd3;\n            cmd3 = cmd2;\n            cmd2 = cmd1;\n            cmd1 = cmdText;\n        }\n        lastCmd = cmdText;\n        \n        if (! proxyInjectionMode) {\n            var commandList = document.commands.commandList;\n            commandList.value = cmd8 + cmd7 + cmd6 + cmd5 + cmd4 + cmd3 + cmd2 + cmd1;\n            commandList.scrollTop = commandList.scrollHeight;\n        }\n    },\n\n    commandComplete : function(result) {\n\n        if (result.failed) {\n            if (postResult == \"CONTINUATION\") {\n                currentTest.aborted = true;\n            }\n            postResult = result.failureMessage;\n            this.commandNode.title = result.failureMessage;\n            this.commandNode.style.backgroundColor = failColor;\n        } else if (result.passed) {\n            postResult = \"OK\";\n            this.commandNode.style.backgroundColor = passColor;\n        } else {\n            if (result.result == null) {\n                postResult = \"OK\";\n            } else {\n                var actualResult = result.result;\n                actualResult = selArrayToString(actualResult);\n                postResult = \"OK,\" + actualResult;\n            }\n            this.commandNode.style.backgroundColor = doneColor;\n        }\n    },\n\n    commandError : function(message) {\n        postResult = \"ERROR: \" + message;\n        this.commandNode.style.backgroundColor = errorColor;\n        this.commandNode.titcle = message;\n    },\n\n    testComplete : function() {\n        window.status = \"Selenium Tests Complete, for this Test\"\n        // Continue checking for new results\n        this.continueTest();\n        postResult = \"START\";\n    },\n\n    _HandleHttpResponse : function() {\n        // When request is completed\n        if (this.xmlHttpForCommandsAndResults.readyState == 4) {\n            // OK\n            if (this.xmlHttpForCommandsAndResults.status == 200) {\n            \tif (this.xmlHttpForCommandsAndResults.responseText==\"\") {\n                    LOG.error(\"saw blank string xmlHttpForCommandsAndResults.responseText\");\n                    return;\n                }\n                var command = this._extractCommand(this.xmlHttpForCommandsAndResults);\n                if (command.command == 'retryLast') {\n                    setTimeout(fnBind(function() {\n                        sendToRC(\"RETRY\", \"retry=true\", fnBind(this._HandleHttpResponse, this), this.xmlHttpForCommandsAndResults, true);\n                    }, this), 1000);\n                } else {\n                    this.currentCommand = command;\n                    this.continueTestAtCurrentCommand();\n                }\n            }\n            // Not OK \n            else {\n                var s = 'xmlHttp returned: ' + this.xmlHttpForCommandsAndResults.status + \": \" + this.xmlHttpForCommandsAndResults.statusText;\n                LOG.error(s);\n                this.currentCommand = null;\n                setTimeout(fnBind(this.continueTestAtCurrentCommand, this), 2000);\n            }\n\n        }\n    },\n\n    _extractCommand : function(xmlHttp) {\n        var command, text, json;\n        text = command = xmlHttp.responseText;\n        if (/^json=/.test(text)) {\n            eval(text);\n            if (json.rest) {\n                eval(json.rest);\n            }\n            return json;\n        }\n        try {\n            var re = new RegExp(\"^(.*?)\\n((.|[\\r\\n])*)\");\n            if (re.exec(xmlHttp.responseText)) {\n                command = RegExp.$1;\n                var rest = RegExp.$2;\n                rest = rest.trim();\n                if (rest) {\n                    eval(rest);\n                }\n            }\n            else {\n                command = xmlHttp.responseText;\n            }\n        } catch (e) {\n            alert('could not get responseText: ' + e.message);\n        }\n        if (command.substr(0, '|testComplete'.length) == '|testComplete') {\n            return null;\n        }\n\n        return this._createCommandFromRequest(command);\n    },\n\n\n    _delay : function(millis) {\n        var startMillis = new Date();\n        while (true) {\n            milli = new Date();\n            if (milli - startMillis > millis) {\n                break;\n            }\n        }\n    },\n\n// Parses a URI query string into a SeleniumCommand object\n    _createCommandFromRequest : function(commandRequest) {\n        //decodeURIComponent doesn't strip plus signs\n        var processed = commandRequest.replace(/\\+/g, \"%20\");\n        // strip trailing spaces\n        var processed = processed.replace(/\\s+$/, \"\");\n        var vars = processed.split(\"&\");\n        var cmdArgs = new Object();\n        for (var i = 0; i < vars.length; i++) {\n            var pair = vars[i].split(\"=\");\n            cmdArgs[pair[0]] = pair[1];\n        }\n        var cmd = cmdArgs['cmd'];\n        var arg1 = cmdArgs['1'];\n        if (null == arg1) arg1 = \"\";\n        arg1 = decodeURIComponent(arg1);\n        var arg2 = cmdArgs['2'];\n        if (null == arg2) arg2 = \"\";\n        arg2 = decodeURIComponent(arg2);\n        if (cmd == null) {\n            throw new Error(\"Bad command request: \" + commandRequest);\n        }\n        return new SeleniumCommand(cmd, arg1, arg2);\n    }\n\n})\n\n\nfunction sendToRC(dataToBePosted, urlParms, callback, xmlHttpObject, async) {\n    if (async == null) {\n        async = true;\n    }\n    if (xmlHttpObject == null) {\n        xmlHttpObject = XmlHttp.create();\n    }\n    var url = buildDriverUrl() + \"?\"\n    if (urlParms) {\n        url += urlParms;\n    }\n    url = addUrlParams(url);\n    url += \"&sequenceNumber=\" + seleniumSequenceNumber++;\n    \n    var postedData = \"postedData=\" + encodeURIComponent(dataToBePosted);\n\n    //xmlHttpObject.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n    xmlHttpObject.open(\"POST\", url, async);\n    if (callback) xmlHttpObject.onreadystatechange = callback;\n    xmlHttpObject.send(postedData);\n    return null;\n}\n\nfunction addUrlParams(url) {\n    return url + \"&localFrameAddress=\" + (proxyInjectionMode ? makeAddressToAUTFrame() : \"top\")\n    + getSeleniumWindowNameURLparameters()\n    + \"&uniqueId=\" + uniqueId\n    + buildDriverParams() + preventBrowserCaching()\n}\n\nfunction sendToRCAndForget(dataToBePosted, urlParams) {\n    var url;\n    if (!(browserVersion.isChrome || browserVersion.isHTA)) { \n        // DGF we're behind a proxy, so we can send our logging message to literally any host, to avoid 2-connection limit\n        var protocol = \"http:\";\n        if (window.location.protocol == \"https:\") {\n            // DGF if we're in HTTPS, use another HTTPS url to avoid security warning\n            protocol = \"https:\";\n        }\n        // we don't choose a super large random value, but rather 1 - 16, because this matches with the pre-computed\n        // tunnels waiting on the Selenium Server side. This gives us higher throughput than the two-connection-per-host\n        // limitation, but doesn't require we generate an extremely large ammount of fake SSL certs either.\n        url = protocol + \"//\" + Math.floor(Math.random()* 16 + 1) + \".selenium.doesnotexist/selenium-server/driver/?\" + urlParams;\n    } else {\n        url = buildDriverUrl() + \"?\" + urlParams;\n    }\n    url = addUrlParams(url);\n    \n    var method = \"GET\";\n    if (method == \"POST\") {\n        // DGF submit a request using an iframe; we can't see the response, but we don't need to\n        // TODO not using this mechanism because it screws up back-button\n        var loggingForm = document.createElement(\"form\");\n        loggingForm.method = \"POST\";\n        loggingForm.action = url;\n        loggingForm.target = \"seleniumLoggingFrame\";\n        var postedDataInput = document.createElement(\"input\");\n        postedDataInput.type = \"hidden\";\n        postedDataInput.name = \"postedData\";\n        postedDataInput.value = dataToBePosted;\n        loggingForm.appendChild(postedDataInput);\n        document.body.appendChild(loggingForm);\n        loggingForm.submit();\n        document.body.removeChild(loggingForm);\n    } else {\n        var postedData = \"&postedData=\" + encodeURIComponent(dataToBePosted);\n        var scriptTag = document.createElement(\"script\");\n        scriptTag.src = url + postedData;\n        document.body.appendChild(scriptTag);\n        document.body.removeChild(scriptTag);\n    }\n}\n\nfunction buildDriverParams() {\n    var params = \"\";\n\n    var sessionId = runOptions.getSessionId();\n    if (sessionId == undefined) {\n        sessionId = injectedSessionId;\n    }\n    if (sessionId != undefined) {\n        params = params + \"&sessionId=\" + sessionId;\n    }\n    return params;\n}\n\nfunction preventBrowserCaching() {\n    var t = (new Date()).getTime();\n    return \"&counterToMakeURsUniqueAndSoStopPageCachingInTheBrowser=\" + t;\n}\n\n//\n// Return URL parameters pertaining to the name(s?) of the current window\n//\n// In selenium, the main (i.e., first) window's name is a blank string.\n//\n// Additional pop-ups are associated with either 1.) the name given by the 2nd parameter to window.open, or 2.) the name of a\n// property on the opening window which points at the window.\n//\n// An example of #2: if window X contains JavaScript as follows:\n//\n// \tvar windowABC = window.open(...)\n//\n// Note that the example JavaScript above is equivalent to\n//\n// \twindow[\"windowABC\"] = window.open(...)\n//\nfunction getSeleniumWindowNameURLparameters() {\n    var w = (proxyInjectionMode ? selenium.browserbot.getCurrentWindow() : window).top;\n    var s = \"&seleniumWindowName=\";\n    if (w.opener == null) {\n        return s;\n    }\n    if (w[\"seleniumWindowName\"] == null) {\n        if (w.name) {\n            w[\"seleniumWindowName\"] = w.name;\n        } else {\n    \t    w[\"seleniumWindowName\"] = 'generatedSeleniumWindowName_' + Math.round(100000 * Math.random());\n    \t}\n    }\n    s += w[\"seleniumWindowName\"];\n    var windowOpener = w.opener;\n    for (key in windowOpener) {\n        var val = null;\n        try {\n    \t    val = windowOpener[key];\n        }\n        catch(e) {\n        }\n        if (val==w) {\n\t    s += \"&jsWindowNameVar=\" + key;\t\t\t// found a js variable in the opener referring to this window\n        }\n    }\n    return s;\n}\n\n// construct a JavaScript expression which leads to my frame (i.e., the frame containing the window\n// in which this code is operating)\nfunction makeAddressToAUTFrame(w, frameNavigationalJSexpression)\n{\n    if (w == null)\n    {\n        w = top;\n        frameNavigationalJSexpression = \"top\";\n    }\n\n    if (w == selenium.browserbot.getCurrentWindow())\n    {\n        return frameNavigationalJSexpression;\n    }\n    for (var j = 0; j < w.frames.length; j++)\n    {\n        var t = makeAddressToAUTFrame(w.frames[j], frameNavigationalJSexpression + \".frames[\" + j + \"]\");\n        if (t != null)\n        {\n            return t;\n        }\n    }\n    return null;\n}\n\nSelenium.prototype.doSetContext = function(context) {\n    /**\n   * Writes a message to the status bar and adds a note to the browser-side\n   * log.\n   *\n   * @param context\n   *            the message to be sent to the browser\n   */\n    //set the current test title\n    var ctx = document.getElementById(\"context\");\n    if (ctx != null) {\n        ctx.innerHTML = context;\n    }\n};\n\n/**\n * Adds a script tag referencing a specially-named user extensions \"file\". The\n * resource handler for this special file (which won't actually exist) will use\n * the session ID embedded in its name to retrieve per-session specified user\n * extension javascript.\n *\n * @param sessionId\n */\nfunction requireExtensionJs(sessionId) {\n    var src = 'scripts/user-extensions.js[' + sessionId + ']';\n    if (document.getElementById(src) == null) {\n        var scriptTag = document.createElement('script');\n        scriptTag.language = 'JavaScript';\n        scriptTag.type = 'text/javascript';\n        scriptTag.src = src;\n        scriptTag.id = src;\n        var headTag = document.getElementsByTagName('head')[0];\n        headTag.appendChild(scriptTag);\n    }\n}\n\nSelenium.prototype.doAttachFile = function(fieldLocator,fileLocator) {\n   /**\n   * Sets a file input (upload) field to the file listed in fileLocator\n   *\n   *  @param fieldLocator an <a href=\"#locators\">element locator</a>\n   *  @param fileLocator a URL pointing to the specified file. Before the file\n   *  can be set in the input field (fieldLocator), Selenium RC may need to transfer the file  \n   *  to the local machine before attaching the file in a web page form. This is common in selenium\n   *  grid configurations where the RC server driving the browser is not the same\n   *  machine that started the test.\n   *\n   *  Supported Browsers: Firefox (\"*chrome\") only.\n   *   \n   */\n   // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us! \n};\n\nSelenium.prototype.doCaptureScreenshot = function(filename) {\n    /**\n    * Captures a PNG screenshot to the specified file.\n    *\n    * @param filename the absolute path to the file to be written, e.g. \"c:\\blah\\screenshot.png\"\n    */\n    // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!\n};\n\nSelenium.prototype.doCaptureScreenshotToString = function() {\n    /**\n    * Capture a PNG screenshot.  It then returns the file as a base 64 encoded string. \n    * \n    * @return string The base 64 encoded string of the screen shot (PNG file)\n    */\n    // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!\n};\n\nSelenium.prototype.doCaptureEntirePageScreenshotToString = function(kwargs) {\n    /**\n    * Downloads a screenshot of the browser current window canvas to a \n    * based 64 encoded PNG file. The <em>entire</em> windows canvas is captured,\n    * including parts rendered outside of the current view port.\n    *\n\t* Currently this only works in Mozilla and when running in chrome mode. \n    * \n    * @param kwargs  A kwargs string that modifies the way the screenshot is captured. Example: \"background=#CCFFDD\". This may be useful to set for capturing screenshots of less-than-ideal layouts, for example where absolute positioning causes the calculation of the canvas dimension to fail and a black background is exposed  (possibly obscuring black text).\n    *\n    * @return string The base 64 encoded string of the page screenshot (PNG file)\n    */\n    // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!\n};\n\nSelenium.prototype.doShutDownSeleniumServer = function(keycode) {\n    /**\n    * Kills the running Selenium Server and all browser sessions.  After you run this command, you will no longer be able to send\n    * commands to the server; you can't remotely start the server once it has been stopped.  Normally\n    * you should prefer to run the \"stop\" command, which terminates the current browser session, rather than \n    * shutting down the entire server.\n    *\n    */\n    // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!\n};\n\nSelenium.prototype.doRetrieveLastRemoteControlLogs = function() {\n    /**\n    * Retrieve the last messages logged on a specific remote control. Useful for error reports, especially\n    * when running multiple remote controls in a distributed environment. The maximum number of log messages\n    * that can be retrieve is configured on remote control startup.\n    *\n    * @return string The last N log messages as a multi-line string.\n    */\n    // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!\n};\n\nSelenium.prototype.doKeyDownNative = function(keycode) {\n    /**\n    * Simulates a user pressing a key (without releasing it yet) by sending a native operating system keystroke.\n    * This function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing\n    * a key on the keyboard.  It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and\n    * metaKeyDown commands, and does not target any particular HTML element.  To send a keystroke to a particular\n    * element, focus on the element first before running this command.\n    *\n    * @param keycode an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes!\n    */\n    // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!\n};\n\nSelenium.prototype.doKeyUpNative = function(keycode) {\n    /**\n    * Simulates a user releasing a key by sending a native operating system keystroke.\n    * This function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing\n    * a key on the keyboard.  It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and\n    * metaKeyDown commands, and does not target any particular HTML element.  To send a keystroke to a particular\n    * element, focus on the element first before running this command.\n    *\n    * @param keycode an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes!\n    */\n    // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!\n};\n\nSelenium.prototype.doKeyPressNative = function(keycode) {\n    /**\n    * Simulates a user pressing and releasing a key by sending a native operating system keystroke.\n    * This function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing\n    * a key on the keyboard.  It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and\n    * metaKeyDown commands, and does not target any particular HTML element.  To send a keystroke to a particular\n    * element, focus on the element first before running this command.\n    *\n    * @param keycode an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes!\n    */\n    // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!\n};\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-testrunner.js",
    "content": "/*\n* Copyright 2004 ThoughtWorks, Inc\n*\n*  Licensed under the Apache License, Version 2.0 (the \"License\");\n*  you may not use this file except in compliance with the License.\n*  You may obtain a copy of the License at\n*\n*      http://www.apache.org/licenses/LICENSE-2.0\n*\n*  Unless required by applicable law or agreed to in writing, software\n*  distributed under the License is distributed on an \"AS IS\" BASIS,\n*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n*  See the License for the specific language governing permissions and\n*  limitations under the License.\n*\n*/\n\n// An object representing the current test, used external\nvar currentTest = null; // TODO: get rid of this global, which mirrors the htmlTestRunner.currentTest\nvar selenium = null;\n\nvar htmlTestRunner;\nvar HtmlTestRunner = classCreate();\nobjectExtend(HtmlTestRunner.prototype, {\n    initialize: function() {\n        this.metrics = new Metrics();\n        this.controlPanel = new HtmlTestRunnerControlPanel();\n        this.testFailed = false;\n        this.currentTest = null;\n        this.runAllTests = false;\n        this.appWindow = null;\n        // we use a timeout here to make sure the LOG has loaded first, so we can see _every_ error\n        setTimeout(fnBind(function() {\n            this.loadSuiteFrame();\n        }, this), 500);\n    },\n\n    getTestSuite: function() {\n        return suiteFrame.getCurrentTestSuite();\n    },\n\n    markFailed: function() {\n        this.testFailed = true;\n        this.getTestSuite().markFailed();\n    },\n\n    loadSuiteFrame: function() {\n        var logLevel = this.controlPanel.getDefaultLogLevel();\n        if (logLevel) {\n            LOG.setLogLevelThreshold(logLevel);\n        }\n        if (selenium == null) {\n            var appWindow = this._getApplicationWindow();\n            try { appWindow.location; }\n            catch (e) { \n                // when reloading, we may be pointing at an old window (Perm Denied)\n                setTimeout(fnBind(function() {\n                    this.loadSuiteFrame();\n                }, this), 50);\n                return;\n            }\n            selenium = Selenium.createForWindow(appWindow);\n            this._registerCommandHandlers();\n        }\n        this.controlPanel.setHighlightOption();\n        var testSuiteName = this.controlPanel.getTestSuiteName();\n        var self = this;\n        if (testSuiteName) {\n            suiteFrame.load(testSuiteName, function() {setTimeout(fnBind(self._onloadTestSuite, self), 50)} );\n            selenium.browserbot.baseUrl = absolutify(testSuiteName, window.location.href);\n        }\n        // DGF or should we use the old default?\n        // selenium.browserbot.baseUrl = window.location.href;\n        if (this.controlPanel.getBaseUrl()) {\n            selenium.browserbot.baseUrl = this.controlPanel.getBaseUrl();\n        }\n    },\n\n    _getApplicationWindow: function () {\n        if (this.controlPanel.isMultiWindowMode()) {\n            return this._getSeparateApplicationWindow();\n        }\n        return sel$('selenium_myiframe').contentWindow;\n    },\n\n    _getSeparateApplicationWindow: function () {\n        if (this.appWindow == null) {\n            this.appWindow = openSeparateApplicationWindow('TestRunner-splash.html', this.controlPanel.isAutomatedRun());\n        }\n        return this.appWindow;\n    },\n\n    _onloadTestSuite:function () {\n        suiteFrame = new HtmlTestSuiteFrame(getSuiteFrame());\n        if (! this.getTestSuite().isAvailable()) {\n            return;\n        }\n        if (this.controlPanel.isAutomatedRun()) {\n            this.startTestSuite();\n        } else if (this.controlPanel.getAutoUrl()) {\n            //todo what is the autourl doing, left to check it out\n            addLoadListener(this._getApplicationWindow(), fnBind(this._startSingleTest, this));\n            this._getApplicationWindow().src = this.controlPanel.getAutoUrl();\n        } else {\n            var testCaseLoaded = fnBind(function(){this.testCaseLoaded=true;},this);\n            var testNumber = 0;\n            if (this.controlPanel.getTestNumber() != null){\n                var testNumber = this.controlPanel.getTestNumber() - 1; \n            }\n            this.getTestSuite().getSuiteRows()[testNumber].loadTestCase(testCaseLoaded);\n        }\n    },\n\n    _startSingleTest:function () {\n        removeLoadListener(getApplicationWindow(), fnBind(this._startSingleTest, this));\n        var singleTestName = this.controlPanel.getSingleTestName();\n        testFrame.load(singleTestName, fnBind(this.startTest, this));\n    },\n\n    _registerCommandHandlers: function () {\n        this.commandFactory = new CommandHandlerFactory();\n        this.commandFactory.registerAll(selenium);\n    },\n\n    startTestSuite: function() {\n        this.controlPanel.reset();\n        this.metrics.resetMetrics();\n        this.getTestSuite().reset();\n        this.runAllTests = true;\n        this.runNextTest();\n    },\n\n    runNextTest: function () {\n        this.getTestSuite().updateSuiteWithResultOfPreviousTest();\n        if (!this.runAllTests) {\n            return;\n        }\n        this.getTestSuite().runNextTestInSuite();\n    },\n\n    startTest: function () {\n        this.controlPanel.reset();\n        testFrame.scrollToTop();\n        //todo: move testFailed and storedVars to TestCase\n        this.testFailed = false;\n        storedVars = new Object();\n        storedVars.nbsp = String.fromCharCode(160);\n        storedVars.space = ' ';\n        this.currentTest = new HtmlRunnerTestLoop(testFrame.getCurrentTestCase(), this.metrics, this.commandFactory);\n        currentTest = this.currentTest;\n        this.currentTest.start();\n    },\n\n    runSingleTest:function() {\n        this.runAllTests = false;\n        this.metrics.resetMetrics();\n        this.startTest();\n    }\n});\n\nvar runInterval = 0;\n\n/** SeleniumFrame encapsulates an iframe element */\nvar SeleniumFrame = classCreate();\nobjectExtend(SeleniumFrame.prototype, {\n\n    initialize : function(frame) {\n        this.frame = frame;\n        addLoadListener(this.frame, fnBind(this._handleLoad, this));\n    },\n\n    getWindow : function() {\n        return this.frame.contentWindow;\n    },\n\n    getDocument : function() {\n        return this.frame.contentWindow.document;\n    },\n\n    _handleLoad: function() {\n        this._attachStylesheet();\n        this._onLoad();\n        if (this.loadCallback) {\n            this.loadCallback();\n        }\n    },\n\n    _attachStylesheet: function() {\n        var d = this.getDocument();\n        var head = d.getElementsByTagName('head').item(0);\n        var styleLink = d.createElement(\"link\");\n        styleLink.rel = \"stylesheet\";\n        styleLink.type = \"text/css\";\n        if (browserVersion && browserVersion.isChrome) {\n            // DGF We have to play a clever trick to get the right absolute path.\n            // This trick works on most browsers, (not IE), but is only needed in\n            // chrome\n            var tempLink = window.document.createElement(\"link\");\n            tempLink.href = \"selenium-test.css\"; // this will become an absolute href\n            styleLink.href = tempLink.href;\n        } else {\n            // this works in every browser (except Firefox in chrome mode)\n            var styleSheetPath = window.location.pathname.replace(/[^\\/\\\\]+$/, \"selenium-test.css\");\n            if (browserVersion.isIE && window.location.protocol == \"file:\") {\n                styleSheetPath = \"file:///\" + styleSheetPath;\n            }\n            styleLink.href = styleSheetPath;\n        }\n        // DGF You're only going to see this log message if you set defaultLogLevel=debug\n        LOG.debug(\"styleLink.href=\"+styleLink.href);\n        head.appendChild(styleLink);\n    },\n\n    _onLoad: function() {\n    },\n\n    scrollToTop : function() {\n        this.frame.contentWindow.scrollTo(0, 0);\n    },\n\n    _setLocation: function(location) {\n        var isChrome = browserVersion.isChrome || false;\n        var isHTA = browserVersion.isHTA || false;\n        // DGF TODO multiWindow\n        location += (location.indexOf(\"?\") == -1 ? \"?\" : \"&\");\n        location += \"thisIsChrome=\" + isChrome + \"&thisIsHTA=\" + isHTA; \n        if (browserVersion.isSafari) {\n            // safari doesn't reload the page when the location equals to current location.\n            // hence, set the location to blank so that the page will reload automatically.\n            this.frame.src = \"about:blank\";\n            this.frame.src = location;\n        } else {\n            this.frame.contentWindow.location.replace(location);\n        }\n    },\n\n    load: function(/* url, [callback] */) {\n        if (arguments.length > 1) {\n            this.loadCallback = arguments[1];\n\n        }\n        this._setLocation(arguments[0]);\n    }\n\n});\n\n/** HtmlTestSuiteFrame - encapsulates the suite iframe element */\nvar HtmlTestSuiteFrame = classCreate();\nobjectExtend(HtmlTestSuiteFrame.prototype, SeleniumFrame.prototype);\nobjectExtend(HtmlTestSuiteFrame.prototype, {\n\n    getCurrentTestSuite: function() {\n        if (!this.currentTestSuite) {\n            this.currentTestSuite = new HtmlTestSuite(this.getDocument());\n        }\n        return this.currentTestSuite;\n    }\n\n});\n\n/** HtmlTestFrame - encapsulates the test-case iframe element */\nvar HtmlTestFrame = classCreate();\nobjectExtend(HtmlTestFrame.prototype, SeleniumFrame.prototype);\nobjectExtend(HtmlTestFrame.prototype, {\n\n    _onLoad: function() {\n        this.currentTestCase = new HtmlTestCase(this.getWindow(), htmlTestRunner.getTestSuite().getCurrentRow());\n    },\n\n    getCurrentTestCase: function() {\n        return this.currentTestCase;\n    }\n\n});\n\nfunction onSeleniumLoad() {\n    suiteFrame = new HtmlTestSuiteFrame(getSuiteFrame());\n    testFrame = new HtmlTestFrame(getTestFrame());\n    htmlTestRunner = new HtmlTestRunner();\n}\n\nvar suiteFrame;\nvar testFrame;\n\nfunction getSuiteFrame() {\n    var f = sel$('testSuiteFrame');\n    if (f == null) {\n        f = top;\n        // proxyInjection mode does not set selenium_myiframe\n    }\n    return f;\n}\n\nfunction getTestFrame() {\n    var f = sel$('testFrame');\n    if (f == null) {\n        f = top;\n        // proxyInjection mode does not set selenium_myiframe\n    }\n    return f;\n}\n\nvar HtmlTestRunnerControlPanel = classCreate();\nobjectExtend(HtmlTestRunnerControlPanel.prototype, URLConfiguration.prototype);\nobjectExtend(HtmlTestRunnerControlPanel.prototype, {\n    initialize: function() {\n        this._acquireQueryString();\n\n        this.runInterval = 0;\n\n        this.highlightOption = sel$('highlightOption');\n        this.pauseButton = sel$('pauseTest');\n        this.stepButton = sel$('stepTest');\n\n        this.highlightOption.onclick = fnBindAsEventListener((function() {\n            this.setHighlightOption();\n        }), this);\n        this.pauseButton.onclick = fnBindAsEventListener(this.pauseCurrentTest, this);\n        this.stepButton.onclick = fnBindAsEventListener(this.stepCurrentTest, this);\n\n\n        this.speedController = new Control.Slider('speedHandle', 'speedTrack', {\n            range: $R(0, 1000),\n            onSlide: fnBindAsEventListener(this.setRunInterval, this),\n            onChange: fnBindAsEventListener(this.setRunInterval, this)\n        });\n\n        this._parseQueryParameter();\n    },\n\n    setHighlightOption: function () {\n        var isHighlight = this.highlightOption.checked;\n        selenium.browserbot.setShouldHighlightElement(isHighlight);\n    },\n\n    _parseQueryParameter: function() {\n        var tempRunInterval = this._getQueryParameter(\"runInterval\");\n        if (tempRunInterval) {\n            this.setRunInterval(tempRunInterval);\n        }\n        this.highlightOption.checked = this._getQueryParameter(\"highlight\");\n    },\n\n    setRunInterval: function(runInterval) {\n        this.runInterval = runInterval;\n    },\n\n    setToPauseAtNextCommand: function() {\n        this.runInterval = -1;\n    },\n\n    pauseCurrentTest: function () {\n        this.setToPauseAtNextCommand();\n        this._switchPauseButtonToContinue();\n    },\n\n    continueCurrentTest: function () {\n        this.reset();\n        currentTest.resume();\n    },\n\n    reset: function() {\n        this.runInterval = this.speedController.value;\n        this._switchContinueButtonToPause();\n    },\n\n    _switchContinueButtonToPause: function() {\n        this.pauseButton.className = \"cssPauseTest\";\n        this.pauseButton.onclick = fnBindAsEventListener(this.pauseCurrentTest, this);\n    },\n\n    _switchPauseButtonToContinue: function() {\n        sel$('stepTest').disabled = false;\n        this.pauseButton.className = \"cssContinueTest\";\n        this.pauseButton.onclick = fnBindAsEventListener(this.continueCurrentTest, this);\n    },\n\n    stepCurrentTest: function () {\n        this.setToPauseAtNextCommand();\n        currentTest.resume();\n    },\n\n    isAutomatedRun: function() {\n        return this._isQueryParameterTrue(\"auto\");\n    },\n\n    shouldSaveResultsToFile: function() {\n        return this._isQueryParameterTrue(\"save\");\n    },\n\n    closeAfterTests: function() {\n        return this._isQueryParameterTrue(\"close\");\n    },\n\n    getTestSuiteName: function() {\n        return this._getQueryParameter(\"test\");\n    },\n\n    getTestNumber: function() {\n        return this._getQueryParameter(\"testNumber\");\n    },\n\n    getSingleTestName: function() {\n        return this._getQueryParameter(\"singletest\");\n    },\n\n    getAutoUrl: function() {\n        return this._getQueryParameter(\"autoURL\");\n    },\n    \n    getDefaultLogLevel: function() {\n        return this._getQueryParameter(\"defaultLogLevel\");\n    },\n\n    getResultsUrl: function() {\n        return this._getQueryParameter(\"resultsUrl\");\n    },\n\n    _acquireQueryString: function() {\n        if (this.queryString) return;\n        if (browserVersion.isHTA) {\n            var args = this._extractArgs();\n            if (args.length < 2) return null;\n            this.queryString = args[1];\n        } else {\n            this.queryString = location.search.substr(1);\n        }\n    }\n\n});\n\nvar AbstractResultAwareRow = classCreate();\nobjectExtend(AbstractResultAwareRow.prototype, {\n\n    initialize: function(trElement) {\n        this.trElement = trElement;\n    },\n\n    setStatus: function(status) {\n        this.unselect();\n        this.trElement.className = this.trElement.className.replace(/status_[a-z]+/, \"\");\n        if (status) {\n            addClassName(this.trElement, \"status_\" + status);\n        }\n    },\n\n    select: function() {\n        addClassName(this.trElement, \"selected\");\n        safeScrollIntoView(this.trElement);\n    },\n\n    unselect: function() {\n        removeClassName(this.trElement, \"selected\");\n    },\n\n    markPassed: function() {\n        this.setStatus(\"passed\");\n    },\n\n    markDone: function() {\n        this.setStatus(\"done\");\n    },\n\n    markFailed: function() {\n        this.setStatus(\"failed\");\n    }\n\n});\n\nvar TitleRow = classCreate();\nobjectExtend(TitleRow.prototype, AbstractResultAwareRow.prototype);\nobjectExtend(TitleRow.prototype, {\n\n    initialize: function(trElement) {\n        this.trElement = trElement;\n        trElement.className = \"title\";\n    }\n\n});\n\nvar HtmlTestCaseRow = classCreate();\nobjectExtend(HtmlTestCaseRow.prototype, AbstractResultAwareRow.prototype);\nobjectExtend(HtmlTestCaseRow.prototype, {\n\n    getCommand: function () {\n        return new SeleniumCommand(getText(this.trElement.cells[0]),\n                getText(this.trElement.cells[1]),\n                getText(this.trElement.cells[2]),\n                this.isBreakpoint());\n    },\n\n    markFailed: function(errorMsg) {\n        AbstractResultAwareRow.prototype.markFailed.call(this, errorMsg);\n        this.setMessage(errorMsg);\n    },\n\n    setMessage: function(message) {\n        setText(this.trElement.cells[2], message);\n    },\n\n    reset: function() {\n        this.setStatus(null);\n        var thirdCell = this.trElement.cells[2];\n        if (thirdCell) {\n            if (thirdCell.originalHTML) {\n                thirdCell.innerHTML = thirdCell.originalHTML;\n            } else {\n                thirdCell.originalHTML = thirdCell.innerHTML;\n            }\n        }\n    },\n\n    onClick: function() {\n        if (this.trElement.isBreakpoint == undefined) {\n            this.trElement.isBreakpoint = true;\n            addClassName(this.trElement, \"breakpoint\");\n        } else {\n            this.trElement.isBreakpoint = undefined;\n            removeClassName(this.trElement, \"breakpoint\");\n        }\n    },\n\n    addBreakpointSupport: function() {\n        elementSetStyle(this.trElement, {\"cursor\" : \"pointer\"});\n        this.trElement.onclick = fnBindAsEventListener(function() {\n            this.onClick();\n        }, this);\n    },\n\n    isBreakpoint: function() {\n        if (this.trElement.isBreakpoint == undefined || this.trElement.isBreakpoint == null) {\n            return false\n        }\n        return this.trElement.isBreakpoint;\n    }\n});\n\nvar HtmlTestSuiteRow = classCreate();\nobjectExtend(HtmlTestSuiteRow.prototype, AbstractResultAwareRow.prototype);\nobjectExtend(HtmlTestSuiteRow.prototype, {\n\n    initialize: function(trElement, testFrame, htmlTestSuite) {\n        this.trElement = trElement;\n        this.testFrame = testFrame;\n        this.htmlTestSuite = htmlTestSuite;\n        this.link = trElement.getElementsByTagName(\"a\")[0];\n        this.link.onclick = fnBindAsEventListener(this._onClick, this);\n    },\n\n    reset: function() {\n        this.setStatus(null);\n    },\n\n    _onClick: function() {\n        this.loadTestCase(null);\n        return false;\n    },\n\n    loadTestCase: function(onloadFunction) {\n        this.htmlTestSuite.unselectCurrentRow();\n        this.select();\n        this.htmlTestSuite.currentRowInSuite = this.trElement.rowIndex - 1;\n        // If the row has a stored results table, use that\n        var resultsFromPreviousRun = this.trElement.cells[1];\n        if (resultsFromPreviousRun) {\n            // todo: delegate to TestFrame, e.g.\n            //   this.testFrame.restoreTestCase(resultsFromPreviousRun.innerHTML);\n            var testBody = this.testFrame.getDocument().body;\n            testBody.innerHTML = resultsFromPreviousRun.innerHTML;\n            this.testFrame._onLoad();\n            if (onloadFunction) {\n                onloadFunction();\n            }\n        } else {\n            this.testFrame.load(this.link.href, onloadFunction);\n        }\n    },\n\n    saveTestResults: function() {\n        // todo: GLOBAL ACCESS!\n        var resultHTML = this.testFrame.getDocument().body.innerHTML;\n        if (!resultHTML) return;\n\n        // todo: why create this div?\n        var divElement = this.trElement.ownerDocument.createElement(\"div\");\n        divElement.innerHTML = resultHTML;\n\n        var hiddenCell = this.trElement.ownerDocument.createElement(\"td\");\n        hiddenCell.appendChild(divElement);\n        hiddenCell.style.display = \"none\";\n\n        this.trElement.appendChild(hiddenCell);\n    }\n\n});\n\nvar HtmlTestSuite = classCreate();\nobjectExtend(HtmlTestSuite.prototype, {\n\n    initialize: function(suiteDocument) {\n        this.suiteDocument = suiteDocument;\n        this.suiteRows = this._collectSuiteRows();\n        var testTable = this.getTestTable();\n        if (!testTable) return;\n        this.titleRow = new TitleRow(testTable.rows[0]);\n        this.reset();\n    },\n\n    reset: function() {\n        this.failed = false;\n        this.currentRowInSuite = -1;\n        this.titleRow.setStatus(null);\n        for (var i = 0; i < this.suiteRows.length; i++) {\n            var row = this.suiteRows[i];\n            row.reset();\n        }\n    },\n\n    getSuiteRows: function() {\n        return this.suiteRows;\n    },\n\n    getTestTable: function() {\n        var tables = sel$A(this.suiteDocument.getElementsByTagName(\"table\"));\n        return tables[0];\n    },\n\n    isAvailable: function() {\n        return this.getTestTable() != null;\n    },\n\n    _collectSuiteRows: function () {\n        var result = [];\n        var tables = sel$A(this.suiteDocument.getElementsByTagName(\"table\"));\n        var testTable = tables[0];\n        if (!testTable) return;\n        for (rowNum = 1; rowNum < testTable.rows.length; rowNum++) {\n            var rowElement = testTable.rows[rowNum];\n            result.push(new HtmlTestSuiteRow(rowElement, testFrame, this));\n        }\n        \n        // process the unsuited rows as well\n        for (var tableNum = 1; tableNum < sel$A(this.suiteDocument.getElementsByTagName(\"table\")).length; tableNum++) {\n            testTable = tables[tableNum];\n            for (rowNum = 1; rowNum < testTable.rows.length; rowNum++) {\n                var rowElement = testTable.rows[rowNum];\n                new HtmlTestSuiteRow(rowElement, testFrame, this);\n            }\n        }\n        return result;\n    },\n\n    getCurrentRow: function() {\n        if (this.currentRowInSuite == -1) {\n            return null;\n        }\n        return this.suiteRows[this.currentRowInSuite];\n    },\n\n    unselectCurrentRow: function() {\n        var currentRow = this.getCurrentRow()\n        if (currentRow) {\n            currentRow.unselect();\n        }\n    },\n\n    markFailed: function() {\n        this.failed = true;\n        this.titleRow.markFailed();\n    },\n\n    markDone: function() {\n        if (!this.failed) {\n            this.titleRow.markPassed();\n        }\n    },\n\n    _startCurrentTestCase: function() {\n        this.getCurrentRow().loadTestCase(fnBind(htmlTestRunner.startTest, htmlTestRunner));\n    },\n\n    _onTestSuiteComplete: function() {\n        this.markDone();\n        new SeleniumTestResult(this.failed, this.getTestTable()).post();\n    },\n\n    updateSuiteWithResultOfPreviousTest: function() {\n        if (this.currentRowInSuite >= 0) {\n            this.getCurrentRow().saveTestResults();\n        }\n    },\n\n    runNextTestInSuite: function() {\n        this.currentRowInSuite++;\n\n        // If we are done with all of the tests, set the title bar as pass or fail\n        if (this.currentRowInSuite >= this.suiteRows.length) {\n            this._onTestSuiteComplete();\n        } else {\n            this._startCurrentTestCase();\n        }\n    }\n\n\n\n});\n\nvar SeleniumTestResult = classCreate();\nobjectExtend(SeleniumTestResult.prototype, {\n\n// Post the results to a servlet, CGI-script, etc.  The URL of the\n// results-handler defaults to \"/postResults\", but an alternative location\n// can be specified by providing a \"resultsUrl\" query parameter.\n//\n// Parameters passed to the results-handler are:\n//      result:         passed/failed depending on whether the suite passed or failed\n//      totalTime:      the total running time in seconds for the suite.\n//\n//      numTestPasses:  the total number of tests which passed.\n//      numTestFailures: the total number of tests which failed.\n//\n//      numCommandPasses: the total number of commands which passed.\n//      numCommandFailures: the total number of commands which failed.\n//      numCommandErrors: the total number of commands which errored.\n//\n//      suite:      the suite table, including the hidden column of test results\n//      testTable.1 to testTable.N: the individual test tables\n//\n    initialize: function (suiteFailed, suiteTable) {\n        this.controlPanel = htmlTestRunner.controlPanel;\n        this.metrics = htmlTestRunner.metrics;\n        this.suiteFailed = suiteFailed;\n        this.suiteTable = suiteTable;\n    },\n\n    post: function () {\n        if (!this.controlPanel.isAutomatedRun()) {\n            return;\n        }\n        var form = document.createElement(\"form\");\n        document.body.appendChild(form);\n\n        form.id = \"resultsForm\";\n        form.method = \"post\";\n        form.target = \"selenium_myiframe\";\n\n        var resultsUrl = this.controlPanel.getResultsUrl();\n        if (!resultsUrl) {\n            resultsUrl = \"./postResults\";\n        }\n\n        var actionAndParameters = resultsUrl.split('?', 2);\n        form.action = actionAndParameters[0];\n        var resultsUrlQueryString = actionAndParameters[1];\n\n        form.createHiddenField = function(name, value) {\n            input = document.createElement(\"input\");\n            input.type = \"hidden\";\n            input.name = name;\n            input.value = value;\n            this.appendChild(input);\n        };\n\n        if (resultsUrlQueryString) {\n            var clauses = resultsUrlQueryString.split('&');\n            for (var i = 0; i < clauses.length; i++) {\n                var keyValuePair = clauses[i].split('=', 2);\n                var key = unescape(keyValuePair[0]);\n                var value = unescape(keyValuePair[1]);\n                form.createHiddenField(key, value);\n            }\n        }\n\n        form.createHiddenField(\"selenium.version\", Selenium.version);\n        form.createHiddenField(\"selenium.revision\", Selenium.revision);\n\n        form.createHiddenField(\"result\", this.suiteFailed ? \"failed\" : \"passed\");\n\n        form.createHiddenField(\"totalTime\", Math.floor((this.metrics.currentTime - this.metrics.startTime) / 1000));\n        form.createHiddenField(\"numTestPasses\", this.metrics.numTestPasses);\n        form.createHiddenField(\"numTestFailures\", this.metrics.numTestFailures);\n        form.createHiddenField(\"numCommandPasses\", this.metrics.numCommandPasses);\n        form.createHiddenField(\"numCommandFailures\", this.metrics.numCommandFailures);\n        form.createHiddenField(\"numCommandErrors\", this.metrics.numCommandErrors);\n\n        // Create an input for each test table.  The inputs are named\n        // testTable.1, testTable.2, etc.\n        for (rowNum = 1; rowNum < this.suiteTable.rows.length; rowNum++) {\n            // If there is a second column, then add a new input\n            if (this.suiteTable.rows[rowNum].cells.length > 1) {\n                var resultCell = this.suiteTable.rows[rowNum].cells[1];\n                form.createHiddenField(\"testTable.\" + rowNum, resultCell.innerHTML);\n                // remove the resultCell, so it's not included in the suite HTML\n                resultCell.parentNode.removeChild(resultCell);\n            }\n        }\n\n        form.createHiddenField(\"numTestTotal\", rowNum-1);\n\n        // Add HTML for the suite itself\n        form.createHiddenField(\"suite\", this.suiteTable.parentNode.innerHTML);\n\n        var logMessages = [];\n        while (LOG.pendingMessages.length > 0) {\n            var msg = LOG.pendingMessages.shift();\n            logMessages.push(msg.type);\n            logMessages.push(\": \");\n            logMessages.push(msg.msg);\n            logMessages.push('\\n');\n        }\n        var logOutput = logMessages.join(\"\");\n        form.createHiddenField(\"log\", logOutput);\n\n        if (this.controlPanel.shouldSaveResultsToFile()) {\n            this._saveToFile(resultsUrl, form);\n        } else {\n            form.submit();\n        }\n        document.body.removeChild(form);\n        if (this.controlPanel.closeAfterTests()) {\n            window.top.close();\n        }\n    },\n\n    _saveToFile: function (fileName, form) {\n        // This only works when run as an IE HTA\n        var inputs = new Object();\n        for (var i = 0; i < form.elements.length; i++) {\n            inputs[form.elements[i].name] = form.elements[i].value;\n        }\n        \n        var objFSO = new ActiveXObject(\"Scripting.FileSystemObject\")\n        \n        // DGF get CSS\n        var styles = \"\";\n        try {\n            var styleSheetPath = window.location.pathname.replace(/[^\\/\\\\]+$/, \"selenium-test.css\");\n            if (window.location.protocol == \"file:\") {\n                var stylesFile = objFSO.OpenTextFile(styleSheetPath, 1);\n                styles = stylesFile.ReadAll();\n            } else {\n                var xhr = XmlHttp.create();\n                xhr.open(\"GET\", styleSheetPath, false);\n                xhr.send(\"\");\n                styles = xhr.responseText;\n            }\n        } catch (e) {}\n        \n        var scriptFile = objFSO.CreateTextFile(fileName);\n        \n        \n        scriptFile.WriteLine(\"<html><head><title>Test suite results</title><style>\");\n        scriptFile.WriteLine(styles);\n        scriptFile.WriteLine(\"</style>\");\n        scriptFile.WriteLine(\"<body>\\n<h1>Test suite results</h1>\" +\n             \"\\n\\n<table>\\n<tr>\\n<td>result:</td>\\n<td>\" + inputs[\"result\"] + \"</td>\\n\" +\n             \"</tr>\\n<tr>\\n<td>totalTime:</td>\\n<td>\" + inputs[\"totalTime\"] + \"</td>\\n</tr>\\n\" +\n             \"<tr>\\n<td>numTestTotal:</td>\\n<td>\" + inputs[\"numTestTotal\"] + \"</td>\\n</tr>\\n\" +\n             \"<tr>\\n<td>numTestPasses:</td>\\n<td>\" + inputs[\"numTestPasses\"] + \"</td>\\n</tr>\\n\" +\n             \"<tr>\\n<td>numTestFailures:</td>\\n<td>\" + inputs[\"numTestFailures\"] + \"</td>\\n</tr>\\n\" +\n             \"<tr>\\n<td>numCommandPasses:</td>\\n<td>\" + inputs[\"numCommandPasses\"] + \"</td>\\n</tr>\\n\" +\n             \"<tr>\\n<td>numCommandFailures:</td>\\n<td>\" + inputs[\"numCommandFailures\"] + \"</td>\\n</tr>\\n\" +\n             \"<tr>\\n<td>numCommandErrors:</td>\\n<td>\" + inputs[\"numCommandErrors\"] + \"</td>\\n</tr>\\n\" +\n             \"<tr>\\n<td>\" + inputs[\"suite\"] + \"</td>\\n<td>&nbsp;</td>\\n</tr></table><table>\");\n        var testNum = inputs[\"numTestTotal\"];\n        \n        for (var rowNum = 1; rowNum <= testNum; rowNum++) {\n            scriptFile.WriteLine(\"<tr>\\n<td>\" + inputs[\"testTable.\" + rowNum] + \"</td>\\n<td>&nbsp;</td>\\n</tr>\");\n        }\n        scriptFile.WriteLine(\"</table><pre>\");\n        var log = inputs[\"log\"];\n        log=log.replace(/&/gm,\"&amp;\").replace(/</gm,\"&lt;\").replace(/>/gm,\"&gt;\").replace(/\"/gm,\"&quot;\").replace(/'/gm,\"&apos;\");\n        scriptFile.WriteLine(log);\n        scriptFile.WriteLine(\"</pre></body></html>\");\n        scriptFile.Close();\n    }\n});\n\n/** HtmlTestCase encapsulates an HTML test document */\nvar HtmlTestCase = classCreate();\nobjectExtend(HtmlTestCase.prototype, {\n\n    initialize: function(testWindow, htmlTestSuiteRow) {\n        if (testWindow == null) {\n            throw \"testWindow should not be null\";\n        }\n        if (htmlTestSuiteRow == null) {\n            throw \"htmlTestSuiteRow should not be null\";\n        }\n        this.testWindow = testWindow;\n        this.testDocument = testWindow.document;\n        this.pathname = \"'unknown'\";\n        try {\n            if (this.testWindow.location) {\n                this.pathname = this.testWindow.location.pathname;\n            }\n        } catch (e) {}\n            \n        this.htmlTestSuiteRow = htmlTestSuiteRow;\n        this.headerRow = new TitleRow(this.testDocument.getElementsByTagName(\"tr\")[0]);\n        this.commandRows = this._collectCommandRows();\n        this.nextCommandRowIndex = 0;\n        this._addBreakpointSupport();\n    },\n\n    _collectCommandRows: function () {\n        var commandRows = [];\n        var tables = sel$A(this.testDocument.getElementsByTagName(\"table\"));\n        var self = this;\n        for (var i = 0; i < tables.length; i++) {\n            var table = tables[i];\n            var tableRows = sel$A(table.rows);\n            for (var j = 0; j < tableRows.length; j++) {\n                var candidateRow = tableRows[j];\n                if (self.isCommandRow(candidateRow)) {\n                    commandRows.push(new HtmlTestCaseRow(candidateRow));\n                }\n            }\n        }\n        return commandRows;\n    },\n\n    isCommandRow:  function (row) {\n        return row.cells.length >= 3;\n    },\n\n    reset: function() {\n        /**\n         * reset the test to runnable state\n         */\n        this.nextCommandRowIndex = 0;\n\n        this.setStatus('');\n        for (var i = 0; i < this.commandRows.length; i++) {\n            var row = this.commandRows[i];\n            row.reset();\n        }\n\n        // remove any additional fake \"error\" row added to the end of the document\n        var errorElement = this.testDocument.getElementById('error');\n        if (errorElement) {\n            errorElement.parentNode.removeChild(errorElement);\n        }\n    },\n\n    getCommandRows: function () {\n        return this.commandRows;\n    },\n\n    setStatus: function(status) {\n        this.headerRow.setStatus(status);\n    },\n\n    markFailed: function() {\n        this.setStatus(\"failed\");\n        this.htmlTestSuiteRow.markFailed();\n    },\n\n    markPassed: function() {\n        this.setStatus(\"passed\");\n        this.htmlTestSuiteRow.markPassed();\n    },\n\n    addErrorMessage: function(errorMsg, currentRow) {\n        errorMsg = errorMsg.replace(/ /g, String.fromCharCode(160)).replace(\"\\n\", '\\\\n');\n        if (currentRow) {\n            currentRow.markFailed(errorMsg);\n        } else {\n            var errorElement = this.testDocument.createElement(\"p\");\n            errorElement.id = \"error\";\n            setText(errorElement, errorMsg);\n            this.testDocument.body.appendChild(errorElement);\n            errorElement.className = \"status_failed\";\n        }\n    },\n\n    _addBreakpointSupport: function() {\n        for (var i = 0; i < this.commandRows.length; i++) {\n            var row = this.commandRows[i];\n            row.addBreakpointSupport();\n        }\n    },\n\n    hasMoreCommandRows: function() {\n        return this.nextCommandRowIndex < this.commandRows.length;\n    },\n\n    getNextCommandRow: function() {\n        if (this.hasMoreCommandRows()) {\n            return this.commandRows[this.nextCommandRowIndex++];\n        }\n        return null;\n    }\n\n});\n\n\n// TODO: split out an JavascriptTestCase class to handle the \"sejs\" stuff\n\nvar get_new_rows = function() {\n    var row_array = new Array();\n    for (var i = 0; i < new_block.length; i++) {\n\n        var new_source = (new_block[i][0].tokenizer.source.slice(new_block[i][0].start,\n                new_block[i][0].end));\n\n        var row = '<td style=\"display:none;\" class=\"js\">getEval</td>' +\n                  '<td style=\"display:none;\">currentTest.doNextCommand()</td>' +\n                  '<td style=\"white-space: pre;\">' + new_source + '</td>' +\n                  '<td></td>'\n\n        row_array.push(row);\n    }\n    return row_array;\n};\n\n\nvar Metrics = classCreate();\nobjectExtend(Metrics.prototype, {\n    initialize: function() {\n        // The number of tests run\n        this.numTestPasses = 0;\n        // The number of tests that have failed\n        this.numTestFailures = 0;\n        // The number of commands which have passed\n        this.numCommandPasses = 0;\n        // The number of commands which have failed\n        this.numCommandFailures = 0;\n        // The number of commands which have caused errors (element not found)\n        this.numCommandErrors = 0;\n        // The time that the test was started.\n        this.startTime = null;\n        // The current time.\n        this.currentTime = null;\n    },\n\n    printMetrics: function() {\n        setText(sel$('commandPasses'), this.numCommandPasses);\n        setText(sel$('commandFailures'), this.numCommandFailures);\n        setText(sel$('commandErrors'), this.numCommandErrors);\n        setText(sel$('testRuns'), this.numTestPasses + this.numTestFailures);\n        setText(sel$('testFailures'), this.numTestFailures);\n\n        this.currentTime = new Date().getTime();\n\n        var timeDiff = this.currentTime - this.startTime;\n        var totalSecs = Math.floor(timeDiff / 1000);\n\n        var minutes = Math.floor(totalSecs / 60);\n        var seconds = totalSecs % 60;\n\n        setText(sel$('elapsedTime'), this._pad(minutes) + \":\" + this._pad(seconds));\n    },\n\n// Puts a leading 0 on num if it is less than 10\n    _pad: function(num) {\n        return (num > 9) ? num : \"0\" + num;\n    },\n\n    resetMetrics: function() {\n        this.numTestPasses = 0;\n        this.numTestFailures = 0;\n        this.numCommandPasses = 0;\n        this.numCommandFailures = 0;\n        this.numCommandErrors = 0;\n        this.startTime = new Date().getTime();\n    }\n\n});\n\nvar HtmlRunnerCommandFactory = classCreate();\nobjectExtend(HtmlRunnerCommandFactory.prototype, {\n\n    initialize: function(seleniumCommandFactory, testLoop) {\n        this.seleniumCommandFactory = seleniumCommandFactory;\n        this.testLoop = testLoop;\n        this.handlers = {};\n        //todo: register commands\n    },\n\n    getCommandHandler: function(command) {\n        if (this.handlers[command]) {\n            return this.handlers[command];\n        }\n        return this.seleniumCommandFactory.getCommandHandler(command);\n    }\n\n});\n\nvar HtmlRunnerTestLoop = classCreate();\nobjectExtend(HtmlRunnerTestLoop.prototype, new TestLoop());\nobjectExtend(HtmlRunnerTestLoop.prototype, {\n    initialize: function(htmlTestCase, metrics, seleniumCommandFactory) {\n\n        this.commandFactory = new HtmlRunnerCommandFactory(seleniumCommandFactory, this);\n        this.metrics = metrics;\n\n        this.htmlTestCase = htmlTestCase;\n        LOG.info(\"Starting test \" + htmlTestCase.pathname);\n\n        this.currentRow = null;\n        this.currentRowIndex = 0;\n\n        // used for selenium tests in javascript\n        this.currentItem = null;\n        this.commandAgenda = new Array();\n        this.expectedFailure = null;\n        this.expectedFailureType = null;\n\n        this.htmlTestCase.reset();\n    },\n\n    _advanceToNextRow: function() {\n        if (this.htmlTestCase.hasMoreCommandRows()) {\n            this.currentRow = this.htmlTestCase.getNextCommandRow();\n            if (this.sejsElement) {\n                this.currentItem = agenda.pop();\n                this.currentRowIndex++;\n            }\n        } else {\n            this.currentRow = null;\n            this.currentItem = null;\n        }\n    },\n\n    nextCommand : function() {\n        this._advanceToNextRow();\n        if (this.currentRow == null) {\n            return null;\n        }\n        return this.currentRow.getCommand();\n    },\n\n    commandStarted : function() {\n        sel$('pauseTest').disabled = false;\n        this.currentRow.select();\n        this.metrics.printMetrics();\n    },\n\n    commandComplete : function(result) {\n        this._checkExpectedFailure(result);\n        if (result.failed) {\n            this.metrics.numCommandFailures += 1;\n            this._recordFailure(result.failureMessage);\n        } else if (result.passed) {\n            this.metrics.numCommandPasses += 1;\n            this.currentRow.markPassed();\n        } else {\n            this.currentRow.markDone();\n        }\n    },\n\n    _checkExpectedFailure : function(result) {\n        if (this.expectedFailure != null) {\n            if (this.expectedFailureJustSet) {\n                this.expectedFailureJustSet = false;\n                return;\n            }\n            if (!result.failed) {\n                result.passed = false;\n                result.failed = true;\n                result.failureMessage = \"Expected \" + this.expectedFailureType + \" did not occur.\";\n            } else {\n                if (PatternMatcher.matches(this.expectedFailure, result.failureMessage)) {\n                    var failureType = result.error ? \"error\" : \"failure\";\n                    if (failureType == this.expectedFailureType) {\n                        result.failed = false;\n                        result.passed = true;\n                    } else {\n                        result.failed = true;\n                        result.failureMessage = \"Expected \"+this.expectedFailureType+\", but \"+failureType+\" occurred instead\";\n                    }\n                } else {\n                    result.failed = true;\n                    result.failureMessage = \"Expected \" + this.expectedFailureType + \" message '\" + this.expectedFailure\n                                            + \"' but was '\" + result.failureMessage + \"'\";\n                }\n            }\n            this.expectedFailure = null;\n            this.expectedFailureType = null;\n        }\n    },\n\n    commandError : function(errorMessage) {\n        var tempResult = {};\n        tempResult.passed = false;\n        tempResult.failed = true;\n        tempResult.error = true;\n        tempResult.failureMessage = errorMessage;\n        this._checkExpectedFailure(tempResult);\n        if (tempResult.passed) {\n            this.currentRow.markDone();\n            return true;\n        }\n        errorMessage = tempResult.failureMessage;\n        this.metrics.numCommandErrors += 1;\n        this._recordFailure(errorMessage);\n    },\n\n    _recordFailure : function(errorMsg) {\n        LOG.warn(\"currentTest.recordFailure: \" + errorMsg);\n        htmlTestRunner.markFailed();\n        this.htmlTestCase.addErrorMessage(errorMsg, this.currentRow);\n    },\n\n    testComplete : function() {\n        sel$('pauseTest').disabled = true;\n        sel$('stepTest').disabled = true;\n        if (htmlTestRunner.testFailed) {\n            this.htmlTestCase.markFailed();\n            this.metrics.numTestFailures += 1;\n        } else {\n            this.htmlTestCase.markPassed();\n            this.metrics.numTestPasses += 1;\n        }\n\n        this.metrics.printMetrics();\n\n        window.setTimeout(function() {\n            htmlTestRunner.runNextTest();\n        }, 1);\n    },\n\n    getCommandInterval : function() {\n        return htmlTestRunner.controlPanel.runInterval;\n    },\n\n    pause : function() {\n        htmlTestRunner.controlPanel.pauseCurrentTest();\n    },\n\n    doNextCommand: function() {\n        var _n = this.currentItem[0];\n        var _x = this.currentItem[1];\n\n        new_block = new Array()\n        execute(_n, _x);\n        if (new_block.length > 0) {\n            var the_table = this.htmlTestCase.testDocument.getElementById(\"se-js-table\")\n            var loc = this.currentRowIndex\n            var new_rows = get_new_rows()\n\n            // make the new statements visible on screen...\n            for (var i = 0; i < new_rows.length; i++) {\n                the_table.insertRow(loc + 1);\n                the_table.rows[loc + 1].innerHTML = new_rows[i];\n                this.commandRows.unshift(the_table.rows[loc + 1])\n            }\n\n        }\n    }\n\n});\n\nSelenium.prototype.doPause = function(waitTime) {\n    /** Wait for the specified amount of time (in milliseconds)\n     * @param waitTime the amount of time to sleep (in milliseconds)\n     */\n    // todo: should not refer to currentTest directly\n    currentTest.pauseInterval = waitTime;\n};\n\nSelenium.prototype.doBreak = function() {\n    /** Halt the currently running test, and wait for the user to press the Continue button.\n     * This command is useful for debugging, but be careful when using it, because it will\n     * force automated tests to hang until a user intervenes manually.\n     */\n    // todo: should not refer to controlPanel directly\n    htmlTestRunner.controlPanel.setToPauseAtNextCommand();\n};\n\nSelenium.prototype.doStore = function(expression, variableName) {\n    /** This command is a synonym for storeExpression.\n     * @param expression the value to store\n     * @param variableName the name of a <a href=\"#storedVars\">variable</a> in which the result is to be stored.\n     */\n    storedVars[variableName] = expression;\n}\n\n/*\n * Click on the located element, and attach a callback to notify\n * when the page is reloaded.\n */\n// DGF TODO this code has been broken for some time... what is it trying to accomplish?\nSelenium.prototype.XXXdoModalDialogTest = function(returnValue) {\n    this.browserbot.doModalDialogTest(returnValue);\n};\n\nSelenium.prototype.doEcho = function(message) {\n    /** Prints the specified message into the third table cell in your Selenese tables.\n     * Useful for debugging.\n     * @param message the message to print\n     */\n    currentTest.currentRow.setMessage(message);\n}\n\n/*\n * doSetSpeed and getSpeed are already defined in selenium-api.js,\n * so we're defining these functions in a tricky way so that doc.js doesn't\n * try to read API doc from the function definitions here.\n */\nSelenium.prototype._doSetSpeed = function(value) {\n    var milliseconds = parseInt(value);\n    if (milliseconds < 0) milliseconds = 0;\n    htmlTestRunner.controlPanel.speedController.setValue(milliseconds);\n    htmlTestRunner.controlPanel.setRunInterval(milliseconds);\n}\nSelenium.prototype.doSetSpeed = Selenium.prototype._doSetSpeed;\n\nSelenium.prototype._getSpeed = function() {\n    return htmlTestRunner.controlPanel.runInterval;\n}\nSelenium.prototype.getSpeed = Selenium.prototype._getSpeed;\n\nSelenium.prototype.assertSelected = function(selectLocator, optionLocator) {\n    /**\n     * Verifies that the selected option of a drop-down satisfies the optionSpecifier.  <i>Note that this command is deprecated; you should use assertSelectedLabel, assertSelectedValue, assertSelectedIndex, or assertSelectedId instead.</i>\n     *\n     * <p>See the select command for more information about option locators.</p>\n     *\n     * @param selectLocator an <a href=\"#locators\">element locator</a> identifying a drop-down menu\n     * @param optionLocator an option locator, typically just an option label (e.g. \"John Smith\")\n     */\n    var element = this.page().findElement(selectLocator);\n    var locator = this.optionLocatorFactory.fromLocatorString(optionLocator);\n    if (element.selectedIndex == -1)\n    {\n        Assert.fail(\"No option selected\");\n    }\n    locator.assertSelected(element);\n};\n\nSelenium.prototype.assertFailureOnNext = function(message) {\n    /**\n     * Tell Selenium to expect a failure on the next command execution. \n     * @param message The failure message we should expect.  This command will fail if the wrong failure message appears.\n     */\n    if (!message) {\n        throw new SeleniumError(\"Message must be provided\");\n    }\n\n    currentTest.expectedFailure = message;\n    currentTest.expectedFailureType = \"failure\";\n    currentTest.expectedFailureJustSet = true;\n};\n\nSelenium.prototype.assertErrorOnNext = function(message) {\n    /**\n     * Tell Selenium to expect an error on the next command execution. \n     * @param message The error message we should expect.  This command will fail if the wrong error message appears.\n     */\n     // This command temporarily installs a CommandFactory that generates\n     // CommandHandlers that expect an error.\n    if (!message) {\n        throw new SeleniumError(\"Message must be provided\");\n    }\n\n    currentTest.expectedFailure = message;\n    currentTest.expectedFailureType = \"error\";\n    currentTest.expectedFailureJustSet = true;\n};\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-version.js",
    "content": "Selenium.version = \"1.0-beta-2\";\nSelenium.revision = \"2330\";\n\nwindow.top.document.title += \" v\" + Selenium.version + \" [\" + Selenium.revision + \"]\";\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/ui-doc.html",
    "content": "<html>\n<head>\n<title>Selenium UI-Element Reference</title>\n<style type=\"text/css\">\nbody {\n    margin-left: 5%;\n    margin-right: 5%;\n}\ndt {\n    font-weight: bolder;\n}\ndd {\n    margin-top: 10px;\n    margin-bottom: 10px;\n}\npre {\n    margin: 10px;\n    padding: 10px;\n    background-color: #eaeaea;\n}\ncode {\n    padding: 2px;\n    background-color: #dfd;\n}\ntable {\n    border-collapse: collapse;\n    border: solid 1px black;\n}\nth, td {\n    border: solid 1px grey;\n    padding: 5px;\n}\n.highlight {\n    background-color: #eea;\n}\n.deprecated {\n    font-style: italic;\n    color: #c99;\n}\n</style>\n</head>\n\n<body>\n\n<h1>Selenium UI-Element Reference</h1>\n\n<h2>Introduction</h2>\n\n<p>UI-Element is a Selenium feature that makes it possible to define a mapping between semantically meaningful names of elements on webpages, and the elements themselves. The mapping is defined using <a href=\"http://en.wikipedia.org/wiki/JSON\">JavaScript Object Notation</a>, and may be shared both by the IDE and tests run via Selenium RC. It also offers a single point of update should the user interface of the application under test change.</p>\n\n<h2>Terminology</h2>\n\n<dl>\n<dt>Page</dt>\n<dd>A unique URL, and the contents available by accessing that URL. A page typically consists of several interactive page elements. A page may also be considered a DOM document object, complete with URL information.</dd>\n<dt>Page element</dt>\n<dd>An element on the actual webpage. Generally speaking, an element is anything the user might interact with, or anything that contains meaningful content. More specifically, an element is realized as a <a href=\"http://en.wikipedia.org/wiki/Document_Object_Model\">Document Object Model (DOM)</a> node and its contents. So when we refer to a page element, we mean both of the following, at the same time:\n<ul>\n<li>something on the page</li>\n<li>its DOM representation, including its relationship with other page elements</li>\n</ul>\n</dd>\n<dt>Pageset</dt>\n<dd>A set of pages that share some set of common page elements. For example, I might be able to log into my application from several different pages. If certain page elements on each of those pages appear similarly (i.e. their DOM representations are identical), those pages can be grouped into a pageset with respect to these page elements. There is no restriction on how many pagesets a given page can be a member of. Similarly, a UI element belong to multiple pagesets. A pageset is commonly represented by a <a href=\"http://en.wikipedia.org/wiki/Regular_expression\">regular expression</a> which matches the URL's that uniquely identify pages; however, there are cases when the page content must be considered to determine pageset membership. A pageset also has a name.</dd>\n<dt>UI element</dt>\n<dd>A mapping between a meaningful name for a page element, and the means to locate that page element's DOM node. The page element is located via a locator. UI elements belong to pagesets.</dd>\n<dt>UI argument</dt>\n<dd>An optional piece of logic that determines how the locator is generated by a UI element. Typically used when similar page elements appear multiple times on the same page, and you want to address them all with a single UI element. For example, if a page presents 20 clickable search results, the index of the search result might be a UI argument.</dd>\n<dt>UI map</dt>\n<dd>A collection of pagesets, which in turn contain UI elements. The UI map is the medium for translating between UI specifier strings, page elements, and UI elements.</dd>\n<dt>UI specifier string</dt>\n<dd>A bit of text containing a pageset name, a UI element name, and optionally arguments that modify the way a locator is constructed by the UI element. UI specifier strings are intended to be the human-readable identifier for page elements.</dd>\n<dt>Rollup rule</dt>\n<dd>Logic that describes how one or more Selenium commands can be grouped into a single command, and how that single command may be expanded into its component Selenium commands. The single command is referred to simply as a \"rollup\".</dd>\n<dt>Command matcher</dt>\n<dd>Typically folded into a rollup rule, it matches one or more Selenium commands and optionally sets values for rollup arguments based on the matched commands. A rollup rule usually has one or more command matchers.</dd>\n<dt>Rollup argument</dt>\n<dd>An optional piece of logic that modifies the command expansion of a rollup.</dd>\n</dl>\n\n<h2>The Basics</h2>\n\n<h3>Getting Motivated</h3>\n\n<p>Question: Why use UI-Element? Answer: So your testcases can look like this (boilerplate code omitted):</p>\n\n<pre>\n&lt;tr&gt;\n    &lt;td&gt;open&lt;/td&gt;\n    &lt;td&gt;/&lt;/td&gt;\n    &lt;td&gt;&lt;/td&gt;\n&lt;/tr&gt;\n&lt;tr&gt;\n    &lt;td&gt;clickAndWait&lt;/td&gt;\n    &lt;td&gt;<span class=\"highlight\">ui=allPages::section(section=topics)</span>&lt;/td&gt;\n    &lt;td&gt;&lt;/td&gt;\n&lt;/tr&gt;\n&lt;tr&gt;\n    &lt;td&gt;clickAndWait&lt;/td&gt;\n    &lt;td&gt;<span class=\"highlight\">ui=topicListingPages::topic(topic=Process)</span>&lt;/td&gt;\n    &lt;td&gt;&lt;/td&gt;\n&lt;/tr&gt;\n&lt;tr&gt;\n    &lt;td&gt;clickAndWait&lt;/td&gt;\n    &lt;td&gt;<span class=\"highlight\">ui=subtopicListingPages::subtopic(subtopic=Creativity)</span>&lt;/td&gt;\n    &lt;td&gt;&lt;/td&gt;\n&lt;/tr&gt;\n&lt;tr&gt;\n    &lt;td&gt;click&lt;/td&gt;\n    &lt;td&gt;<span class=\"highlight\">ui=subtopicArticleListingPages::article(index=2)</span>&lt;/td&gt;\n    &lt;td&gt;&lt;/td&gt;\n&lt;/tr&gt;\n</pre>\n\n<h3>Including the Right Files</h3>\n\n<p>UI-Element is now fully integrated with Selenium. The only additional file that needs to be specified is your map definitions file. In the IDE, add it to the comma-delimited <em>Selenium Core extensions</em> field of the IDE options. A sample definition file created for the website <a href=\"http://alistapart.com\">alistapart.com</a> is included in the distribution and is available here:</p>\n\n<pre><a href=\"chrome://selenium-ide/content/selenium/scripts/ui-map-sample.js\">chrome://selenium-ide/content/selenium/scripts/ui-map-sample.js</a></pre>\n\n<p>You might want to experiment with the sample map to get a feel for UI-Element. For the Selenium RC, you have two options. The map file may be included in the <code>user-extensions.js</code> file specified at startup with the <code>-userExtensions</code> switch. Or, you may load it dynamically with the variant of the <code>setUserExtensionJs</code> command in your driver language, before the browser is started.</p>\n\n<h3>Map Definitions File Syntax</h3>\n\n<p>This is the general format of a map file:</p>\n\n<pre>\nvar map = new UIMap();\n\nmap.addPageset({\n    name: 'aPageset'\n    , ... \n});\nmap.addElement('aPageset', { ... });\nmap.addElement('aPageset', { ... });\n...\n\nmap.addPageset({\n    name: 'anotherPageset'\n    , ... \n});\n...\n</pre>\n\n<p>The map object is initialized by creating a new <code>UIMap</code> object. Next, a pageset is defined. Then one or more UI elements are defined for that pageset. More pagesets are defined, each with corresponding UI elements. That's it!</p>\n\n<h3>Pageset Shorthand</h3>\n\n<p>The method signature of <code>addPageset()</code> is <em>(pagesetShorthand)</em>. <em>pagesetShorthand</em> is a JSON description of the pageset. Here's a minimal example:</p>\n\n<pre>\nmap.addPageset({\n    name: 'allPages'\n    , description: 'contains elements common to all pages'\n    , pathRegexp: '.*'\n});\n</pre>\n    \n<p>Here's a table containing information about the attributes of the Pageset object. The conditionally required or unrequired items are for IDE recording support only.</p>\n\n<table>\n<tr><th>Name</th>\n    <th>Required?</th>\n    <th>Description</th>\n    <th>Example</th>\n</tr>\n<tr><td>name</td>\n    <td>Yes</td>\n    <td>(String) the name of the pageset. This should be unique within the map.</td>\n    <td><pre>name: 'shopPages'</pre></td>\n</tr>\n<tr><td>description</td>\n    <td>Yes</td>\n    <td>(String) a description of the pageset. Ideally, this will give the reader an idea of what types of UI elements the pageset will have.</td>\n    <td><pre>description: 'all pages displaying product'</pre></td>\n</tr>\n<tr><td>pathPrefix</td>\n    <td>No</td>\n    <td>(String) the path of the URL of all included pages in this pageset will contain this prefix. For example, if all pages are of the form http://www.example.com/<span class=\"highlight\">gallery/</span>light-show/, the page prefix might be <code>gallery/</code> .</td>\n    <td><pre>pathPrefix: 'gallery/'</pre></td>\n</tr>\n<tr><td>paths<br />pathRegexp</td>\n    <td>Conditional</td>\n    <td>(Array | String) either a list of path strings, or a string that represents a regular expression. One or the other should be defined, but not both. If an array, it enumerates pages that are included in the pageset. If a regular expression, any pages whose URL paths match the expression are considered part of the pageset. In either case, the part of the URL being matched (called the <em>path</em>) is the part following the domain, less any training slash, and not including the CGI parameters. For example:\n    <ul>\n    <li>http://www.example.com/<span class=\"highlight\">articles/index.php</span></li>\n    <li>http://www.example.com/<span class=\"highlight\">articles/2579</span>?lang=en_US</li>\n    <li>http://www.example.com/<span class=\"highlight\">articles/selenium</span>/</li>\n    </ul>\n     The entire path must match (however, <code>pathPrefix</code> is taken into account if specified). If specified as a regular expression, the two regular expression characters <code>^</code> and <code>$</code> marking the start and end of the matched string are included implicitly, and should not be specified in this string. Please notice too that backslashes must be backslash-escaped in javascript strings.</td>\n    <td><pre>paths: [\n    'gotoHome.do'\n    , 'gotoAbout.do'\n    , 'gotoFaq.do'\n]</pre>\n        <pre>pathRegexp: 'goto(Home|About|Faq)\\\\.do'</pre>\n</tr>\n<tr><td>paramRegexps</td>\n    <td>No</td>\n    <td>(Object) a mapping from URL parameter names to regular expression strings which must match their values. If specified, the set of pages potentially included in this pageset will be further filtered by URL parameter values. There is no filtering by parameter value by default.</td>\n    <td><pre>paramRegexps: {\n    dept: '^[abcd]$'\n    , team: 'marketing'\n}</pre></td>\n</tr>\n<tr><td>pageContent</td>\n    <td>Conditional</td>\n    <td><p>(Function) a function that tests whether a page, represented by its document object, is contained in the pageset, and returns true if and only if this is the case. If specified, the set of pages potentially included in this pageset will be further filtered by content, after URL and URL parameter filtering.</p>\n    <p>Since the URL is available from the document object (<code>document.location.href</code>), you may encode the logic used for the <code>paths</code> and <code>pathRegexp</code> attributes all into the definition of <code>pageContent</code>. Thus, you may choose to omit the former if and only if using <code>pageContent</code>. Of course, you may continue to use them for clarity.</td>\n    <td><pre>pageContent: function(doc) {\n    var id = 'address-tab';\n    return doc.getElementById(id) != null;\n}</pre></td>\n</tr>\n</table>\n\n<h3><a name=\"ui-element-shorthand\">UI-Element Shorthand</a></h3>\n\n<p>The method signature of <code>addElement()</code> is <em>(pagesetName, uiElementShorthand)</em>. <em>pagesetName</em> is the name of the pageset the UI element is being added to. <em>uiElementShorthand</em> is a complete JSON description of the UI element object in shorthand notation.</p>\n\n<p>In its simplest form, a UI element object looks like this:</p>\n\n<pre>\nmap.addElement('allPages', {\n    name: 'about_link'\n    , description: 'link to the about page'\n    , locator: \"//a[contains(@href, 'about.php')]\"\n});\n</pre>\n\n<p>Here's a table containing information about the attributes of the UI element object. The asterisk (<code>*</code>) means any string:</p>\n\n<table>\n<tr><th>Name</th>\n    <th>Required?</th>\n    <th>Description</th>\n    <th>Example</th>\n</tr>\n<tr><td>name</td>\n    <td>Yes</td>\n    <td>(String) the name of the UI element</td>\n    <td><pre>name: 'article'</pre></td>\n</tr>\n<tr><td>description</td>\n    <td>Yes</td>\n    <td>(String) a description of the UI element. This is the main documentation for this UI element, so the more detailed, the better.</td>\n    <td><pre>description: 'front or issue page link to article'</pre></td>\n</tr>\n<tr><td>args</td>\n    <td>No</td>\n    <td>(Array) a list of arguments that modify the <code>getLocator()</code> method. If unspecified, it will be treated as an empty list.</td>\n    <td><pre>[\n    { name: 'index'\n    , description: 'the index of the author, by article'\n    , defaultValues: range(1, 5) }\n]</pre><em>See section below elaborating on attributes of argument objects.</em></td>\n</tr>\n<tr><td>locator<br />getLocator()<br /><span class=\"deprecated\">xpath</span<br /><span class=\"deprecated\">getXPath()</span></td>\n    <td>Yes</td>\n    <td><p>(String | Function) either a fixed locator string, or a function that returns a locator string given a set of arguments. One or the other should be defined, but not both. Under the sheets, the <code>locator</code> attribute eventually gets transcripted as a <code>getLocator()</code> function.</p><p><span class=\"deprecated\">As of ui0.7, <code>xpath</code> and <code>getXPath()</code> have been deprecated. They are still supported for backward compatibility.</span></p></td>\n    <td><pre>locator: 'submit'</pre>\n        <pre>getLocator: function(args) {\n    return 'css=div.item:nth-child(' + args.index + ')'\n        + ' > h5 > a';\n}</pre>\n        <pre>getLocator: function(args) {\n    var label = args.label;\n    var id = this._idMap[label];\n    return '//input[@id=' + id.quoteForXPath() + ']';\n}</pre></td>\n<tr><td>genericLocator<br />getGenericLocator</td>\n    <td>No</td>\n    <td><p>(String | Function) either a fixed locator string, or a function that returns a locator string. If a function, it should take no arguments.</p><p>You may experience some slowdown when recording on pages where individual UI elements have many default locators (due to many permutations of default values over multiple arguments). This is because each default locator is potentially evaluated and matched against the interacted page element. This becomes especially problematic if several UI elements have this characteristic.</p><p>By specifying a generic locator, you give the matching engine a chance to skip over UI elements that definitely don't match. The default locators for skipped elements will not be evaluated unless the generic locator matches the interacted page element..</p></td>\n    <td><pre>genericLocator: \"//table[@class='ctrl']\"\n    + \"/descendant::input\"</pre>\n        <pre>getGenericLocator: function() {\n    return this._xpathPrefix + '/descendant::a';\n}</pre>\n</tr>\n<tr><td>getOffsetLocator</td>\n    <td>No</td>\n    <td><p>(Function) a function that returns an offset locator. The locator is offset from the element identified by a UI specifier string. The function should take this element, and the interacted page element, as arguments, and have the method signature <code>getOffsetLocator(locatedElement, pageElement)</code>. If an offset locator can't be found, a value that evaluates to <code>false</code> must be returned.</p><p>A convenient default function <code>UIElement.defaultOffsetLocatorStrategy</code> is provided so you don't have to define your own. It uses several typical strategies also employed by the IDE recording when recording normally. See the Advanced Topics section below for more information on offset locators.</p></td>\n    <td><pre>getOffsetLocator: <span class=\"highlight\">UIElement.defaultOffsetLocatorStrategy</span></pre>\n        <pre>getOffsetLocator:\n    function(locatedElement, pageElement) {\n    if (pageElement.parentNode == locatedElement) {\n        return '/child::' + pageElement.nodeName;\n    }\n    return null;\n}</pre></td>\n<tr><td>testcase*</td>\n    <td>No</td>\n    <td>(Object) a testcase for testing the implementation of the <code>getLocator()</code> method. As many testcases as desired may be defined for each UI element. They must all start with the string \"testcase\".</td>\n    <td><pre>testcase1: {\n    xhtml: '&lt;div class=\"item\"&gt;&lt;h5&gt;'\n        + '&lt;a expected-result=\"1\" /&gt;&lt;/h5&gt;&lt;/div&gt;'\n}</pre><em>See section below elaborating on testcases.</em></td>\n</tr>\n<tr><td>_*</td>\n    <td>No</td>\n    <td>(Any data type) a \"local variable\" declared for the UI element. This variable will be available both within the <code>getLocator()</code> method of the UI element, and any <code>getDefaultValues()</code> methods of the arguments via the <code>this</code> keyword. They must all start with an underscore \"_\".</td>\n    <td><pre>_labelMap: {\n    'Name': 'user'\n    , 'Email': 'em'\n    , 'Phone': 'tel'\n}</pre></td>\n</tr>\n</table>\n\n<h3>UI-Argument Shorthand</h3>\n\n<p>UI arguments are defined as part of UI elements, and help determine how an XPath is generated. A list of arguments may be defined within the UI element JSON shorthand. Here's an example of how that might look:</p>\n\n<pre>\nmap.addElement('searchPages', {\n    name: 'result'\n    , description: 'link to a result page'\n    , args: [\n        {\n            name: 'index'\n            , description: 'the index of the search result'\n            , defaultValues: range(1, 21)\n        }\n        , {\n            name: 'type'\n            , description: 'the type of result page'\n            , defaultValues: [ 'summary', 'detail' ]\n        }\n    ]\n    , getLocator: function(args) {\n        var index = args['index'];\n        var type = args['type'];\n        return \"//div[@class='result'][\" + index + \"]\"\n            + \"/descendant::a[@class='\" + type + \"']\";\n    }\n});\n</pre>\n\n<p>In the above example, two arguments are defined, <code>index</code> and <code>type</code>. Metadata is provided to describe them, and default values are also specified. FInally, the <code>getLocator()</code> method is defined. The behavior of the method depends on the values of the arguments that are passed in.</p>\n\n<p>Default values come into play when recording tests using the Selenium IDE. When you interact with a page element in recording mode, the IDE uses all the locator strategies at its disposal to deduce an appropriate locator string for that element. UI-Element introduces a new <code>ui</code> locator strategy. When applying this strategy using a particular UI element, Selenium generates a list of XPaths to try by permuting the arguments of that UI element over all default values. Here, the default values <em>{ 1, 2, 3, 4 .. 20 }</em> are given for the <code>index</code> argument using the special <code>range()</code> function, and the values <em>{ summary, detail }</em> are given for the <code>type</code> argument in standard javascript array notation. If you don't intend to use the IDE, go ahead and set the default values to the empty array <code>[]</code>.</p>\n\n<p>Here's a table containing information about the attributes of the UI argument object.</p>\n\n<table>\n<tr><th>Name</th>\n    <th>Required?</th>\n    <th>Description</th>\n    <th>Example</th>\n</tr>\n<tr><td>name</td>\n    <td>Yes</td>\n    <td>(String) the name of the argument. This will be the name of the property of the object passed into the parent UI element's <code>getLocator()</code> method containing the argument value.</td>\n    <td><pre>name: 'index'</pre></td>\n</tr>\n<tr><td>description</td>\n    <td>Yes</td>\n    <td>(String) a description for the argument.</td>\n    <td><pre>description: 'the index of the article'</pre></td>\n</tr>\n<tr><td>defaultValues<br/>getDefaultValues()</td>\n    <td>Yes</td>\n    <td><p>(Array | Function) either an array of string or numerical values, or a function that returns an array of string or numerical values. One or the other should be defined, but not both. Under the sheets, the <code>defaultValues</code> attribute eventually gets transcripted as a <code>getDefaultValues()</code> function.</p><p>The method signature of the function is <code>getDefaultValues(inDocument)</code>. <code>inDocument</code> is the current document object of the page at time of recording. In cases where the default values are known a priori, <code>inDocument</code> need not be used. If the default values of all arguments of a UI element are known a priori, the list of default locators for the element may be precalculated, resulting in better performance. If <code>inDocument</code> is used, in cases where the current document is inspected for valid values, the element's default locators are calculated once for every recordable event.</p></td>\n    <td><pre>defaultValues: [ 'alpha', 'beta', 'unlimited' ]</pre>\n        <pre>getDefaultValues: function() {\n    return keys(this._idMap);\n}</pre>\n        <pre>getDefaultValues: function(inDocument) {\n    var defaultValues = [];\n    var links = inDocument\n        .getElementsByTagName('a');\n    for (var i = 0; i < links.length; ++i) {\n        var link = links[i];\n        if (link.className == 'category') {\n            defaultValues.push(link.innerHTML);\n        }\n    }\n    return defaultValues;\n}</pre></td>\n</tr>\n</table>\n\n<h3>About <code>this</code></h3>\n\n<p>You may have noticed usage of the <code>this</code> keyword in the examples above, specifically in the <code>getLocator()</code> and <code>getDefaultValues()</code> methods. Well, what exactly is <code>this</code>?</p>\n\n<p>The answer is: it depends. The object referred to by <code>this</code> changes depending on the context in which it is being evaluated. At the time of object creation using <code>addPageset()</code> or <code>addElement()</code>, it refers to the <code>window</code> object of the Selenium IDE, which isn't useful at all. However, subsequently any time <code>getLocator()</code> is called, its <code>this</code> references the UI element object it's attached too. Thus, using <code>this</code>, any \"local variables\" defined for the UI element may be accessed. Similarly, when <code>getDefaultValues()</code> is called, its <code>this</code> references the UI argument object it's attached too. But ... what \"local variables\" are accessible by the from <code>getDefaultValues()</code>?</p>\n\n<p>There's a little magic here. If you defined your local variables as prescribed in the above <a href=\"#ui-element-shorthand\">UI-Element Shorthand</a> section, starting with an underscore, those variable are automatically made available to the UI argument via its <code>this</code> keyword. Note that this isn't standard javascript behavior. It's implemented this way to clear out clutter in the method definitions and to avoid the use of global variables for lists and maps used within the methods. It is sometimes useful, for example, to define an object that maps human-friendly argument values to DOM element <code>id</code>'s. In such a case, <code>getDefaultValues()</code> can be made to simply return the <code>keys()</code> (or property names) of the map, while the <code>getLocator()</code> method uses the map to retrieve the associated <code>id</code> to involve in the locator.</p>\n\n<p>Also note that <code>this</code> only behaves this way in the two mentioned methods, <code>getLocator()</code> and <code>getDefaultValues()</code>; in other words you can't reference the UI element's local variables using <code>this</code> outside of methods.</p>\n\n<p>If you're interested, here's some <a href=\"http://www.digital-web.com/articles/scope_in_javascript/\">additional reading on javascript scope</a>.</p>\n\n<h2>Advanced Topics</h2>\n\n<h3>Testcases</h3>\n\n<p>You can write testcases for your UI element implementations that are run every time the Selenium IDE is started. Any testcases that fail are reported on. The dual purpose of writing testcases is to both validate the <code>getLocator()</code> method against a representation of the real page under test, and to give a visual example of what the DOM context of a page element is expected to be.</p>\n\n<p>A testcase is an object with a required <code>xhtml</code> property (String), and a required <code>args</code> property (Object). An example is due:</p>\n\n<pre>\ntestcase1: {\n    args: { line: 2, column: 3 }\n    , xhtml: '&lt;table id=\"scorecard\"&gt;'\n        + '&lt;tr class=\"line\" /&gt;'\n        + '&lt;tr class=\"line\"&gt;&lt;td /&gt;&lt;td /&gt;&lt;td expected-result=\"1\" /&gt;&lt;/tr&gt;'\n        + '&lt;/table&gt;'\n}\n</pre>\n\n<p>The <code>args</code> property specifies the object to be passed into the UI element's <code>getLocator()</code> method to generate the test locator, which is then applied to the <code>xhtml</code>. If evaluating the locator on the XHTML document returns a DOM node with the <code>expected-result</code> attribute, the testcase is considered to have passed.</p>\n\n<p>The <code>xhtml</code> property must represent a complete XML document, sans <code>&lt;html&gt;</code> tags, which are automatically added. The reason this is necessary is that the text is being converted into an XPath evaluable DOM tree via Mozilla's native XML parser. Unfortunately, there is no way to generate a simple HTML document, only XML documents. This means that the content of the <code>xhtml</code> must be well-formed. <span class=\"highlight\">Tags should also be specified in lowercase.</span></p>\n\n<h3>Fuzzy Matching</h3>\n\n<p>Here's a real-world example of where fuzzy matching is important:</p>\n\n<pre>\n&lt;table&gt;\n&lt;tr onclick=\"showDetails(0)\"&gt;\n    &lt;td&gt;Brahms&lt;/td&gt;\n    &lt;td&gt;Viola Quintet&lt;/td&gt;\n&lt;/tr&gt;\n&lt;tr onclick=\"showDetails(1)\"&gt;\n    &lt;td&gt;Saegusa&lt;/td&gt;\n    &lt;td&gt;Cello 88&lt;/td&gt;\n&lt;/tr&gt;\n&lt;/table&gt;\n</pre>\n\n<p>Imagine I'm recording in the IDE. Let's say I click on \"Cello 88\". The IDE would create locator for this action like <code>//table/tr[2]/td[2]</code>. Does that mean that my <code>getLocator()</code> method should return the same XPath?</p>\n\n<p>Clearly not. Clicking on either of the table cells for the second row has the same result. I would like my UI element generated XPath to be <code>//table/tr[2]</code> . However, when recording, the page element that was identified as being acted upon was the table cell, which doesn't match my UI element XPath, so the <code>ui</code> locator strategy will fail to auto-populate. What to do?</p>\n\n<p>Fuzzy matching to the rescue! Fuzzy matching is realized as a fuzzy matcher function that returns true if a target DOM element is considered to be equivalent to a reference DOM element. The reference DOM element would be the element specified by the UI element's generated XPath. Currently, the fuzzy matcher considers it a match if:\n\n<ul>\n<li>the elements are the same element,</li>\n<li>the reference element is an anchor (<code>&lt;a&gt;</code>) element, and the target element is a descendant of it; or</li>\n<li>the reference element has an <code>onclick</code> attribute, and the target element is a descendant of it.</li>\n</ul>\n\n<p>This logic may or may not be sufficient for you. The good news is, it's very easy to modify. Look for the definition of <code>BrowserBot.prototype.locateElementByUIElement.is_fuzzy_match</code> in <code>ui-element.js</code> .</p>\n\n<h3>Offset Locators</h3>\n\n<p>Offset locators are locators that are appended to UI specifier strings to form composite locators. They can be automatically deduced by the IDE recorder for UI elements that have specified a <code>getOffsetLocator</code> function. This feature may be useful if your pages contain too many elements to write UI elements for. In this case, offset locators allow you to define UI elements that \"anchor\" other elements. Given the following markup:</p>\n\n<pre>&lt;form name=\"contact_info\"&gt;\n    &lt;input type=\"text\" name=\"foo\" /&gt;\n    &lt;textarea name=\"bar\"&gt;&lt;/textarea&gt;\n    &lt;input type=\"submit\" value=\"baz\" /&gt;\n&lt;/form&gt;</pre>\n\n<p>Assume that a UI element has been defined for the form element. Then the following locators containing offset locators and \"anchored\" off this element would be recorded using the default offset locator function (<code>UIElement.defaultOffsetLocatorStrategy</code>):</p>\n\n<pre>ui=contactPages::contact_form()<span class=\"highlight\">->//input[@name='foo']</span>\nui=contactPages::contact_form()<span class=\"highlight\">->//textarea[@name='bar']</span>\nui=contactPages::contact_form()<span class=\"highlight\">->//input[@value='baz']</span></pre>\n\n<p>The character sequence <code>-&gt;</code> serves to delimit the offset locator from the main locator. For this reason, the sequence should not appear in the main locator, or else ambiguity will result.</p>\n\n<p>When recording with the IDE, no preference is given to matching plain vanilla UI specifier strings over ones that have offset locators. In other words, if a page element could be specified both by a UI specifier string for one UI element, and by one augmented by an offset locator for a different UI element, there is no guarantee that one or the other locator will be recorded.</p>\n\n<p>Currently, <span class=\"highlight\">only XPath is supported as an offset locator type</span>, as it is the only locator for which a context node can be specified at evaluation time. Other locator strategies may be supported in the future.</p>\n\n<h3>Rollup Rules</h3>\n\n<p>Question: Why use rollup rules? Answer: Remember the testcase from the \"Getting Motivated\" section above? With rollups, that testcase can be condensed into this:</p>\n\n<pre>\n&lt;tr&gt;\n    &lt;td&gt;open&lt;/td&gt;\n    &lt;td&gt;/&lt;/td&gt;\n    &lt;td&gt;&lt;/td&gt;\n&lt;/tr&gt;\n&lt;tr&gt;\n    &lt;td&gt;rollup&lt;/td&gt;\n    &lt;td&gt;<span class=\"highlight\">navigate_to_subtopic_article</span>&lt;/td&gt;\n    &lt;td&gt;<span class=\"highlight\">index=2, subtopic=Creativity</span>&lt;/td&gt;\n&lt;/tr&gt;\n</pre>\n\n<p>It's inevitable that certain sequences of Selenium commands will appear in testcases over and over again. When this happens, you might wish to group several fine-grained commands into a single coarser, more semantically meaningful action. In doing so, you would abstract out the execution details for the action, such that if they were to change at some point, you would have a single point of update. In UI-Element, such actions are given their own command, called <code>rollup</code>. In a sense, rollups are a natural extension of the <code>ui</code> locator.</p>\n\n<p>UI-Element is designed with the belief that the IDE can be a useful tool for writing testcases, and need not be shunned for lack of functionality. A corollary belief is that you should be able to drive your RC test in the language of your choice. The execution of the <code>rollup</code> command by the Selenium testrunner produces the component commands, which are executed in a new context, like a function call. The logic of the rollup \"expansion\" is written in javascript. Corresponding logic for inferring a rollup from a list of commands is also written in javascript. Thus, the logic can be incorporated into any of the family of Selenium products as a user extension. Most notably, the IDE is made viable as a testcase creation tool that understands both how rollups expand to commands, and also how rollup rules can be \"applied\" to commands to reduce them to rollups.</p>\n\n<p>Rollup rule definitions appear in this general format:</p>\n\n<pre>\nvar manager = new RollupManager();\n\nmanager.addRollupRule({ ... });\nmanager.addRollupRule({ ... });\n...\n</pre>\n\n<p>In a relatively simple form, a rollup rule looks like this:</p>\n\n<pre>\nmanager.addRollupRule({\n    name: 'do_search'\n    , description: 'performs a search'\n    , args: [\n        name: 'term'\n        , description: 'the search term'\n    ]\n    , commandMatchers: [\n        {\n            command: 'type'\n            , target: 'ui=searchPages::search_box\\\\(.+'\n            , updateArgs: function(command, args) {\n                var uiSpecifier = new UISpecifier(command.target);\n                args.term = uiSpecifier.args.term;\n                return args;\n            }\n        }\n        , {\n            command: 'click.+'\n            , target: 'ui=searchPages::search_go\\\\(.+'\n        }\n    ]\n    , getExpandedCommands: function(args) {\n        var commands = [];\n        var uiSpecifier = new UISpecifier(\n            'searchPages'\n            , 'search_box'\n            , { term: args.term });\n        commands.push({\n            command: 'type'\n            , target: 'ui=' + uiSpecifier.toString()\n        });\n        commands.push({\n            command: 'clickAndWait'\n            , target: 'ui=searchPages::search_go()'\n        });\n        return commands;\n    }\n});\n</pre>\n\n<p>In the above example, a rollup rule is defined for performing a search. The rule can be \"applied\" to two consecutive commands that match the <code>commandMatchers</code>. The rollup takes one argument, <code>term</code>, and expands back to the original two commands. One thing to note is that the second command matcher will match all commands starting with <code>click</code>. The rollup will expand that command to a <code>clickAndWait</code>.</p>\n\n<p>Here's a table containing information about the attributes of the rollup rule object.</p>\n\n<table>\n<tr><th>Name</th>\n    <th>Required?</th>\n    <th>Description</th>\n    <th>Example</th>\n</tr>\n<tr><td>name</td>\n    <td>Yes</td>\n    <td>(String) the name of the rollup rule. This will be the target of the resulting <code>rollup</code> command.</td>\n    <td><pre>name: 'do_login'</pre></td>\n</tr>\n<tr><td>description</td>\n    <td>Yes</td>\n    <td>(String) a description for the rollup rule.</td>\n    <td><pre>description: 'logs into the application'</pre></td>\n</tr>\n<tr><td>alternateCommand</td>\n    <td>No</td>\n    <td>(String) specifies an alternate usage of rollup rules to replace commands. This string is used to replace the command name of the first matched command.</td>\n    <td><pre>alternateCommand: 'clickAndWait'</pre></td>\n</tr>\n<tr><td>pre</td>\n    <td>No</td>\n    <td>(String) a detailed summary of the preconditions that must be satisfied for the rollup to execute successfully. This metadata is easily viewable in the IDE when the rollup command is selected.</td>\n    <td><pre>pre: 'the page contains login widgets'</pre></td>\n</tr>\n<tr><td>post</td>\n    <td>No</td>\n    <td>(String) a detailed summary of the postconditions that will exist after the rollup has been executed.</td>\n    <td><pre>post: 'the user is logged in, or is \\\ndirected to a login error page'</pre></td>\n</tr>\n<tr><td>args</td>\n    <td>Conditional</td>\n    <td><p>(Array) a list of arguments that are used to modify the rollup expansion. These are similar to UI arguments, with the exception that <code>exampleValues</code> are provided, instead of <code>defaultValues</code>. Here, example values are used for reference purposes only; they are displayed in the rollup pane in the IDE.</p><p>This attribute may be omitted if no <code>updateArgs()</code> functions are defined for any command matchers.</td>\n    <td><pre>args: {\n    name: 'user'\n    , description: 'the username to login as'\n    , exampleValues: [\n        'John Doe'\n        , 'Jane Doe'\n    ]\n}</pre></td>\n</tr>\n<tr><td>commandMatchers<br />getRollup()</td>\n    <td>Yes</td>\n    <td><p>(Array | Function) a list of command matcher definitions, or a function that, given a list of commands, returns either 1) a rollup command if the rule is considered to match the commands (starting at the first command); or 2) false. If a function, it should have the method signature <code>getRollup(commands)</code>, and the returned rollup command (if any) must have the <code>replacementIndexes</code> attribute, which is a list of array indexes indicating which commands in the <code>commands</code> parameter are to be replaced.</p>\n    <p>If you don't intend on using the IDE with your rollups, go ahead and set this to the empty array <code>[]</code>.</p></td>\n    <td><pre>commandMatchers: [\n    {\n        command: 'type'\n        , target: 'ui=loginPages::user\\\\(.+'\n        , value: '.+'\n        , minMatches: 1\n        , maxMatches: 1\n        , updateArgs:\n            function(command, args) {\n            args.user = command.value;\n            return args;\n        }\n    }\n]</pre>\n        <pre>// this is a simplistic example, roughy\n// equivalent to the commandMatchers\n// example above. The <span class=\"highlight\">to_kwargs()</span> function\n// is used to turn an arguments object into\n// a keyword-arguments string.\ngetRollup: function(commands) {\n    var command = commands[0];\n    var re = /^ui=loginPages::user\\(.+/;\n    if (command.command == 'type' &&\n        re.test(command.target) &&\n        command.value) {\n        var args = { user: command.value };\n        return {\n            command: 'rollup'\n            , target: this.name\n            , value: to_kwargs(args)\n            , replacementIndexes: [ 0 ]\n        };\n    }\n    return false;\n}</pre><em>See section below elaborating on command matcher objects.</em></td>\n</tr>\n<tr><td>expandedCommands<br />getExpandedCommands()</td>\n    <td>Yes</td>\n    <td><p>(Array | Function) a list of commands the rollup command expands into, or a function that, given an argument object mapping argument names to values, returns a list of expanded commands. If a function, it should have the method signature <code>getExpandedCommands(args)</code>.</p><p>Each command in the list of expanded commands should contain a <code>command</code> attribute, which is the name of the command, and optionally <code>target</code> and <code>value</code> attributes, depending on the type of command.</p><p>It is expected that providing a fixed list of expanded commands will be of limited use, as rollups will typically contain commands that have arguments, requiring more sophisticated logic to expand.</td>\n    <td><pre>expandedCommands: [\n    {\n        command: 'check'\n        , target: 'ui=termsPages::agree\\\\(.+'\n    }\n    , {\n        command: 'clickAndWait'\n        , target: 'ui=termsPages::submit\\\\(.+'\n    }\n]</pre>\n        <pre>getExpandedCommands: function(args) {\n    var commands = [];\n    commands.push({\n        command: 'type'\n        , target: 'ui=loginPages::user()'\n        , value: args.user\n    });\n    commands.push({\n        command: 'type'\n        , target: 'ui=loginPages::pass()'\n        , value: args.pass\n    });\n    commands.push({\n        command: 'clickAndWait'\n        , target: 'ui=loginPages::submit()'\n    });\n    commands.push({\n        command: 'verifyLocation'\n        , target: 'regexp:.+/home'\n    });\n    return commands;\n}</pre>\n        <pre>// if using alternateCommand\nexpandedCommands: []\n</pre></td>\n</tr>\n</table>\n\n<p>The user should be able to freely record commands in the IDE, which can be collapsed into rollups at any point by applying the defined rollup rules. Healthy usage of the <code>ui</code> locator makes commands easy to match using command matcher definitions. Command matchers simplify the specification of a command match. In basic usage, for a rollup rule, you might specify 3 command matchers: <em>M1</em>, <em>M2</em>, and <em>M3</em>, that you intend to match 3 corresponding commands, <em>C1</em>, <em>C2</em>, and <em>C3</em>. In more complex usage, a single command matcher might match more than one command. For example, <em>M1</em> matches <em>C1</em> and <em>C2</em>, <em>M2</em> matches <em>C3</em>, and <em>M3</em> matches <em>C4</em>, <em>C5</em>, and <em>C6</em>. In the latter case, you would want to track the matches by updating argument values in the command matchers' <code>updateArgs()</code> methods.</p>\n\n<p>Here are the required and optional fields for command matcher objects:</p>\n\n<table>\n<tr><th>Name</th>\n    <th>Required?</th>\n    <th>Description</th>\n    <th>Example</th>\n</tr>\n<tr><td>command</td>\n    <td>Yes</td>\n    <td>(String) a simplified regular expression string that matches the command name of a command. The special regexp characters <code>^</code> and <code>$</code> are automatically included at the beginning and end of the string, and therefore should not be explicitly provided.</td>\n    <td><pre>command: 'click.+'</pre>\n        <pre>command: 'rollup'</pre></td>\n</tr>\n<tr><td>target</td>\n    <td>Yes</td>\n    <td>(String) a simplified regular expression string that matches the target of a command. Same rules as for the <code>command</code> attribute.</td>\n    <td><pre>target: 'btnG'</pre>\n        <pre>// special regexp characters must be\n// escaped in regexp strings. Backslashes\n// always need to be escaped in javascript\n// strings.\ntarget: 'ui=loginPages::user\\\\(.+'\n    </pre></td>\n</tr>\n<tr><td>value</td>\n    <td>No</td>\n    <td>(String) a simplified regular expression string that matches the value of a command. Same rules as for the <code>command</code> attribute.</td>\n    <td><pre>value: '\\\\d+'</pre>\n        <pre>value: (?:foo|bar)</pre></td>\n</tr>\n<tr><td>minMatches</td>\n    <td>No</td>\n    <td>(Number) the minimum number of times this command matcher must match consecutive commands for the rollup rule to match a set of commands. If unspecified, the default is 1. If <code>maxMatches</code> is also specified, <code>minMatches</code> must be less than or equal to it.</td>\n    <td><pre>minMatches: 2</pre></td>\n</tr>\n<tr><td>maxMatches</td>\n    <td>No</td>\n    <td>(Number) the maximum number of times this command matcher is allowed to match consecutive commands for the rollup rule. If unspecified, the default is 1.</td>\n    <td><pre>maxMatches: 2</pre></td>\n</tr>\n<tr><td>updateArgs()</td>\n    <td>No</td>\n    <td><p>(Function) updates an arguments object when a match has been found, and returns the updated arguments object. This method is used to keep track of the way in which one or more commands were matched. When a rollup rule is successfully applied, any argument name-value pairs are stored as the rollup command's value. At time of expanding the rollup command, the command's value is converted back to an arguments object, which is passed to the rollup rule's <code>getExpandedCommands()</code> method.</p><p>This method must have the following method signature: <code>updateArgs(command, args)</code>, where <code>command</code> is the command object that was just matched, and <code>args</code> is the arguments object for the current trial application of the parent rollup rule.</td>\n    <td><pre>// reused from above\nupdateArgs: function(command, args) {\n    args.user = command.value;\n    return args;\n}</pre>\n        <pre>// for multiple matches\nupdateArgs: function(command, args) {\n    if (!args.clickCount) {\n        args.clickCount = 0;\n    }\n    ++args.clickCount;\n    return args;\n}</pre>\n        <pre>// another example from above (modified).\n// If you need to parse a UI specifier,\n// instantiate a new <span class=\"highlight\">UISpecifier</span> object with the\n// locator. To do it by the book, you should\n// first strip off the \"ui=\" prefix. If you just\n// want to inspect the UI specifier's args, you\n// can safely skip this step.\nupdateArgs: function(command, args) {\n    var s = command.target.replace(/^ui=/, '');\n    var uiSpecifier = new UISpecifier(s);\n    args.term = uiSpecifier.args.term;\n    return args;\n}</pre>\n        <pre>// example from sample map file. If you're\n// matching a rollup command that has arguments,\n// you'll want to parse them. The easiest way\n// to do this is with the <span class=\"highlight\">parse_kwargs()</span>\n// function, which has its roots in python.\nupdateArgs: function(command, args) {\n    var args1 = parse_kwargs(command.value);\n    args.subtopic = args1.subtopic;\n    return args;\n}</pre></td>\n</tr>\n</table>\n\n<p>Too much mumbo jumbo?</p>\n\n<p>To see rollup rules in action in the IDE, use the included sample map with UI-Element (see instructions above in the \"Including the Right Files\" section), and grab the listing of 4 commands from the \"Getting Motivated\" section, above. Under the <em>Source</em> tab of the IDE, paste the commands in between the <code>&lt;tbody&gt;</code> and <code>&lt;/tbody&gt;</code> tags. Now switch back to the <em>Table</em> tab, and click the new <span class=\"highlight\">purple spiral button</span>; this is the \"Apply rollup rules\" button. If done correctly, you should be prompted when rollup rule matches are found. Go ahead - go to the <a href=\"http://alistapart.com\">alistapart.com</a> site and try executing the rollups!</p>\n\n<h2>Release Notes</h2>\n\n<h3>Core-1.0</h3>\n\n<ul>\n<li>UI-Element is now completely integrated into Selenium Core.</li>\n<li>Added offset locators. Modified the delimiter to be <code>-&gt;</code>.</li>\n<li><code>getDefaultValues()</code> can dynamically construct a list of values and assume that a <code>document</code> object is being passed in.</li>\n<li>Arguments in UI specifier strings are presented in the same order as they are defined in the mapping file (no longer alphabetically).</li>\n<li>Allow generic locators to be specified, potentially improving recording performance when there are many UI arguments.</li>\n<li>Updated documentation.</li>\n<li>Many other fixes.</li>\n</ul>\n\n<h3>ui0.7</h3>\n\n<ul>\n<li>Changed extensions id and homepage to avoid conflicting with standard Selenium IDE distribution.</li>\n<li>Added rollup button.</li>\n<li>Added UI-Element and Rollup panes, with beautiful colors and formatting.</li>\n<li>Updated referenced version of Selenium Core to 0.8.3, and RC to 0.9.2 .</li>\n<li>Added <code>quoteForXPath()</code> to <code>String</code> prototype.</li>\n<li>Made XPath uppercasing much more robust. It is now backed by the ajaxslt library. Uppercasing is no longer required by UI-Element. It is used to demonstrate how XPath transformations may be used to improve XPath evaluation performance when using the javascript engine. See <a href=\"http://groups.google.com/group/google-ajax-discuss/browse_thread/thread/f7a7a2014a6415d4\">this thread on XPath performance</a>.\n<li>Added new <code>rollup</code> Selenium command and associated functionality with the RollupManager object.</li>\n<li>Deprecated <code>getXPath()</code> and <code>xpath</code> in favor of <code>getLocator()</code> and <code>locator</code> in the UI-Element shorthand. Testcases now work with locator types other than XPath (implicit, CSS, etc.).</li>\n<li>UI element testcases are now truly XHTML. All content is considered inner HTML of the html element, which is automatically generated. This supports the use of alternate locator types described in the above bullet.</li>\n<li>Global variables introduced by UI-Element are now properties of the variable <code>GLOBAL</code>. You can now name your map <code>uiMap</code> if you wish.</li>\n<li>Updated the sample map, including demonstration of implicit and CSS locators, Rollup Rules, and usage of <code>quoteForXPath()</code>.</li>\n<li>Improved auto-population of target dropdown with UI element locators and rollup names. The population logic is as follows: when a command is loaded from a file or inserted without having been recorded, all UI element locators are shown. After a command recorded or executed, only UI element locators for pagesets that match the page at time of recording or execution will be shown.</li>\n<li>Made UI element testcase args mandatory. This reduces the startup time for the IDE, and improves testcase readability.</li>\n<li>Updated documentation. Added this release notes section.</li>\n</ul>\n\n<h2>Final Thoughts</h2>\n\n<p>Catch UI-Element news in the <a href=\"http://ttwhy.org/home/blog/category/selenium/\">Selenium category of my blog</a>. You can also find me on the <a href=\"http://clearspace.openqa.org/people/gyrm\">OpenQA Forums</a>.</p>\n\n<p><em>- Haw-Bin Chai</em></p>\n\n</body>\n</html>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/ui-element.js",
    "content": "//******************************************************************************\n// Globals, including constants\n\nvar UI_GLOBAL = {\n    UI_PREFIX: 'ui'\n    , XHTML_DOCTYPE: '<!DOCTYPE html PUBLIC '\n        + '\"-//W3C//DTD XHTML 1.0 Strict//EN\" '\n        + '\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">'\n    , XHTML_XMLNS: 'http://www.w3.org/1999/xhtml'\n};\n\n//*****************************************************************************\n// Exceptions\n\nfunction UIElementException(message)\n{\n    this.message = message;\n    this.name = 'UIElementException';\n}\n\nfunction UIArgumentException(message)\n{\n    this.message = message;\n    this.name = 'UIArgumentException';\n}\n\nfunction PagesetException(message)\n{\n    this.message = message;\n    this.name = 'PagesetException';\n}\n\nfunction UISpecifierException(message)\n{\n    this.message = message;\n    this.name = 'UISpecifierException';\n}\n\nfunction CommandMatcherException(message)\n{\n    this.message = message;\n    this.name = 'CommandMatcherException';\n}\n\n//*****************************************************************************\n// UI-Element core\n\n/**\n * The UIElement object. This has been crafted along with UIMap to make\n * specifying UI elements using JSON as simple as possible. Object construction\n * will fail if 1) a proper name isn't provided, 2) a faulty args argument is\n * given, or 3) getLocator() returns undefined for a valid permutation of\n * default argument values. See ui-doc.html for the documentation on the\n * builder syntax.\n *\n * @param uiElementShorthand  an object whose contents conform to the\n *                            UI-Element builder syntax.\n *\n * @return  a new UIElement object\n * @throws  UIElementException\n */\nfunction UIElement(uiElementShorthand)\n{\n    // a shorthand object might look like:\n    //\n    // {\n    //     name: 'topic'\n    //     , description: 'sidebar links to topic categories'\n    //     , args: [\n    //         {\n    //             name: 'name'\n    //             , description: 'the name of the topic'\n    //             , defaultValues: topLevelTopics\n    //         }\n    //     ]\n    //     , getLocator: function(args) {\n    //         return this._listXPath +\n    //             \"/a[text()=\" + args.name.quoteForXPath() + \"]\";\n    //     }\n    //     , getGenericLocator: function() {\n    //         return this._listXPath + '/a';\n    //     }\n    //     // maintain testcases for getLocator()\n    //     , testcase1: {\n    //         // defaultValues used if args not specified\n    //         args: { name: 'foo' }\n    //         , xhtml: '<div id=\"topiclist\">'\n    //             + '<ul><li><a expected-result=\"1\">foo</a></li></ul>'\n    //             + '</div>'\n    //     }\n    //     // set a local element variable\n    //     , _listXPath: \"//div[@id='topiclist']/ul/li\"\n    // }\n    //\n    // name cannot be null or an empty string. Enforce the same requirement for\n    // the description.\n    \n    /**\n     * Recursively returns all permutations of argument-value pairs, given\n     * a list of argument definitions. Each argument definition will have\n     * a set of default values to use in generating said pairs. If an argument\n     * has no default values defined, it will not be included among the\n     * permutations.\n     *\n     * @param args            a list of UIArguments\n     * @param opt_inDocument  (optional)\n     * @return      a list of associative arrays containing key value pairs\n     */\n    this.permuteArgs = function(args, opt_inDocument) {\n        var permutations = [];\n        for (var i = 0; i < args.length; ++i) {\n            var arg = args[i];\n            var defaultValues = (arguments.length > 1)\n                ? arg.getDefaultValues(opt_inDocument)\n                : arg.getDefaultValues();\n            \n            // skip arguments for which no default values are defined\n            if (defaultValues.length == 0) {\n                continue;\n            }\n            for (var j = 0; j < defaultValues.length; ++j) {\n                var value = defaultValues[j];\n                var nextPermutations = this.permuteArgs(args.slice(i+1));\n                if (nextPermutations.length == 0) {\n                    var permutation = {};\n                    permutation[arg.name] = value + ''; // make into string\n                    permutations.push(permutation);\n                }\n                else {\n                    for (var k = 0; k < nextPermutations.length; ++k) {\n                        nextPermutations[k][arg.name] = value + '';\n                        permutations.push(nextPermutations[k]);\n                    }\n                }\n            }\n            break;\n        }\n        return permutations;\n    }\n    \n    \n    \n    /**\n     * Returns a list of all testcases for this UIElement.\n     */\n    this.getTestcases = function()\n    {\n        return this.testcases;\n    }\n    \n    \n    \n    /**\n     * Run all unit tests, stopping at the first failure, if any. Return true\n     * if no failures encountered, false otherwise. See the following thread\n     * regarding use of getElementById() on XML documents created by parsing\n     * text via the DOMParser:\n     *\n     * http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/2b1b82b3c53a1282/\n     */\n    this.test = function()\n    {\n        var parser = new DOMParser();\n        var testcases = this.getTestcases();\n        testcaseLoop: for (var i = 0; i < testcases.length; ++i) {\n            var testcase = testcases[i];\n            var xhtml = UI_GLOBAL.XHTML_DOCTYPE + '<html xmlns=\"'\n                + UI_GLOBAL.XHTML_XMLNS + '\">' + testcase.xhtml + '</html>';\n            var doc = parser.parseFromString(xhtml, \"text/xml\");\n            if (doc.firstChild.nodeName == 'parsererror') {\n                safe_alert('Error parsing XHTML in testcase \"' + testcase.name\n                    + '\" for UI element \"' + this.name + '\": ' + \"\\n\"\n                    + doc.firstChild.firstChild.nodeValue);\n            }\n            \n            // we're no longer using the default locators when testing, because\n            // args is now required\n            var locator = parse_locator(this.getLocator(testcase.args));\n            var results;\n            if (locator.type == 'xpath' || (locator.type == 'implicit' &&\n                locator.string.substring(0, 2) == '//')) {\n                // try using the javascript xpath engine to avoid namespace\n                // issues. The xpath does have to be lowercase however, it\n                // seems. \n                results = eval_xpath(locator.string, doc,\n                    { allowNativeXpath: false, returnOnFirstMatch: true });\n            }\n            else {\n                // piece the locator back together\n                locator = (locator.type == 'implicit')\n                    ? locator.string\n                    : locator.type + '=' + locator.string;\n                results = eval_locator(locator, doc);\n            }\n            if (results.length && results[0].hasAttribute('expected-result')) {\n                continue testcaseLoop;\n            }\n            \n            // testcase failed\n            if (is_IDE()) {\n                var msg = 'Testcase \"' + testcase.name\n                    + '\" failed for UI element \"' + this.name + '\":';\n                if (!results.length) {\n                    msg += '\\n\"' + locator + '\" did not match any elements!';\n                }\n                else {\n                    msg += '\\n' + results[0] + ' was not the expected result!';\n                }\n                safe_alert(msg);\n            }\n            return false;\n        }\n        return true;\n    };\n    \n    \n    \n    /**\n     * Creates a set of locators using permutations of default values for\n     * arguments used in the locator construction. The set is returned as an\n     * object mapping locators to key-value arguments objects containing the\n     * values passed to getLocator() to create the locator.\n     *\n     * @param opt_inDocument (optional) the document object of the \"current\"\n     *                       page when this method is invoked. Some arguments\n     *                       may have default value lists that are calculated\n     *                       based on the contents of the page.\n     *\n     * @return  a list of locator strings\n     * @throws  UIElementException\n     */\n    this.getDefaultLocators = function(opt_inDocument) {\n        var defaultLocators = {};\n        if (this.args.length == 0) {\n            defaultLocators[this.getLocator({})] = {};\n        }\n        else {\n            var permutations = this.permuteArgs(this.args, opt_inDocument);\n            if (permutations.length != 0) {\n                for (var i = 0; i < permutations.length; ++i) {\n                    var args = permutations[i];\n                    var locator = this.getLocator(args);\n                    if (!locator) {\n                        throw new UIElementException('Error in UIElement(): '\n                            + 'no getLocator return value for element \"' + name\n                            + '\"');\n                    }\n                    defaultLocators[locator] = args;\n                }\n            }\n            else {\n                // try using no arguments. If it doesn't work, fine.\n                try {\n                    var locator = this.getLocator();\n                    defaultLocators[locator] = {};\n                }\n                catch (e) {\n                    safe_log('debug', e.message);\n                }\n            }\n        }\n        return defaultLocators;\n    };\n    \n    \n    \n    /**\n     * Validate the structure of the shorthand notation this object is being\n     * initialized with. Throws an exception if there's a validation error.\n     *\n     * @param uiElementShorthand\n     *\n     * @throws  UIElementException\n     */\n    this.validate = function(uiElementShorthand)\n    {\n        var msg = \"UIElement validation error:\\n\" + print_r(uiElementShorthand);\n        if (!uiElementShorthand.name) {\n            throw new UIElementException(msg + 'no name specified!');\n        }\n        if (!uiElementShorthand.description) {\n            throw new UIElementException(msg + 'no description specified!');\n        }\n        if (!uiElementShorthand.locator\n            && !uiElementShorthand.getLocator\n            && !uiElementShorthand.xpath\n            && !uiElementShorthand.getXPath) {\n            throw new UIElementException(msg + 'no locator specified!');\n        }\n    };\n    \n    \n    \n    this.init = function(uiElementShorthand)\n    {\n        this.validate(uiElementShorthand);\n        \n        this.name = uiElementShorthand.name;\n        this.description = uiElementShorthand.description;\n        \n        // construct a new getLocator() method based on the locator property,\n        // or use the provided function. We're deprecating the xpath property\n        // and getXPath() function, but still allow for them for backwards\n        // compatability.\n        if (uiElementShorthand.locator) {\n            this.getLocator = function(args) {\n                return uiElementShorthand.locator;\n            };\n        }\n        else if (uiElementShorthand.getLocator) {\n            this.getLocator = uiElementShorthand.getLocator;\n        }\n        else if (uiElementShorthand.xpath) {\n            this.getLocator = function(args) {\n                return uiElementShorthand.xpath;\n            };\n        }\n        else {\n            this.getLocator = uiElementShorthand.getXPath;\n        }\n        \n        if (uiElementShorthand.genericLocator) {\n            this.getGenericLocator = function() {\n                return uiElementShorthand.genericLocator;\n            };\n        }\n        else if (uiElementShorthand.getGenericLocator) {\n            this.getGenericLocator = uiElementShorthand.getGenericLocator;\n        }\n        \n        if (uiElementShorthand.getOffsetLocator) {\n            this.getOffsetLocator = uiElementShorthand.getOffsetLocator;\n        }\n        \n        // get the testcases and local variables\n        this.testcases = [];\n        var localVars = {};\n        for (var attr in uiElementShorthand) {\n            if (attr.match(/^testcase/)) {\n                var testcase = uiElementShorthand[attr];\n                if (uiElementShorthand.args &&\n                    uiElementShorthand.args.length && !testcase.args) {\n                    safe_alert('No args defined in ' + attr + ' for UI element '\n                        + this.name + '! Skipping testcase.');\n                    continue;\n                } \n                testcase.name = attr;\n                this.testcases.push(testcase);\n            }\n            else if (attr.match(/^_/)) {\n                this[attr] = uiElementShorthand[attr];\n                localVars[attr] = uiElementShorthand[attr];\n            }\n        }\n        \n        // create the arguments\n        this.args = []\n        this.argsOrder = [];\n        if (uiElementShorthand.args) {\n            for (var i = 0; i < uiElementShorthand.args.length; ++i) {\n                var arg = new UIArgument(uiElementShorthand.args[i], localVars);\n                this.args.push(arg);\n                this.argsOrder.push(arg.name);\n\n                // if an exception is thrown when invoking getDefaultValues()\n                // with no parameters passed in, assume the method requires an\n                // inDocument parameter, and thus may only be invoked at run\n                // time. Mark the UI element object accordingly.\n                try {\n                    arg.getDefaultValues();\n                }\n                catch (e) {\n                    this.isDefaultLocatorConstructionDeferred = true;\n                }\n            }\n            \n        }\n        \n        if (!this.isDefaultLocatorConstructionDeferred) {\n            this.defaultLocators = this.getDefaultLocators();\n        }\n    };\n    \n    \n    \n    this.init(uiElementShorthand);\n}\n\n// hang this off the UIElement \"namespace\"\nUIElement.defaultOffsetLocatorStrategy = function(locatedElement, pageElement) {\n    if (is_ancestor(locatedElement, pageElement)) {\n        var offsetLocator;\n        var recorder = Recorder.get(locatedElement.ownerDocument.defaultView);\n        var builderNames = [\n            'xpath:link'\n            , 'xpath:img'\n            , 'xpath:attributes'\n            , 'xpath:idRelative'\n            , 'xpath:href'\n            , 'xpath:position'\n        ];\n        for (var i = 0; i < builderNames.length; ++i) {\n            offsetLocator = recorder.locatorBuilders\n                .buildWith(builderNames[i], pageElement, locatedElement);\n            if (offsetLocator) {\n                return offsetLocator;\n            }\n        }\n    }\n    return null;\n};\n\n\n\n/**\n * Constructs a UIArgument. This is mostly for checking that the values are\n * valid.\n *\n * @param uiArgumentShorthand\n * @param localVars\n *\n * @throws  UIArgumentException\n */\nfunction UIArgument(uiArgumentShorthand, localVars)\n{\n    /**\n     * @param uiArgumentShorthand\n     *\n     * @throws  UIArgumentException\n     */\n    this.validate = function(uiArgumentShorthand)\n    {\n        var msg = \"UIArgument validation error:\\n\"\n            + print_r(uiArgumentShorthand);\n        \n        // try really hard to throw an exception!\n        if (!uiArgumentShorthand.name) {\n            throw new UIArgumentException(msg + 'no name specified!');\n        }\n        if (!uiArgumentShorthand.description) {\n            throw new UIArgumentException(msg + 'no description specified!');\n        }\n        if (!uiArgumentShorthand.defaultValues &&\n            !uiArgumentShorthand.getDefaultValues) {\n            throw new UIArgumentException(msg + 'no default values specified!');\n        }\n    };\n    \n    \n    \n    /**\n     * @param uiArgumentShorthand\n     * @param localVars            a list of local variables\n     */\n    this.init = function(uiArgumentShorthand, localVars)\n    {\n        this.validate(uiArgumentShorthand);\n        \n        this.name = uiArgumentShorthand.name;\n        this.description = uiArgumentShorthand.description;\n        \n        if (uiArgumentShorthand.defaultValues) {\n            var defaultValues = uiArgumentShorthand.defaultValues;\n            this.getDefaultValues =\n                function() { return defaultValues; }\n        }\n        else {\n            this.getDefaultValues = uiArgumentShorthand.getDefaultValues;\n        }\n        \n        for (var name in localVars) {\n            this[name] = localVars[name];\n        }\n    }\n    \n    \n    \n    this.init(uiArgumentShorthand, localVars);\n}\n\n\n\n/**\n * The UISpecifier constructor is overloaded. If less than three arguments are\n * provided, the first argument will be considered a UI specifier string, and\n * will be split out accordingly. Otherwise, the first argument will be\n * considered the path.\n *\n * @param uiSpecifierStringOrPagesetName  a UI specifier string, or the pageset\n *                                        name of the UI specifier\n * @param elementName  the name of the element\n * @param args         an object associating keys to values\n *\n * @return  new UISpecifier object\n */\nfunction UISpecifier(uiSpecifierStringOrPagesetName, elementName, args)\n{\n    /**\n     * Initializes this object from a UI specifier string of the form:\n     *\n     *     pagesetName::elementName(arg1=value1, arg2=value2, ...)\n     *\n     * into its component parts, and returns them as an object.\n     *\n     * @return  an object containing the components of the UI specifier\n     * @throws  UISpecifierException\n     */\n    this._initFromUISpecifierString = function(uiSpecifierString) {\n        var matches = /^(.*)::([^\\(]+)\\((.*)\\)$/.exec(uiSpecifierString);\n        if (matches == null) {\n            throw new UISpecifierException('Error in '\n                + 'UISpecifier._initFromUISpecifierString(): \"'\n                + this.string + '\" is not a valid UI specifier string');\n        }\n        this.pagesetName = matches[1];\n        this.elementName = matches[2];\n        this.args = (matches[3]) ? parse_kwargs(matches[3]) : {};\n    };\n    \n    \n    \n    /**\n     * Override the toString() method to return the UI specifier string when\n     * evaluated in a string context. Combines the UI specifier components into\n     * a canonical UI specifier string and returns it.\n     *\n     * @return   a UI specifier string\n     */\n    this.toString = function() {\n        // empty string is acceptable for the path, but it must be defined\n        if (this.pagesetName == undefined) {\n            throw new UISpecifierException('Error in UISpecifier.toString(): \"'\n                + this.pagesetName + '\" is not a valid UI specifier pageset '\n                + 'name');\n        }\n        if (!this.elementName) {\n            throw new UISpecifierException('Error in UISpecifier.unparse(): \"'\n                + this.elementName + '\" is not a valid UI specifier element '\n                + 'name');\n        }\n        if (!this.args) {\n            throw new UISpecifierException('Error in UISpecifier.unparse(): \"'\n                + this.args + '\" are not valid UI specifier args');\n        }\n        \n        uiElement = UIMap.getInstance()\n            .getUIElement(this.pagesetName, this.elementName);\n        if (uiElement != null) {\n            var kwargs = to_kwargs(this.args, uiElement.argsOrder);\n        }\n        else {\n            // probably under unit test\n            var kwargs = to_kwargs(this.args);\n        }\n        return this.pagesetName + '::' + this.elementName + '(' + kwargs + ')';\n    };\n    \n    \n    \n    // construct the object\n    if (arguments.length < 2) {\n        this._initFromUISpecifierString(uiSpecifierStringOrPagesetName);\n    }\n    else {\n        this.pagesetName = uiSpecifierStringOrPagesetName;\n        this.elementName = elementName;\n        this.args = (args) ? clone(args) : {};\n    }\n}\n\n\n\nfunction Pageset(pagesetShorthand)\n{\n    /**\n     * Returns true if the page is included in this pageset, false otherwise.\n     * The page is specified by a document object.\n     *\n     * @param inDocument  the document object representing the page\n     */\n    this.contains = function(inDocument)\n    {\n        var urlParts = parseUri(unescape(inDocument.location.href));\n        var path = urlParts.path\n            .replace(/^\\//, \"\")\n            .replace(/\\/$/, \"\");\n        if (!this.pathRegexp.test(path)) {\n            return false;\n        }\n        for (var paramName in this.paramRegexps) {\n            var paramRegexp = this.paramRegexps[paramName];\n            if (!paramRegexp.test(urlParts.queryKey[paramName])) {\n                return false;\n            }\n        }\n        if (!this.pageContent(inDocument)) {\n            return false;\n        }\n        \n        return true;\n    }\n    \n    \n    \n    this.getUIElements = function()\n    {\n        var uiElements = [];\n        for (var uiElementName in this.uiElements) {\n            uiElements.push(this.uiElements[uiElementName]);\n        }\n        return uiElements;\n    };\n    \n    \n    \n    /**\n     * Returns a list of UI specifier string stubs representing all UI elements\n     * for this pageset. Stubs contain all required arguments, but leave\n     * argument values blank. Each element stub is paired with the element's\n     * description.\n     *\n     * @return  a list of UI specifier string stubs\n     */\n    this.getUISpecifierStringStubs = function()\n    {\n        var stubs = [];\n        for (var name in this.uiElements) {\n            var uiElement = this.uiElements[name];\n            var args = {};\n            for (var i = 0; i < uiElement.args.length; ++i) {\n                args[uiElement.args[i].name] = '';\n            }\n            var uiSpecifier = new UISpecifier(this.name, uiElement.name, args);\n            stubs.push([\n                UI_GLOBAL.UI_PREFIX + '=' + uiSpecifier.toString()\n                , uiElement.description\n            ]);\n        }\n        return stubs;\n    }\n    \n    \n    \n    /**\n     * Throws an exception on validation failure.\n     */\n    this._validate = function(pagesetShorthand)\n    {\n        var msg = \"Pageset validation error:\\n\"\n            + print_r(pagesetShorthand);\n        if (!pagesetShorthand.name) {\n            throw new PagesetException(msg + 'no name specified!');\n        }\n        if (!pagesetShorthand.description) {\n            throw new PagesetException(msg + 'no description specified!');\n        }\n        if (!pagesetShorthand.paths &&\n            !pagesetShorthand.pathRegexp &&\n            !pagesetShorthand.pageContent) {\n            throw new PagesetException(msg\n                + 'no path, pathRegexp, or pageContent specified!');\n        }\n    };\n    \n    \n    \n    this.init = function(pagesetShorthand)\n    {\n        this._validate(pagesetShorthand);\n        \n        this.name = pagesetShorthand.name;\n        this.description = pagesetShorthand.description;\n        \n        var pathPrefixRegexp = pagesetShorthand.pathPrefix\n            ? RegExp.escape(pagesetShorthand.pathPrefix) : \"\";\n        var pathRegexp = '^' + pathPrefixRegexp;\n        \n        if (pagesetShorthand.paths != undefined) {\n            pathRegexp += '(?:';\n            for (var i = 0; i < pagesetShorthand.paths.length; ++i) {\n                if (i > 0) {\n                    pathRegexp += '|';\n                }\n                pathRegexp += RegExp.escape(pagesetShorthand.paths[i]);\n            }\n            pathRegexp += ')$';\n        }\n        else if (pagesetShorthand.pathRegexp) {\n            pathRegexp += '(?:' + pagesetShorthand.pathRegexp + ')$';\n        }\n\n        this.pathRegexp = new RegExp(pathRegexp);\n        this.paramRegexps = {};\n        for (var paramName in pagesetShorthand.paramRegexps) {\n            this.paramRegexps[paramName] =\n                new RegExp(pagesetShorthand.paramRegexps[paramName]);\n        }\n        this.pageContent = pagesetShorthand.pageContent ||\n            function() { return true; };\n        this.uiElements = {};\n    };\n    \n    \n    \n    this.init(pagesetShorthand);\n}\n\n\n\n/**\n * Construct the UI map object, and return it. Once the object is instantiated,\n * it binds to a global variable and will not leave scope.\n *\n * @return  new UIMap object\n */\nfunction UIMap()\n{\n    // the singleton pattern, split into two parts so that \"new\" can still\n    // be used, in addition to \"getInstance()\"\n    UIMap.self = this;\n    \n    // need to attach variables directly to the Editor object in order for them\n    // to be in scope for Editor methods\n    if (is_IDE()) {\n        Editor.uiMap = this;\n        Editor.UI_PREFIX = UI_GLOBAL.UI_PREFIX;\n    }\n    \n    this.pagesets = new Object();\n    \n    \n    \n    /**\n     * pageset[pagesetName]\n     *   regexp\n     *   elements[elementName]\n     *     UIElement\n     */\n    this.addPageset = function(pagesetShorthand)\n    {\n        try {\n            var pageset = new Pageset(pagesetShorthand);\n        }\n        catch (e) {\n            safe_alert(\"Could not create pageset from shorthand:\\n\"\n                + print_r(pagesetShorthand) + \"\\n\" + e.message);\n            return false;\n        }\n        \n        if (this.pagesets[pageset.name]) {\n            safe_alert('Could not add pageset \"' + pageset.name\n                + '\": a pageset with that name already exists!');\n            return false;\n        }\n        \n        this.pagesets[pageset.name] = pageset;\n        return true;\n    };\n    \n    \n    \n    /**\n     * @param pagesetName\n     * @param uiElementShorthand  a representation of a UIElement object in\n     *                            shorthand JSON.\n     */\n    this.addElement = function(pagesetName, uiElementShorthand)\n    {\n        try {\n            var uiElement = new UIElement(uiElementShorthand);\n        }\n        catch (e) {\n            safe_alert(\"Could not create UI element from shorthand:\\n\"\n                + print_r(uiElementShorthand) + \"\\n\" + e.message);\n            return false;\n        }\n        \n        // run the element's unit tests only for the IDE, and only when the\n        // IDE is starting. Make a rough guess as to the latter condition.\n        if (is_IDE() && !editor.selDebugger && !uiElement.test()) {\n            safe_alert('Could not add UI element \"' + uiElement.name\n                + '\": failed testcases!');\n            return false;\n        }\n        \n        try {\n            this.pagesets[pagesetName].uiElements[uiElement.name] = uiElement;\n        }\n        catch (e) {\n            safe_alert(\"Could not add UI element '\" + uiElement.name\n                + \"' to pageset '\" + pagesetName + \"':\\n\" + e.message);\n            return false;\n        }\n        \n        return true;\n    };\n    \n    \n    \n    /**\n     * Returns the pageset for a given UI specifier string.\n     *\n     * @param uiSpecifierString\n     * @return  a pageset object\n     */\n    this.getPageset = function(uiSpecifierString)\n    {\n        try {\n            var uiSpecifier = new UISpecifier(uiSpecifierString);\n            return this.pagesets[uiSpecifier.pagesetName];\n        }\n        catch (e) {\n            return null;\n        }\n    }\n    \n    \n    \n    /**\n     * Returns the UIElement that a UISpecifierString or pageset and element\n     * pair refer to.\n     *\n     * @param pagesetNameOrUISpecifierString\n     * @return  a UIElement, or null if none is found associated with\n     *          uiSpecifierString\n     */\n    this.getUIElement = function(pagesetNameOrUISpecifierString, uiElementName)\n    {\n        var pagesetName = pagesetNameOrUISpecifierString;\n        if (arguments.length == 1) {\n            var uiSpecifierString = pagesetNameOrUISpecifierString;\n            try {\n                var uiSpecifier = new UISpecifier(uiSpecifierString);\n                pagesetName = uiSpecifier.pagesetName;\n                var uiElementName = uiSpecifier.elementName;\n            }\n            catch (e) {\n                return null;\n            }\n        }\n        try {\n            return this.pagesets[pagesetName].uiElements[uiElementName];\n        }\n        catch (e) {\n            return null;\n        }\n    };\n    \n    \n    \n    /**\n     * Returns a list of pagesets that \"contains\" the provided page,\n     * represented as a document object. Containership is defined by the\n     * Pageset object's contain() method.\n     *\n     * @param inDocument  the page to get pagesets for\n     * @return            a list of pagesets\n     */\n    this.getPagesetsForPage = function(inDocument)\n    {\n        var pagesets = [];\n        for (var pagesetName in this.pagesets) {\n            var pageset = this.pagesets[pagesetName];\n            if (pageset.contains(inDocument)) {\n                pagesets.push(pageset);\n            }\n        }\n        return pagesets;\n    };\n    \n    \n    \n    /**\n     * Returns a list of all pagesets.\n     *\n     * @return  a list of pagesets\n     */\n    this.getPagesets = function()\n    {\n        var pagesets = [];\n        for (var pagesetName in this.pagesets) {\n            pagesets.push(this.pagesets[pagesetName]);\n        }\n        return pagesets;\n    };\n    \n    \n    \n    /**\n     * Returns a list of elements on a page that a given UI specifier string,\n     * maps to. If no elements are mapped to, returns an empty list..\n     *\n     * @param   uiSpecifierString  a String that specifies a UI element with\n     *                             attendant argument values\n     * @param   inDocument         the document object the specified UI element\n     *                             appears in\n     * @return                     a potentially-empty list of elements\n     *                             specified by uiSpecifierString\n     */\n    this.getPageElements = function(uiSpecifierString, inDocument)\n    {\n        var locator = this.getLocator(uiSpecifierString);\n        var results = locator ? eval_locator(locator, inDocument) : [];\n        return results;\n    };\n    \n    \n    \n    /**\n     * Returns the locator string that a given UI specifier string maps to, or\n     * null if it cannot be mapped.\n     *\n     * @param uiSpecifierString\n     */\n    this.getLocator = function(uiSpecifierString)\n    {\n        try {\n            var uiSpecifier = new UISpecifier(uiSpecifierString);\n        }\n        catch (e) {\n            safe_alert('Could not create UISpecifier for string \"'\n                + uiSpecifierString + '\": ' + e.message);\n            return null;\n        }\n        \n        var uiElement = this.getUIElement(uiSpecifier.pagesetName,\n            uiSpecifier.elementName);\n        try {\n            return uiElement.getLocator(uiSpecifier.args);\n        }\n        catch (e) {\n            return null;\n        }\n    }\n    \n    \n    \n    /**\n     * Finds and returns a UI specifier string given an element and the page\n     * that it appears on.\n     *\n     * @param pageElement  the document element to map to a UI specifier\n     * @param inDocument   the document the element appears in\n     * @return             a UI specifier string, or false if one cannot be\n     *                     constructed\n     */\n    this.getUISpecifierString = function(pageElement, inDocument)\n    {\n        var is_fuzzy_match =\n            BrowserBot.prototype.locateElementByUIElement.is_fuzzy_match;\n        var pagesets = this.getPagesetsForPage(inDocument);\n        for (var i = 0; i < pagesets.length; ++i) {\n            var pageset = pagesets[i];\n            var uiElements = pageset.getUIElements();\n            for (var j = 0; j < uiElements.length; ++j) {\n                var uiElement = uiElements[j];\n                \n                // first test against the generic locator, if there is one.\n                // This should net some performance benefit when recording on\n                // more complicated pages.\n                if (uiElement.getGenericLocator) {\n                    var passedTest = false;\n                    var results =\n                        eval_locator(uiElement.getGenericLocator(), inDocument);\n                    for (var i = 0; i < results.length; ++i) {\n                        if (results[i] == pageElement) {\n                            passedTest = true;\n                            break;\n                        }\n                    }\n                    if (!passedTest) {\n                        continue;\n                    }\n                }\n                \n                var defaultLocators;\n                if (uiElement.isDefaultLocatorConstructionDeferred) {\n                    defaultLocators = uiElement.getDefaultLocators(inDocument);\n                }\n                else {\n                    defaultLocators = uiElement.defaultLocators;\n                }\n                \n                //safe_alert(print_r(uiElement.defaultLocators));\n                for (var locator in defaultLocators) {\n                    var locatedElements = eval_locator(locator, inDocument);\n                    if (locatedElements.length) {\n                        var locatedElement = locatedElements[0];\n                    }\n                    else {\n                        continue;\n                    }\n                    \n                    // use a heuristic to determine whether the element\n                    // specified is the \"same\" as the element we're matching\n                    if (is_fuzzy_match) {\n                        if (is_fuzzy_match(locatedElement, pageElement)) {\n                            return UI_GLOBAL.UI_PREFIX + '=' +\n                                new UISpecifier(pageset.name, uiElement.name,\n                                    defaultLocators[locator]);\n                        }\n                    }\n                    else {\n                        if (locatedElement == pageElement) {\n                            return UI_GLOBAL.UI_PREFIX + '=' +\n                                new UISpecifier(pageset.name, uiElement.name,\n                                    defaultLocators[locator]);\n                        }\n                    }\n                    // ok, matching the element failed. See if an offset\n                    // locator can complete the match.\n                    if (uiElement.getOffsetLocator) {\n                        for (var i = 0; i < locatedElements.length; ++i) {\n                            var offsetLocator = uiElement\n                                .getOffsetLocator(locatedElement, pageElement);\n                            if (offsetLocator) {\n                                return UI_GLOBAL.UI_PREFIX + '=' +\n                                    new UISpecifier(pageset.name,\n                                        uiElement.name,\n                                        defaultLocators[locator])\n                                    + '->' + offsetLocator;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        return false;\n    };\n    \n    \n    \n    /**\n     * Returns a sorted list of UI specifier string stubs representing possible\n     * UI elements for all pagesets, paired the their descriptions. Stubs\n     * contain all required arguments, but leave argument values blank.\n     *\n     * @return  a list of UI specifier string stubs\n     */\n    this.getUISpecifierStringStubs = function() {\n        var stubs = [];\n        var pagesets = this.getPagesets();\n        for (var i = 0; i < pagesets.length; ++i) {\n            stubs = stubs.concat(pagesets[i].getUISpecifierStringStubs());\n        }\n        stubs.sort(function(a, b) {\n            if (a[0] < b[0]) {\n                return -1;\n            }\n            return a[0] == b[0] ? 0 : 1;\n        });\n        return stubs;\n    }\n}\n\nUIMap.getInstance = function() {\n    return (UIMap.self == null) ? new UIMap() : UIMap.self;\n}\n\n//******************************************************************************\n// Rollups\n\n/**\n * The Command object isn't available in the Selenium RC. We introduce an\n * object with the identical constructor. In the IDE, this will be redefined,\n * which is just fine.\n *\n * @param command\n * @param target\n * @param value\n */\nif (typeof(Command) == 'undefined') {\n    function Command(command, target, value) {\n        this.command = command != null ? command : '';\n        this.target = target != null ? target : '';\n        this.value = value != null ? value : '';\n    }\n}\n\n\n\n/**\n * A CommandMatcher object matches commands during the application of a\n * RollupRule. It's specified with a shorthand format, for example:\n *\n *  new CommandMatcher({\n *      command: 'click'\n *      , target: 'ui=allPages::.+'\n *  })\n *\n * which is intended to match click commands whose target is an element in the\n * allPages PageSet. The matching expressions are given as regular expressions;\n * in the example above, the command must be \"click\"; \"clickAndWait\" would be\n * acceptable if 'click.*' were used. Here's a more complete example:\n *\n *  new CommandMatcher({\n *      command: 'type'\n *      , target: 'ui=loginPages::username()'\n *      , value: '.+_test'\n *      , updateArgs: function(command, args) {\n *          args.username = command.value;\n *      }\n *  })\n *\n * Here, the command and target are fixed, but there is variability in the \n * value of the command. When a command matches, the username is saved to the\n * arguments object.\n */\nfunction CommandMatcher(commandMatcherShorthand)\n{\n    /**\n     * Ensure the shorthand notation used to initialize the CommandMatcher has\n     * all required values.\n     *\n     * @param commandMatcherShorthand  an object containing information about\n     *                                 the CommandMatcher\n     */\n    this.validate = function(commandMatcherShorthand) {\n        var msg = \"CommandMatcher validation error:\\n\"\n            + print_r(commandMatcherShorthand);\n        if (!commandMatcherShorthand.command) {\n            throw new CommandMatcherException(msg + 'no command specified!');\n        }\n        if (!commandMatcherShorthand.target) {\n            throw new CommandMatcherException(msg + 'no target specified!');\n        }\n        if (commandMatcherShorthand.minMatches &&\n            commandMatcherShorthand.maxMatches &&\n            commandMatcherShorthand.minMatches >\n            commandMatcherShorthand.maxMatches) {\n            throw new CommandMatcherException(msg + 'minMatches > maxMatches!');\n        }\n    };\n\n    /**\n     * Initialize this object.\n     *\n     * @param commandMatcherShorthand  an object containing information used to\n     *                                 initialize the CommandMatcher\n     */\n    this.init = function(commandMatcherShorthand) {\n        this.validate(commandMatcherShorthand);\n        \n        this.command = commandMatcherShorthand.command;\n        this.target = commandMatcherShorthand.target;\n        this.value = commandMatcherShorthand.value || null;\n        this.minMatches = commandMatcherShorthand.minMatches || 1;\n        this.maxMatches = commandMatcherShorthand.maxMatches || 1;\n        this.updateArgs = commandMatcherShorthand.updateArgs ||\n            function(command, args) { return args; };\n    };\n    \n    /**\n     * Determines whether a given command matches. Updates args by \"reference\"\n     * and returns true if it does; return false otherwise.\n     *\n     * @param command  the command to attempt to match\n     */\n    this.isMatch = function(command) {\n        var re = new RegExp('^' + this.command + '$');\n        if (! re.test(command.command)) {\n            return false;\n        }\n        re = new RegExp('^' + this.target + '$');\n        if (! re.test(command.target)) {\n            return false;\n        }\n        if (this.value != null) {\n            re = new RegExp('^' + this.value + '$');\n            if (! re.test(command.value)) {\n                return false;\n            }\n        }\n        \n        // okay, the command matches\n        return true;\n    };\n    \n    // initialization\n    this.init(commandMatcherShorthand);\n}\n\n\n\nfunction RollupRuleException(message)\n{\n    this.message = message;\n    this.name = 'RollupRuleException';\n}\n\nfunction RollupRule(rollupRuleShorthand)\n{\n    /**\n     * Ensure the shorthand notation used to initialize the RollupRule has all\n     * required values.\n     *\n     * @param rollupRuleShorthand  an object containing information about the\n     *                             RollupRule\n     */\n    this.validate = function(rollupRuleShorthand) {\n        var msg = \"RollupRule validation error:\\n\"\n            + print_r(rollupRuleShorthand);\n        if (!rollupRuleShorthand.name) {\n            throw new RollupRuleException(msg + 'no name specified!');\n        }\n        if (!rollupRuleShorthand.description) {\n            throw new RollupRuleException(msg + 'no description specified!');\n        }\n        // rollupRuleShorthand.args is optional\n        if (!rollupRuleShorthand.commandMatchers &&\n            !rollupRuleShorthand.getRollup) {\n            throw new RollupRuleException(msg\n                + 'no command matchers specified!');\n        }\n        if (!rollupRuleShorthand.expandedCommands &&\n            !rollupRuleShorthand.getExpandedCommands) {\n            throw new RollupRuleException(msg\n                + 'no expanded commands specified!');\n        }\n        \n        return true;\n    };\n\n    /**\n     * Initialize this object.\n     *\n     * @param rollupRuleShorthand  an object containing information used to\n     *                             initialize the RollupRule\n     */\n    this.init = function(rollupRuleShorthand) {\n        this.validate(rollupRuleShorthand);\n        \n        this.name = rollupRuleShorthand.name;\n        this.description = rollupRuleShorthand.description;\n        this.pre = rollupRuleShorthand.pre || '';\n        this.post = rollupRuleShorthand.post || '';\n        this.alternateCommand = rollupRuleShorthand.alternateCommand;\n        this.args = rollupRuleShorthand.args || [];\n        \n        if (rollupRuleShorthand.commandMatchers) {\n            // construct the rule from the list of CommandMatchers\n            this.commandMatchers = [];\n            var matchers = rollupRuleShorthand.commandMatchers;\n            for (var i = 0; i < matchers.length; ++i) {\n                if (matchers[i].updateArgs && this.args.length == 0) {\n                    // enforce metadata for arguments\n                    var msg = \"RollupRule validation error:\\n\"\n                        + print_r(rollupRuleShorthand)\n                        + 'no argument metadata provided!';\n                    throw new RollupRuleException(msg);\n                }\n                this.commandMatchers.push(new CommandMatcher(matchers[i]));\n            }\n            \n            // returns false if the rollup doesn't match, or a rollup command\n            // if it does. If returned, the command contains the\n            // replacementIndexes property, which indicates which commands it\n            // substitutes for.\n            this.getRollup = function(commands) {\n                // this is a greedy matching algorithm\n                var replacementIndexes = [];\n                var commandMatcherQueue = this.commandMatchers;\n                var matchCount = 0;\n                var args = {};\n                for (var i = 0, j = 0; i < commandMatcherQueue.length;) {\n                    var matcher = commandMatcherQueue[i];\n                    if (j >= commands.length) {\n                        // we've run out of commands! If the remaining matchers\n                        // do not have minMatches requirements, this is a\n                        // match. Otherwise, it's not.\n                        if (matcher.minMatches > 0) {\n                            return false;\n                        }\n                        ++i;\n                        matchCount = 0; // unnecessary, but let's be consistent\n                    }\n                    else {\n                        if (matcher.isMatch(commands[j])) {\n                            ++matchCount;\n                            if (matchCount == matcher.maxMatches) {\n                                // exhausted this matcher's matches ... move on\n                                // to next matcher\n                                ++i;\n                                matchCount = 0;\n                            }\n                            args = matcher.updateArgs(commands[j], args);\n                            replacementIndexes.push(j);\n                            ++j; // move on to next command\n                        }\n                        else {\n                            //alert(matchCount + ', ' + matcher.minMatches);\n                            if (matchCount < matcher.minMatches) {\n                                return false;\n                            }\n                            // didn't match this time, but we've satisfied the\n                            // requirements already ... move on to next matcher\n                            ++i;\n                            matchCount = 0;\n                            // still gonna look at same command\n                        }\n                    }\n                }\n                \n                var rollup;\n                if (this.alternateCommand) {\n                    rollup = new Command(this.alternateCommand,\n                        commands[0].target, commands[0].value);\n                }\n                else {\n                    rollup = new Command('rollup', this.name);\n                    rollup.value = to_kwargs(args);\n                }\n                rollup.replacementIndexes = replacementIndexes;\n                return rollup;\n            };\n        }\n        else {\n            this.getRollup = function(commands) {\n                var result = rollupRuleShorthand.getRollup(commands);\n                if (result) {\n                    var rollup = new Command(\n                        result.command\n                        , result.target\n                        , result.value\n                    );\n                    rollup.replacementIndexes = result.replacementIndexes;\n                    return rollup;\n                }\n                return false;\n            };\n        }\n        \n        this.getExpandedCommands = function(kwargs) {\n            var commands = [];\n            var expandedCommands = (rollupRuleShorthand.expandedCommands\n                ? rollupRuleShorthand.expandedCommands\n                : rollupRuleShorthand.getExpandedCommands(\n                    parse_kwargs(kwargs)));\n            for (var i = 0; i < expandedCommands.length; ++i) {\n                var command = expandedCommands[i];\n                commands.push(new Command(\n                    command.command\n                    , command.target\n                    , command.value\n                ));\n            }\n            return commands;\n        };\n    };\n    \n    this.init(rollupRuleShorthand);\n}\n\n\n\n/**\n *\n */\nfunction RollupManager()\n{\n    // singleton pattern\n    RollupManager.self = this;\n    \n    this.init = function()\n    {\n        this.rollupRules = {};\n        if (is_IDE()) {\n            Editor.rollupManager = this;\n        }\n    };\n\n    /**\n     * Adds a new RollupRule to the repository. Returns true on success, or\n     * false if the rule couldn't be added.\n     *\n     * @param rollupRuleShorthand  shorthand JSON specification of the new\n     *                             RollupRule, possibly including CommandMatcher\n     *                             shorthand too.\n     * @return                     true if the rule was added successfully,\n     *                             false otherwise.\n     */\n    this.addRollupRule = function(rollupRuleShorthand)\n    {\n        try {\n            var rule = new RollupRule(rollupRuleShorthand);\n            this.rollupRules[rule.name] = rule;\n        }\n        catch(e) {\n            smart_alert(\"Could not create RollupRule from shorthand:\\n\\n\"\n                + e.message);\n            return false;\n        }\n        return true;\n    };\n    \n    /**\n     * Returns a RollupRule by name.\n     *\n     * @param rollupName  the name of the rule to fetch\n     * @return            the RollupRule, or null if it isn't found.\n     */\n    this.getRollupRule = function(rollupName)\n    {\n        return (this.rollupRules[rollupName] || null);\n    };\n    \n    /**\n     * Returns a list of name-description pairs for use in populating the\n     * auto-populated target dropdown in the IDE. Rules that have an alternate\n     * command defined are not included in the list, as they are not bona-fide\n     * rollups.\n     *\n     * @return  a list of name-description pairs\n     */\n    this.getRollupRulesForDropdown = function()\n    {\n        var targets = [];\n        var names = keys(this.rollupRules).sort();\n        for (var i = 0; i < names.length; ++i) {\n            var name = names[i];\n            if (this.rollupRules[name].alternateCommand) {\n                continue;\n            }\n            targets.push([ name, this.rollupRules[name].description ]);\n        }\n        return targets;\n    };\n    \n    /**\n     * Applies all rules to the current editor commands, asking the user in\n     * each case if it's okay to perform the replacement. The rules are applied\n     * repeatedly until there are no more matches. The algorithm should\n     * remember when the user has declined a replacement, and not ask to do it\n     * again.\n     *\n     * @return  the list of commands with rollup replacements performed\n     */\n    this.applyRollupRules = function()\n    {\n        var commands = editor.getTestCase().commands;\n        var blacklistedRollups = {};\n    \n        // so long as rollups were performed, we need to keep iterating through\n        // the commands starting at the beginning, because further rollups may\n        // potentially be applied on the newly created ones.\n        while (true) {\n            var performedRollup = false;\n            for (var i = 0; i < commands.length; ++i) {\n                // iterate through commands\n                for (var rollupName in this.rollupRules) {\n                    var rule = this.rollupRules[rollupName];\n                    var rollup = rule.getRollup(commands.slice(i));\n                    if (rollup) {\n                        // since we passed in a sliced version of the commands\n                        // array to the getRollup() method, we need to re-add \n                        // the offset to the replacementIndexes\n                        var k = 0;\n                        for (; k < rollup.replacementIndexes.length; ++k) {\n                            rollup.replacementIndexes[k] += i;\n                        }\n                        \n                        // build the confirmation message\n                        var msg = \"Perform the following command rollup?\\n\\n\";\n                        for (k = 0; k < rollup.replacementIndexes.length; ++k) {\n                            var replacementIndex = rollup.replacementIndexes[k];\n                            var command = commands[replacementIndex];\n                            msg += '[' + replacementIndex + ']: ';\n                            msg += command + \"\\n\";\n                        }\n                        msg += \"\\n\";\n                        msg += rollup;\n                        \n                        // check against blacklisted rollups\n                        if (blacklistedRollups[msg]) {\n                            continue;\n                        }\n                        \n                        // highlight the potentially replaced rows\n                        for (k = 0; k < commands.length; ++k) {\n                            var command = commands[k];\n                            command.result = '';\n                            if (rollup.replacementIndexes.indexOf(k) != -1) {\n                                command.selectedForReplacement = true;\n                            }\n                            editor.view.rowUpdated(replacementIndex);\n                        }\n                        \n                        // get confirmation from user\n                        if (confirm(msg)) {\n                            // perform rollup\n                            var deleteRanges = [];\n                            var replacementIndexes = rollup.replacementIndexes;\n                            for (k = 0; k < replacementIndexes.length; ++k) {\n                                // this is expected to be list of ranges. A\n                                // range has a start, and a list of commands.\n                                // The deletion only checks the length of the\n                                // command list.\n                                deleteRanges.push({\n                                    start: replacementIndexes[k]\n                                    , commands: [ 1 ]\n                                });\n                            }\n                            editor.view.executeAction(new TreeView\n                                .DeleteCommandAction(editor.view,deleteRanges));\n                            editor.view.insertAt(i, rollup);\n                            \n                            performedRollup = true;\n                        }\n                        else {\n                            // cleverly remember not to try this rollup again\n                            blacklistedRollups[msg] = true;\n                        }\n                        \n                        // unhighlight\n                        for (k = 0; k < commands.length; ++k) {\n                            commands[k].selectedForReplacement = false;\n                            editor.view.rowUpdated(k);\n                        }\n                    }\n                }\n            }\n            if (!performedRollup) {\n                break;\n            }\n        }\n        return commands;\n    };\n    \n    this.init();\n}\n\nRollupManager.getInstance = function() {\n    return (RollupManager.self == null)\n        ? new RollupManager()\n        : RollupManager.self;\n}\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/ui-map-sample.js",
    "content": "// sample UI element mapping definition. This is for http://alistapart.com/,\n// a particularly well structured site on web design principles.\n\n\n\n// in general, the map should capture structural aspects of the system, instead\n// of \"content\". In other words, interactive elements / assertible elements\n// that can be counted on to always exist should be defined here. Content -\n// for example text or a link that appears in a blog entry - is always liable\n// to change, and will not be fun to represent in this way. You probably don't\n// want to be testing specific content anyway.\n\n// create the UI mapping object. THIS IS THE MOST IMPORTANT PART - DON'T FORGET\n// TO DO THIS! In order for it to come into play, a user extension must\n// construct the map in this way.\nvar myMap = new UIMap();\n\n\n\n\n// any values which may appear multiple times can be defined as variables here.\n// For example, here we're enumerating a list of top level topics that will be\n// used as default argument values for several UI elements. Check out how\n// this variable is referenced further down.\nvar topics = [\n    'Code',\n    'Content',\n    'Culture',\n    'Design',\n    'Process',\n    'User Science'\n];\n\n// map subtopics to their parent topics\nvar subtopics = {\n    'Browsers':         'Code'\n    , 'CSS':            'Code'\n    , 'Flash':          'Code'\n    , 'HTML and XHTML': 'Code'\n    , 'Scripting':      'Code'\n    , 'Server Side':    'Code'\n    , 'XML':            'Code'\n    , 'Brand Arts': 'Content'\n    , 'Community':  'Content'\n    , 'Writing':    'Content'\n    , 'Industry':           'Culture'\n    , 'Politics and Money': 'Culture'\n    , 'State of the Web':   'Culture'\n    , 'Graphic Design':        'Design'\n    , 'User Interface Design': 'Design'\n    , 'Typography':            'Design'\n    , 'Layout':                'Design'\n    , 'Business':                        'Process'\n    , 'Creativity':                      'Process'\n    , 'Project Management and Workflow': 'Process'\n    , 'Accessibility':            'User Science'\n    , 'Information Architecture': 'User Science'\n    , 'Usability':                'User Science'\n};\n\n\n\n// define UI elements common for all pages. This regular expression does the\n// trick. '^' is automatically prepended, and '$' is automatically postpended.\n// Please note that because the regular expression is being represented as a\n// string, all backslashes must be escaped with an additional backslash. Also\n// note that the URL being matched will always have any trailing forward slash\n// stripped.\nmyMap.addPageset({\n    name: 'allPages'\n    , description: 'all alistapart.com pages'\n    , pathRegexp: '.*'\n});\nmyMap.addElement('allPages', {\n    name: 'masthead'\n    // the description should be short and to the point, usually no longer than\n    // a single line\n    , description: 'top level image link to site homepage'\n    // make sure the function returns the XPath ... it's easy to leave out the\n    // \"return\" statement by accident!\n    , locator: \"xpath=//*[@id='masthead']/a/img\"\n    , testcase1: {\n        xhtml: '<h1 id=\"masthead\"><a><img expected-result=\"1\" /></a></h1>'\n    }\n});\nmyMap.addElement('allPages', {\n    // be VERY CAREFUL to include commas in the correct place. Missing commas\n    // and extra commas can cause lots of headaches when debugging map\n    // definition files!!!\n    name: 'current_issue'\n    , description: 'top level link to issue currently being browsed'\n    , locator: \"//div[@id='ish']/a\"\n    , testcase1: {\n        xhtml: '<div id=\"ish\"><a expected-result=\"1\"></a></div>'\n    }\n});\nmyMap.addElement('allPages', {\n    name: 'section'\n    , description: 'top level link to articles section'\n    , args: [\n        {\n            name: 'section'\n            , description: 'the name of the section'\n            , defaultValues: [\n                'articles'\n                , 'topics'\n                , 'about'\n                , 'contact'\n                , 'contribute'\n                , 'feed'\n            ]\n        }\n    ]\n    // getXPath has been deprecated by getLocator, but verify backward\n    // compatability here\n    , getXPath: function(args) {\n        return \"//li[@id=\" + args.section.quoteForXPath() + \"]/a\";\n    }\n    , testcase1: {\n        args: { section: 'feed' }\n        , xhtml: '<ul><li id=\"feed\"><a expected-result=\"1\" /></li></ul>'\n    }\n});\nmyMap.addElement('allPages', {\n    name: 'search_box'\n    , description: 'site search input field'\n    // xpath has been deprecated by locator, but verify backward compatability\n    , xpath: \"//input[@id='search']\"\n    , testcase1: {\n        xhtml: '<input id=\"search\" expected-result=\"1\" />'\n    }\n});\nmyMap.addElement('allPages', {\n    name: 'search_discussions'\n    , description: 'site search include discussions checkbox'\n    , locator: 'incdisc'\n    , testcase1: {\n        xhtml: '<input id=\"incdisc\" expected-result=\"1\" />'\n    }\n});\nmyMap.addElement('allPages', {\n    name: 'search_submit'\n    , description: 'site search submission button'\n    , locator: 'submit'\n    , testcase1: {\n        xhtml: '<input id=\"submit\" expected-result=\"1\" />'\n    }\n});\nmyMap.addElement('allPages', {\n    name: 'topics'\n    , description: 'sidebar links to topic categories'\n    , args: [\n        {\n            name: 'topic'\n            , description: 'the name of the topic'\n            , defaultValues: topics\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@id='topiclist']/ul/li\" +\n            \"/a[text()=\" + args.topic.quoteForXPath() + \"]\";\n    }\n    , testcase1: {\n        args: { topic: 'foo' }\n        , xhtml: '<div id=\"topiclist\"><ul><li>'\n            + '<a expected-result=\"1\">foo</a>'\n            + '</li></ul></div>'\n    }\n});\nmyMap.addElement('allPages', {\n    name: 'copyright'\n    , description: 'footer link to copyright page'\n    , getLocator: function(args) { return \"//span[@class='copyright']/a\"; }\n    , testcase1: {\n        xhtml: '<span class=\"copyright\"><a expected-result=\"1\" /></span>'\n    }\n});\n\n\n\n// define UI elements for the homepage, i.e. \"http://alistapart.com/\", and\n// magazine issue pages, i.e. \"http://alistapart.com/issues/234\".\nmyMap.addPageset({\n    name: 'issuePages'\n    , description: 'pages including magazine issues'\n    , pathRegexp: '(issues/.+)?'\n});\nmyMap.addElement('issuePages', {\n    name: 'article'\n    , description: 'front or issue page link to article'\n    , args: [\n        {\n            name: 'index'\n            , description: 'the index of the article'\n            // an array of default values for the argument. A default\n            // value is one that is passed to the getXPath() method of\n            // the container UIElement object when trying to build an\n            // element locator.\n            //\n            // range() may be used to count easily. Remember though that\n            // the ending value does not include the right extreme; for\n            // example range(1, 5) counts from 1 to 4 only.\n            , defaultValues: range(1, 5)\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@class='item'][\" + args.index + \"]/h4/a\";\n    }\n});\nmyMap.addElement('issuePages', {\n    name: 'author'\n    , description: 'article author link'\n    , args: [\n        {\n            name: 'index'\n            , description: 'the index of the author, by article'\n            , defaultValues: range(1, 5)\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@class='item'][\" + args.index + \"]/h5/a\";\n    }\n});\nmyMap.addElement('issuePages', {\n    name: 'store'\n    , description: 'alistapart.com store link'\n    , locator: \"//ul[@id='banners']/li/a[@title='ALA Store']/img\"\n});\nmyMap.addElement('issuePages', {\n    name: 'special_article'\n    , description: \"editor's choice article link\"\n    , locator: \"//div[@id='choice']/h4/a\"\n});\nmyMap.addElement('issuePages', {\n    name: 'special_author'\n    , description: \"author link of editor's choice article\"\n    , locator: \"//div[@id='choice']/h5/a\"\n});\n\n\n\n// define UI elements for the articles page, i.e.\n// \"http://alistapart.com/articles\"\nmyMap.addPageset({\n    name: 'articleListPages'\n    , description: 'page with article listings'\n    , paths: [ 'articles' ]\n});\nmyMap.addElement('articleListPages', {\n    name: 'issue'\n    , description: 'link to issue'\n    , args: [\n        {\n            name: 'index'\n            , description: 'the index of the issue on the page'\n            , defaultValues: range(1, 10)\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//h2[@class='ishinfo'][\" + args.index + ']/a';\n    }\n    , genericLocator: \"//h2[@class='ishinfo']/a\"\n});\nmyMap.addElement('articleListPages', {\n    name: 'article'\n    , description: 'link to article, by issue and article number'\n    ,  args: [\n        {\n            name: 'issue_index'\n            , description: \"the index of the article's issue on the page; \"\n                + 'typically five per page'\n            , defaultValues: range(1, 6)\n        }\n        , {\n            name: 'article_index'\n            , description: 'the index of the article within the issue; '\n                + 'typically two per issue'\n            , defaultValues: range(1, 5)\n        }\n    ]\n    , getLocator: function(args) {\n        var xpath = \"//h2[@class='ishinfo'][\" + (args.issue_index || 1) + ']'\n            + \"/following-sibling::div[@class='item']\"\n            + '[' + (args.article_index || 1) + \"]/h3[@class='title']/a\";\n        return xpath;\n    }\n    , genericLocator: \"//h2[@class='ishinfo']\"\n        + \"/following-sibling::div[@class='item']/h3[@class='title']/a\"\n});\nmyMap.addElement('articleListPages', {\n    name: 'author'\n    , description: 'article author link, by issue and article'\n    , args: [\n        {\n            name: 'issue_index'\n            , description: \"the index of the article's issue on the page; \\\ntypically five per page\"\n            , defaultValues: range(1, 6)\n        }\n        , {\n            name: 'article_index'\n            , description: \"the index of the article within the issue; \\\ntypically two articles per issue\"\n            , defaultValues: range(1, 3)\n        }\n    ]\n    // this XPath uses the \"following-sibling\" axis. The div elements for\n    // the articles in an issue are not children, but siblings of the h2\n    // element identifying the article.\n    , getLocator: function(args) {\n        var xpath = \"//h2[@class='ishinfo'][\" + (args.issue_index || 1) + ']'\n            + \"/following-sibling::div[@class='item']\"\n            + '[' + (args.article_index || 1) + \"]/h4[@class='byline']/a\";\n        return xpath;\n    }\n    , genericLocator: \"//h2[@class='ishinfo']\"\n        + \"/following-sibling::div[@class='item']/h4[@class='byline']/a\"\n});\nmyMap.addElement('articleListPages', {\n    name: 'next_page'\n    , description: 'link to next page of articles (older)'\n    , locator: \"//a[contains(text(),'Next page')]\"\n});\nmyMap.addElement('articleListPages', {\n    name: 'previous_page'\n    , description: 'link to previous page of articles (newer)'\n    , locator: \"//a[contains(text(),'Previous page')]\"\n});\n\n\n\n// define UI elements for specific article pages, i.e.\n// \"http://alistapart.com/articles/culturalprobe\"\nmyMap.addPageset({\n    name: 'articlePages'\n    , description: 'pages for actual articles'\n    , pathRegexp: 'articles/.+'\n});\nmyMap.addElement('articlePages', {\n    name: 'title'\n    , description: 'article title loop-link'\n    , locator: \"//div[@id='content']/h1[@class='title']/a\"\n});\nmyMap.addElement('articlePages', {    \n    name: 'author'\n    , description: 'article author link'\n    , locator: \"//div[@id='content']/h3[@class='byline']/a\"\n});\nmyMap.addElement('articlePages', {    \n    name: 'article_topics'\n    , description: 'links to topics under which article is published, before \\\narticle content'\n    , args: [\n        {\n            name: 'topic'\n            , description: 'the name of the topic'\n            , defaultValues: keys(subtopics)\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//ul[@id='metastuff']/li/a\"\n            + \"[@title=\" + args.topic.quoteForXPath() + \"]\";\n    }\n});\nmyMap.addElement('articlePages', {    \n    name: 'discuss'\n    , description: 'link to article discussion area, before article content'\n    , locator: \"//ul[@id='metastuff']/li[@class='discuss']/p/a\"\n});\nmyMap.addElement('articlePages', {    \n    name: 'related_topics'\n    , description: 'links to topics under which article is published, after \\\narticle content'\n    , args: [\n        {\n            name: 'topic'\n            , description: 'the name of the topic'\n            , defaultValues: keys(subtopics)\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@id='learnmore']/p/a\"\n            + \"[@title=\" + args.topic.quoteForXPath() + \"]\";\n    }\n});\nmyMap.addElement('articlePages', {    \n    name: 'join_discussion'\n    , description: 'link to article discussion area, after article content'\n    , locator: \"//div[@class='discuss']/p/a\"\n});\n\n\n\nmyMap.addPageset({\n    name: 'topicListingPages'\n    , description: 'top level listing of topics'\n    , paths: [ 'topics' ]\n});\nmyMap.addElement('topicListingPages', {\n    name: 'topic'\n    , description: 'link to topic category'\n    , args: [\n        {\n            name: 'topic'\n            , description: 'the name of the topic'\n            , defaultValues: topics\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@id='content']/h2/a\"\n            + \"[text()=\" + args.topic.quoteForXPath() + \"]\";\n    }\n});\nmyMap.addElement('topicListingPages', {\n    name: 'subtopic'\n    , description: 'link to subtopic category'\n    , args: [\n        {\n            name: 'subtopic'\n            , description: 'the name of the subtopic'\n            , defaultValues: keys(subtopics)\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@id='content']\" +\n            \"/descendant::a[text()=\" + args.subtopic.quoteForXPath() + \"]\";\n    }\n});\n\n// the following few subtopic page UI elements are very similar. Define UI\n// elements for the code page, which is a subpage under topics, i.e.\n// \"http://alistapart.com/topics/code/\"\nmyMap.addPageset({\n    name: 'subtopicListingPages' \n    , description: 'pages listing subtopics'\n    , pathPrefix: 'topics/'\n    , paths: [\n        'code'\n        , 'content'\n        , 'culture'\n        , 'design'\n        , 'process'\n        , 'userscience'\n    ]\n});\nmyMap.addElement('subtopicListingPages', {\n    name: 'subtopic'\n    , description: 'link to a subtopic category'\n    , args: [\n        {\n            name: 'subtopic'\n            , description: 'the name of the subtopic'\n            , defaultValues: keys(subtopics)\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@id='content']/h2\" +\n            \"/a[text()=\" + args.subtopic.quoteForXPath() + \"]\";\n    }\n});\n\n\n\n// subtopic articles page\nmyMap.addPageset({\n    name: 'subtopicArticleListingPages'\n    , description: 'pages listing the articles for a given subtopic'\n    , pathRegexp: 'topics/[^/]+/.+'\n});\nmyMap.addElement('subtopicArticleListingPages', {\n    name: 'article'\n    , description: 'link to a subtopic article'\n    , args: [\n        {\n            name: 'index'\n            , description: 'the index of the article'\n            , defaultValues: range(1, 51) // the range seems unlimited ...\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@id='content']/div[@class='item']\"\n            + \"[\" + args.index + \"]/h3/a\";\n    }\n    , testcase1: {\n        args: { index: 2 }\n        , xhtml: '<div id=\"content\"><div class=\"item\" /><div class=\"item\">'\n            + '<h3><a expected-result=\"1\" /></h3></div></div>'\n    }\n});\nmyMap.addElement('subtopicArticleListingPages', {\n    name: 'author'\n    , description: \"link to a subtopic article author's page\"\n    , args: [\n        {\n            name: 'article_index'\n            , description: 'the index of the authored article'\n            , defaultValues: range(1, 51)\n        }\n        , {\n            name: 'author_index'\n            , description: 'the index of the author when there are multiple'\n            , defaultValues: range(1, 4)\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@id='content']/div[@class='item'][\" +\n            args.article_index + \"]/h4/a[\" +\n            (args.author_index ? args.author_index : '1') + ']';\n    }\n});\nmyMap.addElement('subtopicArticleListingPages', {\n    name: 'issue'\n    , description: 'link to issue a subtopic article appears in'\n    , args: [\n        {\n            name: 'index'\n            , description: 'the index of the subtopic article'\n            , defaultValues: range(1, 51)\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@id='content']/div[@class='item']\"\n            + \"[\" + args.index + \"]/h5/a\";\n    }\n});\n\n\n\nmyMap.addPageset({\n    name: 'aboutPages'\n    , description: 'the website about page'\n    , paths: [ 'about' ]\n});\nmyMap.addElement('aboutPages', {\n    name: 'crew'\n    , description: 'link to site crew member bio or personal website'\n    , args: [\n        {\n            name: 'role'\n            , description: 'the role of the crew member'\n            , defaultValues: [\n                'ALA Crew'\n                , 'Support'\n                , 'Emeritus'\n            ]\n        }\n        , {\n            name: 'role_index'\n            , description: 'the index of the member within the role'\n            , defaultValues: range(1, 20)\n        }\n        , {\n            name: 'member_index'\n            , description: 'the index of the member within the role title'\n            , defaultValues: range(1, 5)\n        }\n    ]\n    , getLocator: function(args) {\n        // the first role is kind of funky, and requires a conditional to\n        // build the XPath correctly. Its header looks like this:\n        //\n        // <h3>\n        // <span class=\"caps\">ALA 4</span>.0 <span class=\"caps\">CREW</span>\n        // </h3>\n        //\n        // This kind of complexity is a little daunting, but you can see\n        // how the format can handle it relatively easily and concisely.\n        if (args.role == 'ALA Crew') {\n            var selector = \"descendant::text()='CREW'\";\n        }\n        else {\n            var selector = \"text()=\" + args.role.quoteForXPath();\n        }\n        var xpath =\n            \"//div[@id='secondary']/h3[\" + selector + ']' +\n            \"/following-sibling::dl/dt[\" + (args.role_index || 1) + ']' +\n            '/a[' + (args.member_index || '1') + ']';\n        return xpath;\n    }\n});\n\n\n\nmyMap.addPageset({\n    name: 'searchResultsPages'\n    , description: 'pages listing search results'\n    , paths: [ 'search' ]\n});\nmyMap.addElement('searchResultsPages', {\n    name: 'result_link'\n    , description: 'search result link'\n    , args: [\n        {\n            name: 'index'\n            , description: 'the index of the search result'\n            , defaultValues: range(1, 11)\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@id='content']/ul[\" + args.index + ']/li/h3/a';\n    }\n});\nmyMap.addElement('searchResultsPages', {\n    name: 'more_results_link'\n    , description: 'next or previous results link at top or bottom of page'\n    , args: [\n        {\n            name: 'direction'\n            , description: 'next or previous results page'\n            // demonstrate a method which acquires default values from the\n            // document object. Such default values may contain EITHER commas\n            // OR equals signs, but NOT BOTH.\n            , getDefaultValues: function(inDocument) {\n                var defaultValues = [];\n                var divs = inDocument.getElementsByTagName('div');\n                for (var i = 0; i < divs.length; ++i) {\n                    if (divs[i].className == 'pages') {\n                        break;\n                    }\n                }\n                var links = divs[i].getElementsByTagName('a');\n                for (i = 0; i < links.length; ++i) {\n                    defaultValues.push(links[i].innerHTML\n                        .replace(/^\\xab\\s*/, \"\")\n                        .replace(/\\s*\\bb$/, \"\")\n                        .replace(/\\s*\\d+$/, \"\"));\n                }\n                return defaultValues;\n            }\n        }\n        , {\n            name: 'position'\n            , description: 'position of the link'\n            , defaultValues: ['top', 'bottom']\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@id='content']/div[@class='pages'][\"\n            + (args.position == 'top' ? '1' : '2') + ']'\n            + \"/a[contains(text(), \"\n            + (args.direction ? args.direction.quoteForXPath() : undefined)\n            + \")]\";\n    }\n});\n    \n    \n    \nmyMap.addPageset({\n    name: 'commentsPages'\n    , description: 'pages listing comments made to an article'\n    , pathRegexp: 'comments/.+'\n});\nmyMap.addElement('commentsPages', {\n    name: 'article_link'\n    , description: 'link back to the original article'\n    , locator: \"//div[@id='content']/h1[@class='title']/a\"\n});\nmyMap.addElement('commentsPages', {\n    name: 'comment_link'\n    , description: 'same-page link to comment'\n    , args: [\n        {\n            name: 'index'\n            , description: 'the index of the comment'\n            , defaultValues: range(1, 11)\n        }\n    ]\n    , getLocator: function(args) {\n        return \"//div[@class='content']/div[contains(@class, 'comment')]\" +\n            '[' + args.index + ']/h4/a[2]';\n    }\n});\nmyMap.addElement('commentsPages', {\n    name: 'paging_link'\n    , description: 'links to more pages of comments'\n    , args: [\n        {\n            name: 'dest'\n            , description: 'the destination page'\n            , defaultValues: ['next', 'prev'].concat(range(1, 16))\n        }\n        , {\n            name: 'position'\n            , description: 'position of the link'\n            , defaultValues: ['top', 'bottom']\n        }\n    ]\n    , getLocator: function(args) {\n        var dest = args.dest;\n        var xpath = \"//div[@id='content']/div[@class='pages']\" +\n            '[' + (args.position == 'top' ? '1' : '2') + ']/p';\n        if (dest == 'next' || dest == 'prev') {\n            xpath += \"/a[contains(text(), \" + dest.quoteForXPath() + \")]\";\n        }\n        else {\n            xpath += \"/a[text()=\" + dest.quoteForXPath() + \"]\";\n        }\n        return xpath;\n    }\n});\n\n\n\nmyMap.addPageset({\n    name: 'authorPages'\n    , description: 'personal pages for each author'\n    , pathRegexp: 'authors/[a-z]/.+'\n});\nmyMap.addElement('authorPages', {\n    name: 'article'\n    , description: \"link to article written by this author.\\n\"\n        + 'This description has a line break.'\n    , args: [\n        {\n            name: 'index'\n            , description: 'index of the article on the page'\n            , defaultValues: range(1, 11)\n        }\n    ]\n    , getLocator: function(args) {\n        var index = args.index;\n        // try out the CSS locator!\n        //return \"//h4[@class='title'][\" + index + \"]/a\";\n        return 'css=h4.title:nth-child(' + index + ') > a';\n    }\n    , testcase1: {\n        args: { index: '2' }\n        , xhtml: '<h4 class=\"title\" /><h4 class=\"title\">'\n            + '<a expected-result=\"1\" /></h4>'\n    }\n});\n\n\n\n// test the offset locator. Something like the following can be recorded:\n// ui=qaPages::content()//a[contains(text(),'May I quote from your articles?')]\nmyMap.addPageset({\n    name: 'qaPages'\n    , description: 'question and answer pages'\n    , pathRegexp: 'qa'\n});\nmyMap.addElement('qaPages', {\n    name: 'content'\n    , description: 'the content pane containing the q&a entries'\n    , locator: \"//div[@id='content' and \"\n        + \"child::h1[text()='Questions and Answers']]\"\n    , getOffsetLocator: UIElement.defaultOffsetLocatorStrategy\n});\nmyMap.addElement('qaPages', {\n    name: 'last_updated'\n    , description: 'displays the last update date'\n    // demonstrate calling getLocator() for another UI element within a\n    // getLocator(). The former must have already been added to the map. And\n    // obviously, you can't randomly combine different locator types!\n    , locator: myMap.getUIElement('qaPages', 'content').getLocator() + '/p/em'\n});\n\n\n\n//******************************************************************************\n\nvar myRollupManager = new RollupManager();\n\n// though the description element is required, its content is free form. You\n// might want to create a documentation policy as given below, where the pre-\n// and post-conditions of the rollup are spelled out.\n//\n// To take advantage of a \"heredoc\" like syntax for longer descriptions,\n// add a backslash to the end of the current line and continue the string on\n// the next line.\nmyRollupManager.addRollupRule({\n    name: 'navigate_to_subtopic_article_listing'\n    , description: 'drill down to the listing of articles for a given subtopic \\\nfrom the section menu, then the topic itself.'\n    , pre: 'current page contains the section menu (most pages should)'\n    , post: 'navigated to the page listing all articles for a given subtopic'\n    , args: [\n        {\n            name: 'subtopic'\n            , description: 'the subtopic whose article listing to navigate to'\n            , exampleValues: keys(subtopics)\n        }\n    ]\n    , commandMatchers: [\n        {\n            command: 'clickAndWait'\n            , target: 'ui=allPages::section\\\\(section=topics\\\\)'\n            // must escape parentheses in the the above target, since the\n            // string is being used as a regular expression. Again, backslashes\n            // in strings must be escaped too.\n        }\n        , {\n            command: 'clickAndWait'\n            , target: 'ui=topicListingPages::topic\\\\(.+'\n        }\n        , {\n            command: 'clickAndWait'\n            , target: 'ui=subtopicListingPages::subtopic\\\\(.+'\n            , updateArgs: function(command, args) {\n                // don't bother stripping the \"ui=\" prefix from the locator\n                // here; we're just using UISpecifier to parse the args out\n                var uiSpecifier = new UISpecifier(command.target);\n                args.subtopic = uiSpecifier.args.subtopic;\n                return args;\n            }\n        }\n    ]\n    , getExpandedCommands: function(args) {\n        var commands = [];\n        var topic = subtopics[args.subtopic];\n        var subtopic = args.subtopic;\n        commands.push({\n            command: 'clickAndWait'\n            , target: 'ui=allPages::section(section=topics)'\n        });\n        commands.push({\n            command: 'clickAndWait'\n            , target: 'ui=topicListingPages::topic(topic=' + topic + ')'\n        });\n        commands.push({\n            command: 'clickAndWait'\n            , target: 'ui=subtopicListingPages::subtopic(subtopic=' + subtopic\n                + ')'\n        });\n        commands.push({\n            command: 'verifyLocation'\n            , target: 'regexp:.+/topics/.+/.+'\n        });\n        return commands;\n    }\n});\n\n\n\nmyRollupManager.addRollupRule({\n    name: 'replace_click_with_clickAndWait'\n    , description: 'replaces commands where a click was detected with \\\nclickAndWait instead'\n    , alternateCommand: 'clickAndWait'\n    , commandMatchers: [\n        {\n            command: 'click'\n            , target: 'ui=subtopicArticleListingPages::article\\\\(.+'\n        }\n    ]\n    , expandedCommands: []\n});\n\n\n\nmyRollupManager.addRollupRule({\n    name: 'navigate_to_subtopic_article'\n    , description: 'navigate to an article listed under a subtopic.'\n    , pre: 'current page contains the section menu (most pages should)'\n    , post: 'navigated to an article page'\n    , args: [\n        {\n            name: 'subtopic'\n            , description: 'the subtopic whose article listing to navigate to'\n            , exampleValues: keys(subtopics)\n        }\n        , {\n            name: 'index'\n            , description: 'the index of the article in the listing'\n            , exampleValues: range(1, 11)\n        }\n    ]\n    , commandMatchers: [\n        {\n            command: 'rollup'\n            , target: 'navigate_to_subtopic_article_listing'\n            , value: 'subtopic\\\\s*=.+'\n            , updateArgs: function(command, args) {\n                var args1 = parse_kwargs(command.value);\n                args.subtopic = args1.subtopic;\n                return args;\n            }\n        }\n        , {\n            command: 'clickAndWait'\n            , target: 'ui=subtopicArticleListingPages::article\\\\(.+'\n            , updateArgs: function(command, args) {\n                var uiSpecifier = new UISpecifier(command.target);\n                args.index = uiSpecifier.args.index;\n                return args;\n            }\n        }\n    ]\n    /*\n    // this is pretty much equivalent to the commandMatchers immediately above.\n    // Seems more verbose and less expressive, doesn't it? But sometimes you\n    // might prefer the flexibility of a function.\n    , getRollup: function(commands) {\n        if (commands.length >= 2) {\n            command1 = commands[0];\n            command2 = commands[1];\n            var args1 = parse_kwargs(command1.value);\n            try {\n                var uiSpecifier = new UISpecifier(command2.target\n                    .replace(/^ui=/, ''));\n            }\n            catch (e) {\n                return false;\n            }\n            if (command1.command == 'rollup' &&\n                command1.target == 'navigate_to_subtopic_article_listing' &&\n                args1.subtopic &&\n                command2.command == 'clickAndWait' &&\n                uiSpecifier.pagesetName == 'subtopicArticleListingPages' &&\n                uiSpecifier.elementName == 'article') {\n                var args = {\n                    subtopic: args1.subtopic\n                    , index: uiSpecifier.args.index\n                };\n                return {\n                    command: 'rollup'\n                    , target: this.name\n                    , value: to_kwargs(args)\n                    , replacementIndexes: [ 0, 1 ]\n                };\n            }\n        }\n        return false;\n    }\n    */\n    , getExpandedCommands: function(args) {\n        var commands = [];\n        commands.push({\n            command: 'rollup'\n            , target: 'navigate_to_subtopic_article_listing'\n            , value: to_kwargs({ subtopic: args.subtopic })\n        });\n        var uiSpecifier = new UISpecifier(\n            'subtopicArticleListingPages'\n            , 'article'\n            , { index: args.index });\n        commands.push({\n            command: 'clickAndWait'\n            , target: 'ui=' + uiSpecifier.toString()\n        });\n        commands.push({\n            command: 'verifyLocation'\n            , target: 'regexp:.+/articles/.+'\n        });\n        return commands;\n    }\n});\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/user-extensions.js",
    "content": "// User extensions can be added here.\n//\n// Keep this file to avoid  mystifying \"Invalid Character\" error in IE\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/user-extensions.js.sample",
    "content": "/*\n * By default, Selenium looks for a file called \"user-extensions.js\", and loads and javascript\n * code found in that file. This file is a sample of what that file could look like.\n *\n * user-extensions.js provides a convenient location for adding extensions to Selenium, like\n * new actions, checks and locator-strategies.\n * By default, this file does not exist. Users can create this file and place their extension code\n * in this common location, removing the need to modify the Selenium sources, and hopefully assisting\n * with the upgrade process.\n *\n * You can find contributed extensions at http://wiki.openqa.org/display/SEL/Contributed%20User-Extensions\n */\n\n// The following examples try to give an indication of how Selenium can be extended with javascript.\n\n// All do* methods on the Selenium prototype are added as actions.\n// Eg add a typeRepeated action to Selenium, which types the text twice into a text box.\n// The typeTwiceAndWait command will be available automatically\nSelenium.prototype.doTypeRepeated = function(locator, text) {\n    // All locator-strategies are automatically handled by \"findElement\"\n    var element = this.page().findElement(locator);\n\n    // Create the text to type\n    var valueToType = text + text;\n\n    // Replace the element text with the new text\n    this.page().replaceText(element, valueToType);\n};\n\n// All assert* methods on the Selenium prototype are added as checks.\n// Eg add a assertValueRepeated check, that makes sure that the element value\n// consists of the supplied text repeated.\n// The verify version will be available automatically.\nSelenium.prototype.assertValueRepeated = function(locator, text) {\n    // All locator-strategies are automatically handled by \"findElement\"\n    var element = this.page().findElement(locator);\n\n    // Create the text to verify\n    var expectedValue = text + text;\n\n    // Get the actual element value\n    var actualValue = element.value;\n\n    // Make sure the actual value matches the expected\n    Assert.matches(expectedValue, actualValue);\n};\n\n// All get* methods on the Selenium prototype result in\n// store, assert, assertNot, verify, verifyNot, waitFor, and waitForNot commands.\n// E.g. add a getTextLength method that returns the length of the text\n// of a specified element.\n// Will result in support for storeTextLength, assertTextLength, etc.\nSelenium.prototype.getTextLength = function(locator) {\n\treturn this.getText(locator).length;\n};\n\n// All locateElementBy* methods are added as locator-strategies.\n// Eg add a \"valuerepeated=\" locator, that finds the first element with the supplied value, repeated.\n// The \"inDocument\" is a the document you are searching.\nPageBot.prototype.locateElementByValueRepeated = function(text, inDocument) {\n    // Create the text to search for\n    var expectedValue = text + text;\n\n    // Loop through all elements, looking for ones that have a value === our expected value\n    var allElements = inDocument.getElementsByTagName(\"*\");\n    for (var i = 0; i < allElements.length; i++) {\n        var testElement = allElements[i];\n        if (testElement.value && testElement.value === expectedValue) {\n            return testElement;\n        }\n    }\n    return null;\n};\n\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/scripts/xmlextras.js",
    "content": "// This is a third party JavaScript library from\n// http://webfx.eae.net/dhtml/xmlextras/xmlextras.html\n// i.e. This has not been written by ThoughtWorks.\n\n//<script>\n//////////////////\n// Helper Stuff //\n//////////////////\n\n// used to find the Automation server name\nfunction getDomDocumentPrefix() {\n\tif (getDomDocumentPrefix.prefix)\n\t\treturn getDomDocumentPrefix.prefix;\n\t\n\tvar prefixes = [\"MSXML2\", \"Microsoft\", \"MSXML\", \"MSXML3\"];\n\tvar o;\n\tfor (var i = 0; i < prefixes.length; i++) {\n\t\ttry {\n\t\t\t// try to create the objects\n\t\t\to = new ActiveXObject(prefixes[i] + \".DomDocument\");\n\t\t\treturn getDomDocumentPrefix.prefix = prefixes[i];\n\t\t}\n\t\tcatch (ex) {};\n\t}\n\t\n\tthrow new Error(\"Could not find an installed XML parser\");\n}\n\nfunction getXmlHttpPrefix() {\n\tif (getXmlHttpPrefix.prefix)\n\t\treturn getXmlHttpPrefix.prefix;\n\t\n\tvar prefixes = [\"MSXML2\", \"Microsoft\", \"MSXML\", \"MSXML3\"];\n\tvar o;\n\tfor (var i = 0; i < prefixes.length; i++) {\n\t\ttry {\n\t\t\t// try to create the objects\n\t\t\to = new ActiveXObject(prefixes[i] + \".XmlHttp\");\n\t\t\treturn getXmlHttpPrefix.prefix = prefixes[i];\n\t\t}\n\t\tcatch (ex) {};\n\t}\n\t\n\tthrow new Error(\"Could not find an installed XML parser\");\n}\n\n//////////////////////////\n// Start the Real stuff //\n//////////////////////////\n\n\n// XmlHttp factory\nfunction XmlHttp() {}\n\nXmlHttp.create = function () {\n\ttry {\n\t\tif (window.XMLHttpRequest) {\n\t\t\tvar req = new XMLHttpRequest();\n\t\t\t\n\t\t\t// some versions of Moz do not support the readyState property\n\t\t\t// and the onreadystate event so we patch it!\n\t\t\tif (req.readyState == null) {\n\t\t\t\treq.readyState = 1;\n\t\t\t\treq.addEventListener(\"load\", function () {\n\t\t\t\t\treq.readyState = 4;\n\t\t\t\t\tif (typeof req.onreadystatechange == \"function\")\n\t\t\t\t\t\treq.onreadystatechange();\n\t\t\t\t}, false);\n\t\t\t}\n\t\t\t\n\t\t\treturn req;\n\t\t}\n\t\tif (window.ActiveXObject) {\n\t\t\treturn new ActiveXObject(getXmlHttpPrefix() + \".XmlHttp\");\n\t\t}\n\t}\n\tcatch (ex) {}\n\t// fell through\n\tthrow new Error(\"Your browser does not support XmlHttp objects\");\n};\n\n// XmlDocument factory\nfunction XmlDocument() {}\n\nXmlDocument.create = function () {\n\ttry {\n\t\t// DOM2\n\t\tif (document.implementation && document.implementation.createDocument) {\n\t\t\tvar doc = document.implementation.createDocument(\"\", \"\", null);\n\t\t\t\n\t\t\t// some versions of Moz do not support the readyState property\n\t\t\t// and the onreadystate event so we patch it!\n\t\t\tif (doc.readyState == null) {\n\t\t\t\tdoc.readyState = 1;\n\t\t\t\tdoc.addEventListener(\"load\", function () {\n\t\t\t\t\tdoc.readyState = 4;\n\t\t\t\t\tif (typeof doc.onreadystatechange == \"function\")\n\t\t\t\t\t\tdoc.onreadystatechange();\n\t\t\t\t}, false);\n\t\t\t}\n\t\t\t\n\t\t\treturn doc;\n\t\t}\n\t\tif (window.ActiveXObject)\n\t\t\treturn new ActiveXObject(getDomDocumentPrefix() + \".DomDocument\");\n\t}\n\tcatch (ex) {}\n\tthrow new Error(\"Your browser does not support XmlDocument objects\");\n};\n\n// Create the loadXML method and xml getter for Mozilla\nif (window.DOMParser &&\n\twindow.XMLSerializer &&\n\twindow.Node && Node.prototype && Node.prototype.__defineGetter__) {\n\n\t// XMLDocument did not extend the Document interface in some versions\n\t// of Mozilla. Extend both!\n\t//XMLDocument.prototype.loadXML = \n\tDocument.prototype.loadXML = function (s) {\n\t\t\n\t\t// parse the string to a new doc\t\n\t\tvar doc2 = (new DOMParser()).parseFromString(s, \"text/xml\");\n\t\t\n\t\t// remove all initial children\n\t\twhile (this.hasChildNodes())\n\t\t\tthis.removeChild(this.lastChild);\n\t\t\t\n\t\t// insert and import nodes\n\t\tfor (var i = 0; i < doc2.childNodes.length; i++) {\n\t\t\tthis.appendChild(this.importNode(doc2.childNodes[i], true));\n\t\t}\n\t};\n\t\n\t\n\t/*\n\t * xml getter\n\t *\n\t * This serializes the DOM tree to an XML String\n\t *\n\t * Usage: var sXml = oNode.xml\n\t *\n\t */\n\t// XMLDocument did not extend the Document interface in some versions\n\t// of Mozilla. Extend both!\n\t/*\n\tXMLDocument.prototype.__defineGetter__(\"xml\", function () {\n\t\treturn (new XMLSerializer()).serializeToString(this);\n\t});\n\t*/\n\tDocument.prototype.__defineGetter__(\"xml\", function () {\n\t\treturn (new XMLSerializer()).serializeToString(this);\n\t});\n}"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/selenium-test.css",
    "content": "body, table {\n    font-family: Verdana, Arial, sans-serif;\n    font-size: 12;\n}\n\ntable {\n    border-collapse: collapse;\n    border: 1px solid #ccc;\n}\n\nth, td {\n    padding-left: 0.3em;\n    padding-right: 0.3em;\n}\n\na {\n    text-decoration: none;\n}\n\n.title {\n    font-style: italic;\n}\n\n.selected {\n    background-color: #ffffcc;\n}\n\n.status_done {\n    background-color: #eeffee;\n}\n\n.status_passed {\n    background-color: #ccffcc;\n}\n\n.status_failed {\n    background-color: #ffcccc;\n}\n\n.breakpoint {\n    background-color: #cccccc;\n    border: 1px solid black;\n}\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/selenium.css",
    "content": "/*\n * Copyright 2005 ThoughtWorks, Inc\n * \n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *  \n *      http://www.apache.org/licenses/LICENSE-2.0\n *  \n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\n/*---( Layout )---*/\n\n* {\n    margin: 0px;\n    padding: 0px;\n}\n\nbody {\n    overflow: auto;\n}\n\ntd {\n    position: static;\n}\n\ntr {\n    vertical-align: top;\n}\n\n.layout {\n    width: 100%;\n    height: 100%;\n    border-collapse: collapse;\n}\n\n.layout td {\n    border: 0;\n}\n\niframe {\n    border: 0px;\n    width: 100%;\n    height: 100%;\n    background: white;\n    /*  HBC - this particular property seems to be causing an issue in\n        conjunction with the native Draw() method in Snapsie. I don't really\n        see a visual difference from commenting this out, so I'm going ahead\n        with it.\n    overflow: auto; */\n}\n\n/*---( Style )---*/\n\nbody, html {\n    font-family: Verdana, Arial, sans-serif;\n}\n\n.selenium th, .selenium td {\n    border: 1px solid #999;\n}\n\n.header {\n    background: #ccc;\n    padding: 0;\n    font-size: 90%;\n}\n\n.remoterunner {\n\tfont-size: 10pt;\n}\n\n.remoterunner fieldset {\n\tpadding: 0.25em;\n}\n\n.remoterunner button, .remoterunner label {\n\tmargin-right: 1em;\n}\n\n\n#controlPanel {\n    padding: 0.5ex;\n    background: #eee;\n    overflow: auto;\n    font-size: 75%;\n    text-align: center;\n}\n\n#controlPanel fieldset {\n    margin: 0.3ex;\n    padding: 0.3ex;\n}\n\n#controlPanel fieldset legend {\n    color: black;\n}\n\n#controlPanel button {\n    margin: 0.5ex;\n}\n\n#imageButtonPanel button {\n    width: 24px;\n    height: 20px;\n    background-color:white;\n    background-repeat: no-repeat;\n    background-position: center;\n    border-style: solid;\n    border-color: black;\n    border-width: 1px;\n}\n\n#controlPanel #runSuite {\n    width: 32px;\n    background-image: url(\"icons/all.png\");\n}\n\n#controlPanel #runSeleniumTest {\n    width: 32px;\n    background-image: url(\"icons/selected.png\");\n}\n\n.cssPauseTest {\n    background-image: url(\"icons/pause.png\");\n}\n\n.cssPauseTest[disabled]  {\n    background-image: url(\"icons/pause_disabled.png\");\n}\n\n.cssContinueTest {\n    background-image: url(\"icons/continue.png\");\n}\n\n.cssContinueTest[disabled] {\n    background-image: url(\"icons/continue_disabled.png\");\n}\n\n#controlPanel #stepTest {\n    background-image: url(\"icons/step.png\");\n}\n\n#controlPanel #stepTest[disabled] {\n    background-image: url(\"icons/step_disabled.png\");\n}\n\n#controlPanel table {\n    font-size: 100%;\n}\n\n#controlPanel th, #controlPanel td {\n    border: 0;\n}\n\nh1 {\n    margin: 0.2ex;\n    font-size: 130%;\n    font-weight: bold;\n}\n\nh2 {\n    margin: 0.2ex;\n    font-size: 80%;\n    font-weight: normal;\n}\n\n.selenium a {\n    color: black;\n    text-decoration: none;\n}\n\n.selenium a:hover {\n    text-decoration: underline;\n}\n\nbutton, label {\n    cursor: pointer;\n}\n\n#stats {\n    margin: 0.5em auto 0.5em auto;\n}\n\n#stats th, #stats td {\n    text-align: left;\n    padding-left: 2px;\n}\n\n#stats th {\n    text-decoration: underline;\n}\n\n#stats td.count {\n    font-weight: bold;\n    text-align: right;\n}\n\n#testRuns {\n    color: green;\n}\n\n#testFailures {\n    color: red;\n}\n\n#commandPasses {\n    color: green;\n}\n\n#commandFailures {\n    color: red;\n}\n\n#commandErrors {\n    color: #f90;\n}\n\n\n/*---( Logging Console )---*/\n\n#logging-console {\n    background: #fff;\n    font-size: 75%;\n}\n\n#logging-console #banner {\n    display: block;\n    width: 100%;\n    position: fixed;\n    top: 0;\n    background: #ddd;\n    border-bottom: 1px solid #666;\n}\n\n#logging-console #logLevelChooser {\n    float: right;\n    margin: 3px;\n}\n\n#logging-console ul {\n    list-style-type: none;\n    margin: 0px;\n    margin-top: 3em;\n    padding-left: 5px;\n}\n\n#logging-console li {\n    margin: 2px;\n    border-top: 1px solid #ccc;\n}\n\n#logging-console li.error {\n    font-weight: bold;\n    color: red;\n}\n\n#logging-console li.warn {\n    color: red;\n}\n\n#logging-console li.debug {\n    color: green;\n}\n\ndiv.executionOptions {\n    padding-left: 5em;\n}\n\ndiv.executionOptions label, div.executionOptions input {\n    display: block;\n    float: left;\n}\n\ndiv.executionOptions br {\n    clear: left;\n}\n\n#speedSlider {\n    text-align: left;\n    margin: 0px auto;\n    width: 260px;\n    line-height: 0px;\n    font-size: 0px;\n    padding: 0px;\n}\n\n#speedSlider #speedTrack {\n    background-color: #333;\n    width: 260px;\n    height: 2px;\n    line-height: 2px;\n    z-index: 1;\n    border: 1px solid;\n    border-color: #999 #ddd #ddd #999;\n    cursor: pointer;\n}\n\n#speedSlider #speedHandle {\n    width: 12px;\n    top: -8px;\n    background-color: #666;\n    position: relative;\n    margin: 0px;\n    height: 8px;\n    line-height: 8px;\n    z-index: 1;\n    border: 1px solid;\n    border-color: #999 #333 #333 #999;\n    cursor: pointer;\n}\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/xpath/dom.js",
    "content": "// Copyright 2005 Google Inc.\n// All Rights Reserved\n//\n// Author: Steffen Meschkat <mesch@google.com>\n//\n// An XML parse and a minimal DOM implementation that just supportes\n// the subset of the W3C DOM that is used in the XSLT implementation.\n\n// NOTE: The split() method in IE omits empty result strings. This is\n// utterly annoying. So we don't use it here.\n\n// Resolve entities in XML text fragments. According to the DOM\n// specification, the DOM is supposed to resolve entity references at\n// the API level. I.e. no entity references are passed through the\n// API. See \"Entities and the DOM core\", p.12, DOM 2 Core\n// Spec. However, different browsers actually pass very different\n// values at the API. See <http://mesch.nyc/test-xml-quote>.\nfunction xmlResolveEntities(s) {\n\n  var parts = stringSplit(s, '&');\n\n  var ret = parts[0];\n  for (var i = 1; i < parts.length; ++i) {\n    var rp = parts[i].indexOf(';');\n    if (rp == -1) {\n      // no entity reference: just a & but no ;\n      ret += parts[i];\n      continue;\n    }\n\n    var entityName = parts[i].substring(0, rp);\n    var remainderText = parts[i].substring(rp + 1);\n\n    var ch;\n    switch (entityName) {\n      case 'lt':\n        ch = '<';\n        break;\n      case 'gt':\n        ch = '>';\n        break;\n      case 'amp':\n        ch = '&';\n        break;\n      case 'quot':\n        ch = '\"';\n        break;\n      case 'apos':\n        ch = '\\'';\n        break;\n      case 'nbsp':\n        ch = String.fromCharCode(160);\n        break;\n      default:\n        // Cool trick: let the DOM do the entity decoding. We assign\n        // the entity text through non-W3C DOM properties and read it\n        // through the W3C DOM. W3C DOM access is specified to resolve\n        // entities.\n        var span = domCreateElement(window.document, 'span');\n        span.innerHTML = '&' + entityName + '; ';\n        ch = span.childNodes[0].nodeValue.charAt(0);\n    }\n    ret += ch + remainderText;\n  }\n\n  return ret;\n}\n\nvar XML10_TAGNAME_REGEXP = new RegExp('^(' + XML10_NAME + ')');\nvar XML10_ATTRIBUTE_REGEXP = new RegExp(XML10_ATTRIBUTE, 'g');\n\nvar XML11_TAGNAME_REGEXP = new RegExp('^(' + XML11_NAME + ')');\nvar XML11_ATTRIBUTE_REGEXP = new RegExp(XML11_ATTRIBUTE, 'g');\n\n// Parses the given XML string with our custom, JavaScript XML parser. Written\n// by Steffen Meschkat (mesch@google.com).\nfunction xmlParse(xml) {\n  var regex_empty = /\\/$/;\n\n  var regex_tagname;\n  var regex_attribute;\n  if (xml.match(/^<\\?xml/)) {\n    // When an XML document begins with an XML declaration\n    // VersionInfo must appear.\n    if (xml.search(new RegExp(XML10_VERSION_INFO)) == 5) {\n      regex_tagname = XML10_TAGNAME_REGEXP;\n      regex_attribute = XML10_ATTRIBUTE_REGEXP;\n    } else if (xml.search(new RegExp(XML11_VERSION_INFO)) == 5) {\n      regex_tagname = XML11_TAGNAME_REGEXP;\n      regex_attribute = XML11_ATTRIBUTE_REGEXP;\n    } else {\n      // VersionInfo is missing, or unknown version number.\n      // TODO : Fallback to XML 1.0 or XML 1.1, or just return null?\n      alert('VersionInfo is missing, or unknown version number.');\n    }\n  } else {\n    // When an XML declaration is missing it's an XML 1.0 document.\n    regex_tagname = XML10_TAGNAME_REGEXP;\n    regex_attribute = XML10_ATTRIBUTE_REGEXP;\n  }\n\n  var xmldoc = new XDocument();\n  var root = xmldoc;\n\n  // For the record: in Safari, we would create native DOM nodes, but\n  // in Opera that is not possible, because the DOM only allows HTML\n  // element nodes to be created, so we have to do our own DOM nodes.\n\n  // xmldoc = document.implementation.createDocument('','',null);\n  // root = xmldoc; // .createDocumentFragment();\n  // NOTE(mesch): using the DocumentFragment instead of the Document\n  // crashes my Safari 1.2.4 (v125.12).\n  var stack = [];\n\n  var parent = root;\n  stack.push(parent);\n\n  // The token that delimits a section that contains markup as\n  // content: CDATA or comments.\n  var slurp = '';\n\n  var x = stringSplit(xml, '<');\n  for (var i = 1; i < x.length; ++i) {\n    var xx = stringSplit(x[i], '>');\n    var tag = xx[0];\n    var text = xmlResolveEntities(xx[1] || '');\n\n    if (slurp) {\n      // In a \"slurp\" section (CDATA or comment): only check for the\n      // end of the section, otherwise append the whole text.\n      var end = x[i].indexOf(slurp);\n      if (end != -1) {\n        var data = x[i].substring(0, end);\n        parent.nodeValue += '<' + data;\n        stack.pop();\n        parent = stack[stack.length-1];\n        text = x[i].substring(end + slurp.length);\n        slurp = '';\n      } else {\n        parent.nodeValue += '<' + x[i];\n        text = null;\n      }\n\n    } else if (tag.indexOf('![CDATA[') == 0) {\n      var start = '![CDATA['.length;\n      var end = x[i].indexOf(']]>');\n      if (end != -1) {\n        var data = x[i].substring(start, end);\n        var node = domCreateCDATASection(xmldoc, data);\n        domAppendChild(parent, node);\n      } else {\n        var data = x[i].substring(start);\n        text = null;\n        var node = domCreateCDATASection(xmldoc, data);\n        domAppendChild(parent, node);\n        parent = node;\n        stack.push(node);\n        slurp = ']]>';\n      }\n\n    } else if (tag.indexOf('!--') == 0) {\n      var start = '!--'.length;\n      var end = x[i].indexOf('-->');\n      if (end != -1) {\n        var data = x[i].substring(start, end);\n        var node = domCreateComment(xmldoc, data);\n        domAppendChild(parent, node);\n      } else {\n        var data = x[i].substring(start);\n        text = null;\n        var node = domCreateComment(xmldoc, data);\n        domAppendChild(parent, node);\n        parent = node;\n        stack.push(node);\n        slurp = '-->';\n      }\n\n    } else if (tag.charAt(0) == '/') {\n      stack.pop();\n      parent = stack[stack.length-1];\n\n    } else if (tag.charAt(0) == '?') {\n      // Ignore XML declaration and processing instructions\n    } else if (tag.charAt(0) == '!') {\n      // Ignore notation and comments\n    } else {\n      var empty = tag.match(regex_empty);\n      var tagname = regex_tagname.exec(tag)[1];\n      var node = domCreateElement(xmldoc, tagname);\n\n      var att;\n      while (att = regex_attribute.exec(tag)) {\n        var val = xmlResolveEntities(att[5] || att[7] || '');\n        domSetAttribute(node, att[1], val);\n      }\n\n      domAppendChild(parent, node);\n      if (!empty) {\n        parent = node;\n        stack.push(node);\n      }\n    }\n\n    if (text && parent != root) {\n      domAppendChild(parent, domCreateTextNode(xmldoc, text));\n    }\n  }\n\n  return root;\n}\n\n// Based on <http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/\n// core.html#ID-1950641247>\nvar DOM_ELEMENT_NODE = 1;\nvar DOM_ATTRIBUTE_NODE = 2;\nvar DOM_TEXT_NODE = 3;\nvar DOM_CDATA_SECTION_NODE = 4;\nvar DOM_ENTITY_REFERENCE_NODE = 5;\nvar DOM_ENTITY_NODE = 6;\nvar DOM_PROCESSING_INSTRUCTION_NODE = 7;\nvar DOM_COMMENT_NODE = 8;\nvar DOM_DOCUMENT_NODE = 9;\nvar DOM_DOCUMENT_TYPE_NODE = 10;\nvar DOM_DOCUMENT_FRAGMENT_NODE = 11;\nvar DOM_NOTATION_NODE = 12;\n\n// Traverses the element nodes in the DOM section underneath the given\n// node and invokes the given callbacks as methods on every element\n// node encountered. Function opt_pre is invoked before a node's\n// children are traversed; opt_post is invoked after they are\n// traversed. Traversal will not be continued if a callback function\n// returns boolean false. NOTE(mesch): copied from\n// <//google3/maps/webmaps/javascript/dom.js>.\nfunction domTraverseElements(node, opt_pre, opt_post) {\n  var ret;\n  if (opt_pre) {\n    ret = opt_pre.call(null, node);\n    if (typeof ret == 'boolean' && !ret) {\n      return false;\n    }\n  }\n\n  for (var c = node.firstChild; c; c = c.nextSibling) {\n    if (c.nodeType == DOM_ELEMENT_NODE) {\n      ret = arguments.callee.call(this, c, opt_pre, opt_post);\n      if (typeof ret == 'boolean' && !ret) {\n        return false;\n      }\n    }\n  }\n\n  if (opt_post) {\n    ret = opt_post.call(null, node);\n    if (typeof ret == 'boolean' && !ret) {\n      return false;\n    }\n  }\n}\n\n// Our W3C DOM Node implementation. Note we call it XNode because we\n// can't define the identifier Node. We do this mostly for Opera,\n// where we can't reuse the HTML DOM for parsing our own XML, and for\n// Safari, where it is too expensive to have the template processor\n// operate on native DOM nodes.\nfunction XNode(type, name, opt_value, opt_owner) {\n  this.attributes = [];\n  this.childNodes = [];\n\n  XNode.init.call(this, type, name, opt_value, opt_owner);\n}\n\n// Don't call as method, use apply() or call().\nXNode.init = function(type, name, value, owner) {\n  this.nodeType = type - 0;\n  this.nodeName = '' + name;\n  this.nodeValue = '' + value;\n  this.ownerDocument = owner;\n\n  this.firstChild = null;\n  this.lastChild = null;\n  this.nextSibling = null;\n  this.previousSibling = null;\n  this.parentNode = null;\n}\n\nXNode.unused_ = [];\n\nXNode.recycle = function(node) {\n  if (!node) {\n    return;\n  }\n\n  if (node.constructor == XDocument) {\n    XNode.recycle(node.documentElement);\n    return;\n  }\n\n  if (node.constructor != this) {\n    return;\n  }\n\n  XNode.unused_.push(node);\n  for (var a = 0; a < node.attributes.length; ++a) {\n    XNode.recycle(node.attributes[a]);\n  }\n  for (var c = 0; c < node.childNodes.length; ++c) {\n    XNode.recycle(node.childNodes[c]);\n  }\n  node.attributes.length = 0;\n  node.childNodes.length = 0;\n  XNode.init.call(node, 0, '', '', null);\n}\n\nXNode.create = function(type, name, value, owner) {\n  if (XNode.unused_.length > 0) {\n    var node = XNode.unused_.pop();\n    XNode.init.call(node, type, name, value, owner);\n    return node;\n  } else {\n    return new XNode(type, name, value, owner);\n  }\n}\n\nXNode.prototype.appendChild = function(node) {\n  // firstChild\n  if (this.childNodes.length == 0) {\n    this.firstChild = node;\n  }\n\n  // previousSibling\n  node.previousSibling = this.lastChild;\n\n  // nextSibling\n  node.nextSibling = null;\n  if (this.lastChild) {\n    this.lastChild.nextSibling = node;\n  }\n\n  // parentNode\n  node.parentNode = this;\n\n  // lastChild\n  this.lastChild = node;\n\n  // childNodes\n  this.childNodes.push(node);\n}\n\n\nXNode.prototype.replaceChild = function(newNode, oldNode) {\n  if (oldNode == newNode) {\n    return;\n  }\n\n  for (var i = 0; i < this.childNodes.length; ++i) {\n    if (this.childNodes[i] == oldNode) {\n      this.childNodes[i] = newNode;\n\n      var p = oldNode.parentNode;\n      oldNode.parentNode = null;\n      newNode.parentNode = p;\n\n      p = oldNode.previousSibling;\n      oldNode.previousSibling = null;\n      newNode.previousSibling = p;\n      if (newNode.previousSibling) {\n        newNode.previousSibling.nextSibling = newNode;\n      }\n\n      p = oldNode.nextSibling;\n      oldNode.nextSibling = null;\n      newNode.nextSibling = p;\n      if (newNode.nextSibling) {\n        newNode.nextSibling.previousSibling = newNode;\n      }\n\n      if (this.firstChild == oldNode) {\n        this.firstChild = newNode;\n      }\n\n      if (this.lastChild == oldNode) {\n        this.lastChild = newNode;\n      }\n\n      break;\n    }\n  }\n}\n\n\nXNode.prototype.insertBefore = function(newNode, oldNode) {\n  if (oldNode == newNode) {\n    return;\n  }\n\n  if (oldNode.parentNode != this) {\n    return;\n  }\n\n  if (newNode.parentNode) {\n    newNode.parentNode.removeChild(newNode);\n  }\n\n  var newChildren = [];\n  for (var i = 0; i < this.childNodes.length; ++i) {\n    var c = this.childNodes[i];\n    if (c == oldNode) {\n      newChildren.push(newNode);\n\n      newNode.parentNode = this;\n\n      newNode.previousSibling = oldNode.previousSibling;\n      oldNode.previousSibling = newNode;\n      if (newNode.previousSibling) {\n        newNode.previousSibling.nextSibling = newNode;\n      }\n\n      newNode.nextSibling = oldNode;\n\n      if (this.firstChild == oldNode) {\n        this.firstChild = newNode;\n      }\n    }\n    newChildren.push(c);\n  }\n  this.childNodes = newChildren;\n}\n\n\nXNode.prototype.removeChild = function(node) {\n  var newChildren = [];\n  for (var i = 0; i < this.childNodes.length; ++i) {\n    var c = this.childNodes[i];\n    if (c != node) {\n      newChildren.push(c);\n    } else {\n      if (c.previousSibling) {\n        c.previousSibling.nextSibling = c.nextSibling;\n      }\n      if (c.nextSibling) {\n        c.nextSibling.previousSibling = c.previousSibling;\n      }\n      if (this.firstChild == c) {\n        this.firstChild = c.nextSibling;\n      }\n      if (this.lastChild == c) {\n        this.lastChild = c.previousSibling;\n      }\n    }\n  }\n  this.childNodes = newChildren;\n}\n\n\nXNode.prototype.hasAttributes = function() {\n  return this.attributes.length > 0;\n}\n\n\nXNode.prototype.setAttribute = function(name, value) {\n  for (var i = 0; i < this.attributes.length; ++i) {\n    if (this.attributes[i].nodeName == name) {\n      this.attributes[i].nodeValue = '' + value;\n      return;\n    }\n  }\n  this.attributes.push(XNode.create(DOM_ATTRIBUTE_NODE, name, value, this));\n}\n\n\nXNode.prototype.getAttribute = function(name) {\n  for (var i = 0; i < this.attributes.length; ++i) {\n    if (this.attributes[i].nodeName == name) {\n      return this.attributes[i].nodeValue;\n    }\n  }\n  return null;\n}\n\n\nXNode.prototype.removeAttribute = function(name) {\n  var a = [];\n  for (var i = 0; i < this.attributes.length; ++i) {\n    if (this.attributes[i].nodeName != name) {\n      a.push(this.attributes[i]);\n    }\n  }\n  this.attributes = a;\n}\n\n\nXNode.prototype.getElementsByTagName = function(name) {\n  var ret = [];\n  var self = this;\n  if (\"*\" == name) {\n    domTraverseElements(this, function(node) {\n      if (self == node) return;\n      ret.push(node);\n    }, null);\n  } else {\n    domTraverseElements(this, function(node) {\n      if (self == node) return;\n      if (node.nodeName == name) {\n        ret.push(node);\n      }\n    }, null);\n  }\n  return ret;\n}\n\n\nXNode.prototype.getElementById = function(id) {\n  var ret = null;\n  domTraverseElements(this, function(node) {\n    if (node.getAttribute('id') == id) {\n      ret = node;\n      return false;\n    }\n  }, null);\n  return ret;\n}\n\n\nfunction XDocument() {\n  // NOTE(mesch): Acocording to the DOM Spec, ownerDocument of a\n  // document node is null.\n  XNode.call(this, DOM_DOCUMENT_NODE, '#document', null, null);\n  this.documentElement = null;\n}\n\nXDocument.prototype = new XNode(DOM_DOCUMENT_NODE, '#document');\n\nXDocument.prototype.clear = function() {\n  XNode.recycle(this.documentElement);\n  this.documentElement = null;\n}\n\nXDocument.prototype.appendChild = function(node) {\n  XNode.prototype.appendChild.call(this, node);\n  this.documentElement = this.childNodes[0];\n}\n\nXDocument.prototype.createElement = function(name) {\n  return XNode.create(DOM_ELEMENT_NODE, name, null, this);\n}\n\nXDocument.prototype.createDocumentFragment = function() {\n  return XNode.create(DOM_DOCUMENT_FRAGMENT_NODE, '#document-fragment',\n                    null, this);\n}\n\nXDocument.prototype.createTextNode = function(value) {\n  return XNode.create(DOM_TEXT_NODE, '#text', value, this);\n}\n\nXDocument.prototype.createAttribute = function(name) {\n  return XNode.create(DOM_ATTRIBUTE_NODE, name, null, this);\n}\n\nXDocument.prototype.createComment = function(data) {\n  return XNode.create(DOM_COMMENT_NODE, '#comment', data, this);\n}\n\nXDocument.prototype.createCDATASection = function(data) {\n  return XNode.create(DOM_CDATA_SECTION_NODE, '#cdata-section', data, this);\n}\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/xpath/javascript-xpath-0.1.11.js",
    "content": "/*  JavaScript-XPath 0.1.11\n *  (c) 2007 Cybozu Labs, Inc.\n *\n *  JavaScript-XPath is freely distributable under the terms of an MIT-style license.\n *  For details, see the JavaScript-XPath web site: http://coderepos.org/share/wiki/JavaScript-XPath\n *\n/*--------------------------------------------------------------------------*/\n\n\n\n(function () {\n\nvar undefined = void(0);\n\nvar defaultConfig = {\n    targetFrame: undefined,\n    exportInstaller: false,\n    useNative: true,\n    useInnerText: true\n};\n\nvar config;\n\nif (window.jsxpath) {\n    config = window.jsxpath;\n}\nelse {\n    var scriptElms = document.getElementsByTagName('script');\n    var scriptElm = scriptElms[scriptElms.length - 1];\n    var scriptSrc = scriptElm.src;\n    config = {};\n    var scriptSrcMatchResult = scriptSrc.match(/\\?(.*)$/);\n    if (scriptSrcMatchResult) {\n        var configStrings = scriptSrcMatchResult[1].split('&');\n        for (var i = 0, l = configStrings.length; i < l; i ++) {\n            var configString = configStrings[i];\n            var configStringSplited = configString.split('=');\n            var configName = configStringSplited[0];\n            var configValue = configStringSplited[1];\n            if (configValue == undefined) {\n                configValue == true;\n            }\n            else if (configValue == 'false' || /^-?\\d+$/.test(configValue)) {\n                configValue = eval(configValue);\n            }\n            config[configName] = configValue;\n        }\n    }\n}\n\nfor (var n in defaultConfig) {\n    if (!(n in config)) config[n] = defaultConfig[n];\n}\n\nconfig.hasNative = !!(document.implementation\n                        && document.implementation.hasFeature\n                        && document.implementation.hasFeature(\"XPath\", null));\n\nif (config.hasNative && config.useNative && !config.exportInstaller) {\n    return;\n}\n\n\n\nvar BinaryExpr;\nvar FilterExpr;\nvar FunctionCall;\nvar Literal;\nvar NameTest;\nvar NodeSet;\nvar NodeType;\nvar NodeUtil;\nvar Number;\nvar PathExpr;\nvar Step;\nvar UnaryExpr;\nvar UnionExpr;\nvar VariableReference;\n\n/*\n * object: user agent identifier\n */\nvar uai = new function() {\n\n    var ua = navigator.userAgent;\n\n    if (RegExp == undefined) {\n        if (ua.indexOf(\"Opera\") >= 0) {\n            this.opera = true;\n        } else if (ua.indexOf(\"Netscape\") >= 0) {\n            this.netscape = true;\n        } else if (ua.indexOf(\"Mozilla/\") == 0) {\n            this.mozilla = true;\n        } else {\n            this.unknown = true;\n        }\n\n        if (ua.indexOf(\"Gecko/\") >= 0) {\n            this.gecko = true;\n        }\n\n        if (ua.indexOf(\"Win\") >= 0) {\n            this.windows = true;\n        } else if (ua.indexOf(\"Mac\") >= 0) {\n            this.mac = true;\n        } else if (ua.indexOf(\"Linux\") >= 0) {\n            this.linux = true;\n        } else if (ua.indexOf(\"BSD\") >= 0) {\n            this.bsd = true;\n        } else if (ua.indexOf(\"SunOS\") >= 0) {\n            this.sunos = true;\n        }\n    }\n    else {\n\n        /* for Trident/Tasman */\n        /*@cc_on\n        @if (@_jscript)\n            function jscriptVersion() {\n                switch (@_jscript_version) {\n                    case 3.0:  return \"4.0\";\n                    case 5.0:  return \"5.0\";\n                    case 5.1:  return \"5.01\";\n                    case 5.5:  return \"5.5\";\n                    case 5.6:\n                        if (\"XMLHttpRequest\" in window) return \"7.0\";\n                        return \"6.0\";\n                    case 5.7:\n                        return \"7.0\";\n                    default:   return true;\n                }\n            }\n            if (@_win16 || @_win32 || @_win64) {\n                this.windows = true;\n                this.trident = jscriptVersion();\n            } else if (@_mac || navigator.platform.indexOf(\"Mac\") >= 0) {\n                // '@_mac' may be 'NaN' even if the platform is Mac,\n                // so we check 'navigator.platform', too.\n                this.mac = true;\n                this.tasman = jscriptVersion();\n            }\n            if (/MSIE (\\d+\\.\\d+)b?;/.test(ua)) {\n                this.ie = RegExp.$1;\n                this['ie' + RegExp.$1.charAt(0)] = true;\n            }\n        @else @*/\n\n        /* for AppleWebKit */\n        if (/AppleWebKit\\/(\\d+(?:\\.\\d+)*)/.test(ua)) {\n            this.applewebkit = RegExp.$1;\n            if (RegExp.$1.charAt(0) == 4) {\n                this.applewebkit2 = true;\n            }\n            else {\n                this.applewebkit3 = true;\n            }\n        }\n\n        /* for Gecko */\n        else if (typeof Components == \"object\" &&\n                 (/Gecko\\/(\\d{8})/.test(ua) ||\n                  navigator.product == \"Gecko\" && /^(\\d{8})$/.test(navigator.productSub))) {\n            this.gecko = RegExp.$1;\n        }\n\n        /*@end @*/\n\n        if (typeof(opera) == \"object\" && typeof(opera.version) == \"function\") {\n            this.opera = opera.version();\n            this['opera' + this.opera[0] + this.opera[2]] = true;\n        } else if (typeof opera == \"object\"\n                && (/Opera[\\/ ](\\d+\\.\\d+)/.test(ua))) {\n            this.opera = RegExp.$1;\n        } else if (this.ie) {\n        } else if (/Safari\\/(\\d+(?:\\.\\d+)*)/.test(ua)) {\n            this.safari = RegExp.$1;\n        } else if (/NetFront\\/(\\d+(?:\\.\\d+)*)/.test(ua)) {\n            this.netfront = RegExp.$1;\n        } else if (/Konqueror\\/(\\d+(?:\\.\\d+)*)/.test(ua)) {\n            this.konqueror = RegExp.$1;\n        } else if (ua.indexOf(\"(compatible;\") < 0\n                && (/^Mozilla\\/(\\d+\\.\\d+)/.test(ua))) {\n            this.mozilla = RegExp.$1;\n            if (/\\([^(]*rv:(\\d+(?:\\.\\d+)*).*?\\)/.test(ua))\n                this.mozillarv = RegExp.$1;\n            if (/Firefox\\/(\\d+(?:\\.\\d+)*)/.test(ua)) {\n                this.firefox = RegExp.$1;\n            } else if (/Netscape\\d?\\/(\\d+(?:\\.\\d+)*)/.test(ua)) {\n                this.netscape = RegExp.$1;\n            }\n        } else {\n            this.unknown = true;\n        }\n\n        if (ua.indexOf(\"Win 9x 4.90\") >= 0) {\n            this.windows = \"ME\";\n        } else if (/Win(?:dows)? ?(NT ?(\\d+\\.\\d+)?|\\d+|ME|Vista|XP)/.test(ua)) {\n            this.windows = RegExp.$1;\n            if (RegExp.$2) {\n                this.winnt = RegExp.$2;\n            } else switch (RegExp.$1) {\n                case \"2000\":   this.winnt = \"5.0\";  break;\n                case \"XP\":     this.winnt = \"5.1\";  break;\n                case \"Vista\":  this.winnt = \"6.0\";  break;\n            }\n        } else if (ua.indexOf(\"Mac\") >= 0) {\n            this.mac = true;\n        } else if (ua.indexOf(\"Linux\") >= 0) {\n            this.linux = true;\n        } else if (/(\\w*BSD)/.test(ua)) {\n            this.bsd = RegExp.$1;\n        } else if (ua.indexOf(\"SunOS\") >= 0) {\n            this.sunos = true;\n        }\n    }\n};\n\n\n/**\n * pseudo class: Lexer\n */\nvar Lexer = function(source) {\n    var proto = Lexer.prototype;\n    var tokens = source.match(proto.regs.token);\n    for (var i = 0, l = tokens.length; i < l; i ++) {\n        if (proto.regs.strip.test(tokens[i])) {\n            tokens.splice(i, 1);\n        }\n    }\n    for (var n in proto) tokens[n] = proto[n];\n    tokens.index = 0;\n    return tokens;\n};\n\nLexer.prototype.regs = {\n    token: /\\$?(?:(?![0-9-])[\\w-]+:)?(?![0-9-])[\\w-]+|\\/\\/|\\.\\.|::|\\d+(?:\\.\\d*)?|\\.\\d+|\"[^\"]*\"|'[^']*'|[!<>]=|(?![0-9-])[\\w-]+:\\*|\\s+|./g,\n    strip: /^\\s/\n};\n\nLexer.prototype.peek = function(i) {\n    return this[this.index + (i||0)];\n};\nLexer.prototype.next = function() {\n    return this[this.index++];\n};\nLexer.prototype.back = function() {\n    this.index--;\n};\nLexer.prototype.empty = function() {\n    return this.length <= this.index;\n};\n\n\n/**\n * class: Ctx\n */\nvar Ctx = function(node, position, last) {\n    this.node = node;\n    this.position = position || 1;\n    this.last = last || 1;\n};\n\n\n/**\n * abstract class: BaseExpr\n */\nvar BaseExpr = function() {};\n\nBaseExpr.prototype.number = function(ctx) {\n    var exrs = this.evaluate(ctx);\n    if (exrs.isNodeSet) return exrs.number();\n    return + exrs;\n};\n\nBaseExpr.prototype.string = function(ctx) {\n    var exrs = this.evaluate(ctx);\n    if (exrs.isNodeSet) return exrs.string();\n    return '' + exrs;\n};\n\nBaseExpr.prototype.bool = function(ctx) {\n    var exrs = this.evaluate(ctx);\n    if (exrs.isNodeSet) return exrs.bool();\n    return !! exrs;\n};\n\n\n/**\n * abstract class: BaseExprHasPredicates\n */\nvar BaseExprHasPredicates = function() {};\n\nBaseExprHasPredicates.parsePredicates = function(lexer, expr) {\n    while (lexer.peek() == '[') {\n        lexer.next();\n        if (lexer.empty()) {\n            throw Error('missing predicate expr');\n        }\n        var predicate = BinaryExpr.parse(lexer);\n        expr.predicate(predicate);\n        if (lexer.empty()) {\n            throw Error('unclosed predicate expr');\n        }\n        if (lexer.next() != ']') {\n            lexer.back();\n            throw Error('bad token: ' + lexer.next());\n        }\n    }\n};\n\nBaseExprHasPredicates.prototyps = new BaseExpr();\n\nBaseExprHasPredicates.prototype.evaluatePredicates = function(nodeset, start) {\n    var predicates, predicate, nodes, node, nodeset, position, reverse;\n\n    reverse = this.reverse;\n    predicates = this.predicates;\n\n    nodeset.sort();\n\n    for (var i = start || 0, l0 = predicates.length; i < l0; i ++) {\n        predicate = predicates[i];\n\n        var deleteIndexes = [];\n        var nodes = nodeset.list();\n\n        for (var j = 0, l1 = nodes.length; j < l1; j ++) {\n\n            position = reverse ? (l1 - j) : (j + 1);\n            exrs = predicate.evaluate(new Ctx(nodes[j], position, l1));\n\n            switch (typeof exrs) {\n                case 'number':\n                    exrs = (position == exrs);\n                    break;\n                case 'string':\n                    exrs = !!exrs;\n                    break;\n                case 'object':\n                    exrs = exrs.bool();\n                    break;\n            }\n\n            if (!exrs) {\n                deleteIndexes.push(j);\n            }\n        }\n\n        for (var j = deleteIndexes.length - 1, l1 = 0; j >= l1; j --) {\n            nodeset.del(deleteIndexes[j]);\n        }\n\n    }\n\n    return nodeset;\n};\n\n\n/**\n * class: BinaryExpr\n */\nif (!window.BinaryExpr && window.defaultConfig)\n    window.BinaryExpr = null;\n\nBinaryExpr = function(op, left, right, datatype) {\n    this.op = op;\n    this.left = left;\n    this.right = right;\n\n    this.datatype = BinaryExpr.ops[op][2];\n\n    this.needContextPosition = left.needContextPosition || right.needContextPosition;\n    this.needContextNode = left.needContextNode || right.needContextNode;\n\n    // Optimize [@id=\"foo\"] and [@name=\"bar\"]\n    if (this.op == '=') {\n        if (!right.needContextNode && !right.needContextPosition && \n            right.datatype != 'nodeset' && right.datatype != 'void' && left.quickAttr) {\n            this.quickAttr = true;\n            this.attrName = left.attrName;\n            this.attrValueExpr = right;\n        }\n        else if (!left.needContextNode && !left.needContextPosition && \n            left.datatype != 'nodeset' && left.datatype != 'void' && right.quickAttr) {\n            this.quickAttr = true;\n            this.attrName = right.attrName;\n            this.attrValueExpr = left;\n        }\n    }\n};\n\nBinaryExpr.compare = function(op, comp, left, right, ctx) {\n    var type, lnodes, rnodes, nodes, nodeset, primitive;\n\n    left = left.evaluate(ctx);\n    right = right.evaluate(ctx);\n\n    if (left.isNodeSet && right.isNodeSet) {\n        lnodes = left.list();\n        rnodes = right.list();\n        for (var i = 0, l0 = lnodes.length; i < l0; i ++)\n            for (var j = 0, l1 = rnodes.length; j < l1; j ++)\n                if (comp(NodeUtil.to('string', lnodes[i]), NodeUtil.to('string', rnodes[j])))\n                    return true;\n        return false;\n    }\n\n    if (left.isNodeSet || right.isNodeSet) {\n        if (left.isNodeSet)\n            nodeset = left, primitive = right;\n        else\n            nodeset = right, primitive = left;\n\n        nodes = nodeset.list();\n        type = typeof primitive;\n        for (var i = 0, l = nodes.length; i < l; i ++) {\n            if (comp(NodeUtil.to(type, nodes[i]), primitive))\n                return true;\n        }\n        return false;\n    }\n\n    if (op == '=' || op == '!=') {\n        if (typeof left == 'boolean' || typeof right == 'boolean') {\n            return comp(!!left, !!right);\n        }\n        if (typeof left == 'number' || typeof right == 'number') {\n            return comp(+left, +right);\n        }\n        return comp(left, right);\n    }\n\n    return comp(+left, +right);\n};\n\n\nBinaryExpr.ops = {\n    'div': [6, function(left, right, ctx) {\n        return left.number(ctx) / right.number(ctx);\n    }, 'number'],\n    'mod': [6, function(left, right, ctx) {\n        return left.number(ctx) % right.number(ctx);\n    }, 'number'],\n    '*': [6, function(left, right, ctx) {\n        return left.number(ctx) * right.number(ctx);\n    }, 'number'],\n    '+': [5, function(left, right, ctx) {\n        return left.number(ctx) + right.number(ctx);\n    }, 'number'],\n    '-': [5, function(left, right, ctx) {\n        return left.number(ctx) - right.number(ctx);\n    }, 'number'],\n    '<': [4, function(left, right, ctx) {\n        return BinaryExpr.compare('<',\n                    function(a, b) { return a < b }, left, right, ctx);\n    }, 'boolean'],\n    '>': [4, function(left, right, ctx) {\n        return BinaryExpr.compare('>',\n                    function(a, b) { return a > b }, left, right, ctx);\n    }, 'boolean'],\n    '<=': [4, function(left, right, ctx) {\n        return BinaryExpr.compare('<=',\n                    function(a, b) { return a <= b }, left, right, ctx);\n    }, 'boolean'],\n    '>=': [4, function(left, right, ctx) {\n        return BinaryExpr.compare('>=',\n                    function(a, b) { return a >= b }, left, right, ctx);\n    }, 'boolean'],\n    '=': [3, function(left, right, ctx) {\n        return BinaryExpr.compare('=',\n                    function(a, b) { return a == b }, left, right, ctx);\n    }, 'boolean'],\n    '!=': [3, function(left, right, ctx) {\n        return BinaryExpr.compare('!=',\n                    function(a, b) { return a != b }, left, right, ctx);\n    }, 'boolean'],\n    'and': [2, function(left, right, ctx) {\n        return left.bool(ctx) && right.bool(ctx);\n    }, 'boolean'],\n    'or': [1, function(left, right, ctx) {\n        return left.bool(ctx) || right.bool(ctx);\n    }, 'boolean']\n};\n\n\nBinaryExpr.parse = function(lexer) {\n    var op, precedence, info, expr, stack = [], index = lexer.index;\n\n    while (true) {\n\n        if (lexer.empty()) {\n            throw Error('missing right expression');\n        }\n        expr = UnaryExpr.parse(lexer);\n\n        op = lexer.next();\n        if (!op) {\n            break;\n        }\n\n        info = this.ops[op];\n        precedence = info && info[0];\n        if (!precedence) {\n            lexer.back();\n            break;\n        }\n\n        while (stack.length && precedence <= this.ops[stack[stack.length-1]][0]) {\n            expr = new BinaryExpr(stack.pop(), stack.pop(), expr);\n        }\n\n        stack.push(expr, op);\n    }\n\n    while (stack.length) {\n        expr = new BinaryExpr(stack.pop(), stack.pop(), expr);\n    }\n\n    return expr;\n};\n\nBinaryExpr.prototype = new BaseExpr();\n\nBinaryExpr.prototype.evaluate = function(ctx) {\n    return BinaryExpr.ops[this.op][1](this.left, this.right, ctx);\n};\n\nBinaryExpr.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'binary: ' + this.op + '\\n';\n    indent += '    ';\n    t += this.left.show(indent);\n    t += this.right.show(indent);\n    return t;\n};\n\n\n/**\n * class: UnaryExpr\n */\nif (!window.UnaryExpr && window.defaultConfig)\n    window.UnaryExpr = null;\n\nUnaryExpr = function(op, expr) {\n    this.op = op;\n    this.expr = expr;\n\n    this.needContextPosition = expr.needContextPosition;\n    this.needContextNode = expr.needContextNode;\n};\n\nUnaryExpr.ops = { '-': 1 };\n\nUnaryExpr.parse = function(lexer) {\n    var token;\n    if (this.ops[lexer.peek()])\n        return new UnaryExpr(lexer.next(), UnaryExpr.parse(lexer));\n    else\n        return UnionExpr.parse(lexer);\n};\n\nUnaryExpr.prototype = new BaseExpr();\n\nUnaryExpr.prototype.datatype = 'number';\n\nUnaryExpr.prototype.evaluate = function(ctx) {\n    return - this.expr.number(ctx);\n};\n\nUnaryExpr.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'unary: ' + this.op + '\\n';\n    indent += '    ';\n    t += this.expr.show(indent);\n    return t;\n};\n\n\n/**\n * class: UnionExpr\n */\nif (!window.UnionExpr && window.defaultConfig)\n    window.UnionExpr = null;\n\nUnionExpr = function() {\n    this.paths = [];\n};\n\nUnionExpr.ops = { '|': 1 };\n\n\nUnionExpr.parse = function(lexer) {\n    var union, expr;\n\n    expr = PathExpr.parse(lexer);\n    if (!this.ops[lexer.peek()])\n        return expr;\n\n    union = new UnionExpr();\n    union.path(expr);\n\n    while (true) {\n        if (!this.ops[lexer.next()]) break;\n        if (lexer.empty()) {\n            throw Error('missing next union location path');\n        }\n        union.path(PathExpr.parse(lexer));\n    }\n\n\n\n    lexer.back();\n    return union;\n};\n\nUnionExpr.prototype = new BaseExpr();\n\nUnionExpr.prototype.datatype = 'nodeset';\n\nUnionExpr.prototype.evaluate = function(ctx) {\n    var paths = this.paths;\n    var nodeset = new NodeSet();\n    for (var i = 0, l = paths.length; i < l; i ++) {\n        var exrs = paths[i].evaluate(ctx);\n        if (!exrs.isNodeSet) throw Error('PathExpr must be nodeset');\n        nodeset.merge(exrs);\n    }\n    return nodeset;\n};\n\nUnionExpr.prototype.path = function(path) {\n    this.paths.push(path);\n\n    if (path.needContextPosition) {\n        this.needContextPosition = true;\n    }\n    if (path.needContextNode) {\n        this.needContextNode = true;\n    }\n}\nUnionExpr.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'union:' + '\\n';\n    indent += '    ';\n    for (var i = 0; i < this.paths.length; i ++) {\n        t += this.paths[i].show(indent);\n    }\n    return t;\n};\n\n\n/**\n * class: PathExpr\n */\nif (!window.PathExpr && window.defaultConfig)\n    window.PathExpr = null;\n\nPathExpr = function(filter) {\n    this.filter = filter;\n    this.steps = [];\n\n    this.datatype = filter.datatype;\n\n    this.needContextPosition = filter.needContextPosition;\n    this.needContextNode = filter.needContextNode;\n};\n\nPathExpr.ops = { '//': 1, '/': 1 };\n\nPathExpr.parse = function(lexer) {\n    var op, expr, path, token;\n\n    if (this.ops[lexer.peek()]) {\n        op = lexer.next();\n        token = lexer.peek();\n\n        if (op == '/' && (lexer.empty() || \n                (token != '.' && token != '..' && token != '@' && token != '*' && \n                !/(?![0-9])[\\w]/.test(token)))) { \n            return FilterExpr.root();\n        }\n\n        path = new PathExpr(FilterExpr.root()); // RootExpr\n\n        if (lexer.empty()) {\n            throw Error('missing next location step');\n        }\n        expr = Step.parse(lexer);\n        path.step(op, expr);\n    }\n    else {\n        expr = FilterExpr.parse(lexer);\n        if (!expr) {\n            expr = Step.parse(lexer);\n            path = new PathExpr(FilterExpr.context());\n            path.step('/', expr);\n        }\n        else if (!this.ops[lexer.peek()])\n            return expr;\n        else\n            path = new PathExpr(expr);\n    }\n\n    while (true) {\n        if (!this.ops[lexer.peek()]) break;\n        op = lexer.next();\n        if (lexer.empty()) {\n            throw Error('missing next location step');\n        }\n        path.step(op, Step.parse(lexer));\n    }\n\n    return path;\n};\n\nPathExpr.prototype = new BaseExpr();\n\nPathExpr.prototype.evaluate = function(ctx) {\n    var nodeset = this.filter.evaluate(ctx);\n    if (!nodeset.isNodeSet) throw Exception('Filter nodeset must be nodeset type');\n\n    var steps = this.steps;\n\n    for (var i = 0, l0 = steps.length; i < l0 && nodeset.length; i ++) {\n        var step = steps[i][1];\n        var reverse = step.reverse;\n        var iter = nodeset.iterator(reverse);\n        var prevNodeset = nodeset;\n        nodeset = null;\n        var node, next;\n        if (!step.needContextPosition && step.axis == 'following') {\n            for (node = iter(); next = iter(); node = next) {\n\n                // Safari 2 node.contains problem\n                if (uai.applewebkit2) {\n                    var contains = false;\n                    var ancestor = next;\n                    do {\n                        if (ancestor == node) {\n                            contains = true;\n                            break;\n                        }\n                    } while (ancestor = ancestor.parentNode);\n                    if (!contains) break;\n                }\n                else {\n                    try { if (!node.contains(next)) break }\n                    catch(e) { if (!(next.compareDocumentPosition(node) & 8)) break }\n                }\n            }\n            nodeset = step.evaluate(new Ctx(node));\n        }\n        else if (!step.needContextPosition && step.axis == 'preceding') {\n            node = iter();\n            nodeset = step.evaluate(new Ctx(node));\n        }\n        else {\n            node = iter();\n            var j = 0;\n            nodeset = step.evaluate(new Ctx(node), false, prevNodeset, j);\n            while (node = iter()) {\n                j ++;\n                nodeset.merge(step.evaluate(new Ctx(node), false, prevNodeset, j));\n            }\n        }\n    }\n\n    return nodeset;\n};\n\nPathExpr.prototype.step = function(op, step) {\n    step.op = op;\n    this.steps.push([op, step]);\n\n    this.quickAttr = false;\n\n    if (this.steps.length == 1) {\n        if (op == '/' && step.axis == 'attribute') {\n            var test = step.test;\n            if (!test.notOnlyElement && test.name != '*') {\n                this.quickAttr = true;\n                this.attrName = test.name;\n            }\n        }\n    }\n};\n\nPathExpr.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'path:' + '\\n';\n    indent += '    ';\n    t += indent + 'filter:' + '\\n';\n    t += this.filter.show(indent + '    ');\n    if (this.steps.length) {\n        t += indent + 'steps:' + '\\n';\n        indent += '    ';\n        for (var i = 0; i < this.steps.length; i ++) {\n            var step = this.steps[i];\n            t += indent + 'operator: ' + step[0] + '\\n';\n            t += step[1].show(indent);\n        }\n    }\n    return t;\n};\n\n\n/**\n * class: FilterExpr\n */\nif (!window.FilterExpr && window.defaultConfig)\n    window.FilterExpr = null;\n\nFilterExpr = function(primary) {\n    this.primary = primary;\n    this.predicates = [];\n\n    this.datatype = primary.datatype;\n\n    this.needContextPosition = primary.needContextPosition;\n\n    this.needContextNode = primary.needContextNode;\n};\n\nFilterExpr.parse = function(lexer) {\n    var expr, filter, token, ch;\n\n    token = lexer.peek();\n    ch = token.charAt(0);\n\n    switch (ch) {\n        case '$':\n            expr = VariableReference.parse(lexer);\n            break;\n\n        case '(':\n            lexer.next();\n            expr = BinaryExpr.parse(lexer);\n            if (lexer.empty()) {\n                throw Error('unclosed \"(\"');\n            }\n            if (lexer.next() != ')') {\n                lexer.back();\n                throw Error('bad token: ' + lexer.next());\n            }\n            break;\n\n        case '\"':\n        case \"'\":\n            expr = Literal.parse(lexer);\n            break;\n\n        default:\n            if (!isNaN(+token)) {\n                expr = Number.parse(lexer);\n            }\n\n            else if (NodeType.types[token]) {\n                return null;\n            }\n\n            else if (/(?![0-9])[\\w]/.test(ch) && lexer.peek(1) == '(') {\n                expr = FunctionCall.parse(lexer);\n            }\n            else {\n                return null;\n            }\n            break;\n    }\n\n    if (lexer.peek() != '[') return expr;\n\n    filter = new FilterExpr(expr);\n\n    BaseExprHasPredicates.parsePredicates(lexer, filter);\n\n    return filter;\n};\n\nFilterExpr.root = function() {\n    return new FunctionCall('root-node');\n};\nFilterExpr.context = function() {\n    return new FunctionCall('context-node');\n};\n\nFilterExpr.prototype = new BaseExprHasPredicates();\n\nFilterExpr.prototype.evaluate = function(ctx) {\n    var nodeset = this.primary.evaluate(ctx);\n    if(!nodeset.isNodeSet) {\n        if (this.predicates.length)\n            throw Error(\n                'Primary result must be nodeset type ' +\n                'if filter have predicate expression');\n        return nodeset;\n    }\n\n    return  this.evaluatePredicates(nodeset);\n};\n\nFilterExpr.prototype.predicate = function(predicate) {\n    this.predicates.push(predicate);\n};\n\nFilterExpr.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'filter: ' + '\\n';\n    indent += '    ';\n    t += this.primary.show(indent);\n    if (this.predicates.length) {\n        t += indent + 'predicates: ' + '\\n';\n        indent += '    ';\n        for (var i = 0; i < this.predicates.length; i ++) {\n            t += this.predicates[i].show(indent);\n        }\n    }\n    return t;\n};\n\n\nif (!window.NodeUtil && window.defaultConfig)\n    window.NodeUtil = null;\n\nNodeUtil = {\n    to: function(valueType, node) {\n        var t, type = node.nodeType;\n        // Safari2: innerText contains some bugs\n        if (type == 1 && config.useInnerText && !uai.applewebkit2) {\n            t = node.textContent;\n            t = (t == undefined || t == null) ? node.innerText : t;\n            t = (t == undefined || t == null) ? '' : t;\n        }\n        if (typeof t != 'string') {\n/*@cc_on\n            if (type == 1 && node.nodeName.toLowerCase() == 'title') {\n                t = node.text;\n            }\n            else\n@*/\n            if (type == 9 || type == 1) {\n                if (type == 9) {\n                    node =  node.documentElement;\n                }\n                else {\n                    node = node.firstChild;\n                }\n                for (t = '', stack = [], i = 0; node;) {\n                    do {\n                        if (node.nodeType != 1) {\n                            t += node.nodeValue;\n                        }\n/*@cc_on\n                        else if (node.nodeName.toLowerCase() == 'title') {\n                            t += node.text;\n                        }\n@*/\n                        stack[i++] = node; // push\n                    } while (node = node.firstChild);\n                    while (i && !(node = stack[--i].nextSibling)) {}\n                }\n            }\n            else {\n                t = node.nodeValue;\n            }\n        }\n        switch (valueType) {\n            case 'number':\n                return + t;\n            case 'boolean':\n                return !! t;\n            default:\n                return t;\n        }\n    },\n    attrPropMap: {\n        name: 'name',\n        'class': 'className',\n        dir: 'dir',\n        id: 'id',\n        name: 'name',\n        title: 'title'\n    },\n    attrMatch: function(node, attrName, attrValue) {\n/*@cc_on @if (@_jscript)\n        var propName = NodeUtil.attrPropMap[attrName];\n        if (!attrName ||\n            attrValue == null && (\n                propName && node[propName] ||\n                !propName && node.getAttribute && node.getAttribute(attrName, 2)\n            ) ||\n            attrValue != null && (\n                propName && node[propName] == attrValue ||\n                !propName && node.getAttribute && node.getAttribute(attrName, 2) == attrValue\n            )) {\n@else @*/\n        if (!attrName ||\n            attrValue == null && node.hasAttribute && node.hasAttribute(attrName) ||\n            attrValue != null && node.getAttribute && node.getAttribute(attrName) == attrValue) {\n/*@end @*/\n            return true;\n        }\n        else {\n            return false;\n        }\n    },\n    getDescendantNodes: function(test, node, nodeset, attrName, attrValue, prevNodeset, prevIndex) {\n        if (prevNodeset) {\n            prevNodeset.delDescendant(node, prevIndex);\n        }\n/*@cc_on\n        try {\n            if (!test.notOnlyElement || test.type == 8 || (attrName && test.type == 0)) {\n\n                var all = node.all;\n                if (!all) {\n                    return nodeset;\n                }\n\n                var name = test.name;\n                if (test.type == 8) name = '!';\n                else if (test.type == 0) name = '*';\n\n                if (name != '*') {\n                    all = all.tags(name);\n                    if (!all) {\n                        return nodeset;\n                    }\n                }\n\n                if (attrName) {\n                    var result = []\n                    var i = 0;\n                    if (attrValue != null && (attrName == 'id' || attrName == 'name')) {\n                        all = all[attrValue];\n                        if (!all) {\n                            return nodeset;\n                        }\n                        if (!all.length || all.nodeType) {\n                            all = [all];\n                        }\n                    }\n        \n                    while (node = all[i++]) {\n                        if (NodeUtil.attrMatch(node, attrName, attrValue)) result.push(node);\n                    }\n\n                    all = result;\n                }\n\n                var i = 0;\n                while (node = all[i++]) {\n                    if (name != '*' || node.tagName != '!') {\n                        nodeset.push(node);\n                    }\n                }\n\n                return nodeset;\n            }\n\n            (function (parent) {\n                var g = arguments.callee;\n                var node = parent.firstChild;\n                if (node) {\n                    for (; node; node = node.nextSibling) {\n                        if (NodeUtil.attrMatch(node, attrName, attrValue)) {\n                            if (test.match(node)) nodeset.push(node);\n                        }\n                        g(node);\n                    }\n                }\n            })(node);\n\n            return nodeset;\n        }\n        catch(e) {\n@*/\n        if (attrValue && attrName == 'id' && node.getElementById) {\n            node = node.getElementById(attrValue);\n            if (node && test.match(node)) {\n                nodeset.push(node);\n            }\n        }\n        else if (attrValue && attrName == 'name' && node.getElementsByName) {\n            var nodes = node.getElementsByName(attrValue);\n            for (var i = 0, l = nodes.length; i < l; i ++) {\n                node = nodes[i];\n                if (uai.opera ? (node.name == attrValue && test.match(node)) : test.match(node)) {\n                    nodeset.push(node);\n                }\n            }\n        }\n        else if (attrValue && attrName == 'class' && node.getElementsByClassName) {\n            var nodes = node.getElementsByClassName(attrValue);\n            for (var i = 0, l = nodes.length; i < l; i ++) {\n                node = nodes[i];\n                if (node.className == attrValue && test.match(node)) {\n                    nodeset.push(node);\n                }\n            }\n        }\n        else if (test.notOnlyElement) {\n            (function (parent) {\n                var f = arguments.callee;\n                for (var node = parent.firstChild; node; node = node.nextSibling) {\n                    if (NodeUtil.attrMatch(node, attrName, attrValue)) {\n                        if (test.match(node.nodeType)) nodeset.push(node);\n                    }\n                    f(node);\n                }\n            })(node);\n        }\n        else {\n            var name = test.name;\n            if (node.getElementsByTagName) {\n                var nodes = node.getElementsByTagName(name);\n                if (nodes) {\n                    var i = 0;\n                    while (node = nodes[i++]) {\n                        if (NodeUtil.attrMatch(node, attrName, attrValue)) nodeset.push(node);\n                    }\n                }\n            }\n        }\n        return nodeset;\n/*@cc_on\n        }\n@*/\n    },\n\n    getChildNodes: function(test, node, nodeset, attrName, attrValue) {\n\n/*@cc_on\n        try {\n            var children;\n\n            if ((!test.notOnlyElement || test.type == 8 || (attrName && test.type == 0)) && (children = node.children)) {\n                var name, elm;\n\n                name = test.name;\n                if (test.type == 8) name = '!';\n                else if (test.type == 0) name = '*';\n\n                if (name != '*') {\n                    children = children.tags(name);\n                    if (!children) {\n                        return nodeset;\n                    }\n                }\n\n                if (attrName) {\n                    var result = []\n                    var i = 0;\n                    if (attrName == 'id' || attrName == 'name') {\n                        children = children[attrValue];\n        \n                        if (!children) {\n                            return nodeset;\n                        }\n        \n                        if (!children.length || children.nodeType) {\n                            children = [children];\n                        }\n                    }\n        \n                    while (node = children[i++]) {\n                        if (NodeUtil.attrMatch(node, attrName, attrValue)) result.push(node);\n                    }\n                    children = result;\n                }\n\n                var i = 0;\n                while (node = children[i++]) {\n                    if (name != '*' || node.tagName != '!') {\n                        nodeset.push(node);\n                    }\n                }\n\n                return nodeset;\n            }\n\n            for (var i = 0, node = node.firstChild; node; i++, node = node.nextSibling) {\n                if (NodeUtil.attrMatch(node, attrName, attrValue)) {\n                    if (test.match(node)) nodeset.push(node);\n                }\n            }\n\n            return nodeset;\n        } catch(e) {\n@*/\n        for (var node = node.firstChild; node; node = node.nextSibling) {\n            if (NodeUtil.attrMatch(node, attrName, attrValue)) {\n                if (test.match(node)) nodeset.push(node);\n            }\n        }\n        return nodeset;\n/*@cc_on\n        }\n@*/\n    }\n};\n\n/*@cc_on\nvar AttributeWrapper = function(node, parent, sourceIndex) {\n    this.node = node;\n    this.nodeType = 2;\n    this.nodeValue = node.nodeValue;\n    this.nodeName = node.nodeName;\n    this.parentNode = parent;\n    this.ownerElement = parent;\n    this.parentSourceIndex = sourceIndex;\n};\n\n@*/\n\n\n/**\n * class: Step\n */\nif (!window.Step && window.defaultConfig)\n    window.Step = null;\n\nStep = function(axis, test) {\n    // TODO check arguments and throw axis error\n    this.axis = axis;\n    this.reverse = Step.axises[axis][0];\n    this.func = Step.axises[axis][1];\n    this.test = test;\n    this.predicates = [];\n    this._quickAttr = Step.axises[axis][2]\n};\n\nStep.axises = {\n\n    ancestor: [true, function(test, node, nodeset, _, __, prevNodeset, prevIndex) {\n        while (node = node.parentNode) {\n            if (prevNodeset && node.nodeType == 1) {\n                prevNodeset.reserveDelByNode(node, prevIndex, true);\n            }\n            if (test.match(node)) nodeset.unshift(node);\n        }\n        return nodeset;\n    }],\n\n    'ancestor-or-self': [true, function(test, node, nodeset, _, __, prevNodeset, prevIndex) {\n        do {\n            if (prevNodeset && node.nodeType == 1) {\n                prevNodeset.reserveDelByNode(node, prevIndex, true);\n            }\n            if (test.match(node)) nodeset.unshift(node);\n        } while (node = node.parentNode)\n        return nodeset;\n    }],\n\n    attribute: [false, function(test, node, nodeset) {\n        var attrs = node.attributes;\n        if (attrs) {\n/*@cc_on\n            var sourceIndex = node.sourceIndex;\n@*/\n            if ((test.notOnlyElement && test.type == 0) || test.name == '*') {\n                for (var i = 0, attr; attr = attrs[i]; i ++) {\n/*@cc_on @if (@_jscript)\n                    if (attr.nodeValue) {\n                        nodeset.push(new AttributeWrapper(attr, node, sourceIndex));\n                    }\n@else @*/\n                    nodeset.push(attr);\n/*@end @*/\n                }\n            }\n            else {\n                var attr = attrs.getNamedItem(test.name);\n                \n/*@cc_on @if (@_jscript)\n                if (attr && attr.nodeValue) {\n                    attr = new AttributeWrapper(attr, node, sourceIndex);;\n@else @*/\n                if (attr) {\n/*@end @*/\n                    nodeset.push(attr);\n                }\n            }\n        }\n        return nodeset;\n    }],\n\n    child: [false, NodeUtil.getChildNodes, true],\n\n    descendant: [false, NodeUtil.getDescendantNodes, true],\n\n    'descendant-or-self': [false, function(test, node, nodeset, attrName, attrValue, prevNodeset, prevIndex) {\n        if (NodeUtil.attrMatch(node, attrName, attrValue)) {\n            if (test.match(node)) nodeset.push(node);\n        }\n        return NodeUtil.getDescendantNodes(test, node, nodeset, attrName, attrValue, prevNodeset, prevIndex);\n    }, true],\n\n    following: [false, function(test, node, nodeset, attrName, attrValue) {\n        do {\n            var child = node;\n            while (child = child.nextSibling) {\n                if (NodeUtil.attrMatch(child, attrName, attrValue)) {\n                    if (test.match(child)) nodeset.push(child);\n                }\n                nodeset = NodeUtil.getDescendantNodes(test, child, nodeset, attrName, attrValue);\n            }\n        } while (node = node.parentNode);\n        return nodeset;\n    }, true],\n\n    'following-sibling': [false, function(test, node, nodeset, _, __, prevNodeset, prevIndex) {\n        while (node = node.nextSibling) {\n\n            if (prevNodeset && node.nodeType == 1) {\n                prevNodeset.reserveDelByNode(node, prevIndex);\n            }\n\n            if (test.match(node)) {\n                nodeset.push(node);\n            }\n        }\n        return nodeset;\n    }],\n\n    namespace: [false, function(test, node, nodeset) {\n        // not implemented\n        return nodeset;\n    }],\n\n    parent: [false, function(test, node, nodeset) {\n        if (node.nodeType == 9) {\n            return nodeset;\n        }\n        if (node.nodeType == 2) {\n            nodeset.push(node.ownerElement);\n            return nodeset;\n        }\n        var node = node.parentNode;\n        if (test.match(node)) nodeset.push(node);\n        return nodeset;\n    }],\n\n    preceding: [true, function(test, node, nodeset, attrName, attrValue) {\n        var parents = [];\n        do {\n            parents.unshift(node);\n        } while (node = node.parentNode);\n\n        for (var i = 1, l0 = parents.length; i < l0; i ++) {\n            var siblings = [];\n            node = parents[i];\n            while (node = node.previousSibling) {\n                siblings.unshift(node);\n            }\n\n            for (var j = 0, l1 = siblings.length; j < l1; j ++) {\n                node = siblings[j];\n                if (NodeUtil.attrMatch(node, attrName, attrValue)) {\n                    if (test.match(node)) nodeset.push(node);\n                }\n                nodeset = NodeUtil.getDescendantNodes(test, node, nodeset, attrName, attrValue);\n            }\n        }\n        return nodeset;\n    }, true],\n\n    'preceding-sibling': [true, function(test, node, nodeset, _, __, prevNodeset, prevIndex) {\n        while (node = node.previousSibling) {\n\n            if (prevNodeset && node.nodeType == 1) {\n                prevNodeset.reserveDelByNode(node, prevIndex, true);\n            }\n\n            if (test.match(node)) {\n                nodeset.unshift(node)\n            }\n        }\n        return nodeset;\n    }],\n\n    self: [false, function(test, node, nodeset) {\n        if (test.match(node)) nodeset.push(node);\n        return nodeset;\n    }]\n};\n\nStep.parse = function(lexer) {\n    var axis, test, step, token;\n\n    if (lexer.peek() == '.') {\n        step = this.self();\n        lexer.next();\n    }\n    else if (lexer.peek() == '..') {\n        step = this.parent();\n        lexer.next();\n    }\n    else {\n        if (lexer.peek() == '@') {\n            axis = 'attribute';\n            lexer.next();\n            if (lexer.empty()) {\n                throw Error('missing attribute name');\n            }\n        }\n        else {\n            if (lexer.peek(1) == '::') {\n                \n                if (!/(?![0-9])[\\w]/.test(lexer.peek().charAt(0))) {\n                    throw Error('bad token: ' + lexer.next());\n                }\n        \n                axis = lexer.next();\n                lexer.next();\n\n                if (!this.axises[axis]) {\n                    throw Error('invalid axis: ' + axis);\n                }\n                if (lexer.empty()) {\n                    throw Error('missing node name');\n                }\n            }\n            else {\n                axis = 'child';\n            }\n        }\n    \n        token = lexer.peek();\n        if (!/(?![0-9])[\\w]/.test(token.charAt(0))) {\n            if (token == '*') {\n                test = NameTest.parse(lexer)\n            }\n            else {\n                throw Error('bad token: ' + lexer.next());\n            }\n        }\n        else {\n            if (lexer.peek(1) == '(') {\n                if (!NodeType.types[token]) {\n                    throw Error('invalid node type: ' + token);\n                }\n                test = NodeType.parse(lexer)\n            }\n            else {\n                test = NameTest.parse(lexer);\n            }\n        }\n        step = new Step(axis, test);\n    }\n\n    BaseExprHasPredicates.parsePredicates(lexer, step);\n\n    return step;\n};\n\nStep.self = function() {\n    return new Step('self', new NodeType('node'));\n};\n\nStep.parent = function() {\n    return new Step('parent', new NodeType('node'));\n};\n\nStep.prototype = new BaseExprHasPredicates();\n\nStep.prototype.evaluate = function(ctx, special, prevNodeset, prevIndex) {\n    var node = ctx.node;\n    var reverse = false;\n\n    if (!special && this.op == '//') {\n\n        if (!this.needContextPosition && this.axis == 'child') {\n            if (this.quickAttr) {\n                var attrValue = this.attrValueExpr ? this.attrValueExpr.string(ctx) : null;\n                var nodeset = NodeUtil.getDescendantNodes(this.test, node, new NodeSet(), this.attrName, attrValue, prevNodeset, prevIndex);\n                nodeset = this.evaluatePredicates(nodeset, 1);\n            }\n            else {\n                var nodeset = NodeUtil.getDescendantNodes(this.test, node, new NodeSet(), null, null, prevNodeset, prevIndex);\n                nodeset = this.evaluatePredicates(nodeset);\n            }\n        }\n        else {\n            var step = new Step('descendant-or-self', new NodeType('node'));\n            var nodes = step.evaluate(ctx, false, prevNodeset, prevIndex).list();\n            var nodeset = null;\n            step.op = '/';\n            for (var i = 0, l = nodes.length; i < l; i ++) {\n                if (!nodeset) {\n                    nodeset = this.evaluate(new Ctx(nodes[i]), true);\n                }\n                else {\n                    nodeset.merge(this.evaluate(new Ctx(nodes[i]), true));\n                }\n            }\n            nodeset = nodeset || new NodeSet();\n        }\n    }\n    else {\n\n        if (this.needContextPosition) {\n            prevNodeset = null;\n            prevIndex = null;\n        }\n\n        if (this.quickAttr) {\n            var attrValue = this.attrValueExpr ? this.attrValueExpr.string(ctx) : null;\n            var nodeset = this.func(this.test, node, new NodeSet(), this.attrName, attrValue, prevNodeset, prevIndex);\n            nodeset = this.evaluatePredicates(nodeset, 1);\n        }\n        else {\n            var nodeset = this.func(this.test, node, new NodeSet(), null, null, prevNodeset, prevIndex);\n            nodeset = this.evaluatePredicates(nodeset);\n        }\n        if (prevNodeset) {\n            prevNodeset.doDel();\n        }\n    }\n    return nodeset;\n};\n\nStep.prototype.predicate = function(predicate) {\n    this.predicates.push(predicate);\n\n    if (predicate.needContextPosition ||\n        predicate.datatype == 'number'||\n        predicate.datatype == 'void') {\n        this.needContextPosition = true;\n    }\n\n    if (this._quickAttr && this.predicates.length == 1 && predicate.quickAttr) {\n        var attrName = predicate.attrName;\n/*@cc_on @if (@_jscript)\n        this.attrName = attrName.toLowerCase();\n@else @*/\n        this.attrName = attrName;\n/*@end @*/\n        this.attrValueExpr = predicate.attrValueExpr;\n        this.quickAttr = true;\n    }\n};\n\nStep.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'step: ' + '\\n';\n    indent += '    ';\n    if (this.axis) t += indent + 'axis: ' + this.axis + '\\n';\n    t += this.test.show(indent);\n    if (this.predicates.length) {\n        t += indent + 'predicates: ' + '\\n';\n        indent += '    ';\n        for (var i = 0; i < this.predicates.length; i ++) {\n            t += this.predicates[i].show(indent);\n        }\n    }\n    return t;\n};\n\n\n\n/**\n * NodeType\n */\nif (!window.NodeType && window.defaultConfig)\n    window.NodeType = null;\n    \nNodeType = function(name, literal) {\n    this.name = name;\n    this.literal = literal;\n\n    switch (name) {\n        case 'comment':\n            this.type = 8;\n            break;\n        case 'text':\n            this.type = 3;\n            break;\n        case 'processing-instruction':\n            this.type = 7;\n            break;\n        case 'node':\n            this.type = 0;\n            break;\n    }\n};\n\nNodeType.types = {\n    'comment':1, 'text':1, 'processing-instruction':1, 'node':1\n};\n\nNodeType.parse = function(lexer) {\n    var type, literal, ch;\n    type = lexer.next();\n    lexer.next();\n    if (lexer.empty()) {\n        throw Error('bad nodetype');\n    }\n    ch = lexer.peek().charAt(0);\n    if (ch == '\"' || ch == \"'\") {\n        literal = Literal.parse(lexer);\n    }\n    if (lexer.empty()) {\n        throw Error('bad nodetype');\n    }\n    if (lexer.next() != ')') {\n        lexer.back();\n        throw Error('bad token ' + lexer.next());\n    }\n    return new NodeType(type, literal);\n};\n\nNodeType.prototype = new BaseExpr();\n\nNodeType.prototype.notOnlyElement = true;\n\nNodeType.prototype.match = function(node) {\n    return !this.type || this.type == node.nodeType;\n};\n\nNodeType.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'nodetype: ' + this.type + '\\n';\n    if (this.literal) {\n        indent += '    ';\n        t += this.literal.show(indent);\n    }\n    return t;\n};\n\n\n/**\n * NodeType\n */\nif (!window.NameTest && window.defaultConfig)\n    window.NameTest = null;\n\nNameTest = function(name) {\n    this.name = name.toLowerCase();\n};\n\nNameTest.parse = function(lexer) {\n    if (lexer.peek() != '*' &&  lexer.peek(1) == ':' && lexer.peek(2) == '*') {\n        return new NameTest(lexer.next() + lexer.next() + lexer.next());\n    }\n    return new NameTest(lexer.next());\n};\n\nNameTest.prototype = new BaseExpr();\n\nNameTest.prototype.match = function(node) {\n    var type = node.nodeType;\n\n    if (type == 1 || type == 2) {\n        if (this.name == '*' || this.name == node.nodeName.toLowerCase()) {\n            return true;\n        }\n    }\n    return false;\n};\n\nNameTest.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'nametest: ' + this.name + '\\n';\n    return t;\n};\n\n\n/**\n * class: VariableRefernce\n */\nif (!window.VariableReference && window.defaultConfig)\n    window.VariableReference = null;\n    \nVariableReference = function(name) {\n    this.name = name.substring(1);\n};\n\n\nVariableReference.parse = function(lexer) {\n    var token = lexer.next();\n    if (token.length < 2) {\n        throw Error('unnamed variable reference');\n    }\n    return new VariableReference(token)\n};\n\nVariableReference.prototype = new BaseExpr();\n\nVariableReference.prototype.datatype = 'void';\n\nVariableReference.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'variable: ' + this.name + '\\n';\n    return t;\n};\n\n\n/**\n * class: Literal\n */\nif (!window.Literal && window.defaultConfig)\n    window.Literal = null;\n\nLiteral = function(text) {\n    this.text = text.substring(1, text.length - 1);\n};\n\nLiteral.parse = function(lexer) {\n    var token = lexer.next();\n    if (token.length < 2) {\n        throw Error('unclosed literal string');\n    }\n    return new Literal(token)\n};\n\nLiteral.prototype = new BaseExpr();\n\nLiteral.prototype.datatype = 'string';\n\nLiteral.prototype.evaluate = function(ctx) {\n    return this.text;\n};\n\nLiteral.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'literal: ' + this.text + '\\n';\n    return t;\n};\n\n\n/**\n * class: Number\n */\nif (!window.Number && window.defaultConfig)\n    window.Number = null;\n\nNumber = function(digit) {\n    this.digit = +digit;\n};\n\n\nNumber.parse = function(lexer) {\n    return new Number(lexer.next());\n};\n\nNumber.prototype = new BaseExpr();\n\nNumber.prototype.datatype = 'number';\n\nNumber.prototype.evaluate = function(ctx) {\n    return this.digit;\n};\n\nNumber.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'number: ' + this.digit + '\\n';\n    return t;\n};\n\n\n/**\n * class: FunctionCall\n */\nif (!window.FunctionCall && window.defaultConfig)\n    window.FunctionCall = null;\n\nFunctionCall = function(name) {\n    var info = FunctionCall.funcs[name];\n    if (!info)\n        throw Error(name +' is not a function');\n\n    this.name = name;\n    this.func = info[0];\n    this.args = [];\n\n    this.datatype = info[1];\n\n    if (info[2]) {\n        this.needContextPosition = true;\n    }\n\n    this.needContextNodeInfo = info[3];\n    this.needContextNode = this.needContextNodeInfo[0]\n};\n\nFunctionCall.funcs = {\n\n    // Original Function\n    'context-node': [function() {\n        if (arguments.length != 0) {\n            throw Error('Function context-node expects ()');\n        }\n        var ns;\n        ns = new NodeSet();\n        ns.push(this.node);\n        return ns;\n    }, 'nodeset', false, [true]],\n\n    // Original Function\n    'root-node': [function() {\n        if (arguments.length != 0) {\n            throw Error('Function root-node expects ()');\n        }\n        var ns, ctxn;\n        ns = new NodeSet();\n        ctxn = this.node;\n        if (ctxn.nodeType == 9)\n            ns.push(ctxn);\n        else\n            ns.push(ctxn.ownerDocument);\n        return ns;\n    }, 'nodeset', false, []],\n\n    last: [function() {\n        if (arguments.length != 0) {\n            throw Error('Function last expects ()');\n        }\n        return this.last;\n    }, 'number', true, []],\n\n    position: [function() {\n        if (arguments.length != 0) {\n            throw Error('Function position expects ()');\n        }\n        return this.position;\n    }, 'number', true, []],\n\n    count: [function(ns) {\n        if (arguments.length != 1 || !(ns = ns.evaluate(this)).isNodeSet) {\n            throw Error('Function count expects (nodeset)');\n        }\n        return ns.length;\n    }, 'number', false, []],\n\n    id: [function(s) {\n        var ids, ns, i, id, elm, ctxn, doc;\n        if (arguments.length != 1) {\n            throw Error('Function id expects (object)');\n        }\n        ctxn = this.node;\n        if (ctxn.nodeType == 9)\n            doc = ctxn;\n        else\n            doc = ctxn.ownerDocument;\n/*@cc_on\n        all = doc.all;\n@*/\n        s = s.string(this);\n        ids = s.split(/\\s+/);\n        ns = new NodeSet();\n        for (i = 0, l = ids.length; i < l; i ++) {\n            id = ids[i];\n\n/*@cc_on @if (@_jscript)\n            elm = all[id];\n            if (elm) {\n                if ((!elm.length || elm.nodeType) && id == elm.id) {\n                    ns.push(elm)\n                }\n                else if (elm.length) {\n                    var elms = elm;\n                    for (var j = 0, l0 = elms.length; j < l0; j ++) {\n                        var elem = elms[j];\n                        if (id == elem.id) {\n                            ns.push(elem);\n                            break;\n                        }\n                    }\n                }\n            }\n@else @*/\n            elm = doc.getElementById(id);\n            if (uai.opera && elm && elm.id != id) {\n                var elms = doc.getElementsByName(id);\n                for (var j = 0, l0 = elms.length; j < l0; j ++) {\n                    elm = elms[j];\n                    if (elm.id == id) {\n                        ns.push(elm);\n                    }\n                }\n            }\n            else {\n                if (elm) ns.push(elm)\n            }\n/*@end @*/\n\n        }\n        ns.isSorted = false;\n        return ns;\n    }, 'nodeset', false, []],\n\n    'local-name': [function(ns) {\n        var nd;\n        switch (arguments.length) {\n            case 0:\n                nd = this.node;\n                break;\n            case 1:\n                if ((ns = ns.evaluate(this)).isNodeSet) {\n                    nd = ns.first();\n                    break;\n                }\n            default:\n                throw Error('Function local-name expects (nodeset?)');\n                break;\n        }\n        return '' + nd.nodeName.toLowerCase();\n    }, 'string', false, [true, false]],\n\n    name: [function(ns) {\n        // not implemented\n        return FunctionCall.funcs['local-name'][0].apply(this, arguments);\n    }, 'string', false, [true, false]],\n\n    'namespace-uri': [function(ns) {\n        // not implemented\n        return '';\n    }, 'string', false, [true, false]],\n\n    string: [function(s) {\n        switch (arguments.length) {\n            case 0:\n                s = NodeUtil.to('string', this.node);\n                break;\n            case 1:\n                s = s.string(this);\n                break;\n            default:\n                throw Error('Function string expects (object?)');\n                break;\n        }\n        return s;\n    }, 'string', false, [true, false]],\n\n    concat: [function(s1, s2) {\n        if (arguments.length < 2) {\n            throw Error('Function concat expects (string, string[, ...])');\n        }\n        for (var t = '', i = 0, l = arguments.length; i < l; i ++) {\n            t += arguments[i].string(this);\n        }\n        return t;\n    }, 'string', false, []],\n\n    'starts-with': [function(s1, s2) {\n        if (arguments.length != 2) {\n            throw Error('Function starts-with expects (string, string)');\n        }\n        s1 = s1.string(this);\n        s2 = s2.string(this);\n        return s1.indexOf(s2) == 0;\n    }, 'boolean', false, []],\n\n    contains: [function(s1, s2) {\n        if (arguments.length != 2) {\n            throw Error('Function contains expects (string, string)');\n        }\n        s1 = s1.string(this);\n        s2 = s2.string(this);\n        return s1.indexOf(s2) != -1;\n    }, 'boolean', false, []],\n\n    substring: [function(s, n1, n2) {\n        var a1, a2;\n        s = s.string(this);\n        n1 = n1.number(this);\n        switch (arguments.length) {\n            case 2:\n                n2 = s.length - n1 + 1;\n                break;\n            case 3:\n                n2 = n2.number(this);\n                break;\n            default:\n                throw Error('Function substring expects (string, string)');\n                break;\n        }\n        n1 = Math.round(n1);\n        n2 = Math.round(n2);\n        a1 = n1 - 1;\n        a2 = n1 + n2 - 1;\n        if (a2 == Infinity) {\n            return s.substring(a1 < 0 ? 0 : a1);\n        }\n        else {\n            return s.substring(a1 < 0 ? 0 : a1, a2)\n        }\n    }, 'string', false, []],\n\n    'substring-before': [function(s1, s2) {\n        var n;\n        if (arguments.length != 2) {\n            throw Error('Function substring-before expects (string, string)');\n        }\n        s1 = s1.string(this);\n        s2 = s2.string(this);\n        n = s1.indexOf(s2);\n        if (n == -1) return '';\n        return s1.substring(0, n);\n    }, 'string', false, []],\n\n    'substring-after': [function(s1, s2) {\n        if (arguments.length != 2) {\n            throw Error('Function substring-after expects (string, string)');\n        }\n        s1 = s1.string(this);\n        s2 = s2.string(this);\n        var n = s1.indexOf(s2);\n        if (n == -1) return '';\n        return s1.substring(n + s2.length);\n    }, 'string', false, []],\n\n    'string-length': [function(s) {\n        switch (arguments.length) {\n            case 0:\n                s = NodeUtil.to('string', this.node);\n                break;\n            case 1:\n                s = s.string(this);\n                break;\n            default:\n                throw Error('Function string-length expects (string?)');\n                break;\n        }\n        return s.length;\n    }, 'number', false, [true, false]],\n\n    'normalize-space': [function(s) {\n        switch (arguments.length) {\n            case 0:\n                s = NodeUtil.to('string', this.node);\n                break;\n            case 1:\n                s = s.string(this);\n                break;\n            default:\n                throw Error('Function normalize-space expects (string?)');\n                break;\n        }\n        return s.replace(/\\s+/g, ' ').replace(/^ /, '').replace(/ $/, '');\n    }, 'string', false, [true, false]],\n\n    translate: [function(s1, s2, s3) {\n        if (arguments.length != 3) {\n            throw Error('Function translate expects (string, string, string)');\n        }\n        s1 = s1.string(this);\n        s2 = s2.string(this);\n        s3 = s3.string(this);\n\n        var map = [];\n        for (var i = 0, l = s2.length; i < l; i ++) {\n            var ch = s2.charAt(i);\n            if (!map[ch]) map[ch] = s3.charAt(i) || '';\n        }\n        for (var t = '', i = 0, l = s1.length; i < l; i ++) {\n            var ch = s1.charAt(i);\n            var replace = map[ch]\n            t += (replace != undefined) ? replace : ch;\n        }\n        return t;\n    }, 'string', false, []],\n\n    'boolean': [function(b) {\n        if (arguments.length != 1) {\n            throw Error('Function boolean expects (object)');\n        }\n        return b.bool(this)\n    }, 'boolean', false, []],\n\n    not: [function(b) {\n        if (arguments.length != 1) {\n            throw Error('Function not expects (object)');\n        }\n        return !b.bool(this)\n    }, 'boolean', false, []],\n\n    'true': [function() {\n        if (arguments.length != 0) {\n            throw Error('Function true expects ()');\n        }\n        return true;\n    }, 'boolean', false, []],\n\n    'false': [function() {\n        if (arguments.length != 0) {\n            throw Error('Function false expects ()');\n        }\n        return false;\n    }, 'boolean', false, []],\n\n    lang: [function(s) {\n        // not implemented\n        return false;\n    }, 'boolean', false, []],\n\n    number: [function(n) {\n        switch (arguments.length) {\n            case 0:\n                n = NodeUtil.to('number', this.node);\n                break;\n            case 1:\n                n = n.number(this);\n                break;\n            default:\n                throw Error('Function number expects (object?)');\n                break;\n        }\n        return n;\n    }, 'number', false, [true, false]],\n\n    sum: [function(ns) {\n        var nodes, n, i, l;\n        if (arguments.length != 1 || !(ns = ns.evaluate(this)).isNodeSet) {\n            throw Error('Function sum expects (nodeset)');\n        }\n        nodes = ns.list();\n        n = 0;\n        for (i = 0, l = nodes.length; i < l; i ++) {\n            n += NodeUtil.to('number', nodes[i]);\n        }\n        return n;\n    }, 'number', false, []],\n\n    floor: [function(n) {\n        if (arguments.length != 1) {\n            throw Error('Function floor expects (number)');\n        }\n        n = n.number(this);\n        return Math.floor(n);\n    }, 'number', false, []],\n\n    ceiling: [function(n) {\n        if (arguments.length != 1) {\n            throw Error('Function ceiling expects (number)');\n        }\n        n = n.number(this);\n        return Math.ceil(n);\n    }, 'number', false, []],\n\n    round: [function(n) {\n        if (arguments.length != 1) {\n            throw Error('Function round expects (number)');\n        }\n        n = n.number(this);\n        return Math.round(n);\n    }, 'number', false, []]\n};\n\nFunctionCall.parse = function(lexer) {\n    var expr, func = new FunctionCall(lexer.next());\n    lexer.next();\n    while (lexer.peek() != ')') {\n        if (lexer.empty()) {\n            throw Error('missing function argument list');\n        }\n        expr = BinaryExpr.parse(lexer);\n        func.arg(expr);\n        if (lexer.peek() != ',') break;\n        lexer.next();\n    }\n    if (lexer.empty()) {\n        throw Error('unclosed function argument list');\n    }\n    if (lexer.next() != ')') {\n        lexer.back();\n        throw Error('bad token: ' + lexer.next());\n    }\n    return func\n};\n\nFunctionCall.prototype = new BaseExpr();\n\nFunctionCall.prototype.evaluate = function (ctx) {\n    return this.func.apply(ctx, this.args);\n};\n\nFunctionCall.prototype.arg = function(arg) {\n    this.args.push(arg);\n\n    if (arg.needContextPosition) {\n        this.needContextPosition = true;\n    }\n\n    var args = this.args;\n    if (arg.needContextNode) {\n        args.needContexNode = true;\n    }\n    this.needContextNode = args.needContextNode ||\n                            this.needContextNodeInfo[args.length];\n};\n\nFunctionCall.prototype.show = function(indent) {\n    indent = indent || '';\n    var t = '';\n    t += indent + 'function: ' + this.name + '\\n';\n    indent += '    ';\n\n    if (this.args.length) {\n        t += indent + 'arguments: ' + '\\n';\n        indent += '    ';\n        for (var i = 0; i < this.args.length; i ++) {\n            t += this.args[i].show(indent);\n        }\n    }\n\n    return t;\n};\n\n\n/*@cc_on @if (@_jscript)\nvar NodeWrapper = function(node, sourceIndex, subIndex, attributeName) {\n    this.node = node;\n    this.nodeType = node.nodeType;\n    this.sourceIndex = sourceIndex;\n    this.subIndex = subIndex;\n    this.attributeName = attributeName || '';\n    this.order = String.fromCharCode(sourceIndex) + String.fromCharCode(subIndex) + attributeName;\n};\n\nNodeWrapper.prototype.toString = function() {\n    return this.order;\n};\n@else @*/\nvar NodeID = {\n    uuid: 1,\n    get: function(node) {\n        return node.__jsxpath_id__ || (node.__jsxpath_id__ = this.uuid++);\n    }\n};\n/*@end @*/\n\nif (!window.NodeSet && window.defaultConfig)\n    window.NodeSet = null;\n    \nNodeSet = function() {\n    this.length = 0;\n    this.nodes = [];\n    this.seen = {};\n    this.idIndexMap = null;\n    this.reserveDels = [];\n};\n\nNodeSet.prototype.isNodeSet = true;\nNodeSet.prototype.isSorted = true;\n\n/*@_cc_on\nNodeSet.prototype.shortcut = true;\n@*/\n\nNodeSet.prototype.merge = function(nodeset) {\n    this.isSorted = false;\n    if (nodeset.only) {\n        return this.push(nodeset.only);\n    }\n\n    if (this.only){\n        var only = this.only;\n        delete this.only;\n        this.push(only);\n        this.length --;\n    }\n\n    var nodes = nodeset.nodes;\n    for (var i = 0, l = nodes.length; i < l; i ++) {\n        this._add(nodes[i]);\n    }\n};\n\nNodeSet.prototype.sort = function() {\n    if (this.only) return;\n    if (this.sortOff) return;\n\n    if (!this.isSorted) {\n        this.isSorted = true;\n        this.idIndexMap = null;\n\n/*@cc_on\n        if (this.shortcut) {\n            this.nodes.sort();\n        }\n        else {\n            this.nodes.sort(function(a, b) {\n                var result;\n                result = a.sourceIndex - b.sourceIndex;\n                if (result == 0)\n                    return a.subIndex - a.subIndex;\n                else\n                    return result;\n            });\n        }\n        return;\n@*/\n        var nodes = this.nodes;\n        nodes.sort(function(a, b) {\n            if (a == b) return 0;\n\n            if (a.compareDocumentPosition) {\n                var result = a.compareDocumentPosition(b);\n                if (result & 2) return 1;\n                if (result & 4) return -1;\n                return 0;\n            }\n            else {\n                var node1 = a, node2 = b, ancestor1 = a, ancestor2 = b, deep1 = 0, deep2 = 0;\n\n                while(ancestor1 = ancestor1.parentNode) deep1 ++;\n                while(ancestor2 = ancestor2.parentNode) deep2 ++;\n\n                // same deep\n                if (deep1 > deep2) {\n                    while (deep1-- != deep2) node1 = node1.parentNode;\n                    if (node1 == node2) return 1;\n                }\n                else if (deep2 > deep1) {\n                    while (deep2-- != deep1) node2 = node2.parentNode;\n                    if (node1 == node2) return -1;\n                }\n\n                while ((ancestor1 = node1.parentNode) != (ancestor2 = node2.parentNode)) {\n                    node1 = ancestor1;\n                    node2 = ancestor2;\n                }\n\n                // node1 is node2's sibling\n                while (node1 = node1.nextSibling) if (node1 == node2) return -1;\n\n                return 1;\n            }\n        });\n    }\n};\n\n\n/*@cc_on @if (@_jscript)\nNodeSet.prototype.sourceOffset = 1;\nNodeSet.prototype.subOffset = 2;\nNodeSet.prototype.createWrapper = function(node) {\n    var parent, child, attributes, attributesLength, sourceIndex, subIndex, attributeName;\n\n    sourceIndex = node.sourceIndex;\n\n    if (typeof sourceIndex != 'number') {\n        type = node.nodeType;\n        switch (type) {\n            case 2:\n                parent = node.parentNode;\n                sourceIndex = node.parentSourceIndex;\n                subIndex = -1;\n                attributeName = node.nodeName;\n                break;\n            case 9:\n                subIndex = -2;\n                sourceIndex = -1;\n                break;\n            default:\n                child = node;\n                subIndex = 0;\n                do {\n                    subIndex ++;\n                    sourceIndex = child.sourceIndex;\n                    if (sourceIndex) {\n                        parent = child;\n                        child = child.lastChild;\n                        if (!child) {\n                            child = parent;\n                            break;\n                        }\n                        subIndex ++;\n                    }\n                } while (child = child.previousSibling);\n                if (!sourceIndex) {\n                    sourceIndex = node.parentNode.sourceIndex;\n                }\n                break;\n        }\n    }\n    else {\n        subIndex = -2;\n    }\n\n    sourceIndex += this.sourceOffset;\n    subIndex += this.subOffset;\n\n    return new NodeWrapper(node, sourceIndex, subIndex, attributeName);\n};\n\nNodeSet.prototype.reserveDelBySourceIndexAndSubIndex = function(sourceIndex, subIndex, offset, reverse) {\n    var map = this.createIdIndexMap();\n    var index;\n    if ((map = map[sourceIndex]) && (index = map[subIndex])) {\n        if (reverse && (this.length - offset - 1) > index || !reverse && offset < index) {\n            var obj = {\n                value: index,\n                order: String.fromCharCode(index),\n                toString: function() { return this.order },\n                valueOf: function() { return this.value }\n            };\n            this.reserveDels.push(obj);\n        }\n    }\n};\n@else @*/\nNodeSet.prototype.reserveDelByNodeID = function(id, offset, reverse) {\n    var map = this.createIdIndexMap();\n    var index;\n    if (index = map[id]) {\n        if (reverse && (this.length - offset - 1) > index || !reverse && offset < index) {\n            var obj = {\n                value: index,\n                order: String.fromCharCode(index),\n                toString: function() { return this.order },\n                valueOf: function() { return this.value }\n            };\n            this.reserveDels.push(obj);\n        }\n    }\n};\n/*@end @*/\n\nNodeSet.prototype.reserveDelByNode = function(node, offset, reverse) {\n/*@cc_on @if (@_jscript)\n    node = this.createWrapper(node);\n    this.reserveDelBySourceIndexAndSubIndex(node.sourceIndex, node.subIndex, offset, reverse);\n@else @*/\n    this.reserveDelByNodeID(NodeID.get(node), offset, reverse);\n/*@end @*/\n};\n\nNodeSet.prototype.doDel = function() {\n    if (!this.reserveDels.length) return;\n\n    if (this.length < 0x10000) {\n        var dels = this.reserveDels.sort(function(a, b) { return b - a });\n    }\n    else {\n        var dels = this.reserveDels.sort(function(a, b) { return b - a });\n    }\n    for (var i = 0, l = dels.length; i < l; i ++) {\n        this.del(dels[i]);\n    }\n    this.reserveDels = [];\n    this.idIndexMap = null;\n};\n\nNodeSet.prototype.createIdIndexMap = function() {\n    if (this.idIndexMap) {\n        return this.idIndexMap;\n    }\n    else {\n        var map = this.idIndexMap = {};\n        var nodes = this.nodes;\n        for (var i = 0, l = nodes.length; i < l; i ++) {\n            var node = nodes[i];\n/*@cc_on @if (@_jscript)\n            var sourceIndex = node.sourceIndex;\n            var subIndex = node.subIndex;\n            if (!map[sourceIndex]) map[sourceIndex] = {};\n            map[sourceIndex][subIndex] = i;\n@else @*/\n            var id = NodeID.get(node);\n            map[id] = i;\n/*@end @*/\n        }\n        return map;\n    }\n};\n\nNodeSet.prototype.del = function(index) {\n    this.length --;\n    if (this.only) {\n        delete this.only;\n    }\n    else {  \n        var node = this.nodes.splice(index, 1)[0];\n\n        if (this._first == node) {\n            delete this._first;\n            delete this._firstSourceIndex;\n            delete this._firstSubIndex;\n        }\n\n/*@cc_on @if (@_jscript)\n        delete this.seen[node.sourceIndex][node.subIndex];\n@else @*/\n        delete this.seen[NodeID.get(node)];\n/*@end @*/\n    }\n};\n\n\nNodeSet.prototype.delDescendant = function(elm, offset) {\n    if (this.only) return;\n    var nodeType = elm.nodeType;\n    if (nodeType != 1 && nodeType != 9) return;\n    if (uai.applewebkit2) return;\n\n    // element || document\n    if (!elm.contains) {\n        if (nodeType == 1) {\n            var _elm = elm;\n            elm = {\n                contains: function(node) {\n                    return node.compareDocumentPosition(_elm) & 8;\n                }\n            };\n        }\n        else {\n            // document\n            elm = {\n                contains: function() {\n                    return true;\n                }\n            };\n        }\n    }\n\n    var nodes = this.nodes;\n    for (var i = offset + 1; i < nodes.length; i ++) {\n\n/*@cc_on @if (@_jscript)\n        if (nodes[i].node.nodeType == 1 && elm.contains(nodes[i].node)) {\n@else @*/\n        if (elm.contains(nodes[i])) {\n/*@end @*/\n            this.del(i);\n            i --;\n        }\n    }\n};\n\nNodeSet.prototype._add = function(node, reverse) {\n\n/*@cc_on @if (@_jscript)\n\n    var first, firstSourceIndex, firstSubIndex, sourceIndex, subIndex, attributeName;\n\n    sourceIndex = node.sourceIndex;\n    subIndex = node.subIndex;\n    attributeName = node.attributeName;\n    seen = this.seen;\n\n    seen = seen[sourceIndex] || (seen[sourceIndex] = {});\n\n    if (node.nodeType == 2) {\n        seen = seen[subIndex] || (seen[subIndex] = {});\n        if (seen[attributeName]) {\n            return true;\n        }\n        seen[attributeName] = true;\n    }\n    else {\n        if (seen[subIndex]) {\n            return true;\n        }\n        seen[subIndex] = true;\n    }\n\n    if (sourceIndex >= 0x10000 || subIndex >= 0x10000) {\n        this.shortcut = false;\n    }\n\n    // if this._first is undefined and this.nodes is not empty\n    // then first node shortcut is disabled.\n    if (this._first || this.nodes.length == 0) {\n        first = this._first;\n        firstSourceIndex = this._firstSourceIndex;\n        firstSubIndex = this._firstSubIndex;\n        if (!first || firstSourceIndex > sourceIndex || (firstSourceIndex == sourceIndex && firstSubIndex > subIndex)) {\n            this._first = node;\n            this._firstSourceIndex = sourceIndex;\n            this._firstSubIndex = subIndex\n        }\n    }\n\n@else @*/\n\n    var seen = this.seen;\n    var id = NodeID.get(node);\n    if (seen[id]) return true;\n    seen[id] = true;\n\n/*@end @*/\n\n    this.length++;\n    if (reverse) \n        this.nodes.unshift(node);\n    else\n        this.nodes.push(node);\n};\n\n\nNodeSet.prototype.unshift = function(node) {\n    if (!this.length) {\n        this.length ++;\n        this.only = node;\n        return\n    }\n    if (this.only){\n        var only = this.only;\n        delete this.only;\n        this.unshift(only);\n        this.length --;\n    }\n/*@cc_on\n    node = this.createWrapper(node);\n@*/\n    return this._add(node, true);\n};\n\n\nNodeSet.prototype.push = function(node) {\n    if (!this.length) {\n        this.length ++;\n        this.only = node;\n        return;\n    }\n    if (this.only) {\n        var only = this.only;\n        delete this.only;\n        this.push(only);\n        this.length --;\n    }\n/*@cc_on\n    node = this.createWrapper(node);\n@*/\n    return this._add(node);\n};\n\nNodeSet.prototype.first = function() {\n    if (this.only) return this.only;\n/*@cc_on\n    if (this._first) return this._first.node;\n    if (this.nodes.length > 1) this.sort();\n    var node = this.nodes[0];\n    return node ? node.node : undefined;\n@*/\n    if (this.nodes.length > 1) this.sort();\n    return this.nodes[0];\n};\n\nNodeSet.prototype.list = function() {\n    if (this.only) return [this.only];\n    this.sort();\n/*@cc_on\n    var i, l, nodes, results;\n    nodes = this.nodes;\n    results = [];\n    for (i = 0, l = nodes.length; i < l; i ++) {\n        results.push(nodes[i].node);\n    }\n    return results;\n@*/\n    return this.nodes;\n};\n\nNodeSet.prototype.string = function() {\n    var node = this.only || this.first();\n    return node ? NodeUtil.to('string', node) : '';\n};\n\nNodeSet.prototype.bool = function() {\n    return !! (this.length || this.only);\n};\n\nNodeSet.prototype.number = function() {\n    return + this.string();\n};\n\nNodeSet.prototype.iterator = function(reverse) {\n    this.sort();\n    var nodeset = this;\n\n    if (!reverse) {\n        var count = 0;\n        return function() {\n            if (nodeset.only && count++ == 0) return nodeset.only;\n/*@cc_on @if(@_jscript)\n            var wrapper = nodeset.nodes[count++];\n            if (wrapper) return wrapper.node;\n            return undefined;\n@else @*/\n            return nodeset.nodes[count++];\n/*@end @*/\n        };\n    }\n    else {\n        var count = 0;\n        return function() {\n            var index = nodeset.length - (count++) - 1;\n            if (nodeset.only && index == 0) return nodeset.only;\n/*@cc_on @if(@_jscript)\n            var wrapper = nodeset.nodes[index];\n            if (wrapper) return wrapper.node;\n            return undefined;\n@else @*/\n            return nodeset.nodes[index];\n/*@end @*/\n        };\n    }\n};\n\n\nvar install = function(win) {\n\n    win = win || this;\n    var doc = win.document;\n    var undefined = win.undefined;\n\n    win.XPathExpression = function(expr) {\n        if (!expr.length) {\n            throw win.Error('no expression');\n        }\n        var lexer = this.lexer = Lexer(expr);\n        if (lexer.empty()) {\n            throw win.Error('no expression');\n        }\n        this.expr = BinaryExpr.parse(lexer);\n        if (!lexer.empty()) {\n            throw win.Error('bad token: ' + lexer.next());\n        }\n    };\n    \n    win.XPathExpression.prototype.evaluate = function(node, type) {\n        return new win.XPathResult(this.expr.evaluate(new Ctx(node)), type);\n    };\n    \n    win.XPathResult = function (value, type) {\n        if (type == 0) {\n            switch (typeof value) {\n                case 'object':  type ++; // 4\n                case 'boolean': type ++; // 3\n                case 'string':  type ++; // 2\n                case 'number':  type ++; // 1\n            }\n        }\n    \n        this.resultType = type;\n    \n        switch (type) {\n            case 1:\n                this.numberValue = value.isNodeSet ? value.number() : +value;\n                return;\n            case 2:\n                this.stringValue = value.isNodeSet ? value.string() : '' + value;\n                return;\n            case 3:\n                this.booleanValue = value.isNodeSet ? value.bool() : !! value;\n                return;\n            case 4: case 5: case 6: case 7:\n                this.nodes = value.list();\n                this.snapshotLength = value.length;\n                this.index = 0;\n                this.invalidIteratorState = false;\n                break;\n            case 8: case 9:\n                this.singleNodeValue = value.first();\n                return;\n        }\n    };\n    \n    win.XPathResult.prototype.iterateNext = function() { return this.nodes[this.index++] };\n    win.XPathResult.prototype.snapshotItem = function(i) { return this.nodes[i] };\n    \n    win.XPathResult.ANY_TYPE = 0;\n    win.XPathResult.NUMBER_TYPE = 1;\n    win.XPathResult.STRING_TYPE = 2;\n    win.XPathResult.BOOLEAN_TYPE = 3;\n    win.XPathResult.UNORDERED_NODE_ITERATOR_TYPE = 4;\n    win.XPathResult.ORDERED_NODE_ITERATOR_TYPE = 5;\n    win.XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE = 6;\n    win.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE = 7;\n    win.XPathResult.ANY_UNORDERED_NODE_TYPE = 8;\n    win.XPathResult.FIRST_ORDERED_NODE_TYPE = 9;\n    \n    \n    doc.createExpression = function(expr) {\n        return new win.XPathExpression(expr, null);\n    };\n    \n    doc.evaluate = function(expr, context, _, type) {\n        return doc.createExpression(expr, null).evaluate(context, type);\n    };\n};\n\nvar win;\n\nif (config.targetFrame) {\n    var frame = document.getElementById(config.targetFrame);\n    if (frame) win = frame.contentWindow;\n}\n\nif (config.exportInstaller) {\n    window.install = install;\n}\n\nif (!config.hasNative || !config.useNative) {\n    install(win || window);\n}\n\n\n})();\n\n// Thanks for reading this source code. We love JavaScript.\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/xpath/util.js",
    "content": "// Copyright 2005 Google\n//\n// Author: Steffen Meschkat <mesch@google.com>\n//\n// Miscellaneous utility and placeholder functions.\n\n// Dummy implmentation for the logging functions. Replace by something\n// useful when you want to debug.\nfunction xpathLog(msg) {};\nfunction xsltLog(msg) {};\nfunction xsltLogXml(msg) {};\n\nvar ajaxsltIsIE6 = navigator.appVersion.match(/MSIE 6.0/);\n\n// Throws an exception if false.\nfunction assert(b) {\n  if (!b) {\n    throw \"Assertion failed\";\n  }\n}\n\n// Splits a string s at all occurrences of character c. This is like\n// the split() method of the string object, but IE omits empty\n// strings, which violates the invariant (s.split(x).join(x) == s).\nfunction stringSplit(s, c) {\n  var a = s.indexOf(c);\n  if (a == -1) {\n    return [ s ];\n  }\n  var parts = [];\n  parts.push(s.substr(0,a));\n  while (a != -1) {\n    var a1 = s.indexOf(c, a + 1);\n    if (a1 != -1) {\n      parts.push(s.substr(a + 1, a1 - a - 1));\n    } else {\n      parts.push(s.substr(a + 1));\n    }\n    a = a1;\n  }\n  return parts;\n}\n\n// The following function does what document.importNode(node, true)\n// would do for us here; however that method is broken in Safari/1.3,\n// so we have to emulate it.\nfunction xmlImportNode(doc, node) {\n  if (node.nodeType == DOM_TEXT_NODE) {\n    return domCreateTextNode(doc, node.nodeValue);\n\n  } else if (node.nodeType == DOM_CDATA_SECTION_NODE) {\n    return domCreateCDATASection(doc, node.nodeValue);\n\n  } else if (node.nodeType == DOM_ELEMENT_NODE) {\n    var newNode = domCreateElement(doc, node.nodeName);\n    for (var i = 0; i < node.attributes.length; ++i) {\n      var an = node.attributes[i];\n      var name = an.nodeName;\n      var value = an.nodeValue;\n      domSetAttribute(newNode, name, value);\n    }\n\n    for (var c = node.firstChild; c; c = c.nextSibling) {\n      var cn = arguments.callee(doc, c);\n      domAppendChild(newNode, cn);\n    }\n\n    return newNode;\n\n  } else {\n    return domCreateComment(doc, node.nodeName);\n  }\n}\n\n// A set data structure. It can also be used as a map (i.e. the keys\n// can have values other than 1), but we don't call it map because it\n// would be ambiguous in this context. Also, the map is iterable, so\n// we can use it to replace for-in loops over core javascript Objects.\n// For-in iteration breaks when Object.prototype is modified, which\n// some clients of the maps API do.\n//\n// NOTE(mesch): The set keys by the string value of its element, NOT\n// by the typed value. In particular, objects can't be used as keys.\n//\n// @constructor\nfunction Set() {\n  this.keys = [];\n}\n\nSet.prototype.size = function() {\n  return this.keys.length;\n}\n\n// Adds the entry to the set, ignoring if it is present.\nSet.prototype.add = function(key, opt_value) {\n  var value = opt_value || 1;\n  if (!this.contains(key)) {\n    this[':' + key] = value;\n    this.keys.push(key);\n  }\n}\n\n// Sets the entry in the set, adding if it is not yet present.\nSet.prototype.set = function(key, opt_value) {\n  var value = opt_value || 1;\n  if (!this.contains(key)) {\n    this[':' + key] = value;\n    this.keys.push(key);\n  } else {\n    this[':' + key] = value;\n  }\n}\n\n// Increments the key's value by 1. This works around the fact that\n// numbers are always passed by value, never by reference, so that we\n// can't increment the value returned by get(), or the iterator\n// argument. Sets the key's value to 1 if it doesn't exist yet.\nSet.prototype.inc = function(key) {\n  if (!this.contains(key)) {\n    this[':' + key] = 1;\n    this.keys.push(key);\n  } else {\n    this[':' + key]++;\n  }\n}\n\nSet.prototype.get = function(key) {\n  if (this.contains(key)) {\n    return this[':' + key];\n  } else {\n    var undefined;\n    return undefined;\n  }\n}\n\n// Removes the entry from the set.\nSet.prototype.remove = function(key) {\n  if (this.contains(key)) {\n    delete this[':' + key];\n    removeFromArray(this.keys, key, true);\n  }\n}\n\n// Tests if an entry is in the set.\nSet.prototype.contains = function(entry) {\n  return typeof this[':' + entry] != 'undefined';\n}\n\n// Gets a list of values in the set.\nSet.prototype.items = function() {\n  var list = [];\n  for (var i = 0; i < this.keys.length; ++i) {\n    var k = this.keys[i];\n    var v = this[':' + k];\n    list.push(v);\n  }\n  return list;\n}\n\n\n// Invokes function f for every key value pair in the set as a method\n// of the set.\nSet.prototype.map = function(f) {\n  for (var i = 0; i < this.keys.length; ++i) {\n    var k = this.keys[i];\n    f.call(this, k, this[':' + k]);\n  }\n}\n\nSet.prototype.clear = function() {\n  for (var i = 0; i < this.keys.length; ++i) {\n    delete this[':' + this.keys[i]];\n  }\n  this.keys.length = 0;\n}\n\n\n// Applies the given function to each element of the array, preserving\n// this, and passing the index.\nfunction mapExec(array, func) {\n  for (var i = 0; i < array.length; ++i) {\n    func.call(this, array[i], i);\n  }\n}\n\n// Returns an array that contains the return value of the given\n// function applied to every element of the input array.\nfunction mapExpr(array, func) {\n  var ret = [];\n  for (var i = 0; i < array.length; ++i) {\n    ret.push(func(array[i]));\n  }\n  return ret;\n};\n\n// Reverses the given array in place.\nfunction reverseInplace(array) {\n  for (var i = 0; i < array.length / 2; ++i) {\n    var h = array[i];\n    var ii = array.length - i - 1;\n    array[i] = array[ii];\n    array[ii] = h;\n  }\n}\n\n// Removes value from array. Returns the number of instances of value\n// that were removed from array.\nfunction removeFromArray(array, value, opt_notype) {\n  var shift = 0;\n  for (var i = 0; i < array.length; ++i) {\n    if (array[i] === value || (opt_notype && array[i] == value)) {\n      array.splice(i--, 1);\n      shift++;\n    }\n  }\n  return shift;\n}\n\n// Shallow-copies an array to the end of another array\n// Basically Array.concat, but works with other non-array collections\nfunction copyArray(dst, src) {\n  if (!src) return;\n  var dstLength = dst.length;\n  for (var i = src.length - 1; i >= 0; --i) {\n    dst[i+dstLength] = src[i];\n  }\n}\n\n/**\n * This is an optimization for copying attribute lists in IE. IE includes many\n * extraneous properties in its DOM attribute lists, which take require\n * significant extra processing when evaluating attribute steps. With this\n * function, we ignore any such attributes that has an empty string value.\n */\nfunction copyArrayIgnoringAttributesWithoutValue(dst, src)\n{\n  if (!src) return;\n  for (var i = src.length - 1; i >= 0; --i) {\n    // this test will pass so long as the attribute has a non-empty string\n    // value, even if that value is \"false\", \"0\", \"undefined\", etc.\n    if (src[i].nodeValue) {\n      dst.push(src[i]);\n    }\n  }\n}\n\n// Returns the text value of a node; for nodes without children this\n// is the nodeValue, for nodes with children this is the concatenation\n// of the value of all children. Browser-specific optimizations are used by\n// default; they can be disabled by passing \"true\" in as the second parameter.\nfunction xmlValue(node, disallowBrowserSpecificOptimization) {\n  if (!node) {\n    return '';\n  }\n\n  var ret = '';\n  if (node.nodeType == DOM_TEXT_NODE ||\n      node.nodeType == DOM_CDATA_SECTION_NODE) {\n    ret += node.nodeValue;\n\n  } else if (node.nodeType == DOM_ATTRIBUTE_NODE) {\n    if (ajaxsltIsIE6) {\n      ret += xmlValueIE6Hack(node);\n    } else {\n      ret += node.nodeValue;\n    }\n  } else if (node.nodeType == DOM_ELEMENT_NODE ||\n             node.nodeType == DOM_DOCUMENT_NODE ||\n             node.nodeType == DOM_DOCUMENT_FRAGMENT_NODE) {\n    if (!disallowBrowserSpecificOptimization) {\n      // IE, Safari, Opera, and friends\n      var innerText = node.innerText;\n      if (innerText != undefined) {\n        return innerText;\n      }\n      // Firefox\n      var textContent = node.textContent;\n      if (textContent != undefined) {\n        return textContent;\n      }\n    }\n    // pobrecito!\n    var len = node.childNodes.length;\n    for (var i = 0; i < len; ++i) {\n      ret += arguments.callee(node.childNodes[i]);\n    }\n  }\n  return ret;\n}\n\nfunction xmlValueIE6Hack(node) {\n    // Issue 19, IE6 mangles href attribute when it's a javascript: url\n    var nodeName = node.nodeName;\n    var nodeValue = node.nodeValue;\n    if (nodeName.length != 4) return nodeValue;\n    if (!/^href$/i.test(nodeName)) return nodeValue;\n    if (!/^javascript:/.test(nodeValue)) return nodeValue;\n    return unescape(nodeValue);\n}\n\n// Returns the representation of a node as XML text.\nfunction xmlText(node, opt_cdata) {\n  var buf = [];\n  xmlTextR(node, buf, opt_cdata);\n  return buf.join('');\n}\n\nfunction xmlTextR(node, buf, cdata) {\n  if (node.nodeType == DOM_TEXT_NODE) {\n    buf.push(xmlEscapeText(node.nodeValue));\n\n  } else if (node.nodeType == DOM_CDATA_SECTION_NODE) {\n    if (cdata) {\n      buf.push(node.nodeValue);\n    } else {\n      buf.push('<![CDATA[' + node.nodeValue + ']]>');\n    }\n\n  } else if (node.nodeType == DOM_COMMENT_NODE) {\n    buf.push('<!--' + node.nodeValue + '-->');\n\n  } else if (node.nodeType == DOM_ELEMENT_NODE) {\n    buf.push('<' + xmlFullNodeName(node));\n    for (var i = 0; i < node.attributes.length; ++i) {\n      var a = node.attributes[i];\n      if (a && a.nodeName && a.nodeValue) {\n        buf.push(' ' + xmlFullNodeName(a) + '=\"' +\n                 xmlEscapeAttr(a.nodeValue) + '\"');\n      }\n    }\n\n    if (node.childNodes.length == 0) {\n      buf.push('/>');\n    } else {\n      buf.push('>');\n      for (var i = 0; i < node.childNodes.length; ++i) {\n        arguments.callee(node.childNodes[i], buf, cdata);\n      }\n      buf.push('</' + xmlFullNodeName(node) + '>');\n    }\n\n  } else if (node.nodeType == DOM_DOCUMENT_NODE ||\n             node.nodeType == DOM_DOCUMENT_FRAGMENT_NODE) {\n    for (var i = 0; i < node.childNodes.length; ++i) {\n      arguments.callee(node.childNodes[i], buf, cdata);\n    }\n  }\n}\n\nfunction xmlFullNodeName(n) {\n  if (n.prefix && n.nodeName.indexOf(n.prefix + ':') != 0) {\n    return n.prefix + ':' + n.nodeName;\n  } else {\n    return n.nodeName;\n  }\n}\n\n// Escape XML special markup chracters: tag delimiter < > and entity\n// reference start delimiter &. The escaped string can be used in XML\n// text portions (i.e. between tags).\nfunction xmlEscapeText(s) {\n  return ('' + s).replace(/&/g, '&amp;').replace(/</g, '&lt;').\n    replace(/>/g, '&gt;');\n}\n\n// Escape XML special markup characters: tag delimiter < > entity\n// reference start delimiter & and quotes \". The escaped string can be\n// used in double quoted XML attribute value portions (i.e. in\n// attributes within start tags).\nfunction xmlEscapeAttr(s) {\n  return xmlEscapeText(s).replace(/\\\"/g, '&quot;');\n}\n\n// Escape markup in XML text, but don't touch entity references. The\n// escaped string can be used as XML text (i.e. between tags).\nfunction xmlEscapeTags(s) {\n  return s.replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\n/**\n * Wrapper function to access the owner document uniformly for document\n * and other nodes: for the document node, the owner document is the\n * node itself, for all others it's the ownerDocument property.\n *\n * @param {Node} node\n * @return {Document}\n */\nfunction xmlOwnerDocument(node) {\n  if (node.nodeType == DOM_DOCUMENT_NODE) {\n    return node;\n  } else {\n    return node.ownerDocument;\n  }\n}\n\n// Wrapper around DOM methods so we can condense their invocations.\nfunction domGetAttribute(node, name) {\n  return node.getAttribute(name);\n}\n\nfunction domSetAttribute(node, name, value) {\n  return node.setAttribute(name, value);\n}\n\nfunction domRemoveAttribute(node, name) {\n  return node.removeAttribute(name);\n}\n\nfunction domAppendChild(node, child) {\n  return node.appendChild(child);\n}\n\nfunction domRemoveChild(node, child) {\n  return node.removeChild(child);\n}\n\nfunction domReplaceChild(node, newChild, oldChild) {\n  return node.replaceChild(newChild, oldChild);\n}\n\nfunction domInsertBefore(node, newChild, oldChild) {\n  return node.insertBefore(newChild, oldChild);\n}\n\nfunction domRemoveNode(node) {\n  return domRemoveChild(node.parentNode, node);\n}\n\nfunction domCreateTextNode(doc, text) {\n  return doc.createTextNode(text);\n}\n\nfunction domCreateElement(doc, name) {\n  return doc.createElement(name);\n}\n\nfunction domCreateAttribute(doc, name) {\n  return doc.createAttribute(name);\n}\n\nfunction domCreateCDATASection(doc, data) {\n  return doc.createCDATASection(data);\n}\n\nfunction domCreateComment(doc, text) {\n  return doc.createComment(text);\n}\n\nfunction domCreateDocumentFragment(doc) {\n  return doc.createDocumentFragment();\n}\n\nfunction domGetElementById(doc, id) {\n  return doc.getElementById(id);\n}\n\n// Same for window methods.\nfunction windowSetInterval(win, fun, time) {\n  return win.setInterval(fun, time);\n}\n\nfunction windowClearInterval(win, id) {\n  return win.clearInterval(id);\n}\n\n/**\n * Escape the special regular expression characters when the regular expression\n * is specified as a string.\n *\n * Based on: http://simonwillison.net/2006/Jan/20/escape/\n */\nRegExp.escape = (function() {\n  var specials = [\n    '/', '.', '*', '+', '?', '|', '^', '$',\n    '(', ')', '[', ']', '{', '}', '\\\\'\n  ];\n    \n  var sRE = new RegExp(\n    '(\\\\' + specials.join('|\\\\') + ')', 'g'\n  );\n    \n  return function(text) {\n    return text.replace(sRE, '\\\\$1');\n  }\n})();\n\n/**\n * Determines whether a predicate expression contains a \"positional selector\".\n * A positional selector filters nodes from the nodelist input based on their\n * position within that list. When such selectors are encountered, the\n * evaluation of the predicate cannot be depth-first, because the positional\n * selector may be based on the result of evaluating predicates that precede\n * it.\n */\nfunction predicateExprHasPositionalSelector(expr, isRecursiveCall) {\n  if (!expr) {\n    return false;\n  }\n  if (!isRecursiveCall && exprReturnsNumberValue(expr)) {\n    // this is a \"proximity position\"-based predicate\n    return true;\n  }\n  if (expr instanceof FunctionCallExpr) {\n    var value = expr.name.value;\n    return (value == 'last' || value == 'position');\n  }\n  if (expr instanceof BinaryExpr) {\n    return (\n      predicateExprHasPositionalSelector(expr.expr1, true) ||\n      predicateExprHasPositionalSelector(expr.expr2, true));\n  }\n  return false;\n}\n\nfunction exprReturnsNumberValue(expr) {\n  if (expr instanceof FunctionCallExpr) {\n    var isMember = {\n      last: true\n      , position: true\n      , count: true\n      , 'string-length': true\n      , number: true\n      , sum: true\n      , floor: true\n      , ceiling: true\n      , round: true\n    };\n    return isMember[expr.name.value];\n  }\n  else if (expr instanceof UnaryMinusExpr) {\n    return true;\n  }\n  else if (expr instanceof BinaryExpr) {\n    var isMember = {\n      '+': true\n      , '-': true\n      , '*': true\n      , mod: true\n      , div: true\n    };\n    return isMember[expr.op.value];\n  }\n  else if (expr instanceof NumberExpr) {\n    return true;\n  }\n  return false;\n}\n\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/xpath/xmltoken.js",
    "content": "// Copyright 2006 Google Inc.\n// All Rights Reserved\n//\n// Defines regular expression patterns to extract XML tokens from string.\n// See <http://www.w3.org/TR/REC-xml/#sec-common-syn>,\n// <http://www.w3.org/TR/xml11/#sec-common-syn> and\n// <http://www.w3.org/TR/REC-xml-names/#NT-NCName> for the specifications.\n//\n// Author: Junji Takagi <jtakagi@google.com>\n\n// Detect whether RegExp supports Unicode characters or not.\n\nvar REGEXP_UNICODE = function() {\n  var tests = [' ', '\\u0120', -1,  // Konquerer 3.4.0 fails here.\n               '!', '\\u0120', -1,\n               '\\u0120', '\\u0120', 0,\n               '\\u0121', '\\u0120', -1,\n               '\\u0121', '\\u0120|\\u0121', 0,\n               '\\u0122', '\\u0120|\\u0121', -1,\n               '\\u0120', '[\\u0120]', 0,  // Safari 2.0.3 fails here.\n               '\\u0121', '[\\u0120]', -1,\n               '\\u0121', '[\\u0120\\u0121]', 0,  // Safari 2.0.3 fails here.\n               '\\u0122', '[\\u0120\\u0121]', -1,\n               '\\u0121', '[\\u0120-\\u0121]', 0,  // Safari 2.0.3 fails here.\n               '\\u0122', '[\\u0120-\\u0121]', -1];\n  for (var i = 0; i < tests.length; i += 3) {\n    if (tests[i].search(new RegExp(tests[i + 1])) != tests[i + 2]) {\n      return false;\n    }\n  }\n  return true;\n}();\n\n// Common tokens in XML 1.0 and XML 1.1.\n\nvar XML_S = '[ \\t\\r\\n]+';\nvar XML_EQ = '(' + XML_S + ')?=(' + XML_S + ')?';\nvar XML_CHAR_REF = '&#[0-9]+;|&#x[0-9a-fA-F]+;';\n\n// XML 1.0 tokens.\n\nvar XML10_VERSION_INFO = XML_S + 'version' + XML_EQ + '(\"1\\\\.0\"|' + \"'1\\\\.0')\";\nvar XML10_BASE_CHAR = (REGEXP_UNICODE) ?\n  '\\u0041-\\u005a\\u0061-\\u007a\\u00c0-\\u00d6\\u00d8-\\u00f6\\u00f8-\\u00ff' +\n  '\\u0100-\\u0131\\u0134-\\u013e\\u0141-\\u0148\\u014a-\\u017e\\u0180-\\u01c3' +\n  '\\u01cd-\\u01f0\\u01f4-\\u01f5\\u01fa-\\u0217\\u0250-\\u02a8\\u02bb-\\u02c1\\u0386' +\n  '\\u0388-\\u038a\\u038c\\u038e-\\u03a1\\u03a3-\\u03ce\\u03d0-\\u03d6\\u03da\\u03dc' +\n  '\\u03de\\u03e0\\u03e2-\\u03f3\\u0401-\\u040c\\u040e-\\u044f\\u0451-\\u045c' +\n  '\\u045e-\\u0481\\u0490-\\u04c4\\u04c7-\\u04c8\\u04cb-\\u04cc\\u04d0-\\u04eb' +\n  '\\u04ee-\\u04f5\\u04f8-\\u04f9\\u0531-\\u0556\\u0559\\u0561-\\u0586\\u05d0-\\u05ea' +\n  '\\u05f0-\\u05f2\\u0621-\\u063a\\u0641-\\u064a\\u0671-\\u06b7\\u06ba-\\u06be' +\n  '\\u06c0-\\u06ce\\u06d0-\\u06d3\\u06d5\\u06e5-\\u06e6\\u0905-\\u0939\\u093d' +\n  '\\u0958-\\u0961\\u0985-\\u098c\\u098f-\\u0990\\u0993-\\u09a8\\u09aa-\\u09b0\\u09b2' +\n  '\\u09b6-\\u09b9\\u09dc-\\u09dd\\u09df-\\u09e1\\u09f0-\\u09f1\\u0a05-\\u0a0a' +\n  '\\u0a0f-\\u0a10\\u0a13-\\u0a28\\u0a2a-\\u0a30\\u0a32-\\u0a33\\u0a35-\\u0a36' +\n  '\\u0a38-\\u0a39\\u0a59-\\u0a5c\\u0a5e\\u0a72-\\u0a74\\u0a85-\\u0a8b\\u0a8d' +\n  '\\u0a8f-\\u0a91\\u0a93-\\u0aa8\\u0aaa-\\u0ab0\\u0ab2-\\u0ab3\\u0ab5-\\u0ab9' +\n  '\\u0abd\\u0ae0\\u0b05-\\u0b0c\\u0b0f-\\u0b10\\u0b13-\\u0b28\\u0b2a-\\u0b30' +\n  '\\u0b32-\\u0b33\\u0b36-\\u0b39\\u0b3d\\u0b5c-\\u0b5d\\u0b5f-\\u0b61\\u0b85-\\u0b8a' +\n  '\\u0b8e-\\u0b90\\u0b92-\\u0b95\\u0b99-\\u0b9a\\u0b9c\\u0b9e-\\u0b9f\\u0ba3-\\u0ba4' +\n  '\\u0ba8-\\u0baa\\u0bae-\\u0bb5\\u0bb7-\\u0bb9\\u0c05-\\u0c0c\\u0c0e-\\u0c10' +\n  '\\u0c12-\\u0c28\\u0c2a-\\u0c33\\u0c35-\\u0c39\\u0c60-\\u0c61\\u0c85-\\u0c8c' +\n  '\\u0c8e-\\u0c90\\u0c92-\\u0ca8\\u0caa-\\u0cb3\\u0cb5-\\u0cb9\\u0cde\\u0ce0-\\u0ce1' +\n  '\\u0d05-\\u0d0c\\u0d0e-\\u0d10\\u0d12-\\u0d28\\u0d2a-\\u0d39\\u0d60-\\u0d61' +\n  '\\u0e01-\\u0e2e\\u0e30\\u0e32-\\u0e33\\u0e40-\\u0e45\\u0e81-\\u0e82\\u0e84' +\n  '\\u0e87-\\u0e88\\u0e8a\\u0e8d\\u0e94-\\u0e97\\u0e99-\\u0e9f\\u0ea1-\\u0ea3\\u0ea5' +\n  '\\u0ea7\\u0eaa-\\u0eab\\u0ead-\\u0eae\\u0eb0\\u0eb2-\\u0eb3\\u0ebd\\u0ec0-\\u0ec4' +\n  '\\u0f40-\\u0f47\\u0f49-\\u0f69\\u10a0-\\u10c5\\u10d0-\\u10f6\\u1100\\u1102-\\u1103' +\n  '\\u1105-\\u1107\\u1109\\u110b-\\u110c\\u110e-\\u1112\\u113c\\u113e\\u1140\\u114c' +\n  '\\u114e\\u1150\\u1154-\\u1155\\u1159\\u115f-\\u1161\\u1163\\u1165\\u1167\\u1169' +\n  '\\u116d-\\u116e\\u1172-\\u1173\\u1175\\u119e\\u11a8\\u11ab\\u11ae-\\u11af' +\n  '\\u11b7-\\u11b8\\u11ba\\u11bc-\\u11c2\\u11eb\\u11f0\\u11f9\\u1e00-\\u1e9b' +\n  '\\u1ea0-\\u1ef9\\u1f00-\\u1f15\\u1f18-\\u1f1d\\u1f20-\\u1f45\\u1f48-\\u1f4d' +\n  '\\u1f50-\\u1f57\\u1f59\\u1f5b\\u1f5d\\u1f5f-\\u1f7d\\u1f80-\\u1fb4\\u1fb6-\\u1fbc' +\n  '\\u1fbe\\u1fc2-\\u1fc4\\u1fc6-\\u1fcc\\u1fd0-\\u1fd3\\u1fd6-\\u1fdb\\u1fe0-\\u1fec' +\n  '\\u1ff2-\\u1ff4\\u1ff6-\\u1ffc\\u2126\\u212a-\\u212b\\u212e\\u2180-\\u2182' +\n  '\\u3041-\\u3094\\u30a1-\\u30fa\\u3105-\\u312c\\uac00-\\ud7a3' :\n  'A-Za-z';\nvar XML10_IDEOGRAPHIC = (REGEXP_UNICODE) ?\n  '\\u4e00-\\u9fa5\\u3007\\u3021-\\u3029' :\n  '';\nvar XML10_COMBINING_CHAR = (REGEXP_UNICODE) ?\n  '\\u0300-\\u0345\\u0360-\\u0361\\u0483-\\u0486\\u0591-\\u05a1\\u05a3-\\u05b9' +\n  '\\u05bb-\\u05bd\\u05bf\\u05c1-\\u05c2\\u05c4\\u064b-\\u0652\\u0670\\u06d6-\\u06dc' +\n  '\\u06dd-\\u06df\\u06e0-\\u06e4\\u06e7-\\u06e8\\u06ea-\\u06ed\\u0901-\\u0903\\u093c' +\n  '\\u093e-\\u094c\\u094d\\u0951-\\u0954\\u0962-\\u0963\\u0981-\\u0983\\u09bc\\u09be' +\n  '\\u09bf\\u09c0-\\u09c4\\u09c7-\\u09c8\\u09cb-\\u09cd\\u09d7\\u09e2-\\u09e3\\u0a02' +\n  '\\u0a3c\\u0a3e\\u0a3f\\u0a40-\\u0a42\\u0a47-\\u0a48\\u0a4b-\\u0a4d\\u0a70-\\u0a71' +\n  '\\u0a81-\\u0a83\\u0abc\\u0abe-\\u0ac5\\u0ac7-\\u0ac9\\u0acb-\\u0acd\\u0b01-\\u0b03' +\n  '\\u0b3c\\u0b3e-\\u0b43\\u0b47-\\u0b48\\u0b4b-\\u0b4d\\u0b56-\\u0b57\\u0b82-\\u0b83' +\n  '\\u0bbe-\\u0bc2\\u0bc6-\\u0bc8\\u0bca-\\u0bcd\\u0bd7\\u0c01-\\u0c03\\u0c3e-\\u0c44' +\n  '\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55-\\u0c56\\u0c82-\\u0c83\\u0cbe-\\u0cc4' +\n  '\\u0cc6-\\u0cc8\\u0cca-\\u0ccd\\u0cd5-\\u0cd6\\u0d02-\\u0d03\\u0d3e-\\u0d43' +\n  '\\u0d46-\\u0d48\\u0d4a-\\u0d4d\\u0d57\\u0e31\\u0e34-\\u0e3a\\u0e47-\\u0e4e\\u0eb1' +\n  '\\u0eb4-\\u0eb9\\u0ebb-\\u0ebc\\u0ec8-\\u0ecd\\u0f18-\\u0f19\\u0f35\\u0f37\\u0f39' +\n  '\\u0f3e\\u0f3f\\u0f71-\\u0f84\\u0f86-\\u0f8b\\u0f90-\\u0f95\\u0f97\\u0f99-\\u0fad' +\n  '\\u0fb1-\\u0fb7\\u0fb9\\u20d0-\\u20dc\\u20e1\\u302a-\\u302f\\u3099\\u309a' :\n  '';\nvar XML10_DIGIT = (REGEXP_UNICODE) ?\n  '\\u0030-\\u0039\\u0660-\\u0669\\u06f0-\\u06f9\\u0966-\\u096f\\u09e6-\\u09ef' +\n  '\\u0a66-\\u0a6f\\u0ae6-\\u0aef\\u0b66-\\u0b6f\\u0be7-\\u0bef\\u0c66-\\u0c6f' +\n  '\\u0ce6-\\u0cef\\u0d66-\\u0d6f\\u0e50-\\u0e59\\u0ed0-\\u0ed9\\u0f20-\\u0f29' :\n  '0-9';\nvar XML10_EXTENDER = (REGEXP_UNICODE) ?\n  '\\u00b7\\u02d0\\u02d1\\u0387\\u0640\\u0e46\\u0ec6\\u3005\\u3031-\\u3035' +\n  '\\u309d-\\u309e\\u30fc-\\u30fe' :\n  '';\nvar XML10_LETTER = XML10_BASE_CHAR + XML10_IDEOGRAPHIC;\nvar XML10_NAME_CHAR = XML10_LETTER + XML10_DIGIT + '\\\\._:' +\n                      XML10_COMBINING_CHAR + XML10_EXTENDER + '-';\nvar XML10_NAME = '[' + XML10_LETTER + '_:][' + XML10_NAME_CHAR + ']*';\n\nvar XML10_ENTITY_REF = '&' + XML10_NAME + ';';\nvar XML10_REFERENCE = XML10_ENTITY_REF + '|' + XML_CHAR_REF;\nvar XML10_ATT_VALUE = '\"(([^<&\"]|' + XML10_REFERENCE + ')*)\"|' +\n                      \"'(([^<&']|\" + XML10_REFERENCE + \")*)'\";\nvar XML10_ATTRIBUTE =\n  '(' + XML10_NAME + ')' + XML_EQ + '(' + XML10_ATT_VALUE + ')';\n\n// XML 1.1 tokens.\n// TODO(jtakagi): NameStartChar also includes \\u10000-\\ueffff.\n// ECMAScript Language Specifiction defines UnicodeEscapeSequence as\n// \"\\u HexDigit HexDigit HexDigit HexDigit\" and we may need to use\n// surrogate pairs, but any browser doesn't support surrogate paris in\n// character classes of regular expression, so avoid including them for now.\n\nvar XML11_VERSION_INFO = XML_S + 'version' + XML_EQ + '(\"1\\\\.1\"|' + \"'1\\\\.1')\";\nvar XML11_NAME_START_CHAR = (REGEXP_UNICODE) ?\n  ':A-Z_a-z\\u00c0-\\u00d6\\u00d8-\\u00f6\\u00f8-\\u02ff\\u0370-\\u037d' +\n  '\\u037f-\\u1fff\\u200c-\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\ud7ff' +\n  '\\uf900-\\ufdcf\\ufdf0-\\ufffd' :\n  ':A-Z_a-z';\nvar XML11_NAME_CHAR = XML11_NAME_START_CHAR +\n  ((REGEXP_UNICODE) ? '\\\\.0-9\\u00b7\\u0300-\\u036f\\u203f-\\u2040-' : '\\\\.0-9-');\nvar XML11_NAME = '[' + XML11_NAME_START_CHAR + '][' + XML11_NAME_CHAR + ']*';\n\nvar XML11_ENTITY_REF = '&' + XML11_NAME + ';';\nvar XML11_REFERENCE = XML11_ENTITY_REF + '|' + XML_CHAR_REF;\nvar XML11_ATT_VALUE = '\"(([^<&\"]|' + XML11_REFERENCE + ')*)\"|' +\n                      \"'(([^<&']|\" + XML11_REFERENCE + \")*)'\";\nvar XML11_ATTRIBUTE =\n  '(' + XML11_NAME + ')' + XML_EQ + '(' + XML11_ATT_VALUE + ')';\n\n// XML Namespace tokens.\n// Used in XML parser and XPath parser.\n\nvar XML_NC_NAME_CHAR = XML10_LETTER + XML10_DIGIT + '\\\\._' +\n                       XML10_COMBINING_CHAR + XML10_EXTENDER + '-';\nvar XML_NC_NAME = '[' + XML10_LETTER + '_][' + XML_NC_NAME_CHAR + ']*';\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium-core/xpath/xpath.js",
    "content": "// Copyright 2005 Google Inc.\n// All Rights Reserved\n//\n// An XPath parser and evaluator written in JavaScript. The\n// implementation is complete except for functions handling\n// namespaces.\n//\n// Reference: [XPATH] XPath Specification\n// <http://www.w3.org/TR/1999/REC-xpath-19991116>.\n//\n//\n// The API of the parser has several parts:\n//\n// 1. The parser function xpathParse() that takes a string and returns\n// an expession object.\n//\n// 2. The expression object that has an evaluate() method to evaluate the\n// XPath expression it represents. (It is actually a hierarchy of\n// objects that resembles the parse tree, but an application will call\n// evaluate() only on the top node of this hierarchy.)\n//\n// 3. The context object that is passed as an argument to the evaluate()\n// method, which represents the DOM context in which the expression is\n// evaluated.\n//\n// 4. The value object that is returned from evaluate() and represents\n// values of the different types that are defined by XPath (number,\n// string, boolean, and node-set), and allows to convert between them.\n//\n// These parts are near the top of the file, the functions and data\n// that are used internally follow after them.\n//\n//\n// Author: Steffen Meschkat <mesch@google.com>\n\n\n// The entry point for the parser.\n//\n// @param expr a string that contains an XPath expression.\n// @return an expression object that can be evaluated with an\n// expression context.\n\nfunction xpathParse(expr) {\n  xpathLog('parse ' + expr);\n  xpathParseInit();\n\n  var cached = xpathCacheLookup(expr);\n  if (cached) {\n    xpathLog(' ... cached');\n    return cached;\n  }\n\n  // Optimize for a few common cases: simple attribute node tests\n  // (@id), simple element node tests (page), variable references\n  // ($address), numbers (4), multi-step path expressions where each\n  // step is a plain element node test\n  // (page/overlay/locations/location).\n\n  if (expr.match(/^(\\$|@)?\\w+$/i)) {\n    var ret = makeSimpleExpr(expr);\n    xpathParseCache[expr] = ret;\n    xpathLog(' ... simple');\n    return ret;\n  }\n\n  if (expr.match(/^\\w+(\\/\\w+)*$/i)) {\n    var ret = makeSimpleExpr2(expr);\n    xpathParseCache[expr] = ret;\n    xpathLog(' ... simple 2');\n    return ret;\n  }\n\n  var cachekey = expr; // expr is modified during parse\n\n  var stack = [];\n  var ahead = null;\n  var previous = null;\n  var done = false;\n\n  var parse_count = 0;\n  var lexer_count = 0;\n  var reduce_count = 0;\n\n  while (!done) {\n    parse_count++;\n    expr = expr.replace(/^\\s*/, '');\n    previous = ahead;\n    ahead = null;\n\n    var rule = null;\n    var match = '';\n    for (var i = 0; i < xpathTokenRules.length; ++i) {\n      var result = xpathTokenRules[i].re.exec(expr);\n      lexer_count++;\n      if (result && result.length > 0 && result[0].length > match.length) {\n        rule = xpathTokenRules[i];\n        match = result[0];\n        break;\n      }\n    }\n\n    // Special case: allow operator keywords to be element and\n    // variable names.\n\n    // NOTE(mesch): The parser resolves conflicts by looking ahead,\n    // and this is the only case where we look back to\n    // disambiguate. So this is indeed something different, and\n    // looking back is usually done in the lexer (via states in the\n    // general case, called \"start conditions\" in flex(1)). Also,the\n    // conflict resolution in the parser is not as robust as it could\n    // be, so I'd like to keep as much off the parser as possible (all\n    // these precedence values should be computed from the grammar\n    // rules and possibly associativity declarations, as in bison(1),\n    // and not explicitly set.\n\n    if (rule &&\n        (rule == TOK_DIV ||\n         rule == TOK_MOD ||\n         rule == TOK_AND ||\n         rule == TOK_OR) &&\n        (!previous ||\n         previous.tag == TOK_AT ||\n         previous.tag == TOK_DSLASH ||\n         previous.tag == TOK_SLASH ||\n         previous.tag == TOK_AXIS ||\n         previous.tag == TOK_DOLLAR)) {\n      rule = TOK_QNAME;\n    }\n\n    if (rule) {\n      expr = expr.substr(match.length);\n      xpathLog('token: ' + match + ' -- ' + rule.label);\n      ahead = {\n        tag: rule,\n        match: match,\n        prec: rule.prec ?  rule.prec : 0, // || 0 is removed by the compiler\n        expr: makeTokenExpr(match)\n      };\n\n    } else {\n      xpathLog('DONE');\n      done = true;\n    }\n\n    while (xpathReduce(stack, ahead)) {\n      reduce_count++;\n      xpathLog('stack: ' + stackToString(stack));\n    }\n  }\n\n  xpathLog('stack: ' + stackToString(stack));\n\n  // DGF any valid XPath should \"reduce\" to a single Expr token\n  if (stack.length != 1) {\n    throw 'XPath parse error ' + cachekey + ':\\n' + stackToString(stack);\n  }\n\n  var result = stack[0].expr;\n  xpathParseCache[cachekey] = result;\n\n  xpathLog('XPath parse: ' + parse_count + ' / ' +\n           lexer_count + ' / ' + reduce_count);\n\n  return result;\n}\n\nvar xpathParseCache = {};\n\nfunction xpathCacheLookup(expr) {\n  return xpathParseCache[expr];\n}\n\n/*DGF xpathReduce is where the magic happens in this parser.\nSkim down to the bottom of this file to find the table of \ngrammatical rules and precedence numbers, \"The productions of the grammar\".\n\nThe idea here\nis that we want to take a stack of tokens and apply\ngrammatical rules to them, \"reducing\" them to higher-level\ntokens.  Ultimately, any valid XPath should reduce to exactly one\n\"Expr\" token.\n\nReduce too early or too late and you'll have two tokens that can't reduce\nto single Expr.  For example, you may hastily reduce a qname that\nshould name a function, incorrectly treating it as a tag name.\nOr you may reduce too late, accidentally reducing the last part of the\nXPath into a top-level \"Expr\" that won't reduce with earlier parts of\nthe XPath.\n\nA \"cand\" is a grammatical rule candidate, with a given precedence\nnumber.  \"ahead\" is the upcoming token, which also has a precedence\nnumber.  If the token has a higher precedence number than\nthe rule candidate, we'll \"shift\" the token onto the token stack,\ninstead of immediately applying the rule candidate.\n\nSome tokens have left associativity, in which case we shift when they\nhave LOWER precedence than the candidate.\n*/\nfunction xpathReduce(stack, ahead) {\n  var cand = null;\n\n  if (stack.length > 0) {\n    var top = stack[stack.length-1];\n    var ruleset = xpathRules[top.tag.key];\n\n    if (ruleset) {\n      for (var i = 0; i < ruleset.length; ++i) {\n        var rule = ruleset[i];\n        var match = xpathMatchStack(stack, rule[1]);\n        if (match.length) {\n          cand = {\n            tag: rule[0],\n            rule: rule,\n            match: match\n          };\n          cand.prec = xpathGrammarPrecedence(cand);\n          break;\n        }\n      }\n    }\n  }\n\n  var ret;\n  if (cand && (!ahead || cand.prec > ahead.prec ||\n               (ahead.tag.left && cand.prec >= ahead.prec))) {\n    for (var i = 0; i < cand.match.matchlength; ++i) {\n      stack.pop();\n    }\n\n    xpathLog('reduce ' + cand.tag.label + ' ' + cand.prec +\n             ' ahead ' + (ahead ? ahead.tag.label + ' ' + ahead.prec +\n                          (ahead.tag.left ? ' left' : '')\n                          : ' none '));\n\n    var matchexpr = mapExpr(cand.match, function(m) { return m.expr; });\n    xpathLog('going to apply ' + cand.rule[3].toString());\n    cand.expr = cand.rule[3].apply(null, matchexpr);\n\n    stack.push(cand);\n    ret = true;\n\n  } else {\n    if (ahead) {\n      xpathLog('shift ' + ahead.tag.label + ' ' + ahead.prec +\n               (ahead.tag.left ? ' left' : '') +\n               ' over ' + (cand ? cand.tag.label + ' ' +\n                           cand.prec : ' none'));\n      stack.push(ahead);\n    }\n    ret = false;\n  }\n  return ret;\n}\n\nfunction xpathMatchStack(stack, pattern) {\n\n  // NOTE(mesch): The stack matches for variable cardinality are\n  // greedy but don't do backtracking. This would be an issue only\n  // with rules of the form A* A, i.e. with an element with variable\n  // cardinality followed by the same element. Since that doesn't\n  // occur in the grammar at hand, all matches on the stack are\n  // unambiguous.\n\n  var S = stack.length;\n  var P = pattern.length;\n  var p, s;\n  var match = [];\n  match.matchlength = 0;\n  var ds = 0;\n  for (p = P - 1, s = S - 1; p >= 0 && s >= 0; --p, s -= ds) {\n    ds = 0;\n    var qmatch = [];\n    if (pattern[p] == Q_MM) {\n      p -= 1;\n      match.push(qmatch);\n      while (s - ds >= 0 && stack[s - ds].tag == pattern[p]) {\n        qmatch.push(stack[s - ds]);\n        ds += 1;\n        match.matchlength += 1;\n      }\n\n    } else if (pattern[p] == Q_01) {\n      p -= 1;\n      match.push(qmatch);\n      while (s - ds >= 0 && ds < 2 && stack[s - ds].tag == pattern[p]) {\n        qmatch.push(stack[s - ds]);\n        ds += 1;\n        match.matchlength += 1;\n      }\n\n    } else if (pattern[p] == Q_1M) {\n      p -= 1;\n      match.push(qmatch);\n      if (stack[s].tag == pattern[p]) {\n        while (s - ds >= 0 && stack[s - ds].tag == pattern[p]) {\n          qmatch.push(stack[s - ds]);\n          ds += 1;\n          match.matchlength += 1;\n        }\n      } else {\n        return [];\n      }\n\n    } else if (stack[s].tag == pattern[p]) {\n      match.push(stack[s]);\n      ds += 1;\n      match.matchlength += 1;\n\n    } else {\n      return [];\n    }\n\n    reverseInplace(qmatch);\n    qmatch.expr = mapExpr(qmatch, function(m) { return m.expr; });\n  }\n\n  reverseInplace(match);\n\n  if (p == -1) {\n    return match;\n\n  } else {\n    return [];\n  }\n}\n\nfunction xpathTokenPrecedence(tag) {\n  return tag.prec || 2;\n}\n\nfunction xpathGrammarPrecedence(frame) {\n  var ret = 0;\n\n  if (frame.rule) { /* normal reduce */\n    if (frame.rule.length >= 3 && frame.rule[2] >= 0) {\n      ret = frame.rule[2];\n\n    } else {\n      for (var i = 0; i < frame.rule[1].length; ++i) {\n        var p = xpathTokenPrecedence(frame.rule[1][i]);\n        ret = Math.max(ret, p);\n      }\n    }\n  } else if (frame.tag) { /* TOKEN match */\n    ret = xpathTokenPrecedence(frame.tag);\n\n  } else if (frame.length) { /* Q_ match */\n    for (var j = 0; j < frame.length; ++j) {\n      var p = xpathGrammarPrecedence(frame[j]);\n      ret = Math.max(ret, p);\n    }\n  }\n\n  return ret;\n}\n\nfunction stackToString(stack) {\n  var ret = '';\n  for (var i = 0; i < stack.length; ++i) {\n    if (ret) {\n      ret += '\\n';\n    }\n    ret += stack[i].tag.label;\n  }\n  return ret;\n}\n\n\n// XPath expression evaluation context. An XPath context consists of a\n// DOM node, a list of DOM nodes that contains this node, a number\n// that represents the position of the single node in the list, and a\n// current set of variable bindings. (See XPath spec.)\n//\n// The interface of the expression context:\n//\n//   Constructor -- gets the node, its position, the node set it\n//   belongs to, and a parent context as arguments. The parent context\n//   is used to implement scoping rules for variables: if a variable\n//   is not found in the current context, it is looked for in the\n//   parent context, recursively. Except for node, all arguments have\n//   default values: default position is 0, default node set is the\n//   set that contains only the node, and the default parent is null.\n//\n//     Notice that position starts at 0 at the outside interface;\n//     inside XPath expressions this shows up as position()=1.\n//\n//   clone() -- creates a new context with the current context as\n//   parent. If passed as argument to clone(), the new context has a\n//   different node, position, or node set. What is not passed is\n//   inherited from the cloned context.\n//\n//   setVariable(name, expr) -- binds given XPath expression to the\n//   name.\n//\n//   getVariable(name) -- what the name says.\n//\n//   setNode(position) -- sets the context to the node at the given\n//   position. Needed to implement scoping rules for variables in\n//   XPath. (A variable is visible to all subsequent siblings, not\n//   only to its children.)\n//\n//   set/isCaseInsensitive -- specifies whether node name tests should\n//   be case sensitive.  If you're executing xpaths against a regular\n//   HTML DOM, you probably don't want case-sensitivity, because\n//   browsers tend to disagree about whether elements & attributes\n//   should be upper/lower case.  If you're running xpaths in an\n//   XSLT instance, you probably DO want case sensitivity, as per the\n//   XSL spec.\n\nfunction ExprContext(node, opt_position, opt_nodelist, opt_parent,\n  opt_caseInsensitive, opt_ignoreAttributesWithoutValue,\n  opt_returnOnFirstMatch)\n{\n  this.node = node;\n  this.position = opt_position || 0;\n  this.nodelist = opt_nodelist || [ node ];\n  this.variables = {};\n  this.parent = opt_parent || null;\n  this.caseInsensitive = opt_caseInsensitive || false;\n  this.ignoreAttributesWithoutValue = opt_ignoreAttributesWithoutValue || false;\n  this.returnOnFirstMatch = opt_returnOnFirstMatch || false;\n  if (opt_parent) {\n    this.root = opt_parent.root;\n  } else if (this.node.nodeType == DOM_DOCUMENT_NODE) {\n    // NOTE(mesch): DOM Spec stipulates that the ownerDocument of a\n    // document is null. Our root, however is the document that we are\n    // processing, so the initial context is created from its document\n    // node, which case we must handle here explcitly.\n    this.root = node;\n  } else {\n    this.root = node.ownerDocument;\n  }\n}\n\nExprContext.prototype.clone = function(opt_node, opt_position, opt_nodelist) {\n  return new ExprContext(\n      opt_node || this.node,\n      typeof opt_position != 'undefined' ? opt_position : this.position,\n      opt_nodelist || this.nodelist, this, this.caseInsensitive,\n      this.ignoreAttributesWithoutValue, this.returnOnFirstMatch);\n};\n\nExprContext.prototype.setVariable = function(name, value) {\n  if (value instanceof StringValue || value instanceof BooleanValue || \n    value instanceof NumberValue || value instanceof NodeSetValue) {\n    this.variables[name] = value;\n    return;\n  }\n  if ('true' === value) {\n    this.variables[name] = new BooleanValue(true);\n  } else if ('false' === value) {\n    this.variables[name] = new BooleanValue(false);\n  } else if (TOK_NUMBER.re.test(value)) {\n    this.variables[name] = new NumberValue(value);\n  } else {\n    // DGF What if it's null?\n    this.variables[name] = new StringValue(value);\n  }\n};\n\nExprContext.prototype.getVariable = function(name) {\n  if (typeof this.variables[name] != 'undefined') {\n    return this.variables[name];\n\n  } else if (this.parent) {\n    return this.parent.getVariable(name);\n\n  } else {\n    return null;\n  }\n};\n\nExprContext.prototype.setNode = function(position) {\n  this.node = this.nodelist[position];\n  this.position = position;\n};\n\nExprContext.prototype.contextSize = function() {\n  return this.nodelist.length;\n};\n\nExprContext.prototype.isCaseInsensitive = function() {\n  return this.caseInsensitive;\n};\n\nExprContext.prototype.setCaseInsensitive = function(caseInsensitive) {\n  return this.caseInsensitive = caseInsensitive;\n};\n\nExprContext.prototype.isIgnoreAttributesWithoutValue = function() {\n  return this.ignoreAttributesWithoutValue;\n};\n\nExprContext.prototype.setIgnoreAttributesWithoutValue = function(ignore) {\n  return this.ignoreAttributesWithoutValue = ignore;\n};\n\nExprContext.prototype.isReturnOnFirstMatch = function() {\n  return this.returnOnFirstMatch;\n};\n\nExprContext.prototype.setReturnOnFirstMatch = function(returnOnFirstMatch) {\n  return this.returnOnFirstMatch = returnOnFirstMatch;\n};\n\n// XPath expression values. They are what XPath expressions evaluate\n// to. Strangely, the different value types are not specified in the\n// XPath syntax, but only in the semantics, so they don't show up as\n// nonterminals in the grammar. Yet, some expressions are required to\n// evaluate to particular types, and not every type can be coerced\n// into every other type. Although the types of XPath values are\n// similar to the types present in JavaScript, the type coercion rules\n// are a bit peculiar, so we explicitly model XPath types instead of\n// mapping them onto JavaScript types. (See XPath spec.)\n//\n// The four types are:\n//\n//   StringValue\n//\n//   NumberValue\n//\n//   BooleanValue\n//\n//   NodeSetValue\n//\n// The common interface of the value classes consists of methods that\n// implement the XPath type coercion rules:\n//\n//   stringValue() -- returns the value as a JavaScript String,\n//\n//   numberValue() -- returns the value as a JavaScript Number,\n//\n//   booleanValue() -- returns the value as a JavaScript Boolean,\n//\n//   nodeSetValue() -- returns the value as a JavaScript Array of DOM\n//   Node objects.\n//\n\nfunction StringValue(value) {\n  this.value = value;\n  this.type = 'string';\n}\n\nStringValue.prototype.stringValue = function() {\n  return this.value;\n}\n\nStringValue.prototype.booleanValue = function() {\n  return this.value.length > 0;\n}\n\nStringValue.prototype.numberValue = function() {\n  return this.value - 0;\n}\n\nStringValue.prototype.nodeSetValue = function() {\n  throw this;\n}\n\nfunction BooleanValue(value) {\n  this.value = value;\n  this.type = 'boolean';\n}\n\nBooleanValue.prototype.stringValue = function() {\n  return '' + this.value;\n}\n\nBooleanValue.prototype.booleanValue = function() {\n  return this.value;\n}\n\nBooleanValue.prototype.numberValue = function() {\n  return this.value ? 1 : 0;\n}\n\nBooleanValue.prototype.nodeSetValue = function() {\n  throw this;\n}\n\nfunction NumberValue(value) {\n  this.value = value;\n  this.type = 'number';\n}\n\nNumberValue.prototype.stringValue = function() {\n  return '' + this.value;\n}\n\nNumberValue.prototype.booleanValue = function() {\n  return !!this.value;\n}\n\nNumberValue.prototype.numberValue = function() {\n  return this.value - 0;\n}\n\nNumberValue.prototype.nodeSetValue = function() {\n  throw this;\n}\n\nfunction NodeSetValue(value) {\n  this.value = value;\n  this.type = 'node-set';\n}\n\nNodeSetValue.prototype.stringValue = function() {\n  if (this.value.length == 0) {\n    return '';\n  } else {\n    return xmlValue(this.value[0]);\n  }\n}\n\nNodeSetValue.prototype.booleanValue = function() {\n  return this.value.length > 0;\n}\n\nNodeSetValue.prototype.numberValue = function() {\n  return this.stringValue() - 0;\n}\n\nNodeSetValue.prototype.nodeSetValue = function() {\n  return this.value;\n};\n\n// XPath expressions. They are used as nodes in the parse tree and\n// possess an evaluate() method to compute an XPath value given an XPath\n// context. Expressions are returned from the parser. Teh set of\n// expression classes closely mirrors the set of non terminal symbols\n// in the grammar. Every non trivial nonterminal symbol has a\n// corresponding expression class.\n//\n// The common expression interface consists of the following methods:\n//\n// evaluate(context) -- evaluates the expression, returns a value.\n//\n// toString() -- returns the XPath text representation of the\n// expression (defined in xsltdebug.js).\n//\n// parseTree(indent) -- returns a parse tree representation of the\n// expression (defined in xsltdebug.js).\n\nfunction TokenExpr(m) {\n  this.value = m;\n}\n\nTokenExpr.prototype.evaluate = function() {\n  return new StringValue(this.value);\n};\n\nfunction LocationExpr() {\n  this.absolute = false;\n  this.steps = [];\n}\n\nLocationExpr.prototype.appendStep = function(s) {\n  var combinedStep = this._combineSteps(this.steps[this.steps.length-1], s);\n  if (combinedStep) {\n    this.steps[this.steps.length-1] = combinedStep;\n  } else {\n    this.steps.push(s);\n  }\n}\n\nLocationExpr.prototype.prependStep = function(s) {\n  var combinedStep = this._combineSteps(s, this.steps[0]);\n  if (combinedStep) {\n    this.steps[0] = combinedStep;\n  } else {\n    this.steps.unshift(s);\n  }\n};\n\n// DGF try to combine two steps into one step (perf enhancement)\nLocationExpr.prototype._combineSteps = function(prevStep, nextStep) {\n  if (!prevStep) return null;\n  if (!nextStep) return null;\n  var hasPredicates = (prevStep.predicates && prevStep.predicates.length > 0);\n  if (prevStep.nodetest instanceof NodeTestAny && !hasPredicates) {\n    // maybe suitable to be combined\n    if (prevStep.axis == xpathAxis.DESCENDANT_OR_SELF) {\n      if (nextStep.axis == xpathAxis.CHILD) {\n        // HBC - commenting out, because this is not a valid reduction\n        //nextStep.axis = xpathAxis.DESCENDANT;\n        //return nextStep;\n      } else if (nextStep.axis == xpathAxis.SELF) {\n        nextStep.axis = xpathAxis.DESCENDANT_OR_SELF;\n        return nextStep;\n      }\n    } else if (prevStep.axis == xpathAxis.DESCENDANT) {\n      if (nextStep.axis == xpathAxis.SELF) {\n        nextStep.axis = xpathAxis.DESCENDANT;\n        return nextStep;\n      }\n    }\n  }\n  return null;\n}\n\nLocationExpr.prototype.evaluate = function(ctx) {\n  var start;\n  if (this.absolute) {\n    start = ctx.root;\n\n  } else {\n    start = ctx.node;\n  }\n\n  var nodes = [];\n  xPathStep(nodes, this.steps, 0, start, ctx);\n  return new NodeSetValue(nodes);\n};\n\nfunction xPathStep(nodes, steps, step, input, ctx) {\n  var s = steps[step];\n  var ctx2 = ctx.clone(input);\n  \n  if (ctx.returnOnFirstMatch && !s.hasPositionalPredicate) {\n    var nodelist = s.evaluate(ctx2).nodeSetValue();\n    // the predicates were not processed in the last evaluate(), so that we can\n    // process them here with the returnOnFirstMatch optimization. We do a\n    // depth-first grab at any nodes that pass the predicate tests. There is no\n    // way to optimize when predicates contain positional selectors, including\n    // indexes or uses of the last() or position() functions, because they\n    // typically require the entire nodelist for context. Process without\n    // optimization if we encounter such selectors.\n    var nLength = nodelist.length;\n    var pLength = s.predicate.length;\n    nodelistLoop:\n    for (var i = 0; i < nLength; ++i) {\n      var n = nodelist[i];\n      for (var j = 0; j < pLength; ++j) {\n        if (!s.predicate[j].evaluate(ctx.clone(n, i, nodelist)).booleanValue()) {\n          continue nodelistLoop;\n        }\n      }\n      // n survived the predicate tests!\n      if (step == steps.length - 1) {\n        nodes.push(n);\n      }\n      else {\n        xPathStep(nodes, steps, step + 1, n, ctx);\n      }\n      if (nodes.length > 0) {\n        break;\n      }\n    }\n  }\n  else {\n    // set returnOnFirstMatch to false for the cloned ExprContext, because\n    // behavior in StepExpr.prototype.evaluate is driven off its value. Note\n    // that the original context may still have true for this value.\n    ctx2.returnOnFirstMatch = false;\n    var nodelist = s.evaluate(ctx2).nodeSetValue();\n    for (var i = 0; i < nodelist.length; ++i) {\n      if (step == steps.length - 1) {\n        nodes.push(nodelist[i]);\n      } else {\n        xPathStep(nodes, steps, step + 1, nodelist[i], ctx);\n      }\n    }\n  }\n}\n\nfunction StepExpr(axis, nodetest, opt_predicate) {\n  this.axis = axis;\n  this.nodetest = nodetest;\n  this.predicate = opt_predicate || [];\n  this.hasPositionalPredicate = false;\n  for (var i = 0; i < this.predicate.length; ++i) {\n    if (predicateExprHasPositionalSelector(this.predicate[i].expr)) {\n      this.hasPositionalPredicate = true;\n      break;\n    }\n  }\n}\n\nStepExpr.prototype.appendPredicate = function(p) {\n  this.predicate.push(p);\n  if (!this.hasPositionalPredicate) {\n    this.hasPositionalPredicate = predicateExprHasPositionalSelector(p.expr);\n  }\n}\n\nStepExpr.prototype.evaluate = function(ctx) {\n  var input = ctx.node;\n  var nodelist = [];\n  var skipNodeTest = false;\n  \n  if (this.nodetest instanceof NodeTestAny) {\n    skipNodeTest = true;\n  }\n\n  // NOTE(mesch): When this was a switch() statement, it didn't work\n  // in Safari/2.0. Not sure why though; it resulted in the JavaScript\n  // console output \"undefined\" (without any line number or so).\n\n  if (this.axis ==  xpathAxis.ANCESTOR_OR_SELF) {\n    nodelist.push(input);\n    for (var n = input.parentNode; n; n = n.parentNode) {\n      nodelist.push(n);\n    }\n\n  } else if (this.axis == xpathAxis.ANCESTOR) {\n    for (var n = input.parentNode; n; n = n.parentNode) {\n      nodelist.push(n);\n    }\n\n  } else if (this.axis == xpathAxis.ATTRIBUTE) {\n    if (this.nodetest.name != undefined) {\n      // single-attribute step\n      if (input.attributes) {\n        if (input.attributes instanceof Array) {\n          // probably evaluating on document created by xmlParse()\n          copyArray(nodelist, input.attributes);\n        }\n        else {\n          if (this.nodetest.name == 'style') {\n            var value = input.getAttribute('style');\n            if (value && typeof(value) != 'string') {\n              // this is the case where indexing into the attributes array\n              // doesn't give us the attribute node in IE - we create our own\n              // node instead\n              nodelist.push(XNode.create(DOM_ATTRIBUTE_NODE, 'style',\n                value.cssText, document));\n            }\n            else {\n              nodelist.push(input.attributes[this.nodetest.name]);\n            }\n          }\n          else {\n            nodelist.push(input.attributes[this.nodetest.name]);\n          }\n        }\n      }\n    }\n    else {\n      // all-attributes step\n      if (ctx.ignoreAttributesWithoutValue) {\n        copyArrayIgnoringAttributesWithoutValue(nodelist, input.attributes);\n      }\n      else {\n        copyArray(nodelist, input.attributes);\n      }\n    }\n    \n  } else if (this.axis == xpathAxis.CHILD) {\n    copyArray(nodelist, input.childNodes);\n\n  } else if (this.axis == xpathAxis.DESCENDANT_OR_SELF) {\n    if (this.nodetest.evaluate(ctx).booleanValue()) {\n      nodelist.push(input);\n    }\n    var tagName = xpathExtractTagNameFromNodeTest(this.nodetest);\n    xpathCollectDescendants(nodelist, input, tagName);\n    if (tagName) skipNodeTest = true;\n\n  } else if (this.axis == xpathAxis.DESCENDANT) {\n    var tagName = xpathExtractTagNameFromNodeTest(this.nodetest);\n    xpathCollectDescendants(nodelist, input, tagName);\n    if (tagName) skipNodeTest = true;\n\n  } else if (this.axis == xpathAxis.FOLLOWING) {\n    for (var n = input; n; n = n.parentNode) {\n      for (var nn = n.nextSibling; nn; nn = nn.nextSibling) {\n        nodelist.push(nn);\n        xpathCollectDescendants(nodelist, nn);\n      }\n    }\n\n  } else if (this.axis == xpathAxis.FOLLOWING_SIBLING) {\n    for (var n = input.nextSibling; n; n = n.nextSibling) {\n      nodelist.push(n);\n    }\n\n  } else if (this.axis == xpathAxis.NAMESPACE) {\n    alert('not implemented: axis namespace');\n\n  } else if (this.axis == xpathAxis.PARENT) {\n    if (input.parentNode) {\n      nodelist.push(input.parentNode);\n    }\n\n  } else if (this.axis == xpathAxis.PRECEDING) {\n    for (var n = input; n; n = n.parentNode) {\n      for (var nn = n.previousSibling; nn; nn = nn.previousSibling) {\n        nodelist.push(nn);\n        xpathCollectDescendantsReverse(nodelist, nn);\n      }\n    }\n\n  } else if (this.axis == xpathAxis.PRECEDING_SIBLING) {\n    for (var n = input.previousSibling; n; n = n.previousSibling) {\n      nodelist.push(n);\n    }\n\n  } else if (this.axis == xpathAxis.SELF) {\n    nodelist.push(input);\n\n  } else {\n    throw 'ERROR -- NO SUCH AXIS: ' + this.axis;\n  }\n\n  if (!skipNodeTest) {\n    // process node test\n    var nodelist0 = nodelist;\n    nodelist = [];\n    for (var i = 0; i < nodelist0.length; ++i) {\n      var n = nodelist0[i];\n      if (this.nodetest.evaluate(ctx.clone(n, i, nodelist0)).booleanValue()) {\n        nodelist.push(n);\n      }\n    }\n  }\n\n  // process predicates\n  if (!ctx.returnOnFirstMatch) {\n    for (var i = 0; i < this.predicate.length; ++i) {\n      var nodelist0 = nodelist;\n      nodelist = [];\n      for (var ii = 0; ii < nodelist0.length; ++ii) {\n        var n = nodelist0[ii];\n        if (this.predicate[i].evaluate(ctx.clone(n, ii, nodelist0)).booleanValue()) {\n          nodelist.push(n);\n        }\n      }\n    }\n  }\n\n  return new NodeSetValue(nodelist);\n};\n\nfunction NodeTestAny() {\n  this.value = new BooleanValue(true);\n}\n\nNodeTestAny.prototype.evaluate = function(ctx) {\n  return this.value;\n};\n\nfunction NodeTestElementOrAttribute() {}\n\nNodeTestElementOrAttribute.prototype.evaluate = function(ctx) {\n  return new BooleanValue(\n      ctx.node.nodeType == DOM_ELEMENT_NODE ||\n      ctx.node.nodeType == DOM_ATTRIBUTE_NODE);\n}\n\nfunction NodeTestText() {}\n\nNodeTestText.prototype.evaluate = function(ctx) {\n  return new BooleanValue(ctx.node.nodeType == DOM_TEXT_NODE);\n}\n\nfunction NodeTestComment() {}\n\nNodeTestComment.prototype.evaluate = function(ctx) {\n  return new BooleanValue(ctx.node.nodeType == DOM_COMMENT_NODE);\n}\n\nfunction NodeTestPI(target) {\n  this.target = target;\n}\n\nNodeTestPI.prototype.evaluate = function(ctx) {\n  return new\n  BooleanValue(ctx.node.nodeType == DOM_PROCESSING_INSTRUCTION_NODE &&\n               (!this.target || ctx.node.nodeName == this.target));\n}\n\nfunction NodeTestNC(nsprefix) {\n  this.regex = new RegExp(\"^\" + nsprefix + \":\");\n  this.nsprefix = nsprefix;\n}\n\nNodeTestNC.prototype.evaluate = function(ctx) {\n  var n = ctx.node;\n  return new BooleanValue(this.regex.match(n.nodeName));\n}\n\nfunction NodeTestName(name) {\n  this.name = name;\n  this.re = new RegExp('^' + name + '$', \"i\");\n}\n\nNodeTestName.prototype.evaluate = function(ctx) {\n  var n = ctx.node;\n  if (ctx.caseInsensitive) {\n    if (n.nodeName.length != this.name.length) return new BooleanValue(false);\n    return new BooleanValue(this.re.test(n.nodeName));\n  } else {\n    return new BooleanValue(n.nodeName == this.name);\n  }\n}\n\nfunction PredicateExpr(expr) {\n  this.expr = expr;\n}\n\nPredicateExpr.prototype.evaluate = function(ctx) {\n  var v = this.expr.evaluate(ctx);\n  if (v.type == 'number') {\n    // NOTE(mesch): Internally, position is represented starting with\n    // 0, however in XPath position starts with 1. See functions\n    // position() and last().\n    return new BooleanValue(ctx.position == v.numberValue() - 1);\n  } else {\n    return new BooleanValue(v.booleanValue());\n  }\n};\n\nfunction FunctionCallExpr(name) {\n  this.name = name;\n  this.args = [];\n}\n\nFunctionCallExpr.prototype.appendArg = function(arg) {\n  this.args.push(arg);\n};\n\nFunctionCallExpr.prototype.evaluate = function(ctx) {\n  var fn = '' + this.name.value;\n  var f = this.xpathfunctions[fn];\n  if (f) {\n    return f.call(this, ctx);\n  } else {\n    xpathLog('XPath NO SUCH FUNCTION ' + fn);\n    return new BooleanValue(false);\n  }\n};\n\nFunctionCallExpr.prototype.xpathfunctions = {\n  'last': function(ctx) {\n    assert(this.args.length == 0);\n    // NOTE(mesch): XPath position starts at 1.\n    return new NumberValue(ctx.contextSize());\n  },\n\n  'position': function(ctx) {\n    assert(this.args.length == 0);\n    // NOTE(mesch): XPath position starts at 1.\n    return new NumberValue(ctx.position + 1);\n  },\n\n  'count': function(ctx) {\n    assert(this.args.length == 1);\n    var v = this.args[0].evaluate(ctx);\n    return new NumberValue(v.nodeSetValue().length);\n  },\n\n  'id': function(ctx) {\n    assert(this.args.length == 1);\n    var e = this.args[0].evaluate(ctx);\n    var ret = [];\n    var ids;\n    if (e.type == 'node-set') {\n      ids = [];\n      var en = e.nodeSetValue();\n      for (var i = 0; i < en.length; ++i) {\n        var v = xmlValue(en[i]).split(/\\s+/);\n        for (var ii = 0; ii < v.length; ++ii) {\n          ids.push(v[ii]);\n        }\n      }\n    } else {\n      ids = e.stringValue().split(/\\s+/);\n    }\n    var d = ctx.root;\n    for (var i = 0; i < ids.length; ++i) {\n      var n = d.getElementById(ids[i]);\n      if (n) {\n        ret.push(n);\n      }\n    }\n    return new NodeSetValue(ret);\n  },\n\n  'local-name': function(ctx) {\n    alert('not implmented yet: XPath function local-name()');\n  },\n\n  'namespace-uri': function(ctx) {\n    alert('not implmented yet: XPath function namespace-uri()');\n  },\n\n  'name': function(ctx) {\n    assert(this.args.length == 1 || this.args.length == 0);\n    var n;\n    if (this.args.length == 0) {\n      n = [ ctx.node ];\n    } else {\n      n = this.args[0].evaluate(ctx).nodeSetValue();\n    }\n\n    if (n.length == 0) {\n      return new StringValue('');\n    } else {\n      return new StringValue(n[0].nodeName);\n    }\n  },\n\n  'string':  function(ctx) {\n    assert(this.args.length == 1 || this.args.length == 0);\n    if (this.args.length == 0) {\n      return new StringValue(new NodeSetValue([ ctx.node ]).stringValue());\n    } else {\n      return new StringValue(this.args[0].evaluate(ctx).stringValue());\n    }\n  },\n\n  'concat': function(ctx) {\n    var ret = '';\n    for (var i = 0; i < this.args.length; ++i) {\n      ret += this.args[i].evaluate(ctx).stringValue();\n    }\n    return new StringValue(ret);\n  },\n\n  'starts-with': function(ctx) {\n    assert(this.args.length == 2);\n    var s0 = this.args[0].evaluate(ctx).stringValue();\n    var s1 = this.args[1].evaluate(ctx).stringValue();\n    return new BooleanValue(s0.indexOf(s1) == 0);\n  },\n  \n  'ends-with': function(ctx) {\n    assert(this.args.length == 2);\n    var s0 = this.args[0].evaluate(ctx).stringValue();\n    var s1 = this.args[1].evaluate(ctx).stringValue();\n    var re = new RegExp(RegExp.escape(s1) + '$');\n    return new BooleanValue(re.test(s0));\n  },\n\n  'contains': function(ctx) {\n    assert(this.args.length == 2);\n    var s0 = this.args[0].evaluate(ctx).stringValue();\n    var s1 = this.args[1].evaluate(ctx).stringValue();\n    return new BooleanValue(s0.indexOf(s1) != -1);\n  },\n\n  'substring-before': function(ctx) {\n    assert(this.args.length == 2);\n    var s0 = this.args[0].evaluate(ctx).stringValue();\n    var s1 = this.args[1].evaluate(ctx).stringValue();\n    var i = s0.indexOf(s1);\n    var ret;\n    if (i == -1) {\n      ret = '';\n    } else {\n      ret = s0.substr(0,i);\n    }\n    return new StringValue(ret);\n  },\n\n  'substring-after': function(ctx) {\n    assert(this.args.length == 2);\n    var s0 = this.args[0].evaluate(ctx).stringValue();\n    var s1 = this.args[1].evaluate(ctx).stringValue();\n    var i = s0.indexOf(s1);\n    var ret;\n    if (i == -1) {\n      ret = '';\n    } else {\n      ret = s0.substr(i + s1.length);\n    }\n    return new StringValue(ret);\n  },\n\n  'substring': function(ctx) {\n    // NOTE: XPath defines the position of the first character in a\n    // string to be 1, in JavaScript this is 0 ([XPATH] Section 4.2).\n    assert(this.args.length == 2 || this.args.length == 3);\n    var s0 = this.args[0].evaluate(ctx).stringValue();\n    var s1 = this.args[1].evaluate(ctx).numberValue();\n    var ret;\n    if (this.args.length == 2) {\n      var i1 = Math.max(0, Math.round(s1) - 1);\n      ret = s0.substr(i1);\n\n    } else {\n      var s2 = this.args[2].evaluate(ctx).numberValue();\n      var i0 = Math.round(s1) - 1;\n      var i1 = Math.max(0, i0);\n      var i2 = Math.round(s2) - Math.max(0, -i0);\n      ret = s0.substr(i1, i2);\n    }\n    return new StringValue(ret);\n  },\n\n  'string-length': function(ctx) {\n    var s;\n    if (this.args.length > 0) {\n      s = this.args[0].evaluate(ctx).stringValue();\n    } else {\n      s = new NodeSetValue([ ctx.node ]).stringValue();\n    }\n    return new NumberValue(s.length);\n  },\n\n  'normalize-space': function(ctx) {\n    var s;\n    if (this.args.length > 0) {\n      s = this.args[0].evaluate(ctx).stringValue();\n    } else {\n      s = new NodeSetValue([ ctx.node ]).stringValue();\n    }\n    s = s.replace(/^\\s*/,'').replace(/\\s*$/,'').replace(/\\s+/g, ' ');\n    return new StringValue(s);\n  },\n\n  'translate': function(ctx) {\n    assert(this.args.length == 3);\n    var s0 = this.args[0].evaluate(ctx).stringValue();\n    var s1 = this.args[1].evaluate(ctx).stringValue();\n    var s2 = this.args[2].evaluate(ctx).stringValue();\n\n    for (var i = 0; i < s1.length; ++i) {\n      s0 = s0.replace(new RegExp(s1.charAt(i), 'g'), s2.charAt(i));\n    }\n    return new StringValue(s0);\n  },\n  \n  'matches': function(ctx) {\n    assert(this.args.length >= 2);\n    var s0 = this.args[0].evaluate(ctx).stringValue();\n    var s1 = this.args[1].evaluate(ctx).stringValue();\n    if (this.args.length > 2) {\n      var s2 = this.args[2].evaluate(ctx).stringValue();\n      if (/[^mi]/.test(s2)) {\n        throw 'Invalid regular expression syntax: ' + s2;\n      }\n    }\n    \n    try {\n      var re = new RegExp(s1, s2);\n    }\n    catch (e) {\n      throw 'Invalid matches argument: ' + s1;\n    }\n    return new BooleanValue(re.test(s0));\n  },\n\n  'boolean': function(ctx) {\n    assert(this.args.length == 1);\n    return new BooleanValue(this.args[0].evaluate(ctx).booleanValue());\n  },\n\n  'not': function(ctx) {\n    assert(this.args.length == 1);\n    var ret = !this.args[0].evaluate(ctx).booleanValue();\n    return new BooleanValue(ret);\n  },\n\n  'true': function(ctx) {\n    assert(this.args.length == 0);\n    return new BooleanValue(true);\n  },\n\n  'false': function(ctx) {\n    assert(this.args.length == 0);\n    return new BooleanValue(false);\n  },\n\n  'lang': function(ctx) {\n    assert(this.args.length == 1);\n    var lang = this.args[0].evaluate(ctx).stringValue();\n    var xmllang;\n    var n = ctx.node;\n    while (n && n != n.parentNode /* just in case ... */) {\n      xmllang = n.getAttribute('xml:lang');\n      if (xmllang) {\n        break;\n      }\n      n = n.parentNode;\n    }\n    if (!xmllang) {\n      return new BooleanValue(false);\n    } else {\n      var re = new RegExp('^' + lang + '$', 'i');\n      return new BooleanValue(xmllang.match(re) ||\n                              xmllang.replace(/_.*$/,'').match(re));\n    }\n  },\n\n  'number': function(ctx) {\n    assert(this.args.length == 1 || this.args.length == 0);\n\n    if (this.args.length == 1) {\n      return new NumberValue(this.args[0].evaluate(ctx).numberValue());\n    } else {\n      return new NumberValue(new NodeSetValue([ ctx.node ]).numberValue());\n    }\n  },\n\n  'sum': function(ctx) {\n    assert(this.args.length == 1);\n    var n = this.args[0].evaluate(ctx).nodeSetValue();\n    var sum = 0;\n    for (var i = 0; i < n.length; ++i) {\n      sum += xmlValue(n[i]) - 0;\n    }\n    return new NumberValue(sum);\n  },\n\n  'floor': function(ctx) {\n    assert(this.args.length == 1);\n    var num = this.args[0].evaluate(ctx).numberValue();\n    return new NumberValue(Math.floor(num));\n  },\n\n  'ceiling': function(ctx) {\n    assert(this.args.length == 1);\n    var num = this.args[0].evaluate(ctx).numberValue();\n    return new NumberValue(Math.ceil(num));\n  },\n\n  'round': function(ctx) {\n    assert(this.args.length == 1);\n    var num = this.args[0].evaluate(ctx).numberValue();\n    return new NumberValue(Math.round(num));\n  },\n\n  // TODO(mesch): The following functions are custom. There is a\n  // standard that defines how to add functions, which should be\n  // applied here.\n\n  'ext-join': function(ctx) {\n    assert(this.args.length == 2);\n    var nodes = this.args[0].evaluate(ctx).nodeSetValue();\n    var delim = this.args[1].evaluate(ctx).stringValue();\n    var ret = '';\n    for (var i = 0; i < nodes.length; ++i) {\n      if (ret) {\n        ret += delim;\n      }\n      ret += xmlValue(nodes[i]);\n    }\n    return new StringValue(ret);\n  },\n\n  // ext-if() evaluates and returns its second argument, if the\n  // boolean value of its first argument is true, otherwise it\n  // evaluates and returns its third argument.\n\n  'ext-if': function(ctx) {\n    assert(this.args.length == 3);\n    if (this.args[0].evaluate(ctx).booleanValue()) {\n      return this.args[1].evaluate(ctx);\n    } else {\n      return this.args[2].evaluate(ctx);\n    }\n  },\n\n  // ext-cardinal() evaluates its single argument as a number, and\n  // returns the current node that many times. It can be used in the\n  // select attribute to iterate over an integer range.\n\n  'ext-cardinal': function(ctx) {\n    assert(this.args.length >= 1);\n    var c = this.args[0].evaluate(ctx).numberValue();\n    var ret = [];\n    for (var i = 0; i < c; ++i) {\n      ret.push(ctx.node);\n    }\n    return new NodeSetValue(ret);\n  }\n};\n\nfunction UnionExpr(expr1, expr2) {\n  this.expr1 = expr1;\n  this.expr2 = expr2;\n}\n\nUnionExpr.prototype.evaluate = function(ctx) {\n  var nodes1 = this.expr1.evaluate(ctx).nodeSetValue();\n  var nodes2 = this.expr2.evaluate(ctx).nodeSetValue();\n  var I1 = nodes1.length;\n  for (var i2 = 0; i2 < nodes2.length; ++i2) {\n    var n = nodes2[i2];\n    var inBoth = false;\n    for (var i1 = 0; i1 < I1; ++i1) {\n      if (nodes1[i1] == n) {\n        inBoth = true;\n        i1 = I1; // break inner loop\n      }\n    }\n    if (!inBoth) {\n      nodes1.push(n);\n    }\n  }\n  return new NodeSetValue(nodes1);\n};\n\nfunction PathExpr(filter, rel) {\n  this.filter = filter;\n  this.rel = rel;\n}\n\nPathExpr.prototype.evaluate = function(ctx) {\n  // the filter expression should be evaluated in its entirety with no\n  // optimization, as we can't backtrack to it after having moved on to\n  // evaluating the relative location path\n  var flag = ctx.returnOnFirstMatch;\n  ctx.setReturnOnFirstMatch(false);\n  var nodes = this.filter.evaluate(ctx).nodeSetValue();\n  ctx.setReturnOnFirstMatch(flag);\n  \n  var nodes1 = [];\n  if (ctx.returnOnFirstMatch) {\n    for (var i = 0; i < nodes.length; ++i) {\n      nodes1 = this.rel.evaluate(ctx.clone(nodes[i], i, nodes)).nodeSetValue();\n      if (nodes1.length > 0) {\n        break;\n      }\n    }\n    return new NodeSetValue(nodes1);\n  }\n  else {\n    for (var i = 0; i < nodes.length; ++i) {\n      var nodes0 = this.rel.evaluate(ctx.clone(nodes[i], i, nodes)).nodeSetValue();\n      for (var ii = 0; ii < nodes0.length; ++ii) {\n        nodes1.push(nodes0[ii]);\n      }\n    }\n    return new NodeSetValue(nodes1);\n  }\n};\n\nfunction FilterExpr(expr, predicate) {\n  this.expr = expr;\n  this.predicate = predicate;\n}\n\nFilterExpr.prototype.evaluate = function(ctx) {\n  var nodes = this.expr.evaluate(ctx).nodeSetValue();\n  for (var i = 0; i < this.predicate.length; ++i) {\n    var nodes0 = nodes;\n    nodes = [];\n    for (var j = 0; j < nodes0.length; ++j) {\n      var n = nodes0[j];\n      if (this.predicate[i].evaluate(ctx.clone(n, j, nodes0)).booleanValue()) {\n        nodes.push(n);\n      }\n    }\n  }\n\n  return new NodeSetValue(nodes);\n}\n\nfunction UnaryMinusExpr(expr) {\n  this.expr = expr;\n}\n\nUnaryMinusExpr.prototype.evaluate = function(ctx) {\n  return new NumberValue(-this.expr.evaluate(ctx).numberValue());\n};\n\nfunction BinaryExpr(expr1, op, expr2) {\n  this.expr1 = expr1;\n  this.expr2 = expr2;\n  this.op = op;\n}\n\nBinaryExpr.prototype.evaluate = function(ctx) {\n  var ret;\n  switch (this.op.value) {\n    case 'or':\n      ret = new BooleanValue(this.expr1.evaluate(ctx).booleanValue() ||\n                             this.expr2.evaluate(ctx).booleanValue());\n      break;\n\n    case 'and':\n      ret = new BooleanValue(this.expr1.evaluate(ctx).booleanValue() &&\n                             this.expr2.evaluate(ctx).booleanValue());\n      break;\n\n    case '+':\n      ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() +\n                            this.expr2.evaluate(ctx).numberValue());\n      break;\n\n    case '-':\n      ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() -\n                            this.expr2.evaluate(ctx).numberValue());\n      break;\n\n    case '*':\n      ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() *\n                            this.expr2.evaluate(ctx).numberValue());\n      break;\n\n    case 'mod':\n      ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() %\n                            this.expr2.evaluate(ctx).numberValue());\n      break;\n\n    case 'div':\n      ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() /\n                            this.expr2.evaluate(ctx).numberValue());\n      break;\n\n    case '=':\n      ret = this.compare(ctx, function(x1, x2) { return x1 == x2; });\n      break;\n\n    case '!=':\n      ret = this.compare(ctx, function(x1, x2) { return x1 != x2; });\n      break;\n\n    case '<':\n      ret = this.compare(ctx, function(x1, x2) { return x1 < x2; });\n      break;\n\n    case '<=':\n      ret = this.compare(ctx, function(x1, x2) { return x1 <= x2; });\n      break;\n\n    case '>':\n      ret = this.compare(ctx, function(x1, x2) { return x1 > x2; });\n      break;\n\n    case '>=':\n      ret = this.compare(ctx, function(x1, x2) { return x1 >= x2; });\n      break;\n\n    default:\n      alert('BinaryExpr.evaluate: ' + this.op.value);\n  }\n  return ret;\n};\n\nBinaryExpr.prototype.compare = function(ctx, cmp) {\n  var v1 = this.expr1.evaluate(ctx);\n  var v2 = this.expr2.evaluate(ctx);\n\n  var ret;\n  if (v1.type == 'node-set' && v2.type == 'node-set') {\n    var n1 = v1.nodeSetValue();\n    var n2 = v2.nodeSetValue();\n    ret = false;\n    for (var i1 = 0; i1 < n1.length; ++i1) {\n      for (var i2 = 0; i2 < n2.length; ++i2) {\n        if (cmp(xmlValue(n1[i1]), xmlValue(n2[i2]))) {\n          ret = true;\n          // Break outer loop. Labels confuse the jscompiler and we\n          // don't use them.\n          i2 = n2.length;\n          i1 = n1.length;\n        }\n      }\n    }\n\n  } else if (v1.type == 'node-set' || v2.type == 'node-set') {\n\n    if (v1.type == 'number') {\n      var s = v1.numberValue();\n      var n = v2.nodeSetValue();\n\n      ret = false;\n      for (var i = 0;  i < n.length; ++i) {\n        var nn = xmlValue(n[i]) - 0;\n        if (cmp(s, nn)) {\n          ret = true;\n          break;\n        }\n      }\n\n    } else if (v2.type == 'number') {\n      var n = v1.nodeSetValue();\n      var s = v2.numberValue();\n\n      ret = false;\n      for (var i = 0;  i < n.length; ++i) {\n        var nn = xmlValue(n[i]) - 0;\n        if (cmp(nn, s)) {\n          ret = true;\n          break;\n        }\n      }\n\n    } else if (v1.type == 'string') {\n      var s = v1.stringValue();\n      var n = v2.nodeSetValue();\n\n      ret = false;\n      for (var i = 0;  i < n.length; ++i) {\n        var nn = xmlValue(n[i]);\n        if (cmp(s, nn)) {\n          ret = true;\n          break;\n        }\n      }\n\n    } else if (v2.type == 'string') {\n      var n = v1.nodeSetValue();\n      var s = v2.stringValue();\n\n      ret = false;\n      for (var i = 0;  i < n.length; ++i) {\n        var nn = xmlValue(n[i]);\n        if (cmp(nn, s)) {\n          ret = true;\n          break;\n        }\n      }\n\n    } else {\n      ret = cmp(v1.booleanValue(), v2.booleanValue());\n    }\n\n  } else if (v1.type == 'boolean' || v2.type == 'boolean') {\n    ret = cmp(v1.booleanValue(), v2.booleanValue());\n\n  } else if (v1.type == 'number' || v2.type == 'number') {\n    ret = cmp(v1.numberValue(), v2.numberValue());\n\n  } else {\n    ret = cmp(v1.stringValue(), v2.stringValue());\n  }\n\n  return new BooleanValue(ret);\n}\n\nfunction LiteralExpr(value) {\n  this.value = value;\n}\n\nLiteralExpr.prototype.evaluate = function(ctx) {\n  return new StringValue(this.value);\n};\n\nfunction NumberExpr(value) {\n  this.value = value;\n}\n\nNumberExpr.prototype.evaluate = function(ctx) {\n  return new NumberValue(this.value);\n};\n\nfunction VariableExpr(name) {\n  this.name = name;\n}\n\nVariableExpr.prototype.evaluate = function(ctx) {\n  return ctx.getVariable(this.name);\n}\n\n// Factory functions for semantic values (i.e. Expressions) of the\n// productions in the grammar. When a production is matched to reduce\n// the current parse state stack, the function is called with the\n// semantic values of the matched elements as arguments, and returns\n// another semantic value. The semantic value is a node of the parse\n// tree, an expression object with an evaluate() method that evaluates the\n// expression in an actual context. These factory functions are used\n// in the specification of the grammar rules, below.\n\nfunction makeTokenExpr(m) {\n  return new TokenExpr(m);\n}\n\nfunction passExpr(e) {\n  return e;\n}\n\nfunction makeLocationExpr1(slash, rel) {\n  rel.absolute = true;\n  return rel;\n}\n\nfunction makeLocationExpr2(dslash, rel) {\n  rel.absolute = true;\n  rel.prependStep(makeAbbrevStep(dslash.value));\n  return rel;\n}\n\nfunction makeLocationExpr3(slash) {\n  var ret = new LocationExpr();\n  ret.appendStep(makeAbbrevStep('.'));\n  ret.absolute = true;\n  return ret;\n}\n\nfunction makeLocationExpr4(dslash) {\n  var ret = new LocationExpr();\n  ret.absolute = true;\n  ret.appendStep(makeAbbrevStep(dslash.value));\n  return ret;\n}\n\nfunction makeLocationExpr5(step) {\n  var ret = new LocationExpr();\n  ret.appendStep(step);\n  return ret;\n}\n\nfunction makeLocationExpr6(rel, slash, step) {\n  rel.appendStep(step);\n  return rel;\n}\n\nfunction makeLocationExpr7(rel, dslash, step) {\n  rel.appendStep(makeAbbrevStep(dslash.value));\n  rel.appendStep(step);\n  return rel;\n}\n\nfunction makeStepExpr1(dot) {\n  return makeAbbrevStep(dot.value);\n}\n\nfunction makeStepExpr2(ddot) {\n  return makeAbbrevStep(ddot.value);\n}\n\nfunction makeStepExpr3(axisname, axis, nodetest) {\n  return new StepExpr(axisname.value, nodetest);\n}\n\nfunction makeStepExpr4(at, nodetest) {\n  return new StepExpr('attribute', nodetest);\n}\n\nfunction makeStepExpr5(nodetest) {\n  return new StepExpr('child', nodetest);\n}\n\nfunction makeStepExpr6(step, predicate) {\n  step.appendPredicate(predicate);\n  return step;\n}\n\nfunction makeAbbrevStep(abbrev) {\n  switch (abbrev) {\n  case '//':\n    return new StepExpr('descendant-or-self', new NodeTestAny);\n\n  case '.':\n    return new StepExpr('self', new NodeTestAny);\n\n  case '..':\n    return new StepExpr('parent', new NodeTestAny);\n  }\n}\n\nfunction makeNodeTestExpr1(asterisk) {\n  return new NodeTestElementOrAttribute;\n}\n\nfunction makeNodeTestExpr2(ncname, colon, asterisk) {\n  return new NodeTestNC(ncname.value);\n}\n\nfunction makeNodeTestExpr3(qname) {\n  return new NodeTestName(qname.value);\n}\n\nfunction makeNodeTestExpr4(typeo, parenc) {\n  var type = typeo.value.replace(/\\s*\\($/, '');\n  switch(type) {\n  case 'node':\n    return new NodeTestAny;\n\n  case 'text':\n    return new NodeTestText;\n\n  case 'comment':\n    return new NodeTestComment;\n\n  case 'processing-instruction':\n    return new NodeTestPI('');\n  }\n}\n\nfunction makeNodeTestExpr5(typeo, target, parenc) {\n  var type = typeo.replace(/\\s*\\($/, '');\n  if (type != 'processing-instruction') {\n    throw type;\n  }\n  return new NodeTestPI(target.value);\n}\n\nfunction makePredicateExpr(pareno, expr, parenc) {\n  return new PredicateExpr(expr);\n}\n\nfunction makePrimaryExpr(pareno, expr, parenc) {\n  return expr;\n}\n\nfunction makeFunctionCallExpr1(name, pareno, parenc) {\n  return new FunctionCallExpr(name);\n}\n\nfunction makeFunctionCallExpr2(name, pareno, arg1, args, parenc) {\n  var ret = new FunctionCallExpr(name);\n  ret.appendArg(arg1);\n  for (var i = 0; i < args.length; ++i) {\n    ret.appendArg(args[i]);\n  }\n  return ret;\n}\n\nfunction makeArgumentExpr(comma, expr) {\n  return expr;\n}\n\nfunction makeUnionExpr(expr1, pipe, expr2) {\n  return new UnionExpr(expr1, expr2);\n}\n\nfunction makePathExpr1(filter, slash, rel) {\n  return new PathExpr(filter, rel);\n}\n\nfunction makePathExpr2(filter, dslash, rel) {\n  rel.prependStep(makeAbbrevStep(dslash.value));\n  return new PathExpr(filter, rel);\n}\n\nfunction makeFilterExpr(expr, predicates) {\n  if (predicates.length > 0) {\n    return new FilterExpr(expr, predicates);\n  } else {\n    return expr;\n  }\n}\n\nfunction makeUnaryMinusExpr(minus, expr) {\n  return new UnaryMinusExpr(expr);\n}\n\nfunction makeBinaryExpr(expr1, op, expr2) {\n  return new BinaryExpr(expr1, op, expr2);\n}\n\nfunction makeLiteralExpr(token) {\n  // remove quotes from the parsed value:\n  var value = token.value.substring(1, token.value.length - 1);\n  return new LiteralExpr(value);\n}\n\nfunction makeNumberExpr(token) {\n  return new NumberExpr(token.value);\n}\n\nfunction makeVariableReference(dollar, name) {\n  return new VariableExpr(name.value);\n}\n\n// Used before parsing for optimization of common simple cases. See\n// the begin of xpathParse() for which they are.\nfunction makeSimpleExpr(expr) {\n  if (expr.charAt(0) == '$') {\n    return new VariableExpr(expr.substr(1));\n  } else if (expr.charAt(0) == '@') {\n    var a = new NodeTestName(expr.substr(1));\n    var b = new StepExpr('attribute', a);\n    var c = new LocationExpr();\n    c.appendStep(b);\n    return c;\n  } else if (expr.match(/^[0-9]+$/)) {\n    return new NumberExpr(expr);\n  } else {\n    var a = new NodeTestName(expr);\n    var b = new StepExpr('child', a);\n    var c = new LocationExpr();\n    c.appendStep(b);\n    return c;\n  }\n}\n\nfunction makeSimpleExpr2(expr) {\n  var steps = stringSplit(expr, '/');\n  var c = new LocationExpr();\n  for (var i = 0; i < steps.length; ++i) {\n    var a = new NodeTestName(steps[i]);\n    var b = new StepExpr('child', a);\n    c.appendStep(b);\n  }\n  return c;\n}\n\n// The axes of XPath expressions.\n\nvar xpathAxis = {\n  ANCESTOR_OR_SELF: 'ancestor-or-self',\n  ANCESTOR: 'ancestor',\n  ATTRIBUTE: 'attribute',\n  CHILD: 'child',\n  DESCENDANT_OR_SELF: 'descendant-or-self',\n  DESCENDANT: 'descendant',\n  FOLLOWING_SIBLING: 'following-sibling',\n  FOLLOWING: 'following',\n  NAMESPACE: 'namespace',\n  PARENT: 'parent',\n  PRECEDING_SIBLING: 'preceding-sibling',\n  PRECEDING: 'preceding',\n  SELF: 'self'\n};\n\nvar xpathAxesRe = [\n    xpathAxis.ANCESTOR_OR_SELF,\n    xpathAxis.ANCESTOR,\n    xpathAxis.ATTRIBUTE,\n    xpathAxis.CHILD,\n    xpathAxis.DESCENDANT_OR_SELF,\n    xpathAxis.DESCENDANT,\n    xpathAxis.FOLLOWING_SIBLING,\n    xpathAxis.FOLLOWING,\n    xpathAxis.NAMESPACE,\n    xpathAxis.PARENT,\n    xpathAxis.PRECEDING_SIBLING,\n    xpathAxis.PRECEDING,\n    xpathAxis.SELF\n].join('|');\n\n\n// The tokens of the language. The label property is just used for\n// generating debug output. The prec property is the precedence used\n// for shift/reduce resolution. Default precedence is 0 as a lookahead\n// token and 2 on the stack. TODO(mesch): this is certainly not\n// necessary and too complicated. Simplify this!\n\n// NOTE: tabular formatting is the big exception, but here it should\n// be OK.\n\nvar TOK_PIPE =   { label: \"|\",   prec:   17, re: new RegExp(\"^\\\\|\") };\nvar TOK_DSLASH = { label: \"//\",  prec:   19, re: new RegExp(\"^//\")  };\nvar TOK_SLASH =  { label: \"/\",   prec:   30, re: new RegExp(\"^/\")   };\nvar TOK_AXIS =   { label: \"::\",  prec:   20, re: new RegExp(\"^::\")  };\nvar TOK_COLON =  { label: \":\",   prec: 1000, re: new RegExp(\"^:\")  };\nvar TOK_AXISNAME = { label: \"[axis]\", re: new RegExp('^(' + xpathAxesRe + ')') };\nvar TOK_PARENO = { label: \"(\",   prec:   34, re: new RegExp(\"^\\\\(\") };\nvar TOK_PARENC = { label: \")\",               re: new RegExp(\"^\\\\)\") };\nvar TOK_DDOT =   { label: \"..\",  prec:   34, re: new RegExp(\"^\\\\.\\\\.\") };\nvar TOK_DOT =    { label: \".\",   prec:   34, re: new RegExp(\"^\\\\.\") };\nvar TOK_AT =     { label: \"@\",   prec:   34, re: new RegExp(\"^@\")   };\n\nvar TOK_COMMA =  { label: \",\",               re: new RegExp(\"^,\") };\n\nvar TOK_OR =     { label: \"or\",  prec:   10, re: new RegExp(\"^or\\\\b\") };\nvar TOK_AND =    { label: \"and\", prec:   11, re: new RegExp(\"^and\\\\b\") };\nvar TOK_EQ =     { label: \"=\",   prec:   12, re: new RegExp(\"^=\")   };\nvar TOK_NEQ =    { label: \"!=\",  prec:   12, re: new RegExp(\"^!=\")  };\nvar TOK_GE =     { label: \">=\",  prec:   13, re: new RegExp(\"^>=\")  };\nvar TOK_GT =     { label: \">\",   prec:   13, re: new RegExp(\"^>\")   };\nvar TOK_LE =     { label: \"<=\",  prec:   13, re: new RegExp(\"^<=\")  };\nvar TOK_LT =     { label: \"<\",   prec:   13, re: new RegExp(\"^<\")   };\nvar TOK_PLUS =   { label: \"+\",   prec:   14, re: new RegExp(\"^\\\\+\"), left: true };\nvar TOK_MINUS =  { label: \"-\",   prec:   14, re: new RegExp(\"^\\\\-\"), left: true };\nvar TOK_DIV =    { label: \"div\", prec:   15, re: new RegExp(\"^div\\\\b\"), left: true };\nvar TOK_MOD =    { label: \"mod\", prec:   15, re: new RegExp(\"^mod\\\\b\"), left: true };\n\nvar TOK_BRACKO = { label: \"[\",   prec:   32, re: new RegExp(\"^\\\\[\") };\nvar TOK_BRACKC = { label: \"]\",               re: new RegExp(\"^\\\\]\") };\nvar TOK_DOLLAR = { label: \"$\",               re: new RegExp(\"^\\\\$\") };\n\nvar TOK_NCNAME = { label: \"[ncname]\", re: new RegExp('^' + XML_NC_NAME) };\n\nvar TOK_ASTERISK = { label: \"*\", prec: 15, re: new RegExp(\"^\\\\*\"), left: true };\nvar TOK_LITERALQ = { label: \"[litq]\", prec: 20, re: new RegExp(\"^'[^\\\\']*'\") };\nvar TOK_LITERALQQ = {\n  label: \"[litqq]\",\n  prec: 20,\n  re: new RegExp('^\"[^\\\\\"]*\"')\n};\n\nvar TOK_NUMBER  = {\n  label: \"[number]\",\n  prec: 35,\n  re: new RegExp('^\\\\d+(\\\\.\\\\d*)?') };\n\nvar TOK_QNAME = {\n  label: \"[qname]\",\n  re: new RegExp('^(' + XML_NC_NAME + ':)?' + XML_NC_NAME)\n};\n\nvar TOK_NODEO = {\n  label: \"[nodetest-start]\",\n  re: new RegExp('^(processing-instruction|comment|text|node)\\\\(')\n};\n\n// The table of the tokens of our grammar, used by the lexer: first\n// column the tag, second column a regexp to recognize it in the\n// input, third column the precedence of the token, fourth column a\n// factory function for the semantic value of the token.\n//\n// NOTE: order of this list is important, because the first match\n// counts. Cf. DDOT and DOT, and AXIS and COLON.\n\nvar xpathTokenRules = [\n    TOK_DSLASH,\n    TOK_SLASH,\n    TOK_DDOT,\n    TOK_DOT,\n    TOK_AXIS,\n    TOK_COLON,\n    TOK_AXISNAME,\n    TOK_NODEO,\n    TOK_PARENO,\n    TOK_PARENC,\n    TOK_BRACKO,\n    TOK_BRACKC,\n    TOK_AT,\n    TOK_COMMA,\n    TOK_OR,\n    TOK_AND,\n    TOK_NEQ,\n    TOK_EQ,\n    TOK_GE,\n    TOK_GT,\n    TOK_LE,\n    TOK_LT,\n    TOK_PLUS,\n    TOK_MINUS,\n    TOK_ASTERISK,\n    TOK_PIPE,\n    TOK_MOD,\n    TOK_DIV,\n    TOK_LITERALQ,\n    TOK_LITERALQQ,\n    TOK_NUMBER,\n    TOK_QNAME,\n    TOK_NCNAME,\n    TOK_DOLLAR\n];\n\n// All the nonterminals of the grammar. The nonterminal objects are\n// identified by object identity; the labels are used in the debug\n// output only.\nvar XPathLocationPath = { label: \"LocationPath\" };\nvar XPathRelativeLocationPath = { label: \"RelativeLocationPath\" };\nvar XPathAbsoluteLocationPath = { label: \"AbsoluteLocationPath\" };\nvar XPathStep = { label: \"Step\" };\nvar XPathNodeTest = { label: \"NodeTest\" };\nvar XPathPredicate = { label: \"Predicate\" };\nvar XPathLiteral = { label: \"Literal\" };\nvar XPathExpr = { label: \"Expr\" };\nvar XPathPrimaryExpr = { label: \"PrimaryExpr\" };\nvar XPathVariableReference = { label: \"Variablereference\" };\nvar XPathNumber = { label: \"Number\" };\nvar XPathFunctionCall = { label: \"FunctionCall\" };\nvar XPathArgumentRemainder = { label: \"ArgumentRemainder\" };\nvar XPathPathExpr = { label: \"PathExpr\" };\nvar XPathUnionExpr = { label: \"UnionExpr\" };\nvar XPathFilterExpr = { label: \"FilterExpr\" };\nvar XPathDigits = { label: \"Digits\" };\n\nvar xpathNonTerminals = [\n    XPathLocationPath,\n    XPathRelativeLocationPath,\n    XPathAbsoluteLocationPath,\n    XPathStep,\n    XPathNodeTest,\n    XPathPredicate,\n    XPathLiteral,\n    XPathExpr,\n    XPathPrimaryExpr,\n    XPathVariableReference,\n    XPathNumber,\n    XPathFunctionCall,\n    XPathArgumentRemainder,\n    XPathPathExpr,\n    XPathUnionExpr,\n    XPathFilterExpr,\n    XPathDigits\n];\n\n// Quantifiers that are used in the productions of the grammar.\nvar Q_01 = { label: \"?\" };\nvar Q_MM = { label: \"*\" };\nvar Q_1M = { label: \"+\" };\n\n// Tag for left associativity (right assoc is implied by undefined).\nvar ASSOC_LEFT = true;\n\n// The productions of the grammar. Columns of the table:\n//\n// - target nonterminal,\n// - pattern,\n// - precedence,\n// - semantic value factory\n//\n// The semantic value factory is a function that receives parse tree\n// nodes from the stack frames of the matched symbols as arguments and\n// returns an a node of the parse tree. The node is stored in the top\n// stack frame along with the target object of the rule. The node in\n// the parse tree is an expression object that has an evaluate() method\n// and thus evaluates XPath expressions.\n//\n// The precedence is used to decide between reducing and shifting by\n// comparing the precendence of the rule that is candidate for\n// reducing with the precedence of the look ahead token. Precedence of\n// -1 means that the precedence of the tokens in the pattern is used\n// instead. TODO: It shouldn't be necessary to explicitly assign\n// precedences to rules.\n\n// DGF As it stands, these precedences are purely empirical; we're\n// not sure they can be made to be consistent at all.\n\nvar xpathGrammarRules =\n  [\n   [ XPathLocationPath, [ XPathRelativeLocationPath ], 18,\n     passExpr ],\n   [ XPathLocationPath, [ XPathAbsoluteLocationPath ], 18,\n     passExpr ],\n\n   [ XPathAbsoluteLocationPath, [ TOK_SLASH, XPathRelativeLocationPath ], 18,\n     makeLocationExpr1 ],\n   [ XPathAbsoluteLocationPath, [ TOK_DSLASH, XPathRelativeLocationPath ], 18,\n     makeLocationExpr2 ],\n\n   [ XPathAbsoluteLocationPath, [ TOK_SLASH ], 0,\n     makeLocationExpr3 ],\n   [ XPathAbsoluteLocationPath, [ TOK_DSLASH ], 0,\n     makeLocationExpr4 ],\n\n   [ XPathRelativeLocationPath, [ XPathStep ], 31,\n     makeLocationExpr5 ],\n   [ XPathRelativeLocationPath,\n     [ XPathRelativeLocationPath, TOK_SLASH, XPathStep ], 31,\n     makeLocationExpr6 ],\n   [ XPathRelativeLocationPath,\n     [ XPathRelativeLocationPath, TOK_DSLASH, XPathStep ], 31,\n     makeLocationExpr7 ],\n\n   [ XPathStep, [ TOK_DOT ], 33,\n     makeStepExpr1 ],\n   [ XPathStep, [ TOK_DDOT ], 33,\n     makeStepExpr2 ],\n   [ XPathStep,\n     [ TOK_AXISNAME, TOK_AXIS, XPathNodeTest ], 33,\n     makeStepExpr3 ],\n   [ XPathStep, [ TOK_AT, XPathNodeTest ], 33,\n     makeStepExpr4 ],\n   [ XPathStep, [ XPathNodeTest ], 33,\n     makeStepExpr5 ],\n   [ XPathStep, [ XPathStep, XPathPredicate ], 33,\n     makeStepExpr6 ],\n\n   [ XPathNodeTest, [ TOK_ASTERISK ], 33,\n     makeNodeTestExpr1 ],\n   [ XPathNodeTest, [ TOK_NCNAME, TOK_COLON, TOK_ASTERISK ], 33,\n     makeNodeTestExpr2 ],\n   [ XPathNodeTest, [ TOK_QNAME ], 33,\n     makeNodeTestExpr3 ],\n   [ XPathNodeTest, [ TOK_NODEO, TOK_PARENC ], 33,\n     makeNodeTestExpr4 ],\n   [ XPathNodeTest, [ TOK_NODEO, XPathLiteral, TOK_PARENC ], 33,\n     makeNodeTestExpr5 ],\n\n   [ XPathPredicate, [ TOK_BRACKO, XPathExpr, TOK_BRACKC ], 33,\n     makePredicateExpr ],\n\n   [ XPathPrimaryExpr, [ XPathVariableReference ], 33,\n     passExpr ],\n   [ XPathPrimaryExpr, [ TOK_PARENO, XPathExpr, TOK_PARENC ], 33,\n     makePrimaryExpr ],\n   [ XPathPrimaryExpr, [ XPathLiteral ], 30,\n     passExpr ],\n   [ XPathPrimaryExpr, [ XPathNumber ], 30,\n     passExpr ],\n   [ XPathPrimaryExpr, [ XPathFunctionCall ], 31,\n     passExpr ],\n\n   [ XPathFunctionCall, [ TOK_QNAME, TOK_PARENO, TOK_PARENC ], -1,\n     makeFunctionCallExpr1 ],\n   [ XPathFunctionCall,\n     [ TOK_QNAME, TOK_PARENO, XPathExpr, XPathArgumentRemainder, Q_MM,\n       TOK_PARENC ], -1,\n     makeFunctionCallExpr2 ],\n   [ XPathArgumentRemainder, [ TOK_COMMA, XPathExpr ], -1,\n     makeArgumentExpr ],\n\n   [ XPathUnionExpr, [ XPathPathExpr ], 20,\n     passExpr ],\n   [ XPathUnionExpr, [ XPathUnionExpr, TOK_PIPE, XPathPathExpr ], 20,\n     makeUnionExpr ],\n\n   [ XPathPathExpr, [ XPathLocationPath ], 20,\n     passExpr ],\n   [ XPathPathExpr, [ XPathFilterExpr ], 19,\n     passExpr ],\n   [ XPathPathExpr,\n     [ XPathFilterExpr, TOK_SLASH, XPathRelativeLocationPath ], 19,\n     makePathExpr1 ],\n   [ XPathPathExpr,\n     [ XPathFilterExpr, TOK_DSLASH, XPathRelativeLocationPath ], 19,\n     makePathExpr2 ],\n\n   [ XPathFilterExpr, [ XPathPrimaryExpr, XPathPredicate, Q_MM ], 31,\n     makeFilterExpr ],\n\n   [ XPathExpr, [ XPathPrimaryExpr ], 16,\n     passExpr ],\n   [ XPathExpr, [ XPathUnionExpr ], 16,\n     passExpr ],\n\n   [ XPathExpr, [ TOK_MINUS, XPathExpr ], -1,\n     makeUnaryMinusExpr ],\n\n   [ XPathExpr, [ XPathExpr, TOK_OR, XPathExpr ], -1,\n     makeBinaryExpr ],\n   [ XPathExpr, [ XPathExpr, TOK_AND, XPathExpr ], -1,\n     makeBinaryExpr ],\n\n   [ XPathExpr, [ XPathExpr, TOK_EQ, XPathExpr ], -1,\n     makeBinaryExpr ],\n   [ XPathExpr, [ XPathExpr, TOK_NEQ, XPathExpr ], -1,\n     makeBinaryExpr ],\n\n   [ XPathExpr, [ XPathExpr, TOK_LT, XPathExpr ], -1,\n     makeBinaryExpr ],\n   [ XPathExpr, [ XPathExpr, TOK_LE, XPathExpr ], -1,\n     makeBinaryExpr ],\n   [ XPathExpr, [ XPathExpr, TOK_GT, XPathExpr ], -1,\n     makeBinaryExpr ],\n   [ XPathExpr, [ XPathExpr, TOK_GE, XPathExpr ], -1,\n     makeBinaryExpr ],\n\n   [ XPathExpr, [ XPathExpr, TOK_PLUS, XPathExpr ], -1,\n     makeBinaryExpr, ASSOC_LEFT ],\n   [ XPathExpr, [ XPathExpr, TOK_MINUS, XPathExpr ], -1,\n     makeBinaryExpr, ASSOC_LEFT ],\n\n   [ XPathExpr, [ XPathExpr, TOK_ASTERISK, XPathExpr ], -1,\n     makeBinaryExpr, ASSOC_LEFT ],\n   [ XPathExpr, [ XPathExpr, TOK_DIV, XPathExpr ], -1,\n     makeBinaryExpr, ASSOC_LEFT ],\n   [ XPathExpr, [ XPathExpr, TOK_MOD, XPathExpr ], -1,\n     makeBinaryExpr, ASSOC_LEFT ],\n\n   [ XPathLiteral, [ TOK_LITERALQ ], -1,\n     makeLiteralExpr ],\n   [ XPathLiteral, [ TOK_LITERALQQ ], -1,\n     makeLiteralExpr ],\n\n   [ XPathNumber, [ TOK_NUMBER ], -1,\n     makeNumberExpr ],\n\n   [ XPathVariableReference, [ TOK_DOLLAR, TOK_QNAME ], 200,\n     makeVariableReference ]\n   ];\n\n// That function computes some optimizations of the above data\n// structures and will be called right here. It merely takes the\n// counter variables out of the global scope.\n\nvar xpathRules = [];\n\nfunction xpathParseInit() {\n  if (xpathRules.length) {\n    return;\n  }\n\n  // Some simple optimizations for the xpath expression parser: sort\n  // grammar rules descending by length, so that the longest match is\n  // first found.\n\n  xpathGrammarRules.sort(function(a,b) {\n    var la = a[1].length;\n    var lb = b[1].length;\n    if (la < lb) {\n      return 1;\n    } else if (la > lb) {\n      return -1;\n    } else {\n      return 0;\n    }\n  });\n\n  var k = 1;\n  for (var i = 0; i < xpathNonTerminals.length; ++i) {\n    xpathNonTerminals[i].key = k++;\n  }\n\n  for (i = 0; i < xpathTokenRules.length; ++i) {\n    xpathTokenRules[i].key = k++;\n  }\n\n  xpathLog('XPath parse INIT: ' + k + ' rules');\n\n  // Another slight optimization: sort the rules into bins according\n  // to the last element (observing quantifiers), so we can restrict\n  // the match against the stack to the subest of rules that match the\n  // top of the stack.\n  //\n  // TODO(mesch): What we actually want is to compute states as in\n  // bison, so that we don't have to do any explicit and iterated\n  // match against the stack.\n\n  function push_(array, position, element) {\n    if (!array[position]) {\n      array[position] = [];\n    }\n    array[position].push(element);\n  }\n\n  for (i = 0; i < xpathGrammarRules.length; ++i) {\n    var rule = xpathGrammarRules[i];\n    var pattern = rule[1];\n\n    for (var j = pattern.length - 1; j >= 0; --j) {\n      if (pattern[j] == Q_1M) {\n        push_(xpathRules, pattern[j-1].key, rule);\n        break;\n\n      } else if (pattern[j] == Q_MM || pattern[j] == Q_01) {\n        push_(xpathRules, pattern[j-1].key, rule);\n        --j;\n\n      } else {\n        push_(xpathRules, pattern[j].key, rule);\n        break;\n      }\n    }\n  }\n\n  xpathLog('XPath parse INIT: ' + xpathRules.length + ' rule bins');\n\n  var sum = 0;\n  mapExec(xpathRules, function(i) {\n    if (i) {\n      sum += i.length;\n    }\n  });\n\n  xpathLog('XPath parse INIT: ' + (sum / xpathRules.length) +\n           ' average bin size');\n}\n\n// Local utility functions that are used by the lexer or parser.\n\nfunction xpathCollectDescendants(nodelist, node, opt_tagName) {\n  if (opt_tagName && node.getElementsByTagName) {\n    copyArray(nodelist, node.getElementsByTagName(opt_tagName));\n    return;\n  }\n  for (var n = node.firstChild; n; n = n.nextSibling) {\n    nodelist.push(n);\n    xpathCollectDescendants(nodelist, n);\n  }\n}\n\n// DGF extract a tag name suitable for getElementsByTagName\nfunction xpathExtractTagNameFromNodeTest(nodetest) {\n  if (nodetest instanceof NodeTestName) {\n    return nodetest.name;\n  } else if (/* nodetest instanceof NodeTestAny || */ nodetest instanceof NodeTestElementOrAttribute) {\n    // HBC - commented out the NodeTestAny in the above condition; it causes\n    // non-element nodes to be excluded! The XPath spec says \"node()\" must\n    // match all node types.\n    return \"*\";\n  }\n}\n\nfunction xpathCollectDescendantsReverse(nodelist, node) {\n  for (var n = node.lastChild; n; n = n.previousSibling) {\n    nodelist.push(n);\n    xpathCollectDescendantsReverse(nodelist, n);\n  }\n}\n\n\n// The entry point for the library: match an expression against a DOM\n// node. Returns an XPath value.\nfunction xpathDomEval(expr, node) {\n  var expr1 = xpathParse(expr);\n  var ret = expr1.evaluate(new ExprContext(node));\n  return ret;\n}\n\n// Utility function to sort a list of nodes. Used by xsltSort() and\n// nxslSelect().\nfunction xpathSort(input, sort) {\n  if (sort.length == 0) {\n    return;\n  }\n\n  var sortlist = [];\n\n  for (var i = 0; i < input.contextSize(); ++i) {\n    var node = input.nodelist[i];\n    var sortitem = { node: node, key: [] };\n    var context = input.clone(node, 0, [ node ]);\n\n    for (var j = 0; j < sort.length; ++j) {\n      var s = sort[j];\n      var value = s.expr.evaluate(context);\n\n      var evalue;\n      if (s.type == 'text') {\n        evalue = value.stringValue();\n      } else if (s.type == 'number') {\n        evalue = value.numberValue();\n      }\n      sortitem.key.push({ value: evalue, order: s.order });\n    }\n\n    // Make the sort stable by adding a lowest priority sort by\n    // id. This is very convenient and furthermore required by the\n    // spec ([XSLT] - Section 10 Sorting).\n    sortitem.key.push({ value: i, order: 'ascending' });\n\n    sortlist.push(sortitem);\n  }\n\n  sortlist.sort(xpathSortByKey);\n\n  var nodes = [];\n  for (var i = 0; i < sortlist.length; ++i) {\n    nodes.push(sortlist[i].node);\n  }\n  input.nodelist = nodes;\n  input.setNode(0);\n}\n\n\n// Sorts by all order criteria defined. According to the JavaScript\n// spec ([ECMA] Section 11.8.5), the compare operators compare strings\n// as strings and numbers as numbers.\n//\n// NOTE: In browsers which do not follow the spec, this breaks only in\n// the case that numbers should be sorted as strings, which is very\n// uncommon.\nfunction xpathSortByKey(v1, v2) {\n  // NOTE: Sort key vectors of different length never occur in\n  // xsltSort.\n\n  for (var i = 0; i < v1.key.length; ++i) {\n    var o = v1.key[i].order == 'descending' ? -1 : 1;\n    if (v1.key[i].value > v2.key[i].value) {\n      return +1 * o;\n    } else if (v1.key[i].value < v2.key[i].value) {\n      return -1 * o;\n    }\n  }\n\n  return 0;\n}\n\n\n// Parses and then evaluates the given XPath expression in the given\n// input context. Notice that parsed xpath expressions are cached.\nfunction xpathEval(select, context) {\n  var expr = xpathParse(select);\n  var ret = expr.evaluate(context);\n  return ret;\n}\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/selenium.yml",
    "content": "# Please read as our directions have changed:\n# Move this file to your rails apps config directory and rename it to selenium.yml in order to configure the plugin\n\n#\n# General settings\n#\n\nenvironments:\n  - test\n#  - development # Uncomment this line to enable in development environment. N.B. your development database will likely be altered/destroyed/abducted\n\n#selenium_path: 'c:\\selenium' #path to selenium installation. only needed if you for some reason don't want to use the bundled version of selenium core\n\n#\n# rake test:acceptance settings\n#\n\nbrowsers:\n  # Windows\n  # firefox: 'c:\\Program Files\\Mozilla Firefox\\firefox.exe'\n  # ie: 'c:\\Program Files\\Internet Explorer\\iexplore.exe'\n\n  # Mac OS X\n  firefox: '/Applications/Firefox.app/Contents/MacOS/firefox-bin'\n  safari: '/Applications/Safari.app/Contents/MacOS/Safari'\n\n#host: 'localhost'\n#port_start: 3000\n#port_end: 3005\n#base_url_path: '/'\n#max_browser_duration: 120\n#multi_window: false\n  \n#result_dir: 'c:\\result' # the directory where the results will be stored after a test:acceptance run\n\n#fixtures_path: <%= \"#{RAILS_ROOT}/spec/fixtures\" %>\n#selenium_tests_path: <%= \"#{RAILS_ROOT}/spec/selenium\" %>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/fixtures/config.yml",
    "content": "# Please read as our directions have changed:\n# Move this file to your rails apps config directory and rename it to selenium.yml in order to configure the plugin\n\n#\n# General settings\n#\n\nenvironments:\n  - test\n#  - development # Uncomment this line to enable in development environment. N.B. your development database will likely be altered/destroyed/abducted\n\n#selenium_path: 'c:\\selenium' #path to selenium installation. only needed if you for some reason don't want to use the bundled version of selenium core\n\n#\n# rake test:acceptance settings\n#\n\nbrowsers:\n  # Windows\n  # firefox: 'c:\\Program Files\\Mozilla Firefox\\firefox.exe'\n  # ie: 'c:\\Program Files\\Internet Explorer\\iexplore.exe'\n\n  # Mac OS X\n  firefox: '/Applications/Firefox.app/Contents/MacOS/firefox-bin'\n  safari: '/Applications/Safari.app/Contents/MacOS/Safari'\n\n#host: 'localhost'\n#port_start: 3000\n#port_end: 3005\n#base_url_path: '/'\n#max_browser_duration: 120\n#multi_window: false\n  \n#result_dir: 'c:\\result' # the directory where the results will be stored after a test:acceptance run\n\n#fixtures_path: <%= \"#{RAILS_ROOT}/spec/fixtures\" %>\n#selenium_tests_path: <%= \"#{RAILS_ROOT}/spec/selenium\" %>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/fixtures/selenium.yml",
    "content": "# Move this file to your rails apps config directory and rename it to selenium.yml in order to configure the plugin\n\n#\n# General settings\n#\n\nenvironments:\n  - test_cache\n#  - development # Uncomment this line to enable in development environment. N.B. your development database will likely be altered/destroyed/abducted\n\n#selenium_path: 'c:\\selenium' #path to selenium installation. only needed if you for some reason don't want to use the bundled version of selenium core\n\n#\n# rake test:acceptance settings\n#\n\nbrowsers:\n  firefox: 'script/openfirefox'\n  # safari: '/Applications/Safari.app/Contents/MacOS/Safari'\n\nport_start: 4000\nport_end: 4001\n#base_url_path: '/'\n#max_browser_duration: 120\n#multi_window: false\n  \n#result_dir: 'c:\\result' # the directory where the results will be stored after a test:acceptance run\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/paths_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\nrequire 'mocha'\nRAILS_ROOT = File.expand_path(File.dirname(__FILE__) + \"/\")\n\nclass SeleniumOnRails::PathsTest < Test::Unit::TestCase\n  \n  include SeleniumOnRails::Paths\n  \n  def test_selenium_tests_path_when_config_has_not_selenium_tests_path\n    SeleniumOnRailsConfig.expects(:get).with(\"selenium_tests_path\").returns(nil)\n    assert_equal \"#{RAILS_ROOT}/test/selenium\", selenium_tests_path\n  end\n  \n  def test_selenium_tests_path_when_config_has_selenium_tests_path\n    SeleniumOnRailsConfig.expects(:get).with(\"selenium_tests_path\").returns(\"path\").at_least_once\n    assert_equal \"path\", selenium_tests_path\n  end\n  \n  def test_fixtures_path_when_config_has_not_fixtures_path\n    SeleniumOnRailsConfig.expects(:get).with(\"fixtures_path\").returns(nil)\n    assert_equal \"#{RAILS_ROOT}/test/fixtures\", fixtures_path\n  end\n  \n  def test_fixtures_path_when_config_has_fixtures_path\n    SeleniumOnRailsConfig.expects(:get).with(\"fixtures_path\").returns(\"path\").at_least_once\n    assert_equal \"path\", fixtures_path\n  end\n  \n  def test_view_path\n    assert_equal File.expand_path(\"#{RAILS_ROOT}/../lib/views/my_view\"), view_path('my_view')\n  end\n  \n  def test_layout_path\n    assert_equal \"layout.rhtml\", layout_path\n  end\n  \n  def test_skip_file_when_file_contain_CVS\n    assert skip_file?(\"file/with/CVS/in/the/middle/of/path\")\n  end\n\n  def test_skip_file_when_file_contain_dot\n    assert skip_file?(\"file/with/./(dot)/in/the/middle/of/path\")\n  end\n\n  def test_skip_file_when_file_contain_underline\n    assert skip_file?(\"file/with/_underline/in/the/middle/of/path\")\n  end\n  \n  def test_skip_file_when_file_contain_accent_mark\n    assert skip_file?(\"file/with/mark~/in/the/middle/of/path\")\n  end\n\n  def test_skip_file_when_file_does_not_have_any_reason_to_skip\n    assert !skip_file?(\"my/valid/file\")\n  end\n  \n  def test_selenium_path\n    assert_equal File.expand_path(\"#{RAILS_ROOT}/../selenium-core\") + \"/\", selenium_path\n  end\n\n  def test_selenium_path_when_selenium_core_installation_is_not_found\n    selenium_core_path = File.expand_path(File.dirname(__FILE__) + \"/../selenium-core\")\n    \n    File.expects(:exist?).with(\"#{selenium_core_path}/core/TestRunner.html\").returns(false)\n    File.expects(:exist?).with(\"#{selenium_core_path}/selenium/TestRunner.html\").returns(false)\n    File.expects(:exist?).with(\"#{selenium_core_path}/javascript/TestRunner.html\").returns(false)\n    File.expects(:exist?).with(\"#{selenium_core_path}/TestRunner.html\").returns(false)\n    @@selenium_path = nil\n    assert_raise(RuntimeError) { selenium_path }\n  end\n  \nend"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/renderer_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\n\nclass RendererTest < Test::Unit::TestCase\n  def setup\n    SeleniumOnRails::PartialsSupport.send(:include, SeleniumOnRails::PathsTestHelper)\n    @controller = SeleniumController.new\n    @controller.extend(SeleniumOnRails::PathsTestHelper)\n    ActionController::Routing::Routes.draw\n    @request    = ActionController::TestRequest.new\n    @response   = ActionController::TestResponse.new\n    @controller.layout_override =<<END\n<html><head><title>test layout</title></head><body>\n@content_for_layout\n</body></html>\nEND\n  end\n\n  def test_route\n    get :test_file, :testname => 'html.html' #initialize the controller\n    assert_equal 'http://test.host/selenium/tests/suite%2Ftest_case.sel', \n        @controller.url_for(:controller => 'selenium', :action => 'test_file', :testname => 'suite/test_case.sel')\n  end\n  \n  def test_html\n    expected =<<END\n<html><head><title>test layout</title></head><body>\n<p>Testing plain HTML</p>\n<table>\n  <tr><th colspan=\"3\">Test HTML</th></tr>\n  <tr><td>open</td><td>/selenium/setup</td><td>&nbsp;</td></tr>\n</table>\n<p>and it works...</p>\n</body></html>\nEND\n    File.open(test_path_for('html.html'), 'w+') { |index_file| index_file << expected }\n    get :test_file, :testname => 'html.html'\n    assert_headers\n    \n    assert_text_equal expected, @response.body\n  end\n  \n  def test_path_for(name)\n    \"#{File.expand_path(File.dirname(__FILE__) + \"/../test_data\")}/#{name}\"\n  end\n    \n  def test_rhtml\n    get :test_file, :testname => 'rhtml.rhtml'\n    assert_headers\n    expected =<<END\n<html><head><title>test layout</title></head><body>\n<table>\n  <tr><th colspan=\"3\">Rhtml</th></tr>\n  <tr><td>open</td><td>/fi</td><td>&nbsp;</td></tr>\n  <tr><td>open</td><td>/fo</td><td>&nbsp;</td></tr>\n  <tr><td>open</td><td>/fum</td><td>&nbsp;</td></tr>\n  <tr><td>assertTitle</td><td>Partial from RHTML</td><td>&nbsp;</td></tr>\n</table>\n</body></html>\nEND\n    assert_text_equal expected, @response.body\n  end\n  \n  def test_selenese\n    get :test_file, :testname => 'selenese.sel'\n    \n    assert_headers\n    expected =<<END\n<html><head><title>test layout</title></head><body>\n<p>Selenese <strong>support</strong></p>\n<table>\n<tr><th colspan=\"3\">Selenese</th></tr>\n<tr><td>open</td><td>/selenium/setup</td><td>&nbsp;</td></tr>\n<tr><td>goBack</td><td>&nbsp;</td><td>&nbsp;</td></tr>\n<tr><td>assertTitle</td><td>Partial from Selenese</td><td>&nbsp;</td></tr>\n</table>\n<p>works.</p>\n\n</body></html>\nEND\n    assert_text_equal expected, @response.body\n  end\n  \n  def test_rselenese\n    get :test_file, :testname => 'rselenese.rsel'\n    assert_headers\n    expected = <<END\n<html><head><title>test layout</title></head><body>\n<table>\n  <tr><th colspan=\"3\">Rselenese</th></tr>\n  <tr><td>open</td><td>/selenium/setup</td><td>&nbsp;</td></tr>\n  <tr><td>open</td><td>/selenium/setup?keep_session=true</td><td>&nbsp;</td></tr>\n  <tr><td>open</td><td>/selenium/setup?fixtures=all</td><td>&nbsp;</td></tr>\n  <tr><td>open</td><td>/selenium/setup?fixtures=foo%2Cbar</td><td>&nbsp;</td></tr>\n  <tr><td>open</td><td>/selenium/setup?clear_tables=foo%2Cbar&amp;amp;fixtures=all</td><td>&nbsp;</td></tr>\n  <tr><td>assertAbsoluteLocation</td><td>exact:http://test.host/selenium/setup</td><td>&nbsp;</td></tr>\n  <tr><td>assertTitle</td><td>selenium</td><td>&nbsp;</td></tr>\n  <tr><td>assertTitle</td><td>Partial from RSelenese</td><td>&nbsp;</td></tr>\n</table>\n</body></html>\nEND\n    assert_text_equal expected, @response.body\n  end\n  \n  def test_partial_support\n    get :test_file, :testname => 'partials/all_partials.rsel'\n    assert_headers\n    expected = <<END\n<html><head><title>test layout</title></head><body>\n<table>\n  <tr><th colspan=\"3\">All partials</th></tr>\n  <tr><td>assertTitle</td><td>Partial from All partials</td><td>&nbsp;</td></tr>\n  <tr><td>type</td><td>partial</td><td>HTML partial</td></tr>\n  <tr><td>type</td><td>world</td><td>RHTML partial</td></tr>\n  <tr><td>type</td><td>partial</td><td>Selenese partial</td></tr>\n  <tr><td>type</td><td>world</td><td>RSelenese partial</td></tr>\n  <tr><td>type</td><td>nesting</td><td>Nesting partial</td></tr>\n  <tr><td>type</td><td>dlrow</td><td>RSelenese partial</td></tr>\n</table>\n</body></html>\nEND\n    assert_text_equal expected, @response.body\n  end\n\n  def test_own_layout\n    get :test_file, :testname => 'own_layout.html'\n    assert_headers\n    expected =<<END\n<html>\n  <head>\n    <title>Test case with own layout</title>\n    <style type=\"text/css\"> body { background-color: #ccc; } </style>\n  </head>\n  <body>\n    <table>\n      <tr><th colspan=\"3\">Test own layout</th></tr>\n      <tr><td>open</td><td>/selenium/setup</td><td>&nbsp;</td></tr>\n    </table>\n  </body>\n</html>\nEND\n    assert_text_equal expected, @response.body\n  end\n  \n  def test_not_found\n    get :test_file, :testname => 'missing'\n    assert_response 404\n    assert_equal 'Not found', @response.body\n  end\n  \n  def assert_headers\n    assert_response :success\n    assert_equal 'no-cache', @response.headers['Cache-control']\n    assert_equal 'no-cache', @response.headers['Pragma']\n    assert_equal '-1', @response.headers['Expires']\n  end\n   \nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/rselenese_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\n\nclass RSeleneseTest < Test::Unit::TestCase\n  include ERB::Util\n  \n  # All this is exactly the same as selenese - with an r in front of it.  How do I kill the duplication\n  \n  def render_rselenese(page_title, input)\n    create_rsel_file_from(input, \"html.rsel\")\n    \n    @view = TestView.new\n    @view.extend(SeleniumOnRails::PathsTestHelper)\n    @sel = SeleniumOnRails::RSelenese.new(@view) \n    @sel.render ActionView::Template.new(test_path_for(\"html.rsel\")), {'page_title' => page_title}\n  end\n  \n  def create_rsel_file_from(input, name)\n    File.open(test_path_for(name), 'w+') { |index_file| index_file << input }\n  end\n  \n  def test_path_for(name)\n    \"#{File.expand_path(File.dirname(__FILE__) + \"/../test_data\")}/#{name}\"\n  end\n   \n  def assert_rselenese expected, name, input\n    assert_text_equal expected, render_rselenese(name, input)\n  end\n  \n  def test_empty\n    expected = <<END\n<table>\n<tr><th colspan=\"3\">Empty</th></tr>\n</table>\nEND\n    input = ''\n    assert_rselenese expected, 'Empty', input\n  end\n\n  def assert_generates_command expected, name, *args\n    expected = expected.map {|v| h(v) }\n    expected << '&nbsp;' while expected.length < 3\n    expected = expected.map {|v| \"<td>#{v}</td>\" }.join\n    expected_html = <<END\n<table>\n<tr><th colspan=\"3\">Selenese Commands</th></tr>\n<tr>#{expected}</tr>\n</table>\nEND\n    args_str  = args.map {|a| a.inspect }.join(',')\n    input = \"#{name}(#{args_str})\"\n    assert_rselenese expected_html, 'Selenese Commands', input\n  end\n  \n  def test_render_rselenese_without_locals\n    expected_html = <<END\n<table>\n<tr><th colspan=\"3\"></th></tr>\n</table>\nEND\n    create_rsel_file_from('', \"html.rsel\")\n    \n    @view = TestView.new\n    @view.extend(SeleniumOnRails::PathsTestHelper)\n    @sel = SeleniumOnRails::RSelenese.new(@view)\n    \n    assert_text_equal expected_html, @sel.render(ActionView::Template.new(test_path_for(\"html.rsel\")))\n  end\n \n  def test_element_locators\n    assert_generates_command %w{click aCheckbox}, :click, 'aCheckbox'\n    assert_generates_command %w{click document.foo}, :click, 'document.foo'\n    # assert_generates_command %w{click //a}, :click, '//a'\n  end\n\n  def test_collection_arguments\n    # assert_generates_command ['assertAllLinks', 'link1,link2,link3'], :assert_all_links, ['link1', 'link2','link3']\n    # assert_generates_command ['assertAllLinks', 'link?,link?,link?'], :assert_all_links, 'link?,link?,link?'\n  end\n\n  ARG_VALUE_MAP = {\n    # We can't test url_for style arguments here, because we don't have\n    # a valid controller to interpret them.  See RendererTest.\n    :url => '/relative/url',\n    :string => '1234',\n    :pattern => 'glob:J* Smith', # Also: many other formats.\n    :dimension => '10',\n    :variable => 'varname',\n    :locator => 'foo',\n    :coord_string => '10,20',\n    :movements_string => '+70,-300',\n    :script => 'script',\n    :attribute_name => 'attribute',\n    :locator_and_attribute_name => [['foo', 'attribute'], 'foo@attribute'],\n    :table_locator => [['table', 2, 4], 'table.2.4'],\n    :coll_pattern => [[['a', \"b\\\\\", 'c,']], \"a,b\\\\\\\\,c\\\\,\"],\n    :event_name => 'eventName',\n    :keycode => 123,\n    :option_locator => 'label=hello',\n    :window_id => [[nil], 'null'],\n    :window_name => 'myWindow',\n    :timeout => 123,\n    :integer => 1,\n    :log_level => :debug,\n    :name_value_pair => 'name=value',\n    :options_string => 'path=/path/, max_age=60'\n  }\n\n  # Call _command_ with _args_ and make sure it produces a good table.\n  # If the input command doesn't 'selenize' cleanly (e.g. if the input command\n  # is :do_foo and the expected result is +dofoo+ and not +doFoo+) +command+\n  # can be specified as an array (e.g. +[:input_command, 'expectedResult']+).\n  def assert_command_works command, *args\n    expected_values = args.inject([]) do |c, arg|\n      v = ARG_VALUE_MAP[arg]\n      if v.is_a? Array\n        c << v[1]\n      else\n        c << v\n      end\n    end\n    input_values = args.inject([]) do |c, arg|\n      v = ARG_VALUE_MAP[arg]\n      if v.is_a? Array\n        c.concat v[0]\n      else\n        c << v\n      end\n    end\n    input_name, expected_name  = (command.is_a?(Array) ? command : [command, SeleniumOnRails::TestBuilder.selenize(command.to_s)])\n    assert_generates_command [expected_name]+expected_values, input_name.to_s, *input_values\n  end\n\n  def test_action_commands\n    assert_command_works [:brake, 'break']\n    assert_command_works :create_cookie, :name_value_pair, :options_string\n    assert_command_works :delete_cookie, :string, :string\n    assert_command_works :double_click, :locator\n    assert_command_works :double_click_at, :locator, :coord_string\n    assert_command_works :drag_and_drop, :locator, :movements_string\n    assert_command_works :drag_and_drop_to_object, :locator, :locator\n    assert_command_works :echo, :string\n    assert_command_works :highlight, :locator\n    assert_command_works :meta_key_down\n    assert_command_works :meta_key_up\n    assert_command_works :mouse_down_at, :locator, :coord_string\n    assert_command_works :mouse_move, :locator\n    assert_command_works :mouse_move_at, :locator, :coord_string\n    assert_command_works :mouse_out, :locator\n    assert_command_works :mouse_up, :locator\n    assert_command_works :mouse_up_at, :locator, :coord_string\n    assert_command_works :open_window, :url, :integer\n    assert_command_works :pause, :timeout\n    assert_command_works :remove_all_selections, :locator\n    assert_command_works :select_frame, :locator\n    assert_command_works :set_cursor_position, :locator, :integer\n    assert_command_works :set_mouse_speed, :integer\n    assert_command_works :shift_key_down\n    assert_command_works :shift_key_up\n    assert_command_works :store, :script, :variable\n    assert_command_works :type_keys, :locator, :string\n    assert_command_works :window_focus, :window_name\n    assert_command_works :window_maximize, :window_name\n    assert_command_works :click, :locator\n    assert_command_works :click_and_wait, :locator\n    assert_command_works :click_at, :locator, :coord_string\n    assert_command_works :fire_event, :locator, :event_name\n    assert_command_works :fire_event_and_wait, :locator, :event_name\n    assert_command_works :key_press, :locator, :keycode\n    assert_command_works :key_press_and_wait, :locator, :keycode\n    assert_command_works :key_down, :locator, :keycode\n    assert_command_works :key_down_and_wait, :locator, :keycode\n    assert_command_works :key_up, :locator, :keycode\n    assert_command_works :key_up_and_wait, :locator, :keycode\n    assert_command_works :alt_key_down\n    assert_command_works :alt_key_up\n    assert_command_works :control_key_down\n    assert_command_works :control_key_up\n    assert_command_works :mouse_over, :locator\n    assert_command_works :mouse_over_and_wait, :locator\n    assert_command_works :mouse_down, :locator\n    assert_command_works :mouse_down_and_wait, :locator\n    assert_command_works :type, :locator, :string\n    assert_command_works :type_and_wait, :locator, :string\n    assert_command_works :check, :locator\n    assert_command_works :check_and_wait, :locator\n    assert_command_works :uncheck, :locator\n    assert_command_works :uncheck_and_wait, :locator\n    assert_command_works :select, :locator, :option_locator\n    assert_command_works :select_and_wait, :locator, :option_locator\n    assert_command_works :add_selection, :locator, :option_locator\n    assert_command_works :add_selection_and_wait, :locator, :option_locator\n    assert_command_works :remove_selection, :locator, :option_locator\n    assert_command_works :remove_selection_and_wait, :locator, :option_locator\n    assert_command_works :submit, :locator\n    assert_command_works :open, :url\n    assert_command_works :select_window, :window_id\n    assert_command_works [:wait_for_popup, 'waitForPopUp'], :window_id, :timeout\n    assert_command_works :choose_cancel_on_next_confirmation\n    assert_command_works :choose_cancel_on_next_confirmation_and_wait\n    assert_command_works :answer_on_next_prompt, :string\n    assert_command_works :answer_on_next_prompt_and_wait, :string\n    assert_command_works :go_back\n    assert_command_works :refresh\n    assert_command_works :close\n    assert_command_works :set_context, :string\n    assert_command_works :set_context, :string, :log_level\n    assert_command_works :wait_for_condition, :script, :timeout\n    assert_command_works :set_timeout, :timeout\n    assert_command_works :wait_for_page_to_load, :timeout\n  end\n\n  # This is bad.  They can be their own tests.\n  def test_accessor_commands\n    assert_command_works :store_alert_present, :variable\n    assert_command_works :assert_alert_present\n    assert_command_works :assert_alert_not_present\n    assert_command_works :verify_alert_present\n    assert_command_works :verify_alert_not_present\n    assert_command_works :wait_for_alert_present\n    assert_command_works :wait_for_alert_not_present\n    \n    assert_command_works :store_prompt_present, :variable \n    assert_command_works :assert_prompt_present\n    assert_command_works :assert_prompt_not_present\n    assert_command_works :verify_prompt_present\n    assert_command_works :verify_prompt_not_present\n    assert_command_works :wait_for_prompt_present\n    assert_command_works :wait_for_prompt_not_present\n    \n    assert_command_works :store_confirmation_present, :variable \n    assert_command_works :assert_confirmation_present\n    assert_command_works :assert_confirmation_not_present\n    assert_command_works :verify_confirmation_present\n    assert_command_works :verify_confirmation_not_present\n    assert_command_works :wait_for_confirmation_present\n    assert_command_works :wait_for_confirmation_not_present\n    \n    assert_command_works :store_alert, :variable\n    assert_command_works :assert_alert, :pattern\n    assert_command_works :assert_not_alert, :pattern\n    assert_command_works :verify_alert, :pattern\n    assert_command_works :verify_not_alert, :pattern\n    assert_command_works :wait_for_alert, :pattern\n    assert_command_works :wait_for_not_alert, :pattern\n    \n    assert_command_works :store_confirmation, :variable\n    assert_command_works :assert_confirmation, :pattern\n    assert_command_works :assert_not_confirmation, :pattern\n    assert_command_works :verify_confirmation, :pattern\n    assert_command_works :verify_not_confirmation, :pattern\n    assert_command_works :wait_for_confirmation, :pattern\n    assert_command_works :wait_for_not_confirmation, :pattern\n    \n    assert_command_works :store_prompt, :variable\n    assert_command_works :assert_prompt, :pattern\n    assert_command_works :assert_not_prompt, :pattern\n    assert_command_works :verify_prompt, :pattern\n    assert_command_works :verify_not_prompt, :pattern\n    assert_command_works :wait_for_prompt, :pattern\n    assert_command_works :wait_for_not_prompt, :pattern\n    \n    assert_command_works :store_absolute_location, :variable\n    assert_command_works :assert_absolute_location, :url\n    assert_command_works :assert_not_absolute_location, :url\n    assert_command_works :verify_absolute_location, :url\n    assert_command_works :verify_not_absolute_location, :url\n    assert_command_works :wait_for_absolute_location, :url\n    assert_command_works :wait_for_not_absolute_location, :url\n    \n    assert_command_works :store_location, :pattern, :variable\n    assert_command_works :assert_location, :url\n    assert_command_works :assert_not_location, :url\n    assert_command_works :verify_location, :url\n    assert_command_works :verify_not_location, :url\n    assert_command_works :wait_for_location, :url\n    assert_command_works :wait_for_not_location, :url\n    \n    assert_command_works :store_title, :variable\n    assert_command_works :assert_title, :pattern\n    assert_command_works :assert_not_title, :pattern\n    assert_command_works :verify_title, :pattern\n    assert_command_works :verify_not_title, :pattern\n    assert_command_works :wait_for_title, :pattern\n    assert_command_works :wait_for_not_title, :pattern\n    \n    assert_command_works :store_body_text, :variable\n    assert_command_works :assert_body_text, :pattern\n    assert_command_works :assert_not_body_text, :pattern\n    assert_command_works :verify_body_text, :pattern\n    assert_command_works :verify_not_body_text, :pattern\n    assert_command_works :wait_for_body_text, :pattern\n    assert_command_works :wait_for_not_body_text, :pattern\n    \n    assert_command_works :store_value, :locator, :variable\n    assert_command_works :assert_value, :locator, :pattern\n    assert_command_works :assert_not_value, :locator, :pattern\n    assert_command_works :verify_value, :locator, :pattern\n    assert_command_works :verify_not_value, :locator, :pattern\n    assert_command_works :wait_for_value, :locator, :pattern\n    assert_command_works :wait_for_not_value, :locator, :pattern\n    \n    assert_command_works :store_text, :locator, :variable\n    assert_command_works :assert_text, :locator, :pattern\n    assert_command_works :assert_not_text, :locator, :pattern\n    assert_command_works :verify_text, :locator, :pattern\n    assert_command_works :verify_not_text, :locator, :pattern\n    assert_command_works :wait_for_text, :locator, :pattern\n    assert_command_works :wait_for_not_text, :locator, :pattern\n    \n    assert_command_works :store_eval, :script, :variable\n    assert_command_works :assert_eval, :script, :pattern\n    assert_command_works :assert_not_eval, :script, :pattern\n    assert_command_works :verify_eval, :script, :pattern\n    assert_command_works :verify_not_eval, :script, :pattern\n    assert_command_works :wait_for_eval, :script, :pattern\n    assert_command_works :wait_for_not_eval, :script, :pattern\n    \n    assert_command_works :store_checked, :locator, :variable\n    assert_command_works :assert_checked, :locator\n    assert_command_works :assert_not_checked, :locator\n    assert_command_works :verify_checked, :locator\n    assert_command_works :verify_not_checked, :locator\n    assert_command_works :wait_for_checked, :locator\n    assert_command_works :wait_for_not_checked, :locator\n    \n    assert_command_works :store_table, :table_locator, :variable\n    assert_command_works :assert_table, :table_locator, :pattern\n    assert_command_works :assert_not_table, :table_locator, :pattern\n    assert_command_works :verify_table, :table_locator, :pattern\n    assert_command_works :verify_not_table, :table_locator, :pattern\n    assert_command_works :wait_for_table, :table_locator, :pattern\n    assert_command_works :wait_for_not_table, :table_locator, :pattern\n    \n    assert_raise RuntimeError do\n      assert_command_works :store_selected, :locator, :option_locator, :variable\n    end\n    assert_command_works :assert_selected, :locator, :option_locator\n    assert_command_works :assert_not_selected, :locator, :option_locator\n    assert_command_works :verify_selected, :locator, :option_locator\n    assert_command_works :verify_not_selected, :locator, :option_locator\n    assert_command_works :wait_for_selected, :locator, :option_locator\n    assert_command_works :wait_for_not_selected, :locator, :option_locator\n    \n    assert_command_works :store_selected_id, :locator, :variable\n    assert_command_works :assert_selected_id, :locator, :pattern\n    assert_command_works :assert_not_selected_id, :locator, :pattern\n    assert_command_works :verify_selected_id, :locator, :pattern\n    assert_command_works :verify_not_selected_id, :locator, :pattern\n    assert_command_works :wait_for_selected_id, :locator, :pattern\n    assert_command_works :wait_for_not_selected_id, :locator, :pattern\n    \n    assert_command_works :store_selected_ids, :locator, :variable\n    assert_command_works :assert_selected_ids, :locator, :pattern\n    assert_command_works :assert_not_selected_ids, :locator, :pattern\n    assert_command_works :verify_selected_ids, :locator, :pattern\n    assert_command_works :verify_not_selected_ids, :locator, :pattern\n    assert_command_works :wait_for_selected_ids, :locator, :pattern\n    assert_command_works :wait_for_not_selected_ids, :locator, :pattern\n    \n    assert_command_works :store_selected_index, :locator, :variable\n    assert_command_works :assert_selected_index, :locator, :pattern\n    assert_command_works :assert_not_selected_index, :locator, :pattern\n    assert_command_works :verify_selected_index, :locator, :pattern\n    assert_command_works :verify_not_selected_index, :locator, :pattern\n    assert_command_works :wait_for_selected_index, :locator, :pattern\n    assert_command_works :wait_for_not_selected_index, :locator, :pattern\n    \n    assert_command_works :store_selected_indexes, :locator, :variable\n    assert_command_works :assert_selected_indexes, :locator, :pattern\n    assert_command_works :assert_not_selected_indexes, :locator, :pattern\n    assert_command_works :verify_selected_indexes, :locator, :pattern\n    assert_command_works :verify_not_selected_indexes, :locator, :pattern\n    assert_command_works :wait_for_selected_indexes, :locator, :pattern\n    assert_command_works :wait_for_not_selected_indexes, :locator, :pattern\n    \n    assert_command_works :store_selected_label, :locator, :variable\n    assert_command_works :assert_selected_label, :locator, :pattern\n    assert_command_works :assert_not_selected_label, :locator, :pattern\n    assert_command_works :verify_selected_label, :locator, :pattern\n    assert_command_works :verify_not_selected_label, :locator, :pattern\n    assert_command_works :wait_for_selected_label, :locator, :pattern\n    assert_command_works :wait_for_not_selected_label, :locator, :pattern\n    \n    assert_command_works :store_selected_labels, :locator, :variable\n    assert_command_works :assert_selected_labels, :locator, :pattern\n    assert_command_works :assert_not_selected_labels, :locator, :pattern\n    assert_command_works :verify_selected_labels, :locator, :pattern\n    assert_command_works :verify_not_selected_labels, :locator, :pattern\n    assert_command_works :wait_for_selected_labels, :locator, :pattern\n    assert_command_works :wait_for_not_selected_labels, :locator, :pattern\n    \n    assert_command_works :store_selected_value, :locator, :variable\n    assert_command_works :assert_selected_value, :locator, :pattern\n    assert_command_works :assert_not_selected_value, :locator, :pattern\n    assert_command_works :verify_selected_value, :locator, :pattern\n    assert_command_works :verify_not_selected_value, :locator, :pattern\n    assert_command_works :wait_for_selected_value, :locator, :pattern\n    assert_command_works :wait_for_not_selected_value, :locator, :pattern\n    \n    assert_command_works :store_selected_values, :locator, :variable\n    assert_command_works :assert_selected_values, :locator, :pattern\n    assert_command_works :assert_not_selected_values, :locator, :pattern\n    assert_command_works :verify_selected_values, :locator, :pattern\n    assert_command_works :verify_not_selected_values, :locator, :pattern\n    assert_command_works :wait_for_selected_values, :locator, :pattern\n    assert_command_works :wait_for_not_selected_values, :locator, :pattern\n    \n    assert_command_works :store_something_selected, :locator, :variable\n    assert_command_works :assert_something_selected, :locator\n    assert_command_works :assert_not_something_selected, :locator\n    assert_command_works :verify_something_selected, :locator\n    assert_command_works :verify_not_something_selected, :locator\n    assert_command_works :wait_for_something_selected, :locator\n    assert_command_works :wait_for_not_something_selected, :locator\n    \n    assert_command_works :store_selected_options, :locator, :variable\n    assert_command_works :assert_selected_options, :locator, :coll_pattern\n    assert_command_works :assert_not_selected_options, :locator, :coll_pattern\n    assert_command_works :verify_selected_options, :locator, :coll_pattern\n    assert_command_works :verify_not_selected_options, :locator, :coll_pattern\n    assert_command_works :wait_for_selected_options, :locator, :coll_pattern\n    assert_command_works :wait_for_not_selected_options, :locator, :coll_pattern\n    \n    assert_command_works :store_select_options, :locator, :variable\n    assert_command_works :assert_select_options, :locator, :coll_pattern\n    assert_command_works :assert_not_select_options, :locator, :coll_pattern\n    assert_command_works :verify_select_options, :locator, :coll_pattern\n    assert_command_works :verify_not_select_options, :locator, :coll_pattern\n    assert_command_works :wait_for_select_options, :locator, :coll_pattern\n    assert_command_works :wait_for_not_select_options, :locator, :coll_pattern\n    \n    assert_command_works :store_attribute, :locator_and_attribute_name, :variable\n    assert_command_works :assert_attribute, :locator_and_attribute_name, :pattern\n    assert_command_works :assert_not_attribute, :locator_and_attribute_name, :pattern\n    assert_command_works :verify_attribute, :locator_and_attribute_name, :pattern\n    assert_command_works :verify_not_attribute, :locator_and_attribute_name, :pattern\n    assert_command_works :wait_for_attribute, :locator_and_attribute_name, :pattern\n    assert_command_works :wait_for_not_attribute, :locator_and_attribute_name, :pattern\n    \n    assert_raise RuntimeError do\n      assert_command_works :store_ordered, :locator, :locator, :variable\n    end\n    assert_command_works :assert_ordered, :locator, :locator\n    assert_command_works :assert_not_ordered, :locator, :locator\n    assert_command_works :verify_ordered, :locator, :locator\n    assert_command_works :verify_not_ordered, :locator, :locator\n    assert_command_works :wait_for_ordered, :locator, :locator\n    assert_command_works :wait_for_not_ordered, :locator, :locator\n    \n    assert_command_works :store_text_present, :pattern, :variable\n    assert_command_works :assert_text_present, :pattern\n    assert_command_works :assert_text_not_present, :pattern\n    assert_command_works :verify_text_present, :pattern\n    assert_command_works :verify_text_not_present, :pattern\n    assert_command_works :wait_for_text_present, :pattern\n    assert_command_works :wait_for_text_not_present, :pattern\n    \n    assert_command_works :store_element_present, :locator, :variable\n    assert_command_works :assert_element_present, :locator\n    assert_command_works :assert_element_not_present, :locator\n    assert_command_works :verify_element_present, :locator\n    assert_command_works :verify_element_not_present, :locator\n    assert_command_works :wait_for_element_present, :locator\n    assert_command_works :wait_for_element_not_present, :locator\n    \n    assert_command_works :store_visible, :locator, :variable\n    assert_command_works :assert_visible, :locator\n    assert_command_works :assert_not_visible, :locator\n    assert_command_works :verify_visible, :locator\n    assert_command_works :verify_not_visible, :locator\n    assert_command_works :wait_for_visible, :locator\n    assert_command_works :wait_for_not_visible, :locator\n    \n    assert_raise RuntimeError do\n      assert_command_works :store_error_on_next, :string\n    end\n    assert_command_works :assert_error_on_next, :string\n    assert_command_works :assert_not_error_on_next, :string\n    assert_command_works :verify_error_on_next, :string\n    assert_command_works :verify_not_error_on_next, :string\n    assert_command_works :wait_for_error_on_next, :string\n    assert_command_works :wait_for_not_error_on_next, :string    \n    \n    assert_raise RuntimeError do\n      assert_command_works :store_failure_on_next, :string\n    end\n    assert_command_works :assert_failure_on_next, :string\n    assert_command_works :assert_not_failure_on_next, :string\n    assert_command_works :verify_failure_on_next, :string\n    assert_command_works :verify_not_failure_on_next, :string\n    assert_command_works :wait_for_failure_on_next, :string\n    assert_command_works :wait_for_not_failure_on_next, :string\n    \n    assert_command_works :store_all_window_ids, :variable\n    assert_command_works :assert_all_window_ids, :pattern\n    assert_command_works :assert_not_all_window_ids, :pattern\n    assert_command_works :verify_all_window_ids, :pattern\n    assert_command_works :verify_not_all_window_ids, :pattern\n    assert_command_works :wait_for_all_window_ids, :pattern\n    assert_command_works :wait_for_not_all_window_ids, :pattern\n    \n    assert_command_works :store_all_window_names, :variable\n    assert_command_works :assert_all_window_names, :pattern\n    assert_command_works :assert_not_all_window_names, :pattern\n    assert_command_works :verify_all_window_names, :pattern\n    assert_command_works :verify_not_all_window_names, :pattern\n    assert_command_works :wait_for_all_window_names, :pattern\n    assert_command_works :wait_for_not_all_window_names, :pattern\n    \n    assert_command_works :store_all_window_titles, :variable\n    assert_command_works :assert_all_window_titles, :pattern\n    assert_command_works :assert_not_all_window_titles, :pattern\n    assert_command_works :verify_all_window_titles, :pattern\n    assert_command_works :verify_not_all_window_titles, :pattern\n    assert_command_works :wait_for_all_window_titles, :pattern\n    assert_command_works :wait_for_not_all_window_titles, :pattern\n    \n    assert_command_works :store_cookie, :variable\n    assert_command_works :assert_cookie, :pattern\n    assert_command_works :assert_not_cookie, :pattern\n    assert_command_works :verify_cookie, :pattern\n    assert_command_works :verify_not_cookie, :pattern\n    assert_command_works :wait_for_cookie, :pattern\n    assert_command_works :wait_for_not_cookie, :pattern\n    \n    assert_command_works :store_log_messages, :variable\n    assert_command_works :assert_log_messages, :pattern\n    assert_command_works :assert_not_log_messages, :pattern\n    assert_command_works :verify_log_messages, :pattern\n    assert_command_works :verify_not_log_messages, :pattern\n    assert_command_works :wait_for_log_messages, :pattern\n    assert_command_works :wait_for_not_log_messages, :pattern\n    \n    assert_command_works :store_mouse_speed, :variable\n    assert_command_works :assert_mouse_speed, :pattern\n    assert_command_works :assert_not_mouse_speed, :pattern\n    assert_command_works :verify_mouse_speed, :pattern\n    assert_command_works :verify_not_mouse_speed, :pattern\n    assert_command_works :wait_for_mouse_speed, :pattern\n    assert_command_works :wait_for_not_mouse_speed, :pattern\n    \n    assert_command_works :store_cursor_position, :locator, :variable\n    assert_command_works :assert_cursor_position, :locator, :pattern\n    assert_command_works :assert_not_cursor_position, :locator, :pattern\n    assert_command_works :verify_cursor_position, :locator, :pattern\n    assert_command_works :verify_not_cursor_position, :locator, :pattern\n    assert_command_works :wait_for_cursor_position, :locator, :pattern\n    assert_command_works :wait_for_not_cursor_position, :locator, :pattern\n    \n    assert_command_works :store_attribute_from_all_windows, :attribute_name, :variable\n    assert_command_works :assert_attribute_from_all_windows, :attribute_name, :pattern\n    assert_command_works :assert_not_attribute_from_all_windows, :attribute_name, :pattern\n    assert_command_works :verify_attribute_from_all_windows, :attribute_name, :pattern\n    assert_command_works :verify_not_attribute_from_all_windows, :attribute_name, :pattern\n    assert_command_works :wait_for_attribute_from_all_windows, :attribute_name, :pattern\n    assert_command_works :wait_for_not_attribute_from_all_windows, :attribute_name, :pattern\n    \n    assert_command_works :store_element_height, :locator, :variable\n    assert_command_works :assert_element_height, :locator, :dimension\n    assert_command_works :assert_not_element_height, :locator, :dimension\n    assert_command_works :verify_element_height, :locator, :dimension\n    assert_command_works :verify_not_element_height, :locator, :dimension\n    assert_command_works :wait_for_element_height, :locator, :dimension\n    assert_command_works :wait_for_not_element_height, :locator, :dimension\n    \n    assert_command_works :store_element_index, :locator, :variable\n    assert_command_works :assert_element_index, :locator, :pattern\n    assert_command_works :assert_not_element_index, :locator, :pattern\n    assert_command_works :verify_element_index, :locator, :pattern\n    assert_command_works :verify_not_element_index, :locator, :pattern\n    assert_command_works :wait_for_element_index, :locator, :pattern\n    assert_command_works :wait_for_not_element_index, :locator, :pattern\n    \n    assert_command_works :store_element_width, :locator, :variable\n    assert_command_works :assert_element_width, :locator, :dimension\n    assert_command_works :assert_not_element_width, :locator, :dimension\n    assert_command_works :verify_element_width, :locator, :dimension\n    assert_command_works :verify_not_element_width, :locator, :dimension\n    assert_command_works :wait_for_element_width, :locator, :dimension\n    assert_command_works :wait_for_not_element_width, :locator, :dimension\n    \n    assert_command_works :store_element_position_left, :locator, :variable\n    assert_command_works :assert_element_position_left, :locator, :dimension\n    assert_command_works :assert_not_element_position_left, :locator, :dimension\n    assert_command_works :verify_element_position_left, :locator, :dimension\n    assert_command_works :verify_not_element_position_left, :locator, :dimension\n    assert_command_works :wait_for_element_position_left, :locator, :dimension\n    assert_command_works :wait_for_not_element_position_left, :locator, :dimension\n    \n    assert_command_works :store_element_position_top, :locator, :variable\n    assert_command_works :assert_element_position_top, :locator, :dimension\n    assert_command_works :assert_not_element_position_top, :locator, :dimension\n    assert_command_works :verify_element_position_top, :locator, :dimension\n    assert_command_works :verify_not_element_position_top, :locator, :dimension\n    assert_command_works :wait_for_element_position_top, :locator, :dimension\n    assert_command_works :wait_for_not_element_position_top, :locator, :dimension\n    \n    assert_command_works :store_editable, :locator, :variable\n    assert_command_works :assert_editable, :locator\n    assert_command_works :assert_not_editable, :locator\n    assert_command_works :verify_editable, :locator\n    assert_command_works :verify_not_editable, :locator\n    assert_command_works :wait_for_editable, :locator\n    assert_command_works :wait_for_not_editable, :locator\n    \n    assert_command_works :store_all_buttons, :variable\n    assert_command_works :assert_all_buttons, :coll_pattern\n    assert_command_works :assert_not_all_buttons, :coll_pattern\n    assert_command_works :verify_all_buttons, :coll_pattern\n    assert_command_works :verify_not_all_buttons, :coll_pattern\n    assert_command_works :wait_for_all_buttons, :coll_pattern\n    assert_command_works :wait_for_not_all_buttons, :coll_pattern\n    \n    assert_command_works :store_all_links, :variable\n    assert_command_works :assert_all_links, :coll_pattern\n    assert_command_works :assert_not_all_links, :coll_pattern\n    assert_command_works :verify_all_links, :coll_pattern\n    assert_command_works :verify_not_all_links, :coll_pattern\n    assert_command_works :wait_for_all_links, :coll_pattern\n    assert_command_works :wait_for_not_all_links, :coll_pattern\n    \n    assert_command_works :store_all_fields, :variable\n    assert_command_works :assert_all_fields, :coll_pattern\n    assert_command_works :assert_not_all_fields, :coll_pattern\n    assert_command_works :verify_all_fields, :coll_pattern\n    assert_command_works :verify_not_all_fields, :coll_pattern\n    assert_command_works :wait_for_all_fields, :coll_pattern\n    assert_command_works :wait_for_not_all_fields, :coll_pattern\n    \n    assert_command_works :store_html_source, :variable\n    assert_command_works :assert_html_source, :pattern\n    assert_command_works :assert_not_html_source, :pattern\n    assert_command_works :verify_html_source, :pattern\n    assert_command_works :verify_not_html_source, :pattern\n    assert_command_works :wait_for_html_source, :pattern\n    assert_command_works :wait_for_not_html_source, :pattern\n    \n    assert_command_works :store_expression, :script, :variable\n    assert_command_works :assert_expression, :script, :pattern\n    assert_command_works :assert_not_expression, :script, :pattern\n    assert_command_works :verify_expression, :script, :pattern\n    assert_command_works :verify_not_expression, :script, :pattern\n    assert_command_works :wait_for_expression, :script, :pattern\n    assert_command_works :wait_for_not_expression, :script, :pattern\n    \n    assert_raise RuntimeError do\n      assert_command_works :store_whether_this_frame_match_frame_expression, :string, :string, :variable\n    end\n    assert_command_works :assert_whether_this_frame_match_frame_expression, :string, :string\n    assert_command_works :assert_not_whether_this_frame_match_frame_expression, :string, :string\n    assert_command_works :verify_whether_this_frame_match_frame_expression, :string, :string\n    assert_command_works :verify_not_whether_this_frame_match_frame_expression, :string, :string\n    assert_command_works :wait_for_whether_this_frame_match_frame_expression, :string, :string\n    assert_command_works :wait_for_not_whether_this_frame_match_frame_expression, :string, :string\n    \n    assert_raise RuntimeError do\n      assert_command_works :store_whether_this_window_match_window_expression, :string, :string, :variable\n    end\n    assert_command_works :assert_whether_this_window_match_window_expression, :string, :string\n    assert_command_works :assert_not_whether_this_window_match_window_expression, :string, :string\n    assert_command_works :verify_whether_this_window_match_window_expression, :string, :string\n    assert_command_works :verify_not_whether_this_window_match_window_expression, :string, :string\n    assert_command_works :wait_for_whether_this_window_match_window_expression, :string, :string\n    assert_command_works :wait_for_not_whether_this_window_match_window_expression, :string, :string\n  end\n\n  def test_partial_support\n    expected = <<END\n<table>\n<tr><th colspan=\"3\">Partial support</th></tr>\n<tr><td>type</td><td>partial</td><td>RSelenese partial</td></tr>\n</table>\nEND\n    input = \"include_partial 'override'\"\n    partial = \"type 'partial', 'RSelenese partial'\"\n    \n    create_rsel_file_from(partial, \"_override.rsel\")\n    \n    assert_rselenese expected, 'Partial support', input\n    \n    File.delete(test_path_for(\"_override.rsel\"))\n  end\n  \n  def test_partial_support_with_local_assigns\n    expected = <<END_EXPECTED\n<table>\n<tr><th colspan=\"3\">Partial support with local variables</th></tr>\n<tr><td>type</td><td>partial</td><td>RSelenese partial</td></tr>\n<tr><td>type</td><td>local</td><td>par</td></tr>\n<tr><td>type</td><td>local</td><td>tial</td></tr>\n</table>\nEND_EXPECTED\n    input = \"include_partial 'override', :locator => 'local', :input => ['par', 'tial']\"\n    partial = <<END_PARTIAL\ntype 'partial', 'RSelenese partial'\ninput.each do |i|\n  type locator, i\nend\nEND_PARTIAL\n\n    create_rsel_file_from(partial, \"_override.rsel\")\n\n    assert_rselenese expected, 'Partial support with local variables', input\n    \n    File.delete(test_path_for(\"_override.rsel\"))\n  end\n\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/selenese_test.rb",
    "content": "  require File.dirname(__FILE__) + '/test_helper'\n\nclass SeleneseTest < Test::Unit::TestCase\n  \n  def setup\n    @view = TestView.new\n    @view.extend(SeleniumOnRails::PathsTestHelper)\n    @sel = SeleniumOnRails::Selenese.new(@view) \n  end\n  \n  def render_selenese(page_title, input)\n    create_sel_file_from(input, \"html.sel\")\n    \n    @sel.render ActionView::Template.new(test_path_for(\"html.sel\")), {'page_title' => page_title}\n  end\n  \n  def create_sel_file_from(input, name)\n    File.open(test_path_for(name), 'w+') { |index_file| index_file << input }\n  end\n  \n  def test_path_for(name)\n    \"#{File.expand_path(File.dirname(__FILE__) + \"/../test_data\")}/#{name}\"\n  end\n   \n  def assert_selenese expected, name, input\n    assert_text_equal expected, render_selenese(name, input)\n  end\n   \n  def test_empty\n    expected = <<END\n<table>\n<tr><th colspan=\"3\">Empty</th></tr>\n</table>\nEND\n    input = ''\n    assert_selenese expected, 'Empty', ''\n  end\n   \n  def test_one_line\n    expected = <<END\n<table>\n<tr><th colspan=\"3\">One line</th></tr>\n<tr><td>open</td><td>/</td><td>&nbsp;</td></tr>\n</table>\nEND\n    input = '|open|/|'\n    assert_selenese expected, 'One line', input\n  end\n   \n  def test_comments_only\n    expected = <<END\n<p>Comment <strong>1</strong></p>\n\n\n<p>Comment 2</p>\n<table>\n<tr><th colspan=\"3\">Only comments</th></tr>\n</table>\nEND\n    input = <<END\nComment *1*\n \nComment 2\n \nEND\n    assert_selenese expected, 'Only comments', input\n  end\n   \n  def test_commands_only\n    expected = <<END\n<table>\n<tr><th colspan=\"3\">Only commands</th></tr>\n<tr><td>goBack</td><td>&nbsp;</td><td>&nbsp;</td></tr>\n<tr><td>open</td><td>/foo</td><td>&nbsp;</td></tr>\n<tr><td>fireEvent</td><td>textField</td><td>focus</td></tr>\n</table>\nEND\n    input = <<END\n\n|goBack   |\n\n|open|   /foo  |  \n| fireEvent | textField | focus |\n\n\nEND\n    assert_selenese expected, 'Only commands', input\n  end\n   \n  def test_commands_and_comments\n    expected = <<END\n<table>\n<tr><th colspan=\"3\">Commands and comments</th></tr>\n<tr><td>goBack</td><td>&nbsp;</td><td>&nbsp;</td></tr>\n<tr><td>fireEvent</td><td>textField</td><td>focus</td></tr>\n</table>\n<p>Comment 1</p>\n\n\n <p>Comment <strong>2</strong></p>\nEND\n    input = <<END\n\n|goBack   |\n\n|  fireEvent | textField| focus|\nComment 1\n\nComment *2*\n\nEND\n    assert_selenese expected, 'Commands and comments', input\n  end\n   \n  def test_comments_and_commands\n    expected = <<END\n<p>Comment 1</p>\n \n<p>Comment <strong>2</strong></p>\n<table>\n<tr><th colspan=\"3\">Comments and commands</th></tr>\n<tr><td>goBack</td><td>&nbsp;</td><td>&nbsp;</td></tr>\n<tr><td>fireEvent</td><td>textField</td><td>focus</td></tr>\n</table>\nEND\n    input = <<END\nComment 1\n\nComment *2*\n|goBack   |\n\n|  fireEvent | textField|focus|\n\nEND\n    assert_selenese expected, 'Comments and commands', input\n  end\n   \n  def test_comments_commands_comments\n    expected = <<END\n<p>Comment 1</p>\n<p>Comment <strong>2</strong></p>\n<table>\n<tr><th colspan=\"3\">Comments, commands and comments</th></tr>\n<tr><td>goBack</td><td>&nbsp;</td><td>&nbsp;</td></tr>\n<tr><td>fireEvent</td><td>textField</td><td>focus</td></tr>\n</table>\n<p>Comment 3</p>\nEND\n    \n    input = <<END\nComment 1\n\nComment *2*\n|goBack   |\n|  fireEvent | textField| focus|\nComment 3\nEND\n    assert_selenese expected, 'Comments, commands and comments', input\n  end\n   \n  def test_command_html_entity_escaping\n    expected = <<END\n<table>\n<tr><th colspan=\"3\">HTML escaping</th></tr>\n<tr><td>type</td><td>nameField</td><td>&lt;&gt;&amp;</td></tr>\n</table>\nEND\n    input = '|type|nameField|<>&|'\n    assert_selenese expected, 'HTML escaping', input\n  end\n   \n  def test_partial_support\n    expected = <<END\n<table>\n<tr><th colspan=\"3\">Partial support</th></tr>\n<tr><td>type</td><td>partial</td><td>Selenese partial</td></tr>\n</table>\nEND\n    input = '|includePartial|override|'\n    partial = '|type|partial|Selenese partial|'\n    create_sel_file_from(partial, \"_override.sel\")\n    \n    assert_selenese(expected, 'Partial support', input)\n    \n    File.delete(test_path_for(\"_override.sel\"))\n  end\n   \n  def test_partial_support_with_local_assigns\n    expected = <<END_EXPECTED\n<table>\n<tr><th colspan=\"3\">Partial support with local assigns</th></tr>\n<tr><td>type</td><td>assigns</td><td>a=hello,b=world!,c_123ABC=</td></tr>\n<tr><td>type</td><td>assigns</td><td>a=a b c d,b=,c_123ABC=hello</td></tr>\n</table>\nEND_EXPECTED\n     \n    input = <<END_INPUT\n|includePartial|override|a=hello|b=world!|\n|includePartial|override|a = a b c d|b=|c_123ABC= hello  |\nEND_INPUT\n\n    partial = <<END_PARTIAL\n<table><tr><th>whatever</th></tr>\n<tr><td>type</td><td>assigns</td><td>\na=<%= a if defined? a%>,\nb=<%= b if defined? b%>,\nc_123ABC=<%= c_123ABC if defined? c_123ABC%>\n</td></tr>\n</table>\nEND_PARTIAL\n\n    create_sel_file_from(partial, \"_override.html\")\n    \n    assert_selenese(expected, 'Partial support with local assigns', input)\n    \n    File.delete(test_path_for(\"_override.html\"))\n  end\n     \n  def test_raised_when_more_than_three_columns\n    assert_raise RuntimeError, 'There might only be a maximum of three cells!' do\n      render_selenese 'name', '|col1|col2|col3|col4|'\n    end\n  end\n \n  def test_raised_when_more_than_one_set_of_commands\n    assert_raise RuntimeError, 'You cannot have comments in the middle of commands!' do\n      input = <<END\ncomment\n|command|\ncomment\n|command|\nEND\n      render_selenese 'name', input\n    end\n  end\n   \n  def test_raised_when_incorrect_partial_format\n    assert_raise RuntimeError, \"Invalid format 'invalid'. Should be '|includePartial|partial|var1=value|var2=value|.\" do\n      render_selenese 'name', '|includePartial|partial|a=valid|invalid|'\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/selenium_controller_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\nrequire 'mocha'\n\nclass SeleniumControllerTest < Test::Unit::TestCase\n\n  def setup\n    @controller = SeleniumController.new\n    @controller.extend(SeleniumOnRails::PathsTestHelper)\n    ActionController::Routing::Routes.draw\n    SeleniumController.any_instance.stubs(:layout_path).returns(false)\n    @request    = ActionController::TestRequest.new\n    @response   = ActionController::TestResponse.new\n    @result_dir = File.join(File.dirname(__FILE__), \"..\", \"test_result\")\n    \n    @suite = <<EOS\n<script>\n</script>\n<table>\n  <tr><td bgcolor=\"#ccffcc\"><a href=\"/selenium/tests/foo.sel\">Foo</a></td></tr>\n  <tr><td bgcolor=\"#ccffcc\"><a href=\"/selenium/tests/bar.sel\">Bar</a></td></tr>\n</table>\nEOS\n  end\n\n  def teardown\n    FileUtils.rm_rf @result_dir\n  end\n  \n  def test_record_with_result\n    @controller.instance_variable_set(:@result_dir, @result_dir)\n    \n    post :record, :suite => @suite, \"testTable.1\" => \"<table></table>\", \"testTable.2\" => \"<table></table>\"\n    \n    cur_result_dir = File.join(@result_dir, \"default\")\n    assert File.directory?(cur_result_dir)\n    assert_equal [\"blank.html\", \"index.html\", \"suite.html\", \"test1.html\", \"test2.html\"], \n                 Dir.glob(\"#{cur_result_dir}/*.html\").map{|path| File.basename(path)}.sort\n\n    expected = <<EOS\n<html>\n<head>\n<link rel=\"stylesheet\" type=\"text/css\" href=\"selenium-test.css\">\n</head>\n<body>\n<table>\n  <tr><td bgcolor=\"#ccffcc\"><a href=\"test1.html\" target=\"testcase\">Foo</a></td></tr>\n  <tr><td bgcolor=\"#ccffcc\"><a href=\"test2.html\" target=\"testcase\">Bar</a></td></tr>\n</table>\n</body></html>\nEOS\n    assert_equal expected, File.read(\"#{cur_result_dir}/suite.html\")\n  end\n  \n  def test_result_hash\n    post :record, :suite => @suite, \"testTable.1\" => \"<table></table>\", \"testTable.2\" => \"<table></table>\",\n                  :result => 'Failed', :numTestFailures => \"906\", :numTestPasses => \"1079\", :numCommandFailures => '1027', \n                  :numCommandErrors => '57', :numCommandPasses => '3', :totalTime => \"A long time\"\n    \n    assert_equal 'Failed', assigns['result']['result']\n    assert_equal '906', assigns['result']['numTestFailures']\n    assert_equal '1079', assigns['result']['numTestPasses']\n    assert_equal '1027', assigns['result']['numCommandFailures']\n    assert_equal '57', assigns['result']['numCommandErrors']\n    assert_equal '3', assigns['result']['numCommandPasses']\n    assert_equal  'A long time', assigns['result']['totalTime']\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/selenium_on_rails_config_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\nrequire 'mocha'\n\nclass SeleniumOnRailsConfig\n  def self.reset_config\n    @@configs = nil\n  end\nend\n\nclass SeleniumOnRailsConfigTest < Test::Unit::TestCase\n  \n  def setup\n    SeleniumOnRailsConfig.reset_config\n    @selenium_file = File.join(RAILS_ROOT, 'config', 'selenium.yml')\n    @config_file = File.expand_path(File.dirname(__FILE__) + '/../config.yml')\n    @selenium_content = File.read(File.dirname(__FILE__) + '/fixtures/selenium.yml')\n    @config_content = File.read(File.dirname(__FILE__) + '/fixtures/config.yml')\n  end\n\n  def test_get_selenium_yaml\n    File.expects(:exist?).with(@selenium_file).returns(true)\n    IO.expects(:read).with(@selenium_file).returns(@selenium_content)\n    IO.expects(:read).with(@config_file).never\n    IO.expects(:exist?).with(@config_file).never\n    \n    assert_equal [\"test_cache\"], SeleniumOnRailsConfig.get(:environments)\n    assert_equal({\"firefox\"=>\"script/openfirefox\"}, SeleniumOnRailsConfig.get(:browsers))\n  end\n\n  def test_get_when_config_yml_exists_but_selenium_yaml_not\n    File.expects(:exist?).with(@selenium_file).returns(false)\n    File.expects(:exist?).with(@config_file).returns(true)\n    IO.expects(:read).with(@config_file).returns(@config_content)\n    IO.expects(:read).with(@selenium_file).never\n    \n    assert_equal [\"test\"], SeleniumOnRailsConfig.get(:environments)\n    expected_config = {\"safari\"=>\"/Applications/Safari.app/Contents/MacOS/Safari\",\n                       \"firefox\"=>\"/Applications/Firefox.app/Contents/MacOS/firefox-bin\"} \n    \n    assert_equal(expected_config, SeleniumOnRailsConfig.get(:browsers))\n  end\n\nend"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/selenium_support_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\n\nclass SeleniumSupportTest < Test::Unit::TestCase  \n  def setup\n    @controller = SeleniumController.new\n    @controller.extend(SeleniumOnRails::PathsTestHelper)\n    ActionController::Routing::Routes.draw\n    @request    = ActionController::TestRequest.new\n    @response   = ActionController::TestResponse.new\n  end\n  \n  def test_route\n    get :support_file, :filename => 'TestRunner.html' #initialize the controller\n    assert_equal 'http://test.host/selenium/TestRunner.html', \n        @controller.url_for(:controller => 'selenium', :action => 'support_file', :filename => 'TestRunner.html')\n  end\n  \n  def test_test_runner_existance\n    get :support_file, :filename => 'TestRunner.html'\n    assert_response :success\n    assert @response.body.include?('Selenium')\n  end\n  \n  def test_default_file\n    get :support_file, :filename => ''\n    assert_redirected_to :filename => 'TestRunner.html', :test => 'tests'\n  end\n    \n  def test_missing_file\n    get :support_file, :filename => 'missing.html'\n    assert_response 404\n    assert_equal 'Not found', @response.body\n  end\n     \nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/setup_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\nrequire 'mocha'\nRAILS_ROOT = File.expand_path(File.dirname(__FILE__) + \"/\")\n\nclass SetupTest < Test::Unit::TestCase\n  def setup\n    @controller = SeleniumController.new\n    @controller.extend(SeleniumOnRails::PathsTestHelper)\n    SeleniumController.any_instance.stubs(:clear_tables).returns([])\n    SeleniumController.any_instance.stubs(:layout_path).returns(false)\n    ActionController::Routing::Routes.draw\n    @request    = ActionController::TestRequest.new\n    @response   = ActionController::TestResponse.new\n  end\n\n  def test_session_reset\n    @request.session['key'] = 'value'\n    get :setup\n    assert_nil session['key']\n    assert_response :success\n    assert_tag :content => 'The session is wiped clean.'\n  end\n  \n  def test_session_no_reset\n    @request.session['key'] = 'value'\n    get :setup, :keep_session => true\n    assert_equal 'value', session['key']\n    assert_response :success\n    assert_no_tag :content => 'The session is wiped clean.'\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/suite_renderer_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\n\nclass SuiteRendererTest < Test::Unit::TestCase\n  def setup\n    @controller = SeleniumController.new\n    @controller.extend(SeleniumOnRails::PathsTestHelper)\n    ActionController::Routing::Routes.draw\n    @request    = ActionController::TestRequest.new\n    @response   = ActionController::TestResponse.new\n    @controller.layout_override =<<END\n<html><head><title>test layout</title></head><body>\n@content_for_layout\n</body></html>\nEND\n  end\n  \n  def test_empty_suite\n    get :test_file, :testname => 'empty_suite'\n    \n    assert_response :success\n    assert_tag :tag => \"title\", :content => \"test layout\"\n    assert_tag :tag => \"script\", :attributes => {:type => \"text/javascript\"}\n    assert_tag :tag => \"select\", :attributes => {:onchange => \"openSuite(this)\"}, \n               :descendant => {:tag => \"option\", :attributes => {:value => \"header\"}, :content => \"Suites:\"},\n               :descendant => {:tag => \"option\", :attributes => {:value => \"\"}, :content => \"..\"}\n               \n    assert_tag :tag => \"table\",\n              :descendant => {:tag => \"th\", :content => \"Empty suite\"}\n  end\n\n  def test_root_suite\n    _test_root_suite ''\n  end\n  \n  def test_test_suite_html\n    #TestSuite.html is the default name the Selenium Runner tries to run\n    _test_root_suite 'TestSuite.html'\n  end\n  \n  def _test_root_suite testname\n    get :test_file, :testname => testname\n    assert_response :success\n    \n    assert_tag :tag => \"title\", :content => \"test layout\"\n    assert_tag :tag => \"script\", :attributes => {:type => \"text/javascript\"}\n    assert_tag :tag => \"select\", :attributes => {:onchange => \"openSuite(this)\"}, \n               :descendant => {:tag => \"option\", :attributes => {:value => \"header\"}, :content => \"Suites:\"},\n               :descendant => {:tag => \"option\", :attributes => {:value => \"/partials\"}, :content => \"Partials\"},\n               :descendant => {:tag => \"option\", :attributes => {:value => \"/suite_one\"}, :content => \"Suite one\"},\n               :descendant => {:tag => \"option\", :attributes => {:value => \"/suite_two\"}, :content => \"Suite two\"},\n               :descendant => {:tag => \"option\", :attributes => {:value => \"/suite_one/subsuite\"}, :content => \"Suite one.Subsuite\"}\n               \n    assert_tag :tag => \"table\",\n              :descendant => {:tag => \"th\", :content => \"All test cases\"},\n              :descendant => {:tag => \"td\", :content => \"Html\"},\n              :descendant => {:tag => \"td\", :content => \"Own layout\"},\n              :descendant => {:tag => \"td\", :content => \"Rhtml\"},\n              :descendant => {:tag => \"td\", :content => \"Rselenese\"},\n              :descendant => {:tag => \"td\", :content => \"Selenese\"},\n              :descendant => {:tag => \"td\", :content => \"Partials.All partials\"},\n              :descendant => {:tag => \"td\", :content => \"Suite one.Suite one testcase1\"},\n              :descendant => {:tag => \"td\", :content => \"Suite one.Suite one testcase2\"},\n              :descendant => {:tag => \"td\", :content => \"Suite one.Subsuite.Suite one subsuite testcase\"},\n              :descendant => {:tag => \"td\", :content => \"Suite two.Suite two testcase\"}\n  end\n\n  def test_suite_one\n    get :test_file, :testname => 'suite_one'\n    \n    assert_response :success   \n    assert_tag :tag => \"title\", :content => \"test layout\"\n    assert_tag :tag => \"script\", :attributes => {:type => \"text/javascript\"}\n    assert_tag :tag => \"select\", :attributes => {:onchange => \"openSuite(this)\"}, \n               :descendant => {:tag => \"option\", :attributes => {:value => \"header\"}, :content => \"Suites:\"},\n               :descendant => {:tag => \"option\", :attributes => {:value => \"\"}, :content => \"..\"},\n               :descendant => {:tag => \"option\", :attributes => {:value => \"/suite_one/subsuite\"}, :content => \"Subsuite\"}\n               \n    assert_tag :tag => \"table\",\n              :descendant => {:tag => \"th\", :content => \"Suite one\"},\n              :descendant => {:tag => \"td\", :content => \"Suite one testcase1\"},\n              :descendant => {:tag => \"td\", :content => \"Suite one testcase2\"},\n              :descendant => {:tag => \"td\", :content => \"Subsuite.Suite one subsuite testcase\"}\n  end\n  \n  def test_sub_suite\n    get :test_file, :testname => 'suite_one/subsuite'\n    \n    assert_response :success\n    assert_tag :tag => \"title\", :content => \"test layout\"\n    assert_tag :tag => \"script\", :attributes => {:type => \"text/javascript\"}\n    assert_tag :tag => \"select\", :attributes => {:onchange => \"openSuite(this)\"}, \n               :descendant => {:tag => \"option\", :attributes => {:value => \"header\"}, :content => \"Suites:\"},\n               :descendant => {:tag => \"option\", :attributes => {:value => \"/suite_one\"}, :content => \"..\"}\n               \n    assert_tag :tag => \"table\",\n              :descendant => {:tag => \"th\", :content => \"Subsuite\"},\n              :descendant => {:tag => \"td\", :content => \"Suite one subsuite testcase\"}\n  end\n  \n  def test_missing_tests_directory\n    def @controller.selenium_tests_path\n      File.join(File.dirname(__FILE__), 'invalid')\n    end\n    get :test_file, :testname => ''\n    assert_response 404\n    assert_equal \"Did not find the Selenium tests path (#{File.join(File.dirname(__FILE__), 'invalid')}). Run script/generate selenium\",  @response.body\n  end\n  \nend\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/switch_environment_controller_test.rb",
    "content": "require File.dirname(__FILE__) + '/test_helper'\nrequire 'mocha'\nrequire 'controllers/switch_environment_controller'\n\nclass SwitchEnvironmentControllerTest < Test::Unit::TestCase\n\n  def setup\n    @config = mock()\n    setup_controller_test(SwitchEnvironmentController)\n  end\n  \n  def test_index\n    SeleniumOnRailsConfig.expects(:get).with(:environments).returns(\"hello dolly\")\n    get :index\n    assert @response.body.include?('hello dolly')\n  end\nend"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/test_builder_functions_authortest.rb",
    "content": "#----------------------------------------------------------------------------\n# This is a *_authortest.rb file, which means it will only run if you run:\n# rake alltests\n# It is not run as part of the standard test suite, as it's of limited\n# value unless you're actually developing Selenium On Rails.\n\n#----------------------------------------------------------------------------\n# The test_builder_actions.rb and test_builder_accessors.rb files do not\n# necessarily contain all the functions which are available in Selenium.\n# Here we use the iedoc.xml file to find functions which might need to be\n# added to the files.  Ultimately it would be great not to need to do this\n# process manually, however, this is a temporary step toward improving\n# function parity.\n\nrequire File.dirname(__FILE__) + '/test_helper'\n\nclass TestTheTestBuilderFunctions < Test::Unit::TestCase\n\n  def test_functions_in_iedoc_are_supported\n\n    base_path = File.dirname(__FILE__) + '/../'\n\n    iedoc_file = File.read base_path + \"selenium-core/iedoc.xml\"\n    test_builder_actions_file = File.read base_path + \"lib/selenium_on_rails/test_builder_actions.rb\"\n    test_builder_accessors_file = File.read base_path + \"lib/selenium_on_rails/test_builder_accessors.rb\"\n\n    # Don't include any deprecated functions\n    deprecated_functions = %W{dragdrop}\n\n    iedoc_functions = iedoc_file.scan(/function *name *= *[\"']([a-zA-Z]+)[\"']/)\\\n                                .sort.collect{|x| x[0]} - deprecated_functions\n\n    for function_name in iedoc_functions\n\n      function_name.gsub!(/[A-Z]/) { |s| \"_\" + s.downcase }\n      \n      test_description = \"The function listed in the iedoc.xml file, \" +\n                         \"#{function_name}, exists in the test_builder files\" \n      \n      if test_builder_actions_file.match(/def *#{function_name}/) ||\n          test_builder_accessors_file.match(/(?:def *|tt>)#{function_name}/)\n        assert true, test_description\n      else\n        assert false, test_description\n      end\n    end\n    \n  end\n  \nend\n\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test/test_helper.rb",
    "content": "ENV[\"RAILS_ENV\"] = \"test\"\nRAILS_ROOT = \"test\" unless defined?(RAILS_ROOT)\n$: << File.expand_path(File.dirname(__FILE__) + \"/../lib\")\n\nrequire 'rubygems'\ngem 'activesupport'\nrequire 'active_support'\n\ngem 'actionpack'\nrequire 'action_view/template_handler'\nrequire 'action_view/template_handlers/builder'\nrequire 'action_view/template_handlers/erb'\nrequire 'action_view/template_handlers/rjs'\nrequire 'action_view/base'\nrequire 'action_view/partials'\nrequire 'action_view/template_error'\nrequire 'action_controller'\n\nrequire 'selenium_on_rails/suite_renderer'\nrequire 'selenium_on_rails/fixture_loader'\nrequire 'selenium_helper'\nrequire 'controllers/selenium_controller'\nrequire File.expand_path(File.dirname(__FILE__) + \"/../routes\")\nrequire 'action_controller/test_process'\n\nSeleniumController.append_view_path File.expand_path(File.dirname(__FILE__))\n\ndef setup_controller_test(controller)\n  @controller = controller.new\n  ActionController::Routing::Routes.draw\n  @request    = ActionController::TestRequest.new\n  @response   = ActionController::TestResponse.new\nend\n\n\nclass SeleniumController\n  attr_accessor :layout_override\n  # Re-raise errors caught by the controller.\n  def rescue_action e\n    raise e\n  end\n      \n  def render options = nil\n    if override_layout? options\n      options[:layout] = false\n      super options\n      return response.body = @layout_override.gsub('@content_for_layout', response.body)\n    end\n    super options\n  end\n  \n  private\n    def override_layout? options\n      return false unless @layout_override\n      if options[:action] or options[:template]\n        options[:layout] != false #for action and template the default layout is used if not explicitly disabled\n      else\n        not [nil, false].include? options[:layout] #otherwise a layout has to be specified\n      end\n    end\n\nend\n\nclass Test::Unit::TestCase\n  def assert_text_equal expected, actual\n    assert_equal clean_text(expected), clean_text(actual)\n  end\n  \n  def clean_text text\n    text.gsub(\"\\t\", '  ').gsub(\"\\r\", '').gsub(\"\\n\", '').gsub(/ *</, '<')\n  end\n  \nend\n\nmodule SeleniumOnRails::PathsTestHelper\n  def selenium_tests_path\n    File.expand_path(File.dirname(__FILE__) + '/../test_data')\n  end\nend\n\nclass TestView < ActionView::Base\n  include SeleniumOnRails::PartialsSupport\n  \n  # alias_method :render_partial_without_override, :render_partial\n  # def render_partial partial_path = default_template_name, object = nil, local_assigns = nil, status = nil\n  #   if @override\n  #     partial = render :inline => @override, :type => @override_type, :locals => local_assigns\n  #     extract_commands_from_partial partial\n  #   else\n  #     render_partial_without_override partial_path, object, local_assigns, status\n  #   end\n  # end\n  # \n  # def override_partial partial, type\n  #   @override, @override_type = partial, type\n  #   result = yield\n  #   @override, @override_type = nil, nil\n  #   result\n  # end\n  \nend"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/_partial.rsel",
    "content": "assert_title \"Partial from #{source}\""
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/backup.html~",
    "content": ""
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/own_layout.html",
    "content": "<html>\n\t<head>\n\t\t<title>Test case with own layout</title>\n\t\t<style type=\"text/css\"> body { background-color: #ccc; } </style>\n\t</head>\n\t<body>\n\t\t<table>\n\t\t\t<tr><th colspan=\"3\">Test own layout</th></tr>\n\t\t\t<tr><td>open</td><td>/selenium/setup</td><td>&nbsp;</td></tr>\n\t\t</table>\n\t</body>\n</html>\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/partials/_html.html",
    "content": "<h1>This should never be visible!</h1>\n<table>\n\t<tr><th colspan=\"3\">HTML partial</th></tr>\n\t<tr><td>type</td><td>partial</td><td>HTML partial</td></tr>\n</table>\n<p>Neither should this!</p>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/partials/_nesting.rsel",
    "content": "type 'nesting', 'Nesting partial'\ninclude_partial 'partials/rsel', :hello => hello.reverse"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/partials/_rhtml.html.erb",
    "content": "<h1>This should never be visible!</h1>\n<table>\n\t<tr><th colspan=\"3\">RHTML partial</th></tr>\n\t<tr><td>type</td><td><%= hello %></td><td>RHTML partial</td></tr>\n</table>\n<p>Neither should this!</p>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/partials/_rsel.rsel",
    "content": "type hello, 'RSelenese partial'\n"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/partials/_sel.sel",
    "content": "h1. This should not be visible!\n\n|type|partial|Selenese partial|\n\np. Neither should this!"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/partials/all_partials.rsel",
    "content": "include_partial 'partial', :source => title\n['html', 'rhtml',  'sel', 'rsel'].each do |format|\n  include_partial \"partials/#{format}\", :hello => 'world'\nend\ninclude_partial 'partials/nesting', :hello => 'world'"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/rhtml.html.erb",
    "content": "<table>\n  <tr><th colspan=\"3\"><%= @page_title %></th></tr>\n<% for page in ['/fi', '/fo', '/fum'] -%>\n  <tr><td>open</td><td><%= page %></td><td>&nbsp;</td></tr>\n<% end -%>\n  <%= render :partial => 'partial', :locals => {:source => 'RHTML'} %>\n</table>"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/rselenese.rsel",
    "content": "setup\nsetup :keep_session\ntest.setup :fixtures => :all\nsetup :fixtures => [:foo, 'bar']\nsetup :clear_tables => [:foo, :bar], :fixtures => :all\nassert_absolute_location :controller => 'selenium', :action => 'setup' #urls must be tested with a controller\nassert_title @view.controller.controller_name #make sure we can access the view easily\ninclude_partial 'partial', :source => 'RSelenese'"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/selenese.sel",
    "content": "Selenese *support*\n\n|open|/selenium/setup|\n|goBack|\n|includePartial|partial|source=Selenese|\n  \nworks."
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/suite_one/subsuite/suite_one_subsuite_testcase.sel",
    "content": "|open|/|"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/suite_one/suite_one_testcase1.sel",
    "content": "|open|/|"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/suite_one/suite_one_testcase2.sel",
    "content": "|open|/|"
  },
  {
    "path": "vendor/plugins/selenium-on-rails/test_data/suite_two/suite_two_testcase.sel",
    "content": "|open|/|"
  },
  {
    "path": "vendor/plugins/simple-private-messages/MIT-LICENSE",
    "content": "Copyright (c) 2008 [name of plugin creator]\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "vendor/plugins/simple-private-messages/README.rdoc",
    "content": "= Simple Private Messages\n\nThis plugin provides basic private messaging functionality between the users\nof a site. It's not big on features but the idea is that it's nice and simple\nand light on resources.\n\nIt's not bound to specific model names and plays nice with will_paginate.\n\n= Setup\n\nFirst create the private message model by running the private_message_model\ngenerator, passing two parameters - the name you want to use for the Message\nmodel and the name of the User model.\n\nFor all examples in the readme, we will use Message and User.\n\n  ./script/generate private_message_model Message User\n\nNow add the following entry to the model which will have the messages\n\n  has_private_messages\n\nIf you have used anything other than \"Message\", you will have to pass the\ncorrect class name along as :class_name.\n\nThat's it.\n\n= Usage\n\nExamples assume you're using Restful Authentication or AAA, with a user model\nof User and message model of Message.\n\n== Creating / sending a message:\n\n  frank = User.find_by_login(\"frank\")\n  george = User.find_by_login(\"george\")\n\n  message = Message.new\n  message.subject = \"Happy Festivus, son\"\n  message.body = \"It's time for the Feats of Strength.\"\n  message.sender = frank\n  message.recipient = george\n  message.save\n\n== Reading a message\n\n  message = Message.read(id, user)\n  \nReturns the message of the chosen id and ensures the passed user is either the\nsender or the recipient. If unread, it checks to see if the passed user is the\nrecipient and if so marks the read_at timestamp.\n\nYou can also check if a message has been read with the following:\n\n  message.read?\n\n== Retrieving a user's received mail\n\n  newman = User.find_by_login(\"newman\")\n  newman.received_messages\n\nThe following will return Newman's number of unread messages:\n\n  newman.unread_message_count\n  \nOr the following for true or false on whether there are unread messages:\n\n  newman.unread_messages?\n  \n== Retrieving a user's sent mail\n\n  newman = User.find_by_login(\"newman\")\n  newman.sent_messages\n  \n== Custom finds\n\n  newman.sent_messages.find(:all,\n                          :conditions => [\"read_at < ?\", 2.days.ago],\n                          :limit => 20,\n                          :order => \"created_at ASC\")\n\n== Deleting a message\n\n  newman = User.find_by_login(\"newman\")\n  message = newman.received_messages.find(3)\n  message.mark_deleted(newman)\n  \nThis will look at a message and mark it read by the sender or recipient,\nbased on whichever Newman is. It now will no longer appear in Newman's\nmessages.\n\n  kramer = User.find_by_login(\"kramer\")\n  message = kramer.sent_messages.find(3)\n  message.mark_deleted\n\nNow that both sender and recipient have marked the message deleted, it\ngets destroyed. Should a message be sent to oneself, it will be deleted\nin one step due to the sender and recipient being the same.\n\n= Scaffold\n\nA generator is included to create a basic controller and set of views.\n\nRun the private_message_scaffold generator with the same options as before:\n\n  ./script/generate private_message_scaffold Message User\n\nThe controller will be named with the pluralised version of the model name.\n\nAfter that you need to add the resource to your routes.rb as a nested resource\nof the users controller, with a collection for the delete_selected action.\n\n  map.resources :users do |users|\n    users.resources :messages, :collection => { :delete_selected => :post }\n  end\n\nThen uncomment the entry at the top of the message model to establish the\n:to accessor.\n\nYou should now have working messaging.\n\n= Tests\n\nUnit tests are provided for the model extensions but not for the generated\nscaffold. Running these requires sqlite3.\n\n=== Credits\n\nTesting functionality for creating dedicated models / loading of a custom\nschema taken from acts_as_taggable_on_steroids.\n\n=== Bug reports / suggestions\n\nwww.professionalnerd.com / \"jonYADAYADAprofessionalnerd.com\".gsub(/YADAYADA/, \"@\")\n\n=== License\n\nCopyright (c) 2007 Jon Gilbraith released under the MIT license\nhttp://en.wikipedia.org/wiki/MIT_License"
  },
  {
    "path": "vendor/plugins/simple-private-messages/Rakefile",
    "content": "require 'rake'\nrequire 'rake/testtask'\nrequire 'rake/rdoctask'\n\ndesc 'Default: run unit tests.'\ntask :default => :test\n\ndesc 'Test the simple_private_messages plugin.'\nRake::TestTask.new(:test) do |t|\n  t.libs << 'lib'\n  t.pattern = 'test/**/*_test.rb'\n  t.verbose = true\nend\n\ndesc 'Generate documentation for the simple_private_messages plugin.'\nRake::RDocTask.new(:rdoc) do |rdoc|\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title    = 'SimplePrivateMessages'\n  rdoc.options << '--line-numbers' << '--inline-source'\n  rdoc.rdoc_files.include('README')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n"
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_model/USAGE",
    "content": "Description:\n    Creates the private message model and migration for use with \n    the simple_private_messages plugin.\n\n    Run the migration, passing the name of the model to be created.\n\nExample:\n  \n    ./script/generate private_message_model Message\n\nFurther steps are involved after this, see the README for full details."
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_model/private_message_model_generator.rb",
    "content": "class PrivateMessageModelGenerator < Rails::Generator::NamedBase\n\n  attr_reader :singular_camel_case_name, :plural_camel_case_name, :singular_lower_case_name, :plural_lower_case_name\n  attr_reader :singular_camel_case_parent, :plural_camel_case_parent, :singular_lower_case_parent, :plural_lower_case_parent\n\n  def initialize(runtime_args, runtime_options = {})\n    super\n    \n    @singular_camel_case_name = @name.singularize.camelize\n    @plural_camel_case_name = @name.pluralize.camelize\n    @singular_lower_case_name = @name.singularize.underscore\n    @plural_lower_case_name = @name.pluralize.underscore\n\n    @parent_name = args.shift || 'User'\n    @singular_camel_case_parent = @parent_name.singularize.camelize\n    @plural_camel_case_parent = @parent_name.pluralize.camelize\n    @singular_lower_case_parent = @parent_name.singularize.underscore\n    @plural_lower_case_parent = @parent_name.pluralize.underscore    \n  end\n  \n  def manifest\n    record do |m|\n      m.directory \"app/models\"\n      m.template \"model.rb\", \"app/models/#{singular_lower_case_name}.rb\"\n\n      m.migration_template \"migration.rb\", \"db/migrate\", :assigns => {\n        :migration_name => \"Create#{plural_camel_case_name}\"\n      }, :migration_file_name => \"create_#{plural_lower_case_name}\"\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_model/templates/migration.rb",
    "content": "class <%= \"Create#{plural_camel_case_name}\" %> < ActiveRecord::Migration\n  def self.up\n    create_table :<%= plural_lower_case_name %> do |t|\n      t.integer :sender_id, :recipient_id\n      t.boolean :sender_deleted, :recipient_deleted, :default => 0\n      t.string :subject\n      t.text :body\n      t.datetime :read_at\n      t.timestamps\n    end\n  end\n\n  def self.down\n    drop_table <%= plural_lower_case_name %>\n  end\nend"
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_model/templates/model.rb",
    "content": "class <%= singular_camel_case_name %> < ActiveRecord::Base\n\n  is_private_message<% unless singular_camel_case_parent == \"User\" %> :class_name => \"<%= \"#{singular_camel_case_parent}\" %>\"<% end %>\n  \n  # The :to accessor is used by the scaffolding,\n  # uncomment it if using it or you can remove it if not\n  #attr_accessor :to\n  \nend"
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_scaffold/USAGE",
    "content": "Description:\n    Creates a basic but working controller and set of views for private\n    messages.\n\n    Run the following generator, passing the name of the model you created.\n\nExample:\n  \n    ./script/generate private_message_scaffold Message\n\nFurther steps are involved after this, see the README for full details."
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_scaffold/private_message_scaffold_generator.rb",
    "content": "class PrivateMessageScaffoldGenerator < Rails::Generator::NamedBase\n  \n  attr_reader :singular_camel_case_name, :plural_camel_case_name, :singular_lower_case_name, :plural_lower_case_name\n  attr_reader :singular_camel_case_parent, :plural_camel_case_parent, :singular_lower_case_parent, :plural_lower_case_parent\n\n  def initialize(runtime_args, runtime_options = {})\n    super\n    \n    @singular_camel_case_name = @name.singularize.camelize\n    @plural_camel_case_name = @name.pluralize.camelize\n    @singular_lower_case_name = @name.singularize.underscore\n    @plural_lower_case_name = @name.pluralize.underscore\n\n    @parent_name = args.shift || 'User'\n    @singular_camel_case_parent = @parent_name.singularize.camelize\n    @plural_camel_case_parent = @parent_name.pluralize.camelize\n    @singular_lower_case_parent = @parent_name.singularize.underscore\n    @plural_lower_case_parent = @parent_name.pluralize.underscore    \n  end\n  \n  def manifest\n    record do |m|\n      m.directory \"app/controllers\"\n      m.template \"controller.rb\", \"app/controllers/#{@plural_lower_case_name}_controller.rb\"\n\n      m.directory \"app/views\"\n      m.directory \"app/views/#{@plural_lower_case_name}\"\n      m.template \"view_index.html.erb\", \"app/views/#{@plural_lower_case_name}/index.html.erb\"\n      m.template \"view_index_inbox.html.erb\", \"app/views/#{@plural_lower_case_name}/_inbox.html.erb\"\n      m.template \"view_index_sent.html.erb\", \"app/views/#{@plural_lower_case_name}/_sent.html.erb\"\n      m.template \"view_show.html.erb\", \"app/views/#{@plural_lower_case_name}/show.html.erb\"\n      m.template \"view_new.html.erb\", \"app/views/#{@plural_lower_case_name}/new.html.erb\"\n    end\n  end\nend\n"
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_scaffold/templates/controller.rb",
    "content": "class <%= plural_camel_case_name %>Controller < ApplicationController\n  \n  before_filter :set_user\n  \n  def index\n    if params[:mailbox] == \"sent\"\n      @<%= plural_lower_case_name %> = @<%= singular_lower_case_parent %>.sent_messages\n    else\n      @<%= plural_lower_case_name %> = @<%= singular_lower_case_parent %>.received_messages\n    end\n  end\n  \n  def show\n    @<%= singular_lower_case_name %> = <%= singular_camel_case_name %>.read(params[:id], current_user)\n  end\n  \n  def new\n    @<%= singular_lower_case_name %> = <%= singular_camel_case_name %>.new\n\n    if params[:reply_to]\n      @reply_to = @<%= singular_lower_case_parent %>.received_messages.find(params[:reply_to])\n      unless @reply_to.nil?\n        @<%= singular_lower_case_name %>.to = @reply_to.sender.login\n        @<%= singular_lower_case_name %>.subject = \"Re: #{@reply_to.subject}\"\n        @<%= singular_lower_case_name %>.body = \"\\n\\n*Original message*\\n\\n #{@reply_to.body}\"\n      end\n    end\n  end\n  \n  def create\n    @<%= singular_lower_case_name %> = <%= singular_camel_case_name %>.new(params[:<%= singular_lower_case_name %>])\n    @<%= singular_lower_case_name %>.sender = @<%= singular_lower_case_parent %>\n    @<%= singular_lower_case_name %>.recipient = <%= singular_camel_case_parent %>.find_by_login(params[:<%= singular_lower_case_name %>][:to])\n\n    if @<%= singular_lower_case_name %>.save\n      flash.now[:success] = \"Message sent\"\n      redirect_to user_<%= plural_lower_case_name %>_path(@<%= singular_lower_case_parent %>)\n    else\n      render :action => :new\n    end\n  end\n  \n  def delete_selected\n    if request.post?\n      if params[:delete]\n        params[:delete].each { |id|\n          @<%= singular_lower_case_name %> = <%= singular_camel_case_name %>.find(:first, :conditions => [\"<%= plural_lower_case_name %>.id = ? AND (sender_id = ? OR recipient_id = ?)\", id, @<%= singular_lower_case_parent %>, @<%= singular_lower_case_parent %>])\n          @<%= singular_lower_case_name %>.mark_deleted(@<%= singular_lower_case_parent %>) unless @<%= singular_lower_case_name %>.nil?\n        }\n        flash.now[:success] = \"Messages deleted\"\n      end\n      redirect_to user_<%= singular_lower_case_name %>_path(@<%= singular_lower_case_parent %>, @<%= plural_lower_case_name %>)\n    end\n  end\n  \n  private\n    def set_user\n      @<%= singular_lower_case_parent %> = User.find(params[:<%= singular_lower_case_parent %>_id])\n    end\nend"
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_scaffold/templates/view_index.html.erb",
    "content": "<%% form_tag delete_selected_user_<%= plural_lower_case_name %>_path(@<%= singular_lower_case_parent %>) do %>\n\t<%% if params[:mailbox] == \"sent\" %>\n\t\t\t<%%= render :partial => \"sent\" %>\n\t<%% else %>\n\t\t\t<%%= render :partial => \"inbox\" %>\n\t\t<%% end %>\n<%% end %>"
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_scaffold/templates/view_index_inbox.html.erb",
    "content": "<h2>Inbox</h2>\n<table>\n\t<tr>\n\t\t<th>Del?</th>\n\t\t<th>Sent</th>\n\t\t<th>Sender</th>\n\t\t<th>Sent</th>\n\t</tr>\n\t<%% if @<%= plural_lower_case_name %>.size == 0 %>\n\t\t<tr>\n\t\t\t<td colspan=\"4\">\n\t\t\t\tNo messages\n\t\t\t</td>\n\t\t</tr>\n\t<%% else %>\n\t\t<%% for <%= singular_lower_case_name %> in @<%= plural_lower_case_name %> %>\n\t\t\t<tr>\n\t\t\t\t<td><%%= check_box_tag \"delete[]\", <%= singular_lower_case_name %>.id %></td>\n\t\t\t\t<td>\n\t\t\t\t\t<%% if <%= singular_lower_case_name %>.read? %>\n\t\t\t\t\t  <%%= link_to h(<%= singular_lower_case_name %>.subject), user_<%= singular_lower_case_name %>_path(@<%= singular_lower_case_parent %>, <%= singular_lower_case_name %>) %>\n\t\t\t\t\t<%% else %>\n\t\t\t\t\t  <%%= link_to \"#{h(<%= singular_lower_case_name %>.subject)} (unread)\", user_<%= singular_lower_case_name %>_path(@<%= singular_lower_case_parent %>, <%= singular_lower_case_name %>) %>\n\t\t\t\t\t<%% end %>\n\t\t\t\t</td>\n\t\t\t\t<td><%%= link_to h(<%= singular_lower_case_name %>.sender.login), user_path(@<%= singular_lower_case_parent %>) %></td>\n\t\t    <td><%%=h <%= singular_lower_case_name %>.created_at.to_s(:long) %></td>\n\t\t\t</tr>\n\t\t<%% end %>\n\t\t<tr>\n\t\t\t<td colspan=\"4\">\n\t\t\t\t<%%= submit_tag \"Delete\" %>\n\t\t\t</td>\n\t\t</tr>\n\t<%% end %>\n</table>\n<%%= link_to \"Sent\", user_<%= plural_lower_case_name %>_path(@<%= singular_lower_case_parent %>, :mailbox => :sent)%> |\n<%%= link_to \"Compose\", new_user_<%= singular_lower_case_name %>_path(@<%= singular_lower_case_parent %>)%>"
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_scaffold/templates/view_index_sent.html.erb",
    "content": "<h2>Sent</h2>\n<table>\n\t<tr>\n\t\t<th>Del?</th>\n\t\t<th>Subject</th>\n\t\t<th>To</th>\n\t\t<th>Sent</th>\n\t</tr>\n\t<%% if @<%= plural_lower_case_name %>.size == 0 %>\n\t\t<tr>\n\t\t\t<td colspan=\"4\">\n\t\t\t\tNo messages\n\t\t\t</td>\n\t\t</tr>\n\t<%% else %>\n\t\t<%% for <%= singular_lower_case_name %> in @<%= plural_lower_case_name %> %>\n\t\t\t<tr>\n\t\t\t\t<td><%%= check_box_tag \"delete[]\", <%= singular_lower_case_name %>.id %></td>\n\t\t\t\t<td><%%= link_to h(<%= singular_lower_case_name %>.subject), user_<%= singular_lower_case_name %>_path(@<%= singular_lower_case_parent %>, <%= singular_lower_case_name %>) %></td>\n  \t\t\t<td><%%= link_to h(<%= singular_lower_case_name %>.recipient.login), user_path(@<%= singular_lower_case_parent %>) %></td>\n\t\t\t  <td><%%=h <%= singular_lower_case_name %>.created_at.to_s(:long) %></td>\n\t\t\t</tr>\n\t\t<%% end %>\n\t\t<tr>\n\t\t\t<td colspan=\"4\">\n\t\t\t\t<%%= submit_tag \"Delete\" %>\n\t\t\t</td>\n\t\t</tr>\n \t<%% end %>\n</table>\n<%%= link_to \"Inbox\", user_<%= plural_lower_case_name %>_path(@<%= singular_lower_case_parent %>)%>"
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_scaffold/templates/view_new.html.erb",
    "content": "<%% form_for @<%= singular_lower_case_name %>, :url => user_<%= plural_lower_case_name %>_path(@user) do |f| %>\n  <p>\n    To:<br />\n\t\t<%%= f.text_field :to %>\n\t\t<%%= error_message_on @<%= singular_lower_case_name %>, :to %>\n  </p>\n  <p>\n    Subject:<br />\n    <%%= f.text_field :subject %>\n    <%%= error_message_on @<%= singular_lower_case_name %>, :subject %>\n    </p>\n    <p>\n      Message<br />\n      <%%= f.text_area :body %>\n\t\t\t<%%= error_message_on @<%= singular_lower_case_name %>, :body %>\n    </p>\n    <p>\n      <%%= submit_tag \"Send\" %>\n    </p>\n<%% end %>"
  },
  {
    "path": "vendor/plugins/simple-private-messages/generators/private_message_scaffold/templates/view_show.html.erb",
    "content": "<p><strong>From:</strong> <%%= @<%= singular_lower_case_name %>.sender == @user ? link_to(\"You\", user_path(@user)) : link_to(h(@<%= singular_lower_case_name %>.sender.login), user_path(@user)) %></p>\n<p><strong>Received:</strong> <%%= @<%= singular_lower_case_name %>.created_at.to_s(:long) %></p>\n<p><strong>To:</strong> <%%= @<%= singular_lower_case_name %>.recipient == @user ? link_to(\"You\", user_path(@user)) : link_to(h(@<%= singular_lower_case_name %>.recipient.login), user_path(@user)) %></p>\n<p>\n  <strong>Message</strong><br />\n  <%%=h @<%= singular_lower_case_name %>.body %>\n</p>\n<p>\n  <%% if @<%= singular_lower_case_name %>.recipient == @user %>\n\t  <%%= link_to \"Reply\", new_user_<%= singular_lower_case_name %>_path(@user, :reply_to => @<%= singular_lower_case_name %>) %> |\n  <%% end %>\n  <%%= link_to \"Inbox\", user_<%= plural_lower_case_name %>_path(@user)%>\n</p>"
  },
  {
    "path": "vendor/plugins/simple-private-messages/init.rb",
    "content": "ActiveRecord::Base.send(:include, Professionalnerd::SimplePrivateMessages::HasPrivateMessagesExtensions)\nActiveRecord::Base.send(:include, Professionalnerd::SimplePrivateMessages::PrivateMessageExtensions)"
  },
  {
    "path": "vendor/plugins/simple-private-messages/lib/professionalnerd/simple_private_messages/has_private_messages_extensions.rb",
    "content": "module Professionalnerd #:nodoc:\n  module SimplePrivateMessages #:nodoc:\n    module HasPrivateMessagesExtensions #:nodoc:\n      def self.included(base) #:nodoc:\n        base.extend ActMethods\n      end \n\n      module ActMethods\n        # Sets up a model have private messages, defining the child class as specified in :class_name (typically \"Messages\").\n        # Provided the following instance messages:\n        # *  <tt>sent_messages</tt> - returns a collection of messages for which this object is the sender.\n        # *  <tt>received_messages</tt> - returns a collection of messages for which this object is the recipient.\n        def has_private_messages(options = {})\n          options[:class_name] ||= 'Message'\n          \n          unless included_modules.include? InstanceMethods\n            class_inheritable_accessor :options\n            table_name = options[:class_name].constantize.table_name\n            \n            has_many :sent_messages,\n                     :class_name => options[:class_name],\n                     :foreign_key => 'sender_id',\n                     :order => \"#{table_name}.created_at DESC\",\n                     :conditions => [\"#{table_name}.sender_deleted = ?\", false]\n\n            has_many :received_messages,\n                     :class_name => options[:class_name],\n                     :foreign_key => 'recipient_id',\n                     :order => \"#{table_name}.created_at DESC\",\n                     :conditions => [\"#{table_name}.recipient_deleted = ?\", false]\n\n            extend ClassMethods \n            include InstanceMethods \n          end \n          self.options = options\n        end \n      end \n\n      module ClassMethods #:nodoc:\n        # None yet...\n      end\n\n      module InstanceMethods\n        # Returns true or false based on if this user has any unread messages\n        def unread_messages?\n          unread_message_count > 0 ? true : false\n        end\n        \n        # Returns the number of unread messages for this user\n        def unread_message_count\n          eval options[:class_name] + '.count(:conditions => [\"recipient_id = ? AND read_at IS NULL\", self])'\n        end\n      end \n    end\n  end\nend \n"
  },
  {
    "path": "vendor/plugins/simple-private-messages/lib/professionalnerd/simple_private_messages/private_message_extensions.rb",
    "content": "module Professionalnerd # :nodoc:\n  module SimplePrivateMessages # :nodoc:\n    module PrivateMessageExtensions\n      def self.included(base) # :nodoc:\n        base.extend ActMethods\n      end \n\n      module ActMethods\n        # Sets up a model to be a private message model, defining the parent class as specified in :class_name (typically \"User\")\n        # Provides the following instance methods:\n        # *  <tt>sender</tt> - the sender of the message.\n        # *  <tt>recipient</tt> - the recipient of the message.\n        #\n        # Also adds a named scopes of :read and :unread, to get, well, read and unread messages.\n        def is_private_message(options = {})\n          options[:class_name] ||= 'User'\n          \n          unless included_modules.include? InstanceMethods \n            belongs_to :sender,\n                       :class_name => options[:class_name],\n                       :foreign_key => 'sender_id'\n            belongs_to :recipient,\n                       :class_name => options[:class_name],\n                       :foreign_key => 'recipient_id'\n\n            extend ClassMethods \n            include InstanceMethods \n          end \n\n          named_scope :read, :conditions => \"read_at IS NOT NULL\"\n          named_scope :unread, :conditions => \"read_at IS NULL\"\n        end \n      end \n\n      module ClassMethods\n        # Ensures the passed user is either the sender or the recipient then returns the message.\n        # If the reader is the recipient and the message has yet not been read, it marks the read_at timestamp.\n        def read_and_get(id, reader)\n          message = find(id, :conditions => [\"sender_id = ? OR recipient_id = ?\", reader, reader])\n          if message.read_at.nil? && reader == message.recipient\n            message.read_at = Time.now\n            message.save!\n          end\n          message\n        end\n      end\n\n      module InstanceMethods\n        # Returns true or false value based on whether the a message has been read by it's recipient.\n        def read?\n          self.read_at.nil? ? false : true\n        end\n\n        # Marks a message as deleted by either the sender or the recipient, which ever the user that was passed is.\n        # Once both have marked it deleted, it is destroyed.\n        def mark_deleted(user)\n          self.sender_deleted = true if self.sender == user\n          self.recipient_deleted = true if self.recipient == user\n          self.sender_deleted && self.recipient_deleted ? self.destroy : save!\n        end\n      end \n    end\n  end\nend \n"
  },
  {
    "path": "vendor/plugins/simple-private-messages/lib/professionalnerd/simple_private_messages/tasks/simple_private_messages_tasks.rake",
    "content": "# desc \"Explaining what the task does\"\n# task :simple_private_messages do\n#   # Task goes here\n# end\n"
  },
  {
    "path": "vendor/plugins/simple-private-messages/test/database.yml",
    "content": "sqlite3:\n  :adapter: sqlite3\n  :database: ':memory:'"
  },
  {
    "path": "vendor/plugins/simple-private-messages/test/fixtures/message.rb",
    "content": "class Message < ActiveRecord::Base\n  is_private_message\nend"
  },
  {
    "path": "vendor/plugins/simple-private-messages/test/fixtures/user.rb",
    "content": "class User < ActiveRecord::Base\n  has_private_messages\nend"
  },
  {
    "path": "vendor/plugins/simple-private-messages/test/schema.rb",
    "content": "ActiveRecord::Schema.define(:version => 2) do\n\n  create_table \"messages\", :force => true do |t|\n    t.integer  \"sender_id\"\n    t.integer  \"recipient_id\"\n    t.boolean  \"sender_deleted\",    :default => false\n    t.boolean  \"recipient_deleted\", :default => false\n    t.string   \"subject\"\n    t.text     \"body\"\n    t.datetime \"read_at\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\n  create_table \"users\", :force => true do |t|\n    t.string   \"login\"\n    t.datetime \"created_at\"\n    t.datetime \"updated_at\"\n  end\n\nend"
  },
  {
    "path": "vendor/plugins/simple-private-messages/test/test_helper.rb",
    "content": "require File.dirname(__FILE__) + '/../../../../config/environment'\nrequire File.dirname(__FILE__) + '/../lib/professionalnerd/simple_private_messages/has_private_messages_extensions'\nrequire File.dirname(__FILE__) + '/../lib/professionalnerd/simple_private_messages/private_message_extensions'\nbegin require 'redgreen'; rescue LoadError; end\n\n#ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/debug.log')\nActiveRecord::Base.configurations = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))\nActiveRecord::Base.establish_connection(ENV['DB'] || 'sqlite3')\nfixture_path = File.dirname(__FILE__) + '/fixtures/'\nDependencies.load_paths.insert(0, fixture_path)\nload(File.dirname(__FILE__) + '/schema.rb')\n\nclass Test::Unit::TestCase\n  \n  def create_user(options = {})\n    return User.create({:login => \"Dolores\"}.merge(options))\n  end\n\n  def create_message(options = {})\n    return Message.create({:sender => @george,\n                           :recipient => @jerry,\n                           :subject => \"Frolf, Jerry!\",\n                           :body => \"Frolf, Jerry! Frisbee golf!\"}.merge(options))\n  end\n  \nend"
  },
  {
    "path": "vendor/plugins/simple-private-messages/test/unit/message_model.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass MessageModelTest < Test::Unit::TestCase\n\n  def setup\n    @jerry = create_user(:login => \"jerry\")\n    @george = create_user(:login => \"george\")\n    @message = create_message\n  end\n\n  def test_create_message\n    @message = create_message\n    \n    assert_equal @message.sender, @george\n    assert_equal @message.recipient, @jerry\n    assert_equal @message.subject, \"Frolf, Jerry!\"\n    assert_equal @message.body, \"Frolf, Jerry! Frisbee golf!\"\n    assert @message.read_at.nil?\n  end\n\n  def test_read_returns_message\n    assert_equal @message, Message.read(@message, @george)\n  end\n\n  def test_read_records_timestamp\n    assert !@message.nil?\n  end\n  \n  def test_read?\n    Message.read(@message, @jerry)\n    @message.reload\n    assert @message.read?\n  end\n  \n  def test_mark_deleted_sender\n    @message.mark_deleted(@george)\n    @message.reload\n    assert @message.sender_deleted\n  end\n\n  def test_mark_deleted_recipient\n    @message.mark_deleted(@jerry)\n    @message.reload\n    assert @message.recipient_deleted\n  end\n\n  def test_mark_deleted_both\n    id = @message.id\n    @message.mark_deleted(@jerry)\n    @message.mark_deleted(@george)\n    assert !Message.exists?(id)\n  end\n\nend"
  },
  {
    "path": "vendor/plugins/simple-private-messages/test/unit/user_model.rb",
    "content": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass UserModelTest < Test::Unit::TestCase\n\n  def setup\n    @jerry = create_user(:login => \"jerry\")\n    @message = create_message\n  end\n\n  def test_unread_messages?\n    assert @jerry.unread_messages?\n  end\n\n  def test_unread_message_count\n    assert_equal @jerry.unread_message_count, 1\n  end\nend"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/CHANGELOG",
    "content": "== v0.2.1 ==\n* Added support for using textile_editor_initialize from an AJAX request\n\n== v0.2 ==\n* Refactored all the Javascript methods into a more OOP-style architecture\n* Added ability to add custom buttons to the toolbar via new helper: textile_editor_button\n\n== v0.1 ==\n* Initial Release"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/MIT-LICENSE",
    "content": "Copyright (c) 2007 Dave Olsen, West Virginia University\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "vendor/plugins/textile-editor-helper/README",
    "content": "= Textile Editor Helper v0.3\n\nTextile Editor Helper is a plugin for Ruby on Rails to add a Textile toolbar above textareas\n\t\nThis version of Textile Editor Helper is a fork of the code found at http://svn.webtest.wvu.edu/repos/rails/plugins/textile_editor_helper/ to allow for use with the form_for method. \n\n== Dependency\n\nTo use Textile Editor Helper you must be using either the Prototype or jQuery JavaScript libraries. If using Prototype, the Textile Editor Helper starts up on the 'dom:loaded' custom event. If using jQuery, it uses the $(document).ready() method.\n\n\n== To use Textile Editor Helper\n\nDirections to get the helper up and running for your install:\n\n\t1. run rake textile_editor_helper:install\n\t2. for the textarea(s) that you want to add the TEH toolbar to replace the text area tag with:\n\n\t\t<% form_for(:user, :url => user_path(@user), :html => { :method => :put }) do |f| %>\n\t  \t<%= f.textile_editor :description %>\n    <% end %>\n\n\t\t**OR**\n\t\t\n\t\t<%= form_tag :controller => \"users\", :action => \"edit\", :id => @user.id %>\n\t\t\t<%= textile_editor :user, \"website\" %>\n\t\t</form>\n\t\t\n\t\t**OR** \n\t\t\n\t\t<%= textile_editor_tag 'description', :description -%> \n\t\t\n\t\t**just like writing a text area tag, same options**\n\n\t3. at the end of your form put in the following code:\n\n\t\t<%= textile_editor_initialize -%> **Important!**\n\t\t\n\t\tIf using jQuery, do textile_editor_initialize(:framework => :jquery)\n\n\t4. save your view and check it out\n\n\n== Simple vs. Extended\n\nTEH has a built-in mode to show only a sub-selection of available tags called simple. Currently the 'simple' tags are: bold, underline, italic, strikethrough. To create a text area that will only use the 'simple' tags create your text area with the following code:\n\n\t<%= textile_editor 'object', 'field', :simple -%>\n\t\n\n== To modify Textile Editor Helper\n\nMost of the options that you might want to modify (e.g. access keystroke or whether a tag is available in simple) are found in textile_editor_config.js. Pretty straightforward.\n\n\n== More Info on Textile\n\nTo learn more about Textile check out: Textism, http://www.textism.com/tools/textile/index.php & Textile Reference, http://hobix.com/textile/\n\n\n== More Info on slate\n\nslate is the CMS in development at West Virginia University that led to the development of Textile Editor Helper. Learn more at: http://slateinfo.blogs.wvu.edu\n\n\n== License\n\nTextile Editor Helper is released under the MIT license.\n\n\n= Credits\n\nTextile Editor Helper was created by Dave Olsen (Javascript) and Chris Scharf (Ruby/Rails) of West Virginia University Web Services (http://webservices.wvu.edu/)\n\n\n= Inspired by \n\nPatrick Woods, http://www.hakjoon.com/code/38/textile-quicktags-redirect & \nAlex King, http://alexking.org/projects/js-quicktags\n"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/Rakefile",
    "content": "require 'rake'\nrequire 'rake/testtask'\nrequire 'rake/rdoctask'\n\ndesc 'Default: run unit tests.'\ntask :default => :test\n\ndesc 'Test the textile_editor_helper plugin.'\nRake::TestTask.new(:test) do |t|\n  t.libs << 'lib'\n  t.pattern = 'test/**/*_test.rb'\n  t.verbose = true\nend\n\ndesc 'Generate documentation for the textile_editor_helper plugin.'\nRake::RDocTask.new(:rdoc) do |rdoc|\n  rdoc.rdoc_dir = 'rdoc'\n  rdoc.title    = 'TextileEditorHelper'\n  rdoc.options << '--line-numbers' << '--inline-source'\n  rdoc.rdoc_files.include('README')\n  rdoc.rdoc_files.include('lib/**/*.rb')\nend\n"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/assets/javascripts/textile-editor-config.js",
    "content": "var teButtons = TextileEditor.buttons;\n\nteButtons.push(new TextileEditorButton('ed_strong',\t\t\t'bold.png',          '*',   '*',  'b', 'Bold','s'));\nteButtons.push(new TextileEditorButton('ed_emphasis',\t\t'italic.png',        '_',   '_',  'i', 'Italicize','s'));\nteButtons.push(new TextileEditorButton('ed_underline',\t'underline.png',     '+',   '+',  'u', 'Underline','s'));\nteButtons.push(new TextileEditorButton('ed_strike',     'strikethrough.png', '-',   '-',  's', 'Strikethrough','s'));\nteButtons.push(new TextileEditorButton('ed_ol',\t\t\t\t\t'list_numbers.png',  ' # ', '\\n', ',', 'Numbered List'));\nteButtons.push(new TextileEditorButton('ed_ul',\t\t\t\t\t'list_bullets.png',  ' * ', '\\n', '.', 'Bulleted List'));\nteButtons.push(new TextileEditorButton('ed_p',\t\t\t\t\t'paragraph.png',     'p',   '\\n', 'p', 'Paragraph'));\nteButtons.push(new TextileEditorButton('ed_h1',\t\t\t\t\t'h1.png',            'h1',  '\\n', '1', 'Header 1'));\nteButtons.push(new TextileEditorButton('ed_h2',\t\t\t\t\t'h2.png',            'h2',  '\\n', '2', 'Header 2'));\nteButtons.push(new TextileEditorButton('ed_h3',\t\t\t\t\t'h3.png',            'h3',  '\\n', '3', 'Header 3'));\nteButtons.push(new TextileEditorButton('ed_h4',\t\t\t\t\t'h4.png',            'h4',  '\\n', '4', 'Header 4'));\nteButtons.push(new TextileEditorButton('ed_block',   \t\t'blockquote.png',    'bq',  '\\n', 'q', 'Blockquote'));\nteButtons.push(new TextileEditorButton('ed_outdent', \t\t'outdent.png',       ')',   '\\n', ']', 'Outdent'));\nteButtons.push(new TextileEditorButton('ed_indent',  \t\t'indent.png',        '(',   '\\n', '[', 'Indent'));\nteButtons.push(new TextileEditorButton('ed_justifyl',\t\t'left.png',          '<',   '\\n', 'l', 'Left Justify'));\nteButtons.push(new TextileEditorButton('ed_justifyc',\t\t'center.png',        '=',   '\\n', 'e', 'Center Text'));\nteButtons.push(new TextileEditorButton('ed_justifyr',\t\t'right.png',         '>',   '\\n', 'r', 'Right Justify'));\nteButtons.push(new TextileEditorButton('ed_justify', \t\t'justify.png',       '<>',  '\\n', 'j', 'Justify'));\n\n// teButtons.push(new TextileEditorButton('ed_code','code','@','@','c','Code'));"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/assets/javascripts/textile-editor.js",
    "content": "/*\n\nTextile Editor v0.2\ncreated by: dave olsen, wvu web services\ncreated on: march 17, 2007\nproject page: slateinfo.blogs.wvu.edu\n\ninspired by: \n - Patrick Woods, http://www.hakjoon.com/code/38/textile-quicktags-redirect & \n - Alex King, http://alexking.org/projects/js-quicktags\n\nfeatures:\n - supports: IE7, FF2, Safari2\n - ability to use \"simple\" vs. \"extended\" editor\n - supports all block elements in textile except footnote\n - supports all block modifier elements in textile\n - supports simple ordered and unordered lists\n - supports most of the phrase modifiers, very easy to add the missing ones\n - supports multiple-paragraph modification\n - can have multiple \"editors\" on one page, access key use in this environment is flaky\n - access key support\n - select text to add and remove tags, selection stays highlighted\n - seamlessly change between tags and modifiers\n - doesn't need to be in the body onload tag\n - can supply your own, custom IDs for the editor to be drawn around\n\ntodo:\n - a clean way of providing image and link inserts\n - get the selection to properly show in IE\n\nmore on textile:\n - Textism, http://www.textism.com/tools/textile/index.php\n - Textile Reference, http://hobix.com/textile/\n\n*/\n\n// Define Button Object\nfunction TextileEditorButton(id, display, tagStart, tagEnd, access, title, sve, open) {\n  this.id = id;       // used to name the toolbar button\n  this.display = display;   // label on button\n  this.tagStart = tagStart;   // open tag\n  this.tagEnd = tagEnd;   // close tag\n  this.access = access;   // set to -1 if tag does not need to be closed\n  this.title = title;     // sets the title attribute of the button to give 'tool tips'\n  this.sve = sve;       // sve = simple vs. extended. add an 's' to make it show up in the simple toolbar\n  this.open = open;     // set to -1 if tag does not need to be closed\n  this.standard = true;  // this is a standard button\n  // this.framework = 'prototype'; // the JS framework used\n}\n\nfunction TextileEditorButtonSeparator(sve) {\n  this.separator = true;\n  this.sve = sve;\n}\n\nvar TextileEditor = function() {};\nTextileEditor.buttons = new Array();\nTextileEditor.Methods = {\n  // class methods\n\n  // create the toolbar (edToolbar)\n  initialize: function(canvas, view) {\n    var toolbar = document.createElement(\"div\");\n    toolbar.id = \"textile-toolbar-\" + canvas;\n    toolbar.className = 'textile-toolbar';\n    this.canvas = document.getElementById(canvas);\n    this.canvas.parentNode.insertBefore(toolbar, this.canvas);\n    this.openTags = new Array();\n\n    // Create the local Button array by assigning theButtons array to edButtons\n    var edButtons = new Array();\n    edButtons = this.buttons;\n    \n    var standardButtons = new Array();\n    for(var i = 0; i < edButtons.length; i++) {\n      var thisButton = this.prepareButton(edButtons[i]);\n      if (view == 's') {\n        if (edButtons[i].sve == 's') {\n          toolbar.appendChild(thisButton);\n          standardButtons.push(thisButton);\n        }\n      } else {\n        if (typeof thisButton == 'string') {\n          toolbar.innerHTML += thisButton;\n        } else {\n          toolbar.appendChild(thisButton);\n          standardButtons.push(thisButton);\n        }\n      }\n    } // end for\n    \n    var te = this;\n    var buttons = toolbar.getElementsByTagName('button');\n    for(var i = 0; i < buttons.length; i++) {\n    //$A(toolbar.getElementsByTagName('button')).each(function(button) {\n      if (!buttons[i].onclick) {\n        buttons[i].onclick = function() { te.insertTag(this); return false; }\n      } // end if\n      \n      buttons[i].tagStart = buttons[i].getAttribute('tagStart');\n      buttons[i].tagEnd = buttons[i].getAttribute('tagEnd');\n      buttons[i].open = buttons[i].getAttribute('open');\n      buttons[i].textile_editor = te;\n      buttons[i].canvas = te.canvas;\n      // console.log(buttons[i].canvas);\n    //});\n    }\n  }, // end initialize\n  \n  // draw individual buttons (edShowButton)\n  prepareButton: function(button) {\n    if (button.separator) {\n      var theButton = document.createElement('span');\n      theButton.className = 'ed_sep';\n      return theButton;\n    }\n\n    if (button.standard) {\n      var theButton = document.createElement(\"button\");\n      theButton.id = button.id;\n      theButton.setAttribute('class', 'standard');\n      theButton.setAttribute('tagStart', button.tagStart);\n      theButton.setAttribute('tagEnd', button.tagEnd);\n      theButton.setAttribute('open', button.open);\n\n      var img = document.createElement('img');\n      img.src = '/images/textile-editor/' + button.display;\n      theButton.appendChild(img);\n    } else {\n      return button;\n    } // end if !custom\n\n    theButton.accessKey = button.access;\n    theButton.title = button.title;\n    return theButton; \n  }, // end prepareButton\n  \n  // if clicked, no selected text, tag not open highlight button\n  // (edAddTag)\n  addTag: function(button) {\n    if (button.tagEnd != '') {\n      this.openTags[this.openTags.length] = button;\n      //var el = document.getElementById(button.id);\n      //el.className = 'selected';\n      button.className = 'selected';\n    }\n  }, // end addTag\n\n  // if clicked, no selected text, tag open lowlight button\n  // (edRemoveTag)\n  removeTag: function(button) {\n    for (i = 0; i < this.openTags.length; i++) {\n      if (this.openTags[i] == button) {\n        this.openTags.splice(button, 1);\n        //var el = document.getElementById(button.id);\n        //el.className = 'unselected';\n        button.className = 'unselected';\n      }\n    }\n  }, // end removeTag\n\n  // see if there are open tags. for the remove tag bit...\n  // (edCheckOpenTags)\n  checkOpenTags: function(button) {\n    var tag = 0;\n    for (i = 0; i < this.openTags.length; i++) {\n      if (this.openTags[i] == button) {\n        tag++;\n      }\n    }\n    if (tag > 0) {\n      return true; // tag found\n    }\n    else {\n      return false; // tag not found\n    }\n  }, // end checkOpenTags\n\n  // insert the tag. this is the bulk of the code.\n  // (edInsertTag)\n  insertTag: function(button, tagStart, tagEnd) {\n    // console.log(button);\n    var myField = button.canvas;\n    myField.focus();\n\n    if (tagStart) {\n      button.tagStart = tagStart;\n      button.tagEnd = tagEnd ? tagEnd : '\\n';\n    }\n\n    var textSelected = false;\n    var finalText = '';\n    var FF = false;\n\n    // grab the text that's going to be manipulated, by browser\n    if (document.selection) { // IE support\n      sel = document.selection.createRange();\n\n      // set-up the text vars\n      var beginningText = '';\n      var followupText = '';\n      var selectedText = sel.text;\n\n      // check if text has been selected\n      if (sel.text.length > 0) {\n        textSelected = true;  \n      }\n\n      // set-up newline regex's so we can swap tags across multiple paragraphs\n      var newlineReplaceRegexClean = /\\r\\n\\s\\n/g;\n      var newlineReplaceRegexDirty = '\\\\r\\\\n\\\\s\\\\n';\n      var newlineReplaceClean = '\\r\\n\\n';\n    }\n    else if (myField.selectionStart || myField.selectionStart == '0') { // MOZ/FF/NS/S support\n\n      // figure out cursor and selection positions\n      var startPos = myField.selectionStart;\n      var endPos = myField.selectionEnd;\n      var cursorPos = endPos;\n      var scrollTop = myField.scrollTop;\n      FF = true; // note that is is a FF/MOZ/NS/S browser\n\n      // set-up the text vars\n      var beginningText = myField.value.substring(0, startPos);\n      var followupText = myField.value.substring(endPos, myField.value.length);\n\n      // check if text has been selected\n      if (startPos != endPos) {\n        textSelected = true;\n        var selectedText = myField.value.substring(startPos, endPos); \n      }\n\n      // set-up newline regex's so we can swap tags across multiple paragraphs\n      var newlineReplaceRegexClean = /\\n\\n/g;\n      var newlineReplaceRegexDirty = '\\\\n\\\\n';\n      var newlineReplaceClean = '\\n\\n';\n    }\n\n\n    // if there is text that has been highlighted...\n    if (textSelected) {\n\n      // set-up some defaults for how to handle bad new line characters\n      var newlineStart = '';\n      var newlineStartPos = 0;\n      var newlineEnd = '';\n      var newlineEndPos = 0;\n      var newlineFollowup = '';\n\n      // set-up some defaults for how to handle placing the beginning and end of selection\n      var posDiffPos = 0;\n      var posDiffNeg = 0;\n      var mplier = 1;\n\n      // remove newline from the beginning of the selectedText.\n      if (selectedText.match(/^\\n/)) {\n        selectedText = selectedText.replace(/^\\n/,'');\n        newlineStart = '\\n';\n        newlineStartpos = 1;\n      }\n\n      // remove newline from the end of the selectedText.\n      if (selectedText.match(/\\n$/g)) {\n        selectedText = selectedText.replace(/\\n$/g,'');\n        newlineEnd = '\\n';\n        newlineEndPos = 1;\n      }\n\n      // remove space from the end of the selectedText.\n      // Fixes a bug that causes any browser running under Microsoft Internet Explorer \n      // to append an additional space before the closing element.\n      // *Bold text *here => *Bold text*\n      if (selectedText.match(/\\s$/g)) {\n        selectedText = selectedText.replace(/\\s$/g,'');\n        followupText = ' ';\n      }\n      \n      // no clue, i'm sure it made sense at the time i wrote it\n      if (followupText.match(/^\\n/)) {\n        newlineFollowup = '';\n      }\n      else {\n        newlineFollowup = '\\n\\n';\n      }\n\n      // first off let's check if the user is trying to mess with lists\n      if ((button.tagStart == ' * ') || (button.tagStart == ' # ')) {\n\n        listItems = 0; // sets up a default to be able to properly manipulate final selection\n\n        // set-up all of the regex's\n        re_start = new RegExp('^ (\\\\*|\\\\#) ','g');\n        if (button.tagStart == ' # ') {\n          re_tag = new RegExp(' \\\\# ','g'); // because of JS regex stupidity i need an if/else to properly set it up, could have done it with a regex replace though\n        }\n        else {\n          re_tag = new RegExp(' \\\\* ','g');\n        }\n        re_replace = new RegExp(' (\\\\*|\\\\#) ','g');\n\n        // try to remove bullets in text copied from ms word **Mac Only!** \n        re_word_bullet_m_s = new RegExp('• ','g'); // mac/safari\n        re_word_bullet_m_f = new RegExp('∑ ','g'); // mac/firefox\n        selectedText = selectedText.replace(re_word_bullet_m_s,'').replace(re_word_bullet_m_f,'');\n\n        // if the selected text starts with one of the tags we're working with...\n        if (selectedText.match(re_start)) {\n\n          // if tag that begins the selection matches the one clicked, remove them all\n          if (selectedText.match(re_tag)) {\n            finalText = beginningText\n                    + newlineStart\n                    + selectedText.replace(re_replace,'')\n                    + newlineEnd\n                    + followupText;\n            if (matches = selectedText.match(/ (\\*|\\#) /g)) {\n              listItems = matches.length;\n            }\n            posDiffNeg = listItems*3; // how many list items were there because that's 3 spaces to remove from final selection\n          }\n\n          // else replace the current tag type with the selected tag type\n          else {\n            finalText = beginningText\n                    + newlineStart\n                    + selectedText.replace(re_replace,button.tagStart)\n                    + newlineEnd\n                    + followupText;\n          }\n        }\n\n        // else try to create the list type\n        // NOTE: the items in a list will only be replaced if a newline starts with some character, not a space\n        else {\n          finalText = beginningText\n                  + newlineStart\n                        + button.tagStart\n                  + selectedText.replace(newlineReplaceRegexClean,newlineReplaceClean + button.tagStart).replace(/\\n(\\S)/g,'\\n' + button.tagStart + '$1')\n                  + newlineEnd\n                  + followupText;\n          if (matches = selectedText.match(/\\n(\\S)/g)) {\n            listItems = matches.length;\n          }\n          posDiffPos = 3 + listItems*3;\n        } \n      }\n\n      // now lets look and see if the user is trying to muck with a block or block modifier\n      else if (button.tagStart.match(/^(h1|h2|h3|h4|h5|h6|bq|p|\\>|\\<\\>|\\<|\\=|\\(|\\))/g)) {\n\n        var insertTag = '';\n        var insertModifier = '';\n        var tagPartBlock = '';\n        var tagPartModifier = '';\n        var tagPartModifierOrig = ''; // ugly hack but it's late\n        var drawSwitch = '';\n        var captureIndentStart = false;\n        var captureListStart = false;\n        var periodAddition = '\\\\. ';\n        var periodAdditionClean = '. ';\n        var listItemsAddition = 0;\n\n        var re_list_items = new RegExp('(\\\\*+|\\\\#+)','g'); // need this regex later on when checking indentation of lists\n\n        var re_block_modifier = new RegExp('^(h1|h2|h3|h4|h5|h6|bq|p| [\\\\*]{1,} | [\\\\#]{1,} |)(\\\\>|\\\\<\\\\>|\\\\<|\\\\=|[\\\\(]{1,}|[\\\\)]{1,6}|)','g');\n        if (tagPartMatches = re_block_modifier.exec(selectedText)) {\n          tagPartBlock = tagPartMatches[1];\n          tagPartModifier = tagPartMatches[2];\n          tagPartModifierOrig = tagPartMatches[2];\n          tagPartModifierOrig = tagPartModifierOrig.replace(/\\(/g,\"\\\\(\");\n        }\n\n        // if tag already up is the same as the tag provided replace the whole tag\n        if (tagPartBlock == button.tagStart) { \n          insertTag  = tagPartBlock + tagPartModifierOrig; // use Orig because it's escaped for regex\n          drawSwitch = 0; \n        }\n        // else if let's check to add/remove block modifier\n        else if ((tagPartModifier == button.tagStart) || (newm = tagPartModifier.match(/[\\(]{2,}/g))) {\n          if ((button.tagStart == '(') || (button.tagStart == ')')) {\n            var indentLength = tagPartModifier.length;\n            if (button.tagStart == '(') {\n              indentLength = indentLength + 1;\n            }\n            else {\n              indentLength = indentLength - 1;\n            }\n            for (var i = 0; i < indentLength; i++) {\n              insertModifier = insertModifier + '(';\n            }\n            insertTag = tagPartBlock + insertModifier;\n          }\n          else {\n            if (button.tagStart == tagPartModifier) {\n              insertTag =  tagPartBlock;\n              } // going to rely on the default empty insertModifier\n            else {\n\n              if (button.tagStart.match(/(\\>|\\<\\>|\\<|\\=)/g)) {\n                insertTag = tagPartBlock + button.tagStart;\n              }\n              else {\n                insertTag = button.tagStart + tagPartModifier;\n              }\n            }\n\n          }\n          drawSwitch = 1;\n        }\n        // indentation of list items\n        else if (listPartMatches = re_list_items.exec(tagPartBlock)) {\n            var listTypeMatch = listPartMatches[1];\n            var indentLength = tagPartBlock.length - 2;\n            var listInsert = '';\n            if (button.tagStart == '(') {\n              indentLength = indentLength + 1;\n            }\n            else {\n              indentLength = indentLength - 1;\n            }\n            if (listTypeMatch.match(/[\\*]{1,}/g)) {\n              var listType = '*';\n              var listReplace = '\\\\*';\n            }\n            else {\n              var listType = '#';\n              var listReplace = '\\\\#';\n            }\n            for (var i = 0; i < indentLength; i++) {\n              listInsert = listInsert + listType;\n            }\n            if (listInsert != '') {\n              insertTag = ' ' + listInsert + ' ';\n            }\n            else {\n              insertTag = '';\n            }\n            tagPartBlock = tagPartBlock.replace(/(\\*|\\#)/g,listReplace);\n            drawSwitch = 1;\n            captureListStart = true;\n            periodAddition = '';\n            periodAdditionClean = '';\n            if (matches = selectedText.match(/\\n\\s/g)) {\n              listItemsAddition = matches.length;\n            }\n        }\n        // must be a block modification e.g. p>. to p<.\n        else {\n\n          // if this is a block modification/addition\n          if (button.tagStart.match(/(h1|h2|h3|h4|h5|h6|bq|p)/g)) { \n            if (tagPartBlock == '') {\n              drawSwitch = 2;\n            }\n            else {\n              drawSwitch = 1;\n            }\n\n            insertTag = button.tagStart + tagPartModifier;\n          }\n\n          // else this is a modifier modification/addition\n          else {\n            if ((tagPartModifier == '') && (tagPartBlock != '')) {\n              drawSwitch = 1;\n            }\n            else if (tagPartModifier == '') {\n              drawSwitch = 2;\n            }\n            else {\n              drawSwitch = 1;\n            }\n\n            // if no tag part block but a modifier we need at least the p tag\n            if (tagPartBlock == '') {\n              tagPartBlock = 'p';\n            }\n\n            //make sure to swap out outdent\n            if (button.tagStart == ')') {\n              tagPartModifier = '';\n            }\n            else {\n              tagPartModifier = button.tagStart;\n              captureIndentStart = true; // ugly hack to fix issue with proper selection handling\n            }\n\n            insertTag = tagPartBlock + tagPartModifier;\n          }\n        }\n\n        mplier = 0;\n        if (captureListStart || (tagPartModifier.match(/[\\(\\)]{1,}/g))) {\n          re_start = new RegExp(insertTag.escape + periodAddition,'g'); // for tags that mimic regex properties, parens + list tags\n        }\n        else {\n          re_start = new RegExp(insertTag + periodAddition,'g'); // for tags that don't, why i can't just escape everything i have no clue\n        }\n        re_old = new RegExp(tagPartBlock + tagPartModifierOrig + periodAddition,'g');\n        re_middle = new RegExp(newlineReplaceRegexDirty + insertTag.escape + periodAddition.escape,'g');\n        re_tag = new RegExp(insertTag.escape + periodAddition.escape,'g');\n\n        // *************************************************************************************************************************\n        // this is where everything gets swapped around or inserted, bullets and single options have their own if/else statements\n        // *************************************************************************************************************************\n        if ((drawSwitch == 0) || (drawSwitch == 1)) {\n          if (drawSwitch == 0) { // completely removing a tag\n            finalText = beginningText\n                    + newlineStart\n                    + selectedText.replace(re_start,'').replace(re_middle,newlineReplaceClean)\n                    + newlineEnd\n                    + followupText;\n            if (matches = selectedText.match(newlineReplaceRegexClean)) {\n              mplier = mplier + matches.length;\n            }\n            posDiffNeg = insertTag.length + 2 + (mplier*4);\n          }\n          else { // modifying a tag, though we do delete bullets here\n            finalText = beginningText\n                    + newlineStart\n                    + selectedText.replace(re_old,insertTag + periodAdditionClean)\n                    + newlineEnd\n                    + followupText;\n\n            if (matches = selectedText.match(newlineReplaceRegexClean)) {\n              mplier = mplier + matches.length;\n            }\n            // figure out the length of various elements to modify the selection position\n            if (captureIndentStart) { // need to double-check that this wasn't the first indent\n              tagPreviousLength = tagPartBlock.length;\n              tagCurrentLength = insertTag.length;\n            }\n            else if (captureListStart) { // if this is a list we're manipulating\n              if (button.tagStart == '(') { // if indenting\n                tagPreviousLength = listTypeMatch.length + 2;\n                tagCurrentLength = insertTag.length + listItemsAddition;\n              }\n              else if (insertTag.match(/(\\*|\\#)/g)) { // if removing but still has bullets\n                tagPreviousLength = insertTag.length + listItemsAddition;\n                tagCurrentLength = listTypeMatch.length;\n              }\n              else {  // if removing last bullet\n                tagPreviousLength = insertTag.length + listItemsAddition;\n                tagCurrentLength = listTypeMatch.length - (3*listItemsAddition) - 1;\n              }\n            }\n            else { // everything else\n              tagPreviousLength = tagPartBlock.length + tagPartModifier.length;\n              tagCurrentLength = insertTag.length;\n            }\n            if (tagCurrentLength > tagPreviousLength) {\n              posDiffPos = (tagCurrentLength - tagPreviousLength) + (mplier*(tagCurrentLength - tagPreviousLength));\n            }\n            else {\n              posDiffNeg = (tagPreviousLength - tagCurrentLength) + (mplier*(tagPreviousLength - tagCurrentLength));\n            }\n          }\n        }\n        else { // for adding tags other then bullets (have their own statement)\n          finalText = beginningText\n                  + newlineStart\n                        + insertTag + '. '\n                  + selectedText.replace(newlineReplaceRegexClean,button.tagEnd + '\\n' + insertTag + '. ')\n                  + newlineFollowup\n                  + newlineEnd\n                  + followupText;\n          if (matches = selectedText.match(newlineReplaceRegexClean)) {\n            mplier = mplier + matches.length;\n          }\n          posDiffPos = insertTag.length + 2 + (mplier*4);\n        }       \n      }\n\n      // swap in and out the simple tags around a selection like bold\n      else {\n\n        mplier = 1; // the multiplier for the tag length\n        re_start = new RegExp('^\\\\' + button.tagStart,'g');\n        re_end =  new RegExp('\\\\' + button.tagEnd + '$','g');\n        re_middle = new RegExp('\\\\' + button.tagEnd + newlineReplaceRegexDirty + '\\\\' + button.tagStart,'g');\n        if (selectedText.match(re_start) && selectedText.match(re_end)) {\n          finalText = beginningText\n                  + newlineStart\n                  + selectedText.replace(re_start,'').replace(re_end,'').replace(re_middle,newlineReplaceClean)\n                  + newlineEnd\n                  + followupText;\n          if (matches = selectedText.match(newlineReplaceRegexClean)) {\n            mplier = mplier + matches.length;\n          }\n          posDiffNeg = button.tagStart.length*mplier + button.tagEnd.length*mplier;\n        }\n        else {\n          finalText = beginningText\n                  + newlineStart\n                        + button.tagStart\n                  + selectedText.replace(newlineReplaceRegexClean,button.tagEnd + newlineReplaceClean + button.tagStart)\n                  + button.tagEnd\n                  + newlineEnd\n                  + followupText;\n          if (matches = selectedText.match(newlineReplaceRegexClean)) {\n            mplier = mplier + matches.length;\n          }\n          posDiffPos = (button.tagStart.length*mplier) + (button.tagEnd.length*mplier);\n        }\n      }\n\n      cursorPos += button.tagStart.length + button.tagEnd.length;\n\n    }\n\n    // just swap in and out single values, e.g. someone clicks b they'll get a *\n    else {\n      var buttonStart = '';\n      var buttonEnd = '';\n      var re_p = new RegExp('(\\\\<|\\\\>|\\\\=|\\\\<\\\\>|\\\\(|\\\\))','g');\n      var re_h = new RegExp('^(h1|h2|h3|h4|h5|h6|p|bq)','g');\n      if (!this.checkOpenTags(button) || button.tagEnd == '') { // opening tag\n\n        if (button.tagStart.match(re_h)) {\n          buttonStart = button.tagStart + '. ';\n        }\n        else {\n          buttonStart = button.tagStart;\n        }\n        if (button.tagStart.match(re_p)) { // make sure that invoking block modifiers don't do anything\n          finalText = beginningText \n                     + followupText;\n          cursorPos = startPos;\n        }\n        else {\n          finalText = beginningText \n                      + buttonStart\n                      + followupText;\n          this.addTag(button);\n          cursorPos = startPos + buttonStart.length;\n        }\n\n      }\n      else {  // closing tag\n        if (button.tagStart.match(re_p)) {\n          buttonEnd = '\\n\\n';\n        }\n        else if (button.tagStart.match(re_h)) {\n          buttonEnd = '\\n\\n';\n        }\n        else {\n          buttonEnd = button.tagEnd\n        }\n        finalText = beginningText \n                    + button.tagEnd\n                    + followupText;\n        this.removeTag(button);\n        cursorPos = startPos + button.tagEnd.length;\n      }\n    }\n\n    // set the appropriate DOM value with the final text\n    if (FF == true) {\n      myField.value = finalText;\n      myField.scrollTop = scrollTop;\n    }\n    else {\n      sel.text = finalText;\n    }\n\n    // build up the selection capture, doesn't work in IE\n    if (textSelected) {\n      myField.selectionStart = startPos + newlineStartPos;\n      myField.selectionEnd = endPos + posDiffPos - posDiffNeg - newlineEndPos;\n      //alert('s: ' + myField.selectionStart + ' e: ' + myField.selectionEnd + ' sp: ' + startPos + ' ep: ' + endPos + ' pdp: ' + posDiffPos + ' pdn: ' + posDiffNeg)\n    }\n    else {\n      myField.selectionStart = cursorPos;\n      myField.selectionEnd = cursorPos;\n    }\n  } // end insertTag\n}; // end class\n\n// add class methods\n// Object.extend(TextileEditor, TextileEditor.Methods);\ndestination = TextileEditor\nsource = TextileEditor.Methods\nfor(var property in source) destination[property] = source[property];\n\ndocument.write('<script src=\"/javascripts/textile-editor-config.js\" type=\"text/javascript\"></script>');"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/assets/stylesheets/textile-editor.css",
    "content": "div.textile-toolbar span.ed_sep {\n\txposition: relative;\n\txtop: -4px;\n  padding: 0;\n  height: 6px;\n  width: 2px;\n  margin: 0 2px;\n  border-left: solid 1px #d5d5d5;\n  border-right: solid 1px #f5f5f5;\n}\n\ndiv.textile-toolbar button {\n\tmargin: 0;\n\tbackground-color: #f0f0ee;\n\tbackground-repeat: no-repeat;\n\tborder: 1px solid #f0f0ee;\n\tpadding: 2px 0;\n}\n\ndiv.textile-toolbar button.standard {\n\ttext-align: center;\n\twidth: 24px;\n}\n\ndiv.textile-toolbar button img {\n\tvertical-align: text-bottom;\n}\n\ndiv.textile-toolbar button:hover, \ndiv.textile-toolbar button.unselected:hover {\n\tborder: 1px solid #999;\n}\n\ndiv.textile-toolbar button.selected {\n\tborder: 1px solid #ce9100;\n\tbackground-color: #ffffff;\n}\n\ndiv.textile-toolbar button.unselected {\n\tborder: 1px solid #f0f0ee;\n\tbackground-color: #f0f0ee;\n}\n\ndiv.textile-toolbar button.publish {\n\tpadding:5px;\n\tdisplay:block;\n}\n\ndiv.textile-toolbar {\n\tbackground-color: #f0f0ee;\n\tpadding: 3px;\n\tmargin-bottom: 4px;\n}"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/init.rb",
    "content": "# Include hook code here\nrequire 'textile_editor_helper'"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/install.rb",
    "content": "# Install hook code here\n"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/lib/tasks/textile_editor_helper_tasks.rake",
    "content": "namespace :textile_editor_helper do\n  PLUGIN_ROOT = File.dirname(__FILE__) + '/..'\n  ASSET_FILES = Dir[PLUGIN_ROOT + '/assets/**/*'].select { |e| File.file?(e) }\n  \n  desc 'Installs required assets'\n  task :install do\n    #ENV['FORCE'] = true\n    #Rake::Task[:update].invoke\n    #force = ENV['FORCE'] || false\n    verbose = true\n    ASSET_FILES.each do |file|\n      path = File.dirname(file) + '/'\n      path.gsub!(PLUGIN_ROOT, RAILS_ROOT)\n      path.gsub!('assets', 'public')\n      destination = File.join(path, File.basename(file))\n      puts \" * Copying %-50s to %s\" % [file.gsub(PLUGIN_ROOT, ''), destination.gsub(RAILS_ROOT, '')] if verbose\n      FileUtils.mkpath(path) unless File.directory?(path)\n      \n      #puts File.mtime(file), File.mtime(destination)\n      #if force || !FileUtils.identical?(file, destination)\n      FileUtils.cp [file], path\n      #end  \n    end    \n  end\n  \n  desc 'Removes assets for the plugin'\n  task :remove do\n    ASSET_FILES.each do |file|\n      path = File.dirname(file) + '/'\n      path.gsub!(PLUGIN_ROOT, RAILS_ROOT)\n      path.gsub!('assets', 'public')\n      path = File.join(path, File.basename(file))\n      puts ' * Removing %s' % path.gsub(RAILS_ROOT, '') if verbose\n      FileUtils.rm [path]\n    end\n  end\nend"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/lib/textile_editor_helper.rb",
    "content": "module ActionView\n  module Helpers\n\n    class FormBuilder\n      def textile_editor(method, options = {})\n        @template.textile_editor(@object_name, method, options.merge(:object => @object))\n      end\n    end\n    \n    module PrototypeHelper\n    end\n    \n    module FormHelper\n      # Returns a textarea opening and closing tag set tailored for accessing a specified attribute (identified by +method+)\n      # on an object assigned to the template (identified by +object+). Additional options on the input tag can be passed as a\n      # hash with +options+ and places the textile toolbar above it\n      #\n      # ==== Examples\n      #   textile_editor(:post, :body, :cols => 20, :rows => 40)\n      #   # => <textarea cols=\"20\" rows=\"40\" id=\"post_body\" name=\"post[body]\">\n      #   #      #{@post.body}\n      #   #    </textarea>\n      #\n      #   textile_editor(:comment, :text, :size => \"20x30\")\n      #   # => <textarea cols=\"20\" rows=\"30\" id=\"comment_text\" name=\"comment[text]\">\n      #   #      #{@comment.text}\n      #   #    </textarea>\n      #\n      #   textile_editor(:application, :notes, :cols => 40, :rows => 15, :class => 'app_input')\n      #   # => <textarea cols=\"40\" rows=\"15\" id=\"application_notes\" name=\"application[notes]\" class=\"app_input\">\n      #   #      #{@application.notes}\n      #   #    </textarea>\n      #\n      #   textile_editor(:entry, :body, :size => \"20x20\", :disabled => 'disabled')\n      #   # => <textarea cols=\"20\" rows=\"20\" id=\"entry_body\" name=\"entry[body]\" disabled=\"disabled\">\n      #   #      #{@entry.body}\n      #   #    </textarea>\n      def textile_editor(object_name, method, options = {})        \n        editor_id = options[:id] || '%s_%s' % [object_name, method]\n        mode      = options.delete(:simple) ? 'simple' : 'extended'\n        (@textile_editor_ids ||= []) << [editor_id.to_s, mode.to_s]\n\n        InstanceTag.new(object_name, method, self, options.delete(:object)).to_text_area_tag(options)\n      end\n      \n      def textile_editor_options(options={})\n        (@textile_editor_options ||= { :framework => :prototype }).merge! options\n      end\n      \n      def textile_editor_support\n        output = []\n        output << stylesheet_link_tag('textile-editor') \n        output << javascript_include_tag('textile-editor')\n        output.join(\"\\n\")\n      end\n      \n      # registers a new button for the Textile Editor toolbar\n      # Parameters:\n      #   * +text+: text to display (contents of button tag, so HTML is valid as well)\n      #   * +options+: options Hash as supported by +content_tag+ helper in Rails\n      # \n      # Example:\n      #   The following example adds a button labeled 'Greeting' which triggers an\n      #   alert:\n      # \n      #   <% textile_editor_button 'Greeting', :onclick => \"alert('Hello!')\" %> \n      #\n      # *Note*: this method must be called before +textile_editor_initialize+\n      def textile_editor_button(text, options={})\n        return textile_editor_button_separator  if text == :separator\n        button = content_tag(:button, text, options)\n        button = \"TextileEditor.buttons.push(\\\"%s\\\");\" % escape_javascript(button)\n        (@textile_editor_buttons ||= []) << button\n      end\n\n      def textile_editor_button_separator(options={})\n        button = \"TextileEditor.buttons.push(new TextileEditorButtonSeparator('%s'));\" % (options[:simple] || '')\n        (@textile_editor_buttons ||= []) << button\n      end\n\n      def textile_extract_dom_ids(*dom_ids)\n        hash = dom_ids.last.is_a?(Hash) ? dom_ids.pop : {}\n        hash.inject(dom_ids) do |ids, (object, fields)|\n          ids + Array(fields).map { |field| \"%s_%s\" % [object, field] }\n        end\n      end\n      \n      # adds the necessary javascript include tags, stylesheet tags,\n      # and load event with necessary javascript to active textile editor(s)\n      # sample output:\n      #    <link href=\"/stylesheets/textile-editor.css\" media=\"screen\" rel=\"Stylesheet\" type=\"text/css\" />\n      #    <script src=\"/javascripts/textile-editor.js\" type=\"text/javascript\"></script>\n      #    <script type=\"text/javascript\">\n      #    document.observe('dom:loaded', function() {\n      #    TextileEditor.initialize('article_body', 'extended');\n      #    TextileEditor.initialize('article_body_excerpt', 'simple');\n      #    });\n      #    </script>  \n      # \n      # Note: in the case of this helper being called via AJAX, the output will be reduced:\n      #    <script type=\"text/javascript\">\n      #    TextileEditor.initialize('article_body', 'extended');\n      #    TextileEditor.initialize('article_body_excerpt', 'simple');\n      #    </script>  \n      # \n      # This means that the support files must be loaded outside of the AJAX request, either\n      # via a call to this helper or the textile_editor_support() helper\n      def textile_editor_initialize(*dom_ids)\n        options = textile_editor_options.dup\n\n        # extract options from last argument if it's a hash\n        if dom_ids.last.is_a?(Hash)\n          hash = dom_ids.last.dup\n          options.merge! hash\n          dom_ids.last.delete :framework\n        end\n\n        editor_ids = (@textile_editor_ids || []) + textile_extract_dom_ids(*dom_ids)\n        editor_buttons = (@textile_editor_buttons || [])\n        output = []\n        output << textile_editor_support unless request.xhr?\n        output << '<script type=\"text/javascript\">'\n        output << '/* <![CDATA[ */'\n        \n        if !request.xhr?\n          case options[:framework]\n          when :prototype\n            output << %{document.observe('dom:loaded', function() \\{}\n          when :jquery\n            output << %{$(document).ready(function() \\{}\n          end\n        end      \n\n        # output << %q{TextileEditor.framework = '%s';} % options[:framework].to_s\n        output << editor_buttons.join(\"\\n\") if editor_buttons.any?\n        editor_ids.each do |editor_id, mode|\n          output << %q{TextileEditor.initialize('%s', '%s');} % [editor_id, mode || 'extended']\n        end\n        output << '});' unless request.xhr?\n\n        output << '/* ]]> */'\n        output << '</script>'\n        output.join(\"\\n\")\n      end\n    end\n    \n    module FormTagHelper\n      # Creates a text input area; use a textarea for longer text inputs such as blog posts or descriptions \n      # and includes the textile toolbar above it.\n      # \n      # ==== Options\n      # * <tt>:size</tt> - A string specifying the dimensions (columns by rows) of the textarea (e.g., \"25x10\").\n      # * <tt>:rows</tt> - Specify the number of rows in the textarea\n      # * <tt>:cols</tt> - Specify the number of columns in the textarea\n      # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.\n      # * Any other key creates standard HTML attributes for the tag.\n      #\n      # ==== Examples\n      #   textile_editor_tag 'post'\n      #   # => <textarea id=\"post\" name=\"post\"></textarea>\n      #\n      #   textile_editor_tag 'bio', @user.bio\n      #   # => <textarea id=\"bio\" name=\"bio\">This is my biography.</textarea>\n      #\n      #   textile_editor_tag 'body', nil, :rows => 10, :cols => 25\n      #   # => <textarea cols=\"25\" id=\"body\" name=\"body\" rows=\"10\"></textarea>\n      #\n      #   textile_editor_tag 'body', nil, :size => \"25x10\"\n      #   # => <textarea name=\"body\" id=\"body\" cols=\"25\" rows=\"10\"></textarea>\n      #\n      #   textile_editor_tag 'description', \"Description goes here.\", :disabled => true\n      #   # => <textarea disabled=\"disabled\" id=\"description\" name=\"description\">Description goes here.</textarea>\n      #\n      #   textile_editor_tag 'comment', nil, :class => 'comment_input'\n      #   # => <textarea class=\"comment_input\" id=\"comment\" name=\"comment\"></textarea>\n      def textile_editor_tag(name, content = nil, options = {})\n        editor_id = options[:id] || name\n        mode      = options.delete(:simple) ? 'simple' : 'extended'\n        (@textile_editor_ids ||= []) << [editor_id.to_s, mode.to_s]\n        \n        text_area_tag(name, content, options)\n      end\n    end\n    \n  end\nend\n\n"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/test/abstract_unit.rb",
    "content": "$:.unshift(File.dirname(__FILE__) + '/../lib')\n\nrequire 'yaml'\nrequire 'test/unit'\nrequire 'rubygems'\n\nrequire 'action_controller'\nrequire 'action_controller/cgi_ext'\nrequire 'action_controller/test_process'\n\n# Show backtraces for deprecated behavior for quicker cleanup.\nActiveSupport::Deprecation.debug = true\n\nActionController::Base.logger = nil\n# ActionController::Base.ignore_missing_templates = false\nActionController::Routing::Routes.reload rescue nil"
  },
  {
    "path": "vendor/plugins/textile-editor-helper/test/textile_editor_helper_test.rb",
    "content": "require File.dirname(__FILE__) + '/abstract_unit'\nrequire File.dirname(__FILE__) + '/../lib/textile_editor_helper'\nrequire 'ostruct'\n\nclass TextileEditorHelperTest < Test::Unit::TestCase\n  include ActionView::Helpers::TextHelper\n  include ActionView::Helpers::AssetTagHelper\n  include ActionView::Helpers::TagHelper\n  include ActionView::Helpers::FormHelper\n  include ActionView::Helpers::JavaScriptHelper\n  # include TextileEditorHelper\n    \n  def setup\n    @controller = Class.new do\n      attr_reader :url_for_options\n      def url_for(options, *parameters_for_method_reference)\n        @url_for_options = options\n        \"http://www.example.com\"\n      end\n      \n      def request;  @request  ||= ActionController::TestRequest.new;  end\n      def response; @response ||= ActionController::TestResponse.new; end\n    end\n    @controller = @controller.new    \n    @article = OpenStruct.new(:body => nil)\n  end\n  \n  # support methods\n  def request\n    @controller.request\n  end\n  \n  def create_simple_editor(object, field, options={})\n    output = textile_editor(object, field, options.merge(:simple => true))\n    assert_equal  text_area(object, field, options), output\n  end  \n\n  def create_extended_editor(object, field, options={})\n    output = textile_editor(object, field, options)\n    assert_equal  text_area(object, field, options), output\n  end  \n\n  def framework_initialize_output(framework)\n    case framework\n    when :prototype\n      %{document.observe('dom:loaded', function() \\{}\n    when :jquery\n      %{$(document).ready(function() \\{}\n    end\n  end\n  \n  def pre_initialize_output(framework)\n    %{<link href=\"/stylesheets/textile-editor.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />\n      <script src=\"/javascripts/textile-editor.js\" type=\"text/javascript\"></script>\n      <script type=\"text/javascript\">\n      /* <![CDATA[ */\n      } +\n      framework_initialize_output(framework)\n  end\n  \n  def post_initialize_output\n    %{\\});\n      /* ]]> */\n      </script>\n    }\n  end\n  \n  def expected_initialize_output(framework, editors, button_data=nil)\n    expected = [pre_initialize_output(framework)]\n    expected << button_data unless button_data.nil?\n    expected << editors.map do |editor|\n      \"TextileEditor.initialize('%s', '%s');\" % editor\n    end\n    expected << post_initialize_output\n    expected.join(\"\\n\").split(\"\\n\").map { |e| e.lstrip }.join(\"\\n\").chomp\n  end\n  \n  # tests\n  def test_textile_editor\n    assert_nil @textile_editor_ids\n    create_extended_editor('article', 'body')\n    assert_equal [['article_body', 'extended']], @textile_editor_ids\n  end\n  \n  def test_textile_editor_simple_mode\n    assert_nil @textile_editor_ids\n    create_simple_editor('article', 'body')\n    assert_equal [['article_body', 'simple']], @textile_editor_ids\n  end\n  \n  def test_textile_editor_with_custom_id\n    assert_nil @textile_editor_ids\n    create_extended_editor('article', 'body', :id => 'my_custom_id')\n    assert_equal [['my_custom_id', 'extended']], @textile_editor_ids\n  end  \n  \n  def test_textile_editor_simple_mode_with_custom_id\n    assert_nil @textile_editor_ids\n    create_simple_editor('article', 'body', :id => 'my_custom_id')\n    assert_equal [['my_custom_id', 'simple']], @textile_editor_ids\n  end\n  \n  def test_textile_editor_initialize\n    create_extended_editor('article', 'body')\n    output = textile_editor_initialize()\n    assert_equal expected_initialize_output(:prototype, [\n      ['article_body', 'extended']\n    ]), output\n    \n    create_simple_editor('article', 'body_excerpt')\n    output = textile_editor_initialize()\n    assert_equal expected_initialize_output(:prototype, [\n      ['article_body', 'extended'],\n      ['article_body_excerpt', 'simple']\n    ]), output\n\n    output = textile_editor_initialize(:framework => :jquery)\n    assert_equal expected_initialize_output(:jquery, [\n      ['article_body', 'extended'],\n      ['article_body_excerpt', 'simple']\n    ]), output\n    \n    # test using custom default options\n    textile_editor_options :framework => :jquery\n    output = textile_editor_initialize()\n    assert_equal expected_initialize_output(:jquery, [\n      ['article_body', 'extended'],\n      ['article_body_excerpt', 'simple']\n    ]), output\n  end\n  \n  def test_textile_editor_inititalize_with_arbitrary_ids\n    output = textile_editor_initialize(:story_comment, :story_body)\n    assert_equal expected_initialize_output(:prototype, [\n      ['story_comment', 'extended'],\n      ['story_body', 'extended']\n    ]), output\n  end\n\n  def test_textile_editor_initialize_with_custom_buttons\n    b = '<button id=\"test_button\" onclick=\"alert(\\'Hello!\\')\" title=\"Hello world\">Hello</button>'\n    button_data = [\"TextileEditor.buttons.push(\\\"%s\\\");\" % escape_javascript(b)]\n    actual = textile_editor_button('Hello',\n      :id => 'test_button',\n      :onclick => \"alert('Hello!')\", \n      :title => 'Hello world'\n    )   \n    \n    assert_equal button_data, actual\n     \n    create_extended_editor('article', 'body')\n    output = textile_editor_initialize()\n    assert_equal expected_initialize_output(:prototype, [\n      ['article_body', 'extended']\n    ], button_data), output\n  end\n\n  def test_textile_extract_dom_ids_works_with_arrayed_hash\n    hash_with_array = { :recipe => [ :instructions, :introduction ] }\n    assert_equal [ 'recipe_instructions', 'recipe_introduction' ], textile_extract_dom_ids(hash_with_array)\n  end\n\n  def test_textile_extract_dom_ids_works_with_hash\n    hash_with_symbol = { :story  => :title }\n    assert_equal [ 'story_title' ], textile_extract_dom_ids(hash_with_symbol)\n  end\n\n  def test_textile_extract_dom_ids_works_with_ids\n    straight_id = 'article_page'\n    assert_equal [ 'article_page' ], textile_extract_dom_ids(straight_id)\n  end\n\n  def test_textile_extract_dom_ids_works_with_mixed_params\n    paramd  = %w(article_page)\n    paramd += [{ \n      :recipe => [ :instructions, :introduction ], \n      :story  => :title \n    }]\n    assert_equal %w(article_page recipe_instructions recipe_introduction story_title).sort, \n      textile_extract_dom_ids(*paramd).sort { |a,b| a.to_s <=> b.to_s }\n  end\n  \n  def test_textile_editor_button\n    b = '<button id=\"test_button\" onclick=\"alert(\\'Hello!\\')\" title=\"Hello world\">Hello</button>'\n    expected = ['TextileEditor.buttons.push(\"%s\");' % escape_javascript(b)]\n    \n    actual = textile_editor_button('Hello', \n      :id => 'test_button',\n      :onclick => \"alert('Hello!')\", \n      :title => 'Hello world'\n    )\n    \n    assert_equal expected, actual\n  end  \nend"
  },
  {
    "path": "vendor/plugins/yaml_db/README",
    "content": "= YamlDb\n\nYamlDb is a database-independent format for dumping and restoring data.  It complements the the database-independent schema format found in db/schema.rb.  The data is saved into db/data.yml.\n\nThis can be used as a replacement for mysqldump or pg_dump, but only for the databases typically used by Rails apps.  Users, permissions, schemas, triggers, and other advanced database features are not supported - by design.\n\nAny database that has an ActiveRecord adapter should work.\n\n== Usage\n\nrake db:data:dump   ->   Dump contents of Rails database to db/data.yml\nrake db:data:load   ->   Load contents of db/data.yml into the database\n\nFurther, there are tasks db:dump and db:load which do the entire database (the equivalent of running db:schema:dump followed by db:data:load).\n\n== Examples\n\nOne common use would be to switch your data from one database backend to another.  For example, let's say you wanted to switch from SQLite to MySQL.  You might execute the following steps:\n\n1. rake db:dump\n\n2. Edit config/database.yml and change your adapter to mysql, set up database params\n\n3. mysqladmin create [database name]\n\n4. rake db:load\n\n== Credits\n\nCreated by Orion Henry and Adam Wiggins.  Major updates by Ricardo Chimal, Jr.\n\nPatches contributed by Michael Irwin, Tom Locke, and Tim Galeckas.\n\nSend questions, feedback, or patches to the Heroku mailing list: http://groups.google.com/group/heroku\n\n"
  },
  {
    "path": "vendor/plugins/yaml_db/Rakefile",
    "content": "require 'rake'\nrequire 'spec/rake/spectask'\n\ndesc \"Run all specs\"\nSpec::Rake::SpecTask.new('spec') do |t|\n\tt.spec_files = FileList['spec/*_spec.rb']\nend\n\ntask :default => :spec\n\n"
  },
  {
    "path": "vendor/plugins/yaml_db/about.yml",
    "content": "author: Orion Henry and Adam Wiggins of Heroku\nsummary: Dumps and loads a database-independent data dump format in db/data.yml.\nhomepage: http://opensource.heroku.com/\nlicense: MIT\nrails_version: 1.2+\n"
  },
  {
    "path": "vendor/plugins/yaml_db/init.rb",
    "content": "require 'yaml_db'\n"
  },
  {
    "path": "vendor/plugins/yaml_db/lib/tasks/yaml_db_tasks.rake",
    "content": "namespace :db do\n\tdesc \"Dump schema and data to db/schema.rb and db/data.yml\"\n\ttask(:dump => [ \"db:schema:dump\", \"db:data:dump\" ])\n\n\tdesc \"Load schema and data from db/schema.rb and db/data.yml\"\n\ttask(:load => [ \"db:schema:load\", \"db:data:load\" ])\n\n\tnamespace :data do\n\t\tdef db_dump_data_file\n\t\t\t\"#{RAILS_ROOT}/db/data.yml\"\n\t\tend\n\n\t\tdesc \"Dump contents of database to db/data.yml\"\n\t\ttask(:dump => :environment) do\n\t\t\tYamlDb.dump db_dump_data_file\n\t\tend\n\n\t\tdesc \"Load contents of db/data.yml into database\"\n\t\ttask(:load => :environment) do\n\t\t\tYamlDb.load db_dump_data_file\n\t\tend\n\tend\nend\n"
  },
  {
    "path": "vendor/plugins/yaml_db/lib/yaml_db.rb",
    "content": "require 'rubygems'\nrequire 'yaml'\nrequire 'active_record'\n\n\nmodule YamlDb\n\tdef self.dump(filename)\n\t\tdisable_logger\n\t\tYamlDb::Dump.dump(File.new(filename, \"w\"))\n\t\treenable_logger\n\tend\n\n\tdef self.load(filename)\n\t\tdisable_logger\n\t\tYamlDb::Load.load(File.new(filename, \"r\"))\n\t\treenable_logger\n\tend\n\n\tdef self.disable_logger\n\t\t@@old_logger = ActiveRecord::Base.logger\n\t\tActiveRecord::Base.logger = nil\n\tend\n\n\tdef self.reenable_logger\n\t\tActiveRecord::Base.logger = @@old_logger\n\tend\nend\n\n\nmodule YamlDb::Utils\n\tdef self.chunk_records(records)\n\t\tyaml = [ records ].to_yaml\n\t\tyaml.sub!(\"--- \\n\", \"\")\n\t\tyaml.sub!('- - -', '  - -')\n\t\tyaml\n\tend\n\n\tdef self.unhash(hash, keys)\n\t\tkeys.map { |key| hash[key] }\n\tend\n\n\tdef self.unhash_records(records, keys)\n\t\trecords.each_with_index do |record, index|\n\t\t\trecords[index] = unhash(record, keys)\t\n\t\tend\n\t\t\n\t\trecords\n\tend\n\n\tdef self.convert_booleans(records, columns)\n\t\trecords.each do |record|\n\t\t\tcolumns.each do |column|\n\t\t\t\tnext if is_boolean(record[column])\n\t\t\t\trecord[column] = (record[column] == 't' or record[column] == '1')\n\t\t\tend\n\t\tend\n\t\trecords\n\tend\n\n\tdef self.boolean_columns(table)\n\t\tcolumns = ActiveRecord::Base.connection.columns(table).reject { |c| c.type != :boolean }\n\t\tcolumns.map { |c| c.name }\n\tend\n\n\tdef self.is_boolean(value)\n\t\tvalue.kind_of?(TrueClass) or value.kind_of?(FalseClass)\n\tend\n\n\tdef self.quote_table(table)\n\t\tActiveRecord::Base.connection.quote_table_name(table)\n\tend\nend\n\n\nmodule YamlDb::Dump\n\tdef self.dump(io)\n\t\ttables.each do |table|\n\t\t\tdump_table(io, table)\n\t\tend\n\tend\n\n\tdef self.tables\n\t\tActiveRecord::Base.connection.tables.reject { |table| ['schema_info', 'schema_migrations'].include?(table) }\n\tend\n\n\tdef self.dump_table(io, table)\n\t\treturn if table_record_count(table).zero?\n\n\t\tdump_table_columns(io, table)\n\t\tdump_table_records(io, table)\n\tend\n\n\tdef self.dump_table_columns(io, table)\n\t\tio.write(\"\\n\")\n\t\tio.write({ table => { 'columns' => table_column_names(table) } }.to_yaml)\n\tend\n\n\tdef self.dump_table_records(io, table)\n\t\ttable_record_header(io)\t\n\t\n\t\tcolumn_names = table_column_names(table)\n\n\t\teach_table_page(table) do |records|\n\t\t\trows = YamlDb::Utils.unhash_records(records, column_names)\n\t\t\tio.write(YamlDb::Utils.chunk_records(records))\n\t\tend\n\tend\n\n\tdef self.table_record_header(io)\n\t\tio.write(\"  records: \\n\")\n\tend\n\n\tdef self.table_column_names(table)\n\t\tActiveRecord::Base.connection.columns(table).map { |c| c.name }\n\tend\n\n\tdef self.each_table_page(table, records_per_page=1000)\n\t\ttotal_count = table_record_count(table)\n\t\tpages = (total_count.to_f / records_per_page).ceil - 1\n\t\tid = table_column_names(table).first\n\t\tboolean_columns = YamlDb::Utils.boolean_columns(table)\n\t\tquoted_table_name = YamlDb::Utils.quote_table(table)\n\t\t\n\t\t(0..pages).to_a.each do |page|\n\t\t\tsql = ActiveRecord::Base.connection.add_limit_offset!(\"SELECT * FROM #{quoted_table_name} ORDER BY #{id}\",\n\t\t\t\t:limit => records_per_page, :offset => records_per_page * page\n\t\t\t)\n\t\t\trecords = ActiveRecord::Base.connection.select_all(sql)\n\t\t\trecords = YamlDb::Utils.convert_booleans(records, boolean_columns)\n\t\t\tyield records\n\t\tend\n\tend\n\n\tdef self.table_record_count(table)\n\t\tActiveRecord::Base.connection.select_one(\"SELECT COUNT(*) FROM #{YamlDb::Utils.quote_table(table)}\").values.first.to_i\n\tend\nend\n\n\nmodule YamlDb::Load\n\tdef self.load(io)\n\t\tActiveRecord::Base.connection.transaction do\n\t\t\tYAML.load_documents(io) do |ydoc|\n\t\t\t\tydoc.keys.each do |table_name|\n\t\t\t\t\tnext if ydoc[table_name].nil?\n\t\t\t\t\tload_table(table_name, ydoc[table_name])\n\t\t\t\tend\n\t\t\tend\n\t\tend\n\tend\n\n\tdef self.truncate_table(table)\n\t\tbegin\n\t\t\tActiveRecord::Base.connection.execute(\"TRUNCATE #{YamlDb::Utils.quote_table(table)}\")\n\t\trescue Exception\n\t\t\tActiveRecord::Base.connection.execute(\"DELETE FROM #{YamlDb::Utils.quote_table(table)}\")\n\t\tend\n\tend\n\n\tdef self.load_table(table, data)\n\t\tcolumn_names = data['columns']\n\t\ttruncate_table(table)\n\t\tload_records(table, column_names, data['records'])\n\t\treset_pk_sequence!(table)\n\tend\n\n\tdef self.load_records(table, column_names, records)\n\t\tquoted_column_names = column_names.map { |column| ActiveRecord::Base.connection.quote_column_name(column) }.join(',')\n\t\tquoted_table_name = YamlDb::Utils.quote_table(table)\n\t\trecords.each do |record|\n\t\t\tActiveRecord::Base.connection.execute(\"INSERT INTO #{quoted_table_name} (#{quoted_column_names}) VALUES (#{record.map { |r| ActiveRecord::Base.connection.quote(r) }.join(',')})\")\n\t\tend\n\tend\n\n\tdef self.reset_pk_sequence!(table_name)\n\t\tif ActiveRecord::Base.connection.respond_to?(:reset_pk_sequence!)\n\t\t\tActiveRecord::Base.connection.reset_pk_sequence!(table_name)\n\t\tend\n\tend\nend\n"
  },
  {
    "path": "vendor/plugins/yaml_db/spec/base.rb",
    "content": "require 'rubygems'\nrequire 'spec'\n\n$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')\nrequire 'yaml_db'\n\n\n"
  },
  {
    "path": "vendor/plugins/yaml_db/spec/yaml_dump_spec.rb",
    "content": "require File.dirname(__FILE__) + '/base'\n\ndescribe YamlDb::Dump do\n\tbefore do\n\t\tFile.stub!(:new).with('dump.yml', 'w').and_return(StringIO.new)\n\n\t\tActiveRecord::Base = mock('ActiveRecord::Base', :null_object => true)\n\t\tActiveRecord::Base.connection = mock('connection')\n\t\tActiveRecord::Base.connection.stub!(:tables).and_return([ 'mytable', 'schema_info', 'schema_migrations' ])\n\t\tActiveRecord::Base.connection.stub!(:columns).with('mytable').and_return([ mock('a',:name => 'a'), mock('b', :name => 'b') ])\n\t\tActiveRecord::Base.connection.stub!(:select_one).and_return({\"count\"=>\"2\"})\n\t\tActiveRecord::Base.connection.stub!(:select_all).and_return([ { 'a' => 1, 'b' => 2 }, { 'a' => 3, 'b' => 4 } ])\n\t\tYamlDb::Utils.stub!(:quote_table).with('mytable').and_return('mytable')\n\tend\n\n\tbefore(:each) do\n\t\t@io = StringIO.new\n\tend\n\n\tit \"should return a formatted string\" do\n\t\tYamlDb::Dump.table_record_header(@io)\n\t\t@io.rewind\n\t\t@io.read.should == \"  records: \\n\"\n\tend\n\n\tit \"should return a list of column names\" do\n\t\tYamlDb::Dump.table_column_names('mytable').should == [ 'a', 'b' ]\n\tend\n\n\tit \"should return a list of tables without the rails schema table\" do\n\t\tYamlDb::Dump.tables.should == ['mytable']\n\tend\n\n\tit \"should return the total number of records in a table\" do\n\t\tYamlDb::Dump.table_record_count('mytable').should == 2\n\tend\n\n\tit \"should return a yaml string that contains a table header and column names\" do\n\t\tYamlDb::Dump.stub!(:table_column_names).with('mytable').and_return([ 'a', 'b' ])\n\t\tYamlDb::Dump.dump_table_columns(@io, 'mytable')\n\t\t@io.rewind\n\t\t@io.read.should == <<EOYAML\n\n--- \nmytable: \n  columns: \n  - a\n  - b\nEOYAML\n\tend\n\n\tit \"should return all records from the database and return them when there is only 1 page\" do\n\t\tYamlDb::Dump.each_table_page('mytable') do |records|\n\t\t\trecords.should == [ { 'a' => 1, 'b' => 2 }, { 'a' => 3, 'b' => 4 } ]\n\t\tend\n\tend\n\n\tit \"should paginate records from the database and return them\" do\n\t\tActiveRecord::Base.connection.stub!(:select_all).and_return([ { 'a' => 1, 'b' => 2 } ], [ { 'a' => 3, 'b' => 4 } ])\n\n\t\trecords = [ ]\n\t\tYamlDb::Dump.each_table_page('mytable', 1) do |page|\n\t\t\tpage.size.should == 1\n\t\t\trecords.concat(page)\n\t\tend\n\n\t\trecords.should == [ { 'a' => 1, 'b' => 2 }, { 'a' => 3, 'b' => 4 } ]\n\tend\n\n\tit \"should return dump the records for a table in yaml to a given io stream\" do\n\t\tYamlDb::Dump.dump_table_records(@io, 'mytable')\n\t\t@io.rewind\n\t\t@io.read.should == <<EOYAML\n  records: \n  - - 1\n    - 2\n  - - 3\n    - 4\nEOYAML\n\tend\n\n\tit \"should dump a table's contents to yaml\" do\n\t\tYamlDb::Dump.should_receive(:dump_table_columns)\n\t\tYamlDb::Dump.should_receive(:dump_table_records)\n\t\tYamlDb::Dump.dump_table(@io, 'mytable')\n\tend\n\n\tit \"should not dump a table's contents when the record count is zero\" do\n\t\tYamlDb::Dump.stub!(:table_record_count).with('mytable').and_return(0)\n\t\tYamlDb::Dump.should_not_receive(:dump_table_columns)\n\t\tYamlDb::Dump.should_not_receive(:dump_table_records)\n\t\tYamlDb::Dump.dump_table(@io, 'mytable')\n\tend\nend\n"
  },
  {
    "path": "vendor/plugins/yaml_db/spec/yaml_load_spec.rb",
    "content": "require File.dirname(__FILE__) + '/base'\n\ndescribe YamlDb::Load do\n\tbefore do\n\t\tYamlDb::Utils.stub!(:quote_table).with('mytable').and_return('mytable')\n\n\t\tActiveRecord::Base = mock('ActiveRecord::Base', :null_object => true)\n\t\tActiveRecord::Base.connection = mock('connection')\n\t\tActiveRecord::Base.connection.stub!(:transaction).and_yield\n\tend\n\n\tbefore(:each) do\n\t\t@io = StringIO.new\n\tend\n\n\tit \"should truncate the table\" do\n\t\tActiveRecord::Base.connection.stub!(:execute).with(\"TRUNCATE mytable\").and_return(true)\n\t\tActiveRecord::Base.connection.should_not_receive(:execute).with(\"DELETE FROM mytable\")\n\t\tYamlDb::Load.truncate_table('mytable')\n\tend\n\n\tit \"should delete the table if truncate throws an exception\" do\n\t\tActiveRecord::Base.connection.should_receive(:execute).with(\"TRUNCATE mytable\").and_raise()\n\t\tActiveRecord::Base.connection.should_receive(:execute).with(\"DELETE FROM mytable\").and_return(true)\n\t\tYamlDb::Load.truncate_table('mytable')\n\tend\n\n\tit \"should insert records into a table\" do\n\t\tActiveRecord::Base.connection.stub!(:quote_column_name).with('a').and_return('a')\n\t\tActiveRecord::Base.connection.stub!(:quote_column_name).with('b').and_return('b')\n\t\tActiveRecord::Base.connection.stub!(:quote).with(1).and_return(\"'1'\")\n\t\tActiveRecord::Base.connection.stub!(:quote).with(2).and_return(\"'2'\")\n\t\tActiveRecord::Base.connection.stub!(:quote).with(3).and_return(\"'3'\")\n\t\tActiveRecord::Base.connection.stub!(:quote).with(4).and_return(\"'4'\")\n\t\tActiveRecord::Base.connection.should_receive(:execute).with(\"INSERT INTO mytable (a,b) VALUES ('1','2')\")\n\t\tActiveRecord::Base.connection.should_receive(:execute).with(\"INSERT INTO mytable (a,b) VALUES ('3','4')\")\n\n\t\tYamlDb::Load.load_records('mytable', ['a', 'b'], [[1, 2], [3, 4]])\n\tend\n\n\tit \"should quote column names that correspond to sql keywords\" do\n\t\tActiveRecord::Base.connection.stub!(:quote_column_name).with('a').and_return('a')\n\t\tActiveRecord::Base.connection.stub!(:quote_column_name).with('count').and_return('\"count\"')\n\t\tActiveRecord::Base.connection.stub!(:quote).with(1).and_return(\"'1'\")\n\t\tActiveRecord::Base.connection.stub!(:quote).with(2).and_return(\"'2'\")\n\t\tActiveRecord::Base.connection.stub!(:quote).with(3).and_return(\"'3'\")\n\t\tActiveRecord::Base.connection.stub!(:quote).with(4).and_return(\"'4'\")\n\t\tActiveRecord::Base.connection.should_receive(:execute).with(\"INSERT INTO mytable (a,\\\"count\\\") VALUES ('1','2')\")\n\t\tActiveRecord::Base.connection.should_receive(:execute).with(\"INSERT INTO mytable (a,\\\"count\\\") VALUES ('3','4')\")\n\n\t\tYamlDb::Load.load_records('mytable', ['a', 'count'], [[1, 2], [3, 4]])\n\tend\n\n\tit \"should truncate the table and then load the records into the table\" do\n\t\tYamlDb::Load.should_receive(:truncate_table).with('mytable')\n\t\tYamlDb::Load.should_receive(:load_records).with('mytable', ['a', 'b'], [[1, 2], [3, 4]])\n\t\tYamlDb::Load.should_receive(:reset_pk_sequence!).with('mytable')\n\n\t\tYamlDb::Load.load_table('mytable', { 'columns' => [ 'a', 'b' ], 'records' => [[1, 2], [3, 4]] })\n\tend\n\n\tit \"should call load structure for each document in the file\" do\n\t\tYAML.should_receive(:load_documents).with(@io).and_yield({ 'mytable' => { \n\t\t\t\t\t'columns' => [ 'a', 'b' ], \n\t\t\t\t\t'records' => [[1, 2], [3, 4]] \n\t\t\t\t} })\n\t\tYamlDb::Load.should_receive(:load_table).with('mytable', { 'columns' => [ 'a', 'b' ], 'records' => [[1, 2], [3, 4]] })\n\t\tYamlDb::Load.load(@io)\n\tend\n\n\tit \"should not call load structure when the document in the file contains no records\" do\n\t\tYAML.should_receive(:load_documents).with(@io).and_yield({ 'mytable' => nil })\n\t\tYamlDb::Load.should_not_receive(:load_table)\n\t\tYamlDb::Load.load(@io)\n\tend\n\n\tit \"should call reset pk sequence if the connection adapter is postgres\" do\n\t\tActiveRecord::Base.connection.should_receive(:respond_to?).with(:reset_pk_sequence!).and_return(true)\n\t\tActiveRecord::Base.connection.should_receive(:reset_pk_sequence!).with('mytable')\n\t\tYamlDb::Load.reset_pk_sequence!('mytable')\n\tend\n\n\tit \"should not call reset pk sequence for other adapters\" do\n\t\tActiveRecord::Base.connection.should_receive(:respond_to?).with(:reset_pk_sequence!).and_return(false)\n\t\tActiveRecord::Base.connection.should_not_receive(:reset_pk_sequence!)\n\t\tYamlDb::Load.reset_pk_sequence!('mytable')\n\tend\nend\n"
  },
  {
    "path": "vendor/plugins/yaml_db/spec/yaml_utils_spec.rb",
    "content": "require File.dirname(__FILE__) + '/base'\n\ndescribe YamlDb::Utils, \" convert records utility method\" do\n\tbefore do\n\t\tActiveRecord::Base = mock('ActiveRecord::Base', :null_object => true)\n\t\tActiveRecord::Base.connection = mock('connection')\n\tend\n\n\tit \"turns an array with one record into a yaml chunk\" do\n\t\tYamlDb::Utils.chunk_records([ %w(a b) ]).should == <<EOYAML\n  - - a\n    - b\nEOYAML\n\tend\n\n\tit \"turns an array with two records into a yaml chunk\" do\n\t\tYamlDb::Utils.chunk_records([ %w(a b), %w(x y) ]).should == <<EOYAML\n  - - a\n    - b\n  - - x\n    - y\nEOYAML\n\tend\n\n\tit \"returns an array of hash values using an array of ordered keys\" do\n\t\tYamlDb::Utils.unhash({ 'a' => 1, 'b' => 2 }, [ 'b', 'a' ]).should == [ 2, 1 ]\n\tend\n\n\tit \"should unhash each hash an array using an array of ordered keys\" do\n\t\tYamlDb::Utils.unhash_records([ { 'a' => 1, 'b' => 2 }, { 'a' => 3, 'b' => 4 } ], [ 'b', 'a' ]).should == [ [ 2, 1 ], [ 4, 3 ] ]\n\tend\n\n\tit \"should return true if it is a boolean type\" do\n\t\tYamlDb::Utils.is_boolean(true).should == true\n\t\tYamlDb::Utils.is_boolean('true').should_not == true\n\tend\n\n\tit \"should return an array of boolean columns\" do\n\t\tActiveRecord::Base.connection.stub!(:columns).with('mytable').and_return([ mock('a',:name => 'a',:type => :string), mock('b', :name => 'b',:type => :boolean) ])\n\t\tYamlDb::Utils.boolean_columns('mytable').should == ['b']\n\tend\n\n\tit \"should quote the table name\" do\n\t\tActiveRecord::Base.connection.should_receive(:quote_table_name).with('values').and_return('`values`')\n\t\tYamlDb::Utils.quote_table('values').should == '`values`'\n\tend\nend\n"
  }
]